Пример #1
0
    def deactivateApplet(self, folder):
        from girderformindlogger.models.profile import Profile

        applet = folder
        user = Applet().getCurrentUser()
        applet['meta']['applet']['deleted'] = True
        applet = AppletModel().setMetadata(applet, applet.get('meta'), user)
        if applet.get('meta', {}).get('applet', {}).get('deleted') == True:
            message = 'Successfully deactivated applet {} ({}).'.format(
                AppletModel().preferredName(applet), applet.get('_id'))

            users = list(Profile().find(
                {
                    'appletId': ObjectId(applet['_id']),
                    'deactivated': {
                        '$ne': True
                    }
                },
                fields=['userId']))
            Profile().deactivateProfile(applet['_id'], None)

            for user in users:
                if 'userId' in user:
                    UserModel().removeApplet(
                        UserModel().findOne({'_id': ObjectId(user['userId'])}),
                        applet['_id'])
        else:
            message = 'Could not deactivate applet {} ({}).'.format(
                AppletModel().preferredName(applet), applet.get('_id'))
            Description().errorResponse(message, 403)
        return (message)
Пример #2
0
    def _cacheProfileDisplay(self,
                             profile,
                             user,
                             forceManager=False,
                             forceReviewer=False):
        from girderformindlogger.models.applet import Applet
        profileDefinitions = self.cycleDefinitions(
            profile,
            showEmail=forceManager if forceManager else Applet().isCoordinator(
                profile['appletId'], user),
            showIDCode=forceReviewer if forceReviewer else
            Applet().isCoordinator(profile['appletId'], user))

        if 'invitedBy' in profile:
            profileDefinitions['invitedBy'] = self.cycleDefinitions(
                profile['invitedBy'], showEmail=False)

        if forceManager and not forceReviewer:
            profile['cachedDisplay']['manager'] = profileDefinitions
            self.save(profile, validate=False)
        elif forceReviewer:
            profile['cachedDisplay']['reviewer'] = profileDefinitions
            self.save(profile, validate=False)
        print(profileDefinitions)
        return (profileDefinitions)
Пример #3
0
def addApplet(new_user, protocolUrl):
    """
    adds an applet for the user, where the user becomes a manager for it.

    inputs
    ------

    new_user: a user oject (from testCreateUser)
    protocolURL: String, a valid URL to an activity set.

    returns
    -------
    applet response object

    """

    currentUser = authenticate(new_user)

    # TODO: create an activity-set that JUST for testing.
    # make sure it has all the weird qualities that can break

    userAppletsToStart = AppletModel().getAppletsForUser('manager',
                                                         currentUser,
                                                         active=True)

    userApplets = userAppletsToStart.copy()

    # for now, lets do the mindlogger demo
    protocol = ProtocolModel().getFromUrl(protocolUrl, 'protocol',
                                          currentUser)[0]
    randomAS = np.random.randint(1000000)
    ar = AppletModel().createAppletFromUrl(
        name="testProtocol{}".format(randomAS),
        protocolUrl=protocolUrl,
        user=currentUser,
        sendEmail=False)

    while len(userApplets) == len(userAppletsToStart):
        nightyNight(sleepInterval)
        userApplets = AppletModel().getAppletsForUser('manager',
                                                      currentUser,
                                                      active=True)

    ar = jsonld_expander.loadCache(userApplets[-1]['cached'])

    assert jsonld_expander.reprolibCanonize(
        ar['protocol']['url']
    ) == jsonld_expander.reprolibCanonize(protocolUrl), \
        'the URLS do not match! {} {}'.format(
            ar['protocol']['url'],
            protocolUrl
        )

    assert ar['applet']['_id'], 'there is no ID!'

    assert getAppletById(new_user,
                         ar) is not None, 'something wrong with getAppletById'
    return ar
Пример #4
0
 def deactivateApplet(self, folder):
     applet = folder
     user = Applet().getCurrentUser()
     applet['meta']['applet']['deleted'] = True
     applet = AppletModel().setMetadata(applet, applet.get('meta'), user)
     if applet.get('meta', {}).get('applet', {}).get('deleted') == True:
         message = 'Successfully deactivated applet {} ({}).'.format(
             AppletModel().preferredName(applet), applet.get('_id'))
     else:
         message = 'Could not deactivate applet {} ({}).'.format(
             AppletModel().preferredName(applet), applet.get('_id'))
         Description().errorResponse(message, 403)
     return (message)
