slthcore 0.0.6__tar.gz → 0.0.7__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.

Files changed (83) hide show
  1. {slthcore-0.0.6/slthcore.egg-info → slthcore-0.0.7}/PKG-INFO +1 -1
  2. {slthcore-0.0.6 → slthcore-0.0.7}/setup.py +1 -1
  3. {slthcore-0.0.6 → slthcore-0.0.7}/slth/components.py +40 -16
  4. {slthcore-0.0.6 → slthcore-0.0.7}/slth/endpoints.py +41 -3
  5. slthcore-0.0.7/slth/exceptions.py +11 -0
  6. {slthcore-0.0.6 → slthcore-0.0.7}/slth/factory.py +6 -0
  7. {slthcore-0.0.6 → slthcore-0.0.7}/slth/forms.py +23 -2
  8. slthcore-0.0.7/slth/printer.py +70 -0
  9. slthcore-0.0.7/slth/static/js/slth.min.js +236 -0
  10. slthcore-0.0.7/slth/templates/report.html +23 -0
  11. slthcore-0.0.7/slth/templates/signature.html +45 -0
  12. {slthcore-0.0.6 → slthcore-0.0.7}/slth/views.py +6 -2
  13. {slthcore-0.0.6 → slthcore-0.0.7/slthcore.egg-info}/PKG-INFO +1 -1
  14. {slthcore-0.0.6 → slthcore-0.0.7}/slthcore.egg-info/SOURCES.txt +3 -0
  15. slthcore-0.0.6/slth/exceptions.py +0 -6
  16. slthcore-0.0.6/slth/static/js/slth.min.js +0 -225
  17. {slthcore-0.0.6 → slthcore-0.0.7}/MANIFEST.in +0 -0
  18. {slthcore-0.0.6 → slthcore-0.0.7}/setup.cfg +0 -0
  19. {slthcore-0.0.6 → slthcore-0.0.7}/slth/__init__.py +0 -0
  20. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/configure/__main__.py +0 -0
  21. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/__main__.py +0 -0
  22. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/.DS_Store +0 -0
  23. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/.gitignore +0 -0
  24. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/backend/api/__init__.py +0 -0
  25. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/backend/api/asgi.py +0 -0
  26. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/backend/api/endpoints.py +0 -0
  27. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/backend/api/models.py +0 -0
  28. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/backend/api/settings.py +0 -0
  29. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/backend/api/tests.py +0 -0
  30. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/backend/api/urls.py +0 -0
  31. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/backend/api/wsgi.py +0 -0
  32. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/backend/application.yml +0 -0
  33. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/backend/entrypoint.sh +0 -0
  34. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/backend/manage.py +0 -0
  35. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/backend/requirements.txt +0 -0
  36. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/base.env +0 -0
  37. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/docker-compose.yml +0 -0
  38. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/frontend/package.json +0 -0
  39. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/frontend/src/main.jsx +0 -0
  40. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/frontend/vite.config.js +0 -0
  41. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/local.env +0 -0
  42. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/run.sh +0 -0
  43. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/selenium/run.sh +0 -0
  44. {slthcore-0.0.6 → slthcore-0.0.7}/slth/cmd/init/boilerplate/test.sh +0 -0
  45. {slthcore-0.0.6 → slthcore-0.0.7}/slth/db/__init__.py +0 -0
  46. {slthcore-0.0.6 → slthcore-0.0.7}/slth/db/generic.py +0 -0
  47. {slthcore-0.0.6 → slthcore-0.0.7}/slth/db/models.py +0 -0
  48. {slthcore-0.0.6 → slthcore-0.0.7}/slth/management/__init__.py +0 -0
  49. {slthcore-0.0.6 → slthcore-0.0.7}/slth/management/commands/__init__.py +0 -0
  50. {slthcore-0.0.6 → slthcore-0.0.7}/slth/management/commands/integration_test.py +0 -0
  51. {slthcore-0.0.6 → slthcore-0.0.7}/slth/management/commands/sync.py +0 -0
  52. {slthcore-0.0.6 → slthcore-0.0.7}/slth/migrations/0001_initial.py +0 -0
  53. {slthcore-0.0.6 → slthcore-0.0.7}/slth/migrations/0002_email_role_pushsubscription_error.py +0 -0
  54. {slthcore-0.0.6 → slthcore-0.0.7}/slth/migrations/0003_rename_photo_profile_alter_profile_options.py +0 -0
  55. {slthcore-0.0.6 → slthcore-0.0.7}/slth/migrations/0004_alter_profile_photo.py +0 -0
  56. {slthcore-0.0.6 → slthcore-0.0.7}/slth/migrations/0005_alter_profile_photo.py +0 -0
  57. {slthcore-0.0.6 → slthcore-0.0.7}/slth/migrations/0006_user.py +0 -0
  58. {slthcore-0.0.6 → slthcore-0.0.7}/slth/migrations/0007_deletion_log.py +0 -0
  59. {slthcore-0.0.6 → slthcore-0.0.7}/slth/migrations/__init__.py +0 -0
  60. {slthcore-0.0.6 → slthcore-0.0.7}/slth/models.py +0 -0
  61. {slthcore-0.0.6 → slthcore-0.0.7}/slth/notifications.py +0 -0
  62. {slthcore-0.0.6 → slthcore-0.0.7}/slth/oauth.py +0 -0
  63. {slthcore-0.0.6 → slthcore-0.0.7}/slth/permissions.py +0 -0
  64. {slthcore-0.0.6 → slthcore-0.0.7}/slth/queryset.py +0 -0
  65. {slthcore-0.0.6 → slthcore-0.0.7}/slth/roles.py +0 -0
  66. {slthcore-0.0.6 → slthcore-0.0.7}/slth/selenium/__init__.py +0 -0
  67. {slthcore-0.0.6 → slthcore-0.0.7}/slth/selenium/browser.py +0 -0
  68. {slthcore-0.0.6 → slthcore-0.0.7}/slth/serializer.py +0 -0
  69. {slthcore-0.0.6 → slthcore-0.0.7}/slth/static/.DS_Store +0 -0
  70. {slthcore-0.0.6 → slthcore-0.0.7}/slth/static/css/.DS_Store +0 -0
  71. {slthcore-0.0.6 → slthcore-0.0.7}/slth/static/css/slth.css +0 -0
  72. {slthcore-0.0.6 → slthcore-0.0.7}/slth/static/js/index.min.js +0 -0
  73. {slthcore-0.0.6 → slthcore-0.0.7}/slth/static/js/react.min.js +0 -0
  74. {slthcore-0.0.6 → slthcore-0.0.7}/slth/statistics.py +0 -0
  75. {slthcore-0.0.6 → slthcore-0.0.7}/slth/tasks.py +0 -0
  76. {slthcore-0.0.6 → slthcore-0.0.7}/slth/templates/index.html +0 -0
  77. {slthcore-0.0.6 → slthcore-0.0.7}/slth/templates/service-worker.js +0 -0
  78. {slthcore-0.0.6 → slthcore-0.0.7}/slth/tests.py +0 -0
  79. {slthcore-0.0.6 → slthcore-0.0.7}/slth/threadlocal.py +0 -0
  80. {slthcore-0.0.6 → slthcore-0.0.7}/slth/urls.py +0 -0
  81. {slthcore-0.0.6 → slthcore-0.0.7}/slth/utils.py +0 -0
  82. {slthcore-0.0.6 → slthcore-0.0.7}/slthcore.egg-info/dependency_links.txt +0 -0
  83. {slthcore-0.0.6 → slthcore-0.0.7}/slthcore.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: slthcore
