Skip to content

Commit 7af5f36

Browse files
committed
Continue add data
1 parent e40c650 commit 7af5f36

File tree

12 files changed

+280
-23
lines changed

12 files changed

+280
-23
lines changed

.vscode/settings.json

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{
22
"python.formatting.provider": "black",
33
"python.pythonPath": "~/.virtualenvs/etsd/bin/",
4+
"python.linting.enabled": true,
5+
"python.linting.mypyEnabled": true,
46
"python.linting.pylintEnabled": true
57
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 3.2.6 on 2021-08-12 16:25
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('msgs', '0003_alter_message_category'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='message',
15+
name='status',
16+
field=models.CharField(choices=[('DRAFT', 'Draft'), ('SENT', 'Sent'), ('READ', 'Read'), ('ARCHIVED', 'Archived'), ('DELETED', 'Deleted')], default='DRAFT', max_length=32),
17+
),
18+
]

etsd/msgs/models.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,13 @@ class Message(UserDateAbstractModel):
6666
help_text=_("The message is also encrtypted with the sender's public key"),
6767
)
6868
kind = models.CharField(max_length=32, choices=MESSAGE_KIND_CHOICES)
69-
status = models.CharField(max_length=32, choices=MESSAGE_STATUS_CHOICES)
69+
status = models.CharField(max_length=32, choices=MESSAGE_STATUS_CHOICES, default='DRAFT')
7070
category = models.ForeignKey(
71-
MessageCategory, verbose_name=_("Category"), on_delete=models.PROTECT, blank=True, null=True
71+
MessageCategory,
72+
verbose_name=_("Category"),
73+
on_delete=models.PROTECT,
74+
blank=True,
75+
null=True,
7276
)
7377
rel_message = models.ForeignKey(
7478
"self",
@@ -102,7 +106,7 @@ def send(self):
102106
self.protocol = max_protocol + 1
103107
self.status = "SENT"
104108
self.save()
105-
109+
106110
def get_absolute_url(self):
107111
return reverse("message_detail", kwargs={"pk": self.pk})
108112

etsd/msgs/rules_light_registry.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import rules_light
2+
3+
4+
def can_read(user, _rule, msg) -> bool:
5+
authority = user.get_authority()
6+
return msg.participant_set.filter(authority=authority).exists()
7+
8+
9+
def can_add_data(user, _rule, msg) -> bool:
10+
authority = user.get_authority()
11+
return (
12+
msg.status == "DRAFT"
13+
and msg.participant_set.filter(authority=authority, kind="SENDER").exists()
14+
)
15+
16+
17+
def can_send(user, _rule, msg) -> bool:
18+
authority = user.get_authority()
19+
if msg.data_set.all().count() == 0:
20+
return False # no data to send
21+
return (
22+
msg.status == "DRAFT"
23+
and msg.participant_set.filter(authority=authority, kind="SENDER").exists()
24+
)
25+
26+
27+
rules_light.registry["msgs.message.read"] = can_read
28+
rules_light.registry["msgs.message.add_data"] = can_add_data
29+
rules_light.registry["msgs.message.send"] = can_send
30+
rules_light.registry["msgs.message.delete"] = can_add_data

etsd/msgs/tables.py

+29-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
{{% else %}}
1515
{0}
1616
{{% endif %}}
17-
""" .format( _('Draft message'))
17+
""".format(
18+
_("Draft message")
19+
)
1820

1921

2022
class MessageTable(ColumnShiftTable):
@@ -25,10 +27,34 @@ class MessageTable(ColumnShiftTable):
2527
attrs={"a": {"class": "btn btn-primary btn-sm"}},
2628
)
2729

28-
proto = tables.TemplateColumn(PROTOCOL, verbose_name=__('Protocol'), orderable=False)
30+
proto = tables.TemplateColumn(
31+
PROTOCOL, verbose_name=__("Protocol"), orderable=False
32+
)
33+
sender = tables.Column(verbose_name=__("Sender"), empty_values=(), orderable=False)
34+
recipients = tables.Column(
35+
verbose_name=__("Recipients"), empty_values=(), orderable=False
36+
)
2937