Пример #5
0
    def coordinatorProfile(self, appletId, coordinator):
        from girderformindlogger.models.applet import Applet

        if isinstance(coordinator, dict) and "userId" not in coordinator:
            coordinator = self.createProfile(appletId, coordinator,
                                             "coordinator")
        return (self.cycleDefinitions(coordinator, showEmail=True)
                if Applet().isCoordinator(appletId, coordinator) else {})
    def getSchedule(self, applet, refreshCache=False):
        user = self.getCurrentUser()
        if refreshCache:
            thread = threading.Thread(target=jsonld_expander.formatLdObject,
                                      args=(applet, 'applet', user),
                                      kwargs={'refreshCache': refreshCache})
            thread.start()
            return ({
                "message":
                "The applet is being refreshed. Please check back "
                "in several mintutes to see it."
            })

        model = AppletModel()
        filterRequired = model._hasRole(
            applet['_id'], user,
            'user') if not model.isCoordinator(applet['_id'], user) else False
        schedule = model.filterScheduleEvents(
            applet.get('meta', {}).get('applet', {}).get('schedule', {}), user,
            filterRequired)

        return schedule
Пример #7
0
    def create(self, applet, user):
        """
        Create an Assignment for a given Applet, returning an existing
        Assignment if one or more exists.

        :param applet: The ID of the Applet for which to find Assignments.
        :type applet: str
        :param user: User
        :type user: User
        :returns: New Assignments
        """
        # validate Applet ID
        try:
            applet = Applet().load(id=applet, force=True)
        except:
            raise ValidationException(
                message='Invalid Applet ID',
                field='applet'
            )
        assignmentsCollection = Collection().findOne({'name': 'Assignments'})
        # for some reason below didn't work/help.. so I added Assignments manually.
        if not assignmentsCollection:
            Collection().createCollection('Assignments')
        try:
            assignment = Folder().createFolder(
                parent=assignmentsCollection, parentType='collection',
                name=Applet().preferredName(applet), creator=user,
                reuseExisting=True, public=False)
        except:
            assignmentsCollection = Folder().createFolder(
                parent=user, parentType='user', name='Assignments',
                creator=user, reuseExisting=True, public=False)
            assignment = Folder().createFolder(
                parent=assignmentsCollection, parentType='folder',
                name=Applet().preferredName(applet), creator=user,
                reuseExisting=True, public=False)
        return(assignment)
 def updateProfile(self, profileId, user, profileUpdate):
     from copy import deepcopy
     profile = self.load(profileId, force=True)
     if str(user["_id"] == profile["userId"]):
         update = deepcopy(profile.get("userDefined", {}))
         update.update(profileUpdate)
         profile["userDefined"] = update
     elif Applet().isCoordinator(profile["appletId"], user):
         update = deepcopy(profile.get("coordinatorDefined", {}))
         update.update(profileUpdate)
         profile["coordinatorDefined"] = update
     else:
         raise AccessException(
             "You do not have adequate permissions to update this profile.")
     return self.save(profile, validate=False)
Пример #9
0
    def accessToDuplicatedApplets(self, invitation, user, userEmail=''):
        from girderformindlogger.models.applet import Applet
        from girderformindlogger.models.user import User as UserModel
        duplicates = list(Applet().find(
            {'duplicateOf': ObjectId(invitation['appletId'])}))

        if 'inviterId' not in invitation:
            return

        for duplicate in duplicates:
            newInvitation = self.createInvitationForSpecifiedUser(
                duplicate,
                UserModel().load(invitation['inviterId'], force=True),
                invitation.get('role', 'user'), user,
                invitation.get('firstName',
                               ''), invitation.get('lastName', ''),
                invitation.get('MRN', ''), userEmail)

            self.acceptInvitation(self.load(newInvitation['_id'], force=True),
                                  user, userEmail)
