lino 25.8.2__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.
Files changed (143) hide show
  1. lino/__init__.py +1 -1
  2. lino/api/dd.py +0 -1
  3. lino/config/unused/403.html +1 -1
  4. lino/config/unused/404.html +1 -1
  5. lino/config/unused/500.html +1 -1
  6. lino/core/__init__.py +0 -1
  7. lino/core/actions.py +2 -2
  8. lino/core/actors.py +10 -2
  9. lino/core/elems.py +1 -1
  10. lino/core/fields.py +4 -1
  11. lino/core/kernel.py +5 -1
  12. lino/core/model.py +2 -11
  13. lino/core/renderer.py +2 -2
  14. lino/core/requests.py +12 -12
  15. lino/core/site.py +5 -82
  16. lino/core/store.py +3 -1
  17. lino/core/urls.py +1 -1
  18. lino/core/user_types.py +1 -10
  19. lino/help_texts.py +6 -6
  20. lino/management/commands/initdb.py +0 -3
  21. lino/modlib/__init__.py +0 -1
  22. lino/modlib/bootstrap5/README.txt +2 -0
  23. lino/modlib/bootstrap5/__init__.py +69 -0
  24. lino/modlib/{bootstrap3/config/bootstrap3 → bootstrap5/config/bootstrap5}/base.html +9 -4
  25. lino/modlib/{bootstrap3/config/bootstrap3 → bootstrap5/config/bootstrap5}/detail.html +1 -1
  26. lino/modlib/{bootstrap3/config/bootstrap3 → bootstrap5/config/bootstrap5}/index.html +1 -1
  27. lino/modlib/{bootstrap3/config/bootstrap3 → bootstrap5/config/bootstrap5}/table.html +1 -1
  28. lino/modlib/bootstrap5/models.py +30 -0
  29. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.css +4085 -0
  30. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.css.map +1 -0
  31. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.min.css +6 -0
  32. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.min.css.map +1 -0
  33. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.rtl.css +4084 -0
  34. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.rtl.css.map +1 -0
  35. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.rtl.min.css +6 -0
  36. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.rtl.min.css.map +1 -0
  37. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.css +597 -0
  38. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.css.map +1 -0
  39. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.min.css +6 -0
  40. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.min.css.map +1 -0
  41. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.rtl.css +594 -0
  42. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.rtl.css.map +1 -0
  43. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.rtl.min.css +6 -0
  44. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.rtl.min.css.map +1 -0
  45. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.css +5406 -0
  46. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.css.map +1 -0
  47. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.min.css +6 -0
  48. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.min.css.map +1 -0
  49. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.rtl.css +5397 -0
  50. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.rtl.css.map +1 -0
  51. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.rtl.min.css +6 -0
  52. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.rtl.min.css.map +1 -0
  53. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.css +12043 -0
  54. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.css.map +1 -0
  55. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.min.css +6 -0
  56. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.min.css.map +1 -0
  57. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.rtl.css +12016 -0
  58. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.rtl.css.map +1 -0
  59. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.rtl.min.css +6 -0
  60. lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.rtl.min.css.map +1 -0
  61. lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.bundle.js +6315 -0
  62. lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.bundle.js.map +1 -0
  63. lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.bundle.min.js +7 -0
  64. lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.bundle.min.js.map +1 -0
  65. lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.esm.js +4450 -0
  66. lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.esm.js.map +1 -0
  67. lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.esm.min.js +7 -0
  68. lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.esm.min.js.map +1 -0
  69. lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.js +4497 -0
  70. lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.js.map +1 -0
  71. lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.min.js +7 -0
  72. lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.min.js.map +1 -0
  73. lino/modlib/{bootstrap3 → bootstrap5}/views.py +12 -117
  74. lino/modlib/checkdata/choicelists.py +1 -1
  75. lino/modlib/comments/fixtures/demo2.py +1 -0
  76. lino/modlib/comments/mixins.py +1 -8
  77. lino/modlib/comments/models.py +2 -0
  78. lino/modlib/comments/ui.py +7 -7
  79. lino/modlib/extjs/__init__.py +2 -4
  80. lino/modlib/extjs/config/extjs/index.html +1 -1
  81. lino/modlib/extjs/ext_renderer.py +1 -7
  82. lino/modlib/extjs/views.py +2 -0
  83. lino/modlib/help/models.py +1 -12
  84. lino/modlib/jinja/renderer.py +1 -1
  85. lino/modlib/linod/mixins.py +3 -2
  86. lino/modlib/memo/__init__.py +11 -11
  87. lino/modlib/memo/mixins.py +38 -21
  88. lino/modlib/memo/models.py +10 -7
  89. lino/modlib/memo/parser.py +3 -1
  90. lino/modlib/notify/models.py +6 -9
  91. lino/modlib/odata/views.py +7 -7
  92. lino/modlib/publisher/__init__.py +15 -3
  93. lino/modlib/publisher/choicelists.py +8 -94
  94. lino/modlib/publisher/config/publisher/page.pub.html +82 -19
  95. lino/modlib/publisher/fixtures/std.py +14 -1
  96. lino/modlib/publisher/fixtures/synodalworld.py +3 -1
  97. lino/modlib/publisher/mixins.py +59 -77
  98. lino/modlib/publisher/models.py +109 -204
  99. lino/modlib/publisher/renderer.py +31 -11
  100. lino/modlib/publisher/ui.py +46 -98
  101. lino/modlib/publisher/views.py +61 -11
  102. lino/modlib/system/models.py +3 -2
  103. lino/modlib/uploads/__init__.py +1 -0
  104. lino/modlib/uploads/mixins.py +2 -2
  105. lino/modlib/uploads/models.py +55 -21
  106. lino/modlib/uploads/ui.py +1 -0
  107. lino/modlib/uploads/utils.py +2 -2
  108. lino/modlib/users/__init__.py +2 -3
  109. lino/modlib/users/actions.py +12 -17
  110. lino/modlib/users/fixtures/abc.py +20 -0
  111. lino/modlib/users/mixins.py +6 -6
  112. lino/modlib/users/models.py +37 -36
  113. lino/modlib/weasyprint/__init__.py +25 -14
  114. lino/modlib/weasyprint/choicelists.py +6 -0
  115. lino/modlib/weasyprint/config/weasyprint/base.weasy.html +43 -27
  116. lino/utils/diag.py +5 -3
  117. lino/utils/html.py +103 -0
  118. lino/utils/mldbc/mixins.py +2 -2
  119. lino/utils/soup.py +16 -8
  120. {lino-25.8.2.dist-info → lino-25.9.0.dist-info}/METADATA +1 -1
  121. {lino-25.8.2.dist-info → lino-25.9.0.dist-info}/RECORD +135 -95
  122. lino/modlib/bootstrap3/README.txt +0 -2
  123. lino/modlib/bootstrap3/__init__.py +0 -73
  124. lino/modlib/bootstrap3/models.py +0 -30
  125. lino/modlib/bootstrap3/static/bootstrap-3.3.4/css/bootstrap.css +0 -6584
  126. lino/modlib/bootstrap3/static/bootstrap-3.3.4/css/bootstrap.css.map +0 -1
  127. lino/modlib/bootstrap3/static/bootstrap-3.3.4/css/bootstrap.min.css +0 -5
  128. lino/modlib/bootstrap3/static/bootstrap-3.3.4/js/bootstrap.js +0 -2317
  129. lino/modlib/bootstrap3/static/bootstrap-3.3.4/js/bootstrap.min.js +0 -7
  130. /lino/modlib/{bootstrap3 → bootstrap5}/renderer.py +0 -0
  131. /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/css/bootstrap-theme.css +0 -0
  132. /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/css/bootstrap-theme.css.map +0 -0
  133. /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/css/bootstrap-theme.min.css +0 -0
  134. /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/fonts/glyphicons-halflings-regular.eot +0 -0
  135. /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/fonts/glyphicons-halflings-regular.svg +0 -0
  136. /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/fonts/glyphicons-halflings-regular.ttf +0 -0
  137. /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/fonts/glyphicons-halflings-regular.woff +0 -0
  138. /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/fonts/glyphicons-halflings-regular.woff2 +0 -0
  139. /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/js/bootstrap_lino.js +0 -0
  140. /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/js/npm.js +0 -0
  141. {lino-25.8.2.dist-info → lino-25.9.0.dist-info}/WHEEL +0 -0
  142. {lino-25.8.2.dist-info → lino-25.9.0.dist-info}/licenses/AUTHORS.rst +0 -0
  143. {lino-25.8.2.dist-info → lino-25.9.0.dist-info}/licenses/COPYING +0 -0
