blob: c848d245d2b6c7ecdceaf2582eafad4c34fe6f45 [file] [log] [blame]
# Copyright 2014 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 containing the views for proposal duplicates."""
import datetime
from google.appengine.ext import ndb
from django import http
from django.utils import translation
from mapreduce import model as mapreduce_model
from melange.logic import profile as profile_logic
from melange.models import job_status as job_status_model
from melange.request import access
from soc.mapreduce.helper import control as mapreduce_control
from soc.views.helper import url_patterns
from soc.views import base
from soc.views import template
from soc.modules.gsoc.views import base as gsoc_base
from soc.modules.gsoc.views.helper import url_patterns as soc_url_patterns
from summerofcode.logic import profile as soc_profile_logic
from summerofcode.mapreduce import find_duplicates
from summerofcode.request import error
from summerofcode.request import links
from summerofcode.request import render
from summerofcode.views.helper import urls as soc_urls
_CALCULATING_STATE = translation.ugettext('Calulating')
_COMPLETED_STATE = translation.ugettext('Completed')
_NOT_STARTED_STATE = translation.ugettext('Not started')
_UNKNOWN_STATE = translation.ugettext('Unknown')
_FIND_DUPLICATES_JOB_ID = 'find-duplicates'
class Duplicate(template.Template):
"""Template to display a single student with duplicates for the program."""
def __init__(self, data, url_names, profile):
"""Initializes a new template.
Args:
data: request_data.RequestData for the current request.
url_names: Instance of url_names.UrlNames.
profile: profile_model.Profile entity for which to display duplicates.
"""
super(Duplicate, self).__init__(data)
if not profile.is_student:
raise ValueError('Duplicates can be displayed only for student profiles.')
else:
self._url_names = url_names
self._profile = profile
def context(self):
"""See template.Template.context for specification."""
org_details = {}
proposals = ndb.get_multi(
self._profile.student_data.to_be_accepted_proposals)
for proposal in proposals:
if proposal.organization not in org_details:
organization = proposal.organization.get()
org_details[proposal.organization] = {
'admins': [],
'home_url': links.SOC_LINKER.organization(
organization.key, self._url_names.ORG_HOME),
'name': organization.name,
'proposals': [],
}
admins = profile_logic.getOrgAdmins(organization.key)
for admin in admins:
org_details[proposal.organization]['admins'].append({
'name': admin.public_name,
'email': admin.contact.email,
})
org_details[proposal.organization]['proposals'].append({
'review_url': links.SOC_LINKER.userId(
proposal.key.parent(), proposal.key.id(),
self._url_names.PROPOSAL_REVIEW_AS_ORG_MEMBER),
'title': proposal.title,
})
return {
'org_details': org_details,
'profile': self._profile,
}
def templatePath(self):
"""See template.Template.templatePath for specification."""
return 'modules/gsoc/duplicates/proposal_duplicate.html'
class DuplicatesPage(base.RequestHandler):
"""View for the program administrators to see duplicates."""
access_checker = access.PROGRAM_ADMINISTRATOR_ACCESS_CHECKER
def __init__(self, initializer, linker, renderer, error_handler,
url_pattern_constructor, url_names, template_path):
"""Initializes a new instance of the request handler for the specified
parameters.
Args:
initializer: Implementation of initialize.Initializer interface.
linker: Instance of links.Linker class.
renderer: Implementation of render.Renderer interface.
error_handler: Implementation of error.ErrorHandler interface.
url_pattern_constructor:
Implementation of url_patterns.UrlPatternConstructor.
url_names: Instance of url_names.UrlNames.
template_path: The path of the template to be used.
"""
super(DuplicatesPage, self).__init__(
initializer, linker, renderer, error_handler)
self.url_pattern_constructor = url_pattern_constructor
self.url_names = url_names
self.template_path = template_path
def djangoURLPatterns(self):
"""See base.RequestHandler.djangoURLPatterns for specification."""
return [
self.url_pattern_constructor.construct(
r'duplicates/%s$' % url_patterns.PROGRAM, self,
name=self.url_names.DUPLICATES),
]
def templatePath(self):
"""See base.RequestHandler.templatePath for specification."""
return 'modules/gsoc/duplicates/base.html'
def context(self, data, check, mutator):
"""See base.RequestHandler.context for specification."""
duplicates = [
Duplicate(data, self.url_names, profile) for profile
in soc_profile_logic.getProfilesWithDuplicates(data.program.key())]
job_status = job_status_model.JobStatus.get_by_id(_FIND_DUPLICATES_JOB_ID)
if job_status:
mapreduce_state = mapreduce_model.MapreduceState.get_by_key_name(
job_status.identifier)
if mapreduce_state:
calculation_state = (
_CALCULATING_STATE if mapreduce_state.active else _COMPLETED_STATE)
else:
calculation_state = _UNKNOWN_STATE
last_started_on = job_status.started_on
else:
calculation_state = _NOT_STARTED_STATE
last_started_on = None
context = {
'page_name': 'Duplicates for %s' % data.program.name,
'calculation_state': calculation_state,
'last_started_on': last_started_on,
'duplicates': duplicates,
}
return context
def post(self, data, check, mutator):
"""See base.RequestHandler.post for specification."""
_startFindDuplicateJob(data.program.key())
return http.HttpResponseRedirect('')
DUPLICATES = DuplicatesPage(
gsoc_base._GSOC_INITIALIZER, links.SOC_LINKER, render.SOC_RENDERER,
error.SOC_ERROR_HANDLER, soc_url_patterns.SOC_URL_PATTERN_CONSTRUCTOR,
soc_urls.UrlNames, 'modules/gsoc/duplicates/base.html')
def _startFindDuplicateJob(program_key):
params = {
find_duplicates.ENTITY_KIND_ID_PARAM: 'melange.models.profile.Profile',
find_duplicates.PROGRAM_KEY_URLSAFE_PARAM: str(program_key),
}
identifier = mapreduce_control.start_map('FindDuplicates', params=params)
@ndb.transactional
def createOrUpdateJobStatus():
job_status = job_status_model.JobStatus(
id=_FIND_DUPLICATES_JOB_ID, identifier=identifier,
started_on=datetime.datetime.utcnow())
job_status.put()
createOrUpdateJobStatus()