lino 24.10.3__py3-none-any.whl → 24.11.1__py3-none-any.whl
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.
- lino/__init__.py +1 -1
- lino/api/doctest.py +11 -10
- lino/api/rt.py +2 -3
- lino/config/admin_main_base.html +2 -2
- lino/core/actions.py +2 -4
- lino/core/actors.py +70 -35
- lino/core/choicelists.py +2 -2
- lino/core/dashboard.py +2 -1
- lino/core/dbtables.py +15 -15
- lino/core/elems.py +8 -4
- lino/core/fields.py +12 -3
- lino/core/inject.py +9 -2
- lino/core/kernel.py +11 -11
- lino/core/layouts.py +1 -1
- lino/core/model.py +25 -36
- lino/core/plugin.py +1 -0
- lino/core/renderer.py +21 -21
- lino/core/requests.py +94 -83
- lino/core/site.py +9 -90
- lino/core/store.py +16 -19
- lino/core/tables.py +0 -17
- lino/core/utils.py +32 -2
- lino/core/views.py +2 -1
- lino/help_texts.py +10 -5
- lino/locale/bn/LC_MESSAGES/django.po +1210 -907
- lino/locale/de/LC_MESSAGES/django.po +1760 -1375
- lino/locale/django.pot +1136 -906
- lino/locale/es/LC_MESSAGES/django.po +1709 -1347
- lino/locale/et/LC_MESSAGES/django.po +1206 -906
- lino/locale/fr/LC_MESSAGES/django.mo +0 -0
- lino/locale/fr/LC_MESSAGES/django.po +1193 -923
- lino/locale/nl/LC_MESSAGES/django.po +1247 -942
- lino/locale/pt_BR/LC_MESSAGES/django.po +1190 -903
- lino/locale/zh_Hant/LC_MESSAGES/django.po +1190 -903
- lino/management/commands/show.py +2 -4
- lino/mixins/periods.py +15 -7
- lino/mixins/polymorphic.py +3 -3
- lino/mixins/ref.py +6 -3
- lino/modlib/checkdata/__init__.py +3 -3
- lino/modlib/comments/choicelists.py +1 -1
- lino/modlib/comments/fixtures/demo2.py +4 -1
- lino/modlib/comments/mixins.py +9 -10
- lino/modlib/comments/models.py +4 -4
- lino/modlib/comments/ui.py +5 -0
- lino/modlib/extjs/ext_renderer.py +1 -1
- lino/modlib/linod/consumers.py +2 -3
- lino/modlib/linod/mixins.py +3 -2
- lino/modlib/memo/mixins.py +11 -209
- lino/modlib/notify/mixins.py +33 -32
- lino/modlib/periods/__init__.py +12 -1
- lino/modlib/periods/fixtures/std.py +2 -1
- lino/modlib/periods/mixins.py +0 -1
- lino/modlib/periods/models.py +79 -75
- lino/modlib/printing/actions.py +2 -0
- lino/modlib/printing/choicelists.py +3 -3
- lino/modlib/publisher/ui.py +2 -2
- lino/modlib/search/models.py +17 -11
- lino/modlib/system/__init__.py +0 -2
- lino/modlib/system/choicelists.py +55 -1
- lino/modlib/system/fixtures/__init__.py +0 -0
- lino/modlib/system/fixtures/std.py +5 -0
- lino/modlib/system/models.py +4 -2
- lino/modlib/uploads/__init__.py +10 -1
- lino/modlib/uploads/choicelists.py +3 -3
- lino/modlib/uploads/mixins.py +30 -32
- lino/modlib/uploads/models.py +89 -56
- lino/modlib/uploads/ui.py +12 -6
- lino/modlib/uploads/utils.py +107 -0
- lino/modlib/users/models.py +2 -2
- lino/modlib/weasyprint/__init__.py +2 -0
- lino/utils/__init__.py +14 -9
- lino/utils/djangotest.py +2 -1
- lino/utils/html.py +32 -1
- lino/utils/media.py +2 -3
- lino/utils/soup.py +311 -0
- {lino-24.10.3.dist-info → lino-24.11.1.dist-info}/METADATA +1 -3
- {lino-24.10.3.dist-info → lino-24.11.1.dist-info}/RECORD +80 -76
- {lino-24.10.3.dist-info → lino-24.11.1.dist-info}/WHEEL +1 -1
- {lino-24.10.3.dist-info → lino-24.11.1.dist-info}/licenses/AUTHORS.rst +0 -0
- {lino-24.10.3.dist-info → lino-24.11.1.dist-info}/licenses/COPYING +0 -0
lino/core/model.py
CHANGED
@@ -20,6 +20,7 @@ from django.db.models.signals import pre_delete
|
|
20
20
|
from django.utils.text import format_lazy
|
21
21
|
|
22
22
|
from lino.utils.html import E, forcetext, tostring, join_elems
|
23
|
+
from lino.utils.soup import sanitize
|
23
24
|
|
24
25
|
from lino.core import fields
|
25
26
|
from lino.core import signals
|
@@ -36,10 +37,10 @@ from .workflows import ChangeStateAction
|
|
36
37
|
from .requests import ActionRequest, sliced_data_iterator
|
37
38
|
from .tables import AbstractTable
|
38
39
|
|
39
|
-
try:
|
40
|
-
|
41
|
-
except ImportError:
|
42
|
-
|
40
|
+
# try:
|
41
|
+
# import bleach
|
42
|
+
# except ImportError:
|
43
|
+
# bleach = None
|
43
44
|
|
44
45
|
|
45
46
|
class Model(models.Model, fields.TableRow):
|
@@ -308,8 +309,7 @@ class Model(models.Model, fields.TableRow):
|
|
308
309
|
if isinstance(f, RichTextField):
|
309
310
|
if f.editable and (
|
310
311
|
f.bleached is True
|
311
|
-
or f.bleached is None
|
312
|
-
and settings.SITE.textfield_bleached
|
312
|
+
or f.bleached is None and settings.SITE.textfield_bleached
|
313
313
|
):
|
314
314
|
bleached_fields.append(f)
|
315
315
|
cls._bleached_fields = tuple(bleached_fields)
|
@@ -428,27 +428,24 @@ class Model(models.Model, fields.TableRow):
|
|
428
428
|
setattr(self, f.name, new)
|
429
429
|
|
430
430
|
def fields_to_bleach(self):
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
if old != new:
|
450
|
-
logger.debug("Bleaching %s from %r to %r", f.name, old, new)
|
451
|
-
yield f, old, new
|
431
|
+
for f in self._bleached_fields:
|
432
|
+
old = getattr(self, f.name)
|
433
|
+
if old is None:
|
434
|
+
continue
|
435
|
+
new = sanitize(old)
|
436
|
+
# try:
|
437
|
+
# new = bleach.clean(
|
438
|
+
# new,
|
439
|
+
# tags=settings.SITE.bleach_allowed_tags,
|
440
|
+
# attributes=settings.SITE.bleach_allowed_attributes,
|
441
|
+
# strip=True,
|
442
|
+
# )
|
443
|
+
# except TypeError as e:
|
444
|
+
# logger.warning("Could not bleach %r : %s (%s)", old, e, self)
|
445
|
+
# continue
|
446
|
+
if old != new:
|
447
|
+
logger.debug("Bleaching %s from %r to %r", f.name, old, new)
|
448
|
+
yield f, old, new
|
452
449
|
|
453
450
|
updatable_panels = None
|
454
451
|
|
@@ -623,15 +620,6 @@ class Model(models.Model, fields.TableRow):
|
|
623
620
|
def name_column(self, ar):
|
624
621
|
return str(self)
|
625
622
|
|
626
|
-
# @fields.displayfield(_("Description"))
|
627
|
-
# def mobile_item(self, ar):
|
628
|
-
# if ar is None:
|
629
|
-
# return ''
|
630
|
-
# return E.div(*forcetext(self.get_mobile_list_item_elems(ar)))
|
631
|
-
#
|
632
|
-
# def get_mobile_list_item_elems(self, ar):
|
633
|
-
# return [self.as_summary_item(ar)]
|
634
|
-
|
635
623
|
@fields.htmlbox()
|
636
624
|
def navigation_panel(self, ar):
|
637
625
|
# if not isinstance(ar, ActionRequest):
|
@@ -934,6 +922,7 @@ LINO_MODEL_ATTRIBS = (
|
|
934
922
|
"workflow_buttons",
|
935
923
|
"delete_instance",
|
936
924
|
"setup_parameters",
|
925
|
+
"param_defaults",
|
937
926
|
"add_param_filter",
|
938
927
|
"save_new_instance",
|
939
928
|
"save_watched_instance",
|
lino/core/plugin.py
CHANGED
lino/core/renderer.py
CHANGED
@@ -197,7 +197,7 @@ class HtmlRenderer(Renderer):
|
|
197
197
|
import rstgen
|
198
198
|
|
199
199
|
if display_mode == constants.DISPLAY_MODE_CARDS:
|
200
|
-
layout = ar.actor.card_layout or ar.actor.list_layout
|
200
|
+
layout = ar.actor.card_layout # or ar.actor.list_layout
|
201
201
|
lh = layout.get_layout_handle()
|
202
202
|
else:
|
203
203
|
lh = ar.bound_action.get_layout_handel()
|
@@ -262,7 +262,6 @@ class HtmlRenderer(Renderer):
|
|
262
262
|
ar,
|
263
263
|
nosummary=False,
|
264
264
|
stripped=True,
|
265
|
-
show_urls=False,
|
266
265
|
header_level=None,
|
267
266
|
display_mode=None,
|
268
267
|
**kwargs
|
@@ -766,28 +765,27 @@ class TextRenderer(HtmlRenderer):
|
|
766
765
|
"""
|
767
766
|
|
768
767
|
user = None
|
769
|
-
show_urls = False
|
770
768
|
link_url = mark_safe("…") # U+2026 Horizontal Ellipsis
|
771
769
|
|
772
770
|
def __init__(self, *args, **kw):
|
773
|
-
|
771
|
+
super().__init__(*args, **kw)
|
774
772
|
self.user = None
|
775
773
|
|
776
774
|
def get_request_url(self, ar, *args, **kw):
|
777
|
-
if
|
775
|
+
if ar.show_urls:
|
778
776
|
return super().get_request_url(ar, *args, **kw)
|
779
777
|
return self.link_url
|
780
778
|
# return None
|
781
779
|
|
782
780
|
def obj2url(self, ar, obj):
|
783
|
-
if
|
781
|
+
if ar.show_urls:
|
784
782
|
return super().obj2url(ar, obj)
|
785
783
|
return self.link_url
|
786
784
|
# return None
|
787
785
|
|
788
|
-
def get_detail_url(self, *args, **kwargs):
|
789
|
-
if
|
790
|
-
return super().get_detail_url(*args, **kwargs)
|
786
|
+
def get_detail_url(self, ar, *args, **kwargs):
|
787
|
+
if ar.show_urls:
|
788
|
+
return super().get_detail_url(ar, *args, **kwargs)
|
791
789
|
return self.link_url
|
792
790
|
|
793
791
|
# # return str(actor)+"/"+str(pk)
|
@@ -815,7 +813,7 @@ class TextRenderer(HtmlRenderer):
|
|
815
813
|
header_links=None,
|
816
814
|
nosummary=False,
|
817
815
|
stripped=True,
|
818
|
-
|
816
|
+
show_links=False, # added 20241031
|
819
817
|
display_mode=None,
|
820
818
|
**kwargs
|
821
819
|
):
|
@@ -823,9 +821,9 @@ class TextRenderer(HtmlRenderer):
|
|
823
821
|
Render the given table request as reStructuredText to stdout. See
|
824
822
|
:meth:`ar.show <lino.core.request.BaseRequest.show>`.
|
825
823
|
"""
|
826
|
-
self.show_urls = show_urls
|
827
824
|
if display_mode is None:
|
828
825
|
display_mode = ar.actor.get_display_mode()
|
826
|
+
# display_mode = constants.DISPLAY_MODE_GRID
|
829
827
|
if nosummary and display_mode == constants.DISPLAY_MODE_SUMMARY:
|
830
828
|
display_mode = constants.DISPLAY_MODE_GRID
|
831
829
|
else:
|
@@ -874,6 +872,16 @@ class TextRenderer(HtmlRenderer):
|
|
874
872
|
yield rstgen.ul(items).strip()
|
875
873
|
return
|
876
874
|
|
875
|
+
# At this point, display_mode is one of story, grid or html.
|
876
|
+
|
877
|
+
if header_level is not None:
|
878
|
+
h = rstgen.header(header_level, ar.get_title())
|
879
|
+
if stripped:
|
880
|
+
h = h.strip()
|
881
|
+
yield h
|
882
|
+
# s = h + "\n" + s
|
883
|
+
# s = tostring(E.h2(ar.get_title())) + s
|
884
|
+
|
877
885
|
fields, headers, widths = ar.get_field_info(column_names)
|
878
886
|
|
879
887
|
# if str(ar.actor) == "working.WorkedHours":
|
@@ -884,7 +892,7 @@ class TextRenderer(HtmlRenderer):
|
|
884
892
|
recno = 0
|
885
893
|
for row in ar.sliced_data_iterator:
|
886
894
|
recno += 1
|
887
|
-
if show_urls:
|
895
|
+
if ar.show_urls or show_links:
|
888
896
|
rows.append([to_rst(x) for x in ar.row2html(recno, fields, row, sums)])
|
889
897
|
else:
|
890
898
|
# only for debugging:
|
@@ -898,14 +906,6 @@ class TextRenderer(HtmlRenderer):
|
|
898
906
|
# return a SafeString
|
899
907
|
rows.append([text2rst(x) for x in ar.row2text(fields, row, sums)])
|
900
908
|
|
901
|
-
if header_level is not None:
|
902
|
-
h = rstgen.header(header_level, ar.get_title())
|
903
|
-
if stripped:
|
904
|
-
h = h.strip()
|
905
|
-
yield h
|
906
|
-
# s = h + "\n" + s
|
907
|
-
# s = tostring(E.h2(ar.get_title())) + s
|
908
|
-
|
909
909
|
# if str(ar.actor) == "working.WorkedHours":
|
910
910
|
# yield "20200306 rows {}".format(rows)
|
911
911
|
if len(rows) == 0:
|
@@ -1264,7 +1264,7 @@ class JsCacheRenderer(JsRenderer):
|
|
1264
1264
|
# if res.parameters is not None:
|
1265
1265
|
add(res, self.param_panels, res.params_layout, "%s.ParamsPanel" % res)
|
1266
1266
|
add(res, self.other_panels, res.card_layout, "%s.CardsPanel" % res)
|
1267
|
-
add(res, self.other_panels, res.list_layout, "%s.ItemsPanel" % res)
|
1267
|
+
# add(res, self.other_panels, res.list_layout, "%s.ItemsPanel" % res)
|
1268
1268
|
|
1269
1269
|
for ba in res.get_actions():
|
1270
1270
|
if ba.action.parameters:
|
lino/core/requests.py
CHANGED
@@ -35,6 +35,7 @@ from asgiref.sync import sync_to_async
|
|
35
35
|
|
36
36
|
from lino.utils.html import E, tostring, iselement
|
37
37
|
from lino.utils import AttrDict
|
38
|
+
from lino.utils import capture_output
|
38
39
|
from lino.utils import MissingRow
|
39
40
|
from lino.utils.html import html2text
|
40
41
|
from lino.core import constants
|
@@ -237,8 +238,8 @@ class ValidActionResponses(object):
|
|
237
238
|
|
238
239
|
|
239
240
|
inheritable_attrs = frozenset(
|
240
|
-
"user subst_user renderer requesting_panel master_instance
|
241
|
-
)
|
241
|
+
["user", "subst_user", "renderer", "requesting_panel", "master_instance",
|
242
|
+
"logger", "show_urls"] )
|
242
243
|
|
243
244
|
|
244
245
|
def bool2text(x):
|
@@ -311,9 +312,16 @@ class BaseRequest:
|
|
311
312
|
no_data_text = _("No data to display")
|
312
313
|
is_on_main_actor = True
|
313
314
|
permalink_uris = False
|
315
|
+
show_urls = True
|
316
|
+
master = None
|
314
317
|
master_instance = None
|
315
318
|
request = None
|
316
319
|
selected_rows = []
|
320
|
+
order_by = None
|
321
|
+
filter = None
|
322
|
+
gridfilters = None,
|
323
|
+
quick_search = None
|
324
|
+
extra = None
|
317
325
|
content_type = "application/json"
|
318
326
|
requesting_panel = None
|
319
327
|
xcallback_answers = {}
|
@@ -326,12 +334,13 @@ class BaseRequest:
|
|
326
334
|
self,
|
327
335
|
request=None,
|
328
336
|
parent=None,
|
329
|
-
hash_router=None,
|
330
337
|
is_on_main_actor=True,
|
331
338
|
permalink_uris=None,
|
332
339
|
**kw
|
333
340
|
):
|
334
341
|
self.response = dict()
|
342
|
+
# if str(kw.get('actor', None)) == "cal.EntriesByController":
|
343
|
+
# if kw.get('actor', None):
|
335
344
|
if request is not None:
|
336
345
|
assert parent is None
|
337
346
|
self.request = request
|
@@ -339,8 +348,6 @@ class BaseRequest:
|
|
339
348
|
kw = self.parse_req(request, self.rqdata, **kw)
|
340
349
|
if permalink_uris is None:
|
341
350
|
permalink_uris = False # todo: which default value?
|
342
|
-
# if hash_router is None:
|
343
|
-
# hash_router = False
|
344
351
|
elif parent is not None:
|
345
352
|
# if parent.actor is None:
|
346
353
|
# 20190926 we want to have javascript extjs links in dasboard
|
@@ -369,15 +376,16 @@ class BaseRequest:
|
|
369
376
|
# is_on_main_actor = False
|
370
377
|
if permalink_uris is None:
|
371
378
|
permalink_uris = parent.permalink_uris
|
372
|
-
|
373
|
-
|
379
|
+
# else:
|
380
|
+
# kw.setdefault("show_urls", False)
|
374
381
|
|
375
382
|
self.is_on_main_actor = is_on_main_actor
|
376
383
|
self.permalink_uris = permalink_uris
|
377
|
-
# self.hash_router = hash_router
|
378
384
|
|
379
385
|
self.setup(**kw)
|
380
386
|
|
387
|
+
# print("20241101", self.__class__.__name__, self.show_urls)
|
388
|
+
|
381
389
|
if self.master is not None and settings.SITE.strict_master_check:
|
382
390
|
if self.master_instance is None:
|
383
391
|
raise exceptions.BadRequest(
|
@@ -407,10 +415,21 @@ class BaseRequest:
|
|
407
415
|
renderer=None,
|
408
416
|
xcallback_answers=None,
|
409
417
|
known_values={},
|
418
|
+
show_urls=None,
|
419
|
+
quick_search=None,
|
420
|
+
order_by=None,
|
421
|
+
filter=None,
|
422
|
+
gridfilters=None,
|
423
|
+
extra=None,
|
410
424
|
):
|
411
425
|
if logger is not None:
|
412
426
|
self.logger = logger
|
413
427
|
self.requesting_panel = requesting_panel
|
428
|
+
self.quick_search = quick_search
|
429
|
+
self.order_by = order_by
|
430
|
+
self.filter = filter
|
431
|
+
self.gridfilters = gridfilters
|
432
|
+
self.extra = extra
|
414
433
|
if user is None:
|
415
434
|
self.user = settings.SITE.get_anonymous_user()
|
416
435
|
else:
|
@@ -418,27 +437,31 @@ class BaseRequest:
|
|
418
437
|
self.current_project = current_project
|
419
438
|
if renderer is None:
|
420
439
|
renderer = settings.SITE.kernel.text_renderer
|
440
|
+
# renderer = settings.SITE.kernel.default_renderer
|
421
441
|
self.renderer = renderer
|
442
|
+
if show_urls is not None:
|
443
|
+
self.show_urls = show_urls
|
422
444
|
self.subst_user = subst_user
|
423
445
|
if xcallback_answers is not None:
|
424
446
|
self.xcallback_answers = xcallback_answers
|
425
447
|
|
426
|
-
if
|
427
|
-
master
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
master_instance
|
439
|
-
self.
|
440
|
-
|
441
|
-
|
448
|
+
if self.actor is not None:
|
449
|
+
if master is None:
|
450
|
+
master = self.actor.master
|
451
|
+
if master_type is not None and ContentType is not None:
|
452
|
+
try:
|
453
|
+
master = ContentType.objects.get(pk=master_type).model_class()
|
454
|
+
except ContentType.DoesNotExist:
|
455
|
+
raise exceptions.BadRequest("Invalid master_type {}".format(master_type)) from None
|
456
|
+
self.master = master
|
457
|
+
|
458
|
+
if self.master is not None and self.master_instance is None:
|
459
|
+
# master_instance might have been inherited from parent
|
460
|
+
if master_instance is None:
|
461
|
+
master_instance = self.get_master_instance(
|
462
|
+
self.master, master_key, master_type
|
463
|
+
)
|
464
|
+
self.master_instance = self.actor.cast_master_instance(master_instance)
|
442
465
|
|
443
466
|
self.row_meta = dict(meta=True)
|
444
467
|
|
@@ -524,36 +547,11 @@ class BaseRequest:
|
|
524
547
|
master_key=rqdata.get(constants.URL_PARAM_MASTER_PK, None),
|
525
548
|
)
|
526
549
|
|
527
|
-
# if settings.SITE.use_filterRow:
|
528
|
-
# exclude = dict()
|
529
|
-
# for f in self.ah.store.fields:
|
530
|
-
# if f.field:
|
531
|
-
# filterOption = rqdata.get(
|
532
|
-
# 'filter[%s_filterOption]' % f.field.name)
|
533
|
-
# if filterOption == 'empty':
|
534
|
-
# kw[f.field.name + "__isnull"] = True
|
535
|
-
# elif filterOption == 'notempty':
|
536
|
-
# kw[f.field.name + "__isnull"] = False
|
537
|
-
# else:
|
538
|
-
# filterValue = rqdata.get('filter[%s]' % f.field.name)
|
539
|
-
# if filterValue:
|
540
|
-
# if not filterOption:
|
541
|
-
# filterOption = 'contains'
|
542
|
-
# if filterOption == 'contains':
|
543
|
-
# kw[f.field.name + "__icontains"] = filterValue
|
544
|
-
# elif filterOption == 'doesnotcontain':
|
545
|
-
# exclude[f.field.name +
|
546
|
-
# "__icontains"] = filterValue
|
547
|
-
# else:
|
548
|
-
# print("unknown filterOption %r" % filterOption)
|
549
|
-
# if len(exclude):
|
550
|
-
# kw.update(exclude=exclude)
|
551
|
-
|
552
550
|
if settings.SITE.use_gridfilters:
|
553
|
-
|
554
|
-
if
|
555
|
-
|
556
|
-
kw["gridfilters"] = [constants.dict2kw(flt) for flt in
|
551
|
+
v = rqdata.get(constants.URL_PARAM_GRIDFILTER, None)
|
552
|
+
if v is not None:
|
553
|
+
v = json.loads(v)
|
554
|
+
kw["gridfilters"] = [constants.dict2kw(flt) for flt in v]
|
557
555
|
|
558
556
|
# kw = ActionRequest.parse_req(self, request, rqdata, **kw)
|
559
557
|
if settings.SITE.user_model:
|
@@ -954,6 +952,8 @@ class BaseRequest:
|
|
954
952
|
)
|
955
953
|
return
|
956
954
|
|
955
|
+
self.logger.info("Send email '%s' from %s to %s", subject, sender, recipients)
|
956
|
+
|
957
957
|
recipients = [a for a in recipients if "@example.com" not in a]
|
958
958
|
if not len(recipients):
|
959
959
|
self.logger.info(
|
@@ -962,8 +962,6 @@ class BaseRequest:
|
|
962
962
|
# self.logger.info("Email body would have been %s", body)
|
963
963
|
return
|
964
964
|
|
965
|
-
self.logger.info("Send email '%s' from %s to %s", subject, sender, recipients)
|
966
|
-
|
967
965
|
kw = {}
|
968
966
|
if body.startswith("<"):
|
969
967
|
kw["html_message"] = body
|
@@ -1166,6 +1164,9 @@ class BaseRequest:
|
|
1166
1164
|
def story2rst(self, story, *args, **kwargs):
|
1167
1165
|
return self.renderer.show_story(self, story, *args, **kwargs)
|
1168
1166
|
|
1167
|
+
def shows(self, *args, **kwargs):
|
1168
|
+
return capture_output(self.show, *args, **kwargs)
|
1169
|
+
|
1169
1170
|
def show(
|
1170
1171
|
self,
|
1171
1172
|
spec=None,
|
@@ -1175,6 +1176,7 @@ class BaseRequest:
|
|
1175
1176
|
language=None,
|
1176
1177
|
nosummary=False,
|
1177
1178
|
stripped=True,
|
1179
|
+
show_links=False,
|
1178
1180
|
show_urls=False,
|
1179
1181
|
max_width=None,
|
1180
1182
|
header_links=False,
|
@@ -1194,10 +1196,14 @@ class BaseRequest:
|
|
1194
1196
|
|
1195
1197
|
:column_names: overrides default list of columns
|
1196
1198
|
|
1197
|
-
:
|
1199
|
+
:show_links: show links and other html formatting. Used
|
1198
1200
|
.e.g. in :ref:`avanti.specs.roles` where we want
|
1199
1201
|
to show whether cells are clickable or not.
|
1200
1202
|
|
1203
|
+
:show_urls: show the real URLs. URLs in doctests are usually replaced by
|
1204
|
+
"…" to increase readability. If this is explicitly set to True, Lino
|
1205
|
+
prints the full URLs.
|
1206
|
+
|
1201
1207
|
:nosummary: if it is a table with :attr:`display_mode
|
1202
1208
|
<lino.core.tables.AbstractTable.display_mode>`
|
1203
1209
|
set to ``((None, DISPLAY_MODE_SUMMARY), )``,
|
@@ -1253,6 +1259,8 @@ class BaseRequest:
|
|
1253
1259
|
ar = self.spawn(spec, **kwargs)
|
1254
1260
|
# return self.renderer.show_story(spec, **kwargs)
|
1255
1261
|
|
1262
|
+
ar.show_urls = show_urls
|
1263
|
+
|
1256
1264
|
def doit():
|
1257
1265
|
# print 20160530, ar.renderer
|
1258
1266
|
if issubclass(ar.actor, Report):
|
@@ -1275,7 +1283,7 @@ class BaseRequest:
|
|
1275
1283
|
nosummary=nosummary,
|
1276
1284
|
stripped=stripped,
|
1277
1285
|
max_width=max_width,
|
1278
|
-
|
1286
|
+
show_links=show_links,
|
1279
1287
|
display_mode=display_mode,
|
1280
1288
|
)
|
1281
1289
|
elif isinstance(ar.bound_action.action, actions.ShowDetail):
|
@@ -1630,9 +1638,9 @@ class ActionRequest(BaseRequest):
|
|
1630
1638
|
Holds information about an individual web request and provides
|
1631
1639
|
methods like
|
1632
1640
|
|
1633
|
-
- :meth:`get_user <lino.core.
|
1634
|
-
- :meth:`confirm <lino.core.
|
1635
|
-
- :meth:`spawn <lino.core.
|
1641
|
+
- :meth:`get_user <lino.core.requests.BaseRequest.get_user>`
|
1642
|
+
- :meth:`confirm <lino.core.requests.BaseRequest.confirm>`
|
1643
|
+
- :meth:`spawn <lino.core.requests.BaseRequest.spawn>`
|
1636
1644
|
|
1637
1645
|
An `ActionRequest` is also a :class:`BaseRequest` and inherits its
|
1638
1646
|
methods.
|
@@ -1648,11 +1656,8 @@ class ActionRequest(BaseRequest):
|
|
1648
1656
|
renderer = None
|
1649
1657
|
offset = None
|
1650
1658
|
limit = None
|
1651
|
-
order_by = None
|
1652
1659
|
master = None
|
1653
|
-
extra = None
|
1654
1660
|
title = None
|
1655
|
-
filter = None
|
1656
1661
|
limit = None
|
1657
1662
|
offset = None
|
1658
1663
|
|
@@ -1688,25 +1693,14 @@ class ActionRequest(BaseRequest):
|
|
1688
1693
|
known_values=None,
|
1689
1694
|
param_values=None,
|
1690
1695
|
action_param_values={},
|
1691
|
-
quick_search=None,
|
1692
|
-
order_by=None,
|
1693
1696
|
offset=None,
|
1694
1697
|
limit=None,
|
1695
1698
|
title=None,
|
1696
|
-
filter=None,
|
1697
|
-
gridfilters=None,
|
1698
1699
|
exclude=None,
|
1699
1700
|
selected_pks=None,
|
1700
1701
|
selected_rows=None,
|
1701
|
-
extra=None,
|
1702
1702
|
**kw
|
1703
1703
|
):
|
1704
|
-
self.quick_search = quick_search
|
1705
|
-
self.order_by = order_by
|
1706
|
-
self.filter = filter
|
1707
|
-
self.gridfilters = gridfilters
|
1708
|
-
self.extra = extra
|
1709
|
-
|
1710
1704
|
if title is not None:
|
1711
1705
|
self.title = title
|
1712
1706
|
if offset is not None:
|
@@ -1845,7 +1839,7 @@ class ActionRequest(BaseRequest):
|
|
1845
1839
|
return "{0} {1}".format(self.__class__.__name__, self.bound_action)
|
1846
1840
|
|
1847
1841
|
def gen_insert_button(
|
1848
|
-
self, target, button_attrs=dict(style="float: right;"), **values
|
1842
|
+
self, target=None, button_attrs=dict(style="float: right;"), **values
|
1849
1843
|
):
|
1850
1844
|
"""
|
1851
1845
|
Generate an insert button using a cached insertable object.
|
@@ -1860,13 +1854,26 @@ class ActionRequest(BaseRequest):
|
|
1860
1854
|
The difference is that gen_insert_button is more efficient when you do
|
1861
1855
|
this more than once during a single request.
|
1862
1856
|
|
1863
|
-
`target` is the actor into which we want to insert an object.
|
1864
|
-
`
|
1857
|
+
`target` is the actor into which we want to insert an object. When this is `None`, Lino uses :attr:`self.actor`.
|
1858
|
+
`button_attrs` if given, are forwarded to :meth:`ar2button`.
|
1865
1859
|
`values` is a dict of extra default values to apply to the insertable object.
|
1866
1860
|
|
1861
|
+
The `values` must be atomized by the caller, which is especially
|
1862
|
+
important when you want to set a :term:`foreign key` field. So instead
|
1863
|
+
of saying::
|
1864
|
+
|
1865
|
+
gen_insert_button(None, user=u)
|
1866
|
+
|
1867
|
+
you must say::
|
1868
|
+
|
1869
|
+
gen_insert_button(None, user=u.pk, userHidden=str(u))
|
1870
|
+
|
1867
1871
|
First usage example is in :mod:`lino_xl.lib.calview`.
|
1872
|
+
Second usage example is :class:`lino_prima.lib.prima.PupilsAndProjects`.
|
1868
1873
|
|
1869
1874
|
"""
|
1875
|
+
if target is None:
|
1876
|
+
target = self.actor
|
1870
1877
|
if self._insert_sar is None:
|
1871
1878
|
self._insert_sar = target.insert_action.request_from(self)
|
1872
1879
|
else:
|
@@ -1877,7 +1884,7 @@ class ActionRequest(BaseRequest):
|
|
1877
1884
|
# obj = st['data_record']
|
1878
1885
|
# for k, v in values.items():
|
1879
1886
|
# setattr(obj, k, v)
|
1880
|
-
# print(
|
1887
|
+
# print(20241018, st['data_record'])
|
1881
1888
|
return self._insert_sar.ar2button(**button_attrs)
|
1882
1889
|
|
1883
1890
|
def run(self, *args, **kw):
|
@@ -2030,7 +2037,10 @@ class ActionRequest(BaseRequest):
|
|
2030
2037
|
if self.create_kw:
|
2031
2038
|
kw.update(self.create_kw)
|
2032
2039
|
if self.known_values:
|
2033
|
-
kw.update(self.known_values)
|
2040
|
+
# kw.update(self.known_values)
|
2041
|
+
for k, v in self.known_values.items():
|
2042
|
+
if not "__" in k:
|
2043
|
+
kw[k] = v
|
2034
2044
|
obj = self.actor.create_instance(self, **kw)
|
2035
2045
|
return obj
|
2036
2046
|
|
@@ -2143,8 +2153,8 @@ class ActionRequest(BaseRequest):
|
|
2143
2153
|
# actor = self.actor
|
2144
2154
|
# return super(ActorRequest, self).spawn(actor, **kw)
|
2145
2155
|
|
2146
|
-
def row_as_summary(self, obj,
|
2147
|
-
return self.actor.row_as_summary(self, obj,
|
2156
|
+
def row_as_summary(self, obj, text=None, **kwargs):
|
2157
|
+
return self.actor.row_as_summary(self, obj, text, **kwargs)
|
2148
2158
|
|
2149
2159
|
def row_as_page(self, row, **kwargs):
|
2150
2160
|
return self.actor.row_as_page(self, row, **kwargs)
|
@@ -2242,6 +2252,7 @@ class ActionRequest(BaseRequest):
|
|
2242
2252
|
column_names=None,
|
2243
2253
|
header_links=False,
|
2244
2254
|
max_width=None, # ignored
|
2255
|
+
show_links=None, # ignored
|
2245
2256
|
hide_sums=None,
|
2246
2257
|
):
|
2247
2258
|
"""
|
@@ -2431,12 +2442,12 @@ class ActionRequest(BaseRequest):
|
|
2431
2442
|
if v is None:
|
2432
2443
|
td = E.td(**cellattrs)
|
2433
2444
|
else:
|
2445
|
+
td = col.value2html(self, v, **cellattrs)
|
2446
|
+
# print("20240506 {} {}".format(col.__class__, tostring(td)))
|
2434
2447
|
nv = col.value2num(v)
|
2435
2448
|
if nv != 0:
|
2436
2449
|
sums[i] += nv
|
2437
2450
|
has_numeric_value = True
|
2438
|
-
td = col.value2html(self, v, **cellattrs)
|
2439
|
-
# print("20240506 {} {}".format(col.__class__, tostring(td)))
|
2440
2451
|
col.apply_cell_format(td)
|
2441
2452
|
self.actor.apply_cell_format(self, row, col, recno, td)
|
2442
2453
|
cells.append(td)
|