def inferRelationships(person): from girderformindlogger.models.invitation import Invitation from girderformindlogger.models.profile import Profile if "schema:knows" not in person: return (person) start = deepcopy(person) for rel in list(person['schema:knows'].keys()): if rel in DEFINED_RELATIONS.keys(): if "owl:equivalentProperty" in DEFINED_RELATIONS[rel]: for ep in DEFINED_RELATIONS[rel]["owl:equivalentProperty"]: if ep not in person['schema:knows']: person['schema:knows'][ep] = [] for related in person['schema:knows'][rel]: if related not in person['schema:knows'][ep]: person['schema:knows'][ep].append(related) if any([ bool(rp not in start.get('schema:knows', {}).get(rel, [])) for rp in person['schema:knows'][rel] for rel in list(person['schema:knows'].keys()) ]): newPerson = Profile().load(person['_id'], force=True) if 'schema:knows' in newPerson: newPerson['schema:knows'].update(person['schema:knows']) else: newPerson['schema:knows'] = person['schema:knows'] Profile().save( newPerson, validate=False) if 'userId' in newPerson else Invitation().save( newPerson, validate=False) return (person)
def listUsers(self, applet, role, user=None, force=False): from .profile import Profile if not force: if not any([ self.isCoordinator(applet['_id'], user), self._hasRole(applet['_id'], user, 'reviewer') ]): return ([]) userlist = { p['_id']: Profile().display(p, role) for p in list(Profile().find({ 'appletId': applet['_id'], 'userId': { '$in': [ user['_id'] for user in list(UserModel().find({ 'groups': { '$in': [ ObjectId(group) for group in self.getAppletGroups( applet).get(role, {}).keys() ] } })) ] } })) } return (userlist)
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)
def removeCode(self, profileId, code): from girderformindlogger.models.profile import Profile idCode = self.findOne({'profileId': ObjectId(profileId), 'code': code}) if idCode is not None: self.remove(idCode) if not len(self.findIdCodes(profileId)): self.createIdCode(Profile().load(profileId, force=True)) return (Profile().load(profileId, force=True))
def getAppletUsers(self, applet, user=None, force=False): """ Function to return a list of Applet Users :param applet: Applet to get users for. :type applet: dict :param user: User making request :type user: dict :returns: list of dicts """ from .invitation import Invitation from .profile import Profile profileFields = ["_id", "coordinatorDefined", "userDefined"] try: if not isinstance(user, dict): user = UserModel().load( id=user, level=AccessType.READ, force=True) if isinstance( user, str) else {} if not force: if not self.isCoordinator(applet.get('_id', applet), user): return ([]) userDict = { 'active': [ Profile().displayProfileFields(p, user, forceManager=True) for p in list(Profile().find( query={'appletId': applet['_id']})) ], 'pending': [ Profile().displayProfileFields(p, user, forceManager=True) for p in list(Invitation().find( query={'appletId': applet['_id']})) ] } missing = threading.Thread(target=Profile().generateMissing, args=(applet, )) missing.start() if len(userDict['active']): return (userDict) else: return ({**userDict, "message": "cache updating"}) except: import sys, traceback print(sys.exc_info()) return ({traceback.print_tb(sys.exc_info()[2])})
def filterScheduleEvents(self, schedule, user, filterRequired, profilesCache={}): from girderformindlogger.models.profile import Profile if filterRequired and 'events' in schedule: events = [] for event in schedule['events']: notForCurrentUser = '******' in event if 'users' in event: for appletUser in event['users']: if appletUser not in profilesCache: userData = Profile().findOne( query={'_id': ObjectId(appletUser)}, fields=['userId']) if userData and 'userId' in userData: profilesCache[appletUser] = userData['userId'] if profilesCache.get(appletUser, '') == user['_id']: notForCurrentUser = False break if not notForCurrentUser: events.append(event) if len(events): newSchedule = schedule.copy() newSchedule['events'] = events return newSchedule else: return {} return schedule
def getSchedule(currentUser, timezone=None): from girderformindlogger.models.profile import Profile schedule = {} accounts = AccountProfile().getAccounts(currentUser['_id']) applets = [] for account in accounts: for applet in account.get('applets', {}).get('user', []): applets.append(applet) for appletId in applets: profile = Profile().findOne({ 'appletId': appletId, 'userId': currentUser['_id'] }) activities = profile['completed_activities'] appletSchedule = {} for activity in activities: appletSchedule['activity/{}'.format(activity['activity_id'])] = { 'lastResponse': None if not activity['completed_time'] else activity['completed_time'].astimezone( pytz.timezone(timezone)).isoformat() if (isinstance(timezone, str) and timezone in pytz.all_timezones) else activity['completed_time'].isoformat() #, # 'nextScheduled': None, # 'lastScheduled': None } schedule['applet/{}'.format(appletId)] = appletSchedule return schedule
def getScheduleForUser(self, applet_id, user_id, is_coordinator): if is_coordinator: individualized = False else: profile = Profile().findOne({ 'appletId': ObjectId(applet_id), 'userId': ObjectId(user_id) }) individualized = self.hasIndividual(applet_id, profile['_id']) events = self.getEvents(applet_id, individualized) for event in events: event['id'] = event['_id'] event.pop('_id') return { "type": 2, "size": 1, "fill": True, "minimumSize": 0, "repeatCovers": True, "listTimes": False, "eventsOutside": True, "updateRows": True, "updateColumns": False, "around": 1585724400000, 'events': events }
def createInvitationForSpecifiedUser( self, applet, coordinator, role, user, firstName, lastName, MRN, userEmail = "" ): """ create new invitation params applet: The applet for which this invitation exists coordinator: the person who invites (should be manager/coordinator of applet) role: invited role user: invited person displayName: name of invited person """ from girderformindlogger.models.applet import Applet from girderformindlogger.models.profile import Profile query = {'appletId': applet['_id']} if user: query['userId'] = user['_id'] else: query['userEmail'] = userEmail invitation = self.findOne(query) now = datetime.datetime.utcnow() if not invitation: invitation = { 'appletId': applet['_id'], 'created': now } if user: invitation['userId'] = user['_id'] invitation.update({ 'inviterId': coordinator['_id'], 'role': role, 'firstName': firstName, 'lastName': lastName, 'MRN': MRN, 'updated': now, 'size': 0, 'userEmail': userEmail, 'invitedBy': Profile().coordinatorProfile( applet['_id'], coordinator ) }) return self.save(invitation, validate=False)
def _hasRole(self, appletId, user, role): from .profile import Profile user = Profile()._canonicalUser(appletId, user) return (bool( str(appletId) in [ str(applet.get('_id')) for applet in self.getAppletsForUser(role, user) if applet.get('_id') is not None ]))
def _hasRole(self, appletId, user, role): from girderformindlogger.models.profile import Profile user = Profile()._canonicalUser(appletId, user) return (bool( str(appletId) in [ str(applet.get('_id')) for applet in self.getAppletsForUser(role, user, idOnly=True) if applet.get('_id') is not None ]))
def isCoordinator(self, appletId, user): from .profile import Profile try: user = Profile()._canonicalUser(appletId, user) return (any([ self._hasRole(appletId, user, 'coordinator'), self.isManager(appletId, user) ])) except: return (False)
def load(self, id, level=AccessType.ADMIN, user=None, objectId=True, force=False, fields=None, exc=False): """ Calls AccessControlMixin.load while doing some auto-correction. Takes the same parameters as :py:func:`girderformindlogger.models.model_base.AccessControlMixin.load` """ from girderformindlogger.models.profile import Profile # Ensure we include extra fields to do the migration below extraFields = { 'baseParentId', 'baseParentType', 'parentId', 'parentCollection', 'code' } loadFields = self._supplementFields(fields, extraFields) doc = super(IDCode, self).load(id=id, level=level, user=user, objectId=objectId, force=force, fields=loadFields, exc=exc) if doc is not None: if 'baseParentType' not in doc: pathFromRoot = self.parentsToRoot(doc, user=user, force=True) baseParent = pathFromRoot[0] doc['baseParentId'] = baseParent['object']['_id'] doc['baseParentType'] = baseParent['type'] self.update({'_id': doc['_id']}, { '$set': { 'baseParentId': doc['baseParentId'], 'baseParentType': doc['baseParentType'] } }) if 'code' not in doc: doc['code'] = self.generateCode(Profile().load(doc["parentId"], force=True)) self.update({'_id': doc['_id']}, {'$set': { 'code': doc['code'] }}) self._removeSupplementalFields(doc, fields) return doc
def childByParent(parent, applet, parentProfile=None): from girderformindlogger.models.profile import Profile parentProfile = Profile().getProfile( Profile().createProfile( applet['applet']['_id'].split('applet/')[-1], parent, "user" ).get('_id'), user=parent ) if parentProfile is None else parentProfile parentKnows = parentProfile.get('schema:knows', {}) children = [Profile().displayProfileFields( Profile().load( p, force=True ), parent ) for p in list( set(parentKnows.get('rel:parentOf', {})).union( set(parentKnows.get('schema:children', {})) ) ) ] return([ formatChildApplet(child, deepcopy(applet)) for child in children ])
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))
def updateIndividualSchedulesParameter(self, newEvent, oldEvent): new = newEvent['data']['users'] if 'users' in newEvent['data'] else [] old = newEvent['data']['users'] if oldEvent else [] dicrementedUsers = list(set(old).difference(set(new))) incrementedUsers = list(set(new).difference(set(old))) if len(dicrementedUsers): Profile().update(query={"_id": { "$in": dicrementedUsers }}, update={'$inc': { 'individual_events': -1 }}) if len(incrementedUsers): Profile().update(query={"_id": { "$in": incrementedUsers }}, update={'$inc': { 'individual_events': 1 }})
def findIdCodes(self, profileId): from girderformindlogger.models.profile import Profile idCodes = [ i['code'] for i in list( self.find({ 'profileId': { '$in': [str(profileId), ObjectId(profileId)] } })) if isinstance(i, dict) and 'code' in i ] if not len(idCodes): self.createIdCode(Profile().load(profileId, force=True)) return (self.findIdCodes(profileId)) return (idCodes)
def invite(self, applet, role="user", idCode=None, profile=None): from girderformindlogger.models.invitation import Invitation from girderformindlogger.models.profile import Profile user = self.getCurrentUser() try: if role not in USER_ROLE_KEYS: raise ValidationException('Invalid role.', 'role') invitation = Invitation().createInvitation(applet=applet, coordinator=user, role=role, profile=profile, idCode=idCode) return (Profile().displayProfileFields(invitation, user)) except: import sys, traceback print(sys.exc_info())
def getResponseData(self, appletId, reviewer, filter={}): """ Function to collect response data available to given reviewer. :param appletId: ID of applet for which to get response data :type appletId: ObjectId or str :param reviewer: Reviewer making request :type reviewer: dict :param filter: reduction criteria (not yet implemented) :type filter: dict :reutrns: TBD """ from .ID_code import IDCode from .profile import Profile from .response_folder import ResponseItem from .user import User from pymongo import DESCENDING if not self._hasRole(appletId, reviewer, 'reviewer'): raise AccessException("You are not a reviewer for this applet.") query = { "baseParentType": "user", "meta.applet.@id": ObjectId(appletId) } responses = list(ResponseItem().find(query=query, user=reviewer, sort=[("created", DESCENDING)])) respondents = { str(response['baseParentId']): IDCode().findIdCodes(Profile().createProfile( appletId, User().load(response['baseParentId'], force=True), 'user')['_id']) for response in responses if 'baseParentId' in response } return ([{ "respondent": code, **response.get('meta', {}) } for response in responses for code in respondents[str(response['baseParentId'])]])
def findProfile(self, idCode): """ Find a list of profiles for a given ID code. """ existing = list(self.find({'code': idCode})) if len(existing): from girderformindlogger.models.profile import Profile ps = [ Profile().load(exist['profileId'], force=True) for exist in existing ] if len(ps): return (ps) else: from girderformindlogger.models.invitation import Invitation existing = list(self.find({'idCode': idCode})) ps = [ Invitation().load(exist['_id'], force=True) for exist in existing ] if len(ps): return (ps) return (None)
def inviteUserToApplet(user, appletObject, userB): """ invite a user to an applet inputs ------ user: a user object appletObject: userB: a user object of a user you want to invite. If they aren't defined yet, it should be a dict(email="emailaddress") """ groupId = appletObject['roles']['user']['groups'][0]['id'] currentUser = authenticate(user) group = Group().load(id=ObjectId(groupId), force=True) invitation = Invitation().createInvitation(appletObject, currentUser, role="user", profile=Profile().createProfile( appletObject, userB), idCode=None) return Group().inviteUser(group, userB, level=AccessType.READ)
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 ) })
def getAppletUsers(self, applet, user=None, force=False): """ Function to return a list of Applet Users :param applet: Applet to get users for. :type applet: dict :param user: User making request :type user: dict :returns: list of dicts """ from girderformindlogger.models.invitation import Invitation from girderformindlogger.models.profile import Profile profileFields = ["_id", "coordinatorDefined", "userDefined"] try: if not isinstance(user, dict): user = UserModel().load( id=user, level=AccessType.READ, force=True) if isinstance( user, str) else {} if not force: if not self.isCoordinator(applet.get('_id', applet), user): return ([]) profileModel = Profile() userDict = { 'active': [ profileModel.displayProfileFields(p, user, forceManager=True) for p in list( profileModel.find( query={ 'appletId': applet['_id'], 'userId': { '$exists': True }, 'profile': True, 'deactivated': { '$ne': True } })) ], 'pending': [] } for p in list( Invitation().find(query={'appletId': applet['_id']})): fields = [ '_id', 'firstName', 'lastName', 'role', 'MRN', 'created' ] userDict['pending'].append( {key: p[key] for key in fields if p.get(key, None)}) missing = threading.Thread(target=profileModel.generateMissing, args=(applet, )) missing.start() if len(userDict['active']): return (userDict) else: return ({**userDict, "message": "cache updating"}) except: import sys, traceback print(sys.exc_info()) return ({traceback.print_tb(sys.exc_info()[2])})
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())
def getScheduleForUser(self, applet_id, user_id, dayFilter=None): profile = Profile().findOne({ 'appletId': ObjectId(applet_id), 'userId': ObjectId(user_id) }) individualized = profile['individual_events'] > 0 events = self.getEvents(applet_id, individualized, profile['_id']) lastEvent = {} onlyScheduledDay = {} for event in events: event['id'] = event['_id'] event.pop('_id') event['valid'] = True if dayFilter: event['valid'], lastAvailableTime = self.dateMatch( event, dayFilter) activityId = event.get('data', {}).get('activity_id', None) if not activityId: event['valid'] = False continue if not event['valid']: if lastAvailableTime: if activityId not in lastEvent or ( lastEvent[activityId] and lastAvailableTime > lastEvent[activityId][0]): lastEvent[activityId] = (lastAvailableTime, event) else: lastEvent[activityId] = None if event['data'].get('eventType', None) and event['data'].get( 'onlyScheduledDay', False): onlyScheduledDay[activityId] = True return { "type": 2, "size": 1, "fill": True, "minimumSize": 0, "repeatCovers": True, "listTimes": False, "eventsOutside": True, "updateRows": True, "updateColumns": False, "around": 1585724400000, 'events': ([event for event in events if event['valid']] + [ value[1] for value in lastEvent.values() if value and (value[1]['data'].get('completion', False) or value[1] ['data'].get('activity_id', None) in onlyScheduledDay) ]) }
def updateUserCache(self, role, user, active=True, refreshCache=False): import threading from bson import json_util from girderformindlogger.models.profile import Profile from girderformindlogger.utility import jsonld_expander applets = self.getAppletsForUser(role, user, active) user['cached'] = user.get('cached', {}) user['cached'] = json_util.loads(user['cached']) if isinstance( user['cached'], str) else user['cached'] user['cached']['applets'] = user['cached'].get('applets', {}) user['cached']['applets'][role] = user['cached']['applets'].get( role, {}) formatted = [{ **jsonld_expander.formatLdObject(applet, 'applet', user, refreshCache=refreshCache, responseDates=False), "users": self.getAppletUsers(applet, user), "groups": self.getAppletGroups(applet, arrayOfObjects=True) } if role in ["coordinator", "manager"] else { **jsonld_expander.formatLdObject(applet, 'applet', user, refreshCache=refreshCache, responseDates=(role == "user")), "groups": [ group for group in self.getAppletGroups(applet).get(role) if ObjectId(group) in [ *user.get('groups', []), *user.get('formerGroups', []), *[ invite['groupId'] for invite in [ *user.get('groupInvites', []), *user.get('declinedInvites', []) ] ] ] ] } for applet in applets if ( applet is not None and not applet.get('meta', {}).get('applet', {}).get('deleted'))] postformatted = [] for applet in formatted: if role == 'user' and applet['applet'].get( 'informantRelationship') == 'parent': parentProfile = Profile().getProfile(Profile().createProfile( applet['applet']['_id'].split('applet/')[-1], user, "user").get('_id'), user=user) [ postformatted.append(a) for a in jsonld_expander.childByParent( user, applet, parentProfile) ] else: postformatted.append(applet) user['cached']['applets'].update({role: postformatted}) thread = threading.Thread(target=UserModel().save, args=(user, )) thread.start() return (postformatted)
def send_push_notification(applet_id, event_id, activity_id=None, send_time=None): from girderformindlogger.models.events import Events from girderformindlogger.models.profile import Profile now = datetime.datetime.utcnow() now = datetime.datetime.strptime(now.strftime('%Y/%m/%d %H:%M'), '%Y/%m/%d %H:%M') event = Events().findOne({'_id': event_id}) if event: event_time = datetime.datetime.strptime( f"{now.year}/{now.month}/{now.day} {send_time}", '%Y/%m/%d %H:%M') timezone = (event_time - now).total_seconds() / 3600 # this is temporary fix for timezone issue if timezone >= 12: timezone = timezone - 24 elif timezone < -12: timezone = timezone + 24 query = { 'appletId': applet_id, 'timezone': round(timezone, 2), 'profile': True, 'individual_events': 0 } if event['individualized']: query['individual_events'] = {'$gte': 1} query['_id'] = {'$in': event['data']['users']} if activity_id: query['completed_activities'] = { '$elemMatch': { '$or': [{ 'activity_id': activity_id, 'completed_time': { '$not': { '$gt': now - datetime.timedelta(hours=12), '$lt': now } } }, { 'activity_id': activity_id, 'completed_time': { '$eq': None } }] } } profiles = list(Profile().find(query=query, fields=['deviceId', 'badge'])) # ordered by badge message_requests = defaultdict(list) for profile in profiles: message_requests[profile["badge"]].append(profile["deviceId"]) for badge in message_requests: result = push_service.notify_multiple_devices( registration_ids=message_requests[badge], message_title=event['data']['title'], message_body=event['data']['description'], data_message={ "event_id": str(event_id), "applet_id": str(applet_id), "activity_id": str(activity_id), "type": 'event-alert' }, badge=int(badge) + 1) print( f'Notifications with failure status - {str(result["failure"])}' ) print( f'Notifications with success status - {str(result["success"])}' ) Profile().updateProfileBadgets(profiles) # if random time we will reschedule it in time between 23:45 and 23:59 if event['data']['notifications'][0][ 'random'] and now.hour == 23 and 59 >= now.minute >= 45: Events().rescheduleRandomNotifications(event)
def createResponseItem( self, applet, activity, metadata, subject_id, pending, params ): from girderformindlogger.models.profile import Profile try: from girderformindlogger.utility.response import aggregateAndSave # TODO: pending metadata['applet'] = { "@id": applet.get('_id'), "name": AppletModel().preferredName(applet), "url": applet.get( 'url', applet.get('meta', {}).get('applet', {}).get('url') ) } metadata['activity'] = { "@id": activity.get('_id'), "name": ActivityModel().preferredName(activity), "url": activity.get( 'url', activity.get('meta', {}).get('activity', {}).get('url') ) } informant = self.getCurrentUser() subject_id = subject_id if subject_id else str( informant['_id'] ) subject_id = Profile().createProfile( applet, subject_id ).get('_id') print(subject_id) if isinstance(metadata.get('subject'), dict): metadata['subject']['@id'] = subject_id else: metadata['subject'] = {'@id': subject_id} now = datetime.now(tzlocal.get_localzone()) appletName=AppletModel().preferredName(applet) UserResponsesFolder = ResponseFolderModel().load( user=informant, reviewer=informant, force=True ) UserAppletResponsesFolder = Folder().createFolder( parent=UserResponsesFolder, parentType='folder', name=appletName, reuseExisting=True, public=False) AppletSubjectResponsesFolder = Folder().createFolder( parent=UserAppletResponsesFolder, parentType='folder', name=str(subject_id), reuseExisting=True, public=False) try: newItem = self._model.createResponseItem( folder=AppletSubjectResponsesFolder, name=now.strftime("%Y-%m-%d-%H-%M-%S-%Z"), creator=informant, description="{} response on {} at {}".format( Folder().preferredName(activity), now.strftime("%Y-%m-%d"), now.strftime("%H:%M:%S %Z") ), reuseExisting=False) except: raise ValidationException( "Couldn't find activity name for this response" ) # for each blob in the parameter, upload it to a File under the item. for key, value in params.items(): # upload the value (a blob) um = UploadModel() filename = "{}.{}".format( key, metadata['responses'][key]['type'].split('/')[-1] ) newUpload = um.uploadFromFile( value.file, metadata['responses'][key]['size'], filename, 'item', newItem, informant, metadata['responses'][key]['type'] ) # now, replace the metadata key with a link to this upload metadata['responses'][key] = "file::{}".format(newUpload['_id']) if metadata: newItem = self._model.setMetadata(newItem, metadata) print(metadata) if not pending: # create a Thread to calculate and save aggregates # TODO: probably uncomment this as we scale. # idea: thread all time, but synchronously do last7 days # agg = threading.Thread(target=aggregateAndSave, args=(newItem, informant)) # agg.start() aggregateAndSave(newItem, informant) newItem['readOnly'] = True print(newItem) return(newItem) except: import sys, traceback print(sys.exc_info()) print(traceback.print_tb(sys.exc_info()[2])) return(str(traceback.print_tb(sys.exc_info()[2])))
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 ))
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())