Example #1
0
def testPluginTemplates(server):
    val = 'OVERRIDE CORE FOOTER'
    assert mail_utils.renderTemplate('_footer.mako').strip() == val

    # Make sure it also works from in-mako import statements
    content = mail_utils.renderTemplate('temporaryAccess.mako', {'url': 'x'})
    assert val in content
Example #2
0
    def _imagesZipGenerator(self, downloadFileName, images, include):
        datasetCache = {}
        zipGenerator = ziputil.ZipGenerator(downloadFileName)

        for image in images:
            datasetId = image['meta']['datasetId']
            if datasetId not in datasetCache:
                datasetCache[datasetId] = Dataset().load(datasetId,
                                                         force=True,
                                                         exc=True)
            dataset = datasetCache[datasetId]

            if include in {'all', 'images'}:
                imageFile = Image().originalFile(image)
                imageFileGenerator = File().download(imageFile, headers=False)
                for data in zipGenerator.addFile(imageFileGenerator,
                                                 path=os.path.join(
                                                     dataset['name'],
                                                     imageFile['name'])):
                    yield data
            if include in {'all', 'metadata'}:

                def metadataGenerator():
                    # TODO: Consider replacing this with Image().filter
                    yield json.dumps({
                        '_id': str(image['_id']),
                        'name': image['name'],
                        'meta': {
                            'acquisition': image['meta']['acquisition'],
                            'clinical': image['meta']['clinical']
                        }
                    })

                for data in zipGenerator.addFile(
                        metadataGenerator,
                        path=os.path.join(dataset['name'],
                                          '%s.json' % image['name'])):
                    yield data

        for dataset in six.viewvalues(datasetCache):
            licenseText = mail_utils.renderTemplate('license_%s.mako' %
                                                    dataset['license'])
            attributionText = mail_utils.renderTemplate(
                'attribution_%s.mako' % dataset['license'], {
                    'work': dataset['name'],
                    'author': dataset['attribution']
                })
            for data in zipGenerator.addFile(lambda: [licenseText],
                                             path=os.path.join(
                                                 dataset['name'],
                                                 'LICENSE.txt')):
                yield data
            for data in zipGenerator.addFile(lambda: [attributionText],
                                             path=os.path.join(
                                                 dataset['name'],
                                                 'ATTRIBUTION.txt')):
                yield data

        yield zipGenerator.footer()
Example #3
0
    def testPluginTemplates(self):
        val = 'OVERRIDE CORE FOOTER'
        self.assertEqual(mail_utils.renderTemplate('_footer.mako').strip(), val)

        # Make sure it also works from in-mako import statements
        content = mail_utils.renderTemplate('temporaryAccess.mako', {
            'url': 'x'
        })
        self.assertTrue(val in content)
Example #4
0
def testPluginTemplates(server):
    val = 'OVERRIDE CORE FOOTER'
    assert mail_utils.renderTemplate('_footer.mako').strip() == val

    # Make sure it also works from in-mako import statements
    content = mail_utils.renderTemplate('temporaryAccess.mako', {
        'url': 'x'
    })
    assert val in content
Example #5
0
    def testPluginTemplates(self):
        val = 'OVERRIDE CORE FOOTER'
        self.assertEqual(
            mail_utils.renderTemplate('_footer.mako').strip(), val)

        # Make sure it also works from in-mako import statements
        content = mail_utils.renderTemplate('temporaryAccess.mako',
                                            {'url': 'x'})
        self.assertTrue(val in content)
Example #6
0
    def postScore(self, submission, score, params):
        # Ensure admin access on the containing challenge phase
        phase = self.model('phase', 'covalic').load(
            submission['phaseId'], user=self.getCurrentUser(), exc=True,
            level=AccessType.ADMIN)

        # Record whether submission is being re-scored
        rescoring = 'overallScore' in submission

        # Save document to trigger computing overall score
        submission.pop('overallScore', None)
        submission['score'] = score
        submission = self.model('submission', 'covalic').save(submission)

        # Delete the scoring user's job token since the job is now complete.
        token = self.getCurrentToken()
        self.model('token').remove(token)

        user = self.model('user').load(submission['creatorId'], force=True)
        challenge = self.model('challenge', 'covalic').load(
            phase['challengeId'], force=True)
        covalicHost = posixpath.dirname(mail_utils.getEmailUrlPrefix())

        # Mail user
        if not rescoring:
            html = mail_utils.renderTemplate(
                'covalic.submissionCompleteUser.mako',
                {
                    'phase': phase,
                    'challenge': challenge,
                    'submission': submission,
                    'host': covalicHost
                })
            mail_utils.sendEmail(
                to=user['email'], subject='Your submission has been scored',
                text=html)

        # Mail admins
        emails = sorted(getPhaseUserEmails(
            phase, AccessType.WRITE, includeChallengeUsers=True))
        html = mail_utils.renderTemplate(
            'covalic.submissionCompleteAdmin.mako',
            {
                'user': user,
                'phase': phase,
                'challenge': challenge,
                'submission': submission,
                'host': covalicHost
            })
        mail_utils.sendEmail(
            to=emails, subject='A submission has been scored', text=html)

        return self._filterScore(phase, submission, user)
Example #7
0
    def _imagesZipGenerator(self, downloadFileName, images, include):
        datasetCache = {}
        zipGenerator = ziputil.ZipGenerator(downloadFileName)

        for image in images:
            datasetId = image['meta']['datasetId']
            if datasetId not in datasetCache:
                datasetCache[datasetId] = Dataset().load(datasetId, force=True, exc=True)
            dataset = datasetCache[datasetId]

            if include in {'all', 'images'}:
                imageFile = Image().originalFile(image)
                imageFileGenerator = File().download(imageFile, headers=False)
                for data in zipGenerator.addFile(
                        imageFileGenerator,
                        path=os.path.join(dataset['name'], imageFile['name'])):
                    yield data
            if include in {'all', 'metadata'}:
                def metadataGenerator():
                    # TODO: Consider replacing this with Image().filter
                    yield json.dumps({
                        '_id': str(image['_id']),
                        'name': image['name'],
                        'meta': {
                            'acquisition': image['meta']['acquisition'],
                            'clinical': image['meta']['clinical']
                        }
                    })
                for data in zipGenerator.addFile(
                        metadataGenerator,
                        path=os.path.join(dataset['name'], '%s.json' % image['name'])):
                    yield data

        for dataset in datasetCache.values():
            licenseText = mail_utils.renderTemplate(
                'license_%s.mako' % dataset['license'])
            attributionText = mail_utils.renderTemplate(
                'attribution_%s.mako' % dataset['license'],
                {
                    'work': dataset['name'],
                    'author': dataset['attribution']
                })
            for data in zipGenerator.addFile(
                    lambda: [licenseText],
                    path=os.path.join(dataset['name'], 'LICENSE.txt')):
                yield data
            for data in zipGenerator.addFile(
                    lambda: [attributionText],
                    path=os.path.join(dataset['name'], 'ATTRIBUTION.txt')):
                yield data

        yield zipGenerator.footer()