Пример #10
0
    def findAssignments(self, applet):
        """
        Find all Assignments for a given Applet.

        :param applet: The ID of the Applet for which to find Assignments.
        :type applet: str
        :returns: list of Assignments
        """
        # validate Applet ID
        try:
            Applet().load(id=applet, force=True)
        except:
            raise ValidationException(
                message='Invalid Applet ID',
                field='applet'
            )
        allAssignments = [
            {
                '_id': a['_id'],
                '_modelType': 'collection'
            } for a in Collection().find({'name': 'Assignments'})
        ] + [
            {
                '_id': a['_id'],
                '_modelType': 'folder'
            } for a in Folder().find({'name': 'Assignments'})
        ]
        foundAssignments = Folder().find(
            {   '$and': [
                    {'$or': [
                        {'meta.applet.@id': str(applet)},
                        {'meta.applet.url': str(applet)}
                    ]},
                    {'$or': [
                        {'parentId': parent['_id']} for parent in allAssignments
                    ]}
                ]
            }
        )
        return(list(foundAssignments))
    def acceptInvitation(self, invitation, user):
        from girderformindlogger.models.applet import Applet
        from girderformindlogger.models.ID_code import IDCode
        from girderformindlogger.models.profile import Profile

        applet = Applet().load(invitation['appletId'], force=True)
        profiles = None
        if 'idCode' in invitation:
            profiles = IDCode().findProfile(invitation['idCode'])
        if profiles and len(profiles):
            profile = [
                pro for pro in profiles
                if str(pro.get('userId')) == str(user['_id'])
            ]
            profile = profile[0] if len(profile) else None
        else:
            profile = None
        if profiles == None or profile == None or not len(profile):
            profile = Profile().createProfile(applet,
                                              user,
                                              role=invitation.get(
                                                  'role', 'user'))
            IDCode().createIdCode(profile, invitation.get('idCode'))
        if 'schema:knows' in invitation:
            if 'schema:knows' not in profile:
                profile['schema:knows'] = invitation['schema:knows']
            else:
                for k in invitation['schema:knows']:
                    if k in profile['schema:knows']:
                        profile['schema:knows'][k].extend([
                            r for r in invitation['schema:knows'][k]
                            if r not in profile['schema:knows'][k]
                        ])
                    else:
                        profile['schema:knows'][k] = invitation[
                            'schema:knows'][k]
        Profile().save(profile, validate=False)
        self.remove(invitation)
        return (Profile().displayProfileFields(
            Profile().load(profile['_id'], force=True), user))
Пример #12
0
def _setConstraints(applet, activity, schedule, user, refreshCache=False):
    """
    Helper function for method recursion.

    :param applet: applet Object
    :type applet: dict
    :param activity: Activity ID
    :type activity: str, list, or None
    :param schedule: schedule data
    :type schedule: dict, list, or None
    :param user: user making the call
    :type user: dict
    :returns: updated applet Object
    """
    if activity is None:
        if schedule is not None:
            appletMeta = applet.get('meta', {})
            appletMeta['applet']['schedule'] = schedule
            applet = AppletModel().setMetadata(applet, appletMeta)
        return (applet)
    if isinstance(activity, str) and activity.startswith('['):
        try:
            activity = [
                activity_.replace("'", "").replace('"', '').strip()
                for activity_ in activity[1:-1].split(',')
            ]
        except (TypeError, AttributeError) as e:
            print(e)
    if isinstance(activity, list):
        for activity_ in activity:
            applet = _setConstraints(applet, activity_, schedule, user)
        return (applet)
    try:
        activityLoaded = ActivityModel().getFromUrl(activity, 'activity',
                                                    thisUser, refreshCache)[0]
    except:
        activityLoaded = ActivityModel().load(activity, AccessType.WRITE, user)
    try:
        activityMeta = activityLoaded['meta'].get('activity')
    except AttributeError:
        raise ValidationException('Invalid activity.', 'activity')
    activityKey = activityMeta.get(
        'url', activityMeta.get('@id', activityLoaded.get('_id')))
    if activityKey is None:
        raise ValidationException('Invalid activity.', 'activity')
    else:
        activityKey = jsonld_expander.reprolibPrefix(activityKey)
    protocolExpanded = jsonld_expander.formatLdObject(applet, 'applet',
                                                      user).get('applet', {})
    protocolOrder = protocolExpanded.get('ui', {}).get('order', [])
    framedActivityKeys = [
        protocolOrder[i] for i, v in enumerate(
            protocolExpanded.get("reprolib:terms/order")[0].get("@list"))
        if jsonld_expander.reprolibPrefix(v.get("@id")) == activityKey
    ]
    if schedule is not None:
        appletMeta = applet.get('meta', {})
        scheduleInApplet = appletMeta.get('applet', {}).get('schedule', {})
        for k in framedActivityKeys:
            scheduleInApplet[k] = schedule
        appletMeta['applet']['schedule'] = scheduleInApplet
        applet = AppletModel().setMetadata(applet, appletMeta)
    return (applet)
