Google App maker multiple files drive upload - google-app-maker

We are going to use drive picker as attachement field, so whenever an user uploads a file or multiples files to drive we have to get the links of the files and show it to the user in the form.

Here is a code sample with following assumptions:
you have Master and Attachment models with One-to-Many relation
datasource of the current page is set to record from the Master model
datasource is in Auto Save mode
// onDocumentSelect Drive Picker's event handler
var create = widget.root.datasource.relations.Attachments.modes.create;
result.docs.forEach(function(doc) {
create.item.Url = doc.url;
create.createItem();
});
This code will make N requests to the server, where N is number of attachments. You can use google.script.run to make a single call and handle creating new attachment records and relations on server, but then you'll need manually reload relation to show changes to user.

Related

Display only Team Drives in Drive Picker Widget

I am creating an application where I need to provide Drive Picker widget so that users can upload some files. Now I want to restrict users so that they can only select files from their "Team Drives" and not from anywhere else.
I've tried adding method in onPickerInit event.
Here's my function which is getting called in onPickerInit event,
function fetchFolder(widget, pickerBuilder) {
pickerBuilder.addView(new google.picker.DocsView()
.setParent('TeamDriveId')
.setIncludeFolders(true));
}
This method restricts users to select only from particular Team Drive, however my question is how can I give dynamic option so that users can select from any of their Team Drives and not limited to one Team Drive. Also they should not be able to select from their own Google Drives.
It seems that this case requires low level Drive Picker tuning, so lets start from removing all settings that App Maker gives us out of the box:
Remove all features
Remove all views
Then add the following script to the onPickerInit event
// Enable Team Drives
pickerBuilder.enableFeature(google.picker.Feature.SUPPORT_TEAM_DRIVES);
// Let users to select files from any Team Drive
var multiTeamDrive = new google.picker.DocsView();
multiTeamDrive.setIncludeFolders(true)
.setEnableTeamDrives(true);
pickerBuilder.addView(multiTeamDrive);
// This feature need to be set to force `setParent` work.
// Seems to be Drive Picker's bug
pickerBuilder.enableFeature(google.picker.Feature.MULTISELECT_ENABLED);
// Force users to upload files to a specific Team Drive
var uploadView = new google.picker.DocsUploadView();
uploadView.setParent('Fancy KEY from Team Drive folder URL')
.setLabel('Upload to Team Drive XXX');
pickerBuilder.addView(uploadView);
Result
Notes
I didn't find a way to hide the tab for the Personal Drive upload. It is strange that App Maker adds it by default and there is no option to remove it.
I also recommend to add server side validation for the files selected by users to ensure that they originate from Team Drive.
Similar/related answer: https://stackoverflow.com/a/49677679/454137

Adobe Audience Manager - Stitching visitors across devices

