Example #1
0
def share_annotations(request, document_pk=None):
    document = get_object_or_404(Document, pk=document_pk)
    annotations = DocumentAnnotation.objects.filter(user=request.user).order_by('page_number', 'y')
    form = AnnotationSharingForm(request.POST or None)
    
    if form.is_valid():
        user = form.cleaned_data['user']
        annotations = annotations.filter(pk__in=request.POST.getlist('annotation'))
        for annotation in annotations:
            annotation.pk = None
            annotation.user = user
            annotation.save()
        return render(request, 'pdfviewer/annotations/sharing/success.html', {
            'document': document,
            'target_user': user,
            'annotations': annotations,
        })
        
    return render(request, 'pdfviewer/annotations/sharing/share.html', {
        'document': document,
        'form': form,
        'annotations': annotations,
    })
    
    
    
Example #2
0
def activate(request, token=None):
    data, timestamp = _registration_token_factory.parse_token_or_404(token)
    try:
        existing_user = User.objects.get(email__iexact=data['email'])
        return render(request, 'users/registration/already_activated.html', {
            'existing_user': existing_user,
        })
    except User.DoesNotExist:
        pass

    form = ActivationForm(request.POST or None)
    if form.is_valid():
        user = User(
            username=form.cleaned_data['username'], 
            first_name=data['first_name'], 
            last_name=data['last_name'],
            email=data['email']
        )
        user.set_password(form.cleaned_data['password'])
        user.save()
        user.groups = Group.objects.filter(name__in=settings.DEFAULT_USER_GROUPS)
        # the userprofile is auto-created, we only have to update some fields.
        UserProfile.objects.filter(user=user).update(gender=data['gender'])
        return render(request, 'users/registration/activation_complete.html', {
            'activated_user': user,
        })
        
    return render(request, 'users/registration/activation_form.html', {
        'form': form,
        'data': data,
    })
Example #3
0
def vote_sign(request, meeting_pk=None, vote_pk=None):
    vote = get_object_or_404(Vote, pk=vote_pk)
    print 'vote_sign vote "%s"' % (vote_pk)
    pdf_name = vote_filename(vote)
    pdf_template = 'db/meetings/xhtml2pdf/vote.html'
    preview_template = 'db/meetings/xhtml2pdf/vote_preview.html'
    
    context = vote_context(vote)
    html_preview = render(request, preview_template, context).content
    pdf_data = xhtml2pdf(render(request, pdf_template, context).content)
    document_uuid = uuid4().get_hex();

    t_in = tempfile.NamedTemporaryFile(prefix='vote_sign_', suffix='.pdf', delete=False)
    t_out = tempfile.NamedTemporaryFile(prefix='vote_sign_stamped_', suffix='.pdf', delete=False)
    t_in.write(pdf_data)

    t_in.seek(0)
    pdf_barcodestamp(t_in, t_out, document_uuid)
    t_in.close()
    os.remove(t_in.name)
    
    t_out.seek(0)
    pdf_data_stamped = t_out.read()
    t_out.close()
    os.remove(t_out.name)
    
    pdfas_id = votesDepot.deposit(pdf_data_stamped, html_preview, document_uuid, pdf_name)
    return sign(request, pdfas_id, len(pdf_data_stamped), pdf_name)
Example #4
0
def assistant(request, meeting_pk, page_num=0):
    meeting = get_object_or_404(FastLaneMeeting, pk=meeting_pk)
    page_num = int(page_num)

    paginator = Paginator(meeting.tops.all().order_by('pk'), 1)

    if not meeting.started or meeting.ended:
        return render(request, 'fastlane/assistant_main.html', {
            'meeting': meeting,
        })
    elif meeting.started and page_num not in paginator.page_range:
        return HttpResponseRedirect(reverse('ecs.fastlane.views.assistant', kwargs={'meeting_pk': meeting.pk, 'page_num': 1}))

    page = paginator.page(page_num)
    top = page.object_list[0]

    form = FastLaneTopForm(request.POST or None, instance=top)
    if request.method == 'POST' and form.is_valid():
        form.save()
        if page_num+1 > paginator.num_pages:
            return HttpResponseRedirect(reverse('ecs.fastlane.views.assistant', kwargs={'meeting_pk': meeting.pk}))
        return HttpResponseRedirect(reverse('ecs.fastlane.views.assistant', kwargs={'meeting_pk': meeting.pk, 'page_num': page_num+1}))

    return render(request, 'fastlane/assistant_recommendation.html', {
        'meeting': meeting,
        'form': form,
        'top': top,
        'page': page,
    })