3
- Version: 0.0.6
3
+ Version: 0.0.7
4
4
  Summary: API generator based on yml file
5
5
  Home-page: https://github.com/brenokcc
6
6
  Author: Breno Silva
@@ -5,7 +5,7 @@ install_requires = []
5
5
 
6
6
  setup(
7
7
  name='slthcore',
8
- version='0.0.6',
8
+ version='0.0.7',
9
9
  packages=find_packages(),
10
10
  install_requires=install_requires,
11
11
  include_package_data=True,
@@ -170,9 +170,10 @@ class Table(dict):
170
170
 
171
171
 
172
172
  class TemplateContent(dict):
173
- def __init__(self, name, context):
173
+ def __init__(self, name, context, autoreload=None):
174
174
  self["type"] = "html"
175
175
  self["content"] = render_to_string(name, context)
176
+ self["autoreload"] = autoreload * 1000 if autoreload else None
176
177
 
177
178
 
178
179
  class Banner(dict):
@@ -284,11 +285,11 @@ class Grid(dict):
284
285
 
285
286
 
286
287
  class Scheduler(dict):
287
- INTERVALS = {1: ["00"], 2: ["00", "30"]}
288
+ INTERVALS = {1: ["00"], 2: ["00", "30"], 3: ["00", "20", "40"]}
288
289
 
289
290
  def __init__(
290
291
  self,
291
- start_time=7,
292
+ start_time=0,
292
293
  end_time=23,
293
294
  chucks=2,
294
295
  start_day=None,
@@ -296,21 +297,37 @@ class Scheduler(dict):
296
297
  single_selection=False,
297
298
  input_name="schedule",
298
299
  readonly=False,
299
- title=None
300
+ title=None,
301
+ watch=[],
302
+ url=None,
303
+ selectable=None,
304
+ weekly=False
300
305
  ):
301
306
  self["type"] = "scheduler"
302
307
  self["title"] = title
303
308
  self["single_selection"] = single_selection
304
309
  self["input_name"] = input_name
305
310
  self["readonly"] = readonly
306
- self.end_day = start_day or datetime.now()
307
- self.end_day = datetime(self.end_day.year, self.end_day.month, self.end_day.day)
311
+ self["watch"] = watch
312
+ self["url"] = url
313
+ self["selectable"] = ['{} {}'.format(obj.strftime("%d/%m/%Y"), obj.strftime("%H:%M")) for obj in selectable] if selectable is not None else None
314
+ self["weekly"] = weekly
315
+ if weekly:
316
+ self.end_day = datetime.now()
317
+ while self.end_day.weekday() > 0:
318
+ self.end_day = self.end_day - timedelta(days=1)
319
+ days = 7
320
+ else:
321
+ self.end_day = start_day or datetime.now()
322
+ self.end_day = datetime(self.end_day.year, self.end_day.month, self.end_day.day)
308
323
  self.times = []
309
324
  for hour in range(start_time, end_time + 1):
310
325
  for minute in Scheduler.INTERVALS[chucks]:
311
326
  self.times.append("{}:{}".format(str(hour).rjust(2, "0"), minute))
312
327
  self.days = []
313
328
  for n in range(0, days):
329
+ if n == 0:
330
+ self.start_day = self.end_day
314
331
  self.days.append(self.end_day.strftime("%d/%m/%Y"))
315
332
  self.end_day = self.end_day + timedelta(days=1)
316
333
  self.end_day = datetime(self.end_day.year, self.end_day.month, self.end_day.day, 23, 59, 59)
@@ -329,13 +346,20 @@ class Scheduler(dict):
329
346
  row.append(self["slots"][day][time])
330
347
  self["matrix"].append(row)
331
348
 
332
- def append(self, date_time, text, icon='check'):
333
- day = date_time.strftime("%d/%m/%Y")
334
- time = date_time.strftime("%H:%M")
335
- value = dict(text=text, icon=icon)
336
- self["slots"][day][time] = value
337
- j = self.days.index(day) + 1 if day in self.days else -1
338
- x = self.times.index(time) + 1 if time in self.times else -1
339
- self["matrix"][x][j] = value
340
-
341
-
349
+ def append(self, date_time, text=None, icon='check'):
350
+ if date_time.strftime("%d/%m/%Y") in self.days:
351
+ day = date_time.strftime("%d/%m/%Y")
352
+ time = date_time.strftime("%H:%M")
353
+ value = dict(text=text, icon=icon)
354
+ self["slots"][day][time] = value
355
+ j = self.days.index(day) + 1 if day in self.days else -1
356
+ x = self.times.index(time) + 1 if time in self.times else -1
357
+ self["matrix"][x][j] = value
358
+
359
+ def append_weekday(self, weekday, hour, minute):
360
+ date_time = self.start_day
361
+ while date_time < self.end_day + timedelta(days=-1):
362
+ if date_time.weekday() == int(weekday):
363
+ self.append(datetime(date_time.year, date_time.month, date_time.day, hour, minute, 0))
364
+ date_time += timedelta(days=1)
365
+
@@ -1,7 +1,9 @@
1
+ import io
1
2
  import json
2
3
  import types
3
4
  import inspect
4
-
5
+ import requests
6
+ from weasyprint import HTML
5
7
  from .models import Token, Role, Log, Deletion
6
8
  from django.apps import apps
7
9
  from typing import TypeVar, Generic
@@ -9,13 +11,14 @@ from django.core.cache import cache
9
11
  from django.conf import settings
10
12
  from django.utils.text import slugify
11
13
  from django.db import models
12
- from django.http import JsonResponse
14
+ from django.http import JsonResponse, HttpResponse
13
15
  from django.views.decorators.csrf import csrf_exempt
14
16
  from .factory import FormFactory
15
17
  from django.core.exceptions import ValidationError
16
18
  from slth import forms
17
19
  from django.db.models import Model
18
20
  from datetime import datetime
21
+ from django.template.loader import render_to_string
19
22
  from django.contrib.auth import authenticate
20
23
  from .forms import ModelForm, Form
21
24
  from .serializer import serialize, Serializer
@@ -27,8 +30,9 @@ from .components import (
27
30
  Response,
28
31
  Boxes,
29
32
  IconSet,
33
+ TemplateContent,
30
34
  )
31
- from .exceptions import JsonResponseException
35
+ from .exceptions import JsonResponseException, ReadyResponseException
32
36
  from .utils import build_url, append_url
33
37
  from .models import PushSubscription, Profile, User, Log
34
38
  from slth.queryset import QuerySet
@@ -148,6 +152,29 @@ class Endpoint(metaclass=EnpointMetaclass):
148
152
 
149
153
  def redirect(self, url):
150
154
  raise JsonResponseException(dict(type="redirect", url=url))
155
+
156
+ def render(self, data, template=None, pdf=False, autoreload=None):
157
+ base_url='http://localhost:8000'
158
+ data.update(base_url=base_url)
159
+ if template is None:
160
+ template = '{}.html'.format(template or self.__class__.__name__.lower())
161
+ if pdf:
162
+ buffer = io.BytesIO()
163
+ if isinstance(template, str):
164
+ templates = template,
165
+ else:
166
+ templates = template
167
+ pages = []
168
+ for template in templates:
169
+ html = render_to_string(template, data)
170
+ if pdf:
171
+ doc = HTML(string=html).render()
172
+ pages.extend(doc.pages)
173
+ new_doc = doc.copy(pages=pages)
174
+ new_doc.write_pdf(buffer, base_url=base_url, stylesheets=[])
175
+ buffer.seek(0)
176
+ raise ReadyResponseException(HttpResponse(buffer, content_type='application/pdf'))
177
+ return TemplateContent(template, data, autoreload=autoreload)
151
178
 
152
179
  def getform(self, form):
153
180
  return form
@@ -318,6 +345,17 @@ class PublicEndpoint(Endpoint):
318
345
  return True
319
346
 
320
347
 
348
+ class ReportEndpoint(Endpoint):
349
+
350
+ def process(self):
351
+ data = super().process()
352
+ template = '{}.html'.format(self.__class__.__name__.lower())
353
+ html = render_to_string(template, data)
354
+ headers = {'Content-type': 'text/html'}
355
+ response = requests.post('http://weasyprint.aplicativo.click/pdf', headers=headers, data=html)
356
+ raise ReadyResponseException(HttpResponse(response.content, content_type='application/pdf'))
357
+
358
+
321
359
  class ModelEndpoint(Endpoint):
322
360
  def __init__(self):
323
361
  self.model = self.__orig_bases__[0].__args__[0]
@@ -0,0 +1,11 @@
1
+
2
+ class JsonResponseException(Exception):
3
+
4
+ def __init__(self, data, *args, **kwargs):
5
+ super().__init__(*args, **kwargs)
6
+ self.data = data
7
+
8
+ class ReadyResponseException(Exception):
9
+ def __init__(self, response, *args, **kwargs):
10
+ super().__init__(*args, **kwargs)
11
+ self.response = response
@@ -18,6 +18,7 @@ class FormFactory:
18
18
  self._redirect = None
19
19
  self._message = None
20
20
  self._dispose = False
21
+ self._image = None
21
22
 
22
23
  def _append_field(self, field_name):
23
24
  if ':' in field_name:
@@ -25,6 +26,10 @@ class FormFactory:
25
26
  self._actions[field_name] = action_name
26
27
  self._fieldlist.append(field_name)
27
28
  return field_name
29
+
30
+ def image(self, image) -> 'FormFactory':
31
+ self._image = image
32
+ return self
28
33
 
29
34
  def fields(self, *names, **values) -> 'FormFactory':
30
35
  not_str = {name for name in names if not isinstance(name, str)}
@@ -112,6 +117,7 @@ class FormFactory:
112
117
  form._message = self._message
113
118
  form._redirect = self._redirect
114
119
  form._dispose = self._dispose
120
+ form._image = self._image
115
121
  for name in self._fieldlist:
116
122
  if name not in form.fields:
117
123
  form.fields[name] = getattr(endpoint, name)
@@ -166,6 +166,7 @@ class FormMixin:
166
166
  style=self.get_metadata("style"),
167
167
  url=absolute_url(self.request),
168
168
  info=self._info,
169
+ image=self._image,
169
170
  )
