Add Signature field to pdf in javascript - javascript

after hours of searching for a solution, I've decided to ask my first question on stackoverflow.
Our application uses pdf-lib (https://www.npmjs.com/package/pdf-lib) to modify existing PDFs, e.g. add images. We're now looking for a way to ad signature form fields to the PDF as well.
With pdf-lib, it is possible to add a bunch of form fields, except for signature fields. It is possible to get them (https://pdf-lib.js.org/docs/api/classes/pdfform#getsignature), but unlike other fields, there's no create method (e.g. https://pdf-lib.js.org/docs/api/classes/pdfform#createtextfield).
I've digged deeper in the code, and found access to the PDFForms AcroForm (https://pdf-lib.js.org/docs/api/classes/pdfform#acroform). It's possible to add fields with it, but I wasn't able to create the correct Field beforehand (in my opinion it has to be PDFSignature or PDFAcroSignature).
I found out that other fields like PDFAcroText have create methods
class PDFAcroText extends PDFAcroTerminal {
static fromDict = (dict: PDFDict, ref: PDFRef) => new PDFAcroText(dict, ref);
static create = (context: PDFContext) => {
const dict = context.obj({
FT: 'Tx',
Kids: [],
});
const ref = context.register(dict);
return new PDFAcroText(dict, ref);
};
Those get called by the wrapper functions (like createTextfield as mentioned):
createTextField(name: string): PDFTextField {
assertIs(name, 'name', ['string']);
const nameParts = splitFieldName(name);
const parent = this.findOrCreateNonTerminals(nameParts.nonTerminal);
const text = PDFAcroText.create(this.doc.context);
text.setPartialName(nameParts.terminal);
addFieldToParent(parent, [text, text.ref], nameParts.terminal);
return PDFTextField.of(text, text.ref, this.doc);
}
I looked for other js libs that provide the possibility to add signature form fields, but I wasn't able to find the answer to this - except for pay to use libs like pdfjs.express.
Assuming that they are capable of adding such fields, there must be a way to do this!
Please let me know if anyone of you figured out how to do this or if there's another solution for this.
Thank you in advance!
Greetings
Alex

The Acrobat PRO itself doesn't have an option to put a straight "Signature" field. You may "request" a signature, but only using Adobe's services, and an email is required.
If you plan to add a signature by the code, take a look at their "Fill Form" example. They put an image on top of a Button field, but an Image field also works.
const signatureImageField2 = form.getButton('button-signature-field')
signatureImageField2.setImage(signatureImage)
const factionImageField = form.getField('image-signature-field_af_image')
factionImageField.setImage(signatureImage)

Related

Best way to translate inputs

Good evening,
Today I've encountered a question/problem. I'll get right into it. So basically I have form which is used to create meal. Meal table (migration) looks like this:
$table->uuid('id')->primary();
$table->uuid('restaurant_id')->nullable();
$table->string('name_lt', 100);
$table->string('name_en', 100);
$table->string('name_ru', 100);
$table->smallInteger('prep_time');
$table->string('image', 150);
$table->boolean('visibility')->default(0);
$table->boolean('deleted')->default(0);
$table->timestamps();
$table->foreign('restaurant_id')->references('id')->on('restaurants')->onDelete('cascade');
Aside the there's tons of other stuff, like ingredients and stuff, which are related to that specific meal. In the form page I have 3 different forms for different languages that is my native lithuanian, english and russian. There is tab buttons for changing form to other language, all it does is just hide current form and show another (there is 3 identical forms in 1 page).
What I'm trying to achieve is if I fill in lithuanian language's inputs, I want english and russian inputs to be filled also (that can be achieved with jquery or javascript change function), but it should fill in translated text.
Simple example:
In first form I fill in text name_lt = 'Obuolys', so name_en and name_ru should get filled too, but in different language, in this case name_en = 'Apple', name_ru = 'яблоко'
I never used translation api's so I'm wondering what would be the best way, I'm thinking of using DeepL as it is quite cheap.
If someone could give me some advices or simple example would be nice, I could follow on from that.
If you want to use javascript, you could use a button's click event to fill out the other fields before submiting the form. If I understand it correctly you have 3 forms (1 per tab).
You could do something like this for each form.
<form id="form-lt" method="post">
#csrf
<input name="name_lt">
<input type="hidden" name="name_en">
<input type="hidden" name="name_ru">
{{-- Not a true submit button --}}
<button id="button-lt type="button">Submit</button>
</form>
Given a function that takes text input, the original language and the language you want to translate
async function translate(text, from_language, to_language) {
const response = await fetch(...);
const data = await response.json();
// get translated text from data
return translated_text;
}
The js part could look like this
const button_lt = document.getElementById('button-lt');
button_lt.addEventListener('click', async event => {
const form = event.target.form;
const lt_value = form.querySelector('[name=name_lt]').value;
const en_input = form.querySelector('[name=name_en]');
const ru_input = form.querySelector('[name=name_ru]');
en_input.value = await translate(lt_value, 'lt', 'en');
ru_input.value = await translate(lt_value, 'lt', 'ru');
form.submit();
});
Alternatively, if you want to do it server-side, you could try to call whatever translation API you end up using using the Http facade provided by laravel before validating the input data or before saving the model to the database.
Are you using PHP or javascript?
DeepL offers a NodeJS library (for the backend) and a PHP library to easily allow you to translate. For example, to translate in PHP, you can use the following snippet after installing the library:
$authKey = "f63c02c5-f056-..."; // Replace with your key
$translator = new \DeepL\Translator($authKey);
$result = $translator->translateText('Hello, world!', null, 'fr');
echo $result->text; // Bonjour, le monde!
To perform this when your users fill in some text, you will need to write the appropriate Laravel code. Please note that it is not safe to do this in the frontend, as it requires you to expose your $authKey.

Get all user properties from Microsoft graph

We have an application which has used a local AD to fetch user info. Some customers want to move to the cloud and are using Azure AD. We extended the app to sign users in via owin and now we're fetching users via Microsoft Graph.
However from Microsoft Graph we do not get full user profiles. We want to fetch all properties on users, not just the basic ones.
var client = new RestClient(string.Format("https://graph.microsoft.com/v1.0/users/{0}", userEmail));
request = new RestRequest();
request.Method = Method.GET;
request.AddHeader("Authorization", _token.Token);
var reponse = client.Execute(request);
This only gives me some information though, for example I don't get 'Department' from this.
Is it possible to configure in azure what should be returned here, if so then where? Or do I need something other than /users/?
Different customers might have different special properties that need to be fetched. So the best solution would be to have an endpoint to call and get everything, including special properties not standard in azure ad. After that I can parse it on my side. Is this possible?
The app has permission to read both basic and full profiles. Do I need something more?
That's the normal behaviour of Graph API, see documentation here and this extract:
By default, only a limited set of properties are returned (
businessPhones, displayName, givenName, id, jobTitle, mail,
mobilePhone, officeLocation, preferredLanguage, surname,
userPrincipalName).
To return an alternative property set, you must specify the desired
set of user properties using the OData $select query parameter. For
example, to return displayName, givenName, and postalCode, you would
use the add the following to your query
$select=displayName,givenName,postalCode
You have to specify all fields in the select, as $select=* will only output the key fields in Graph API implementation.
So you will not be able to get what you ask (variable custom fields).
More info on the fields of User can be found here
User user = await graphServiceClient
.Users[emailId]
.Request()
.Select(aadUser => new
{
aadUser.Id,
aadUser.UserPrincipalName,
aadUser.DisplayName,
aadUser.GivenName,
aadUser.Surname,
aadUser.City,
aadUser.MailNickname,
aadUser.UserType
})
.GetAsync()
.ConfigureAwait(false);
As already stated by NicolasR, you must list all the fields you want to retrieve by using the "$select" parameter; if you want, instead, to retrieve the custom fields, you can either add them to the previous parameter (if you know their names) or you can use "$expand=extensions"
function getGraphDataAdvanced($authToken, $urlGraph){
$url = $urlGraph + '&$count=true'
$data = (Invoke-RestMethod -Headers #{
Authorization = "Bearer $($authToken)"
ConsistencyLevel = "eventual"
} -Uri $url -Method Get)
$dataList = #()
$dataList += $data.value
$url = $data.'#Odata.NextLink'
while ($null -ne $url){
Write-Warning 'Retreiving Next Page'
$data = (Invoke-RestMethod -Headers #{
Authorization = "Bearer $($authToken)"
ConsistencyLevel = "eventual"
} -Uri $url -Method Get)
$dataList += $data.value
$url = $data.'#Odata.NextLink'
}
return $dataList
}
getGraphDataAdvanced $authToken 'https://graph.microsoft.com/beta/users? $expand=extensions'
Using the Microsoft Graph Explorer, I've been able to find all available properties for a user:
Go to "Groups"
Select "list all groups in my organization"
Change the query to filter by a group you know and expand members: https://graph.microsoft.com/v1.0/groups?$filter=mail eq 'aGroup#company.com'&$expand=members
Now you'll see all the available properties for the users.
I've been trying to find a way to get all Azure AD properties of objects via Powershell MSGraph cmdlets without it truncating at the right edge of the console.
I've discovered that Format-Custom triggers vomiting of (apparently) all properties of an object in a huge, alphabetical, indented, and bracketed list.
Get-MgUser -filter "startswith(userprincipalname, 'username')" | format-custom
The formatted properties of a newly created and unused user account in Azure AD is 13217 lines long.

How to update a user's tags ? using Quickblox javascript SDK

How can i update a user' tags using Quickblox javascript SDK ?
i tried using the following parameter names :
user_tags
tags
using
var params = {
user_tags: ["testing"]
};
Please don't answer me with "you can use custom objects, etc.." i'm already using them for something else.
I want to use tags, and nothing else
As stated in the table on this page: http://quickblox.com/developers/Users#Update_API_User_by_identifier you should use tag_list key which accepts a comma separated list of tags.
QB.users.update(user_id, { tag_list: "tag1,tag2" }, callback);
Unfortunately QB docs aren't the best in the world...

I'm getting a "newItem() was not passed an identity for the new item" error while trying to add a new item to a JSON store

I've seen other posts in this site regarding the same issue and I've tried the solutions given. I've also visited the links that may offer a solution but I'm still stuck with the same error.
I'm using DOJO and something as simple as this won't even work
myStore.newItem({id: 'test', otherfield: 'otherinfohere'});
myStore.save();
Supposedly the "newItem() was not passed an identity for the new item" error appears when you haven't provided an identifier for the new item, which i have.
The whole purpose of this (Just in case anyone can provide a good idea or has done something similar before) is that i want to create a data grid that shows info from a particular store. The problem is, that in that store all the items may not have the same structure. For instance:
I may have a store that looks like this
{identifier: 'id',
label: 'name',
items: [
{ id:'1', name:'Ecuador', capital:'Quito' },
{ id:'2', name:'Egypt', capital:'Cairo' },
{ id:'3', name:'El Salvador', capital:'San Salvador' , additionalField: 'otherinfohere'},
{ abbr:'gq', name:'Equatorial Guinea', capital:'Malabo', additionalField: 'otherinfohere'},
]}
This is possible because I'm the one constructing the store in a Spring Controller (I'm also using the Spring Framework) from information I have locally stored in a Berkeley DB. So what i need is a data grid with a dynamic layout because I don't want blank spaces to show in the view in the rows with lesser amount of fields, and i need to show all the info in the store at the same time, but i don't know how to do this.
I thought of doing it by creating a simple layout of only 1 field. In it I would load data from a store i create dynamically at runtime. The data in the store would be composed of HTML combined with the values coming from the original store so I could obtain something like this, which is inside an attribute of a JavaScript Object and let the browser parse it for me:
<div><span>id: originalID </span>....</div>
This of course is a simple example, the html layout i'm looking for is far more complicated, but i think that passing it as a string to an object might do the trick.
The problem is that i don't even know if that idea will work because i get that error whenever i try to add values to my secondary store.
rdb.modules.monitor.historicStore.fetch({onComplete: function(items, request){
for (var i = 0; i < items.length; i++){
var item = items[i];
var obj = new Object();
obj.id = rdb.modules.monitor.historicStore.getValue(item, "id");;
var html = "<div><span>";
html += rdb.modules.monitor.historicStore.getValue(item, "sql");
html += "</span></div>";
obj.html = html;
myStore.store.newItem(obj);
}
}});
In this context "historicStore" refers to the JSON store that has the values that i need to convert and add to "myStore" after i added some HTML.
I hope you got the main idea of what I'm trying to do. If anyone can help me we either of these problems i would really appreciate it. Thanks in advance
For the issue regarding store:-
"id" is mandatory for a store, if it is going to be used for a grid(datagrid, EnhancedGrid, etc. whatever). The items are handled only on basis of "id" attribute by the grid data structures.
Usually, id can be a loop variable/ auto incrementation, to avoid any cases like you have said. Before adding the store to the grid, ensure that all items have the id attribute. You can write a function which will loop through each item and check for this, else add an auto-incrementing value for the id attribute of that item.

