lino 25.8.3__py3-none-any.whl → 25.9.0__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/dd.py +0 -1
- lino/core/__init__.py +0 -1
- lino/core/actions.py +1 -1
- lino/core/actors.py +8 -0
- lino/core/elems.py +1 -1
- lino/core/fields.py +4 -1
- lino/core/model.py +2 -11
- lino/core/requests.py +8 -7
- lino/core/site.py +0 -79
- lino/core/user_types.py +1 -10
- lino/help_texts.py +1 -5
- lino/management/commands/initdb.py +0 -3
- lino/modlib/__init__.py +0 -1
- lino/modlib/bootstrap5/README.txt +1 -1
- lino/modlib/bootstrap5/__init__.py +34 -38
- lino/modlib/bootstrap5/config/bootstrap5/base.html +4 -0
- lino/modlib/bootstrap5/models.py +23 -23
- lino/modlib/bootstrap5/views.py +2 -107
- lino/modlib/checkdata/choicelists.py +1 -1
- lino/modlib/comments/fixtures/demo2.py +1 -0
- lino/modlib/comments/ui.py +7 -7
- lino/modlib/extjs/__init__.py +2 -4
- lino/modlib/extjs/config/extjs/index.html +1 -1
- lino/modlib/extjs/ext_renderer.py +1 -7
- lino/modlib/extjs/views.py +2 -0
- lino/modlib/help/models.py +1 -12
- lino/modlib/linod/mixins.py +3 -2
- lino/modlib/memo/__init__.py +10 -9
- lino/modlib/memo/mixins.py +38 -21
- lino/modlib/memo/models.py +10 -7
- lino/modlib/memo/parser.py +3 -1
- lino/modlib/notify/models.py +6 -9
- lino/modlib/publisher/__init__.py +12 -7
- lino/modlib/publisher/choicelists.py +9 -64
- lino/modlib/publisher/config/publisher/page.pub.html +73 -7
- lino/modlib/publisher/fixtures/std.py +14 -1
- lino/modlib/publisher/mixins.py +41 -12
- lino/modlib/publisher/models.py +74 -75
- lino/modlib/publisher/renderer.py +28 -12
- lino/modlib/publisher/ui.py +35 -35
- lino/modlib/publisher/views.py +59 -24
- lino/modlib/system/models.py +3 -2
- lino/modlib/uploads/__init__.py +1 -0
- lino/modlib/uploads/mixins.py +2 -2
- lino/modlib/uploads/models.py +55 -21
- lino/modlib/uploads/ui.py +1 -0
- lino/modlib/uploads/utils.py +2 -2
- lino/modlib/users/__init__.py +2 -3
- lino/modlib/users/actions.py +12 -17
- lino/modlib/users/models.py +37 -36
- lino/modlib/weasyprint/choicelists.py +6 -0
- lino/utils/diag.py +5 -3
- lino/utils/html.py +103 -0
- lino/utils/mldbc/mixins.py +2 -2
- lino/utils/soup.py +16 -8
- {lino-25.8.3.dist-info → lino-25.9.0.dist-info}/METADATA +1 -1
- {lino-25.8.3.dist-info → lino-25.9.0.dist-info}/RECORD +61 -61
- {lino-25.8.3.dist-info → lino-25.9.0.dist-info}/WHEEL +0 -0
- {lino-25.8.3.dist-info → lino-25.9.0.dist-info}/licenses/AUTHORS.rst +0 -0
- {lino-25.8.3.dist-info → lino-25.9.0.dist-info}/licenses/COPYING +0 -0
lino/modlib/comments/ui.py
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
# Copyright 2013-2023 Rumma & Ko Ltd
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
|
5
|
-
from lino.modlib.publisher.choicelists import PageFillers
|
6
5
|
from django.contrib.humanize.templatetags.humanize import naturaltime
|
7
6
|
from django.contrib.contenttypes.models import ContentType
|
8
7
|
from django.db import models
|
@@ -66,18 +65,22 @@ class CommentDetail(dd.DetailLayout):
|
|
66
65
|
|
67
66
|
more = dd.Panel(
|
68
67
|
"""
|
69
|
-
|
68
|
+
more1 more2
|
70
69
|
""",
|
71
70
|
label=_("More"),
|
72
71
|
)
|
73
72
|
|
74
|
-
|
73
|
+
more1 = """
|
75
74
|
id user group
|
76
75
|
owner_type owner_id
|
77
|
-
created modified
|
78
76
|
comment_type
|
79
77
|
ReactionsByComment
|
80
78
|
"""
|
79
|
+
more2 = """
|
80
|
+
created modified
|
81
|
+
memo.MentionsByTarget
|
82
|
+
memo.MentionsByOwner
|
83
|
+
"""
|
81
84
|
|
82
85
|
|
83
86
|
class Comments(dd.Table):
|
@@ -314,6 +317,3 @@ class Reactions(dd.Table):
|
|
314
317
|
class ReactionsByComment(Reactions):
|
315
318
|
master_key = "comment"
|
316
319
|
default_display_modes = {None: constants.DISPLAY_MODE_SUMMARY}
|
317
|
-
|
318
|
-
|
319
|
-
PageFillers.add_item(RecentComments)
|
lino/modlib/extjs/__init__.py
CHANGED
@@ -28,7 +28,8 @@ from django.utils.translation import gettext_lazy as _
|
|
28
28
|
class Plugin(Plugin):
|
29
29
|
"""Extends :class:`lino.core.plugin.Plugin`."""
|
30
30
|
|
31
|
-
needs_plugins = ["lino.modlib.bootstrap5"]
|
31
|
+
# needs_plugins = ["lino.modlib.bootstrap5"]
|
32
|
+
needs_plugins = ["lino.modlib.jinja"]
|
32
33
|
|
33
34
|
enter_submits_form = False
|
34
35
|
"""Whether the :kbd:`ENTER` key (or :kbd:`CTRL+ENTER` when in a
|
@@ -216,9 +217,6 @@ class Plugin(Plugin):
|
|
216
217
|
from django.urls import re_path as url
|
217
218
|
from . import views
|
218
219
|
|
219
|
-
# if self.site.developer_site_cache:
|
220
|
-
# self.renderer.build_site_cache()
|
221
|
-
|
222
220
|
rx = "^"
|
223
221
|
|
224
222
|
urlpatterns = [
|
@@ -130,7 +130,7 @@
|
|
130
130
|
{{ ln }}{% endfor -%}
|
131
131
|
{%- endfor -%}
|
132
132
|
{# Main Lino js code #}
|
133
|
-
{{ javascript(site.
|
133
|
+
{{ javascript(site.build_media_url(*ext_renderer.lino_js_parts())) }}
|
134
134
|
{# javascript(site.buildurl('linolib.js')) #}
|
135
135
|
{# ###### OnReady JS code ###### #}
|
136
136
|
<script type="text/javascript">
|
@@ -420,10 +420,7 @@ class ExtRenderer(JsCacheRenderer):
|
|
420
420
|
user = request.subst_user
|
421
421
|
|
422
422
|
def getit():
|
423
|
-
if
|
424
|
-
settings.SITE.developer_site_cache
|
425
|
-
and not settings.SITE.never_build_site_cache
|
426
|
-
):
|
423
|
+
if settings.SITE.developer_site_cache:
|
427
424
|
self.build_js_cache(False)
|
428
425
|
|
429
426
|
# Render template
|
@@ -1478,9 +1475,6 @@ class ExtRenderer(JsCacheRenderer):
|
|
1478
1475
|
)
|
1479
1476
|
yield "LANGUAGE_CHOICES = %s;" % py2js(list(settings.SITE.LANGUAGE_CHOICES))
|
1480
1477
|
yield "MEDIA_URL = %s;" % py2js(settings.SITE.build_media_url())
|
1481
|
-
# if settings.SITE.never_build_site_cache:
|
1482
|
-
# yield "GEN_TIMESTAMP = '%s';" % settings.SITE.kernel.lino_version
|
1483
|
-
# else:
|
1484
1478
|
yield "GEN_TIMESTAMP = %s;" % py2js(settings.SITE.kernel.lino_version)
|
1485
1479
|
|
1486
1480
|
return "\n".join(fn())
|
lino/modlib/extjs/views.py
CHANGED
@@ -597,11 +597,13 @@ class ApiList(View):
|
|
597
597
|
|
598
598
|
if True:
|
599
599
|
kw.update(title=str(ar.get_title()))
|
600
|
+
# kw.update(title=str(ar.get_breadcrumbs()))
|
600
601
|
else:
|
601
602
|
# 20190704 work in progress.
|
602
603
|
# add open_in_own_window button after title of slave panel
|
603
604
|
kw.update(
|
604
605
|
title=str(ar.get_title())
|
606
|
+
# title=str(ar.get_breadcrumbs())
|
605
607
|
+ " "
|
606
608
|
+ tostring(ar.open_in_own_window_button())
|
607
609
|
)
|
lino/modlib/help/models.py
CHANGED
@@ -28,17 +28,6 @@ class OpenHelpWindow(dd.Action):
|
|
28
28
|
help_text = _("Open Help Window")
|
29
29
|
show_in_plain = True
|
30
30
|
|
31
|
-
# def js_handler(self, actor):
|
32
|
-
# parts = ['cache', 'help']
|
33
|
-
# if get_language() != settings.SITE.DEFAULT_LANGUAGE.django_code:
|
34
|
-
# parts.append(get_language())
|
35
|
-
# parts.append(str(actor) + ".html")
|
36
|
-
# url = settings.SITE.build_site_cache_url(*parts)
|
37
|
-
# # return "let _ = window.open('%s');" % url
|
38
|
-
# # return "() => window.open('%s')" % url
|
39
|
-
# return "function (){window.open('%s')}" % url
|
40
|
-
# # return "window.open('%s')" % url
|
41
|
-
|
42
31
|
def run_from_ui(self, ar, **kwargs):
|
43
32
|
# print("20210612")
|
44
33
|
parts = ["cache", "help"]
|
@@ -46,7 +35,7 @@ class OpenHelpWindow(dd.Action):
|
|
46
35
|
parts.append(get_language())
|
47
36
|
parts.append(str(ar.actor) + ".html")
|
48
37
|
# parts.append("index.html")
|
49
|
-
url = settings.SITE.
|
38
|
+
url = settings.SITE.build_media_url(*parts)
|
50
39
|
ar.set_response(success=True)
|
51
40
|
ar.success(open_url=url)
|
52
41
|
|
lino/modlib/linod/mixins.py
CHANGED
@@ -179,10 +179,11 @@ class Runnable(Sequenced, RecurrenceSet):
|
|
179
179
|
await ar.adebug("Terminated %s with warning %s", self, str(e))
|
180
180
|
self.message = out.getvalue()
|
181
181
|
except Exception as e:
|
182
|
+
tb = "".join(traceback.format_exception(e))
|
182
183
|
self.message = out.getvalue()
|
183
|
-
self.message += "\n" +
|
184
|
+
self.message += "\n" + tb
|
184
185
|
self.disabled = True
|
185
|
-
await ar.awarning("Disabled %s after exception
|
186
|
+
await ar.awarning("Disabled %s after exception:\n%s", self, tb)
|
186
187
|
# ar.warning("Disabled %s after exception %s", astr(self), e)
|
187
188
|
# now = await sync_to_async(dd.now)()
|
188
189
|
self.last_end_time = timezone.now()
|
lino/modlib/memo/__init__.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2008-
|
1
|
+
# Copyright 2008-2025 Rumma & Ko Ltd
|
2
2
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
3
3
|
"""See :doc:`/specs/memo`.
|
4
4
|
|
@@ -15,6 +15,7 @@ Adds functionality for using memo commands in your text fields.
|
|
15
15
|
# from importlib import import_module
|
16
16
|
# from rstgen.utils import py2url_txt
|
17
17
|
from lino.api import ad
|
18
|
+
from lino.core import constants
|
18
19
|
from .parser import Parser, split_name_rest
|
19
20
|
from lino.utils.html import tostring
|
20
21
|
|
@@ -94,20 +95,20 @@ class Plugin(ad.Plugin):
|
|
94
95
|
kwargs = dict() # , nosummary=True)
|
95
96
|
dv = self.site.models.resolve(s)
|
96
97
|
sar = dv.create_request(parent=ar, limit=dv.preview_limit)
|
97
|
-
|
98
|
-
#
|
99
|
-
|
100
|
-
|
101
|
-
|
98
|
+
return sar.show(**kwargs)
|
99
|
+
# kwargs.update(display_mode=constants.DISPLAY_MODE_STORY)
|
100
|
+
# return sar.show_story(**kwargs)
|
101
|
+
# rv = ""
|
102
|
+
# # rv += "20230325 [show {}]".format(dv)
|
103
|
+
# for e in sar.renderer.table2story(sar, **kwargs):
|
104
|
+
# rv += tostring(e)
|
105
|
+
# return rv
|
102
106
|
|
103
107
|
self.parser.register_command("show", show2html)
|
104
108
|
|
105
109
|
if False:
|
106
110
|
# letting website users execute arbitrary code is a security risk
|
107
111
|
def eval2html(ar, s, cmdname, mentions, context):
|
108
|
-
from django.conf import settings # context of exec command
|
109
|
-
|
110
|
-
sar = ar.spawn_request(renderer=settings.SITE.kernel.html_renderer)
|
111
112
|
return eval(compile(s, cmdname, "eval"))
|
112
113
|
|
113
114
|
self.parser.register_command("eval", eval2html)
|
lino/modlib/memo/mixins.py
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# -*- coding: UTF-8 -*-
|
2
|
-
# Copyright 2016-
|
2
|
+
# Copyright 2016-2025 Rumma & Ko Ltd
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
|
5
|
+
# import difflib
|
6
|
+
# import sys
|
5
7
|
from lxml.html import fragments_fromstring
|
6
8
|
import lxml
|
7
9
|
|
@@ -19,6 +21,7 @@ from lino.core.fields import RichTextField, PreviewTextField
|
|
19
21
|
from lino.utils.html import E, tostring, mark_safe
|
20
22
|
from lino.utils.restify import restify
|
21
23
|
from lino.utils.soup import truncate_comment
|
24
|
+
from lino.utils.soup import MORE_MARKER
|
22
25
|
from lino.utils.mldbc.fields import BabelTextField
|
23
26
|
from lino.modlib.checkdata.choicelists import Checker
|
24
27
|
from lino.api import rt, dd, _
|
@@ -130,6 +133,7 @@ class MemoReferrable(dd.Model):
|
|
130
133
|
|
131
134
|
# class BasePreviewable(MentionGenerator):
|
132
135
|
class BasePreviewable(dd.Model):
|
136
|
+
|
133
137
|
class Meta:
|
134
138
|
abstract = True
|
135
139
|
|
@@ -138,12 +142,13 @@ class BasePreviewable(dd.Model):
|
|
138
142
|
def get_preview_length(self):
|
139
143
|
return settings.SITE.plugins.memo.short_preview_length
|
140
144
|
|
145
|
+
# def after_ui_save(self, ar, watcher):
|
141
146
|
def save(self, *args, **kwargs):
|
142
147
|
"""Updates the preview fields and the list of mentioned objects."""
|
143
|
-
pf = self.previewable_field
|
144
148
|
mentions = set()
|
149
|
+
pf = self.previewable_field
|
145
150
|
txt = self.get_previewable_text(settings.SITE.DEFAULT_LANGUAGE)
|
146
|
-
short, full = self.parse_previews(txt, None, mentions)
|
151
|
+
short, full = self.parse_previews(txt, None, mentions, True)
|
147
152
|
# if "choose one or the other" in short:
|
148
153
|
# raise Exception("20230928 {} {}".format(len(short), short))
|
149
154
|
# print("20231023 b", short)
|
@@ -154,23 +159,30 @@ class BasePreviewable(dd.Model):
|
|
154
159
|
src = self.get_previewable_text(lng)
|
155
160
|
# src = getattr(self, pf + lng.suffix)
|
156
161
|
with translation.override(lng.django_code):
|
157
|
-
short, full = self.parse_previews(src, None, mentions)
|
162
|
+
short, full = self.parse_previews(src, None, mentions, True)
|
158
163
|
setattr(self, pf + "_short_preview" + lng.suffix, short)
|
159
164
|
setattr(self, pf + "_full_preview" + lng.suffix, full)
|
165
|
+
|
166
|
+
# self.save() # yes this causes a second save()
|
160
167
|
super().save(*args, **kwargs)
|
168
|
+
# super().after_ui_save(ar, watcher)
|
161
169
|
self.synchronize_mentions(mentions)
|
162
170
|
|
163
171
|
def get_previewable_text(self, lng):
|
164
172
|
return getattr(self, self.previewable_field + lng.suffix)
|
165
173
|
|
166
|
-
def parse_previews(
|
174
|
+
def parse_previews(
|
175
|
+
self, source, ar=None, mentions=None, save=False, **context):
|
167
176
|
context.update(self=self)
|
168
177
|
full = settings.SITE.plugins.memo.parser.parse(
|
169
|
-
source, ar=ar,
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
178
|
+
source, ar=ar, mentions=mentions, context=context)
|
179
|
+
short = truncate_comment(
|
180
|
+
full, self.get_preview_length(),
|
181
|
+
ar=ar, save=save, mentions=mentions)
|
182
|
+
if len(chunks := full.split(MORE_MARKER, 1)) == 2:
|
183
|
+
full = " ".join(chunks)
|
184
|
+
if settings.SITE.plugins.memo.use_markup:
|
185
|
+
if not full.startswith("<"):
|
174
186
|
full = markdown.markdown(full, **MARKDOWNCFG)
|
175
187
|
return (short, full)
|
176
188
|
|
@@ -201,7 +213,7 @@ class BasePreviewable(dd.Model):
|
|
201
213
|
for e in lxml.html.fragments_fromstring(self.body_short_preview):
|
202
214
|
yield e
|
203
215
|
except Exception as e:
|
204
|
-
yield "{} [{}]"
|
216
|
+
yield f"{self.body_short_preview} [{e}]"
|
205
217
|
|
206
218
|
|
207
219
|
class Previewable(BasePreviewable):
|
@@ -218,20 +230,21 @@ class Previewable(BasePreviewable):
|
|
218
230
|
|
219
231
|
def get_body_parsed(self, ar, short=False):
|
220
232
|
if ar.renderer is settings.SITE.kernel.editing_front_end.renderer:
|
221
|
-
return
|
233
|
+
return mark_safe(
|
234
|
+
self.body_short_preview if short else self.body_full_preview)
|
222
235
|
# raise Exception("{} is not {}".format(
|
223
236
|
# ar.renderer, settings.SITE.kernel.editing_front_end.renderer))
|
224
237
|
src = self.body
|
225
|
-
s, f = self.parse_previews(src, ar,
|
226
|
-
return s if short else f
|
238
|
+
s, f = self.parse_previews(src, ar, None, False)
|
239
|
+
return mark_safe(s if short else f)
|
227
240
|
|
228
241
|
def as_paragraph(self, ar):
|
229
242
|
s = super().as_paragraph(ar)
|
230
243
|
# s = format_html("<b>{}</b> : {}", .format(ar.add_detail_link(self, str(self)))
|
231
244
|
# s = ar.obj2htmls(self)
|
232
245
|
s = format_html(
|
233
|
-
"<b>{}</b> : {}",
|
234
|
-
|
246
|
+
"<b>{}</b> : {}",
|
247
|
+
s, mark_safe(self.body_short_preview) or _("(no preview)"))
|
235
248
|
return s
|
236
249
|
|
237
250
|
|
@@ -267,13 +280,16 @@ class PreviewableChecker(Checker):
|
|
267
280
|
pf = obj.previewable_field
|
268
281
|
# src = getattr(obj, pf+suffix)
|
269
282
|
expected_mentions = set()
|
270
|
-
short, full = obj.parse_previews(src, None, expected_mentions)
|
283
|
+
short, full = obj.parse_previews(src, None, expected_mentions, False)
|
271
284
|
is_broken = False
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
):
|
285
|
+
stored_short = getattr(obj, pf + "_short_preview" + lng.suffix)
|
286
|
+
stored_full = getattr(obj, pf + "_full_preview" + lng.suffix)
|
287
|
+
if stored_short != short or stored_full != full:
|
276
288
|
yield (True, _("Preview differs from source."))
|
289
|
+
# print(f"20250908 found_full is {stored_full}, to expected: {full}")
|
290
|
+
# # print("20250908 found_full to expected_full:")
|
291
|
+
# sys.stdout.writelines(difflib.unified_diff(
|
292
|
+
# stored_full.splitlines(), full.splitlines()))
|
277
293
|
is_broken = True
|
278
294
|
found_mentions = set([obj.target for obj in obj.get_saved_mentions()])
|
279
295
|
if expected_mentions != found_mentions:
|
@@ -284,6 +300,7 @@ class PreviewableChecker(Checker):
|
|
284
300
|
# setattr(obj, pf+'_full_preview'+suffix, full)
|
285
301
|
obj.full_clean()
|
286
302
|
obj.save()
|
303
|
+
# obj.after_ui_save(ar, None)
|
287
304
|
# self.synchronize_mentions(mentions)
|
288
305
|
|
289
306
|
def get_checkdata_problems(self, ar, obj, fix=False):
|
lino/modlib/memo/models.py
CHANGED
@@ -23,7 +23,8 @@ target_label = _("Target")
|
|
23
23
|
|
24
24
|
|
25
25
|
class Mention(Controllable):
|
26
|
-
|
26
|
+
|
27
|
+
class Meta:
|
27
28
|
app_label = "memo"
|
28
29
|
abstract = dd.is_abstract_model(__name__, "Mention")
|
29
30
|
verbose_name = _("Mention")
|
@@ -85,12 +86,14 @@ class Mentions(dd.Table):
|
|
85
86
|
# id comment owner created
|
86
87
|
# """
|
87
88
|
|
88
|
-
|
89
|
-
|
90
|
-
#
|
91
|
-
#
|
92
|
-
|
93
|
-
|
89
|
+
|
90
|
+
class MentionsByOwner(Mentions):
|
91
|
+
# Not much used because when you are on the owner, you can see the mentions
|
92
|
+
# in the memo text
|
93
|
+
label = _("Mentions")
|
94
|
+
master_key = "owner"
|
95
|
+
column_names = "target *"
|
96
|
+
default_display_modes = {None: constants.DISPLAY_MODE_SUMMARY}
|
94
97
|
|
95
98
|
|
96
99
|
class MentionsByTarget(Mentions):
|
lino/modlib/memo/parser.py
CHANGED
@@ -19,7 +19,7 @@ from django.conf import settings
|
|
19
19
|
from lino import logger
|
20
20
|
|
21
21
|
import re
|
22
|
-
import
|
22
|
+
import traceback
|
23
23
|
from typing import Callable, Any
|
24
24
|
|
25
25
|
from bs4 import BeautifulSoup, MarkupResemblesLocatorWarning
|
@@ -313,6 +313,8 @@ All remaining arguments are used as the text of the link.
|
|
313
313
|
mo.end(),
|
314
314
|
)
|
315
315
|
# logger.debug(msg)
|
316
|
+
# print(msg, ":")
|
317
|
+
# traceback.print_exc()
|
316
318
|
return msg
|
317
319
|
|
318
320
|
def parse_suggestions(self, src):
|
lino/modlib/notify/models.py
CHANGED
@@ -519,13 +519,10 @@ if remove_after:
|
|
519
519
|
# "You do not have a working installation of the service_identity module: .* Many valid certificate/hostname mappings may be rejected.",
|
520
520
|
# UserWarning)
|
521
521
|
|
522
|
+
if dd.get_plugin_setting("linod", "use_channels", False):
|
522
523
|
|
523
|
-
@dd.receiver(dd.post_ui_save)
|
524
|
-
def notify_panels(sender, instance, ar=None, **kwargs):
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
):
|
529
|
-
return
|
530
|
-
data = get_updatables(instance, ar)
|
531
|
-
send_panel_update(data)
|
524
|
+
@dd.receiver(dd.post_ui_save)
|
525
|
+
def notify_panels(sender, instance, ar=None, **kwargs):
|
526
|
+
if instance.updatable_panels:
|
527
|
+
data = get_updatables(instance, ar)
|
528
|
+
send_panel_update(data)
|
@@ -10,7 +10,7 @@ class Plugin(Plugin):
|
|
10
10
|
"lino.modlib.system", # 'lino.modlib.memo',
|
11
11
|
"lino.modlib.linod",
|
12
12
|
"lino.modlib.jinja",
|
13
|
-
"lino.modlib.bootstrap5"
|
13
|
+
"lino.modlib.bootstrap5"
|
14
14
|
]
|
15
15
|
locations: list[tuple[str, str]] = []
|
16
16
|
|
@@ -53,8 +53,17 @@ class Plugin(Plugin):
|
|
53
53
|
# Only if this is the primary front end:
|
54
54
|
if self.site.kernel.primary_front_end is self:
|
55
55
|
# yield url("^(?P<ref>.*)$", views.Index.as_view())
|
56
|
+
Tree = self.site.models.publisher.Tree
|
57
|
+
from django.db.utils import OperationalError, ProgrammingError
|
58
|
+
# language=self.site.DEFAULT_LANGUAGE.django_code
|
59
|
+
try:
|
60
|
+
for t in Tree.objects.filter(ref__isnull=False):
|
61
|
+
yield url(f"^{t.ref}$", views.Index.as_view(ref=t.ref))
|
62
|
+
except (OperationalError, ProgrammingError):
|
63
|
+
pass
|
56
64
|
yield url("^$", views.Index.as_view())
|
57
|
-
|
65
|
+
yield url('^login$',views.Login.as_view())
|
66
|
+
yield url('^logout$',views.Logout.as_view())
|
58
67
|
|
59
68
|
def setup_main_menu(self, site, user_type, m, ar=None):
|
60
69
|
mg = self.get_menu_group()
|
@@ -65,8 +74,4 @@ class Plugin(Plugin):
|
|
65
74
|
mg = self.get_menu_group()
|
66
75
|
m = m.add_menu(mg.app_label, mg.verbose_name)
|
67
76
|
m.add_action("publisher.SpecialPages")
|
68
|
-
|
69
|
-
def setup_explorer_menu(self, site, user_type, m, ar=None):
|
70
|
-
mg = self.get_menu_group()
|
71
|
-
m = m.add_menu(mg.app_label, mg.verbose_name)
|
72
|
-
m.add_action("publisher.RootPages")
|
77
|
+
m.add_action("publisher.Trees")
|
@@ -87,65 +87,7 @@ add("20", _("Ready"), "ready", is_public=False)
|
|
87
87
|
add("30", _("Public"), "published", is_public=True)
|
88
88
|
add("40", _("Removed"), "removed", is_public=False)
|
89
89
|
|
90
|
-
|
91
|
-
# # verbose_name_plural = _("Enrolment states")
|
92
|
-
# required_roles = dd.login_required(dd.SiteAdmin)
|
93
|
-
# is_public = models.BooleanField(_("Public"), default=False)
|
94
|
-
#
|
95
|
-
# @classmethod
|
96
|
-
# def get_column_names(self, ar):
|
97
|
-
# return "value name text button_text is_public"
|
98
|
-
#
|
99
|
-
# add = EntryStates.add_item
|
100
|
-
# add('10', _("Draft"), 'draft', is_public=False)
|
101
|
-
# add('20', _("Ready"), 'ready', is_public=False)
|
102
|
-
# add('30', _("Public"), 'published', is_public=True)
|
103
|
-
# add('40', _("Cancelled"), 'cancelled', is_public=False)
|
104
|
-
|
105
|
-
|
106
|
-
class PageFiller(Choice):
|
107
|
-
data_view = None
|
108
|
-
|
109
|
-
def __init__(self, data_view=None, **request_params):
|
110
|
-
if data_view is not None:
|
111
|
-
self.data_view = data_view
|
112
|
-
self.request_params = request_params
|
113
|
-
super().__init__(str(self.data_view))
|
114
|
-
|
115
|
-
def create_request(self, ar, obj, **kwargs):
|
116
|
-
kwargs.update(self.request_params, parent=ar)
|
117
|
-
return self.data_view.create_request(**kwargs)
|
118
|
-
|
119
|
-
def get_dynamic_story(self, ar, obj, **kwargs):
|
120
|
-
txt = ""
|
121
|
-
sar = self.create_request(ar, obj, limit=self.data_view.preview_limit)
|
122
|
-
# print("20231028", dv, list(sar))
|
123
|
-
# print("20230409", ar.renderer)
|
124
|
-
# rv += "20230325 [show {}]".format(dv)
|
125
|
-
for e in sar.renderer.table2story(sar, **kwargs):
|
126
|
-
txt += tostring(e)
|
127
|
-
return txt
|
128
|
-
|
129
|
-
def get_dynamic_paragraph(self, ar, obj, **kwargs):
|
130
|
-
# dv = self.data_view
|
131
|
-
# sar = dv.create_request(parent=ar, limit=dv.preview_limit)
|
132
|
-
sar = self.create_request(ar, obj)
|
133
|
-
return " / ".join([sar.obj2htmls(row) for row in sar])
|
134
|
-
|
135
|
-
|
136
|
-
class PageFillers(ChoiceList):
|
137
|
-
verbose_name = _("Page filler")
|
138
|
-
verbose_name_plural = _("Page fillers")
|
139
|
-
item_class = PageFiller
|
140
|
-
max_length = 50
|
141
|
-
column_names = "value name text data_view *"
|
142
|
-
|
143
|
-
@dd.virtualfield(models.CharField(_("Data table")))
|
144
|
-
def data_view(cls, choice, ar):
|
145
|
-
return choice.data_view
|
146
|
-
|
147
|
-
|
148
|
-
# class SpecialPage(PointingChoice):
|
90
|
+
|
149
91
|
class SpecialPage(dd.Choice):
|
150
92
|
# pointing_field_name = 'publisher.Page.special_page'
|
151
93
|
# show_values = True
|
@@ -153,7 +95,8 @@ class SpecialPage(dd.Choice):
|
|
153
95
|
def __init__(self, name, text=None, parent=None, **kwargs):
|
154
96
|
self.parent_value = parent
|
155
97
|
self._default_values = dict()
|
156
|
-
for k in ("ref", "title", "filler", "body"):
|
98
|
+
# for k in ("ref", "title", "filler", "body"):
|
99
|
+
for k in ("ref", "title", "body"):
|
157
100
|
if k in kwargs:
|
158
101
|
self._default_values[k] = kwargs.pop(k)
|
159
102
|
super().__init__(name, text, name, **kwargs)
|
@@ -167,8 +110,8 @@ class SpecialPage(dd.Choice):
|
|
167
110
|
def on_page_created(self, obj):
|
168
111
|
for k, v in self._default_values.items():
|
169
112
|
setattr(obj, k, v)
|
170
|
-
if obj.filler and not obj.title:
|
171
|
-
|
113
|
+
# if obj.filler and not obj.title:
|
114
|
+
# obj.title = obj.filler.data_view.get_actor_label()
|
172
115
|
if not obj.title:
|
173
116
|
obj.title = self.text or "20250422"
|
174
117
|
if self.parent_value:
|
@@ -183,7 +126,8 @@ class SpecialPage(dd.Choice):
|
|
183
126
|
# else:
|
184
127
|
# language = ar.request.LANGUAGE_CODE
|
185
128
|
# return rt.models.publisher.Page.objects.get(ref=self.defaul_values['ref'], language=language)
|
186
|
-
return rt.models.publisher.Page.objects.get(
|
129
|
+
return rt.models.publisher.Page.objects.get(
|
130
|
+
special_page=self, language=language)
|
187
131
|
|
188
132
|
|
189
133
|
class SpecialPages(dd.ChoiceList):
|
@@ -206,7 +150,8 @@ class SpecialPages(dd.ChoiceList):
|
|
206
150
|
Page = rt.models.publisher.Page
|
207
151
|
for lng in settings.SITE.languages:
|
208
152
|
try:
|
209
|
-
page = Page.objects.get(
|
153
|
+
page = Page.objects.get(
|
154
|
+
special_page=choice, language=lng.django_code)
|
210
155
|
lst.append(ar.obj2html(page, lng.name))
|
211
156
|
except Page.DoesNotExist:
|
212
157
|
page = _("(create)")
|