Пример #13
0
    def removeUser(self, group, user, delete=False):
        """
        Remove the user from the group. If the user is not in the group but
        has an outstanding invitation to the group, the invitation will be
        revoked. If the user has requested an invitation, calling this will
        deny that request, thereby deleting it.
        """
        from girderformindlogger.models.applet import Applet
        from girderformindlogger.models.folder import Folder
        from girderformindlogger.models.item import Item
        from girderformindlogger.models.user import User
        # Remove group membership for this user.
        if delete:
            # Get applets for group and delete data for applets
            [
                Folder().remove(
                    Folder().load(rf, force=True),
                    progress=None  # TODO: enable progress response
                ) for rf in list(
                    set(responseFolder['parentId'] for responseFolder in [
                        Folder().load(
                            folder,
                            fields=['_id', 'parentId', 'baseParentId'],
                            force=True)
                        for folder in list(
                            set(
                                item.get('folderId')
                                for item in list(Item().find(query={
                                    'meta.applet.@id': {
                                        '$in': [
                                            applet['_id'] for applet in
                                            Applet().getAppletsForGroup(
                                                'user', group.get(
                                                    '_id', group), False)
                                        ]
                                    },
                                    'baseParentType':
                                    'user',
                                    'baseParentId':
                                    user['_id']
                                },
                                                             fields=[
                                                                 'folderId'
                                                             ]))))
                    ] if responseFolder['baseParentId'] == user['_id']))
            ]
        if 'groups' in user and group['_id'] in user['groups']:
            if not delete:
                # if not deleting, save as a former group
                if 'formerGroups' in user and isinstance(
                        user['formerGroups'], list):
                    user['formerGroups'].append(group['_id'])
                else:
                    user['formerGroups'] = [group['_id']]
            user['groups'].remove(group['_id'])

        # Remove outstanding requests from this user
        self._deleteRequest(group, user)

        # Save as declined invitation
        user['declinedInvites'] = list(
            filter(lambda inv: inv['groupId'] == group['_id'],
                   user.get('groupInvites', [])))

        # Remove any outstanding invitations for this group
        user['groupInvites'] = list(
            filter(lambda inv: not inv['groupId'] == group['_id'],
                   user.get('groupInvites', [])))
        user = User().save(user, validate=False)

        # Remove all group access for this user on this group.
        self.setUserAccess(group, user, level=None, save=True)

        return (group)
Пример #14
0
    def htmlInvitation(self,
                       invitation,
                       invitee=None,
                       fullDoc=False,
                       includeLink=True):
        """
        Returns an HTML document rendering the invitation.

        :param invitation: Invitation to render
        :type invitation: dict
        :param invitee: Invited user
        :type invitee: dict or None

        :returns: html document
        """
        from girderformindlogger.models.applet import Applet
        from girderformindlogger.models.profile import Profile
        from girderformindlogger.models.protocol import Protocol
        from girderformindlogger.models.token import Token
        from girderformindlogger.models.user import User
        from girderformindlogger.exceptions import GirderException
        from girderformindlogger.api.rest import getApiUrl
        from girderformindlogger.utility import context as contextUtil,        \
            mail_utils

        web_url = os.getenv('WEB_URI') or 'localhost:8082'

        accept = ("To accept or decline, visit <a href=\"{u}\">{u}</a>".format(
            u=f"https://{web_url}/#/invitation/{str(invitation['_id'])}")
                  ) if includeLink else ""
        applet = Applet().load(ObjectId(invitation['appletId']), force=True)
        appletName = applet['meta']['applet'].get(
            'displayName', applet.get('displayName', 'new applet'))
        try:
            skin = contextUtil.getSkin()
        except:
            skin = {}
        instanceName = skin.get("name", "MindLogger")
        role = invitation.get("role", "user")
        try:
            coordinator = Profile().coordinatorProfile(applet['_id'],
                                                       invitation["invitedBy"])
        except:
            coordinator = None
        displayProfile = Profile().displayProfileFields(invitation, invitee)
        description = applet.get('meta', {}).get('applet', {}).get(
            "schema:description",
            Protocol().load(
                applet['meta']['protocol']['_id'].split('protocol/')[-1],
                force=True).get('meta', {}).get('protocol') if 'protocol'
            in applet.get('meta', {}) else {}).get("schema:description", "")
        managers = mail_utils.htmlUserList(Applet().listUsers(applet,
                                                              'manager',
                                                              force=True))
        coordinators = mail_utils.htmlUserList(Applet().listUsers(
            applet, 'coordinator', force=True))
        reviewers = mail_utils.htmlUserList(Applet().listUsers(applet,
                                                               'reviewer',
                                                               force=True))

        body = mail_utils.renderTemplate(
            f'welcome{"Owner" if role == "owner" else ""}.{invitation.get("lang", "en")}.mako',
            {
                'accept':
                accept,
                'appletName':
                appletName,
                'byCoordinator':
                "by {} ({}) ".format(
                    coordinator.get("displayName", "an anonymous entity"),
                    "<a href=\"mailto:{email}\">{email}</a>".format(
                        email=coordinator["email"]) if "email" in coordinator
                    and coordinator["email"] is not None
                    else "email not available") if isinstance(
                        coordinator, dict) else "",
                'coordinators':
                "{}".format(coordinators if len(coordinators) else
                            "<ul><li>None</li></ul>"),
                'instanceName':
                " on {}".format(instanceName)
                if instanceName is not None and len(instanceName) else "",
                'managers':
                "{}".format(
                    managers if len(managers) else "<ul><li>None</li></ul>"),
                'reviewers':
                "{}".format(
                    reviewers if len(reviewers) else "<ul><li>None</li></ul>"),
                'role':
                "an editor" if role == "editor" else "a {}".format(role),
                'url':
                f'https://{web_url}/#/invitation/{str(invitation["_id"])}'
            })

        return (body if not fullDoc else """
            <!DOCTYPE html>
            <html>
            <head>
            <meta charset="UTF-8">
            <title>Invitation to {appletName} on {instanceName}</title>
            </head>
            <body>
            {body}
            </body>
            </html>
        """.format(appletName=appletName, instanceName=instanceName,
                   body=body).strip())