@@ -1,58 +1,64 @@
1
1
  # -*- coding: UTF-8 -*-
2
- # Copyright 2012-2024 Rumma & Ko Ltd
2
+ # Copyright 2012-2025 Rumma & Ko Ltd
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
 
5
5
  from html import escape
6
+ from lorem import get_paragraph
6
7
  from django.db import models
7
- from django.http import HttpResponseRedirect
8
8
  from django.conf import settings
9
9
  from django.utils import translation
10
- from django.utils.translation import pgettext_lazy
11
-
12
- from django.utils import translation
13
- from django.conf import settings
14
-
15
- try:
16
- from lorem import get_paragraph
17
- except ImportError:
18
- lorem = None
19
-
20
- # from django.utils.translation import get_language
21
- from django.utils.html import mark_safe
22
-
10
+ from django.utils.translation import get_language
23
11
  from lino.api import dd, rt, _
24
- from lino.utils import mti
25
- from lino.utils.html import E, tostring
26
- from lino.core import constants
12
+ # from lino.utils import mti
13
+ from lino.utils.html import E, tostring, format_html
14
+ from lino.utils.instantiator import get_or_create
27
15
  # from lino.core.renderer import add_user_language
28
-
29
- from lino.utils.mldbc.fields import LanguageField
30
- from lino import mixins
16
+ # from lino.utils.mldbc.fields import LanguageField
31
17
  from lino.mixins import Hierarchical, Sequenced, Referrable