Example #8
0
def applyMetadata(self, datasetId, metadataFileId, userId):
    user = User().load(userId, force=True)
    dataset = Dataset().load(datasetId, force=True)
    metadataFileResponse = self.session.get(
        f'file/{metadataFileId}/download',
        allow_redirects=False,
    )
    metadataFileResponse.raise_for_status()
    errors, warnings = Dataset().applyMetadata(
        dataset=dataset,
        metadataFileStream=io.BytesIO(metadataFileResponse.content),
        save=True)

    # metadata is saved even with warnings
    status = 'Failed' if errors else 'Succeeded'
    subject = f'ISIC Archive: Metadata Application {status} - {dataset["name"]}'
    templateFilename = 'metadataApplication.mako'

    # Mail user
    html = mail_utils.renderTemplate(
        templateFilename,
        {
            'warnings': warnings,
            'errors': errors,
            'user': user,
            'dataset': dataset,
        },
    )
    mail_utils.sendMailSync(subject, html, [user['email']] +
                            [u['email'] for u in User().getAdmins()])
Example #9
0
    def generateTemporaryPassword(self, params):
        self.requireParams('email', params)
        email = params['email'].lower().strip()

        users = self.model('user').find({'email': email})

        if not users.count():
            raise RestException('That email is not registered.')
        for user in users:
            token = self.model('token').createToken(None, days=1, scope=(
                TokenScope.USER_AUTH, TokenScope.TEMPORARY_USER_AUTH))
            token['userId'] = user['_id']
            self.model('token').save(token)
            base = cherrypy.request.base.rstrip('/')
            altbase = cherrypy.request.headers.get('X-Forwarded-Host', '')
            if altbase:
                base = '%s://%s' % (cherrypy.request.scheme, altbase)
            url = '%s/#useraccount/%s/token/%s' % (
                base, str(user['_id']), str(token['_id']))

            html = mail_utils.renderTemplate('temporaryAccess.mako', {
                'url': url,
                'token': str(token['_id'])
            })
            mail_utils.sendEmail(to=email, subject='Girder: Temporary Access',
                                 text=html)
        return {'message': 'Sent temporary access email.'}
Example #10
0
    def inviteToGroup(self, group, params):
        """Invite the user to join the group."""
        self.requireParams('userId', params)
        user = self.getCurrentUser()
        level = int(params.get('level', AccessType.READ))

        userToInvite = self.model('user').load(id=params['userId'],
                                               user=user,
                                               level=AccessType.READ,
                                               exc=True)

        # Can only invite into access levels that you yourself have
        self.model('group').requireAccess(group, user, level)
        self.model('group').inviteUser(group, userToInvite, level)

        if params.get('quiet', '').lower() != 'true':
            html = mail_utils.renderTemplate('groupInvite.mako', {
                'userToInvite': userToInvite,
                'user': user,
                'group': group
            })
            mail_utils.sendEmail(
                to=userToInvite['email'],
                text=html,
                subject="Girder: You've been invited to a group")

        return self.model('group').filter(group,
                                          user,
                                          accessList=True,
                                          requests=True)
Example #11
0
    def postScore(self, submission, params):
        # Ensure admin access on the containing challenge phase
        phase = self.model('phase',
                           'challenge').load(submission['phaseId'],
                                             user=self.getCurrentUser(),
                                             exc=True,
                                             level=AccessType.ADMIN)

        submission['score'] = json.loads(cherrypy.request.body.read())
        submission = self.model('submission', 'covalic').save(submission)

        # Delete the scirubg user's job token since the job is now complete.
        token = self.getCurrentToken()
        self.model('token').remove(token)

        user = self.model('user').load(submission['creatorId'], force=True)
        challenge = self.model('challenge',
                               'challenge').load(phase['challengeId'],
                                                 force=True)
        covalicHost = posixpath.dirname(mail_utils.getEmailUrlPrefix())
        html = mail_utils.renderTemplate(
            'covalic.submissionComplete.mako', {
                'phase': phase,
                'challenge': challenge,
                'submission': submission,
                'host': covalicHost
            })
        mail_utils.sendEmail(to=user['email'],
                             subject='Your submission has been scored',
                             text=html)

        return submission
Example #12
0
def _uploadComplete(event):
    """
    Called after an upload finishes. We check if our current token is a special
    authorized upload token, and if so, delete it.

    TODO we could alternatively keep a reference count inside each token that authorized
    more than a single upload at a time, and just decrement it here.
    """
    token = getCurrentToken()
    if token and 'authorizedUploadId' in token:
        user = User().load(token['userId'], force=True)
        item = Item().load(event.info['file']['itemId'], force=True)

        # Save the metadata on the item
        item['description'] = token['authorizedUploadDescription']
        item['authorizedUploadEmail'] = token['authorizedUploadEmail']
        Item().save(item)

        text = mail_utils.renderTemplate(
            'authorized_upload.uploadFinished.mako', {
                'itemId': item['_id'],
                'itemName': item['name'],
                'itemDescription': item.get('description', '')
            })
        mail_utils.sendEmail(to=user['email'],
                             subject='Authorized upload complete',
                             text=text)
        Token().remove(token)
