citavi_mapper/frontend/views.py

321 lines
12 KiB
Python

# -*- coding: utf-8 -*-
# File upload related imports
import os
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from django.conf import settings
from django.views.generic import TemplateView, FormView, CreateView, UpdateView
from django.views.generic.detail import SingleObjectMixin
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.contrib.auth.views import login, logout
from django.core.urlresolvers import reverse
from frontend.forms import NewProjectForm, FileUploadForm, PersonMapForm
from frontend.forms import PresentationForm, PresentationEventForm, PresentationPersonForm
from frontend.forms import PresentationEventFormHelper, PresentationPersonFormHelper
from frontend.models import Presentation, PresentationEvent, PresentationPerson
from frontend.formsets import PresentationEventInlineFormset, PresentationPersonInlineFormset
from frontend.models import Project
FRONTEND_PAGE_NAME = u'Citavi Mapper'
from service.Mapper import person_mapper
# Login wrapper functions
def login_wrap(*args, **kwargs):
""" Wrapper function for login page. """
kwargs[u'extra_context'] = {
u'page': {
u'name': FRONTEND_PAGE_NAME,
u'title': 'Login'
}
}
return login(*args, **kwargs)
def logout_wrap(*args, **kwargs):
""" Wrapper function for logout page. """
kwargs[u'extra_context'] = {
u'page': {
u'name': FRONTEND_PAGE_NAME,
u'title': 'Logout'
}
}
return logout(*args, **kwargs)
# My base classes for views
class MyViewMixin(object):
""" Basic view mixin to add global variables to all templates. """
template_name = u'base.html'
page_name = FRONTEND_PAGE_NAME
page_title = u'BASE'
def get_page_data(self):
return {
u'name': self.page_name,
u'title': self.page_title
}
def get_context_data(self, **kwargs):
kwargs[u'page'] = self.get_page_data()
return super(MyViewMixin, self).get_context_data(**kwargs)
class MyTemplateView(MyViewMixin, TemplateView):
pass
class MyFormView(MyViewMixin, FormView):
pass
class MyCreateView(MyViewMixin, CreateView):
pass
class MyUpdateView(MyViewMixin, UpdateView):
pass
# Mixin to protect pages
class LoggedInMixin(object):
""" Mixin to force a valid login for protected pages. """
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(LoggedInMixin, self).dispatch(*args, **kwargs)
# My protected view classes
class ProtectedTemplateView(LoggedInMixin, MyTemplateView):
pass
class ProtectedFormView(LoggedInMixin, MyFormView):
pass
class ProtectedFormSetView(LoggedInMixin, MyTemplateView):
pass
class ProtectedCreateView(LoggedInMixin, MyCreateView):
pass
class ProtectedUpdateView(LoggedInMixin, MyUpdateView):
pass
# Actual Views
class IndexView(ProtectedTemplateView):
template_name = u'index.html'
page_title = u'Index'
class HelloView(ProtectedTemplateView):
template_name = u'hello.html'
page_title = u'Hello'
success_url = u'/hello'
def __init__(self, *args, **kwargs):
super(HelloView, self).__init__(*args, **kwargs)
def get_context_data(self, **kwargs):
""" Add form + formsets to template context. """
kwargs[u'presentation_form'] = PresentationForm()
person_formset = PresentationPersonInlineFormset(prefix='person')
event_formset = PresentationEventInlineFormset(prefix='event')
kwargs[u'person_formset'] = person_formset
kwargs[u'event_formset'] = event_formset
kwargs[u'person_formhelper'] = PresentationPersonFormHelper;
kwargs[u'event_formhelper'] = PresentationEventFormHelper;
return super(HelloView, self).get_context_data(**kwargs)
class ProjectView(ProtectedFormView):
template_name = u'projects.html'
page_title = u'Projects'
form_class = NewProjectForm
success_url = u'/project'
def get_context_data(self, **kwargs):
kwargs[u'projects'] = Project.objects.order_by(u'id')
return super(ProjectView, self).get_context_data(**kwargs)
def form_valid(self, form):
form.save()
return super(ProjectView, self).form_valid(form)
class ProjectUpdateView(ProtectedFormView, SingleObjectMixin):
template_name = u'project/update.html'
page_title = u'Update project'
form_class = FileUploadForm
success_url = u'/project/'
def get(self, request, *args, **kwargs):
self.project_id = kwargs[u'project_id']
self.object = Project.objects.get(pk=self.project_id)
return super(ProjectUpdateView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.project_id = kwargs[u'project_id']
self.object = Project.objects.get(pk=self.project_id)
self.success_url = self.success_url + self.project_id + u'/update'
return super(ProjectUpdateView, self).post(request, *args, **kwargs)
def form_valid(self, form, *args, **kwargs):
""" This form_valid handles the file upload. """
original_file = form.files[u'file']
original_filename = unicode(original_file)
original_contentfile = ContentFile(original_file.read())
""" Put file into temporary folder for analysis """
target_filename = u'tmp/project_' + unicode(self.project_id) + u'.ctt4'
relative_path = default_storage.save(target_filename, original_contentfile)
temp_sqlite = os.path.join(settings.MEDIA_ROOT, relative_path)
""" Test if SQLite is a valid citavi project. """
from service import Citavi
citavi_project = Citavi.Project(temp_sqlite)
citavi_project.open()
citavi_project_valid = citavi_project.is_valid()
""" Free temporary ressources. """
del citavi_project
default_storage.delete(temp_sqlite)
if citavi_project_valid == False:
""" TODO: Put up an error message or something. """
pass
else:
target_filename = u'citavi/project_' + unicode(self.project_id) + u'.ctt4'
""" Remove eventually pre-existing citavi file. """
if default_storage.exists(target_filename):
default_storage.delete(target_filename)
""" Actually store file in citavi folder """
relative_path = default_storage.save(target_filename, original_contentfile)
sqlite_path = os.path.join(settings.MEDIA_ROOT, relative_path)
""" Store new original filename in Project """
project = Project.objects.get(id=self.project_id)
project.associated_filename = original_filename
project.save()
""" Refresh identities from citavi project. """
# TODO
# citavi_project = Citavi.Project(sqlite_path)
# citavi_project.open()
# del citavi_project
return super(ProjectUpdateView, self).form_valid(form)
class ProjectPersonView(ProtectedFormView, SingleObjectMixin):
template_name = u'project/view-person.html'
page_title = u'Person List View'
form_class = FileUploadForm
success_url = u'/project/'
def get_context_data(self, **kwargs):
project = self.object
kwargs[u'unmapped_persons'] = person_mapper.get_unmapped_identities(project)
kwargs[u'mapped_persons'] = person_mapper.get_mapped_identities(project)
return super(ProjectPersonView, self).get_context_data(**kwargs)
def get(self, request, *args, **kwargs):
self.project_id = kwargs[u'project_id']
self.object = Project.objects.get(pk=self.project_id)
return super(ProjectPersonView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.project_id = kwargs[u'project_id']
# self.success_url = self.success_url + self.project_id + '/update'
return super(ProjectPersonView, self).post(request, *args, **kwargs)
def form_valid(self, form, *args, **kwargs):
return super(ProjectPersonView, self).form_valid(form)
class ProjectMapPersonView(ProtectedFormView, SingleObjectMixin):
""" View containing the person mapping 'wizard'. """
template_name = u'project/map-person.html'
page_title = u'Person Mapping'
form_class = PersonMapForm
success_url = u'/project'
_unmapped_persons = None
def _refresh_unmapped(self):
""" Refresh data about unmapped persons. """
self._unmapped_persons = person_mapper.get_unmapped_identities(self.object)
def _is_unmapped(self, person_uuid):
""" Returns True if the given person is not mapped yet. """
if not self._unmapped_persons:
self._refresh_unmapped()
return person_uuid in self._unmapped_persons
def get_context_data(self, **kwargs):
project = self.object
kwargs[u'person'] = person_mapper.get_person_by_uuid(project, self.person_uuid)
return super(ProjectMapPersonView, self).get_context_data(**kwargs)
def get_success_url(self):
""" TODO: Make this work! - Update success uri to next unmapped person. """
last_uuid = unicode(self.person_uuid)
self._refresh_unmapped()
unmapped = self._unmapped_persons.items()
first_person_uuid = unmapped[0][0]
next_uuid = first_person_uuid
unmapped.reverse()
while True:
try:
current_person = unmapped.pop()
if current_person[1].ID == last_uuid:
next_uuid = unmapped.pop()[0]
break
except IndexError:
break
kwargs = {
u"project_id": self.object.id,
u"person_uuid": next_uuid
}
return reverse('frontend-project-map-person', kwargs=kwargs)
def get(self, request, *args, **kwargs):
self.project_id = kwargs[u'project_id']
self.person_uuid = kwargs[u'person_uuid']
self.object = Project.objects.get(pk=self.project_id)
if self._is_unmapped(self.person_uuid) == False:
raise Exception("Sorry, this person was already mapped. Try deleting the existing mapping and move on. TODO: Make this more beautiful.")
self._refresh_unmapped()
return super(ProjectMapPersonView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.project_id = kwargs[u'project_id']
self.person_uuid = kwargs[u'person_uuid']
self.object = Project.objects.get(pk=self.project_id)
if self._is_unmapped(self.person_uuid) == False:
raise Exception("Sorry, this person was already mapped. Try deleting the existing mapping and move on. TODO: Make this more beautiful.")
self._refresh_unmapped()
return super(ProjectMapPersonView, self).post(request, *args, **kwargs)
def form_valid(self, form, *args, **kwargs):
person = person_mapper.get_person_by_uuid(self.object, self.person_uuid)
if form.data.get(u'skip', False):
""" Nothing to do here, just go on ... """
pass
elif form.data.get(u'save-continue', False):
# TODO: do mapping according to parameters, override success_url to point to next person!
if form.cleaned_data[u'action'] == u'new':
person_mapper.create_new_identity(self.object, person)
elif form.cleaned_data[u'action'] == u'existing':
global_identity = form.cleaned_data[u'global_identity']
person_mapper.map_identity_to_existing(global_identity, self.object, person.ID, form.cleaned_data[u'preferred_identity'])
return super(ProjectMapPersonView, self).form_valid(form)