Пример #15
0
    def generateMissing(self, applet):
        """
        Helper function to generate profiles for users that predate this class.
        To be threaded unless no users with profiles exist.

        :param applet: Applet to get users for.
        :type applet: dict
        :returns: list of dicts
        """
        from girderformindlogger.models.applet import Applet
        from girderformindlogger.models.user import User as UserModel

        # get groups for applet
        appletGroups = Applet().getAppletGroups(applet)

        userList = {
            role: {
                groupId: {
                    'active':
                    list(UserModel().find(
                        query={"groups": {
                            "$in": [ObjectId(groupId)]
                        }},
                        fields=['_id']))
                }
                for groupId in appletGroups[role].keys()
            }
            for role in appletGroups.keys()
        }

        # restructure dictionary & return
        userList = {
            str(ulu["user"]["_id"]): {
                k: v
                for k, v in {
                    "displayName":
                    ulu["user"].get("coordinatorDefined", {}).get(
                        "displayName", ulu["user"].get("userDefined", {}).get(
                            "displayName", ulu["user"].get("displayName"))),
                    "groups":
                    ulu.get("groups")
                }.items() if v is not None
            }
            for ulu in [{
                "user":
                self.createProfile(
                    applet,
                    UserModel().load(user, AccessType.READ, force=True)),
                "groups": [{
                    "_id": groupId,
                    "name": appletGroups[role][groupId],
                    "status": status,
                    "role": role
                } for role in userList for groupId in userList[role]
                           for status in userList[role][groupId]]
            } for user in set([
                ui.get('_id')
                for u in (userList[role][groupId][status] for role in userList
                          for groupId in userList[role]
                          for status in userList[role][groupId]) for ui in u
            ])]
        }
        return (userList)
Пример #16
0
    def createProfile(self, applet, user, role="user"):
        """
        Create a new profile to store information specific to a given (applet ∩
            user)

        :param applet: The applet for which this profile exists
        :type applet: dict
        :param user: The user for which this profile exists
        :type user: dict
        :returns: The profile document that was created.
        """
        from girderformindlogger.models.applet import Applet
        from girderformindlogger.models.group import Group

        if not isinstance(applet, dict):
            applet = Applet().load(applet, force=True)
        user = self._canonicalUser(applet["_id"], user)
        returnFields = ["_id", "appletId", "coordinatorDefined", "userDefined"]
        existing = self.findOne(
            {
                'appletId': applet['_id'],
                'userId': user['_id'],
                'profile': True
            },
            fields=[*returnFields, "deactivated"])

        if applet['_id'] not in [
                a.get('_id') for a in Applet().getAppletsForUser(role, user)
        ]:
            appletGroups = Applet().getAppletGroups(applet)

            roles = ['user', 'editor', 'reviewer', 'coordinator', 'manager'
                     ] if role == 'manager' else [role]
            if 'user' not in roles:
                roles.append('user')

            for role in roles:
                groups = appletGroups.get(role)
                if bool(groups):
                    group = Group().load(ObjectId(list(groups.keys())[0]),
                                         force=True)

                    if group['_id'] not in user.get('groups', []):
                        Group().inviteUser(group, user, level=AccessType.READ)
                        Group().joinGroup(group, user)
                else:
                    raise ValidationException(
                        "User does not have role \"{}\" in this \"{}\" applet "
                        "({})".format(role,
                                      Applet().preferredName(applet),
                                      str(applet['_id'])))

        if existing and not existing.get('deactivated', False):
            if "deactivated" in existing:
                existing.pop("deactivated")

            return existing

        now = datetime.datetime.utcnow()

        managers = list(
            self.find(query={
                'appletId': applet['_id'],
                'roles': 'manager'
            },
                      fields=['_id']))
        profile = {
            k: v
            for k, v in {
                'appletId':
                ObjectId(applet['_id']),
                'userId':
                ObjectId(user['_id']),
                'profile':
                True,
                'badge':
                0,
                'created':
                now,
                'updated':
                now,
                'deviceId':
                user['deviceId'],
                'timezone':
                user['timezone'],
                'individual_events':
                0,
                'completed_activities': [{
                    'activity_id': activity_id,
                    'completed_time': None
                } for activity_id in applet.get('meta', {}).get(
                    'protocol', {}).get('activities', [])],
                'accountId':
                applet.get('accountId', None),
                'size':
                0,
                'coordinatorDefined': {},
                'userDefined': {
                    'displayName':
                    user.get('displayName', user.get('firstName')),
                    'email':
                    user.get('email'
                             ) if not user.get('email_encrypted', None) else ''
                },
                'reviewers': [manager['_id'] for manager in managers]
            }.items() if v is not None
        }

        if existing:
            profile['_id'] = existing['_id']

        self.setPublic(profile, False, save=False)

        # Save the profile.
        self.save(profile, validate=False)
        return ({k: v for k, v in profile.items() if k in returnFields})