32
-
33
18
  # from lino.modlib.summaries.mixins import Summarized
34
- from lino.modlib.office.roles import OfficeUser
35
19
  from lino.modlib.publisher.mixins import Publishable, PublishableContent
36
20
  from lino.modlib.comments.mixins import Commentable
37
21
  from lino.modlib.linod.choicelists import schedule_daily
38
22
  from lino.modlib.memo.mixins import Previewable
39
- from lino.mixins.polymorphic import Polymorphic
40
- from lino_xl.lib.topics.mixins import Taggable
41
23
  from lino.modlib.users.mixins import PrivacyRelevant
42
- # from .utils import render_node
24
+ from lino_xl.lib.topics.mixins import Taggable
43
25
 
44
- from lino.api import rt, dd
45
- from .choicelists import PublishingStates, PageFillers, SpecialPages
26
+ from .choicelists import PublishingStates, SpecialPages
46
27
  from .mixins import Publishable
47
28
  from .ui import *
48
29
 
49
- # class Node(Referrable, Hierarchical, Sequenced, Previewable, Publishable, Commentable):
50
- # Polymorphic,
30
+
31
+ class Tree(PrivacyRelevant, Referrable):
32
+ class Meta:
33
+ verbose_name = _("Tree")
34
+ verbose_name_plural = _("Trees")
35
+ abstract = dd.is_abstract_model(__name__, "Tree")
36
+ # unique_together = ["ref", "language"]
37
+
38
+ # ref = dd.CharField(_("Reference"), max_length=200, blank=True, null=True)
39
+ # root_page = dd.ForeignKey(
40
+ # "publisher.Page", null=True, blank=True,
41
+ # verbose_name=_("Root page"), related_name='+')
42
+
43
+ @dd.virtualfield(dd.ForeignKey(
44
+ 'publisher.Page', verbose_name=_("Root page")))
45
+ def root_page(self, ar=None):
46
+ return self.get_root_page(get_language())
47
+
48
+ def get_root_page(self, language):
49
+ if self.pk is not None:
50
+ qs = Page.objects.filter(
51
+ parent__isnull=True, publisher_tree=self, language=language)
52
+ return qs.first()
53
+ # try:
54
+ # return Page.objects.get(parent=None, publisher_tree=self)
55
+ # except Page.DoesNotExist:
56
+ # return None
51
57
 
