Example #1
0
  def testGetHostName(self):
    """Tests that a correct host name is returned.
    """
    test_data = RequestData()
    test_site = site.Site(link_id='test', hostname='test_host')
    test_data.site = test_site

    try:
      expected_host = os.environ['HTTP_HOST'] = 'some.testing.host.tld'
      self.assertEqual(system.getHostname(), expected_host)
    finally:
      if self.default_host is None:
        del os.environ['HTTP_HOST']
      else:
        os.environ['HTTP_HOST'] = self.default_host

    #test a data object    
    expected_host = 'test_host'
    self.assertEqual(system.getHostname(data=test_data), expected_host)

    test_data.site.hostname = ''
    try:
      expected_host = os.environ['HTTP_HOST'] = 'some.testing.host.tld'
      self.assertEqual(system.getHostname(data=test_data), expected_host)
    finally:
      if self.default_host is None:
        del os.environ['HTTP_HOST']
      else:
        os.environ['HTTP_HOST'] = self.default_host
Example #2
0
def sendInviteNotification(entity):
  """Sends out an invite notification to the user the request is for.

  Args:
    entity : A request containing the information needed to create the message
  """

  from soc.logic.models.user import logic as user_logic
  from soc.views.models.role import ROLE_VIEWS

  invitation_url = 'http://%(host)s%(index)s' % {
      'host' : system.getHostname(),
      'index': redirects.getInviteProcessRedirect(entity, None),
      }

  role_params = ROLE_VIEWS[entity.role].getParams()

  message_properties = {
      'role_verbose' : role_params['name'],
      'group': entity.group.name,
      'invitation_url': invitation_url,
      }

  subject = DEF_INVITATION_MSG_FMT % {
      'role_verbose' : role_params['name'],
      'group' : entity.group.name
      }

  template = DEF_GROUP_INVITE_NOTIFICATION_TEMPLATE

  from_user = user_logic.getCurrentUser()

  sendNotification(entity.user, from_user, message_properties, subject, template)
Example #3
0
def sendNewReviewNotification(to_user, review, reviewed_name, redirect_url):
  """Sends out a notification to alert the user of a new Review.

  Args:
    to_user: The user who should receive a notification
    review: The review which triggers this notification
    reviewed_name: Name of the entity reviewed
    redirect_url: URL to which the follower should be sent for more information
  """
  review_notification_url = 'http://%(host)s%(redirect_url)s' % {
      'host' : system.getHostname(),
      'redirect_url': redirect_url}
  
  message_properties = {'review_notification_url': review_notification_url,
      'reviewer_name': review.author_name(),
      'reviewed_name': reviewed_name,
      'review_content': review.content,
      'review_visibility': 'public' if review.is_public else 'private',
      }

  # determine the subject
  review_type = 'public' if review.is_public else 'private'
  subject = DEF_NEW_REVIEW_SUBJECT_FMT % (review_type, reviewed_name)

  template = DEF_NEW_REVIEW_NOTIFICATION_TEMPLATE

  # send the notification from the system
  # TODO(srabbelier): do this in a task instead
  sendNotification(to_user, None, message_properties, subject, template)
Example #4
0
def sendNewOrganizationNotification(entity, module_name):
  """Sends out an invite notification to the applicant of the Organization.

  Args:
    entity : An accepted OrgAppRecord
  """

  program_entity = entity.survey.scope

  url = 'http://%(host)s%(redirect)s' % {
      'redirect': redirects.getApplicantRedirect(entity,
      {'url_name': '%s/org' % module_name,
       'program': program_entity}),
      'host': system.getHostname(),
      }

  message_properties = {
      'org_name': entity.name,
      'program_name': program_entity.name,
      'url': url
      }

  subject = DEF_NEW_ORG_MSG_FMT % {
      'group_name': entity.name,
      }

  template = DEF_NEW_ORG_TEMPLATE

  for to in [entity.main_admin, entity.backup_admin]:
    if not to:
      continue

    sendNotification(to, None, message_properties, subject, template)