Example #13
0
def sendIngestionNotification(batchId, failedImages, skippedFilenames):
    batch = Batch().load(batchId)
    dataset = Dataset().load(batch['datasetId'], force=True)
    user = User().load(batch['creatorId'], force=True)
    host = mail_utils.getEmailUrlPrefix()
    # TODO: The email should gracefully handle the situation where failedImages or skippedFilenames
    # has an excessive amount of items.
    params = {
        'isOriginalUploader': True,
        'host': host,
        'dataset': dataset,
        # We intentionally leak full user details here, even though all
        # email recipients may not have access permissions to the user
        'user': user,
        'batch': batch,
        'failedImages': failedImages,
        'skippedFilenames': skippedFilenames
    }
    subject = 'ISIC Archive: Dataset Upload Confirmation'
    templateFilename = 'ingestDatasetConfirmation.mako'

    # Mail user
    html = mail_utils.renderTemplate(templateFilename, params)
    sendEmail(to=user['email'], subject=subject, text=html)

    # Mail 'Dataset QC Reviewers' group
    params['isOriginalUploader'] = False
    sendEmailToGroup(
        groupName='Dataset QC Reviewers',
        templateFilename=templateFilename,
        templateParams=params,
        subject=subject)
Example #14
0
    def postScore(self, submission, params):
        # Ensure admin access on the containing challenge phase
        phase = self.model('phase', 'challenge').load(
            submission['phaseId'], user=self.getCurrentUser(), exc=True,
            level=AccessType.ADMIN)

        submission['score'] = json.loads(cherrypy.request.body.read())
        submission = self.model('submission', 'covalic').save(submission)

        # Delete the scirubg user's job token since the job is now complete.
        token = self.getCurrentToken()
        self.model('token').remove(token)

        user = self.model('user').load(submission['creatorId'], force=True)
        challenge = self.model('challenge', 'challenge').load(
            phase['challengeId'], force=True)
        covalicHost = posixpath.dirname(mail_utils.getEmailUrlPrefix())
        html = mail_utils.renderTemplate('covalic.submissionComplete.mako', {
            'phase': phase,
            'challenge': challenge,
            'submission': submission,
            'host': covalicHost
        })
        mail_utils.sendEmail(
            to=user['email'], subject='Your submission has been scored',
            text=html)

        return submission
Example #15
0
def sendIngestionNotification(batchId, failedImages, skippedFilenames, numImages):
    batch = Batch().load(batchId)
    dataset = Dataset().load(batch['datasetId'], force=True)
    user = User().load(batch['creatorId'], force=True)
    host = mail_utils.getEmailUrlPrefix()
    # TODO: The email should gracefully handle the situation where failedImages or skippedFilenames
    # has an excessive amount of items.
    params = {
        'isOriginalUploader': True,
        'host': host,
        'dataset': dataset,
        # We intentionally leak full user details here, even though all
        # email recipients may not have access permissions to the user
        'user': user,
        'batch': batch,
        'failedImages': failedImages,
        'skippedFilenames': skippedFilenames,
        'numImages': numImages,
    }
    subject = f'ISIC Archive: Dataset Upload Confirmation - {dataset["name"]}'
    templateFilename = 'ingestDatasetConfirmation.mako'

    # Mail user
    html = mail_utils.renderTemplate(templateFilename, params)
    mail_utils.sendMailSync(subject, html, user['email'])

    # Mail 'Dataset QC Reviewers' group
    params['isOriginalUploader'] = False
    sendEmailToGroup(
        groupName='Dataset QC Reviewers',
        templateFilename=templateFilename,
        templateParams=params,
        subject=subject,
        asynchronous=False)
Example #16
0
def _uploadComplete(event):
    """
    Called after an upload finishes. We check if our current token is a special
    authorized upload token, and if so, delete it.

    TODO we could alternatively keep a reference count inside each token that authorized
    more than a single upload at a time, and just decrement it here.
    """
    token = getCurrentToken()
    if 'authorizedUploadId' in token:
        user = ModelImporter.model('user').load(token['userId'], force=True)
        item = ModelImporter.model('item').load(event.info['file']['itemId'], force=True)

        # Save the metadata on the item
        item['description'] = token['authorizedUploadDescription']
        item['authorizedUploadEmail'] = token['authorizedUploadEmail']
        ModelImporter.model('item').save(item)

        text = mail_utils.renderTemplate('authorized_upload.uploadFinished.mako', {
            'itemId': item['_id'],
            'itemName': item['name'],
            'itemDescription': item.get('description', '')
        })
        mail_utils.sendEmail(to=user['email'], subject='Authorized upload complete', text=text)
        ModelImporter.model('token').remove(token)
Example #17
0
 def _sendApprovalEmail(self, user):
     url = '%s#user/%s' % (mail_utils.getEmailUrlPrefix(), str(user['_id']))
     text = mail_utils.renderTemplate('accountApproval.mako', {
         'user': user,
         'url': url
     })
     mail_utils.sendMailToAdmins('Girder: Account pending approval', text)
Example #18
0
    def inviteToGroup(self, group, params):
        """Invite the user to join the group."""
        self.requireParams(('userId',), params)
        user = self.getCurrentUser()
        level = int(params.get('level', AccessType.READ))

        userToInvite = self.model('user').load(
            id=params['userId'], user=user, level=AccessType.READ, exc=True)

        # Can only invite into access levels that you yourself have
        self.model('group').requireAccess(group, user, level)
        self.model('group').inviteUser(group, userToInvite, level)

        if params.get('quiet', '').lower() != 'true':
            html = mail_utils.renderTemplate('groupInvite.mako', {
                'userToInvite': userToInvite,
                'user': user,
                'group': group
            })
            mail_utils.sendEmail(
                to=userToInvite['email'], text=html,
                subject="Girder: You've been invited to a group")

        return self.model('group').filter(group, user, accessList=True,
                                          requests=True)
Example #19
0
 def _sendApprovedEmail(self, user):
     text = mail_utils.renderTemplate('accountApproved.mako', {
         'user': user,
         'url': mail_utils.getEmailUrlPrefix()
     })
     mail_utils.sendMail('Girder: Account approved', text,
                         [user.get('email')])
