blob: a784ad288af9aa1938ab75a1d45d527c20abd537 [file] [log] [blame]
#!/usr/bin/env python2.5
#
# Copyright 2011 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.
"""Module for the GSoC proposal page.
"""
from google.appengine.ext import db
from django.utils.translation import ugettext
from soc.logic import cleaning
from soc.logic.exceptions import AccessViolation
from soc.logic.helper import notifications
from soc.views.helper import url_patterns
from soc.tasks import mailer
from soc.modules.gsoc.models.proposal import GSoCProposal
from soc.modules.gsoc.models.profile import GSoCProfile
from soc.modules.gsoc.views.base import RequestHandler
from soc.modules.gsoc.views.forms import GSoCModelForm
from soc.modules.gsoc.views.helper import url_patterns as gsoc_url_patterns
from soc.modules.gsoc.views.helper.url_patterns import url
class ProposalForm(GSoCModelForm):
"""Django form for the proposal page.
"""
class Meta:
model = GSoCProposal
css_prefix = 'gsoc_proposal'
exclude = ['status', 'mentor', 'possible_mentors', 'org', 'program',
'is_editable_post_deadline', 'created_on', 'last_modified_on',
'score', 'nr_scores', 'accept_as_project', 'extra', 'has_mentor']
clean_content = cleaning.clean_html_content('content')
class ProposalPage(RequestHandler):
"""View for the submit proposal.
"""
def djangoURLPatterns(self):
return [
url(r'proposal/submit/%s$' % url_patterns.ORG,
self, name='submit_gsoc_proposal'),
]
def checkAccess(self):
self.check.isLoggedIn()
self.check.isActiveStudent()
self.check.isOrganizationInURLActive()
self.check.canStudentPropose()
def templatePath(self):
return 'v2/modules/gsoc/proposal/base.html'
def buttonsTemplate(self):
return 'v2/modules/gsoc/proposal/_buttons_create.html'
def context(self):
if self.data.POST:
proposal_form = ProposalForm(self.data.POST)
else:
initial = {'content': self.data.organization.contrib_template}
proposal_form = ProposalForm(initial=initial)
return {
'page_name': 'Submit proposal',
'form_header_message': 'Submit proposal to %s' % (
self.data.organization.name),
'proposal_form': proposal_form,
'buttons_template': self.buttonsTemplate()
}
def createFromForm(self):
"""Creates a new proposal based on the data inserted in the form.
Returns:
a newly created proposal entity or None
"""
proposal_form = ProposalForm(self.data.POST)
if not proposal_form.is_valid():
return None
# set the organization and program references
proposal_form.cleaned_data['org'] = self.data.organization
proposal_form.cleaned_data['program'] = self.data.program
student_info_key = self.data.student_info.key()
q = GSoCProfile.all().filter('mentor_for', self.data.organization)
q = q.filter('status', 'active')
q.filter('notify_new_proposals', True)
mentors = q.fetch(1000)
to_emails = [i.email for i in mentors]
def create_proposal_trx():
student_info = db.get(student_info_key)
student_info.number_of_proposals += 1
student_info.put()
proposal = proposal_form.create(commit=True, parent=self.data.profile)
context = notifications.newProposalContext(self.data, proposal, to_emails)
sub_txn = mailer.getSpawnMailTaskTxn(context, parent=proposal)
sub_txn()
return proposal
return db.run_in_transaction(create_proposal_trx)
def post(self):
"""Handler for HTTP POST request.
"""
proposal = self.createFromForm()
if proposal:
self.redirect.review(proposal.key().id(),
self.data.user.link_id)
self.redirect.to('review_gsoc_proposal')
else:
self.get()
class UpdateProposal(RequestHandler):
"""View for the update proposal page.
"""
ACTIONS = {
'resubmit': 'Resubmit',
'update': 'Update',
'withdraw': 'Withdraw',
}
def djangoURLPatterns(self):
return [
url(r'proposal/update/%s$' % gsoc_url_patterns.PROPOSAL,
self, name='update_gsoc_proposal'),
]
def checkAccess(self):
self.check.isLoggedIn()
self.check.isActiveStudent()
self.data.proposal = GSoCProposal.get_by_id(
int(self.data.kwargs['id']), parent=self.data.profile)
self.data.organization = self.data.proposal.org
self.check.canStudentUpdateProposal()
if self.data.POST:
action = self.data.POST['action']
status = self.data.proposal.status
if status == 'pending' and action == self.ACTIONS['resubmit']:
error_msg = ugettext('You cannot resubmit a pending proposal')
raise AccessViolation(error_msg)
if status == 'withdrawn' and action == self.ACTIONS['withdraw']:
error_msg = ugettext('This proposal has already been withdrawn')
raise AccessViolation(error_msg)
if status == 'withdrawn' and action == self.ACTIONS['update']:
error_msg = ugettext('This proposal has been withdrawn')
raise AccessViolation(error_msg)
self.data.action = action
def templatePath(self):
return 'v2/modules/gsoc/proposal/base.html'
def buttonsTemplate(self):
return 'v2/modules/gsoc/proposal/_buttons_update.html'
def context(self):
proposal = self.data.proposal
proposal_form = ProposalForm(self.data.POST or None,
instance=proposal)
return {
'page_name': 'Update proposal',
'form_header_message': 'Update proposal to %s' % (proposal.org.name),
'proposal_form': proposal_form,
'is_pending': self.data.is_pending,
'buttons_template': self.buttonsTemplate(),
}
def _updateFromForm(self):
"""Updates a proposal based on the data inserted in the form.
Returns:
an updated proposal entity or None
"""
proposal_form = ProposalForm(self.data.POST, instance=self.data.proposal)
if not proposal_form.is_valid():
return None
q = GSoCProfile.all().filter('mentor_for', self.data.proposal.org)
q = q.filter('status', 'active')
q.filter('notify_proposal_updates', True)
mentors = q.fetch(1000)
to_emails = [i.email for i in mentors]
proposal_key = self.data.proposal.key()
def update_proposal_txn():
proposal = db.get(proposal_key)
proposal_form.instance = proposal
proposal = proposal_form.save(commit=True)
context = notifications.updatedProposalContext(self.data, proposal, to_emails)
sub_txn = mailer.getSpawnMailTaskTxn(context, parent=proposal)
sub_txn()
return proposal
return db.run_in_transaction(update_proposal_txn)
def _withdraw(self):
"""Withdraws a proposal.
"""
proposal_key = self.data.proposal.key()
def withdraw_proposal_txn():
proposal = db.get(proposal_key)
proposal.status = 'withdrawn'
proposal.put()
db.run_in_transaction(withdraw_proposal_txn)
def _resubmit(self):
"""Resubmits a proposal.
"""
proposal_key = self.data.proposal.key()
def resubmit_proposal_txn():
proposal = db.get(proposal_key)
proposal.status = 'pending'
proposal.put()
db.run_in_transaction(resubmit_proposal_txn)
def post(self):
"""Handler for HTTP POST request.
"""
if self.data.action == self.ACTIONS['update']:
proposal = self._updateFromForm()
if not proposal:
self.get()
return
elif self.data.action == self.ACTIONS['withdraw']:
self._withdraw()
elif self.data.action == self.ACTIONS['resubmit']:
self._resubmit()
self.redirect.review(self.data.proposal.key().id(), self.data.user.link_id)
self.redirect.to('review_gsoc_proposal')