3038
class Meta:
3139
model = models.Message
32-
fields = ("id", "proto", "sent_on", "kind", "status", "category", "rel_message")
40+
fields = (
41+
"id",
42+
"proto",
43+
"sent_on",
44+
"kind",
45+
"status",
46+
"category",
47+
"rel_message",
48+
"sender",
49+
)
3350
attrs = {"class": "table table-sm table-stripped"}
3451
empty_text = "No entries"
52+
53+
def render_sender(self, record):
54+
return record.participant_set.filter(kind="SENDER").first().authority.name
55+
56+
def render_recipients(self, record):
57+
return ", ".join(
58+
z.authority.name
59+
for z in record.participant_set.filter(kind__in=("CC", "RECIPIENT")).all()
60+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{% extends "site_base.html" %}
2+
{% load i18n %}
3+
{% load rules_light_tags %}
4+
{% block head_title %}{% trans "Add Data to Message" %} {{ message.id }}{% endblock %}
5+
{% block page_title %}{% trans "Add Data to Message" %} {{ message.id }}{% endblock %}
6+
{% block page_content %}
7+
8+
9+
{{ participant_keys }}
10+
11+
<div class='row mb-3'>
12+
<div class='col'>
13+
<div>
14+
<label for="formFile" class="form-label">File to upload</label>
15+
<input class="form-control form-control-lg" type="file" id='file'>
16+
</div>
17+
</div>
18+
</div>
19+
20+
21+
<div class="row">
22+
<div class="col-md-12">
23+
24+
<a class='btn btn-success' href='#'>{% trans "Submit" %}</a>
25+
<a class='btn btn-secondary' href='{% url "message_detail" object.id %}'>{% trans "Return" %}</a>
26+
</div>
27+
</div>
28+
29+
{{ participant_keys|json_script:"participant-keys" }}
30+
31+
{% endblock %}
32+
33+
34+
35+
{% block extra_script %}
36+
<script>
37+
console.log("OK")
38+
const participantKeys = JSON.parse(document.getElementById('participant-keys').textContent);
39+
40+
$(function() {
41+
const keyLoadPromises = participantKeys.map(pk => loadPublicKey(pk.participant__participantkey__public_key__key))
42+
43+
Promise.all(keyLoadPromises).then((values) => {
44+
for(let i = 0; i < values.length; i++) {
45+
participantKeys[i].publicKey = values[i]
46+
}
47+
console.log("Keys ok")
48+
});
49+
50+
51+
document.getElementById('file').addEventListener("change", function() {
52+
if (this.files && this.files[0]) {
53+
var theFile = this.files[0];
54+
var reader = new FileReader();
55+
56+
reader.addEventListener('load', function(e) {
57+
58+
console.log("FILE OK")
59+
console.log(e.target.result)
60+
61+
const encryptPromises = participantKeys.map(pk => encrypt(pk.publicKey, e.target.result))
62+
Promise.all(encryptPromises).then((values) => {
63+
console.log("ENC OK")
64+
for(let i = 0; i < values.length; i++) {
65+
participantKeys[i].cipher = values[i]
66+
}
67+
})
68+
});
69+
70+
reader.readAsBinaryString(theFile);
71+
}
72+
});
73+
74+
})
75+
</script>
76+
{% endblock %}
+40-10
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,52 @@
11
{% extends "site_base.html" %}
22
{% load i18n %}
3-
4-
5-
3+
{% load rules_light_tags %}
64
{% block head_title %}{% trans "Message detail" %}{% endblock %}
75
{% block page_title %}{% trans "Message detail" %}{% endblock %}
86
{% block page_content %}
97

8+
<div class='row mb-3'>
9+
<div class='col'>
10+
{% trans "Kind" %}: {{ message.get_kind_display }}<br />
11+
{% trans "Status" %}: {{ message.get_status_display }}<br />
12+
{% trans "Related message" %}: {{ message.rel_message|default:"-" }}<br />
13+
{% trans "Category" %}: {{ message.category|default:"-" }}<br />
14+
{% trans "Sent on" %}: {{ message.sent_on|default:"-" }}<br />
15+
{% trans "Protocol" %}: {% if message.protocol %}{{ message.protocol }} / {{ message.year }}{% endif %}<br />
1016

11-
{% for mp in message.participant_set.all %}
12-
{{ mp.authority }}: {{ mp.get_kind_display }}
13-
14-
{% endfor %}
17+
</div>
18+
<div class='col'>
19+
<h5>{% trans "Participants" %}</h5>
20+
<ul>
21+
{% for mp in message.participant_set.all %}
22+
<li>{{ mp.authority }}: {{ mp.get_kind_display }}</li>
23+
{% endfor %}
24+
</ul>
25+
</div>
26+
</div>
27+
28+
29+
{% rule 'msgs.message.add_data' message as can_add_data %}
30+
{% rule 'msgs.message.send' message as can_send %}
31+
{% rule 'msgs.message.delete' message as can_delete %}
1532

1633
<div class="row">
17-
<div class="col-md-12">
18-
<a class='btn btn-info' href='{% url "message_list" %}'>Return</a>
19-
</div>
34+
<div class="col-md-12">
35+
<a class='btn btn-info' href='{% url "message_list" %}'>{% trans "Return" %}</a>
36+
37+
{% if can_add_data %}
38+
<a class='btn btn-primary' href='{% url "message_add_data" message.id %}'>{% trans "Add data" %}</a>
39+
{% endif %}
40+
41+
{% if can_delete %}
42+
<a class='btn btn-danger' href=''>{% trans "Delete" %}</a>
43+
{% endif %}
44+
{% if can_send %}
45+
<a class='btn btn-success' href=''>{% trans "Send" %}</a>
46+
{% endif %}
47+
48+
<a class='btn btn-warning' href=''>{% trans "Archive" %}</a>
49+
</div>
2050
</div>
2151

2252
{% endblock %}

etsd/msgs/urls.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
from django.contrib import admin
21
from django.urls import path
3-
from . import views
42
from django.contrib.auth.decorators import (
53
permission_required,
64
login_required,
75
user_passes_test,
86
)
7+
import rules_light
8+
from . import views
99

10+
rules_light.autodiscover()
1011

1112
def any_permission_required(*args):
1213
"""
@@ -39,4 +40,11 @@ def any_permission_required(*args):
3940
),
4041
name="message_create",
4142
),
43+
path(
44+
"add_data/<int:pk>/",
45+
any_permission_required("core.admin", "core.user")(
46+
views.MessageAddDataView.as_view()
47+
),
48+
name="message_add_data",
49+
),
4250
]

0 commit comments

Comments
 (0)