Example #20
0
File: user.py Project: cryos/girder
    def generateTemporaryPassword(self, params):
        self.requireParams('email', params)
        email = params['email'].lower().strip()

        users = self.model('user').find({'email': email})

        if not users.count():
            raise RestException('That email is not registered.')
        for user in users:
            token = self.model('token').createToken(
                None,
                days=1,
                scope=(TokenScope.USER_AUTH, TokenScope.TEMPORARY_USER_AUTH))
            token['userId'] = user['_id']
            self.model('token').save(token)
            base = cherrypy.request.base.rstrip('/')
            altbase = cherrypy.request.headers.get('X-Forwarded-Host', '')
            if altbase:
                base = '%s://%s' % (cherrypy.request.scheme, altbase)
            url = '%s/#useraccount/%s/token/%s' % (base, str(
                user['_id']), str(token['_id']))

            html = mail_utils.renderTemplate('temporaryAccess.mako', {
                'url': url,
                'token': str(token['_id'])
            })
            mail_utils.sendEmail(to=email,
                                 subject='Girder: Temporary Access',
                                 text=html)
        return {'message': 'Sent temporary access email.'}
Example #21
0
def send_new_user_email(event):
    try:
        info = event.info
        email = info.get('email')
        brandName = Setting().get(SettingKey.BRAND_NAME)
        rendered = renderTemplate('welcome.mako')
        sendMail(f'Welcome to {brandName}', rendered, [email])
    except Exception:
        logger.exception("Failed to send new user email")
Example #22
0
 def _sendApprovedEmail(self, user):
     text = mail_utils.renderTemplate('accountApproved.mako', {
         'user': user,
         'url': mail_utils.getEmailUrlPrefix()
     })
     mail_utils.sendEmail(
         to=user.get('email'),
         subject='Girder: Account approved',
         text=text)
Example #23
0
 def _sendVerificationEmail(self, user):
     token = self.model('token').createToken(
         user, days=1, scope=TokenScope.EMAIL_VERIFICATION)
     url = '%s#useraccount/%s/verification/%s' % (
         mail_utils.getEmailUrlPrefix(), str(user['_id']), str(
             token['_id']))
     text = mail_utils.renderTemplate('emailVerification.mako',
                                      {'url': url})
     mail_utils.sendEmail(to=user.get('email'),
                          subject='Girder: Email verification',
                          text=text)
Example #24
0
 def _sendApprovalEmail(self, user):
     url = '%s/#user/%s' % (
         mail_utils.getEmailUrlPrefix(), str(user['_id']))
     text = mail_utils.renderTemplate('accountApproval.mako', {
         'user': user,
         'url': url
     })
     mail_utils.sendEmail(
         toAdmins=True,
         subject='Girder: Account pending approval',
         text=text)
Example #25
0
 def _sendVerificationEmail(self, user):
     token = self.model('token').createToken(
         user, days=1, scope=TokenScope.EMAIL_VERIFICATION)
     url = '%s/#useraccount/%s/verification/%s' % (
         mail_utils.getEmailUrlPrefix(), str(user['_id']), str(token['_id']))
     text = mail_utils.renderTemplate('emailVerification.mako', {
         'url': url
     })
     mail_utils.sendEmail(
         to=user.get('email'),
         subject='Girder: Email verification',
         text=text)
Example #26
0
    def inviteToGroup(self, group, params):
        """Invite the user to join the group."""
        self.requireParams('userId', params)
        user = self.getCurrentUser()
        level = int(params.get('level', AccessType.READ))
        force = self.boolParam('force', params, default=False)

        userToInvite = self.model('user').load(id=params['userId'],
                                               user=user,
                                               level=AccessType.READ,
                                               exc=True)

        if force:
            if not user.get('admin', False):
                mustBeAdmin = True
                addPolicy = self.model('setting').get(
                    SettingKey.ADD_TO_GROUP_POLICY)
                addGroup = group.get('addAllowed', 'default')
                if addGroup not in ['no', 'yesadmin', 'yesmod']:
                    addGroup = addPolicy
                if (self.model('group').hasAccess(group, user,
                                                  AccessType.ADMIN)
                        and ('mod' in addPolicy or 'admin' in addPolicy)
                        and addGroup.startswith('yes')):
                    mustBeAdmin = False
                elif (self.model('group').hasAccess(
                        group, user, AccessType.WRITE) and 'mod' in addPolicy
                      and addGroup == 'yesmod'):
                    mustBeAdmin = False
                if mustBeAdmin:
                    self.requireAdmin(user)
            self.model('group').addUser(group, userToInvite, level=level)
        else:
            # Can only invite into access levels that you yourself have
            self.model('group').requireAccess(group, user, level)
            self.model('group').inviteUser(group, userToInvite, level)

            if not self.boolParam('quiet', params, default=False):
                html = mail_utils.renderTemplate('groupInvite.mako', {
                    'userToInvite': userToInvite,
                    'user': user,
                    'group': group
                })
                mail_utils.sendEmail(
                    to=userToInvite['email'],
                    text=html,
                    subject="Girder: You've been invited to a group")

        return self.model('group').filter(group,
                                          user,
                                          accessList=True,
                                          requests=True)
Example #27
0
def send_approved(event):
    dataset = event.info['dataset']
    approver = event.info['approver']
    user = User().load(dataset['userId'], force=True)
    html = mail_utils.renderTemplate('mdb.dataset_approved.mako', {
        'dataset': dataset,
        'user': user,
        'approver': approver
    })

    email_address = user['email']

    mail_utils.sendEmail(to=email_address, subject='Materials Data Bank: Dataset approved.', text=html)
Example #28
0
    def _sendVerificationEmail(self, user):
        from .token import Token

        token = Token().createToken(user,
                                    days=1,
                                    scope=TokenScope.EMAIL_VERIFICATION)
        url = '%s#useraccount/%s/verification/%s' % (
            mail_utils.getEmailUrlPrefix(), str(user['_id']), str(
                token['_id']))
        text = mail_utils.renderTemplate('emailVerification.mako',
                                         {'url': url})
        mail_utils.sendMail('Girder: Email verification', text,
                            [user.get('email')])
Example #29
0
    def resetPassword(self, email):
        user = self.model('user').findOne({'email': email.lower()})
        if user is None:
            raise RestException('That email is not registered.')

        randomPass = genToken(length=12)

        html = mail_utils.renderTemplate('resetPassword.mako', {
            'password': randomPass
        })
        mail_utils.sendEmail(to=email, subject='Girder: Password reset', text=html)
        self.model('user').setPassword(user, randomPass)
        return {'message': 'Sent password reset email.'}
Example #30
0
def send_created(event):
    dataset = event.info['dataset']
    print(dataset)
    user = event.info['user']

    html = mail_utils.renderTemplate('mdb.dataset_created.mako', {
        'dataset': dataset,
        'user': user
    })

    email_address = Setting().get(constants.NOTIFICATION_EMAIL)

    mail_utils.sendEmail(to=email_address, subject='Materials Data Bank: Dataset submitted.', text=html)
