4
votes

I need help with Google App Maker data model security. I want to set multiple owners for a single record. Like the current user + the assigned admin + super admin. I need this because all records can have different owners and super-owners/admins. I know that we can point google app maker to a field containing record owner's email and we can set that field to the current user at the time of the creation of the record.

record.Owner = Session.getActiveUser().getEmail();

I want to know if it is possible to have field owners or have multiple fields like owner1, owner2 and then assign access levels to owner1, owner2...

Or how can we programmatically control the access/security/permissions of records?

1
I only have a suggestion, this approach did not work a year ago but maybe it does now. Create a new model and call it ownership or something. Create one field of type string and call it owner. Then set a many-to-many relation between ownership and your model. In your model security do the advanced setting for all necessary events setting owner and then linking it to the related model field of owner. Second option is to use string to array and vice versa conversions and store all owners in a field in the model and store all owners as comma separated string.Markus Malessa
Have you reviewed this?TheMaster
Yes, @TheMaster and most relevant part from that is this. I know that we can add permissions to roles on models but I need this on records.NdmGjr
Use Script based access? Check if record.owner or record.superOwner === activeUser, grant access?TheMaster
One way would be to combine the role-based permissions for the entire model and make some queries to filter the recordsJuan Bravo Roig

1 Answers

4
votes

The solution I'd use for this one definitely involves a field on the record that contains a comma separated string of all the users who should have access to it. I've worked on the following example to explain better what I have in mind.

I created a model and is called documents and looks like this:

enter image description here

In a page, I have a table and a button to add new document records. The page looks like this:

enter image description here

When I click on the Add Document button, a dialog pops up and looks like this:

enter image description here

The logic on the SUBMIT button on the form above is the following:

widget.datasource.item.owners = app.user.email;
widget.datasource.createItem(function(){
  app.closeDialog();
});

That will automatically assign the creator of the record the ownership. To add additional owners, I do it on an edit form. The edit form popus up when I click the edit button inside the record row. It looks like this:

enter image description here

As you can see, I'm using a list widget to control who the owners are. For that, it is necessary to use a <List>String custom property in the edit dialog and that will be the datasource of the list widget. In this case, I've called it owners. I've applied the following to the onClick event of the edit button:

var owners = widget.datasource.item.owners;
owners = owners ? owners.split(",") : [];
app.pageFragments.documentEdit.properties.owners = owners;
app.showDialog(app.pageFragments.documentEdit);

The add button above the list widget has the following logic for the onClick event handler:

widget.root.properties.owners.push("");

The TextBox widget inside the row of the list widget has the following logic for the onValueEdit event handler:

widget.root.properties.owners[widget.parent.childIndex] = newValue;

And the CLOSE button has the following logic for the onClick event handler:

var owners = widget.root.properties.owners || [];
if(owners && owners.length){
  owners = owners.filter(function(owner){
    return owner != false; //jshint ignore:line
  });
}
widget.datasource.item.owners = owners.join();
app.closeDialog();

Since I want to create a logic that will load records only for authorized users, then I had to use a query script in the datasource that will serve that purpose. For that I created this function on a server script:

function getAuthorizedRecords(){
  var authorized = [];
  var userRoles = app.getActiveUserRoles();
  var allRecs = app.models.documents.newQuery().run();
  if(userRoles.indexOf(app.roles.Admins) > -1){
    return allRecs;
  } else {
    for(var r=0; r<allRecs.length; r++){
      var rec = allRecs[r];
      if(rec.owners && rec.owners.indexOf(Session.getActiveUser().getEmail()) > -1){
        authorized.push(rec);
      }
    }
    return authorized;
  }  
}

And then on the documents datasource, I added the following to the query script:

return getAuthorizedRecords();

enter image description here

This solution will load all records for admin users, but for non-admin users, it will only load records where their email is located in the owners field of the record. This is the most elegant solution I could come up with and I hope it serves your purpose.

References:
https://developers.google.com/appmaker/models/datasources#query_script
https://developers.google.com/appmaker/ui/binding#custom_properties
https://developers.google.com/appmaker/ui/logic#events
https://developers-dot-devsite-v2-prod.appspot.com/appmaker/scripting/api/client#Record