Example #5
0
def submission_billing(request):
    unbilled_submissions = list(Submission.objects.filter(billed_at=None, current_submission_form__acknowledged=True))
    for submission in unbilled_submissions:
        submission.price = Price.objects.get_for_submission(submission)

    if request.method == 'POST':
        selected_for_billing = []
        for submission in unbilled_submissions:
            if request.POST.get('bill_%s' % submission.pk, False):
                selected_for_billing.append(submission)
                
        xls = SimpleXLS()
        xls.write_row(0, (_(u'amt.'), _(u'EC-Number'), _(u'company'), _(u'Eudract-Nr.'), _(u'applicant'), _(u'clinic'), _(u'sum')))
        for i, submission in enumerate(selected_for_billing):
            r = i + 1
            submission_form = submission.current_submission_form
            xls.write_row(i + 1, [
                "%s." % r,
                submission.get_ec_number_display(),
                _get_address(submission_form, submission_form.invoice_name and 'invoice' or 'sponsor'),
                submission_form.eudract_number or '?',
                submission_form.submitter_contact.full_name,
                _get_organizations(submission_form),
                submission.price.price,
            ])
        r = len(selected_for_billing) + 1
        xls.write(r, 6, xlwt.Formula('SUM(G2:G%s)' % r))
        
        xls_buf = StringIO()
        xls.save(xls_buf)
        now = datetime.datetime.now()
        doc = Document.objects.create_from_buffer(xls_buf.getvalue(), mimetype='application/vnd.ms-excel', date=now)

        Submission.objects.filter(pk__in=[s.pk for s in selected_for_billing]).update(billed_at=now)

        htmlmail = unicode(render_html(request, 'billing/email/submissions.html', {}))
        plainmail = whitewash(htmlmail)

        deliver(subject=_(u'Billing request'), 
            message=plainmail,
            message_html=htmlmail,
            attachments=[('billing-%s.xls' % now.strftime('%Y%m%d-%H%I%S'), xls_buf.getvalue(), 'application/vnd.ms-excel'),],
            from_email=settings.DEFAULT_FROM_EMAIL,
            recipient_list=settings.BILLING_RECIPIENT_LIST, 
        )

        summary, total = collect_submission_billing_stats(selected_for_billing)
        
        return render(request, 'billing/submission_summary.html', {
            'summary': summary,
            'xls_doc': doc,
            'total': total,
        })
        return HttpResponseRedirect(reverse('ecs.billing.views.submission_billing'))

    return render(request, 'billing/submissions.html', {
        'submissions': unbilled_submissions,
    })
Example #6
0
def change_password(request):
    form = PasswordChangeForm(request.user, request.POST or None)
    if form.is_valid():
        form.save()
        UserProfile.objects.filter(user=request.user).update(last_password_change=datetime.now())
        return render(request, 'users/change_password_complete.html', {})
    return render(request, 'users/change_password_form.html', {
        'form': form,
    })
Example #7
0
def external_review_payment(request):
    submissions = Submission.objects.filter(external_reviewer=True, external_reviewer_billed_at=None, external_reviewer_name__isnull=False)
    price = Price.objects.get_review_price()

    if request.method == 'POST':
        selected_for_payment = []
        for submission in submissions:
            if request.POST.get('pay_%s' % submission.pk, False):
                selected_for_payment.append(submission)
        reviewers = User.objects.filter(reviewed_submissions__in=selected_for_payment).distinct()
        
        xls = SimpleXLS()
        xls.write_row(0, (_(u'amt.'), _(u'reviewer'), _(u'EC-Nr.'), _(u'sum')))
        for i, reviewer in enumerate(reviewers):
            submissions = reviewer.reviewed_submissions.filter(pk__in=[s.pk for s in selected_for_payment])
            xls.write_row(i + 1, [
                len(submissions),
                reviewer.get_full_name(),
                ", ".join(s.get_ec_number_display() for s in submissions),
                len(submissions) * price.price,
            ])
        r = len(reviewers) + 1
        xls.write_row(r, [
            xlwt.Formula('SUM(A2:A%s)' % r),
            "",
            "",
            xlwt.Formula('SUM(D2:D%s)' % r),
        ])
        
        xls_buf = StringIO()
        xls.save(xls_buf)
        now = datetime.datetime.now()
        doc = Document.objects.create_from_buffer(xls_buf.getvalue(), mimetype='application/vnd.ms-excel', date=now)
        
        Submission.objects.filter(pk__in=[s.pk for s in selected_for_payment]).update(external_reviewer_billed_at=now)
        
        htmlmail = unicode(render_html(request, 'billing/email/external_review.html', {}))
        plainmail = whitewash(htmlmail)
        
        deliver(subject=_(u'Payment request'), 
            message=plainmail,
            message_html=htmlmail,
            attachments=[('externalreview-%s.xls' % now.strftime('%Y%m%d-%H%I%S'), xls_buf.getvalue(), 'application/vnd.ms-excel'),],
            from_email=settings.DEFAULT_FROM_EMAIL,
            recipient_list=settings.BILLING_RECIPIENT_LIST, 
        )
        
        return render(request, 'billing/external_review_summary.html', {
            'reviewers': reviewers,
            'xls_doc': doc,
        })

    return render(request, 'billing/external_review.html', {
        'submissions': submissions,
        'price': price,
    })