52
58
 
53
59
  class Page(
54
60
  Hierarchical, Sequenced, Previewable, Commentable, PublishableContent,
55
- Taggable # PrivacyRelevant
61
+ Taggable
56
62
  ):
57
63
  class Meta:
58
64
  verbose_name = _("Page")
@@ -62,30 +68,21 @@ class Page(
62
68
  # unique_together = ["group", "ref", "language"]
63
69
  # else:
64
70
  # unique_together = ["ref", "language"]
65
- unique_together = ["ref", "language"]
71
+ # unique_together = ["publisher_tree", "language"]
66
72
 
67
73
  memo_command = "page"
74
+ allow_cascaded_delete = ['parent']
68
75
 
69
- ref = dd.CharField(_("Reference"), max_length=200, blank=True, null=True)
70
76
  title = dd.CharField(_("Title"), max_length=250, blank=True)
71
77
  child_node_depth = models.IntegerField(default=1)
72
- # page_type = PageTypes.field(blank=True, null=True)
73
78
  special_page = SpecialPages.field(blank=True)
74
79
 
75
- translated_from = dd.ForeignKey(
76
- "publisher.Page",
77
- verbose_name=_("Translated from"),
78
- null=True,
79
- blank=True,
80
- related_name="translated_to",
81
- )
82
-
83
80
  previous_page = dd.ForeignKey(
84
- "self", null=True, blank=True, verbose_name=_("Previous page")
85
- )
81
+ "self", null=True, blank=True, editable=False,
82
+ verbose_name=_("Previous page"), related_name='+')
86
83
 
87
84
  def __str__(self):
88
- return self.title or self.ref or super().__str__()
85
+ return self.title or super().__str__()
89
86
 
90
87
  # def on_create(self, ar):
91
88
  # self.page_type = self.get_page_type()