Пример #17
0
    def hasAccess(self, doc, user=None, level=AccessType.READ):
        """
        This overrides the default AccessControlledModel behavior for checking
        access to perform an optimized subset of the access control behavior.

        :param doc: The group to check permission on.
        :type doc: dict
        :param user: The user to check against.
        :type user: dict
        :param level: The access level.
        :type level: AccessType
        :returns: Whether the access is granted.
        """
        import itertools
        from girderformindlogger.models.applet import Applet
        from girderformindlogger.models.user import User
        from girderformindlogger.constants import USER_ROLES

        if user is None:
            # Short-circuit the case of anonymous users
            return (level == AccessType.READ
                    and doc.get('public', False) is True)
        elif user.get('_id') in [
                u.get('_id') for u in list(User().find({
                    'groups': {
                        '$in':
                        list(
                            set([
                                g.get('id') for g in [
                                    *list(
                                        itertools.chain.from_iterable([
                                            mgr.get('roles', {}).get(
                                                'manager', {}).get(
                                                    'groups', [])
                                            for mgr in [
                                                *list(
                                                    itertools.chain.
                                                    from_iterable([
                                                        list(Applet().find({
                                                            'roles.{}.groups.id'.format(role):
                                                            doc.get('_id')
                                                        })) for role in list(
                                                            USER_ROLES.keys())
                                                    ]))
                                            ]
                                        ]))
                                ]
                            ]))
                    }
                }))
        ]:
            # Short-circuit the case of admins and managers
            return (True)
        elif level == AccessType.READ:
            # Short-circuit in the case of members without write access to the
            # group
            if not self.getAccessLevel(doc, user) > 1:
                return (False)
            # For read access, just check user document for membership or public
            return (doc.get('public', False) is True
                    or doc['_id'] in user.get('groups', []) or doc['_id']
                    in [i['groupId'] for i in user.get('groupInvites', [])])
        else:
            # Check the actual permissions document for >=WRITE access
            return (self._hasUserAccess(
                doc.get('access', {}).get('users', []), user['_id'], level))
    def createProfile(self, applet, user, role="user"):
        """
        Create a new profile to store information specific to a given (applet ∩
            user)

        :param applet: The applet for which this profile exists
        :type applet: dict
        :param user: The user for which this profile exists
        :type user: dict
        :returns: The profile document that was created.
        """
        from girderformindlogger.models.applet import Applet
        from girderformindlogger.models.group import Group

        if not isinstance(applet, dict):
            applet = Applet().load(applet, force=True)
        user = self._canonicalUser(applet["_id"], user)
        returnFields = ["_id", "appletId", "coordinatorDefined", "userDefined"]
        existing = self.findOne(
            {
                'appletId': applet['_id'],
                'userId': user['_id'],
                'profile': True
            },
            fields=returnFields)

        if existing:
            return existing

        if applet['_id'] not in [
                a.get('_id') for a in Applet().getAppletsForUser(role, user)
        ]:
            groups = Applet().getAppletGroups(applet).get(role)
            if bool(groups):
                group = Group().load(ObjectId(list(groups.keys())[0]),
                                     force=True)
                Group().inviteUser(group, user, level=AccessType.READ)
                Group().joinGroup(group, user)
            else:
                raise ValidationException(
                    "User does not have role \"{}\" in this \"{}\" applet "
                    "({})".format(role,
                                  Applet().preferredName(applet),
                                  str(applet['_id'])))

        now = datetime.datetime.utcnow()

        profile = {
            k: v
            for k, v in {
                'appletId': ObjectId(applet['_id']),
                'userId': ObjectId(user['_id']),
                'profile': True,
                'created': now,
                'updated': now,
                'size': 0,
                'coordinatorDefined': {},
                'userDefined': {
                    'displayName': user.get('displayName', user.get(
                        'firstName')),
                    'email': user.get('email')
                }
            }.items() if v is not None
        }

        self.setPublic(profile, False, save=False)

        # Save the profile.
        self.save(profile, validate=False)
        return ({k: v for k, v in profile.items() if k in returnFields})
Пример #19
0
    def createInvitation(
        self,
        applet,
        coordinator,
        role="user",
        profile=None,
        idCode=None
    ):
        """
        Create a new invitation to store information specific to a given (applet
            ∩ (ID code ∪ profile))

        :param applet: The applet for which this invitation exists
        :type parent: dict
        :param coordinator: user who is doing the inviting
        :type coordinator: dict
        :param profile: Profile to apply to (applet ∩ user) if the invitation is
            accepted
        :type profile: dict or none
        :param idCode: ID code to apply to (applet ∩ user) if invitation is
            accepted
        :type idCode: string or None
        :returns: The invitation document that was created.
        """
        from girderformindlogger.models.applet import Applet
        from girderformindlogger.models.profile import Profile

        if not(Applet().isCoordinator(applet['_id'], coordinator)):
            raise AccessException(
                'You do not have adequate permissions to invite users to this '
                'applet ({}).'.format(Applet().preferredName(applet))
            )

        codified = (isinstance(idCode, str) and len(idCode))

        existing = self.findOne({
            'appletId': applet['_id'],
            'idCode': idCode
        }) if codified else None

        if existing:
            return existing

        now = datetime.datetime.utcnow()

        invitation = {
            'appletId': applet['_id'],
            'created': now,
            'updated': now,
            'role': role,
            'size': 0,
            'invitedBy': Profile().coordinatorProfile(
                applet['_id'],
                coordinator
            )
        }

        if codified:
            invitation["idCode"] = idCode

        if isinstance(profile, dict):
            invitation["coordinatorDefined"] = profile

        self.setPublic(invitation, False, save=False)

        # Now validate and save the profile.
        return ({
            k: v for k, v in self.save(invitation, validate=False).items() if (
                k!="idCode" and v is not None
            )
        })
Пример #20
0
    def htmlInvitation(
        self,
        invitation,
        invitee=None,
        fullDoc=False,
        includeLink=True
    ):
        """
        Returns an HTML document rendering the invitation.

        :param invitation: Invitation to render
        :type invitation: dict
        :param invitee: Invited user
        :type invitee: dict or None

        :returns: html document
        """
        from girderformindlogger.models.applet import Applet
        from girderformindlogger.models.profile import Profile
        from girderformindlogger.models.protocol import Protocol
        from girderformindlogger.models.token import Token
        from girderformindlogger.models.user import User
        from girderformindlogger.exceptions import GirderException
        from girderformindlogger.api.rest import getApiUrl
        from girderformindlogger.utility import context as contextUtil,        \
            mail_utils

        accept = (
            "To accept or decline, visit <a href=\"{u}\">{u}</a>".format(
                u="https://web.mindlogger.org/#/invitation/{}".format(str(
                    invitation['_id']
                ))
            )
        ) if includeLink else ""
        applet = Applet().load(ObjectId(invitation['appletId']), force=True)
        appletName = applet.get(
            'displayName',
            'a new applet'
        )
        try:
            skin = contextUtil.getSkin()
        except:
            skin = {}
        instanceName = skin.get("name", "MindLogger")
        role = invitation.get("role", "user")
        try:
            coordinator = Profile().coordinatorProfile(
                applet['_id'],
                invitation["invitedBy"]
            )
        except:
            coordinator = None
        displayProfile = Profile().displayProfileFields(invitation, invitee)
        description = applet.get('meta', {}).get(
            'applet',
            {}
        ).get(
            "schema:desciription",
            Protocol().load(
                applet['meta']['protocol']['_id'].split('protocol/')[-1],
                force=True
            ).get('meta', {}).get('protocol') if 'protocol' in applet.get(
                'meta',
                {}
            ) else {}
        ).get("schema:description", "")
        managers = mail_utils.htmlUserList(
            Applet().listUsers(applet, 'manager', force=True)
        )
        coordinators = mail_utils.htmlUserList(
            Applet().listUsers(applet, 'coordinator', force=True)
        )
        reviewers = mail_utils.htmlUserList(
            Applet().listUsers(applet, 'reviewer', force=True)
        )
        body = """
{greeting}ou were invited {byCoordinator}to be {role} of <b>{appletName}</b>{instanceName}.
<br/>
Below are the users that have access to your data:
{reviewers}
{managers}
{coordinators}
<br/>
{accept}
        """.format(
            accept=accept,
            appletName=appletName,
            byCoordinator="by {} ({}) ".format(
                coordinator.get("displayName", "an anonymous entity"),
                "<a href=\"mailto:{email}\">{email}</a>".format(
                    email=coordinator["email"]
                ) if "email" in coordinator and coordinator["email"] is not None else "email not available"
            ) if isinstance(coordinator, dict) else "",
            coordinators="<h3>Users who can change this applet's settings, "
                "but who cannot change who can see your data: </h3>{}"
                "".format(
                    coordinators if len(
                        coordinators
                    ) else "<ul><li>None</li></ul>"
                ),
            greeting="Welcome to MindLogger! Y",
            instanceName=" on {}".format(
                instanceName
            ) if instanceName is not None and len(instanceName) else "",
            managers="<h3>Users who can change this applet's settings, "
                " including who can access your data: </h3>{}"
                "".format(
                    managers if len(managers) else "<ul><li>None</li></ul>"
                ),
            reviewers="<h3>Users who can see your data for this "
                "applet: </h3>{}"
                "".format(
                    reviewers if len(reviewers) else "<ul><li>None</li></ul>"
                ),
            role="an editor" if role=="editor" else "a {}".format(role)
        ).strip()
        return(body if not fullDoc else """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Invitation to {appletName} on {instanceName}</title>
</head>
<body>
{body}
</body>
</html>
        """.format(
            appletName=appletName,
            instanceName=instanceName,
            body=body
        ).strip())
Пример #21
0
    def acceptInvitation(self, invitation, user, userEmail = ''): # we need to save coordinator/manager's email as plain text
        from girderformindlogger.models.applet import Applet
        from girderformindlogger.models.ID_code import IDCode
        from girderformindlogger.models.profile import Profile
        from girderformindlogger.utility import mail_utils

        applet = Applet().load(invitation['appletId'], force=True)
        profiles = None
        if 'idCode' in invitation:
            profiles = IDCode().findProfile(invitation['idCode'])
        if profiles and len(profiles):
            profile = [
                pro for pro in profiles if str(
                    pro.get('userId')
                )==str(user['_id'])
            ]
            profile = profile[0] if len(profile) else None
        else:
            profile = None
            Profile().removeWithQuery({ '_id': ObjectId(invitation['_id']) })

        if profile==None or not len(profile):
            profile = Profile().createProfile(
                applet,
                user,
                role=invitation.get('role', 'user')
            )
            IDCode().createIdCode(profile, invitation.get('idCode'))
        if 'schema:knows' in invitation:
            if 'schema:knows' not in profile:
                profile['schema:knows'] = invitation['schema:knows']
            else:
                for k in invitation['schema:knows']:
                    if k in profile['schema:knows']:
                        profile['schema:knows'][k].extend([
                            r for r in invitation['schema:knows'][
                                k
                            ] if r not in profile['schema:knows'][k]
                        ])
                    else:
                        profile['schema:knows'][k] = invitation['schema:knows'][
                            k
                        ]

        # append role value
        profile = Profile().load(profile['_id'], force=True)
        profile['roles'] = profile.get('roles', [])
        invited_role = invitation.get('role','user')

        new_roles = []
        # manager has get all roles by default
        for role in USER_ROLES.keys():
            if role not in profile['roles']:
                if invited_role == 'manager' or invited_role == role or role == 'user':
                    new_roles.append(role)
                    profile['roles'].append(role)

        profile['firstName'] = invitation.get('firstName', '')
        profile['lastName'] = invitation.get('lastName', '')
        profile['MRN'] = invitation.get('MRN', '')

        Profile().save(profile, validate=False)

        from girderformindlogger.models.user import User as UserModel
        
        if not mail_utils.validateEmailAddress(userEmail):
            raise ValidationException(
                'Invalid email address.',
                'email'
            )
        if invited_role != 'user' and user.get('email_encrypted', False):
            if UserModel().hash(userEmail) != user['email']:
                raise ValidationException(
                    'Invalid email address.',
                    'email'
                )
            user['email'] = userEmail
            user['email_encrypted'] = False

            UserModel().save(user)

        UserModel().appendApplet(user, applet['_id'], new_roles)

        self.remove(invitation)        
        return(Profile().displayProfileFields(
            Profile().load(profile['_id'], force=True),
            user
        ))