Me and my team is new to Adobe Audience Manager and we are trying to figure out ways to stitch visitors cookies across devices (of the same visitor) once user does authentication (for ex: logins).
Have setup Adobe Analytics as well and have done integration to send data from Adobe Analytics to Adobe Audience Manager.
Primarily, we are trying to build a unified visitor's journey which as you would know will have endless benefits once we have it.
Any pointers/information or relevant doc will help a lot. Just ensuring we are moving in the right direction.
Regards,
Adwait
You can stitch user devices together (after authentication) by configuring ID sync and profile merge rules.
Here are the steps that you could follow
Configure a Cross device datasource (for merging online & offline data)
Go to Audience Data > Data Sources > Add New
name the data source as Cross Device ID Sync
Enter the following Integration code offlinesyncid, which is your own, unique ID for this data source.
In the ID Type choose Cross Device
In the ID Definition choose Person
In the Data Export Controls tick the No ristriction checkbox and make sure all other checkboxes are unticked.
In the Data Source Settings tick the Inbound checkbox and make sure the Customer ID radio button is chosen
In the Data Source Settings tick the Outbound checkbox
Make sure the Use as Authenticated Profile checkbox is ticked
Tick the Share associated visitor or device IDs across the Audience Manager platform checkbox
Save the datasource
Note the ID of the datasource you just created as we will use it in the following steps. Let's assume it is 123456
Configure an Online ID Sync datasource
Go to Audience Data > Data Sources > Add New
name the data source as Online ID Sync
Enter the following Integration code sitesyncid
In the ID Type choose Cookie
In the Data Export Controls tick the No ristriction checkbox and make sure all other checkboxes are unticked.
In the Data Source Settings tick the Inbound checkbox and make sure the Customer ID radio button is chosen
In the Data Source Settings tick the Outbound, Share Enabled, and Share associated visitor or device IDs across the Audience Manager platform checkboxes.
Save the datasource
Profile Merge Rule Setup
Go to Audience Data > Profile Merge Rules > Add New Rule
Name the new rule as Last Authenticated with Profile Link Device Graph
in the Profile Merge Rule Setup section choose the Last Authenticated Profiles radio button and tick the Cross Device ID Sync - Person datasource
From the Device Options section, choose the Profile Link Device Graph
Build the ID Sync code on your website
Assuming that you are using the dil.js code here is an example of how you can perform the ID sync
var customerID = "<customer ID e.g. 56789142>"; //Replace the text between the double quotes with your own authenticated customer ID
if (customerID) {
var yoursiteDIL = DIL.create({
partner : "<partner name>", //The partner name given to you by Adobe.
uuidCookie : {
name : "aam_uuid",
days : 30
},
visitorService: {
namespace: "XXXXXXXXXXXXXXXXXXXXX#AdobeOrg" //insert adobe org id here.
},
containerNSID: '0', // Recommended to have this set to zero. However, it could change depending on how many completely separate sites you run.
declaredId : {
dpid : "123456" , //This is the ID of the Cross Device datasource that you just created
dpuuid : customerID
}
});
var c = decodeURIComponent('%01');
var cidObject = {
cid_ic : 'sitesyncid' + c + customerID + c + '1' //this is the integration code you set for the Online ID Sync datasource
};
yoursiteDIL.api.signals(cidObject, 'd_');
yoursiteDIL.api.signals({c_sitesyncid: customerID});
} else {
var yoursiteDIL = DIL.create({
partner : "<partner name>",
uuidCookie : {
name : "aam_uuid",
days : 30
},
visitorService: {
namespace: "XXXXXXXXXXXXXXXXXXXXX#AdobeOrg" //insert adobe org id here.
}
});
}
yoursiteDIL.api.signals({ "signalKey": "signalValue"});
You can try setting up the Adobe Analytics s.visitorID based on the login details.
https://marketing.adobe.com/resources/help/en_US/sc/implement/visid_custom.html

SetPermission With sensenet API - version 6.3

I am working on sensenet API. I faced an issue with setPermission on sensenetAPI security.
As per concern, when I create a document I would like to give See, open, Save and RunApplication permission as a default for newly created document to the user(User is taken from the function parameter).
To achieve this I use below code
public static void SetCollabUserSecurity(string myUserEmailId, Node myNodetToSetSecurity)
{
var domainName = "Builtin";
var strUsername = GetNameFromEmail(myUserEmailId);
User user;
using (new SystemAccount())
{
user = User.Load(domainName, strUsername);
if (user != null && user.Enabled)
{
var myUser = user;
myNodetToSetSecurity.Security.SetPermission(myUser, true, PermissionType.See,
PermissionValue.Allow);
myNodetToSetSecurity.Security.SetPermission(myUser, true, PermissionType.Open,
PermissionValue.Allow);
myNodetToSetSecurity.Security.SetPermission(myUser, true, PermissionType.Save,
PermissionValue.Allow);
myNodetToSetSecurity.Security.SetPermission(myUser, true, PermissionType.RunApplication,
PermissionValue.Allow);
}
}
}
While I am using this function, my process for creating document becomes time consuming. It takes around 40 second time for execution.
So in case of, if I would like to share the same newly created document with multiple users, lets say there are 3 user and I want to give the above permission to all of them then my single function call takes 120 second (2 minute) time to simply assign permission.
Is there any Odata REST API call available or any sensenet library call available through which I can assign...
1) multiple permission to multiple user for single document or
2) multiple permission to single user for single document
Can anyone help to come out from this issue?
Thanks!
C# api
On the server there is a c# api for managing permissions, please check this article for details. You may use the AclEditor class for setting multiple permissions in one round. Please note that you have to call the Apply method at the end to actually perform the operation.
// set permissions on folder1, folder2 and file1 for two users and a group
SecurityHandler.CreateAclEditor()
.Allow(folder1.Id, user1.Id, false, PermissionType.Open, PermissionType.Custom01)
.Allow(folder2.Id, user2.Id, false, PermissionType.Open)
.Allow(file1.Id, editorsGroup.Id, false, PermissionType.Save)
.Apply();
As a side note: in most cases it is better to work with groups than users when assigning permissions. So it is advisable to give permissions to a group and put users into the group as members instead of assigning permissions to users directly.
Also: it is easier to maintain a simpler security structure, for example if you assign a permission on the parent container (e.g. a folder) instead of on individual files. Of course if you have to set permission per file, then it is fine.
OData api
The same api is available from the client through the REST api. Please take a look at the SetPermissions action in this article or the similar api in the JavaScript client library of sensenet.