Example #5
0
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=[])
Example #6
0
def sendNewRequestNotification(request_entity):
  """Sends out a notification to the persons who can process this Request.

  Args:
    request_entity: an instance of Request model
  """

  from soc.logic.helper import notifications
  from soc.logic.models.role import ROLE_LOGICS
  from soc.views.models.role import ROLE_VIEWS

  # get the users who should get the notification
  to_users = []

  # retrieve the Role Logics which we should query on
  role_logic = ROLE_LOGICS[request_entity.role]
  role_logics_to_notify = role_logic.getRoleLogicsToNotifyUponNewRequest()

  # the scope of the roles is the same as the scope of the Request entity
  fields = {'scope': request_entity.group,
            'status': 'active'}

  for role_logic in role_logics_to_notify:
    roles = role_logic.getForFields(fields)

    for role_entity in roles:
      # TODO: this might lead to double notifications
      to_users.append(role_entity.user)

  # get the user the request is from
  user_entity = request_entity.user

  role_params = ROLE_VIEWS[request_entity.role].getParams()

  request_url = 'http://%(host)s%(redirect)s' % {
      'host': system.getHostname(),
      'redirect': redirects.getProcessRequestRedirect(request_entity, None),
      }

  message_properties = {
      'requester': user_entity.name,
      'role_verbose': role_params['name'],
      'group': request_entity.group.name,
      'request_url': request_url
      }

  subject = DEF_NEW_REQUEST_MSG_FMT % {
      'requester': user_entity.name,
      'role_verbose' : role_params['name'],
      'group' : request_entity.group.name
      }

  template = DEF_NEW_REQUEST_NOTIFICATION_TEMPLATE

  for to_user in to_users:
    notifications.sendNotification(to_user, None, message_properties,
                                   subject, template)
Example #7
0
def isReferrerSelf(request,
                   expected_prefix=None, suffix=None, url_name=None):
  """Returns True if HTTP referrer path starts with the HTTP request path.
    
  Args:
    request: the Django HTTP request object; request.path is used if
      expected_path is not supplied (the most common usage)
    expected_prefix: optional HTTP path to use instead of the one in
      request.path; default is None (use request.path)
    suffix: suffix to remove from the HTTP request path before comparing
      it to the HTTP referrer path in the HTTP request object headers
      (this is often an link ID, for example, that may be changing from
      a POST referrer to a GET redirect target) 
    url_name: url name of the entity that is being created
  
  Returns:
    True if HTTP referrer path begins with the HTTP request path (either
      request.path or expected_prefix instead if it was supplied), after
      any suffix was removed from that request path
    False otherwise
       
  """
  http_from = request.META.get('HTTP_REFERER')

  if not http_from:
    # no HTTP referrer, so cannot possibly start with expected prefix
    return False

  http_host = 'http://%s/%s' % (system.getHostname(), url_name)

  if http_from.startswith(http_host):
    return True

  from_path = urlparse.urlparse(http_from).path

  if not expected_prefix:
    # use HTTP request path, since expected_prefix was not supplied
    expected_prefix = request.path

  if suffix:
    # remove suffix (such as a link ID) before comparison
    chars_to_remove = len(suffix)
    
    if not suffix.startswith('/'):
      chars_to_remove = chars_to_remove + 1

    expected_prefix = expected_prefix[:-chars_to_remove]

  if not from_path.startswith(expected_prefix):
    # expected prefix did not match first part of HTTP referrer path
    return False

  # HTTP referrer started with (possibly truncated) expected prefix
  return True
