Search code examples
databasegoogle-apps-scriptgoogle-cloud-sqlgoogle-app-maker

Adding multiple owners for Google App Maker records


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?


Solution

  • 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