Example #8
0
def delegate_thread(request, thread_pk=None):
    thread = get_object_or_404(Thread.objects.by_user(request.user), pk=thread_pk)
    form = ThreadDelegationForm(request.POST or None)
    if form.is_valid():
        message = thread.add_message(request.user, text=form.cleaned_data['text'])
        thread.delegate(request.user, form.cleaned_data['to'])

        return render(request, 'communication/delegate_thread_response.html', {
            'to': form.cleaned_data['to'],
            'thread': thread,
        })
    return render(request, 'communication/delegate_thread.html', {
        'thread': thread,
        'form': form,
    })
Example #9
0
def request_password_reset(request):
    form = RequestPasswordResetForm(request.POST or None)
    if form.is_valid():
        token = _password_reset_token_factory.generate_token(form.cleaned_data['email'])
        reset_url = request.build_absolute_uri(reverse('ecs.users.views.do_password_reset', kwargs={'token': token}))
        htmlmail = unicode(render_html(request, 'users/password_reset/reset_email.html', {
            'reset_url': reset_url,
        }))
        deliver(subject=_(u'ECS - Password Reset'), message=None, message_html=htmlmail,
            from_email= settings.DEFAULT_FROM_EMAIL, recipient_list=form.cleaned_data['email'])
        return render(request, 'users/password_reset/request_complete.html', {
            'email': form.cleaned_data['email'],
        })
    return render(request, 'users/password_reset/request_form.html', {
        'form': form,
    })
Example #10
0
def accept_invitation(request, invitation_uuid=None):
    try:
        invitation = Invitation.objects.new().get(uuid=invitation_uuid.lower())
    except Invitation.DoesNotExist:
        raise Http404

    form = PasswordChangeForm(invitation.user, request.POST or None)
    if form.is_valid():
        user = form.save()
        user.ecs_profile.last_password_change = datetime.now()
        user.ecs_profile.phantom = False
        user.ecs_profile.save()
        invitation.accepted = True
        invitation.save()
        user = auth.authenticate(username=invitation.user.username, password=form.cleaned_data['new_password1'])
        auth.login(request, user)
        return HttpResponseRedirect(reverse('ecs.users.views.edit_profile'))

    password = uuid4().get_hex()
    invitation.user.set_password(password)
    invitation.user.save()
    form.fields['old_password'].widget = forms.HiddenInput()
    form.fields['old_password'].initial = password

    return render(request, 'users/invitation/set_password_form.html', {
        'form': form,
    })
Example #11
0
def catalog(request):
    with sudo():
        votes = Vote.objects.filter(result__in=('1', '1a'), submission_form__sponsor_agrees_to_publishing=True, published_at__isnull=False, published_at__lte=datetime.now()).order_by('-top__meeting__start', '-published_at')

    return render(request, 'submissions/catalog.html', {
        'votes': votes,
    })