@@ -102,22 +99,27 @@ class Page(
102
99
  def get_node_info(self, ar):
103
100
  return ""
104
101
 
105
- # def full_clean(self):
106
- # self.page_type = self.mti_child().get_page_type()
107
- # super().full_clean()
102
+ def is_public(self):
103
+ return not self.publisher_tree.private
108
104
 
109
105
  def mti_child(self):
110
106
  # if self.page_type:
111
107
  # return mti.get_child(self, self.page_type.nodes_table.model) or self
112
108
  return self
113
109
 
110
+ def walk(self):
111
+ yield self
112
+ for c in self.children.all():
113
+ for i in c.walk():
114
+ yield i
115
+
114
116
  # def as_summary_row(self, ar, **kwargs):
115
117
  # return ar.obj2htmls(self, **kwargs)
116
118
 
117
119
  # def as_story_item(self, ar, **kwargs):
118
120
  # return "".join(self.as_page(ar, **kwargs))
119
121
 
120
- def as_paragraph(self, ar):
122
+ def old_as_paragraph(self, ar):
121
123
  title = E.b(escape(self.title))
122
124
  url = ar.obj2url(self)
123
125
  if url is not None:
@@ -128,6 +130,17 @@ class Page(
128
130
  item = E.li(title, body)
129
131
  return tostring(item)
130
132
 
133
+ def as_paragraph(self, ar):
134
+ title = format_html("<b>{}</b>", self.title)
135
+ if (url := ar.obj2url(self)) is not None:
136
+ title = format_html(
137
+ '<a href="{url}" style="text-decoration:none;color:black;">{title}</a>',
138
+ title=title, url=url)
139
+ body = self.get_body_parsed(ar, short=True)
140
+ if body:
141
+ return format_html("{} &mdash; {}", title, body)
142
+ return title
143
+
131
144
  def toc_html(self, ar, max_depth=1):
132
145
  def li(obj):
133
146
  # return "<li>{}</li>".format(obj.memo2html(ar, str(obj)))
@@ -144,8 +157,7 @@ class Page(
144
157
  if len(breadcrumbs) > 1:
145
158
  breadcrumbs = [
146
159
  """<a href="{0}">{1}</a>""".format(
147
- ar.obj2url(p.mti_child()), p.title
148
- )
160
+ ar.obj2url(p.mti_child()), p.title)
149
161
  for p in breadcrumbs[:-1]
150
162
  ]
151
163
  yield "<p>{}</p>".format(" &raquo; ".join(breadcrumbs))
@@ -181,7 +193,7 @@ class Page(
181
193
 
182
194
  # if display_mode in ("detail", "story"):
183
195
  if display_mode == "detail":
184
- if hlevel == 1 and not dd.plugins.memo.use_markup and self.ref != 'index':
196
+ if hlevel == 1 and not dd.plugins.memo.use_markup and self.parent_id:
185
197
  yield self.toc_html(ar)
186
198
 
187
199
  if hlevel == 1 and self.main_image:
@@ -198,12 +210,11 @@ class Page(
198
210
  # yield self.body_full_preview
199
211
  yield self.get_body_parsed(ar, short=False)
200
212
 
201
- if self.filler:
202
- yield "\n\n"
203
- if hlevel == 1:
204
- yield self.filler.get_dynamic_story(ar, self)
205
- else:
206
- yield self.filler.get_dynamic_paragraph(ar, self)
213
+ # if self.filler:
214
+ # if hlevel == 1:
215
+ # yield self.filler.get_dynamic_story(ar, self)
216
+ # else:
217
+ # yield self.filler.get_dynamic_paragraph(ar, self)
207
218
 
208
219
  # if dd.plugins.memo.use_markup:
209
220
  # return
@@ -246,77 +257,20 @@ class Page(
246
257
  return
247
258
  return "".join(ar.row_as_page(self))
248
259
 
249
- # @classmethod
250
- # def get_publisher_pages(cls, pv):
251
- # root = cls.objects.get(parent__isnull=True)
252
-
253
- # def compute_summary_values(self):
254
- # def walk(node, prev=None):
255
- # if node.page_type is not None:
256
- # node.set_prev(prev)
257
- # prev = node
258
- # for c in node.children.all():
259
- # prev = walk(c, prev)
260
- # return prev
261
- # root = self.get_ancestor()
262
- # last = walk(root)
263
- # root.set_prev(last)
264
-
265
- # from pprint import pprint
266
- # pprint(self.whole_tree())
267
-
268
- # def get_sidebar_caption(self):
269
- # if self.title:
270
- # return self.title
271
- # if self.ref:
272
- # return self.ref
273
- # return str(self.id)
274
- #
275
- # #~ if self.ref or self.parent:
276
- # #~ return self.ref
277
- # #~ return unicode(_('Home'))
278
-
279
- # def get_sidebar_item(self, request, other):
280
- # kw = dict()
281
- # add_user_language(kw, request)
282
- # url = self.get_absolute_url(**kw)
283
- # a = E.a(self.get_sidebar_caption(), href=url)
284
- # if self == other:
285
- # return E.li(a, **{'class':'active'})
286
- # return E.li(a)
287
- #
288
- # def get_sidebar_html(self, request):
289
- # items = []
290
- # #~ loop over top-level nodes
291
- # for n in self.__class__.objects.filter(parent__isnull=True).order_by('seqno'):
292
- # #~ items += [li for li in n.get_sidebar_items(request,self)]
293
- # items.append(n.get_sidebar_item(request, self))
294
- # if self.is_parented(n):
295
- # children = []
296
- # for ch in n.children.order_by('seqno'):
297
- # children.append(ch.get_sidebar_item(request, self))
298
- # if len(children):
299
- # items.append(E.ul(*children, **{'class':'nav nav-list'}))
300
- #
301
- # e = E.ul(*items, **{'class':'nav nav-list'})
302
- # return tostring_pretty(e)
303
- #
304
- # def get_sidebar_menu(self, request):
305
- # qs = self.__class__.objects.filter(parent__isnull=True, language=get_language())
306
- # #~ qs = self.children.all()
307
- # yield ('/', 'index', str(_('Home')))
308
- # #~ yield ('/downloads/', 'downloads', 'Downloads')
309
- # #~ yield ('/about', 'about', 'About')
310
- # #~ if qs is not None:
311
- # for obj in qs.order_by("seqno"):
312
- # if obj.ref and obj.title:
313
- # yield ('/' + obj.ref, obj.ref, obj.title)
314
- # #~ else:
315
- # #~ yield ('/','index',obj.title)
316
-
317
- def set_previous_page(self, prev):
260
+ def full_clean(self):
261
+ if self.publisher_tree is None and self.parent is not None:
262
+ self.publisher_tree = self.parent.publisher_tree
263
+ super().full_clean()
264
+
265
+ def update_page(self, prev, tree):
266
+ save = False
318
267
  if self.previous_page != prev:
319
268
  self.previous_page = prev
269
+ save = True
270
+ if self.publisher_tree != tree:
271
+ self.publisher_tree = tree
272
+ save = True
273
+ if save:
320
274
  self.save()
321
275
 
322
276
  def get_prev_link(self, ar, text="◄"): # "◄" 0x25c4
@@ -339,18 +293,6 @@ class Page(
339
293
  # url = ar.obj2url(next_node.mti_child())
340
294
  # return """<a href="{}">{}</a>""".format(url, text)
341
295
 
342
- @classmethod
343
- def get_publisher_pages(cls):
344
- def walk(page, prev=None):
345
- yield page
346
- for c in page.children.all():
347
- for i in walk(c):
348
- yield i
349
-
350
- for root in cls.objects.filter(parent__isnull=True):
351
- for i in walk(root):
352
- yield i
353
-
354
296
  @classmethod
355
297
  def get_dashboard_objects(cls, user):
356
298
  # print("20210114 get_dashboard_objects()", get_language())
@@ -367,80 +309,41 @@ class Page(
367
309
 
368
310
  def get_absolute_url(self, **kwargs):
369
311
  parts = []
370
- if self.group is not None:
371
- if self.group.ref is not None:
372
- parts.append(self.group.ref)
373
- if self.ref:
374
- if self.ref != "index":
375
- parts.append(self.group.ref)
312
+ # if self.group is not None:
313
+ # if self.group.ref is not None:
314
+ # parts.append(self.group.ref)
315
+ if self.publisher_tree.ref:
316
+ if self.publisher_tree.ref != "index":
317
+ parts.append(self.publisher_tree.ref)
376
318
  return dd.plugins.publisher.build_plain_url(*parts, **kwargs)
377
319
 
378
- def get_publisher_response(self, ar):
379
- if ar and ar.request and self.language != ar.request.LANGUAGE_CODE:
380
- rqlang = ar.request.LANGUAGE_CODE
381
- # tt = rt.models.pages.Translation.objects.filter(
382
- # parent=self, language=ar.request.LANGUAGE_CODE).first()
383
- obj = None
384
- if self.translated_from_id and self.translated_from.language == rqlang:
385
- obj = self.translated_from
386
- else:
387
- sources = set([self.id])
388
- p = self.translated_from
389
- while p is not None:
390
- sources.add(p.id)
391
- p = p.translated_from
392
- qs = self.__class__.objects.filter(
393
- language=rqlang, translated_from__in=sources)
394
- obj = qs.first()
395
- # obj = self.translated_to.filter(language=rqlang).first()
396
- # print("20231027 redirect to translation", tt.language, ar.request.LANGUAGE_CODE)
397
- if obj is not None:
398
- # print("20231028", self.language, "!=", ar.request.LANGUAGE_CODE, tt)
399
- ar.selected_rows = [obj]
400
- url = ar.get_request_url()
401
- return HttpResponseRedirect(url)
402
- return super().get_publisher_response(ar)
403
-
404
320
 
405
321
  if dd.plugins.memo.use_markup:
406
322
  dd.update_field(Page, "body", format="plain")
407
323
 
408
- # class Translation(dd.Model):
409
- # class Meta:
410
- # verbose_name = _("Page translation")
411
- # verbose_name_plural = _("Page translations")
412
- #
413
- # parent = dd.ForeignKey(
414
- # 'publisher.Page',
415
- # verbose_name=_("Translated from..."),
416
- # related_name='translated_from')
417
- # child = dd.ForeignKey(
418
- # 'publisher.Page',
419
- # blank=True, null=True,
420
- # verbose_name=_("Translated to..."),
421
- # related_name='translated_to')
422
- # language = dd.LanguageField()
423
-
424
324
 
425
325
  @schedule_daily()
426
326
  def update_publisher_pages(ar):
427
327
  # BaseRequest(parent=ar).run(settings.SITE.site_config.check_all_summaries)
428
328
  # rt.login().run(settings.SITE.site_config.check_all_summaries)
429
- Page = settings.SITE.models.publisher.Page
329
+ Page = rt.models.publisher.Page
430
330
  # for pv in PublisherViews.get_list_items():
431
331
  # for m in rt.models_by_base(Published, toplevel_only=True):
432
- prev = None
433
332
  count = 0
434
333
  ar.logger.info("Update publisher pages...")
435
334
 
436
- for obj in Page.get_publisher_pages():
437
- obj.set_previous_page(prev)
438
- prev = obj
439
- count += 1
335
+ for root in Page.objects.filter(parent__isnull=True):
336
+ prev = None
337
+ for obj in root.walk():
338
+ obj.update_page(prev, root.publisher_tree)
339
+ prev = obj
340
+ count += 1
440
341
  ar.logger.info("%d pages have been updated.", count)
441
342
 
442
343
 
443
- def make_demo_pages(pages_desc):
344
+ def make_demo_pages(pages_desc, root_ref, group=None):
345
+ Tree = rt.models.publisher.Tree
346
+ tree = get_or_create(Tree, ref=root_ref, group=group)
444
347
  # Translation = rt.models.pages.Translation
445
348
  # for lc in settings.SITE.LANGUAGE_CHOICES:
446
349
  # language = lc[0]
@@ -451,31 +354,32 @@ def make_demo_pages(pages_desc):
451
354
  for lng in settings.SITE.languages:
452
355
  counter = {None: 0}
453
356
  # count = 0
454
- home_page = Page.objects.get(
455
- special_page=SpecialPages.home, language=lng.django_code)
357
+ # home_page = Page.objects.get(
358
+ # special_page=SpecialPages.home, language=lng.django_code)
456
359
 
457
360
  with translation.override(lng.django_code):
458
361
 
459
- def make_pages(pages, parent=None):
362
+ # def make_pages(pages, parent=None):
363
+ def make_pages(pages, parent=None, root_ref=None):
460
364
  for page in pages:
461
365
  if len(page) != 3:
462
366
  raise Exception(f"Oops {page}")
463
367
  title, body, children = page
464
- kwargs = dict(title=title)
368
+ # kwargs = dict(title=title, group=group)
369
+ kwargs = dict(title=title, publisher_tree=tree,
370
+ language=lng.django_code)
465
371
  if body is None:
466
372
  kwargs.update(body=get_paragraph())
467
373
  else:
468
374
  kwargs.update(body=body)
469
- if parent is None:
470
- # kwargs.update(ref='index')
471
- continue # home page is created by SpecialPages
375
+ if parent is not None:
376
+ kwargs.update(parent=parent)
472
377
  if lng.suffix:
473
378
  kwargs.update(
474
379
  translated_from=parent_nodes[counter[None]])
475
- kwargs.update(language=lng.django_code)
476
380
  if dd.is_installed("publisher"):
477
381
  kwargs.update(publishing_state='published')
478
- obj = Page(parent=parent, **kwargs)
382
+ obj = Page(**kwargs)
479
383
  yield obj
480
384
  if not lng.suffix:
481
385
  parent_nodes.append(obj)
@@ -483,4 +387,5 @@ def make_demo_pages(pages_desc):
483
387
  # print("20230324", title, kwargs)
484
388
  yield make_pages(children, obj)
485
389
 
486
- yield make_pages(pages_desc, parent=home_page)
390
+ # yield make_pages(pages_desc, parent=home_page)
391
+ yield make_pages(pages_desc, None, root_ref)
@@ -1,31 +1,43 @@
1
1
  # -*- coding: UTF-8 -*-
2
- # Copyright 2023 Rumma & Ko Ltd
2
+ # Copyright 2023-2025 Rumma & Ko Ltd
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
 
5
- from lino import logger
6
5
  from lino.core.renderer import add_user_language
7
- from lino.modlib.bootstrap3.renderer import Renderer
6
+ from lino.core.renderer import HtmlRenderer
8
7
 
8
+ from lino.modlib.publisher.mixins import Publishable
9
+
10
+
11
+ class Renderer(HtmlRenderer):
12
+
13
+ tableattrs = {"class": "table table-hover table-striped table-condensed"}
14
+ cellattrs = dict(align="left", valign="top")
15
+
16
+ can_auth = False
9
17
 
10
- class Renderer(Renderer):
11
18
  def __init__(self, front_end):
12
19
  super().__init__(front_end)
13
20
  dr = front_end.site.kernel.default_renderer
14
21
  for k in ("row_action_button", "get_detail_url"):
15
22
  setattr(self, k, getattr(dr, k))
16
23
 
17
- def get_request_url(self, ar, *args, **kwargs):
18
- obj = ar.selected_rows[0]
19
- return self.obj2url(ar, obj, **kwargs)
20
- # return obj.publisher_url(ar, **kwargs)
21
-
22
24
  def obj2url(self, ar, obj, **kwargs):
25
+ if not isinstance(obj, Publishable):
26
+ return super().obj2url(ar, obj, **kwargs)
23
27
  # if ar.actor is None or not isinstance(obj, ar.actor.model):
28
+ add_user_language(kwargs, ar)
29
+ # if isinstance(obj, self.front_end.site.models.publisher.Page) and obj.ref == 'index':
30
+ if isinstance(obj, self.front_end.site.models.publisher.Page) and obj.parent is None:
31
+ if obj.publisher_tree.ref is not None:
32
+ if obj.publisher_tree.ref == 'index':
33
+ return self.front_end.buildurl(**kwargs)
34
+ return self.front_end.buildurl(obj.publisher_tree.ref, **kwargs)
35
+ # if obj.ref:
36
+ # return self.front_end.buildurl(obj.ref, **kwargs)
24
37
  loc = obj.__class__._lino_publisher_location
25
38
  if loc is None:
26
39
  # logger.warning("No location for %s", obj.__class__)
27
40
  return None
28
- add_user_language(kwargs, ar)
29
41
  return self.front_end.buildurl(loc, str(obj.pk), **kwargs)
30
42
  # for i in PublisherViews.get_list_items():
31
43
  # if isinstance(obj, i.table_class.model):
@@ -39,4 +51,12 @@ class Renderer(Renderer):
39
51
  # publisher view,
40
52
  return None
41
53
  return self.front_end.site.kernel.default_renderer.obj2url(ar, obj, **kwargs)
42
- # return super().obj2url(ar, obj, **kwargs)
54
+
55
+ def get_home_url(self, ar, *args, **kw):
56
+ add_user_language(kw, ar)
57
+ return self.front_end.build_plain_url(*args, **kw)
58
+
59
+ def get_request_url(self, ar, *args, **kwargs):
60
+ obj = ar.selected_rows[0]
61
+ return self.obj2url(ar, obj, **kwargs)
62
+ # return obj.publisher_url(ar, **kwargs)