Example #8
0
  def assignSlots(self, request, access_type, page_name=None,
                  params=None, **kwargs):
    """View that allows to assign slots to orgs.
    """

    from soc.modules.gsoc.views.models.organization import view as org_view

    program_entity = program_logic.getFromKeyFieldsOr404(kwargs)
    description = self.DEF_SLOTS_ALLOCATION_MSG

    org_params = org_view.getParams().copy()
    org_params['list_description'] = description
    org_params['list_template'] = "modules/gsoc/program/list/allocation.html"
    org_params['public_field_props'] = {
        "link_id": {
            "hidden": True,
        }
    }
    org_params['public_row_action'] = {}
    org_params['public_row_extra'] = lambda entity: {}
    org_params['public_conf_extra'] = {
        "rowNum": -1,
        "rowList": [],
    }
    org_params['public_field_keys'] = [
        "name", "slots_desired", "nr_applications", "nr_mentors",
        "locked", "slots_ass", "slots", "link_id",
    ]
    org_params['public_field_names'] = [
        "Name", "Desired", "#Proposals", "#Mentors",
        "Locked?", "Slots Assigned", "Slots Visible to Org", "Link ID",
    ]

    fields = {
        'scope': program_entity,
        'status': ['new', 'active', 'inactive']
        }

    return_url =  "http://%(host)s%(index)s" % {
      'host' : system.getHostname(),
      'index': redirects.getSlotsRedirect(program_entity, params)
      }

    context = {
        'total_slots': program_entity.slots,
        'uses_json': True,
        'uses_slot_allocator': True,
        'return_url': return_url,
        }

    return self.list(request, 'allow', page_name=page_name, params=org_params,
                     filter=fields, context=context)
Example #9
0
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)
Example #10
0
  def _fullUrl(self, url, full, secure):
    """Returns the full version of the url iff full.

    The full version starts with http:// and includes getHostname().
    """
    if (not full) and (system.isLocal() or not secure):
      return url

    if secure:
      protocol = 'https'
      hostname = system.getSecureHostname()
    else:
      protocol = 'http'
      hostname = system.getHostname(self._data)

    return '%s://%s%s' % (protocol, hostname, url)
Example #11
0
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)
Example #12
0
def getTaskCommentContext(task, comment, to_emails):
  """Sends out notifications to the subscribers.

  Args:
    task: task entity that comment made on.
    comment: comment entity.
    to_emails: list of recepients for the notification.
  """
  url_kwargs = {
    'sponsor': task.program.scope_path,
    'program': task.program.link_id,
    'id': task.key().id(),
  }

  task_url = 'http://%(host)s%(task)s' % {
      'host': system.getHostname(),
      'task': reverse('gci_view_task', kwargs=url_kwargs)}

  commented_by = comment.created_by.name if comment.created_by else "Melange"

  message_properties = {
      'commented_by': commented_by,
      'comment_title': comment.title,
      'comment_content': comment.content,
      'group': task.org.name,
      'program_name': task.program.name,
      'sender_name': 'The %s Team' % site.singleton().site_name,
      'task_title': task.title,
      'task_url': task_url,
  }

  subject = DEF_NEW_TASK_COMMENT_SUBJECT % message_properties
  template = DEF_NEW_TASK_COMMENT_NOTIFICATION_TEMPLATE
  body = loader.render_to_string(template, dictionary=message_properties)

  return mailer.getMailContext(to=[], subject=subject, html=body, bcc=to_emails)