Example #31
0
    def resetPassword(self, email, params):
        user = self.model('user').findOne({'email': email.lower()})
        if user is None:
            raise RestException('That email is not registered.')

        randomPass = genToken(length=12)

        html = mail_utils.renderTemplate('resetPassword.mako', {
            'password': randomPass
        })
        mail_utils.sendEmail(to=email, subject='Girder: Password reset', text=html)
        self.model('user').setPassword(user, randomPass)
        return {'message': 'Sent password reset email.'}
Example #32
0
    def inviteToGroup(self, group, params):
        self.requireParams('userId', params)
        user = self.getCurrentUser()
        level = int(params.get('level', AccessType.READ))
        force = self.boolParam('force', params, default=False)
        groupModel = self.model('group')

        userToInvite = self.model('user').load(
            id=params['userId'], user=user, level=AccessType.READ, exc=True)

        if force:
            if not user.get('admin', False):
                mustBeAdmin = True
                addPolicy = self.model('setting').get(
                    SettingKey.ADD_TO_GROUP_POLICY)
                addGroup = group.get('addAllowed', 'default')
                if addGroup not in ['no', 'yesadmin', 'yesmod']:
                    addGroup = addPolicy
                if (groupModel.hasAccess(
                        group, user, AccessType.ADMIN) and
                        ('mod' in addPolicy or 'admin' in addPolicy) and
                        addGroup.startswith('yes')):
                    mustBeAdmin = False
                elif (groupModel.hasAccess(
                        group, user, AccessType.WRITE) and
                        'mod' in addPolicy and
                        addGroup == 'yesmod'):
                    mustBeAdmin = False
                if mustBeAdmin:
                    self.requireAdmin(user)
            groupModel.addUser(group, userToInvite, level=level)
        else:
            # Can only invite into access levels that you yourself have
            groupModel.requireAccess(group, user, level)
            groupModel.inviteUser(group, userToInvite, level)

            if not self.boolParam('quiet', params, default=False):
                html = mail_utils.renderTemplate('groupInvite.mako', {
                    'userToInvite': userToInvite,
                    'user': user,
                    'group': group
                })
                mail_utils.sendEmail(
                    to=userToInvite['email'], text=html,
                    subject="Girder: You've been invited to a group")

        group['access'] = groupModel.getFullAccessList(group)
        group['requests'] = list(groupModel.getFullRequestList(group))
        return group
Example #33
0
    def _sendMail(self, folder, userId, subject, template):
        """
        Sends the specified email template to a single user.

        :param folder: the curated folder
        :param userId: the id of the user to email
        :param subject: the email subject
        :param template: the name of the mako template to use
        """
        if not userId:
            return
        data = dict(folder=folder, curation=folder[CURATION])
        text = mail_utils.renderTemplate(template, data)
        emails = [self._getEmail(userId)]
        mail_utils.sendEmail(emails, subject, text)
Example #34
0
def onJobUpdate(event):
    """
    Hook into job update event so we can look for job failure events and email
    administrators accordingly.
    """
    if (event.info['job']['type'] == 'covalic_score' and
            'status' in event.info['params'] and
            int(event.info['params']['status']) == JobStatus.ERROR):
        covalicHost = posixpath.dirname(mail_utils.getEmailUrlPrefix())
        html = mail_utils.renderTemplate('covalic.submissionError.mako', {
            'submissionId': event.info['job']['covalicSubmissionId'],
            'host': covalicHost
        })
        mail_utils.sendEmail(
            toAdmins=True, subject='Submission processing error', text=html)
Example #35
0
def inviteUser(self, params):
    Token = self.model('token')
    User = self.model('user', 'isic_archive')

    params = self._decodeParams(params)
    self.requireParams(['login', 'email', 'firstName', 'lastName'], params)
    if 'validityPeriod' in params:
        try:
            validityPeriod = float(params['validityPeriod'])
        except ValueError:
            raise ValidationException('Validity period must be a number.', 'validityPeriod')
    else:
        validityPeriod = 60.0

    currentUser = self.getCurrentUser()
    User.requireAdminStudy(currentUser)

    newUser = User.createUser(
        login=params['login'],
        password=None,
        email=params['email'],
        firstName=params['firstName'],
        lastName=params['lastName']
    )

    token = Token.createToken(
        newUser, days=validityPeriod,
        scope=[TokenScope.TEMPORARY_USER_AUTH])

    inviteUrl = '%s/#user/%s/rsvp/%s' % (
        mail_utils.getEmailUrlPrefix(), newUser['_id'], token['_id'])

    html = mail_utils.renderTemplate(
        'inviteUser.mako',
        {
            'newUser': newUser,
            'inviteUrl': inviteUrl,
        })
    mail_utils.sendEmail(
        to=newUser['email'],
        subject='ISIC Archive: Invitation',
        text=html)

    return {
        'newUser': User.filterSummary(newUser, currentUser),
        'inviteUrl': inviteUrl
    }
Example #36
0
def onJobUpdate(event):
    """
    Hook into job update event so we can look for job failure events and email
    administrators accordingly.
    """
    if (event.info['job']['type'] == 'covalic_score'
            and 'status' in event.info['params']
            and int(event.info['params']['status']) == JobStatus.ERROR):
        covalicHost = posixpath.dirname(mail_utils.getEmailUrlPrefix())
        html = mail_utils.renderTemplate(
            'covalic.submissionError.mako', {
                'submissionId': event.info['job']['covalicSubmissionId'],
                'host': covalicHost
            })
        mail_utils.sendEmail(toAdmins=True,
                             subject='Submission processing error',
                             text=html)