Send additional data with autocomplete options

I have a field that autocompletes on person name, so it has options like "Obama, Barack", "Lincoln, Abe", etc.
These people also have additional attributes, say "Birthplace" and "Phone number". When a user picks an option from the autocomplete, I would like that person's additional attributes to automatically populate hidden form fields.
The web service that supplies the autocomplete options also knows everyone's birthplace and phone number, so it could send this data to the client. However, the jQuery autocomplete plugin I'm using doesn't accept any additional data like this -- you can only give it the autocomplete options.
Any thoughts on how to do this?
Use YUI :)
Handles all that, completely customizable out of the box.
I'm not familiar with the autocomplete plugin but: Why not download all the data from the server and then only feed the autocomplete what it needs. I.e.
var persons = {
abe: {
name: 'abe',
birthplace: 'I\'m not from the US so I have no clue'
},
Obama: {
name: 'Obama',
birthplace: 'please see abe'
}
};
Then do something like:
for(name in persons){
feedAutocomplete(name); //or persons[name].name
}
Or if you need to feed the autocomplete in one Array:
autoCompleteArray = Array();
for(name in persons){
autoCompleteArray.push(name);
}
feedAutocomplete( autoCompleteArray );
And onAutoComplete callback:
function onAutoComplete(name){
//or if the currect value is not supplied in
// the function: var name = $('#autocompleField').val();
var personInfo = persons[name];
$('#hiddenFieldBirthplace').val( personInfo.birthplace );
}
I believe the auto-complete plug-in allows for callback functions. You could populate the hidden fields based on the users selection in that function.

Categories

Resources