Example #13
0
def createNotificationMail(request, *args, **kwargs):
  """Appengine task that sends mail to the subscribed users.

  Expects the following to be present in the POST dict:
    comment_key: Specifies the comment id for which to send the notifications
    task_key: Specifies the task key name for which the comment belongs to

  Args:
    request: Django Request object
  """

  from soc.modules.gci.logic.helper import notifications as gci_notifications

  from soc.modules.gci.logic.models import comment as gci_comment_logic
  from soc.modules.gci.logic.models import task_subscription as \
      gci_task_subscription_logic

  # set default batch size
  batch_size = 10

  post_dict = request.POST

  comment_key = post_dict.get('comment_key')
  task_key = post_dict.get('task_key')

  if not (comment_key and task_key):
    # invalid task data, log and return OK
    return error_handler.logErrorAndReturnOK(
        'Invalid createNotificationMail data: %s' % post_dict)

  comment_key = long(comment_key)

  # get the task entity under which the specified comment was made
  task_entity = gci_task_logic.logic.getFromKeyName(task_key)

  # get the comment for the given id
  comment_entity = gci_comment_logic.logic.getFromID(
      comment_key, task_entity)

  if not comment_entity:
    # invalid comment specified, log and return OK
    return error_handler.logErrorAndReturnOK(
        'Invalid comment specified: %s/%s' % (comment_key, task_key))

  # check and retrieve the subscriber_start_key that has been done last
  idx = post_dict.get('subscriber_start_index', '')
  subscriber_start_index = int(idx) if idx.isdigit() else 0

  # get all subscribers to GCI task
  fields = {
      'task': task_entity,
      }

  ts_entity = gci_task_subscription_logic.logic.getForFields(
      fields, unique=True)

  subscribers = db.get(ts_entity.subscribers[
      subscriber_start_index:subscriber_start_index+batch_size])

  task_url = "http://%(host)s%(task)s" % {
                 'host': system.getHostname(),
                 'task': redirects.getPublicRedirect(
                     task_entity, {'url_name': 'gci/task'}),
                 }

  # create the data for the mail to be sent
  message_properties = {
      'task_url': task_url,
      'redirect_url': "%(task_url)s#c%(cid)d" % {
          'task_url': task_url,
          'cid': comment_entity.key().id_or_name()
          },
      'comment_entity': comment_entity,
      'task_entity': task_entity,
  }

  subject = DEF_TASK_UPDATE_SUBJECT_FMT % {
      'program_name': task_entity.program.short_name,
      'title': task_entity.title,
      }

  for subscriber in subscribers:
    gci_notifications.sendTaskUpdateMail(subscriber, subject,
                                          message_properties)

  if len(subscribers) == batch_size:
    # spawn task for sending out notifications to next set of subscribers
    next_start = subscriber_start_index + batch_size

    task_params = {
        'comment_key': comment_key,
        'task_key': task_key,
        'subscriber_start_index': next_start
        }
    task_url = '/tasks/gci/task/mail/create'

    new_task = taskqueue.Task(params=task_params, url=task_url)
    new_task.add('mail')

  # return OK
  return http.HttpResponse()
Example #14
0
    def sendCommentNotificationMail(self, request, *args, **kwargs):
        """Appengine task that sends mail to the subscribed users.

    Expects the following to be present in the POST dict:
      comment_key: Specifies the comment id for which to send the notifications

    Args:
      request: Django Request object
    """
        # TODO(ljvderijk): If all mails are equal we can sent one big bcc mail

        # set default batch size
        batch_size = 10

        post_dict = request.POST

        comment_key = post_dict.get("comment_key")

        if not comment_key:
            # invalid task data, log and return OK
            return error_handler.logErrorAndReturnOK("Invalid createNotificationMail data: %s" % post_dict)

        comment_key = db.Key(comment_key)
        comment = GCIComment.get(comment_key)

        if not comment:
            # invalid comment specified, log and return OK
            return error_handler.logErrorAndReturnOK("Invalid comment specified: %s" % (comment_key))

        task = comment.parent()
        subscription = GCITaskSubscription.all().ancestor(task).fetch(1)

        # check and retrieve the subscriber_start_key that has been done last
        idx = int(post_dict.get("subscriber_start_index", 0))
        subscribers = db.get(subscription.subscribers[idx : idx + batch_size])

        url_kwargs = {
            "sponsor": task.program.scope_path,
            "program": task.program.link_id,
            "id": task.key().id_or_name(),
        }
        task_url = "http://%(host)s%(task)s" % {
            "host": system.getHostname(),
            "task": reverse("gci_view_task", kwargs=url_kwargs),
        }

        # create the data for the mail to be sent
        message_properties = {
            "task_url": task_url,
            "redirect_url": "%(task_url)s#c%(cid)d" % {"task_url": task_url, "cid": comment.key().id_or_name()},
            "comment_entity": comment,
            "task_entity": task,
        }

        subject = self.DEF_TASK_UPDATE_SUBJECT % {"program_name": task.program.short_name, "title": task.title}

        for subscriber in subscribers:
            # TODO(ljvderijk): enable sending of mail after template fixes
            # gci_notifications.sendTaskUpdateMail(subscriber, subject,
            #                                      message_properties)
            pass

        if len(subscribers) == batch_size:
            # spawn task for sending out notifications to next set of subscribers
            next_start = idx + batch_size

            task_params = {"comment_key": str(comment_key), "subscriber_start_index": next_start}
            task_url = "/tasks/gci/task/mail/comment"

            new_task = taskqueue.Task(params=task_params, url=task_url)
            new_task.add("mail")

        # return OK
        return http.HttpResponse()