170
171
  data.update(
171
172
  controls=self.controller.controls, width=self.get_metadata("width", "100%")
@@ -466,6 +467,13 @@ class FormMixin:
466
467
  if field_name not in inline_fields
467
468
  }
468
469
  )
470
+ for attr_name in dir(self._endpoint):
471
+ if attr_name.startswith('clean_'):
472
+ try:
473
+ getattr(self._endpoint, attr_name)(data)
474
+ except ValidationError as e:
475
+ fieldname = attr_name.replace('clean_', '')
476
+ raise JsonResponseException(dict(type="error", text="Por favor, corrija os erros.", errors={fieldname: ''.join(e.messages)}))
469
477
  with transaction.atomic():
470
478
  self.cleaned_data = data
471
479
  if isinstance(self, DjangoModelForm):
@@ -506,6 +514,7 @@ class Form(DjangoForm, FormMixin):
506
514
  self._display = []
507
515
  self._endpoint = endpoint
508
516
  self._info = None
517
+ self._image = None
509
518
  self._message = None
510
519
  self._redirect = None
511
520
  self._dispose = False
@@ -540,6 +549,7 @@ class ModelForm(DjangoModelForm, FormMixin):
540
549
  self._display = []
541
550
  self._endpoint = endpoint
542
551
  self._info = None