Example #12
0
def medical_categories(request, meeting_pk=None):
    meeting = get_object_or_404(Meeting, pk=meeting_pk)
    required_categories = MedicalCategory.objects.filter(submissions__timetable_entries__meeting=meeting).order_by('abbrev')

    forms = SortedDict()
    for cat in required_categories:
        forms[cat] = AssignedMedicalCategoryForm(request.POST or None, meeting=meeting, category=cat, prefix='cat%s' % cat.pk)

    if request.method == 'POST':
        for cat, form in forms.iteritems():
            if form.is_valid():
                if form.instance and form.instance.board_member:
                    # remove all participations for a previous selected board member.
                    # XXX: this may delete manually entered data. (FMD2)
                    Participation.objects.filter(medical_category=cat, entry__meeting=meeting).delete()
                amc = form.save()
                # add participations for all timetable entries with matching categories.
                # this assumes that all submissions have already been added to the meeting.
                for entry in meeting.timetable_entries.filter(submission__medical_categories=cat).distinct():
                    Participation.objects.get_or_create(medical_category=cat, entry=entry, user=amc.board_member)

    return render(request, 'meetings/timetable/medical_categories.html', {
        'meeting': meeting,    
        'forms': forms,
    })
Example #13
0
def view_help_page(request, page_pk=None):
    page = get_object_or_404(Page, pk=page_pk)
    related_pages = Page.objects.filter(view=page.view).exclude(pk=page.pk).order_by('title')
    return render(request, 'help/view_page.html', {
        'page': page,
        'related_pages': related_pages,
    })
Example #14
0
def register(request):
    form = RegistrationForm(request.POST or None)
    if form.is_valid():
        token = _registration_token_factory.generate_token(form.cleaned_data)
        activation_url = request.build_absolute_uri(reverse('ecs.users.views.activate', kwargs={'token': token}))        
        htmlmail = unicode(render_html(request, 'users/registration/activation_email.html', {
            'activation_url': activation_url,
            'form': form,
        }))
        deliver(subject=_(u'ECS - Registration'), message=None, message_html=htmlmail,
            from_email= settings.DEFAULT_FROM_EMAIL, recipient_list=form.cleaned_data['email'])
        return render(request, 'users/registration/registration_complete.html', {})
        
    return render(request, 'users/registration/registration_form.html', {
        'form': form,
    })
Example #15
0
def wizard(request):
    from ecs.core.forms.wizard import get_wizard_form
    if request.method == 'GET' and request.docstash.value:
        form = request.docstash['form']
        screen_form = get_wizard_form('start')(prefix='wizard')
    else:
        form = SubmissionFormForm(request.POST or None)
        name = request.POST.get('wizard-name', 'start')
        screen_form = get_wizard_form(name)(request.POST or None, prefix='wizard')
        if screen_form.is_valid():
            if screen_form.is_terminal():
                request.docstash.group = 'ecs.core.views.submissions.create_submission_form'
                request.docstash.save()
                return HttpResponseRedirect(reverse('ecs.core.views.create_submission_form', kwargs={'docstash_key': request.docstash.key}))

            typ, obj = screen_form.get_next()
            if typ == 'wizard':
                screen_form = obj(prefix='wizard')
            elif typ == 'redirect':
                return HttpResponseRedirect(obj)
            else:
                raise ValueError

    return render(request, 'submissions/wizard.html', {
        'form': screen_form,
    })
Example #16
0
def invitations(request, meeting_pk, reallysure=False):
    meeting = get_object_or_404(FastLaneMeeting, pk=meeting_pk)

    def get_submissions_for_recipient(recipient):
        categories_q = recipient.assigned_fastlane_categories.all().values('pk').query
        return Submission.objects.filter(expedited_review_categories__pk__in=categories_q, fast_lane_meetings=meeting)

    recipients = User.objects.filter(assigned_fastlane_categories__meeting=meeting).distinct().order_by('pk')
    if reallysure:
        for recipient in recipients:
            submissions = get_submissions_for_recipient(recipient)

            text = _(u'You have been selected for the Fast Lane Meeting at %(meeting_date)s %(meeting_title)s\nas a participant to the submissions: %(submissions)s') % {
                'meeting_date': meeting.start.strftime('%d.%m.%Y %H:%M'),
                'meeting_title': meeting.title,
                'submissions': u', '.join([s.get_ec_number_display() for s in submissions])
            }
            subject = _(u'Your Participation in the Fast Lane Meeting %(meeting_date)s %(meeting_title)s') % {
                'meeting_date': meeting.start.strftime('%d.%m.%Y %H:%M'),
                'meeting_title': meeting.title,
            }
            thread, created = Thread.objects.get_or_create(
                subject=subject,
                sender=User.objects.get(username='******'),
                receiver=recipient,
            )
            thread.add_message(User.objects.get(username='******'), text=text)

        return HttpResponseRedirect(reverse('ecs.fastlane.views.list'))

    return render(request, 'fastlane/invitations.html', {
        'meeting': meeting,
        'recipients': [(x, get_submissions_for_recipient(x)) for x in recipients],
    })