Example #37
0
def requestCreateDatasetPermission(self, params):
    User = self.model('user', 'isic_archive')
    Group = self.model('group')
    currentUser = self.getCurrentUser()
    resp = {}
    if User.canCreateDataset(currentUser):
        resp['message'] = 'Dataset Contributor access granted.',
        resp['extra'] = 'hasPermission'
    else:
        # Request that user join group
        groupName = 'Dataset Contributors'
        group = Group.findOne({'name': groupName})
        if not group:
            raise RestException('Could not load group: %s' % groupName)
        resp['message'] = 'Dataset Contributor access requested. An administrator may contact ' \
                          'you via email (at %s) to process your request.' % currentUser['email']

        for request in Group.getFullRequestList(group):
            if request['id'] == currentUser['_id']:
                # Request for this user is already pending
                break
        else:
            # No request for this user yet
            Group.joinGroup(group, currentUser)

            # Send email to group moderators and administrators
            groupAcl = Group.getFullAccessList(group)
            groupModeratorEmails = [
                getUserEmail(user)
                for user in groupAcl['users']
                if user['level'] >= AccessType.WRITE
            ]
            host = mail_utils.getEmailUrlPrefix()
            html = mail_utils.renderTemplate(
                'datasetContributorRequest.mako',
                {
                    'user': currentUser,
                    'group': group,
                    'host': host,
                })
            mail_utils.sendEmail(
                to=groupModeratorEmails,
                subject='ISIC Archive: Dataset Contributor Request',
                text=html)

    return resp
Example #38
0
def sendEmailToGroup(groupName, templateFilename, templateParams, subject=None):
    """
    Send a single email with all members of a group as the recipients.

    :param groupName: The name of the group.
    :param templateFilename: The name of the Make template file used to format
        the email.
    :param templateParams: The parameters with which to render the template.
    :param subject: The subject line of the email.
    """
    group = Group().findOne({'name': groupName})
    if not group:
        raise Exception('Could not load group: %s.' % groupName)
    emails = [member['email'] for member in Group().listMembers(group)]
    if emails:
        html = mail_utils.renderTemplate(templateFilename, templateParams)
        sendEmail(to=emails, subject=subject, text=html)
Example #39
0
    def _sendMail(self, folder, userId, subject, template):
        """
        Sends the specified email template to a single user.

        :param folder: the curated folder
        :param userId: the id of the user to email
        :param subject: the email subject
        :param template: the name of the mako template to use
        """
        if not userId:
            return
        data = dict(
            folder=folder,
            curation=folder[CURATION])
        text = mail_utils.renderTemplate(template, data)
        emails = [self._getEmail(userId)]
        mail_utils.sendEmail(emails, subject, text)
Example #40
0
    def generateTemporaryPassword(self, email):
        user = self.model('user').findOne({'email': email.lower()})

        if not user:
            raise RestException('That email is not registered.')

        token = self.model('token').createToken(
            user, days=1, scope=TokenScope.TEMPORARY_USER_AUTH)

        url = '%s#useraccount/%s/token/%s' % (
            mail_utils.getEmailUrlPrefix(), str(user['_id']), str(token['_id']))

        html = mail_utils.renderTemplate('temporaryAccess.mako', {
            'url': url,
            'token': str(token['_id'])
        })
        mail_utils.sendEmail(to=email, subject='Girder: Temporary access', text=html)
        return {'message': 'Sent temporary access email.'}
Example #41
0
    def resetPassword(self, params):
        self.requireParams('email', params)
        email = params['email'].lower().strip()

        cursor = self.model('user').find({'email': email}, limit=1)
        if cursor.count() == 0:
            raise RestException('That email is not registered.')

        user = cursor.next()
        randomPass = genToken(length=12)

        html = mail_utils.renderTemplate('resetPassword.mako',
                                         {'password': randomPass})
        mail_utils.sendEmail(to=email,
                             subject='Girder: Password reset',
                             text=html)
        self.model('user').setPassword(user, randomPass)
        return {'message': 'Sent password reset email.'}
Example #42
0
    def resetPassword(self, params):
        self.requireParams(('email',), params)
        email = params['email'].lower().strip()

        cursor = self.model('user').find({'email': email}, limit=1)
        if cursor.count() == 0:
            raise RestException('That email is not registered.')

        user = cursor.next()
        randomPass = genToken(length=12)

        html = mail_utils.renderTemplate('resetPassword.mako', {
            'password': randomPass
        })
        mail_utils.sendEmail(to=email, subject='Girder: Password reset',
                             text=html)
        self.model('user').setPassword(user, randomPass)
        return {'message': 'Sent password reset email.'}
Example #43
0
    def generateTemporaryPassword(self, email, params):
        user = self.model('user').findOne({'email': email.lower()})

        if not user:
            raise RestException('That email is not registered.')

        token = self.model('token').createToken(
            user, days=1, scope=TokenScope.TEMPORARY_USER_AUTH)

        url = '%s#useraccount/%s/token/%s' % (
            mail_utils.getEmailUrlPrefix(), str(user['_id']), str(token['_id']))

        html = mail_utils.renderTemplate('temporaryAccess.mako', {
            'url': url,
            'token': str(token['_id'])
        })
        mail_utils.sendEmail(to=email, subject='Girder: Temporary access', text=html)
        return {'message': 'Sent temporary access email.'}
Example #44
0
    def inviteToGroup(self, group, userToInvite, level, quiet, force):
        groupModel = self._model
        user = self.getCurrentUser()

        if force:
            if not user['admin']:
                mustBeAdmin = True
                addPolicy = Setting().get(SettingKey.ADD_TO_GROUP_POLICY)
                addGroup = group.get('addAllowed', 'default')
                if addGroup not in ['no', 'yesadmin', 'yesmod']:
                    addGroup = addPolicy
                if (groupModel.hasAccess(
                        group, user, AccessType.ADMIN) and
                        ('mod' in addPolicy or 'admin' in addPolicy) and
                        addGroup.startswith('yes')):
                    mustBeAdmin = False
                elif (groupModel.hasAccess(
                        group, user, AccessType.WRITE) and
                        'mod' in addPolicy and
                        addGroup == 'yesmod'):
                    mustBeAdmin = False
                if mustBeAdmin:
                    self.requireAdmin(user)
            groupModel.addUser(group, userToInvite, level=level)
        else:
            # Can only invite into access levels that you yourself have
            groupModel.requireAccess(group, user, level)
            groupModel.inviteUser(group, userToInvite, level)

            if not quiet:
                html = mail_utils.renderTemplate('groupInvite.mako', {
                    'userToInvite': userToInvite,
                    'user': user,
                    'group': group
                })
                mail_utils.sendEmail(
                    to=userToInvite['email'], text=html,
                    subject="%s: You've been invited to a group"
                    % Setting().get(SettingKey.BRAND_NAME)
                )

        group['access'] = groupModel.getFullAccessList(group)
        group['requests'] = list(groupModel.getFullRequestList(group))
        return group
