app/soc/cron/student_proposal_mailer.py
author Mario Ferraro <fadinlight@gmail.com>
Sun, 15 Nov 2009 22:12:20 +0100
changeset 3093 d1be59b6b627
parent 2365 a66e1dd8ced7
permissions -rw-r--r--
GMaps related JS changed to use new google namespace. Google is going to change permanently in the future the way to load its services, so better stay safe. Also this commit shows uses of the new melange.js module. Fixes Issue 634.

#!/usr/bin/python2.5
#
# Copyright 2009 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Cron job handler for Student Proposal mailing.
"""

__authors__ = [
    '"Lennard de Rijk" <ljvderijk@gmail.com>',
  ]


from soc.logic import mail_dispatcher
from soc.logic.models.job import logic as job_logic
from soc.logic.models.priority_group import logic as priority_logic
from soc.logic.models.program import logic as program_logic
from soc.logic.models.student import logic as student_logic
from soc.logic.models.student_proposal import logic as proposal_logic


# amount of students to create jobs for before updating
DEF_STUDENT_STEP_SIZE = 10

# template for the accepted proposal mail
DEF_ACCEPTED_MAIL_TEMPLATE = \
    'gsoc/student_proposal/mail/accepted_gsoc2009.html'

# template for the rejected proposal mail
DEF_REJECTED_MAIL_TEMPLATE = \
    'gsoc/student_proposal/mail/rejected_gsoc2009.html'


def setupStudentProposalMailing(job_entity):
  """Job that setup jobs that will mail students if they have been accepted in
  a program with a GSoC-like workflow.

  Args:
    job_entity: a Job entity with key_data set to 
                [program, last_completed_student]
  """

  from soc.cron.job import FatalJobError


  # retrieve the data we need to continue our work
  key_data = job_entity.key_data
  program_key = key_data[0]
  program_keyname = program_key.name()

  program_entity = program_logic.getFromKeyName(program_keyname)

  if not program_entity:
    raise FatalJobError('The program with key %s could not be found' % (
        program_keyname))

  student_fields = {'scope': program_entity}

  if len(key_data) >= 2:
    # start where we left off
    student_fields['__key__ >'] = key_data[1]

  students = student_logic.getForFields(student_fields,
                                        limit=DEF_STUDENT_STEP_SIZE)

  # set the default fields for the jobs we are going to create
  priority_group = priority_logic.getGroup(priority_logic.EMAIL)
  job_fields = {
      'priority_group': priority_group,
      'task_name': 'sendStudentProposalMail'}

  job_query_fields = job_fields.copy()

  while students:
    # for each student create a mailing job
    for student in students:

      job_query_fields['key_data'] = student.key()
      mail_job = job_logic.getForFields(job_query_fields, unique=True)

      if not mail_job:
        # this student did not receive mail yet
        job_fields['key_data'] = [student.key()]
        job_logic.updateOrCreateFromFields(job_fields)

    # update our own job
    last_student_key = students[-1].key()

    if len(key_data) >= 2:
      key_data[1] = last_student_key
    else:
      key_data.append(last_student_key)

    updated_job_fields = {'key_data': key_data}
    job_logic.updateEntityProperties(job_entity, updated_job_fields)

    # rinse and repeat
    student_fields['__key__ >'] = last_student_key
    students = student_logic.getForFields(student_fields,
                                          limit=DEF_STUDENT_STEP_SIZE)

  # we are finished
  return


def sendStudentProposalMail(job_entity):
  """Job that will send out an email to a student that sent in a proposal
  that either got accepted or rejected.

  Args:
    job_entity: a Job entity with key_data set to [student_key]
  """

  from soc.cron.job import FatalJobError


  student_keyname = job_entity.key_data[0].name()
  student_entity = student_logic.getFromKeyName(student_keyname)

  if not student_entity:
    raise FatalJobError('The student with keyname %s does not exist!' % (
        student_keyname))

  # only students who have sent in a proposal will be mailed
  fields = {'scope': student_entity}
  proposal = proposal_logic.getForFields(fields, unique=True)

  if proposal:
    # a proposal has been found we must sent out an email
    default_sender = mail_dispatcher.getDefaultMailSender()

    if not default_sender:
      # no default sender abort
      raise FatalJobError('No valid sender address could be found, try '
                          'setting a no-reply address on the site settings '
                          'page')
    else:
      (sender_name, sender) = default_sender

    # construct the contents of the email
    # pylint: disable-msg=E1103
    student_entity = proposal.scope
    program_entity = proposal.program

    context = {
        'to': student_entity.email,
        'to_name': student_entity.given_name,
        'sender': sender,
        'sender_name': sender_name,
        'program_name': program_entity.name,
    }

    # check if the student has an accepted proposal
    fields['status'] = 'accepted'
    accepted_proposal = proposal_logic.getForFields(fields, unique=True)

    if accepted_proposal:
      # use the accepted template and subject
      template = DEF_ACCEPTED_MAIL_TEMPLATE
      context['subject'] = 'Congratulations!'
      context['proposal_title'] = accepted_proposal.title
      context['org_name'] = accepted_proposal.org.name
    else:
      # use the rejected template and subject
      template = DEF_REJECTED_MAIL_TEMPLATE
      context['subject'] = 'Thank you for applying to %s' % (
          program_entity.name)

    # send out the constructed email
    mail_dispatcher.sendMailFromTemplate(template, context)

  # we are done here
  return