Example #15
0
  def sendSurveyReminderForProject(self, request, *args, **kwargs):
    """Sends a reminder mail for a given StudentProject and Survey.

    A reminder is only send if no record is on file for the given Survey and 
    StudentProject.

    Expects the following to be present in the POST dict:
      survey_key: specifies the key name for the ProjectSurvey to send reminders
                  for
      survey_type: either project or grading depending on the type of Survey
      project_key: encoded Key which specifies the project to send a reminder 
                   for

    Args:
      request: Django Request object
    """
    post_dict = request.POST

    project_key = post_dict.get('project_key')
    survey_key = post_dict.get('survey_key')
    survey_type = post_dict.get('survey_type')

    if not (project_key and survey_key and survey_type):
      # invalid task data, log and return OK
      return error_handler.logErrorAndReturnOK(
          'Invalid sendSurveyReminderForProject data: %s' % post_dict)

    # set model depending on survey type specified in POST
    if survey_type == 'project':
      survey_model = ProjectSurvey
      record_model = GSoCProjectSurveyRecord
    elif survey_type == 'grading':
      survey_model = GradingProjectSurvey
      record_model = GSoCGradingProjectSurveyRecord
    else:
      return error_handler.logErrorAndReturnOK(
          '%s is an invalid survey_type' %survey_type)

    # retrieve the project and survey
    project_key = db.Key(project_key)
    project = GSoCProject.get(project_key)
    if not project:
      # no existing project found, log and return OK
      return error_handler.logErrorAndReturnOK(
          'Invalid project specified %s:' % project_key)

    survey = survey_model.get_by_key_name(survey_key)
    if not survey:
      # no existing survey found, log and return OK
      return error_handler.logErrorAndReturnOK(
          'Invalid survey specified %s:' % survey_key)

    # try to retrieve an existing record
    q = record_model.all()
    q.filter('project', project)
    q.filter('survey', survey)
    record = q.get()

    if not record:
      # send reminder email because we found no record
      student_profile = project.parent()
      site_entity = site.singleton()

      if survey_type == 'project':
        url_name = 'gsoc_take_student_evaluation'

        to_name = student_profile.name()
        to_address = student_profile.email
        mail_template = 'v2/modules/gsoc/reminder/student_eval_reminder.html'
      elif survey_type == 'grading':
        url_name = 'gsoc_take_mentor_evaluation'

        mentors = db.get(project.mentors)
        to_address = [m.email for m in mentors]
        to_name = 'mentor(s) for project "%s"' %(project.title)
        mail_template = \
            'v2/modules/gsoc/reminder/mentor_eval_reminder.html'

      program = project.program
      hostname = system.getHostname()
      url_kwargs = {
          'sponsor': program.scope.link_id,
          'program': program.link_id,
          'survey': survey.link_id,
          'user': student_profile.link_id,
          'id': str(project.key().id()),
          }
      url = reverse(url_name, kwargs=url_kwargs)
      survey_url = '%s://%s%s' % ('http', hostname, url)

      # set the context for the mail template
      mail_context = {
          'student_name': student_profile.name(),
          'project_title': project.title,
          'survey_url': survey_url,
          'survey_end': survey.survey_end,
          'to_name': to_name,
          'site_name': site_entity.site_name,
          'sender_name': "The %s Team" % site_entity.site_name,
      }

      # set the sender
      (_, sender_address) = mail_dispatcher.getDefaultMailSender()
      mail_context['sender'] = sender_address
      # set the receiver and subject
      mail_context['to'] = to_address
      mail_context['subject'] = \
          'Evaluation Survey "%s" Reminder' %(survey.title)

      # find all org admins for the project's organization
      org = project.org

      q = GSoCProfile.all()
      q.filter('status', 'active')
      q.filter('org_admin_for', org)
      org_admins = q.fetch(1000)

      # collect email addresses for all found org admins
      org_admin_addresses = []

      for org_admin in org_admins:
        org_admin_addresses.append(org_admin.email)

      if org_admin_addresses:
        mail_context['cc'] = org_admin_addresses

      # send out the email
      mail_dispatcher.sendMailFromTemplate(mail_template, mail_context)

    # return OK
    return http.HttpResponse()