Example #45
0
    def inviteToGroup(self, group, userToInvite, level, quiet, force):
        groupModel = self._model
        user = self.getCurrentUser()

        if force:
            if not user['admin']:
                mustBeAdmin = True
                addPolicy = Setting().get(SettingKey.ADD_TO_GROUP_POLICY)
                addGroup = group.get('addAllowed', 'default')
                if addGroup not in ['no', 'yesadmin', 'yesmod']:
                    addGroup = addPolicy
                if (groupModel.hasAccess(
                        group, user, AccessType.ADMIN) and
                        ('mod' in addPolicy or 'admin' in addPolicy) and
                        addGroup.startswith('yes')):
                    mustBeAdmin = False
                elif (groupModel.hasAccess(
                        group, user, AccessType.WRITE) and
                        'mod' in addPolicy and
                        addGroup == 'yesmod'):
                    mustBeAdmin = False
                if mustBeAdmin:
                    self.requireAdmin(user)
            groupModel.addUser(group, userToInvite, level=level)
        else:
            # Can only invite into access levels that you yourself have
            groupModel.requireAccess(group, user, level)
            groupModel.inviteUser(group, userToInvite, level)

            if not quiet:
                html = mail_utils.renderTemplate('groupInvite.mako', {
                    'userToInvite': userToInvite,
                    'user': user,
                    'group': group
                })
                mail_utils.sendEmail(
                    to=userToInvite['email'], text=html,
                    subject="%s: You've been invited to a group"
                    % Setting().get(SettingKey.BRAND_NAME)
                )

        group['access'] = groupModel.getFullAccessList(group)
        group['requests'] = list(groupModel.getFullRequestList(group))
        return group
Example #46
0
    def _ingestZip(self, dataset, zipFile, batch, user, sendMail):
        """
        Ingest images from a ZIP file into a dataset.

        The images are extracted to a "Pre-review" folder within the dataset folder.
        """
        prereviewFolder = Folder().createFolder(
            parent=self.imagesFolder(dataset),
            name='Pre-review',
            parentType='folder',
            creator=user,
            public=False,
            reuseExisting=True)

        # Process zip file
        # TODO: gracefully clean up after exceptions in handleZip
        self._handleZip(dataset, batch, prereviewFolder, user, zipFile)

        # Send email confirmations
        if sendMail:
            host = mail_utils.getEmailUrlPrefix()
            params = {
                'group': False,
                'host': host,
                'dataset': dataset,
                # We intentionally leak full user details here, even though all
                # email recipients may not have access permissions to the user
                'user': user,
                'batch': batch,
            }
            subject = 'ISIC Archive: Dataset Upload Confirmation'
            templateFilename = 'ingestDatasetConfirmation.mako'

            # Mail user
            html = mail_utils.renderTemplate(templateFilename, params)
            mail_utils.sendEmail(to=user['email'], subject=subject, text=html)

            # Mail 'Dataset QC Reviewers' group
            params['group'] = True
            isic_mail_utils.sendEmailToGroup(
                groupName='Dataset QC Reviewers',
                templateFilename=templateFilename,
                templateParams=params,
                subject=subject)
Example #47
0
def sendEmailToGroup(groupName,
                     templateFilename,
                     templateParams,
                     subject=None):
    """
    Send a single email with all members of a group as the recipients.
    :param groupName: The name of the group.
    :param templateFilename: The name of the Make template file used to format
        the email.
    :param templateParams: The parameters with which to render the template.
    :param subject: The subject line of the email.
    """
    group = Group().findOne({'name': groupName})
    if not group:
        raise Exception('Could not load group: %s.' % groupName)
    emails = [member['email'] for member in Group().listMembers(group)]
    if emails:
        html = mail_utils.renderTemplate(templateFilename, templateParams)
        mail_utils.sendEmail(to=emails, subject=subject, text=html)
Example #48
0
def requestCreateDatasetPermission(self, params):
    currentUser = self.getCurrentUser()
    resp = {}
    if User().canCreateDataset(currentUser):
        resp['message'] = 'Dataset Contributor access granted.',
        resp['extra'] = 'hasPermission'
    else:
        # Request that user join group
        groupName = 'Dataset Contributors'
        group = Group().findOne({'name': groupName})
        if not group:
            raise RestException('Could not load group: %s' % groupName)
        resp['message'] = 'Dataset Contributor access requested. An administrator may contact ' \
                          'you via email (at %s) to process your request.' % currentUser['email']

        for request in Group().getFullRequestList(group):
            if request['id'] == currentUser['_id']:
                # Request for this user is already pending
                break
        else:
            # No request for this user yet
            Group().joinGroup(group, currentUser)

            # Send email to group moderators and administrators
            groupAcl = Group().getFullAccessList(group)
            groupModeratorEmails = [
                getUserEmail(user) for user in groupAcl['users']
                if user['level'] >= AccessType.WRITE
            ]
            if groupModeratorEmails:
                host = mail_utils.getEmailUrlPrefix()
                html = mail_utils.renderTemplate(
                    'datasetContributorRequest.mako', {
                        'user': currentUser,
                        'group': group,
                        'host': host,
                    })
                mail_utils.sendEmail(
                    to=groupModeratorEmails,
                    subject='ISIC Archive: Dataset Contributor Request',
                    text=html)

    return resp
Example #49
0
    def generateTemporaryPassword(self, email):
        user = self._model.findOne({'email': email.lower()})

        if not user:
            raise RestException('That email is not registered.')

        token = Token().createToken(user, days=1, scope=TokenScope.TEMPORARY_USER_AUTH)

        url = '%s#useraccount/%s/token/%s' % (
            mail_utils.getEmailUrlPrefix(), str(user['_id']), str(token['_id']))

        html = mail_utils.renderTemplate('temporaryAccess.mako', {
            'url': url,
            'token': str(token['_id'])
        })
        mail_utils.sendMail(
            '%s: Temporary access' % Setting().get(SettingKey.BRAND_NAME),
            html,
            [email]
        )
        return {'message': 'Sent temporary access email.'}
