def reloadAndUpdateCache(self, applet, editor): from girderformindlogger.models.protocol import Protocol protocolUrl = applet.get('meta', {}).get('protocol', applet).get( 'http://schema.org/url', applet.get('meta', {}).get('protocol', applet).get('url')) if protocolUrl is not None: protocol = Protocol().getFromUrl(protocolUrl, 'protocol', editor, thread=False, refreshCache=True) protocol = protocol[0].get('protocol', protocol[0]) if protocol.get('_id'): self.update({'_id': ObjectId(applet['_id'])}, {'$set': { 'meta.protocol._id': protocol['_id'] }}) if 'meta' in applet and 'protocol' in applet['meta']: applet['meta']['protocol']['_id'] = protocol['_id'] from girderformindlogger.utility import jsonld_expander jsonld_expander.formatLdObject(applet, 'applet', editor, refreshCache=False, responseDates=False)
def createAppletFromUrl(self, name, protocolUrl, user=None, roles=None, constraints=None, sendEmail=True): from girderformindlogger.models.protocol import Protocol # get a protocol from a URL protocol = Protocol().getFromUrl(protocolUrl, 'protocol', user, thread=False, refreshCache=True) protocol = protocol[0].get('protocol', protocol[0]) displayName = Protocol().preferredName(protocol) name = name if name is not None and len(name) else displayName if len(displayName) == 0: displayName = name if len(name) else "activity" applet = self.createApplet( name=name, protocol={ '_id': 'protocol/{}'.format(str(protocol.get('_id')).split('/')[-1]), 'url': protocol.get('meta', {}).get('protocol', {}).get('url', protocolUrl) }, user=user, roles=roles, constraints=constraints, displayName=displayName) emailMessage = "Your applet, {}, has been successfully created. The " \ "applet's ID is {}".format( name, str(applet.get('applet', applet).get('_id') ) ) if sendEmail and 'email' in user: from girderformindlogger.utility.mail_utils import sendMail sendMail(subject=name, text=emailMessage, to=[user['email']]) print(emailMessage)
def createAppletFromUrl(self, name, protocolUrl, user=None, roles=None, constraints=None, email='', sendEmail=True): from girderformindlogger.models.protocol import Protocol from girderformindlogger.utility import mail_utils # we have cases to show manager's email to users if mail_utils.validateEmailAddress(email): user['email'] = email user['email_encrypted'] = False UserModel().save(user) # get a protocol from a URL protocol = Protocol().getFromUrl(protocolUrl, 'protocol', user, thread=False, refreshCache=True) protocol = protocol[0].get('protocol', protocol[0]) displayName = Protocol().preferredName(protocol) name = name if name is not None and len(name) else displayName appletName = '{}/'.format(protocolUrl) applet = self.createApplet( name=name, protocol={ '_id': 'protocol/{}'.format(str(protocol.get('_id')).split('/')[-1]), 'url': protocol.get('meta', {}).get('protocol', {}).get('url', protocolUrl) }, user=user, roles=roles, constraints=constraints, appletName=appletName)
def getOldVersions(responses, applet): IRIs = {} insertedIRI = {} for IRI in responses: IRIs[IRI] = [] for response in responses[IRI]: if 'version' not in response: continue identifier = '{}/{}'.format(IRI, response['version']) if identifier not in insertedIRI: IRIs[IRI].append(response['version']) insertedIRI[identifier] = True return Protocol().getHistoryDataFromItemIRIs( applet.get('meta', {}).get('protocol', {}).get('_id', '').split('/')[-1], IRIs)
def createAppletFromProtocolData(self, name, protocol, user=None, roles=None, constraints=None, email='', sendEmail=True): from girderformindlogger.models.protocol import Protocol from girderformindlogger.utility import mail_utils # we have cases to show manager's email to users if mail_utils.validateEmailAddress(email): user['email'] = email user['email_encrypted'] = False UserModel().save(user) # get a protocol from single json file protocol = Protocol().createProtocol(protocol, user) protocol = protocol.get('protocol', protocol) displayName = Protocol().preferredName(protocol) name = name if name is not None and len(name) else displayName appletName = '{}/'.format(protocol.get('@id')) applet = self.createApplet( name=name, protocol={ '_id': 'protocol/{}'.format(str(protocol.get('_id')).split('/')[-1]) }, user=user, roles=roles, constraints=constraints, appletName=appletName)
def formatLdObject(obj, mesoPrefix='folder', user=None, keepUndefined=False, dropErrors=False, refreshCache=False, responseDates=False): """ Function to take a compacted JSON-LD Object within a Girder for Mindlogger database and return an exapanded JSON-LD Object including an _id. :param obj: Compacted JSON-LD Object :type obj: dict or list :param mesoPrefix: Girder for Mindlogger entity type, defaults to 'folder' if not provided :type mesoPrefix: str :param user: User making the call :type user: User :param keepUndefined: Keep undefined properties :type keepUndefined: bool :param dropErrors: Return `None` instead of raising an error for illegal JSON-LD definitions. :type dropErrors: bool :param refreshCache: Refresh from Dereferencing URLs? :type refreshCache: bool :param responseDates: Include list of ISO date strings of responses :type responseDates: bool :returns: Expanded JSON-LD Object (dict or list) """ from girderformindlogger.models import pluralize refreshCache = False if refreshCache is None else refreshCache try: if obj is None: return (None) if isinstance(obj, dict): oc = obj.get("cached") if all([not refreshCache, oc is not None]): return (loadCache(oc)) if 'meta' not in obj.keys(): return (_fixUpFormat(obj)) mesoPrefix = camelCase(mesoPrefix) if type(obj) == list: return (_fixUpFormat([ formatLdObject(o, mesoPrefix, refreshCache=refreshCache, user=user) for o in obj if o is not None ])) if not type(obj) == dict and not dropErrors: raise TypeError("JSON-LD must be an Object or Array.") newObj = obj.get('meta', obj) newObj = newObj.get(mesoPrefix, newObj) newObj = expand(newObj, keepUndefined=keepUndefined) if type(newObj) == list and len(newObj) == 1: try: newObj = newObj[0] except: raise ValidationException(str(newObj)) if type(newObj) != dict: newObj = {} objID = str(obj.get('_id', 'undefined')) if objID == 'undefined': raise ResourcePathNotFound() newObj['_id'] = "/".join([snake_case(mesoPrefix), objID]) if mesoPrefix == 'applet': protocolUrl = obj.get('meta', {}).get('protocol', obj).get( 'http://schema.org/url', obj.get('meta', {}).get('protocol', obj).get('url')) protocol = ProtocolModel().getFromUrl( protocolUrl, 'protocol', user, thread=False, refreshCache=refreshCache )[0] if protocolUrl is not None else {} protocol = formatLdObject(protocol, 'protocol', user, refreshCache=refreshCache) applet = {} applet['activities'] = protocol.pop('activities', {}) applet['items'] = protocol.pop('items', {}) applet['protocol'] = { key: protocol.get('protocol', protocol.get('activitySet', {})).pop(key) for key in ['@type', '_id', 'http://schema.org/url', 'schema:url', 'url'] if key in list(protocol.get('protocol', {}).keys()) } applet['applet'] = { **protocol.pop('protocol', {}), **obj.get('meta', {}).get(mesoPrefix, {}), '_id': "/".join([snake_case(mesoPrefix), objID]), 'url': "#".join( [obj.get('meta', {}).get('protocol', {}).get("url", "")]) } createCache(obj, applet, 'applet', user) if responseDates: try: applet["applet"]["responseDates"] = responseDateList( obj.get('_id'), user.get('_id'), user) except: applet["applet"]["responseDates"] = [] return (applet) elif mesoPrefix == 'protocol': protocol = {'protocol': newObj, 'activities': {}, "items": {}} activitiesNow = set() itemsNow = set() try: protocol = componentImport(newObj, deepcopy(protocol), user, refreshCache=refreshCache) except: print("636") protocol = componentImport(newObj, deepcopy(protocol), user, refreshCache=True) newActivities = [ a for a in protocol.get('activities', {}).keys() if a not in activitiesNow ] newItems = [ i for i in protocol.get('items', {}).keys() if i not in itemsNow ] while (any([len(newActivities), len(newItems)])): activitiesNow = set(protocol.get('activities', {}).keys()) itemsNow = set(protocol.get('items', {}).keys()) for activityURL in newActivities: activity = protocol['activities'][activityURL] activity = activity.get('meta', {}).get('activity', activity) try: protocol = componentImport(deepcopy(activity), deepcopy(protocol), user, refreshCache=refreshCache) except: print("670") protocol = componentImport(deepcopy(activity), deepcopy(protocol), user, refreshCache=True) for itemURL in newItems: activity = protocol['items'][itemURL] activity = activity.get('meta', {}).get('screen', activity) try: protocol = componentImport(deepcopy(activity), deepcopy(protocol), user, refreshCache=refreshCache) except: print("691") protocol = componentImport(deepcopy(activity), deepcopy(protocol), user, refreshCache=True) newActivities = list( set(protocol.get('activities', {}).keys()) - activitiesNow) newItems = list( set(protocol.get('items', {}).keys()) - itemsNow) return (_fixUpFormat(protocol)) else: return (_fixUpFormat(newObj)) except: if refreshCache == False: return (_fixUpFormat( formatLdObject(obj, mesoPrefix, user, keepUndefined, dropErrors, refreshCache=False, responseDates=responseDates))) import sys, traceback print(sys.exc_info()) print(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 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())
def formatLdObject(obj, mesoPrefix='folder', user=None, keepUndefined=False, dropErrors=False, refreshCache=False, responseDates=False): """ Function to take a compacted JSON-LD Object within a Girder for Mindlogger database and return an exapanded JSON-LD Object including an _id. :param obj: Compacted JSON-LD Object :type obj: dict or list :param mesoPrefix: Girder for Mindlogger entity type, defaults to 'folder' if not provided :type mesoPrefix: str :param user: User making the call :type user: User :param keepUndefined: Keep undefined properties :type keepUndefined: bool :param dropErrors: Return `None` instead of raising an error for illegal JSON-LD definitions. :type dropErrors: bool :param refreshCache: Refresh from Dereferencing URLs? :type refreshCache: bool :param responseDates: Include list of ISO date strings of responses :type responseDates: bool :returns: Expanded JSON-LD Object (dict or list) """ from girderformindlogger.models import pluralize refreshCache = False if refreshCache is None else refreshCache try: if obj is None: return (None) if isinstance(obj, dict): oc = obj.get("cached") if all([not refreshCache, oc is not None]): return (loadCache(oc)) if 'meta' not in obj.keys(): return (_fixUpFormat(obj)) mesoPrefix = camelCase(mesoPrefix) if type(obj) == list: return (_fixUpFormat([ formatLdObject(o, mesoPrefix, refreshCache=refreshCache, user=user) for o in obj if o is not None ])) if not type(obj) == dict and not dropErrors: raise TypeError("JSON-LD must be an Object or Array.") newObj = obj.get('meta', obj) newObj = newObj.get(mesoPrefix, newObj) if not obj.get('loadedFromSingleFile', False): newObj = expand(newObj, keepUndefined=keepUndefined) if type(newObj) == list and len(newObj) == 1: try: newObj = newObj[0] except: raise ValidationException(str(newObj)) if type(newObj) != dict: newObj = {} objID = str(obj.get('_id', 'undefined')) if objID == 'undefined': raise ResourcePathNotFound('unable to load object') newObj['_id'] = "/".join([snake_case(mesoPrefix), objID]) if mesoPrefix == 'applet': protocolUrl = obj.get('meta', {}).get('protocol', obj).get( 'http://schema.org/url', obj.get('meta', {}).get('protocol', obj).get('url')) # get protocol data from id protocol = None protocolId = obj.get('meta', {}).get('protocol', {}).get('_id', '').split('/')[-1] if protocolId: cache = ProtocolModel().getCache(protocolId) if cache: protocol = loadCache(cache) if protocolUrl is not None and not protocol: # get protocol from url protocol = ProtocolModel().getFromUrl( protocolUrl, 'protocol', user, thread=False, refreshCache=refreshCache)[0] # format protocol data protocol = formatLdObject(protocol, 'protocol', user, refreshCache=refreshCache) applet = {} applet['activities'] = protocol.pop('activities', {}) applet['items'] = protocol.pop('items', {}) applet['protocol'] = { key: protocol.get('protocol', protocol.get('activitySet', {})).pop(key) for key in ['@type', '_id', 'http://schema.org/url', 'schema:url', 'url'] if key in list(protocol.get('protocol', {}).keys()) } applet['applet'] = { **protocol.pop('protocol', {}), **obj.get('meta', {}).get(mesoPrefix, {}), '_id': "/".join([snake_case(mesoPrefix), objID]), 'url': "#".join( [obj.get('meta', {}).get('protocol', {}).get("url", "")]) } if 'appletName' in obj and obj['appletName']: suffix = obj['appletName'].split('/')[-1] inserted = False candidates = ['prefLabel', 'altLabel'] for candidate in candidates: for key in applet['applet']: if not inserted and str(key).endswith( candidate) and len( applet['applet'][key]) and len( applet['applet'][key][0].get( '@value', '')): if len(suffix): applet['applet'][key][0]['@value'] += (' ' + suffix) if not len(applet['applet'] ['url']): # for development applet['applet'][key][0][ '@value'] += ' ( single-file )' AppletModel().update({'_id': obj['_id']}, { '$set': { 'displayName': applet['applet'][key][0]['@value'] } }) inserted = True createCache(obj, applet, 'applet', user) if responseDates: try: applet["applet"]["responseDates"] = responseDateList( obj.get('_id'), user.get('_id'), user) except: applet["applet"]["responseDates"] = [] return (applet) elif mesoPrefix == 'protocol': protocol = {'protocol': newObj, 'activities': {}, "items": {}} if obj.get('loadedFromSingleFile', False): activities = list(ActivityModel().find({ 'meta.protocolId': '{}/{}'.format(MODELS()['protocol']().name, obj['_id']) })) items = list(ScreenModel().find({ 'meta.protocolId': '{}/{}'.format(MODELS()['protocol']().name, obj['_id']) })) for activity in activities: formatted = formatLdObject(activity, 'activity', user) protocol['activities'][formatted['@id']] = formatted for item in items: formatted = formatLdObject(item, 'screen', user) protocol['items'][formatted['@id']] = formatted else: try: protocol = componentImport(newObj, deepcopy(protocol), user, refreshCache=refreshCache) except: print("636") protocol = componentImport(newObj, deepcopy(protocol), user, refreshCache=True) newActivities = protocol.get('activities', {}).keys() newItems = protocol.get('items', {}).keys() while (any([len(newActivities), len(newItems)])): activitiesNow = set(protocol.get('activities', {}).keys()) itemsNow = set(protocol.get('items', {}).keys()) for activityURL in newActivities: activity = protocol['activities'][activityURL] activity = activity.get('meta', {}).get('activity', activity) try: protocol = componentImport( deepcopy(activity), deepcopy(protocol), user, refreshCache=refreshCache) except: print("670") protocol = componentImport(deepcopy(activity), deepcopy(protocol), user, refreshCache=True) for itemURL in newItems: activity = protocol['items'][itemURL] activity = activity.get('meta', {}).get('screen', activity) try: protocol = componentImport( deepcopy(activity), deepcopy(protocol), user, refreshCache=refreshCache) except: print("691") protocol = componentImport(deepcopy(activity), deepcopy(protocol), user, refreshCache=True) newActivities = list( set(protocol.get('activities', {}).keys()) - activitiesNow) newItems = list( set(protocol.get('items', {}).keys()) - itemsNow) formatted = _fixUpFormat(protocol) createCache(obj, formatted, 'protocol') return formatted else: return (_fixUpFormat(newObj)) except: if refreshCache == False: return (_fixUpFormat( formatLdObject(obj, mesoPrefix, user, keepUndefined, dropErrors, refreshCache=True, responseDates=responseDates))) import sys, traceback print(sys.exc_info()) print(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())