Example #16
0
def sendSurveyReminderForProject(request, *args, **kwargs):
  """Sends a reminder mail for a given StudentProject and Survey.

  A reminder is only send if no record is on file for the given Survey and 
  StudentProject.

  Expects the following to be present in the POST dict:
    survey_key: specifies the key name for the ProjectSurvey to send reminders
                for
    survey_type: either project or grading depending on the type of Survey
    project_key: key which specifies the project to send a reminder for

  Args:
    request: Django Request object
  """

  from soc.logic import mail_dispatcher
  from soc.logic.models.site import logic as site_logic
  from soc.views.helper import redirects

  from soc.modules.gsoc.logic.models.org_admin import logic as org_admin_logic
  from soc.modules.gsoc.logic.models.student_project import logic as \
      student_project_logic
  from soc.modules.gsoc.logic.models.survey import grading_logic
  from soc.modules.gsoc.logic.models.survey import project_logic

  post_dict = request.POST

  project_key = post_dict.get('project_key')
  survey_key = post_dict.get('survey_key')
  survey_type = post_dict.get('survey_type')

  if not (project_key and survey_key and survey_type):
    # invalid task data, log and return OK
    return error_handler.logErrorAndReturnOK(
        'Invalid sendSurveyReminderForProject data: %s' % post_dict)

  # set logic depending on survey type specified in POST
  if survey_type == 'project':
    survey_logic = project_logic
  elif survey_type == 'grading':
    survey_logic = grading_logic

  # retrieve the project and survey
  student_project = student_project_logic.getFromKeyName(project_key)

  if not student_project:
    # no existing project found, log and return OK
    return error_handler.logErrorAndReturnOK(
        'Invalid project specified %s:' % project_key)

  survey = survey_logic.getFromKeyName(survey_key)

  if not survey:
    # no existing survey found, log and return OK
    return error_handler.logErrorAndReturnOK(
        'Invalid survey specified %s:' % survey_key)

  # try to retrieve an existing record
  record_logic = survey_logic.getRecordLogic()

  fields = {'project': student_project,
            'survey': survey}
  record_entity = record_logic.getForFields(fields, unique=True)

  if not record_entity:
    # send reminder email because we found no record

    student_entity = student_project.student
    site_entity = site_logic.getSingleton()

    if survey_type == 'project':
      survey_redirect = redirects.getTakeSurveyRedirect(
          survey,{'url_name': 'gsoc/project_survey'})
      to_role = student_entity
      mail_template = 'soc/project_survey/mail/reminder_gsoc.html'
    elif survey_type == 'grading':
      survey_redirect = redirects.getTakeSurveyRedirect(
          survey,{'url_name': 'gsoc/grading_project_survey'})
      to_role = student_project.mentor
      mail_template = 'soc/grading_project_survey/mail/reminder_gsoc.html'

    survey_url = "http://%(host)s%(redirect)s" % {
      'redirect': survey_redirect,
      'host': system.getHostname(),
      }

    # set the context for the mail template
    mail_context = {
        'student_name': student_entity.name(),
        'project_title': student_project.title,
        'survey_url': survey_url,
        'survey_end': survey.survey_end,
        'to_name': to_role.name(),
        'site_name': site_entity.site_name,
    }

    # set the sender
    (_, sender_address) = mail_dispatcher.getDefaultMailSender()
    mail_context['sender'] = sender_address
    # set the receiver and subject
    mail_context['to'] = to_role.email
    mail_context['subject'] = 'Evaluation Survey "%s" Reminder' %(survey.title)

    # find all org admins for the project's organization
    org_entity = student_project.scope

    fields = {'scope': org_entity,
              'status': 'active'}
    org_admin_entities = org_admin_logic.getForFields(fields)

    # collect email addresses for all found org admins
    org_admin_addresses = []

    for org_admin_entity in org_admin_entities:
      org_admin_addresses.append(org_admin_entity.email)

    if org_admin_addresses:
      mail_context['cc'] = org_admin_addresses

    # send out the email
    mail_dispatcher.sendMailFromTemplate(mail_template, mail_context)

  # return OK
  return http.HttpResponse()