Source code for apps.project_sheet.views

#-- encoding: utf-8 --
#
# This file is part of I4P.
#
# I4P is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# I4P is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero Public License for more details.
# 
# You should have received a copy of the GNU Affero Public License
# along with I4P.  If not, see <http://www.gnu.org/licenses/>.
#
"""
Django Views for a Project Sheet
"""
try:
    from collections import OrderedDict
except ImportError:
    # Python < 2.7 compatibility
    from ordereddict import OrderedDict

import datetime
from operator import attrgetter

from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from django.db.models import Q
from django.forms.models import modelform_factory
from django.http import HttpResponseRedirect, HttpResponseForbidden, Http404
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template.context import RequestContext
from django.utils import translation, simplejson
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.http import require_POST
from django.views.generic.list_detail import object_list
from django.views.generic import TemplateView

from reversion.models import Version
from tagging.managers import ModelTaggedItemManager
from tagging.models import TaggedItem, Tag
from tagging.utils import get_tag

from .filters import FilterSet
from .forms import I4pProjectInfoForm, I4pProjectLocationForm
from .forms import I4pProjectObjectivesForm, I4pProjectThemesForm
from .forms import ProjectReferenceFormSet, ProjectMemberForm, AnswerForm
from .models import Answer, I4pProjectTranslation, ProjectPicture, ProjectVideo, SiteTopic, Topic
from .models import ProjectMember, I4pProject, VERSIONNED_FIELDS, Question
from .utils import build_filters_and_context
from .utils import get_or_create_project_translation_from_parent, get_or_create_project_translation_by_slug, create_parent_project
from .utils import get_project_translation_by_slug, get_project_translation_from_parent
from .utils import get_project_project_translation_recent_changes, fields_diff