Example #50
0
def sendEmailToGroup(groupName, templateFilename, templateParams, subject=None, asynchronous=True):
    """
    Send a single email with all members of a group as the recipients.

    :param groupName: The name of the group.
    :param templateFilename: The name of the Make template file used to format
        the email.
    :param templateParams: The parameters with which to render the template.
    :param subject: The subject line of the email.
    :param asynchronous: If False, bypass Girder's event system.
    """
    group = Group().findOne({'name': groupName})
    if not group:
        raise Exception(f'Could not load group: {groupName}.')
    emails = [member['email'] for member in Group().listMembers(group)]
    if emails:
        html = mail_utils.renderTemplate(templateFilename, templateParams)
        if asynchronous:
            mail_utils.sendMail(subject, html, emails)
        else:
            mail_utils.sendMailSync(subject, html, emails)
Example #51
0
def inviteUser(self, params):
    params = self._decodeParams(params)
    self.requireParams(['login', 'email', 'firstName', 'lastName'], params)
    if 'validityPeriod' in params:
        try:
            validityPeriod = float(params['validityPeriod'])
        except ValueError:
            raise ValidationException('Validity period must be a number.',
                                      'validityPeriod')
    else:
        validityPeriod = 60.0

    currentUser = self.getCurrentUser()
    User().requireAdminStudy(currentUser)

    newUser = User().createUser(login=params['login'],
                                password=None,
                                email=params['email'],
                                firstName=params['firstName'],
                                lastName=params['lastName'])

    token = Token().createToken(newUser,
                                days=validityPeriod,
                                scope=[TokenScope.TEMPORARY_USER_AUTH])

    inviteUrl = '%s/#user/%s/rsvp/%s' % (mail_utils.getEmailUrlPrefix(),
                                         newUser['_id'], token['_id'])

    html = mail_utils.renderTemplate('inviteUser.mako', {
        'newUser': newUser,
        'inviteUrl': inviteUrl,
    })
    mail_utils.sendEmail(to=newUser['email'],
                         subject='ISIC Archive: Invitation',
                         text=html)

    return {
        'newUser': User().filterSummary(newUser, currentUser),
        'inviteUrl': inviteUrl
    }
Example #52
0
    def ingestDataset(self, zipFile, user, name, owner, description,
                      license, signature, anonymous, attribution,
                      sendMail=False):
        """
        Ingest an uploaded dataset from a .zip file of images. The images are
        extracted to a "Pre-review" folder within a new dataset folder.
        """
        Folder = self.model('folder')

        # Create dataset folder
        dataset = self.createDataset(name, description, user)

        # Set dataset metadata, including license info
        dataset = self.setMetadata(dataset, {
            'owner': owner,
            'signature': signature,
            'anonymous': anonymous,
            'attribution': attribution,
            'license': license,
            'metadataFiles': []
        })

        prereviewFolder = Folder.createFolder(
            parent=dataset,
            name='Pre-review',
            parentType='folder',
            creator=user,
            public=False)
        prereviewFolder = Folder.copyAccessPolicies(
            dataset, prereviewFolder, save=True)

        # Process zip file
        # TODO: gracefully clean up after exceptions in handleZip
        self._handleZip(prereviewFolder, user, zipFile)

        # Send email confirmations
        if sendMail:
            host = mail_utils.getEmailUrlPrefix()
            params = {
                'group': False,
                'host': host,
                # We intentionally leak full user details here, even though all
                # email recipients may not have access permissions to the user
                'user': user,
                'name': name,
                'owner': owner,
                'description': description,
                'license': license,
                'signature': signature,
                'attribution': 'Anonymous' if anonymous else attribution
            }
            subject = 'ISIC Archive: Dataset Upload Confirmation'
            templateFilename = 'ingestDatasetConfirmation.mako'

            # Mail user
            html = mail_utils.renderTemplate(templateFilename, params)
            mail_utils.sendEmail(to=user['email'], subject=subject, text=html)

            # Mail 'Dataset QC Reviewers' group
            params['group'] = True
            isic_mail_utils.sendEmailToGroup(
                groupName='Dataset QC Reviewers',
                templateFilename=templateFilename,
                templateParams=params,
                subject=subject)

        return dataset
Example #53
0
def onJobUpdate(event):
    """
    Hook into job update event so we can look for job failure events and email
    the user and challenge/phase administrators accordingly. Here, an
    administrator is defined to be a user with WRITE access or above.
    """
    isErrorStatus = False
    try:
        isErrorStatus = int(event.info['params'].get('status')) == JobStatus.ERROR
    except (ValueError, TypeError):
        pass

    if (event.info['job']['type'] == 'covalic_score' and isErrorStatus):
        covalicHost = posixpath.dirname(mail_utils.getEmailUrlPrefix())

        # Create minimal log that contains only Covalic errors.
        # Use full log if no Covalic-specific errors are found.
        # Fetch log from model, because log in event may not be up-to-date.
        job = Job().load(
            event.info['job']['_id'], includeLog=True, force=True)
        log = job.get('log')

        minimalLog = None
        if log:
            log = ''.join(log)
            minimalLog = '\n'.join([line[len(JOB_LOG_PREFIX):].strip()
                                    for line in log.splitlines()
                                    if line.startswith(JOB_LOG_PREFIX)])
        if not minimalLog:
            minimalLog = log

        submission = Submission().load(
            event.info['job']['covalicSubmissionId'])
        phase = Phase().load(
            submission['phaseId'], force=True)
        challenge = Challenge().load(
            phase['challengeId'], force=True)
        user = User().load(
            event.info['job']['userId'], force=True)

        rescoring = job.get('rescoring', False)

        # Mail admins, include full log
        emails = sorted(getPhaseUserEmails(
            phase, AccessType.WRITE, includeChallengeUsers=True))
        html = mail_utils.renderTemplate('covalic.submissionErrorAdmin.mako', {
            'submission': submission,
            'challenge': challenge,
            'phase': phase,
            'user': user,
            'host': covalicHost,
            'log': log
        })
        mail_utils.sendEmail(
            to=emails, subject='Submission processing error', text=html)

        # Mail user, include minimal log
        if not rescoring:
            html = mail_utils.renderTemplate('covalic.submissionErrorUser.mako', {
                'submission': submission,
                'challenge': challenge,
                'phase': phase,
                'host': covalicHost,
                'log': minimalLog
            })
            mail_utils.sendEmail(
                to=user['email'], subject='Submission processing error', text=html)