552
+ self._image = None
543
553
  self._message = None
544
554
  self._redirect = None
545
555
  self._dispose = False
@@ -568,6 +578,9 @@ class ModelForm(DjangoModelForm, FormMixin):
568
578
  kwargs.update(files=self.request.FILES or None)
569
579
  super().__init__(instance=instance, **kwargs)
570
580
 
581
+ def is_valid(self):
582
+ valid = super().is_valid()
583
+ return valid
571
584
 
572
585
  class InlineFormField(Field):
573
586
  def __init__(self, *args, form=None, min=1, max=3, **kwargs):
@@ -691,7 +704,7 @@ class SchedulerField(CharField):
691
704
  self.scheduler = scheduler or Scheduler()
692
705
  super().__init__(*args, **kwargs)
693
706
 
694
- def clean(self, value):
707
+ def to_python(self, value):
695
708
  values = dict(select=[], deselect=[])
696
709
  if value:
697
710
  data = json.loads(value)
@@ -701,7 +714,15 @@ class SchedulerField(CharField):
701
714
  values[key].append(datetime.datetime.strptime(data_string, "%d/%m/%Y %H:%M"))
702
715
  if self.scheduler["single_selection"]:
703
716
  return values['select'][0] if values['select'] else None
704
- return values
717
+ else:
718
+ return values
719
+
720
+ def clean(self, value):
721
+ value = self.to_python(value)
722
+ if self.scheduler["single_selection"]:
723
+ if self.required and value is None:
724
+ raise ValidationError('Este campo é obrigatório.')
725
+ return value
705
726
 