[docs]def project_sheet_list(request): """ Display a listing of all projects """ language_code = translation.get_language() data = request.GET.copy() filter_forms_dict, extra_context = build_filters_and_context(data) ordered_project_sheets = I4pProjectTranslation.objects.none() filters = FilterSet(filter_forms_dict.values()) if filters.is_valid(): # First pass to filter project filtered_projects = filters.apply_to(queryset=I4pProject.on_site.all(), model_class=I4pProject) # Second pass to select language and site project_sheet_ids = [] for project in filtered_projects: project_sheet = get_project_translation_from_parent(project, language_code, fallback_language='en', fallback_any=True) project_sheet_ids.append(project_sheet.id) i18n_project_sheets = I4pProjectTranslation.objects.filter(id__in=project_sheet_ids) # Third pass to filter sheet filtered_project_sheets = filters.apply_to(queryset=i18n_project_sheets, model_class=I4pProjectTranslation) # Fourth pass to order sheet if data.get("order") == "creation": ordered_project_sheets = filtered_project_sheets.order_by('-project__created') extra_context["order"] = "creation" elif data.get("order") == "modification": ordered_project_sheets = filtered_project_sheets.order_by('-modified') extra_context["order"] = "modification" else: # By default, display the project listing using the following order: # best_of, random(). ordered_project_sheets = filtered_project_sheets.order_by('-project__best_of', '?') if data.has_key('page'): del data["page"] extra_context["getparams"] = data.urlencode() extra_context["orderparams"] = extra_context["getparams"]\ .replace("order=creation", "")\ .replace("order=modification", "") extra_context["selected_tags"] = [int(t.id) for t in filter_forms_dict["themes_filter"].cleaned_data["themes"]] extra_context.update(filter_forms_dict) extra_context["filters_tab_selected"] = True return object_list(request, template_name='project_sheet/project_list.html', queryset=ordered_project_sheets, # paginate_by=12, allow_empty=True, template_object_name='project_translation', extra_context=extra_context)
[docs]class ProjectStartView(TemplateView): """ When one starts a project, after having selected a topic """ template_name = 'project_sheet/project_sheet.html' def get_context_data(self, topic_slug, **kwargs): context = super(ProjectStartView, self).get_context_data(**kwargs) topic = get_object_or_404(Topic, slug=topic_slug) context['topic'] = topic return context
from wiki.models import Article, ArticleForObject from wiki.models import URLPath class TagPageView(TemplateView): template_name = 'project_sheet/tagpage.html' def get_context_data(self, tag, **kwargs): context = super(TagPageView, self).get_context_data(**kwargs) site = Site.objects.get_current() current_language_code = translation.get_language() tag_instance = get_tag(tag) if tag_instance is None: raise Http404(_('No Tag found matching "%s".') % tag) try: article = Article.get_for_object(tag_instance) except ArticleForObject.DoesNotExist: root_path = URLPath.root() article_path = URLPath.create_article( parent=root_path, slug=tag, site=site, title=tag ) article = article_path.article article.add_object_relation(tag_instance) context['article'] = article # context['article_path'] = article_path # XXX: site not taken in account context['tag'] = tag_instance context['related_tags'] = list( reversed( sorted(Tag.objects.related_for_model(tag_instance, I4pProjectTranslation, counts=True), key=attrgetter('count'), ) ) )[:15] # Get project sheets tagged with this tag # XXX: site=site may not be correct # 4 Random projects with at least one picture context['picture_project_translations'] = list(TaggedItem.objects.get_by_model(I4pProjectTranslation.objects.filter( language_code=current_language_code, project__site=site, project__pictures__isnull=False ), tag_instance).order_by('?')[:4]) # Mature projects context['mature_project_translations'] = TaggedItem.objects.get_by_model(I4pProjectTranslation.objects.filter( language_code=current_language_code, project__site=site, project__status__in=('WIP', 'END') ), tag_instance).order_by('?')[:4] # Starting projects context['starting_project_translations'] = TaggedItem.objects.get_by_model(I4pProjectTranslation.objects.filter( language_code=current_language_code, project__site=site, project__status__in=('IDEA', 'BEGIN') ), tag_instance).order_by('?')[:4] # New projects context['new_project_translations'] = TaggedItem.objects.get_by_model(I4pProjectTranslation.objects.filter( language_code=current_language_code, project__site=site, ), tag_instance).order_by('-project__created')[:4] # Latest modifications context['modified_project_translations'] = TaggedItem.objects.get_by_model(I4pProjectTranslation.objects.filter( language_code=current_language_code, project__site=site, ), tag_instance).order_by('-modified')[:4] # Related people project_translations = ModelTaggedItemManager().with_any([tag_instance.name], I4pProjectTranslation.objects.filter( language_code=current_language_code, project__site=site, ) ) projects = [p.project for p in project_translations] context['people'] = ProjectMember.objects.filter( project__in=projects ).order_by('?')[:6] # XXX Need to remove duplicates return context
[docs]class ProjectTopicSelectView(TemplateView): """ Before starting a project, one needs to pick a topic """ template_name = 'project_sheet/topic_select.html' def get_context_data(self, **kwargs): context = super(ProjectTopicSelectView, self).get_context_data(**kwargs) site = Site.objects.get_current() site_topics = SiteTopic.objects.filter(site=site) context['site_topics'] = site_topics return context
[docs]def project_sheet_show(request, slug, add_media=False): """ Display a project sheet """ language_code = translation.get_language() site = Site.objects.get_current() project_translation = get_object_or_404(I4pProjectTranslation, slug=slug, language_code=language_code, project__site=site) # Info project_info_form = I4pProjectInfoForm(request.POST or None, instance=project_translation.project) if request.method == 'POST' and project_info_form.is_valid(): project_info_form.save() project_themes_form = I4pProjectThemesForm(instance=project_translation) project_objectives_form = I4pProjectObjectivesForm(instance=project_translation.project, prefix="objectives-form") project_member_form = ProjectMemberForm() #project_member_formset = ProjectMemberFormSet(queryset=project_translation.project.detailed_members.all()) project_location_form = I4pProjectLocationForm(instance=project_translation.project.location) reference_formset = ProjectReferenceFormSet(queryset=project_translation.project.references.all()) project_status_choices = OrderedDict((k, unicode(v)) for k, v in I4pProject.STATUS_CHOICES) project = project_translation.project topics = [] for topic in Topic.objects.filter(site_topics=project.topics.all()): questions = [] for question in topic.questions.all().order_by('weight'): answers = Answer.objects.filter(project=project, question=question) questions.append([question, answers and answers[0] or None]) topics.append([topic, questions]) project_status_choices['selected'] = project_translation.project.status context = { 'topics': topics, 'project': project, 'project_translation': project_translation, 'project_themes_form': project_themes_form, 'project_objectives_form': project_objectives_form, 'reference_formset' : reference_formset, 'project_info_form': project_info_form, 'project_location_form': project_location_form, 'project_member_form': project_member_form, 'project_status_choices': simplejson.dumps(project_status_choices), #'project_member_formset': project_member_formset, 'project_tab' : True} if add_media: ProjectPictureForm = modelform_factory(ProjectPicture, fields=('original_image', 'desc', 'license', 'author', 'source')) ProjectVideoForm = modelform_factory(ProjectVideo, fields=('video_url',)) context.update({'picture_form' : ProjectPictureForm(), 'video_form' : ProjectVideoForm()}) return render_to_response(template_name='project_sheet/project_sheet.html', dictionary=context, context_instance=RequestContext(request) )
@login_required
[docs]def project_sheet_create_translation(request, project_slug): """ Given a language and a slug, create a translation for a new language """ current_language_code = translation.get_language() site = Site.objects.get_current() requested_language_code = request.POST.get("requested_language", None) if None: return HttpResponseForbidden() try: current_project_translation = get_project_translation_by_slug(project_translation_slug=project_slug, language_code=current_language_code) except I4pProjectTranslation.DoesNotExist: return Http404 requested_project_translation = get_or_create_project_translation_from_parent(parent_project=current_project_translation.project, language_code=requested_language_code, default_title=current_project_translation.title) current_language = translation.get_language() translation.activate(requested_language_code) url = reverse('project_sheet-show', args=[requested_project_translation.slug]) translation.activate(current_language) return redirect(url)
def project_sheet_edit_location(request, slug): language_code = translation.get_language() # get the project translation and its base try: project_translation = get_project_translation_by_slug(project_translation_slug=slug, language_code=language_code) except I4pProjectTranslation.DoesNotExist: raise Http404 # Location project_location_form = I4pProjectLocationForm(request.POST, instance=project_translation.project.location) # Website project_info_form = I4pProjectInfoForm(request.POST, instance=project_translation.project) if request.method == 'POST' and project_info_form.is_valid(): info = project_info_form.save() if request.method == 'POST' and project_location_form.is_valid(): location = project_location_form.save() if not project_translation.project.location: project_translation.project.location = location project_translation.project.save() return redirect(project_translation)
[docs]def project_sheet_edit_question(request, slug, question_id): """ Edit a question for a given project sheet translation FIXME: Not sure if this is secure. Question may be assigned to projects that doesn't link to them. """ language_code = translation.get_language() # Get project try: project_translation = get_project_translation_by_slug(slug, language_code) except I4pProjectTranslation.DoesNotExist: raise Http404 # Get question question = get_object_or_404(Question, id=question_id) # Lookup the answer. If does not exist, create it. try: answer = Answer.objects.untranslated().get(project=project_translation.project, question=question) if not language_code in answer.get_available_languages(): answer.translate(language_code) except Answer.DoesNotExist: answer = Answer.objects.create(project=project_translation.project, question=question) answer.save() answer_form = AnswerForm(request.POST, instance=answer) if request.method == 'POST': if answer_form.is_valid(): answer = answer_form.save() return redirect(project_translation) context = {} context['answer_form'] = answer_form context['question_id'] = question_id context['project_slug'] = slug return render_to_response(template_name="project_sheet/project_edit_question.html", dictionary=context, context_instance=RequestContext(request))
[docs]def project_sheet_edit_field(request, field, slug=None, topic_slug=None): """ Edit a translatable field of a project (such as baseline) """ language_code = translation.get_language() if topic_slug: topic = get_object_or_404(Topic, slug=topic_slug) FieldForm = modelform_factory(I4pProjectTranslation, fields=(field,)) context = {} project_translation = None if request.method == 'POST': try: project_translation = get_project_translation_by_slug(slug, language_code) except I4pProjectTranslation.DoesNotExist: # Create parent project, then translation parent_project = create_parent_project(topic_slug) project_translation = get_or_create_project_translation_by_slug(slug, parent_project=parent_project, language_code=language_code) form = FieldForm(request.POST, request.FILES, instance=project_translation) if form.is_valid(): form.save() return HttpResponseRedirect(reverse('project_sheet-show', args=[project_translation.slug])) else: try: project_translation = get_project_translation_by_slug(slug, language_code) form = FieldForm(instance=project_translation) context["project_translation"] = project_translation except I4pProjectTranslation.DoesNotExist: form = FieldForm() if project_translation: context['project_info_form'] = I4pProjectInfoForm(instance=project_translation.project) context['project_themes_form'] = I4pProjectThemesForm(instance=project_translation) context['project_objectives_form'] = I4pProjectObjectivesForm(instance=project_translation.project, prefix="objectives-form") context['project_member_form'] = ProjectMemberForm() context['project_location_form'] = I4pProjectLocationForm(instance=project_translation.project.location) context['answer_form'] = AnswerForm() context['reference_formset'] = ProjectReferenceFormSet(queryset=project_translation.project.references.all()) context['project_tab'] = True context['project'] = project_translation.project elif topic_slug: context['topic'] = topic context["%s_form" % field] = form return render_to_response(template_name="project_sheet/project_sheet.html", dictionary=context, context_instance=RequestContext(request))
[docs]def project_sheet_add_media(request): """ Display a page where it is possible to submit either a video or picture Only call when the project is not yet created, else it's project_sheet_show with add_media=True that is called. """ ProjectPictureForm = modelform_factory(ProjectPicture, fields=('original_image', 'desc', 'license', 'author', 'source')) ProjectVideoForm = modelform_factory(ProjectVideo, fields=('video_url',)) context = {'picture_form' : ProjectPictureForm(), 'video_form' : ProjectVideoForm()} return render_to_response("project_sheet/project_sheet.html", context, context_instance=RequestContext(request))
[docs]def project_sheet_add_picture(request, slug=None): """ Add a picture to a project """ language_code = translation.get_language() ProjectPictureForm = modelform_factory(ProjectPicture, fields=('original_image', 'desc', 'license', 'author', 'source')) project_translation = get_project_translation_by_slug(project_translation_slug=slug, language_code=language_code) if request.method == 'POST': picture_form = ProjectPictureForm(request.POST, request.FILES) if picture_form.is_valid(): picture = picture_form.save(commit=False) picture.project = project_translation.project picture.save() return redirect(project_translation)
[docs]def project_sheet_del_picture(request, slug, pic_id): """ Delete a picture from a project sheet """ language_code = translation.get_language() # get the project translation and its base try: project_translation = get_project_translation_by_slug(project_translation_slug=slug, language_code=language_code) except I4pProjectTranslation.DoesNotExist: raise Http404 picture = ProjectPicture.objects.filter(project=project_translation.project, id=pic_id) picture.delete() return redirect(project_translation)
[docs]def project_sheet_add_video(request, slug=None): """ Embed a video to a project """ language_code = translation.get_language() ProjectVideoForm = modelform_factory(ProjectVideo, fields=('video_url',)) project_translation = get_project_translation_by_slug(project_translation_slug=slug, language_code=language_code) if request.method == 'POST': video_form = ProjectVideoForm(request.POST) if video_form.is_valid(): video = video_form.save(commit=False) video.project = project_translation.project video.save() return redirect(project_translation)
[docs]def project_sheet_del_video(request, slug, vid_id): """ Delete a video from a project sheet """ language_code = translation.get_language() # get the project translation and its base try: project_translation = get_project_translation_by_slug(project_translation_slug=slug, language_code=language_code) except I4pProjectTranslation.DoesNotExist: raise Http404 video = ProjectVideo.objects.filter(project=project_translation.project, id=vid_id) video.delete() return redirect(project_translation)
@require_POST
[docs]def project_sheet_edit_references(request, project_slug): """ Edit references of a project """ language_code = translation.get_language() # get the project translation and its base try: project_translation = get_project_translation_by_slug(project_translation_slug=project_slug, language_code=language_code) except I4pProjectTranslation.DoesNotExist: raise Http404 parent_project = project_translation.project reference_formset = ProjectReferenceFormSet(request.POST, queryset=parent_project.references.all()) if reference_formset.is_valid(): refs = reference_formset.save() for ref in refs: parent_project.references.add(ref) next_url = request.POST.get("next", None) if next_url: return HttpResponseRedirect(next_url) return redirect(project_translation)
def project_sheet_member_add(request, project_slug): language_code = translation.get_language() # get the project translation and its base try: project_translation = get_project_translation_by_slug(project_translation_slug=project_slug, language_code=language_code) except I4pProjectTranslation.DoesNotExist: raise Http404 if request.method == 'POST' : project_member_form = ProjectMemberForm(request.POST) if project_member_form.is_valid(): project_member = project_member_form.save(commit=False) project_member.project = project_translation.project project_member.save() return redirect(project_translation)
[docs]def project_sheet_member_delete(request, project_slug, username): """ Delete a project member """ language_code = translation.get_language() # get the project translation and its base try: project_translation = get_project_translation_by_slug(project_translation_slug=project_slug, language_code=language_code) except I4pProjectTranslation.DoesNotExist: raise Http404 parent_project = project_translation.project project_member = get_object_or_404(ProjectMember, user__username=username, project=parent_project) project_member.delete() return redirect(project_translation)
[docs]def project_sheet_history(request, project_slug): """ Show the history of a project member """ language_code = translation.get_language() # get the project translation and its base try: project_translation = get_project_translation_by_slug(project_translation_slug=project_slug, language_code=language_code) except I4pProjectTranslation.DoesNotExist: raise Http404 parent_project = project_translation.project #versions = Version.objects.get_for_object(project_translation).order_by('revision__date_created') project_translation_ct = ContentType.objects.get_for_model(project_translation) parent_project_ct = ContentType.objects.get_for_model(parent_project) versions = Version.objects.filter(Q(content_type=project_translation_ct, object_id=unicode(project_translation.id)) | Q(content_type=parent_project_ct, object_id=unicode(parent_project.id))).order_by('-revision__date_created') project_translation_previous_version = None parent_project_previous_version = None for version in versions: #Directly modify object in query set in order to keep order if version.content_type == project_translation_ct: if project_translation_previous_version: version.diff = fields_diff(project_translation_previous_version, version, VERSIONNED_FIELDS[project_translation_ct.model_class()]) project_translation_previous_version = version else:# version.content_type == parent_project_ct: if parent_project_previous_version: version.diff = fields_diff(parent_project_previous_version, version, VERSIONNED_FIELDS[parent_project_ct.model_class()]) parent_project_previous_version = version return render_to_response('project_sheet/history.html', {'project_translation' : project_translation, 'versions' : versions, 'history_tab' : True}, context_instance=RequestContext(request))
class ProjectRecentChangesView(TemplateView): template_name = 'project_sheet/all_recent_changes.html' def get_context_data(self, **kwargs): context = super(ProjectRecentChangesView, self).get_context_data(**kwargs) twenty_days_ago = datetime.datetime.now() - datetime.timedelta(days=30) project_translation_ct = ContentType.objects.get_for_model(I4pProjectTranslation) parent_project_ct = ContentType.objects.get_for_model(I4pProject) versions = Version.objects.filter(Q(content_type=project_translation_ct) | Q(content_type=parent_project_ct)).filter(revision__date_created__gt=twenty_days_ago).order_by('-revision__date_created') context['history'] = get_project_project_translation_recent_changes(versions) return context