slthcore 0.1.3__tar.gz → 0.1.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of slthcore might be problematic. Click here for more details.
- {slthcore-0.1.3/slthcore.egg-info → slthcore-0.1.5}/PKG-INFO +1 -1
- {slthcore-0.1.3 → slthcore-0.1.5}/setup.py +1 -1
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/__init__.py +13 -2
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/endpoints.py +0 -3
- slthcore-0.1.5/slth/pdf/__init__.py +177 -0
- slthcore-0.1.5/slth/pdf/tests.py +70 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/selenium/__init__.py +1 -0
- {slthcore-0.1.3 → slthcore-0.1.5/slthcore.egg-info}/PKG-INFO +1 -1
- {slthcore-0.1.3 → slthcore-0.1.5}/slthcore.egg-info/SOURCES.txt +2 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/MANIFEST.in +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/setup.cfg +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/configure/__main__.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/__main__.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/.DS_Store +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/.gitignore +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/backend/api/__init__.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/backend/api/asgi.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/backend/api/endpoints.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/backend/api/models.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/backend/api/settings.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/backend/api/tests.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/backend/api/urls.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/backend/api/wsgi.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/backend/application.yml +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/backend/entrypoint.sh +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/backend/manage.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/backend/requirements.txt +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/base.env +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/docker-compose.yml +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/frontend/package.json +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/frontend/src/main.jsx +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/frontend/vite.config.js +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/local.env +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/run.sh +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/selenium/run.sh +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/cmd/init/boilerplate/test.sh +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/components.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/db/__init__.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/db/generic.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/db/models.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/exceptions.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/factory.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/forms.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/management/__init__.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/management/commands/__init__.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/management/commands/integration_test.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/management/commands/sync.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/migrations/0001_initial.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/migrations/0002_email_role_pushsubscription_error.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/migrations/0003_rename_photo_profile_alter_profile_options.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/migrations/0004_alter_profile_photo.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/migrations/0005_alter_profile_photo.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/migrations/0006_user.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/migrations/0007_deletion_log.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/migrations/__init__.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/models.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/notifications.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/oauth.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/permissions.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/printer.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/queryset.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/roles.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/selenium/browser.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/serializer.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/static/.DS_Store +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/static/css/.DS_Store +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/static/css/slth.css +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/static/js/index.min.js +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/static/js/react.min.js +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/static/js/slth.min.js +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/statistics.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/tasks.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/templates/index.html +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/templates/report.html +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/templates/service-worker.js +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/templates/signature.html +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/tests.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/threadlocal.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/urls.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/utils.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slth/views.py +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slthcore.egg-info/dependency_links.txt +0 -0
- {slthcore-0.1.3 → slthcore-0.1.5}/slthcore.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ import yaml
|
|
|
4
4
|
import json
|
|
5
5
|
import warnings
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from datetime import datetime
|
|
7
|
+
from datetime import datetime, date
|
|
8
8
|
from django.apps import apps
|
|
9
9
|
from django.db import models
|
|
10
10
|
from .queryset import QuerySet
|
|
@@ -19,6 +19,8 @@ from django.utils.autoreload import autoreload_started
|
|
|
19
19
|
from django.core import serializers
|
|
20
20
|
from .threadlocal import tl
|
|
21
21
|
|
|
22
|
+
from decimal import Decimal
|
|
23
|
+
|
|
22
24
|
warnings.filterwarnings('ignore', module='urllib3')
|
|
23
25
|
|
|
24
26
|
FILENAME = 'application.yml'
|
|
@@ -34,6 +36,15 @@ if APPLICATON is None and os.path.exists(FILENAME):
|
|
|
34
36
|
APPLICATON = yaml.safe_load(content).get('application')
|
|
35
37
|
|
|
36
38
|
|
|
39
|
+
class JSONEncoder(json.JSONEncoder):
|
|
40
|
+
def default(self, obj):
|
|
41
|
+
if isinstance(obj, Decimal):
|
|
42
|
+
return float(obj)
|
|
43
|
+
if isinstance(obj, date):
|
|
44
|
+
return obj.strftime("%d-%m-%Y")
|
|
45
|
+
return json.JSONEncoder.default(self, obj)
|
|
46
|
+
|
|
47
|
+
|
|
37
48
|
class BaseManager(manager.BaseManager):
|
|
38
49
|
def get_queryset(self):
|
|
39
50
|
return super().get_queryset()
|
|
@@ -120,7 +131,7 @@ class ModelMixin(object):
|
|
|
120
131
|
objects.append(instance)
|
|
121
132
|
if instance.__class__.__name__ not in order:
|
|
122
133
|
order.append(instance.__class__.__name__)
|
|
123
|
-
backup = json.dumps(dict(order=order, objects=serializers.serialize("python", objects)))
|
|
134
|
+
backup = json.dumps(dict(order=order, objects=serializers.serialize("python", objects)), cls=JSONEncoder)
|
|
124
135
|
instance = '{}.{}:{}'.format(self._meta.app_label, self._meta.model_name, self.pk)
|
|
125
136
|
Deletion.objects.create(username=username, datetime=datetime.now(), instance=instance, backup=backup)
|
|
126
137
|
return self.delete()
|
|
@@ -330,7 +330,6 @@ class Endpoint(metaclass=EnpointMetaclass):
|
|
|
330
330
|
if hasattr(tl, 'context') and tl.context['logs']:
|
|
331
331
|
pk = tl.context['pk']
|
|
332
332
|
instance = self.get_instance()
|
|
333
|
-
print(tl.context)
|
|
334
333
|
if pk or isinstance(instance, Model):
|
|
335
334
|
model = '{}.{}'.format(instance._meta.app_label, instance._meta.model_name)
|
|
336
335
|
tl.context.update(model=model, pk=pk or instance.pk)
|
|
@@ -823,8 +822,6 @@ class Application(PublicEndpoint):
|
|
|
823
822
|
icon, label = k.split(":") if ":" in k else (None, k)
|
|
824
823
|
url = build_url(self.request, cls.get_api_url())
|
|
825
824
|
return dict(dict(label=label, url=url, icon=icon))
|
|
826
|
-
else:
|
|
827
|
-
print(v)
|
|
828
825
|
|
|
829
826
|
for k, v in APPLICATON["menu"].items():
|
|
830
827
|
item = get_item(k, v)
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# pip install --upgrade fpdf2
|
|
2
|
+
from fpdf import FPDF, FontFace
|
|
3
|
+
import hashlib
|
|
4
|
+
import base64
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
import requests
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
import tempfile
|
|
10
|
+
from PIL import Image, ImageDraw, ImageFont
|
|
11
|
+
from django.template.loader import render_to_string
|
|
12
|
+
from django.conf import settings
|
|
13
|
+
|
|
14
|
+
SIGNATURE_URL = 'https://assinatura-api.staging.iti.br/externo/v2/assinarPKCS7'
|
|
15
|
+
SIGNATURE_SIZE = 18944
|
|
16
|
+
BYTERANGE='[ ]'
|
|
17
|
+
|
|
18
|
+
STYLE = {
|
|
19
|
+
'h1': FontFace(color="#000000", size_pt=28, family='Helvetica'),
|
|
20
|
+
'h2': FontFace(color="#000000", size_pt=24, family='Helvetica'),
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class PdfWriter:
|
|
24
|
+
def __init__(self):
|
|
25
|
+
self.pdf = FPDF()
|
|
26
|
+
self.pdf.add_page()
|
|
27
|
+
|
|
28
|
+
def render(self, template_name, context):
|
|
29
|
+
context.update(base_url=settings.SITE_URL)
|
|
30
|
+
html = render_to_string(template_name, context)
|
|
31
|
+
self.pdf.write_html(html, tag_styles=STYLE, font_family="Courier")
|
|
32
|
+
|
|
33
|
+
def save(self, path):
|
|
34
|
+
self.pdf.output(path)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class PdfSigner:
|
|
38
|
+
def __init__(self, path, signer):
|
|
39
|
+
self.path = path
|
|
40
|
+
self.signer = signer
|
|
41
|
+
self.xref = None
|
|
42
|
+
self.data = []
|
|
43
|
+
with open(path, 'rb') as fp:
|
|
44
|
+
self.content = fp.read()# + b'\r\n'
|
|
45
|
+
self.offset = len(self.content)
|
|
46
|
+
self.byterange = []
|
|
47
|
+
self.path = path.split('.')[0]
|
|
48
|
+
self.startxref = [int(x[9:].strip()) for x in re.findall(b'startxref[\n\r ]*\d+', self.content)]
|
|
49
|
+
self.objects = {}
|
|
50
|
+
for xref in re.findall(b'xref[\n\r\w\d ]*trailer', self.content[self.startxref[0]:]):
|
|
51
|
+
for offset in sum([[int(n) for n in re.findall(b'\d{10}', xref) if int(n)]], []):
|
|
52
|
+
self.objects[b' '.join(self.content[offset:offset + 15].split()[0:2]).decode()] = offset
|
|
53
|
+
self.trailer = self.content[self.startxref[-1]:].split(b'trailer')[1].split(b'startxref')[0].strip()
|
|
54
|
+
self.root = root = re.findall(b'/Root \d+ \d+ R', self.trailer)[-1][6:-2].decode()
|
|
55
|
+
self.size = int(re.findall(b'/Size \d+', self.trailer)[-1][5:].strip())
|
|
56
|
+
self.page()
|
|
57
|
+
|
|
58
|
+
def obj(self, key=None):
|
|
59
|
+
key = key or self.root
|
|
60
|
+
return self.content[self.objects[key]: self.objects[key] + self.content[self.objects[key]:].index(b'endobj') + 6].replace(b'\r', b'') + b'\n'
|
|
61
|
+
|
|
62
|
+
def next(self, i):
|
|
63
|
+
return max([int(k.split()[0]) for k in self.objects]) + i
|
|
64
|
+
|
|
65
|
+
def add(self, data):
|
|
66
|
+
offset = str(self.offset).rjust(10, '0')
|
|
67
|
+
self.offset += len(data)
|
|
68
|
+
self.data.append(data)
|
|
69
|
+
if self.xref is None:
|
|
70
|
+
self.xref = ['xref', '0 1', '0000000000 65535 f\r']
|
|
71
|
+
self.xref.append('{} 1'.format(data.split()[0]))
|
|
72
|
+
self.xref.append('{} 00000 n\r'.format(offset))
|
|
73
|
+
|
|
74
|
+
def page(self):
|
|
75
|
+
for key, offset in self.objects.items():
|
|
76
|
+
content = self.content[offset:offset + 500]
|
|
77
|
+
if b'/Page' in content and b'/Pages' not in content:
|
|
78
|
+
return key
|
|
79
|
+
raise BaseException('No page was found in the PDF')
|
|
80
|
+
|
|
81
|
+
def finalize(self):
|
|
82
|
+
xrefstart = str(self.offset)
|
|
83
|
+
data = '\n'.join(self.xref)
|
|
84
|
+
data += '\ntrailer\n<<\n/Size {}\n/Root {} R\n/Prev {}\n>>\n'.format(
|
|
85
|
+
(self.size + len(self.xref) - 5), self.root, self.startxref[-1]
|
|
86
|
+
)
|
|
87
|
+
data += 'startxref\n'
|
|
88
|
+
data += xrefstart
|
|
89
|
+
data += '\n%%EOF'
|
|
90
|
+
self.offset += len(data)
|
|
91
|
+
self.data.append(data)
|
|
92
|
+
|
|
93
|
+
def hash(self, n=0):
|
|
94
|
+
w, h = 900, 200
|
|
95
|
+
left = n * 200
|
|
96
|
+
signer = self.signer.split(':')[0]
|
|
97
|
+
stamp_file_path = self.stamp(signer)
|
|
98
|
+
print(stamp_file_path)
|
|
99
|
+
self.add(self.obj().decode().replace('>>', '/AcroForm <<\n/Fields [{} 0 R]\n/SigFlags 3\n>>\n>>'.format(self.next(1))))
|
|
100
|
+
self.add(self.obj(self.page()).decode().replace('/Page', '/Page /Annots [{} 0 R]'.format(self.next(1))))
|
|
101
|
+
a = "{} 0 obj\n<<\n/FT /Sig\n/Type /Annot\n/Subtype /Widget\n/F 132\n/T (Signature1)\n/V {} 0 R\n/P {} R\n/Rect [{} 0 {} {}]\n/AP {} 0 R\n>>\nendobj\n".format(
|
|
102
|
+
self.next(1), self.next(2), self.page(), w/10*2+left, left, h/10*2, self.next(3))
|
|
103
|
+
b = "{} 0 obj\n<<\n/Type /Sig\n/Filter /Adobe.PPKLite\n/SubFilter /adbe.pkcs7.detached\n/M ({})\n/Contents <{}>\n/ByteRange {}\n/Name ({})\n>>\nendobj\n".format(
|
|
104
|
+
self.next(2), datetime.now().strftime("D:%Y%m%d%H%M%S+00'00'"), '0' * SIGNATURE_SIZE, BYTERANGE, signer)
|
|
105
|
+
c = "{} 0 obj\n<<\n/N {} 0 R\n>>\nendobj\n".format(self.next(3), self.next(4))
|
|
106
|
+
stream = 'q\n{} 0 0 {} 0 0 cm\n/Img1 Do\nQ'.format(w, h)
|
|
107
|
+
d = "{} 0 obj\n<</Type/XObject/Subtype/Form/Resources<</XObject<</Img1 {} 0 R>>>>/BBox[0 0 {} {}]/Length {}>>\nstream\n{}\nendstream\nendobj\n".format(self.next(4), self.next(5), w, h, len(stream), stream)
|
|
108
|
+
x = base64.a85encode(open(stamp_file_path, 'rb').read()).decode()
|
|
109
|
+
e = "{} 0 obj\n<<\n/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /DCTDecode ] /Length {} /Subtype /Image /Type /XObject /Width {} /Height {} /Resources<< >> >>\nstream\n{}\nendstream\nendobj\n".format(self.next(5), len(x), w, h, x)
|
|
110
|
+
self.add(a)
|
|
111
|
+
i = self.offset + b.index('/Contents') + 10
|
|
112
|
+
j = i + SIGNATURE_SIZE + 2
|
|
113
|
+
self.add(b)
|
|
114
|
+
self.add(c)
|
|
115
|
+
self.add(d)
|
|
116
|
+
self.add(e)
|
|
117
|
+
self.finalize()
|
|
118
|
+
self.byterange = [0, i, j, self.length() - j]
|
|
119
|
+
self.data[3] = self.data[3].replace(
|
|
120
|
+
BYTERANGE, '[{} {} {} {}]'.format(*self.byterange).ljust(len(BYTERANGE), ' ')
|
|
121
|
+
)
|
|
122
|
+
for data in self.data:
|
|
123
|
+
self.content += data.encode()
|
|
124
|
+
i, j, x, y = self.byterange
|
|
125
|
+
content = self.content[i:i+j] + self.content[x:x+y]
|
|
126
|
+
hash = base64.b64encode(hashlib.sha256(content).digest()).decode()
|
|
127
|
+
return hash
|
|
128
|
+
|
|
129
|
+
def length(self):
|
|
130
|
+
i = len(self.content)
|
|
131
|
+
for data in self.data:
|
|
132
|
+
i += len(data)
|
|
133
|
+
return i
|
|
134
|
+
|
|
135
|
+
def signed(self, name):
|
|
136
|
+
return '/Name ({})'.format(name).encode() in self.content
|
|
137
|
+
|
|
138
|
+
def stamp(self, name):
|
|
139
|
+
w, h = 900, 200
|
|
140
|
+
bgcolor = '#FFFFFF'
|
|
141
|
+
date = datetime.now()
|
|
142
|
+
img = Image.new('RGB', (w, h), (255, 255, 255))
|
|
143
|
+
img1 = ImageDraw.Draw(img)
|
|
144
|
+
img1.rectangle([(3, 3), (w - 3, h - 3)], fill=bgcolor, outline=bgcolor)
|
|
145
|
+
font = ImageFont.truetype(os.path.join('/Users/breno/Documents/Workspace/suap', 'comum', 'static/comum/font/MicrosoftSansSerif.ttf'), 25)
|
|
146
|
+
bold = ImageFont.truetype(os.path.join('/Users/breno/Documents/Workspace/suap', 'comum', 'static/comum/font/MicrosoftSansSerifBold.ttf'), 25)
|
|
147
|
+
x, y = 380, 10
|
|
148
|
+
img1.text((x, y), 'DOCUMENTO ASSINADO DIGITALMENTE', (0, 0, 0), font=font)
|
|
149
|
+
y += 45
|
|
150
|
+
img1.text((x, y), name, (0, 0, 0), font=bold)
|
|
151
|
+
y += 35
|
|
152
|
+
img1.text((x, y), 'Data/Hora: {}'.format(date.strftime('%d/%m/%Y %H:%M:%S')), (0, 0, 0), font=font)
|
|
153
|
+
y += 35
|
|
154
|
+
img1.text((x, y), 'Verifique em https://verificador.iti.br', (0, 0, 0), font=font)
|
|
155
|
+
y += 35
|
|
156
|
+
tmp = tempfile.NamedTemporaryFile(suffix='.jpeg', delete=False)
|
|
157
|
+
logo = Image.open(os.path.join(os.path.dirname(__file__), 'images', 'icp-brasil.png'))
|
|
158
|
+
img.paste(logo.resize((int(logo.width*0.6), int(logo.height*0.6))), (5, 10))
|
|
159
|
+
img = img.convert("RGB")
|
|
160
|
+
img.save(tmp.name, format='jpeg')
|
|
161
|
+
return tmp.name
|
|
162
|
+
|
|
163
|
+
def sign(self, path=None):
|
|
164
|
+
signature = self.sign_hash(self.hash())
|
|
165
|
+
path = path or '{}-signed.pdf'.format(self.path)
|
|
166
|
+
with open(path, 'wb') as fp:
|
|
167
|
+
content = self.content
|
|
168
|
+
if signature:
|
|
169
|
+
i, j, x, y = self.byterange
|
|
170
|
+
content = self.content[i:i + j] + b'<' + base64.b64decode(signature).hex().ljust(SIGNATURE_SIZE, '0').encode() + b'>' + self.content[x:x + y]
|
|
171
|
+
fp.write(content)
|
|
172
|
+
|
|
173
|
+
def sign_hash(self, hash):
|
|
174
|
+
return None
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
#curl -X POST 'https://verificador.staging.iti.br/report' --header 'Content-Type: multipart/form-data' --form 'report_type="json"' --form 'signature_files[]=@"hello-assinado.pdf"' --form 'detached_files[]=""'
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from django.test import TestCase
|
|
2
|
+
from . import PdfWriter, VidaasPdfSigner
|
|
3
|
+
|
|
4
|
+
HTML = """
|
|
5
|
+
<h1>Big title</h1>
|
|
6
|
+
<dl>
|
|
7
|
+
<dt>Description title</dt>
|
|
8
|
+
<dd>Description Detail</dd>
|
|
9
|
+
</dl>
|
|
10
|
+
<section>
|
|
11
|
+
<h2>Section title</h2>
|
|
12
|
+
<p><b>Hello</b> world. <u>I am</u> <i>tired</i>.</p>
|
|
13
|
+
<p><a href="https://github.com/py-pdf/fpdf2">py-pdf/fpdf2 GitHub repo</a></p>
|
|
14
|
+
<p align="right">right aligned text</p>
|
|
15
|
+
<p>i am a paragraph <br>in two parts.</p>
|
|
16
|
+
<font color="#00ff00"><p>hello in green</p></font>
|
|
17
|
+
<font size="7"><p>hello small</p></font>
|
|
18
|
+
<font face="helvetica"><p>hello helvetica</p></font>
|
|
19
|
+
<font face="times"><p>hello times</p></font>
|
|
20
|
+
</section>
|
|
21
|
+
<section>
|
|
22
|
+
<h2>Other section title</h2>
|
|
23
|
+
<ul type="circle">
|
|
24
|
+
<li>unordered</li>
|
|
25
|
+
<li>list</li>
|
|
26
|
+
<li>items</li>
|
|
27
|
+
</ul>
|
|
28
|
+
<ol start="3" type="i">
|
|
29
|
+
<li>ordered</li>
|
|
30
|
+
<li>list</li>
|
|
31
|
+
<li>items</li>
|
|
32
|
+
</ol>
|
|
33
|
+
<br>
|
|
34
|
+
<br>
|
|
35
|
+
<pre>i am preformatted text.</pre>
|
|
36
|
+
<br>
|
|
37
|
+
<blockquote>hello blockquote</blockquote>
|
|
38
|
+
<table width="50%">
|
|
39
|
+
<thead>
|
|
40
|
+
<tr>
|
|
41
|
+
<th width="30%">ID</th>
|
|
42
|
+
<th width="70%">Name</th>
|
|
43
|
+
</tr>
|
|
44
|
+
</thead>
|
|
45
|
+
<tbody>
|
|
46
|
+
<tr>
|
|
47
|
+
<td>1</td>
|
|
48
|
+
<td>Alice</td>
|
|
49
|
+
</tr>
|
|
50
|
+
<tr>
|
|
51
|
+
<td>2</td>
|
|
52
|
+
<td>Bob</td>
|
|
53
|
+
</tr>
|
|
54
|
+
</tbody>
|
|
55
|
+
</table>
|
|
56
|
+
</section>
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
class AnimalTestCase(TestCase):
|
|
60
|
+
def setUp(self):
|
|
61
|
+
return super().setUp()
|
|
62
|
+
|
|
63
|
+
def test_pdf(self):
|
|
64
|
+
writter = PdfWriter(HTML)
|
|
65
|
+
writter.save('test4.pdf')
|
|
66
|
+
signer = VidaasPdfSigner('test4.pdf', 'Carlos Breno Pereira Silva:04770402414')
|
|
67
|
+
signer.sign()
|
|
68
|
+
|
|
69
|
+
def tearDown(self):
|
|
70
|
+
return super().tearDown()
|
|
@@ -78,6 +78,7 @@ class SeleniumTestCase(LiveServerTestCase):
|
|
|
78
78
|
if os.path.exists(fixture_path):
|
|
79
79
|
call_command("loaddata", fixture_path)
|
|
80
80
|
settings.DEBUG = True
|
|
81
|
+
settings.SITE_URL = cls.live_server_url
|
|
81
82
|
|
|
82
83
|
def create_superuser(self, username, password):
|
|
83
84
|
if not User.objects.filter(username=username).exists():
|
|
@@ -61,6 +61,8 @@ slth/migrations/0005_alter_profile_photo.py
|
|
|
61
61
|
slth/migrations/0006_user.py
|
|
62
62
|
slth/migrations/0007_deletion_log.py
|
|
63
63
|
slth/migrations/__init__.py
|
|
64
|
+
slth/pdf/__init__.py
|
|
65
|
+
slth/pdf/tests.py
|
|
64
66
|
slth/selenium/__init__.py
|
|
65
67
|
slth/selenium/browser.py
|
|
66
68
|
slth/static/.DS_Store
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slthcore-0.1.3 → slthcore-0.1.5}/slth/migrations/0003_rename_photo_profile_alter_profile_options.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|