Added Student Proposal Mailer module for mailing students who are accepted/rejected into the program.
authorLennard de Rijk <ljvderijk@gmail.com>
Sat, 18 Apr 2009 21:21:22 +0000
changeset 2223 7b8b812aa146
parent 2222 a91d55e9c9cd
child 2224 fc719e902a70
Added Student Proposal Mailer module for mailing students who are accepted/rejected into the program. TODO has been added to actually sent out the emails. Patch by: Lennard de Rijk Reviewed by: to-be-reviewed
app/index.yaml
app/soc/cron/student_proposal_mailer.py
--- a/app/index.yaml	Sat Apr 18 19:00:04 2009 +0000
+++ b/app/index.yaml	Sat Apr 18 21:21:22 2009 +0000
@@ -36,6 +36,12 @@
   - name: status
   - name: mentor
 
+# used for the bulk mailing of students
+- kind: Student
+  properties:
+  - name: scope
+  - name: __key__
+
 # AUTOGENERATED
 
 # This index.yaml is automatically updated whenever the dev_appserver
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/soc/cron/student_proposal_mailer.py	Sat Apr 18 21:21:22 2009 +0000
@@ -0,0 +1,150 @@
+#!/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>',
+  ]
+
+
+import logging
+
+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
+
+# property text_data for a sendStudentProposalMail Job
+DEF_STUDENT_PROPOSAL_MAIL_TEXT_DATA_FMT = '%s/proposal_mail'
+
+
+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:
+      text_data = DEF_STUDENT_PROPOSAL_MAIL_TEXT_DATA_FMT % (
+          student.key().name())
+
+      job_query_fields['text_data'] = text_data
+      mail_job = job_logic.getForFields(job_query_fields, unique=True)
+
+      if not mail_job:
+        # this student did not receive mail yet
+        job_fields['text_data'] = text_data
+        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:
+    # check if the student has an accepted proposal
+    fields['status'] = 'accepted'
+    accepted_proposal = proposal_logic.getForFields(fields, unique=True)
+
+    # TODO(ljvderijk) replace with real mail sending
+    if accepted_proposal:
+      logging.info('Sending acceptance mail to %s' % (student_entity.name()))
+    else:
+      logging.info('Sending rejectance mail to %s' % (student_entity.name()))
+
+  # we are done here
+  return
+