Example #17
0
def view_notification(request, notification_pk=None):
    notification = get_object_or_404(Notification, pk=notification_pk)
    template_names = ['notifications/view/%s.html' % name for name in (notification.type.form_cls.__name__, 'base')]
    return render(request, template_names, {
        'documents': notification.documents.filter(deleted=False).order_by('doctype__name', '-date'),
        'notification': notification,
    })
Example #18
0
def submission_data_for_notification(request):
    submission_forms = list(SubmissionForm.objects.filter(pk__in=request.GET.getlist('submission_form')))
    investigators = Investigator.objects.filter(submission_form__in=submission_forms)
    return render(request, 'notifications/submission_data.html', {
        'submission_forms': submission_forms,
        'investigators': investigators,
    })
Example #19
0
def manage_task(request, task_pk=None):
    task = get_object_or_404(Task, pk=task_pk)
    form = ManageTaskForm(request.POST or None, task=task)
    if request.method == 'POST' and form.is_valid():
        action = form.cleaned_data['action']
        if action == 'complete':
            task.done(user=request.user, choice=form.get_choice())
        
        elif action == 'delegate':
            task.assign(form.cleaned_data['assign_to'])
        
        elif action == 'message':
            question_type = form.cleaned_data['question_type']
            if question_type == 'callback':
                to = form.cleaned_data['callback_task'].assigned_to
            elif question_type == 'somebody':
                to = form.cleaned_data['receiver']
            elif question_type == 'related':
                to = form.cleaned_data['related_task'].assigned_to
            message = Thread.objects.create(
                subject=u'Frage bzgl. %s' % task,
                submission=task.data.get_submission(), 
                task=task,
                text=form.cleaned_data['question'],
                sender=request.user,
                receiver=to,
            )
        return HttpResponseRedirect(reverse('ecs.tasks.views.my_tasks'))
    return render(request, 'tasks/manage_task.html', {
        'form': form,
        'task': task,
    })
Example #20
0
def edit_help_page(request, view_pk=None, anchor='', page_pk=None):
    if page_pk:
        page = get_object_or_404(Page, pk=page_pk)
        view = page.view
    elif view_pk:
        view = get_object_or_404(View, pk=view_pk)
        try:
            page = Page.objects.get(view=view, anchor=anchor)
        except Page.DoesNotExist:
            page = None
    else:
        view = None
        page = None
    form = HelpPageForm(request.POST or None, instance=page, initial={'anchor': anchor, 'view': getattr(view, 'pk', None)})

    if form.is_valid():
        page = form.save()
        return HttpResponseRedirect(reverse('ecs.help.views.view_help_page', kwargs={'page_pk': page.pk}))
        
    related_pages = Page.objects.filter(view=view).order_by('title')
    if page:
        related_pages = related_pages.exclude(pk=page.pk)

    return render(request, 'help/edit_page.html', {
        'page': page,
        'view': view,
        'form': form,
        'related_pages': related_pages,
    })
Example #21
0
def submission_form_list(request, submissions, stashed_submission_forms, meetings, keyword=None):
    return render(request, 'submissions/list.html', {
        'unscheduled_submissions': submissions.filter(meetings__isnull=True).distinct().order_by('ec_number'),
        'meetings': meetings,
        'stashed_submission_forms': stashed_submission_forms,
        'keyword': keyword,
    })
