def sendFeedItemEmailNotifications(entity, acting_user, update_type, payload, context = {}, **kwargs): """ Sends e-mail notification to user about new feed item. Private payload info can be included in this message (while it is not included in the Atom feed) Params: entity - entity being updated acting_user - use who performed feed action (or None) update_type - type of update (created, updated, deleted) payload - extra information for message context - template dict """ if acting_user: sender_name = acting_user.name sender = acting_user else: sender_name, sender = mail_dispatcher.getDefaultMailSender() if getattr(entity, 'title', None): entity_title = entity.title else: entity_title = entity.key().name() subject = "%s - %s (%s) has been %s" % ( os.environ['APPLICATION_ID'].capitalize(), entity_title, entity.kind(), update_type) # this should be a user query function and there should be # an access check for the receiver and then a check against a # no_subscribe ListProperty for user for both sender and recevier. to_users = subscriptions_logic.getSubscribedUsersForFeedItem(entity) logging.info(to_users) # get site name site_entity = model_logic.site.logic.getSingleton() site_name = site_entity.site_name for to_user in to_users: messageProperties = { # message configuration 'to_name': to_user.name, 'to': accounts.denormalizeAccount(to_user.account).email(), 'sender_name': sender_name, 'sender': accounts.denormalizeAccount(sender.account).email(), # feed item info 'acting_user': acting_user, 'entity': entity, 'payload': payload, 'subject': subject, 'url': news_feed.linkToEntity(entity), 'site_location': 'http://%s' % os.environ['HTTP_HOST'] } logging.info(messageProperties) # send out the message using the news_feed template mail_dispatcher.sendMailFromTemplate( 'soc/mail/news_feed_notification.html', messageProperties)
def as_email(account): """Prints a user as a hyperlinked link_id. """ denormalized = accounts.denormalizeAccount(account) return {'email': denormalized.email()}
def sendApplicationProcessedNotification(entity, status, module_name, mail_templates): """Sends out email about the processed Organization Application. If the application is accepted a Notification is also generated. Args: entity: OrgAppRecord entity status: the new status of the OrgAppRecord entity module_name: The name of the module the Organization entity is in mail_templates: dictionary containing accepted and rejected keys mapping to the location of the mail template to be used iff status is equal to that key """ from soc.logic import accounts from soc.logic import mail_dispatcher from soc.logic.helper import notifications default_sender = mail_dispatcher.getDefaultMailSender() if not default_sender: # no default sender abort return else: (sender_name, sender) = default_sender # construct the contents of the email admin_entity = entity.main_admin backup_entity = entity.backup_admin context = { 'sender': sender, 'sender_name': sender_name, 'program_name': entity.survey.scope.name, 'org_app_name': entity.name } if status == 'accepted': # use the accepted template and subject template = mail_templates['accepted'] context['subject'] = 'Congratulations!' elif status == 'rejected': # use the rejected template and subject template = mail_templates['rejected'] context['subject'] = 'Thank you for your application' for to in [admin_entity, backup_entity]: if not to: continue email = accounts.denormalizeAccount(to.account).email() context['to'] = email context['to_name'] = to.name # send out the constructed email mail_dispatcher.sendMailFromTemplate(template, context) # send out the notifications about what to do next to the accepted ones if status == 'accepted': notifications.sendNewOrganizationNotification(entity, module_name)
def getFirstTaskConfirmationContext(student): """Sends notification to the GCI student, when he or she completes their first task. Args: student: the student who should receive the confirmation """ user = student.parent() to = accounts.denormalizeAccount(user.account).email() subject = DEF_FIRST_TASK_CONFIRMATION_SUBJECT program = student.scope kwargs = { 'sponsor': program.scope_path, 'program': program.link_id } url = reverse('gci_student_form_upload', kwargs=kwargs) protocol = 'http' hostname = system.getHostname() context = { 'student_forms_link': '%s://%s%s' % (protocol, hostname, url), } template = DEF_FIRST_TASK_CONFIRMATION_TEMPLATE body = loader.render_to_string(template, context) return mailer.getMailContext(to=to, subject=subject, html=body, bcc=[])
def convert_user_txn(user_key): user = db.get(user_key) if not user: logging.error("Missing user for key '%r'.", user_key) return MISSING_USER normalized = accounts.denormalizeAccount(user.account) if (user.account.email() == normalized.email() and user.user_id == user.account.user_id()): return IGNORED_USER user.account = normalized user.put() user = db.get(user_key) if not user: logging.error("Missing user second time around for key '%s'.", user_key) return MISSING_USER_SECOND if not user.account.user_id(): logging.error("Missing user_id around for key '%s'.", user_key) return MISSING_USER_ID user.user_id = user.account.user_id() user.put() if not user.user_id: return MISSING_USER_ID return CONVERTED_USER
def orgAppContext(data, record, new_status, apply_url): """Sends out an invite notification to the applicant of the Organization. Args: data: a RequestData object. record: an OrgAppRecord. new_status: the new status that should be assigned to the record. apply_url: Full URL to the org profile create page for accepted orgs. """ context = { 'url': apply_url + '?org_id=' + record.org_id, 'org': record.name, } messages = data.program.getProgramMessages() if new_status == 'accepted': subject = DEF_ACCEPTED_ORG % context template_string = messages.accepted_orgs_msg else: subject = DEF_REJECTED_ORG % context template_string = messages.rejected_orgs_msg context['template_string'] = template_string roles = [record.main_admin, record.backup_admin] emails = [denormalizeAccount(i.account).email() for i in roles if i] context = getDefaultContext(data, emails, subject, context) return context
def testAuthEntity(self): """ """ # create a user from the auth domain email = "*****@*****.**" account = users.User(email=email) link_id = 'auth_user' name = 'Auth User' properties = { 'account': account, 'link_id': link_id, 'name': name, } key_name = user_logic.getKeyNameFromFields(properties) entity = user_logic.updateOrCreateFromKeyName(properties, key_name) self.failIfEqual(account, entity.account) self.failUnlessEqual('test', entity.account.email()) self.failUnlessEqual(link_id, entity.link_id) self.failUnlessEqual(name, entity.name) denormalized = accounts.denormalizeAccount(entity.account) self.failUnlessEqual(account.email().lower(), denormalized.email())
def testCapsAuthEntity(self): """ """ # create a user from the auth domain email = "*****@*****.**" account = users.User(email=email) link_id = 'caps_user' name = 'Caps User' properties = { 'account': account, 'link_id': link_id, 'name': name, } key_name = user_logic.getKeyNameFromFields(properties) entity = user_logic.updateOrCreateFromKeyName(properties, key_name) self.failIfEqual(account, entity.account) self.failUnlessEqual('*****@*****.**', entity.account.email()) self.failUnlessEqual(link_id, entity.link_id) self.failUnlessEqual(name, entity.name) denormalized = accounts.denormalizeAccount(entity.account) self.failUnlessEqual(account.email().lower(), denormalized.email())
def context(self): """Handler to for GSoC Show Request Page HTTP get request. """ assert isSet(self.data.request_entity) assert isSet(self.data.can_respond) assert isSet(self.data.organization) assert isSet(self.data.requester) show_actions = self.data.request_entity.status in [ 'pending', 'withdrawn' ] if self.data.can_respond and self.data.request_entity.status == 'rejected': show_actions = True return { 'page_name': "Request to become a mentor", 'request': self.data.request_entity, 'org': self.data.organization, 'actions': self.ACTIONS, 'user_name': self.data.requester.name, 'user_email': accounts.denormalizeAccount(self.data.requester.account).email(), 'show_actions': show_actions, 'can_respond': self.data.can_respond, }
def context(self): context = { 'user_email': accounts.denormalizeAccount(self.data.user.account).email(), 'link_id': self.data.user.link_id, 'logout_link': links.LINKER.logout(self.data.request), 'dashboard_link': links.LINKER.program(self.data.program, 'gci_dashboard') } # TODO(daniel): simplify this if statement if self.data.ndb_profile: if (self.data.ndb_profile.is_student and self.data.ndb_profile.status == profile_model.Status.ACTIVE): q = GCITask.all() q.filter('student', self.data.ndb_profile.key.to_old_key()) q.filter('status IN', ACTIVE_CLAIMED_TASK) task = q.get() if task: context['task'] = task context['time_left'] = self.getTimeLeftForTask(task) task_url = self.data.redirect.id( task.key().id()).urlOf('gci_view_task') context['task_url'] = task_url return context
def sendApplicationProcessedNotification(entity, status, module_name, mail_templates): """Sends out email about the processed Organization Application. If the application is accepted a Notification is also generated. Args: entity: OrgAppRecord entity status: the new status of the OrgAppRecord entity module_name: The name of the module the Organization entity is in mail_templates: dictionary containing accepted and rejected keys mapping to the location of the mail template to be used iff status is equal to that key """ from soc.logic import accounts from soc.logic import mail_dispatcher from soc.logic.helper import notifications default_sender = mail_dispatcher.getDefaultMailSender() if not default_sender: # no default sender abort return else: (sender_name, sender) = default_sender # construct the contents of the email admin_entity = entity.main_admin backup_entity = entity.backup_admin context = { "sender": sender, "sender_name": sender_name, "program_name": entity.survey.scope.name, "org_app_name": entity.name, } if status == "accepted": # use the accepted template and subject template = mail_templates["accepted"] context["subject"] = "Congratulations!" elif status == "rejected": # use the rejected template and subject template = mail_templates["rejected"] context["subject"] = "Thank you for your application" for to in [admin_entity, backup_entity]: if not to: continue email = accounts.denormalizeAccount(to.account).email() context["to"] = email context["to_name"] = to.name # send out the constructed email mail_dispatcher.sendMailFromTemplate(template, context) # send out the notifications about what to do next to the accepted ones if status == "accepted": notifications.sendNewOrganizationNotification(entity, module_name)
def testDenormalizeAccount(self): """Tests if accounts are denormalised as expected. """ expected_email = self.regular_email denormalized_acc = accounts.denormalizeAccount(self.account) self.assertEqual(denormalized_acc.email(), expected_email) account = users.User(email='test') denormalized_acc = accounts.denormalizeAccount(account) self.assertEqual(denormalized_acc.email(), '*****@*****.**') account = users.User(email='test', _auth_domain='example.com') denormalized_acc = accounts.denormalizeAccount(account) self.assertEqual(denormalized_acc.email(), '*****@*****.**') account = None self.assertRaises(AttributeError, accounts.denormalizeAccount, account)
def context(self): """Handler to for GSoC Show Request Page HTTP get request. """ assert isSet(self.data.request_entity) assert isSet(self.data.can_respond) assert isSet(self.data.organization) assert isSet(self.data.requester) # This code is dupcliated between request and invite status = self.data.request_entity.status can_accept = can_reject = can_withdraw = can_resubmit = False if self.data.can_respond: # admin speaking if status == "pending": can_accept = True can_reject = True if status == "rejected": can_accept = True else: # requester speaking if status == "withdrawn": can_resubmit = True if status == "pending": can_withdraw = True show_actions = can_accept or can_reject or can_withdraw or can_resubmit org_key = self.data.organization.key() status_msg = None if self.data.requester_profile.key() == self.data.profile.key(): if org_key in self.data.requester_profile.org_admin_for: status_msg = "You are now an organization administrator for this organization." elif org_key in self.data.requester_profile.mentor_for: status_msg = "You are now a mentor for this organization." else: if org_key in self.data.requester_profile.org_admin_for: status_msg = "This user is now an organization administrator with your organization." elif org_key in self.data.requester_profile.mentor_for: status_msg = "This user is now a mentor with your organization." return { "page_name": "Request to become a mentor", "request": self.data.request_entity, "org": self.data.organization, "actions": self.ACTIONS, "status_msg": status_msg, "user_name": self.data.requester_profile.name(), "user_link_id": self.data.requester.link_id, "user_email": accounts.denormalizeAccount(self.data.requester.account).email(), "show_actions": show_actions, "can_accept": can_accept, "can_reject": can_reject, "can_withdraw": can_withdraw, "can_resubmit": can_resubmit, }
def sendNewNotificationMessage(notification_entity): """Sends an email to a user about a new notification. Args: notification_entity: Notification about which the message should be sent """ from soc.logic.models.site import logic as site_logic from soc.views.models.notification import view as notification_view # create the url to show this notification notification_url = 'http://%(host)s%(index)s' % { 'host' : system.getHostname(), 'index': redirects.getPublicRedirect(notification_entity, notification_view.getParams())} sender = mail_dispatcher.getDefaultMailSender() site_entity = site_logic.getSingleton() site_name = site_entity.site_name # get the default mail sender default_sender = mail_dispatcher.getDefaultMailSender() if not default_sender: # no valid sender found, abort logging.error('No default sender') return else: (sender_name, sender) = default_sender to = accounts.denormalizeAccount(notification_entity.scope.account).email() subject = DEF_NEW_NOTIFICATION_MSG_SUBJECT_FMT % notification_entity.subject # create the message contents messageProperties = { 'to_name': notification_entity.scope.name, 'sender_name': sender_name, 'to': to, 'sender': sender, 'site_name': site_name, 'subject': force_unicode(subject), 'notification' : notification_entity, 'notification_url' : notification_url } # send out the message using the default new notification template mail_dispatcher.sendMailFromTemplate('soc/mail/new_notification.html', messageProperties)
def testUpdateUserCapsEntity(self): """Test that capital email address will be denormalized on update. """ email = "*****@*****.**" account = users.User(email=email) name = 'Updated User' properties = { 'account': account, 'link_id': self.entity.link_id, 'name': name, } user_logic.updateOrCreateFromFields(properties) entity = user_logic.getFromKeyName(self.entity.link_id) denormalized = accounts.denormalizeAccount(entity.account) self.failUnlessEqual(account.email().lower(), denormalized.email())
def _review(self, request, params, app_entity, status, **kwargs): """Sends out an email if an org_app has been accepted or rejected. For params see group_app.View._review(). """ if status == 'accepted' or status == 'rejected': default_sender = mail_dispatcher.getDefaultMailSender() if not default_sender: # no default sender abort return else: (sender_name, sender) = default_sender # construct the contents of the email admin_entity = app_entity.applicant backup_entity = app_entity.backup_admin context = { 'sender': sender, 'sender_name': sender_name, 'program_name': app_entity.scope.name, 'org_app_name': app_entity.name } if status == 'accepted': # use the accepted template and subject template = params['accepted_mail_template'] context['subject'] = 'Congratulations!' context['HTTP_host'] = 'http://%s' % (os.environ['HTTP_HOST']) elif status == 'rejected': # use the rejected template and subject template = params['rejected_mail_template'] context['subject'] = 'Thank you for your application' for to in [admin_entity, backup_entity]: if not to: continue email = accounts.denormalizeAccount(to.account).email() context['to'] = email context['to_name'] = to.name # send out the constructed email mail_dispatcher.sendMailFromTemplate(template, context)
def _review(self, request, params, app_entity, status, **kwargs): """Sends out an email if an org_app has been accepted or rejected. For params see group_app.View._review(). """ if status == 'accepted' or status == 'rejected': default_sender = mail_dispatcher.getDefaultMailSender() if not default_sender: # no default sender abort return else: (sender_name, sender) = default_sender # construct the contents of the email admin_entity = app_entity.applicant backup_entity = app_entity.backup_admin context = { 'sender': sender, 'sender_name': sender_name, 'program_name': app_entity.scope.name, 'org_app_name': app_entity.name } if status == 'accepted': # use the accepted template and subject template = params['accepted_mail_template'] context['subject'] = 'Congratulations!' context['HTTP_host'] = 'http://%s' % (system.getHostname()) elif status == 'rejected': # use the rejected template and subject template = params['rejected_mail_template'] context['subject'] = 'Thank you for your application' for to in [admin_entity, backup_entity]: if not to: continue email = accounts.denormalizeAccount(to.account).email() context['to'] = email context['to_name'] = to.name # send out the constructed email mail_dispatcher.sendMailFromTemplate(template, context)
def sendNewNotificationMessage(notification_entity): """Sends an email to a user about a new notification. Args: notification_entity: Notification about which the message should be sent """ # pylint: disable-msg=W0612 import soc.views.models.notification # create the url to show this notification notification_url = "http://%(host)s%(index)s" % { 'host' : os.environ['HTTP_HOST'], 'index': redirects.getPublicRedirect(notification_entity, model_view.notification.view.getParams())} sender = mail_dispatcher.getDefaultMailSender() site_entity = model_logic.site.logic.getSingleton() site_name = site_entity.site_name # get the default mail sender default_sender = mail_dispatcher.getDefaultMailSender() if not default_sender: # no valid sender found, abort return else: (sender_name, sender) = default_sender to = accounts.denormalizeAccount(notification_entity.scope.account).email() # create the message contents messageProperties = { 'to_name': notification_entity.scope.name, 'sender_name': sender_name, 'to': to, 'sender': sender, 'site_name': site_name, 'subject': force_unicode(DEF_NEW_NOTIFICATION_MSG), 'notification' : notification_entity, 'notification_url' : notification_url } # send out the message using the default new notification template mail_dispatcher.sendMailFromTemplate('soc/mail/new_notification.html', messageProperties)
def sendTaskUpdateMail(subscriber, subject, message_properties=None): """Sends an email to a user about an update to a Task. Args: subscriber: The user entity to whom the message must be sent subject: Subject of the mail message_properties: The mail message properties template: Optional django template that is used to build the message body """ from soc.logic.models.site import logic as site_logic site_entity = site_logic.getSingleton() site_name = site_entity.site_name # get the default mail sender default_sender = mail_dispatcher.getDefaultMailSender() if not default_sender: # no valid sender found, abort return else: (sender_name, sender) = default_sender to = accounts.denormalizeAccount(subscriber.account).email() # create the message contents new_message_properties = { 'to_name': subscriber.name, 'sender_name': sender_name, 'to': to, 'sender': sender, 'site_name': site_name, 'subject': force_unicode(subject), } messageProperties = dicts.merge(message_properties, new_message_properties) template = 'modules/ghop/task/update_notification' # send out the message using the default new notification template mail_dispatcher.sendMailFromTemplate(template, messageProperties)
def sendWelcomeMessage(user_entity): """Sends out a welcome message to a user. Args: user_entity: User entity which the message should be send to """ from soc.logic.models.site import logic as site_logic # get site name site_entity = site_logic.getSingleton() site_name = site_entity.site_name # get the default mail sender default_sender = mail_dispatcher.getDefaultMailSender() if not default_sender: # no valid sender found, should not happen but abort anyway logging.error('No default sender') return else: sender_name, sender = default_sender to = accounts.denormalizeAccount(user_entity.account).email() # create the message contents messageProperties = { 'to_name': user_entity.name, 'sender_name': sender_name, 'to': to, 'sender': sender, 'subject': DEF_WELCOME_MSG_FMT % { 'site_name': site_name, 'name': user_entity.name }, 'site_name': site_name, 'site_location': 'http://%s' % system.getHostname(), } # send out the message using the default welcome template mail_dispatcher.sendMailFromTemplate('soc/mail/welcome.html', messageProperties)
def sendMail(to_user, subject, message_properties, template): """Sends an email with the specified properties and mail content Args: to_user: user entity to whom the mail should be sent subject: subject of the mail message_properties: contains those properties that need to be customized template: template that holds the content of the mail """ from soc.logic.models.site import logic as site_logic site_entity = site_logic.getSingleton() site_name = site_entity.site_name # get the default mail sender default_sender = mail_dispatcher.getDefaultMailSender() if not default_sender: # no valid sender found, abort return else: (sender_name, sender) = default_sender to = accounts.denormalizeAccount(to_user.account).email() # create the message contents new_message_properties = { 'to_name': to_user.name, 'sender_name': sender_name, 'to': to, 'sender': sender, 'site_name': site_name, 'subject': force_unicode(subject) } messageProperties = dicts.merge(message_properties, new_message_properties) # send out the message using the default new notification template mail_dispatcher.sendMailFromTemplate(template, messageProperties)
def context(self): context = { 'user_email': accounts.denormalizeAccount(self.data.user.account).email(), 'link_id': self.data.user.link_id, 'logout_link': self.data.redirect.logout().url(), 'dashboard_link': self.data.redirect.dashboard().url() } if self.data.profile: if self.data.is_student and self.data.profile.status == 'active': q = GCITask.all() q.filter('student', self.data.profile) q.filter('status IN', ACTIVE_CLAIMED_TASK) task = q.get() if task: context['task'] = task context['time_left'] = self.getTimeLeftForTask(task) task_url = self.data.redirect.id( task.key().id()).urlOf('gci_view_task') context['task_url'] = task_url return context
def context(self): """Handler to for GSoC Show Request Page HTTP get request. """ assert isSet(self.data.request_entity) assert isSet(self.data.can_respond) assert isSet(self.data.organization) assert isSet(self.data.requester) show_actions = self.data.request_entity.status in ['pending', 'withdrawn'] if self.data.can_respond and self.data.request_entity.status == 'rejected': show_actions = True return { 'page_name': "Request to become a mentor", 'request': self.data.request_entity, 'org': self.data.organization, 'actions': self.ACTIONS, 'user_name': self.data.requester.name, 'user_email': accounts.denormalizeAccount( self.data.requester.account).email(), 'show_actions': show_actions, 'can_respond': self.data.can_respond, }
def orgAppContext(data, record, new_status, apply_url): """Sends out an invite notification to the applicant of the Organization. Args: data: a RequestData object """ message_properties = { 'url': apply_url + '?org_id=' + record.org_id, 'program_name': data.program.name, 'org': record.name, } if new_status == 'accepted': subject = DEF_ACCEPTED_ORG % message_properties template = DEF_ACCEPTED_ORG_TEMPLATE else: subject = DEF_REJECTED_ORG % message_properties template = DEF_REJECTED_ORG_TEMPLATE roles = [record.main_admin, record.backup_admin] emails = [denormalizeAccount(i.account).email() for i in roles if i] return getContext(data, emails, message_properties, subject, template)
def context(self): """Handler to for GSoC Show Invitation Page HTTP get request. """ assert isSet(self.data.invite) assert isSet(self.data.can_respond) assert isSet(self.data.organization) assert isSet(self.data.invited_user) show_actions = self.data.invite.status == 'pending' if self.data.can_respond and self.data.invite.status == 'rejected': show_actions = True return { 'request': self.data.invite, 'page_name': "Invite", 'org': self.data.organization, 'actions': self.ACTIONS, 'user_name': self.data.invited_user.name, 'user_email': accounts.denormalizeAccount( self.data.invited_user.account).email(), 'show_actions': show_actions, 'can_respond': self.data.can_respond, }
def context(self): context = { 'user_email': accounts.denormalizeAccount(self.data.user.account).email(), 'link_id': self.data.user.link_id, 'logout_link': links.LINKER.logout(self.data.request), 'dashboard_link': links.LINKER.program( self.data.program, 'gci_dashboard') } # TODO(daniel): simplify this if statement if self.data.ndb_profile: if (self.data.ndb_profile.is_student and self.data.ndb_profile.status == profile_model.Status.ACTIVE): q = GCITask.all() q.filter('student', self.data.ndb_profile.key.to_old_key()) q.filter('status IN', ACTIVE_CLAIMED_TASK) task = q.get() if task: context['task'] = task context['time_left'] = self.getTimeLeftForTask(task) task_url = self.data.redirect.id( task.key().id()).urlOf('gci_view_task') context['task_url'] = task_url return context
def context(self): """Handler to for GSoC Show Invitation Page HTTP get request. """ assert isSet(self.data.invite) assert isSet(self.data.can_respond) assert isSet(self.data.organization) assert isSet(self.data.invited_user) assert isSet(self.data.invited_profile) assert self.data.invited_profile # This code is dupcliated between request and invite status = self.data.invite.status can_accept = can_reject = can_withdraw = can_resubmit = False if self.data.can_respond: # invitee speaking if status == 'pending': can_accept = True can_reject = True if status == 'rejected': can_accept = True else: # admin speaking if status == 'withdrawn': can_resubmit = True if status == 'pending': can_withdraw = True show_actions = can_accept or can_reject or can_withdraw or can_resubmit org_key = self.data.organization.key() status_msg = None if self.data.invited_profile.key() == self.data.profile.key(): if org_key in self.data.invited_profile.org_admin_for: status_msg = DEF_STATUS_FOR_USER_MSG % 'an organization administrator' elif org_key in self.data.invited_profile.mentor_for: status_msg = DEF_STATUS_FOR_USER_MSG % 'a mentor' else: if org_key in self.data.invited_profile.org_admin_for: status_msg = DEF_STATUS_FOR_ADMIN_MSG % 'an organization administrator' elif org_key in self.data.invited_profile.mentor_for: status_msg = DEF_STATUS_FOR_ADMIN_MSG % 'a mentor' return { 'request': self.data.invite, 'page_name': 'Invite', 'org': self.data.organization, 'actions': self.ACTIONS, 'status_msg': status_msg, 'user_name': self.data.invited_profile.name(), 'user_link_id': self.data.invited_user.link_id, 'user_email': accounts.denormalizeAccount( self.data.invited_user.account).email(), 'show_actions': show_actions, 'can_accept': can_accept, 'can_reject': can_reject, 'can_withdraw': can_withdraw, 'can_resubmit': can_resubmit, }