706
727
 
707
728
  FIELD_TYPES = {
@@ -0,0 +1,70 @@
1
+ import io
2
+ import qrcode
3
+ import base64
4
+ from datetime import datetime
5
+ from weasyprint import HTML
6
+ from django.conf import settings
7
+ from django.template.loader import render_to_string
8
+
9
+
10
+ class Signature:
11
+ def __init__(self, date, validation_url, verify_code=None, auth_code=None):
12
+ self.date = date
13
+ if validation_url.startswith('http'):
14
+ self.validation_url = validation_url
15
+ else:
16
+ self.validation_url = '{}{}'.format(settings.SITE_URL, validation_url)
17
+ self.verify_code = verify_code
18
+ self.auth_code = auth_code
19
+ self.signers = []
20
+ self.qrcode = qrcode_base64(self.validation_url)
21
+
22
+ def add_signer(self, identifier, signature_date=None):
23
+ self.signers.append((identifier, signature_date))
24
+
25
+
26
+ def qrcode_base64(texto):
27
+ qr = qrcode.QRCode(version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=10, border=4)
28
+ qr.add_data(texto)
29
+ qr.make(fit=True)
30
+ img = qr.make_image(fill_color="black", back_color="white")
31
+ buffered =io.BytesIO()
32
+ img.save(buffered, format="JPEG")
33
+ img_str = base64.b64encode(buffered.getvalue()).decode()
34
+ return img_str
35
+
36
+ def image_base64(image_bytes):
37
+ return 'data:image/png;base64, {}'.format(base64.b64encode(image_bytes).decode())
38
+
39
+
40
+ def to_pdf(data, template, file_name=None, signature=None):
41
+ templates = []
42
+ buffer = io.BytesIO()
43
+ templates.append(template)
44
+ if signature:
45
+ data.update(signature=signature)
46
+ templates.append('signature.html')
47
+ pages = []
48
+ for template in templates:
49
+ data.update(page=len(pages)+1)
50
+ html = render_to_string(template, data)
51
+ doc = HTML(string=html).render()
52
+ pages.extend(doc.pages)
53
+ doc = doc.copy(pages=pages) if len(templates) > 1 else doc
54
+ doc.write_pdf(file_name or buffer, base_url=settings.SITE_URL, stylesheets=[])
55
+ buffer.seek(0)
56
+ return buffer
57
+
58
+ def test():
59
+ data = dict(lines=range(50))
60
+ signature = Signature(date=datetime.now(), validation_url='/', verify_code=123, auth_code=123)
61
+ signature.add_signer('Carlos Silva', datetime.now())
62
+ signature.add_signer('Juca Silva', None)
63
+ to_pdf(data, 'report.html', '/Users/breno/Downloads/a.pdf', signature=signature)
64
+
65
+ def test2():
66
+ data = dict(lines=range(50))
67
+ signature = Signature(date=datetime.now(), validation_url='https://validar.iti.gov.br/')
68
+ signature.add_signer('Carlos Silva (075.803.982-90)', None)
69
+ signature.add_signer('Juca Silva (075.803.982-90)', None)
70
+ to_pdf(data, 'report.html', '/Users/breno/Downloads/a.pdf', signature=signature)