Example #22
0
def meeting_assistant_quickjump(request, meeting_pk=None):
    meeting = get_object_or_404(Meeting, pk=meeting_pk, started__isnull=False)
    top = None
    q = request.REQUEST.get('q', '').upper()
    explict_top = 'TOP' in q
    q = q.replace('TOP', '').strip()
    
    # if we don't explicitly look for a TOP, try an exact ec_number lookup
    if not explict_top:
        tops = meeting.timetable_entries.filter(submission__ec_number__endswith=q).order_by('timetable_index')
        if len(tops) == 1:
            top = tops[0]
    # if we found no TOP yet, try an exact TOP index lookup
    if not top:
        try:
            top = meeting.timetable_entries.get(timetable_index=int(q)-1)
        except (ValueError, TimetableEntry.DoesNotExist):
            pass
    # if we found no TOP yet and don't explicitly look for a TOP, try a fuzzy ec_number lookup
    if not top and not explict_top:
        tops = meeting.timetable_entries.filter(submission__ec_number__icontains=q).order_by('timetable_index')
        if len(tops) == 1:
            top = tops[0]
    if top:
        return HttpResponseRedirect(reverse('ecs.meetings.views.meeting_assistant_top', kwargs={'meeting_pk': meeting.pk, 'top_pk': top.pk}))
    
    return render(request, 'meetings/assistant/quickjump_error.html', {
        'meeting': meeting,
        'tops': tops,
    })
Example #23
0
def create_meeting(request):
    form = MeetingForm(request.POST or None)
    if form.is_valid():
        meeting = form.save()
        return HttpResponseRedirect(reverse('ecs.meetings.views.timetable_editor', kwargs={'meeting_pk': meeting.pk}))
    return render(request, 'meetings/form.html', {
        'form': form,
    })
Example #24
0
def task_backlog(request, submission_pk=None, template='tasks/log.html'):
    tasks = Task.objects.order_by('created_at')
    if submission_pk:
        submission_ct = ContentType.objects.get_for_model(Submission)
        tasks = tasks.filter(content_type=submission_ct, data_id=submission_pk)
    return render(request, template, {
        'tasks': tasks,
    })
Example #25
0
def invite(request):
    form = InvitationForm(request.POST or None)
    comment = invite_user(request, form.cleaned_data['email']) if form.is_valid() else None

    return render(request, 'users/invitation/invite_user.html', {
        'form': form,
        'comment': comment,
    })
Example #26
0
def do_password_reset(request, token=None):
    email, timestamp = _password_reset_token_factory.parse_token_or_404(token)
    user = get_object_or_404(User, email=email)
    profile = user.get_profile()
    if profile.last_password_change and time.mktime(profile.last_password_change.timetuple()) > timestamp:
        return render(request, 'users/password_reset/token_already_used.html', {})
    
    form = SetPasswordForm(user, request.POST or None)
    if form.is_valid():
        form.save()
        profile.last_password_change = datetime.now()
        profile.save()
        return render(request, 'users/password_reset/reset_complete.html', {})
    return render(request, 'users/password_reset/reset_form.html', {
        'user': user,
        'form': form,
    })
Example #27
0
def import_submission_form(request):
    if 'file' in request.FILES:
        serializer = Serializer()
        submission_form = serializer.read(request.FILES['file'])
        return HttpResponseRedirect(reverse('ecs.core.views.readonly_submission_form', kwargs={'submission_form_pk': submission_form.pk}))
    return render(request, 'submissions/import.html', {
    
    })
Example #28
0
def copy_annotations(request):
    submission_form_pk = request.GET.get('submission_form_pk', None)
    annotations = DocumentAnnotation.objects.filter(user=request.user).select_related('document').order_by('document', 'page_number', 'y')
    if submission_form_pk:
        sf = get_object_or_404(SubmissionForm, pk=submission_form_pk)
        annotations.filter(document__submission_forms=sf)
    return render(request, 'pdfviewer/annotations/copy.html', {
        'annotations': annotations,
    })
Example #29
0
def show(request, document_pk=None):
    document = get_object_or_404(Document, pk=document_pk)
    annotations = list(document.annotations.filter(user=request.user).values('pk', 'page_number', 'x', 'y', 'width', 'height', 'text', 'author__id', 'author__username'))

    return render(request, 'pdfviewer/viewer.html', {
        'document': document,
        'annotations': simplejson.dumps(annotations),
        'images': simplejson.dumps(generate_pages_urllist(document.uuid_document, document.pages)),
    })
Example #30
0
def diff(request, old_submission_form_pk, new_submission_form_pk):
    old_submission_form = get_object_or_404(SubmissionForm, pk=old_submission_form_pk)
    new_submission_form = get_object_or_404(SubmissionForm, pk=new_submission_form_pk)

    diffs = diff_submission_forms(old_submission_form, new_submission_form)

    return render(request, 'submissions/diff/diff.html', {
        'submission': new_submission_form.submission,
        'diffs': diffs,
    })