Commit fb6d5d4b authored by Enrico Zini's avatar Enrico Zini
Browse files

Test signed statement create, delete, download

parent 6fa5d474
{% extends "process/base.html" %}
{% load nm %}
{% load js %}
{% block head_resources %}
{{block.super}}
{% jsinclude "nm" %}
<style type="text/css">
.errorlist { color: red; }
</style>
{% endblock %}
{% block breadcrumbs %}{{block.super}}
/ <a href="{{ person.get_absolute_url }}">{{person.lookup_key}}</a>
{% endblock %}
{% block relatedpages %}
{{block.super}}
{% endblock %}
{% block content %}
<h1>Edit {{type_desc}}</h1>
{% include explain_template with edit=True %}
{% if blurb %}
<p>For your convenince, you can generate the signed statement with this
command, and the site will recognise the text and accept it without a need of
manual validation of its content:</p>
<pre>
(
{% for line in blurb %}echo {{line}}
{% endfor %}
) | gpg --clearsign --default-key {{visitor.fpr}}
</pre>
{% endif %}
<p>Use <tt>gpg --clearsign --default-key {{fpr}}</tt> to generate the
signed statement. Tip: pipe it to <tt>xclip</tt> to have it copied to the
clipboard for easy pasting.</p>
<p>It is a good idea to include some context information like the date and
nm.debian.org in the text, in case someone tries to reuse the signed statement
somewhere else.</p>
<p>The signature will be verified using the key {{fpr|fingerprint}}</p>
<form action="" method="post">{% csrf_token %}
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
{% for field in form.visible_fields %}
{{ field.label_tag }}<br>
{{ field }}<br>
{{ field.errors }}
{% endfor %}
{{ form.non_field_errors }}
<input type="submit" value="Submit">
</form>
{% endblock %}
...@@ -153,9 +153,11 @@ class ProcessFixtureMixin(PersonFixtureMixin): ...@@ -153,9 +153,11 @@ class ProcessFixtureMixin(PersonFixtureMixin):
super(ProcessFixtureMixin, cls).setUpClass() super(ProcessFixtureMixin, cls).setUpClass()
cls.processes = TestProcesses(**cls.get_processes_defaults()) cls.processes = TestProcesses(**cls.get_processes_defaults())
cls.amassignments = NamedObjects(pmodels.AMAssignment) cls.amassignments = NamedObjects(pmodels.AMAssignment)
cls.statements = NamedObjects(pmodels.Statement)
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
cls.statements.delete_all()
cls.amassignments.delete_all() cls.amassignments.delete_all()
cls.processes.delete_all() cls.processes.delete_all()
super(ProcessFixtureMixin, cls).tearDownClass() super(ProcessFixtureMixin, cls).tearDownClass()
...@@ -164,6 +166,7 @@ class ProcessFixtureMixin(PersonFixtureMixin): ...@@ -164,6 +166,7 @@ class ProcessFixtureMixin(PersonFixtureMixin):
super(ProcessFixtureMixin, self).setUp() super(ProcessFixtureMixin, self).setUp()
self.processes.refresh() self.processes.refresh()
self.amassignments.refresh() self.amassignments.refresh()
self.statements.refresh()
def get_all_process_types(): def get_all_process_types():
......
...@@ -11,7 +11,7 @@ from backend import models as bmodels ...@@ -11,7 +11,7 @@ from backend import models as bmodels
from backend.unittest import PersonFixtureMixin, ExpectedSets, TestSet, PageElements from backend.unittest import PersonFixtureMixin, ExpectedSets, TestSet, PageElements
import process.models as pmodels import process.models as pmodels
from mock import patch from mock import patch
from .common import (ProcessFixtureMixin, get_all_process_types, from .common import (ProcessFixtureMixin,
test_fingerprint1, test_fpr1_signed_valid_text, test_fingerprint1, test_fpr1_signed_valid_text,
test_fingerprint2, test_fpr2_signed_valid_text, test_fingerprint2, test_fpr2_signed_valid_text,
test_fingerprint3, test_fpr3_signed_valid_text) test_fingerprint3, test_fpr3_signed_valid_text)
......
...@@ -11,7 +11,7 @@ from backend import models as bmodels ...@@ -11,7 +11,7 @@ from backend import models as bmodels
from backend.unittest import PersonFixtureMixin, ExpectedSets, TestSet, PageElements from backend.unittest import PersonFixtureMixin, ExpectedSets, TestSet, PageElements
import process.models as pmodels import process.models as pmodels
from mock import patch from mock import patch
from .common import ProcessFixtureMixin, get_all_process_types from .common import ProcessFixtureMixin
class TestProcessShow(ProcessFixtureMixin, TestCase): class TestProcessShow(ProcessFixtureMixin, TestCase):
......
# coding: utf8
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from django.test import TestCase
from django.core.urlresolvers import reverse
from django.utils.timezone import now
from backend import const
from backend import models as bmodels
from backend.unittest import PersonFixtureMixin
import process.models as pmodels
from mock import patch
from .common import (ProcessFixtureMixin,
test_fingerprint1, test_fpr1_signed_valid_text)
class TestProcessStatementCreate(ProcessFixtureMixin, TestCase):
@classmethod
def setUpClass(cls):
super(TestProcessStatementCreate, cls).setUpClass()
cls.persons.create("app", status=const.STATUS_DC)
cls.processes.create("app", person=cls.persons.app, applying_for=const.STATUS_DD_U, fd_comment="test")
cls.persons.create("am", status=const.STATUS_DD_NU)
cls.ams.create("am", person=cls.persons.am)
cls.amassignments.create("am", process=cls.processes.app, am=cls.ams.am, assigned_by=cls.persons["fd"], assigned_time=now())
cls.visitor = cls.persons.dc
cls.fingerprints.create("visitor", person=cls.visitor, fpr=test_fingerprint1, is_active=True, audit_skip=True)
@classmethod
def __add_extra_tests__(cls):
for req_type in ("intent", "sc_dmup", "advocate", "am_ok"):
cls._add_method(cls._test_create_forbidden, req_type, set())
cls._add_method(cls._test_create_success, req_type, { "edit_statements" })
def _test_create_success(self, req_type, visit_perms):
with patch.object(pmodels.Requirement, "permissions_of", return_value=visit_perms):
client = self.make_test_client(self.visitor)
response = client.get(reverse("process_statement_create", args=[self.processes.app.pk, req_type]))
self.assertEqual(response.status_code, 200)
self.assertEqual(pmodels.Statement.objects.count(), 0)
response = client.post(reverse("process_statement_create", args=[self.processes.app.pk, req_type]), data={"statement": test_fpr1_signed_valid_text})
req = self.processes.app.requirements.get(type=req_type)
self.assertRedirectMatches(response, req.get_absolute_url())
self.assertEqual(pmodels.Statement.objects.count(), 1)
st = pmodels.Statement.objects.get(requirement=req)
self.assertEquals(st.requirement, req)
self.assertEquals(st.fpr, self.fingerprints.visitor)
self.assertEquals(st.statement, test_fpr1_signed_valid_text)
self.assertEquals(st.uploaded_by, self.visitor)
self.assertIsNotNone(st.uploaded_time)
def _test_create_forbidden(self, req_type, visit_perms=set()):
with patch.object(pmodels.Requirement, "permissions_of", return_value=visit_perms):
client = self.make_test_client(self.visitor)
response = client.get(reverse("process_statement_create", args=[self.processes.app.pk, req_type]))
self.assertPermissionDenied(response)
self.assertEqual(pmodels.Statement.objects.count(), 0)
response = client.post(reverse("process_statement_create", args=[self.processes.app.pk, req_type]), data={"statement": test_fpr1_signed_valid_text})
self.assertPermissionDenied(response)
self.assertEqual(pmodels.Statement.objects.count(), 0)
class TestProcessStatementDelete(ProcessFixtureMixin, TestCase):
@classmethod
def setUpClass(cls):
super(TestProcessStatementDelete, cls).setUpClass()
cls.persons.create("app", status=const.STATUS_DC)
cls.processes.create("app", person=cls.persons.app, applying_for=const.STATUS_DD_U, fd_comment="test")
cls.persons.create("am", status=const.STATUS_DD_NU)
cls.ams.create("am", person=cls.persons.am)
cls.amassignments.create("am", process=cls.processes.app, am=cls.ams.am, assigned_by=cls.persons["fd"], assigned_time=now())
cls.visitor = cls.persons.dc
cls.fingerprints.create("visitor", person=cls.visitor, fpr=test_fingerprint1, is_active=True, audit_skip=True)
cls.statement_pks = {}
for req_type in ("intent", "sc_dmup", "advocate", "am_ok"):
req = cls.processes.app.requirements.get(type=req_type)
cls.statements.create(req_type, requirement=req, fpr=cls.fingerprints.visitor, statement=test_fpr1_signed_valid_text, uploaded_by=cls.visitor, uploaded_time=now())
@classmethod
def __add_extra_tests__(cls):
for req_type in ("intent", "sc_dmup", "advocate", "am_ok"):
cls._add_method(cls._test_delete_forbidden, req_type, set())
cls._add_method(cls._test_delete_success, req_type, { "edit_statements" })
def _test_delete_success(self, req_type, visit_perms):
with patch.object(pmodels.Requirement, "permissions_of", return_value=visit_perms):
client = self.make_test_client(self.visitor)
statement = self.statements[req_type]
url = reverse("process_statement_delete", args=[self.processes.app.pk, req_type, statement.pk])
response = client.get(url)
self.assertEqual(response.status_code, 200)
self.assertTrue(pmodels.Statement.objects.filter(pk=statement.pk).exists())
response = client.post(url)
req = self.processes.app.requirements.get(type=req_type)
self.assertRedirectMatches(response, req.get_absolute_url())
self.assertFalse(pmodels.Statement.objects.filter(pk=statement.pk).exists())
def _test_delete_forbidden(self, req_type, visit_perms=set()):
with patch.object(pmodels.Requirement, "permissions_of", return_value=visit_perms):
client = self.make_test_client(self.visitor)
statement = self.statements[req_type]
url = reverse("process_statement_delete", args=[self.processes.app.pk, req_type, statement.pk])
response = client.get(url)
self.assertPermissionDenied(response)
self.assertTrue(pmodels.Statement.objects.filter(pk=statement.pk).exists())
response = client.post(url)
self.assertPermissionDenied(response)
self.assertTrue(pmodels.Statement.objects.filter(pk=statement.pk).exists())
class TestProcessStatementRaw(ProcessFixtureMixin, TestCase):
@classmethod
def setUpClass(cls):
super(TestProcessStatementRaw, cls).setUpClass()
cls.persons.create("app", status=const.STATUS_DC)
cls.processes.create("app", person=cls.persons.app, applying_for=const.STATUS_DD_U, fd_comment="test")
cls.persons.create("am", status=const.STATUS_DD_NU)
cls.ams.create("am", person=cls.persons.am)
cls.amassignments.create("am", process=cls.processes.app, am=cls.ams.am, assigned_by=cls.persons["fd"], assigned_time=now())
cls.signer = cls.persons.dc
cls.fingerprints.create("signer", person=cls.signer, fpr=test_fingerprint1, is_active=True, audit_skip=True)
cls.statement_pks = {}
for req_type in ("intent", "sc_dmup", "advocate", "am_ok"):
req = cls.processes.app.requirements.get(type=req_type)
cls.statements.create(req_type, requirement=req, fpr=cls.fingerprints.signer, statement=test_fpr1_signed_valid_text, uploaded_by=cls.signer, uploaded_time=now())
@classmethod
def __add_extra_tests__(cls):
for visitor in (None, "pending", "dc", "dc_ga", "dm", "dm_ga", "dd_nu", "dd_u", "dd_e", "dd_r", "app", "am", "activeam", "fd", "dam"):
for req_type in ("intent", "sc_dmup", "advocate", "am_ok"):
cls._add_method(cls._test_access, visitor, req_type)
def _test_access(self, visitor, req_type):
client = self.make_test_client(visitor)
statement = self.statements[req_type]
response = client.get(reverse("process_statement_raw", args=[self.processes.app.pk, req_type, statement.pk]))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, test_fpr1_signed_valid_text)
# TODO: url(r'^(?P<pk>\d+)/(?P<type>[^/]+)/statement/create$', views.StatementCreate.as_view(), name="process_statement_create"),
# TODO: url(r'^(?P<pk>\d+)/(?P<type>[^/]+)/statement/(?P<st>\d+)/delete$', views.StatementDelete.as_view(), name="process_statement_delete"),
# TODO: url(r'^(?P<pk>\d+)/(?P<type>[^/]+)/statement/(?P<st>\d+)/raw$', views.StatementRaw.as_view(), name="process_statement_raw"),
...@@ -17,11 +17,11 @@ urlpatterns = [ ...@@ -17,11 +17,11 @@ urlpatterns = [
url(r'^(?P<pk>\d+)/am_ok$', views.ReqAM.as_view(), name="process_req_am_ok"), url(r'^(?P<pk>\d+)/am_ok$', views.ReqAM.as_view(), name="process_req_am_ok"),
url(r'^(?P<pk>\d+)/keycheck$', views.ReqKeycheck.as_view(), name="process_req_keycheck"), url(r'^(?P<pk>\d+)/keycheck$', views.ReqKeycheck.as_view(), name="process_req_keycheck"),
url(r'^(?P<pk>\d+)/add_log$', views.AddProcessLog.as_view(), name="process_add_log"), url(r'^(?P<pk>\d+)/add_log$', views.AddProcessLog.as_view(), name="process_add_log"),
url(r'^(?P<pk>\d+)/(?P<type>[^/]+)/statement/create$', views.StatementCreate.as_view(), name="process_statement_create"),
url(r'^(?P<pk>\d+)/(?P<type>[^/]+)/statement/(?P<st>\d+)/delete$', views.StatementDelete.as_view(), name="process_statement_delete"),
url(r'^(?P<pk>\d+)/(?P<type>[^/]+)/statement/(?P<st>\d+)/raw$', views.StatementRaw.as_view(), name="process_statement_raw"),
url(r'^(?P<pk>\d+)/assign_am$', views.AssignAM.as_view(), name="process_assign_am"), # TODO: test url(r'^(?P<pk>\d+)/assign_am$', views.AssignAM.as_view(), name="process_assign_am"), # TODO: test
url(r'^(?P<pk>\d+)/unassign_am$', views.UnassignAM.as_view(), name="process_unassign_am"), # TODO: test url(r'^(?P<pk>\d+)/unassign_am$', views.UnassignAM.as_view(), name="process_unassign_am"), # TODO: test
url(r'^(?P<pk>\d+)/(?P<type>[^/]+)/statement/create$', views.StatementCreate.as_view(), name="process_statement_create"), # TODO: test
url(r'^(?P<pk>\d+)/(?P<type>[^/]+)/statement/(?P<st>\d+)/delete$', views.StatementDelete.as_view(), name="process_statement_delete"), # TODO: test
url(r'^(?P<pk>\d+)/(?P<type>[^/]+)/statement/(?P<st>\d+)/raw$', views.StatementRaw.as_view(), name="process_statement_raw"), # TODO: test
url(r'^(?P<pk>\d+)/mailbox/download$', views.MailArchive.as_view(), name="process_mailbox_download"), # TODO: test url(r'^(?P<pk>\d+)/mailbox/download$', views.MailArchive.as_view(), name="process_mailbox_download"), # TODO: test
url(r'^(?P<pk>\d+)/mailbox$', views.DisplayMailArchive.as_view(), name="process_mailbox_show"), # TODO: test url(r'^(?P<pk>\d+)/mailbox$', views.DisplayMailArchive.as_view(), name="process_mailbox_show"), # TODO: test
] ]
...@@ -258,8 +258,6 @@ class UnassignAM(RequirementMixin, View): ...@@ -258,8 +258,6 @@ class UnassignAM(RequirementMixin, View):
class StatementMixin(RequirementMixin): class StatementMixin(RequirementMixin):
require_visit_perms = "see_statements"
def load_objects(self): def load_objects(self):
super(StatementMixin, self).load_objects() super(StatementMixin, self).load_objects()
if "st" in self.kwargs: if "st" in self.kwargs:
...@@ -286,7 +284,7 @@ class StatementMixin(RequirementMixin): ...@@ -286,7 +284,7 @@ class StatementMixin(RequirementMixin):
class StatementCreate(StatementMixin, FormView): class StatementCreate(StatementMixin, FormView):
form_class = StatementForm form_class = StatementForm
require_visit_perms = "edit_statements" require_visit_perms = "edit_statements"
template_name = "process/statement_edit.html" template_name = "process/statement_create.html"
def load_objects(self): def load_objects(self):
super(StatementCreate, self).load_objects() super(StatementCreate, self).load_objects()
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment