'Assigns a role to a user (add the user to a user group)
@param user_id: the record ID of the user account
@param group_id: the record ID(s)/UID(s) of the group
@param for_pe: the person entity (pe_id) to restrict the group
membership to, possible values:
- None: use default realm (entities the user is
affiliated with)
- 0: site-wide realm (no entity-restriction)
- X: restrict to records owned by entity X
@note: strings are assumed to be group UIDs
@note: for_pe will be ignored for ADMIN, ANONYMOUS and AUTHENTICATED'

def s3_assign_role(self, user_id, group_id, for_pe=None):

    db = current.db
    gtable = self.settings.table_group
    mtable = self.settings.table_membership
    query = None
    uuids = None
    if isinstance(group_id, (list, tuple)):
        if isinstance(group_id[0], str):
            uuids = group_id
            query = gtable.uuid.belongs(group_id)
        else:
            group_ids = group_id
    elif (isinstance(group_id, str) and (not group_id.isdigit())):
        uuids = [group_id]
        query = (gtable.uuid == group_id)
    else:
        group_ids = [group_id]
    if (query is not None):
        query = ((gtable.deleted != True) & query)
        groups = db(query).select(gtable.id, gtable.uuid)
        group_ids = [g.id for g in groups]
        missing = [uuid for uuid in uuids if (uuid not in [g.uuid for g in groups])]
        for m in missing:
            group_id = self.s3_create_role(m, uid=m)
            if group_id:
                group_ids.append(group_id)
    query = (((mtable.deleted != True) & (mtable.user_id == user_id)) & (mtable.group_id.belongs(group_ids) & (mtable.pe_id == for_pe)))
    assigned = db(query).select(mtable.group_id)
    assigned_groups = [g.group_id for g in assigned]
    sr = self.get_system_roles()
    unrestrictable = [str(sr.ADMIN), str(sr.ANONYMOUS), str(sr.AUTHENTICATED)]
    for group_id in group_ids:
        if (group_id not in assigned_groups):
            membership = {'user_id': user_id, 'group_id': group_id}
            if ((for_pe is not None) and (str(group_id) not in unrestrictable)):
                membership['pe_id'] = for_pe
            mtable.insert(**membership)
    if (self.user and (str(user_id) == str(self.user.id))):
        self.s3_set_roles()