Google Analytics - Track multiple subdirectories

I have a website where users can create subdirectories and files, and I need to be able to track each subdirectory separately as it's created.
For example: if my site is www.domain.com
User 1 creates www.domain.com/user1/index.html
User 2 creates www.domain.com/user2/index.html
I need to be able to automatically track subdirectories user1 and user2. I can't manually go into GA admin panel and add a segment/filter each time a new subdirectory is created to track it. I also need to be able to display this data back to the users.
Is this possible with Google Analytics?
Managed to do this very easily.
1) Programatically added the google analytics code to each new page the user creates. This automatically tracks traffic to individual subdirectories.
2) Used oocharts.js to display the data individually, by passing in a filter like so.
var timeline1 = new oo.Timeline("12345678", "30d");
timeline1.addMetric("ga:visits", "Visits");
timeline1.query.setFilter('ga:pagePath=~/user1/');
timeline1.draw('chart1');
var timeline2 = new oo.Timeline("12345678", "30d");
timeline2.addMetric("ga:visits", "Visits");
timeline2.query.setFilter('ga:pagePath=~/user2/');
timeline2.draw('chart2');

Programicatlly visit (all) ASP.Net page(s) in a website?

In the Security model for out ASP.Net website (.Net 3.5) we store the page name:
page.GetType().Name
as the primary key in a database table to be able to lookup if a user has access to a certain page. The first time a page is visited this record is created automatically in the database.
We have exported these database statements to insert scripts, but each time a new page gets created we have to update the scripts, not a huge issue, but I would like to find an automated way to do this.
I created an attribute that I tagged a few pages with and then wrote a small process to get all the objects that have this attribute, through the reflection create an instance and insert the record using the same code to for page records mentioned above:
IEnumerable<Type> viewsecurityPages = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsDefined(typeof(ViewSecurityAttribute),false));
foreach (Type t in viewsecurityPages)
{
object obj = Activator.CreateInstance(t, false);
//clip..(This code just checks if the record already exists in the DB)
if (feature == null)
{
Attribute attb = Attribute.GetCustomAttribute(t, typeof(ViewSecurityAttribute));
if (attb != null)
{
CreateSecurableFeatureForPage((Page)obj, uow, attb.ToString());
}
}
}
The issue is that page.GetType().Name when the page goes through the actual page cycle process is something like this:
search_accounts_aspx
but when I used the activator method above it returns:
Accounts
So the records don't match the in the security table. Is there anyway to programtically "visit" a webpage so that it goes through the actual page lifecycle and I would get back the correct value from the Name parameter?
Any help/reference will be greatly appreciated.
Interesting problem...
Of course there's a (too obvious?) way to programmatically visit the page... use System.Net.HttpWebRequest. Of course, that requires the URI and not just a handle to the object. This is a "how do we get there from here?" problem.
My suggestions would be to simply create another attribute (or use that same one) which stores the identifier you need. Then it will be the same either way you access it, right?
Alternatively... why not just use a 3rd party web spider/crawler to crawl your site and hit all the pages? There are several free options. Or am I missing something?

Resources