lino 25.2.2__py3-none-any.whl → 25.3.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 (70) hide show
  1. lino/__init__.py +8 -3
  2. lino/api/dd.py +11 -35
  3. lino/api/doctest.py +49 -17
  4. lino/api/selenium.py +1 -1
  5. lino/core/actions.py +25 -23
  6. lino/core/actors.py +52 -23
  7. lino/core/choicelists.py +10 -8
  8. lino/core/dbtables.py +1 -1
  9. lino/core/elems.py +47 -31
  10. lino/core/fields.py +19 -9
  11. lino/core/kernel.py +26 -20
  12. lino/core/model.py +27 -16
  13. lino/core/renderer.py +2 -2
  14. lino/core/requests.py +103 -56
  15. lino/core/site.py +5 -5
  16. lino/core/store.py +5 -2
  17. lino/core/utils.py +12 -7
  18. lino/help_texts.py +7 -8
  19. lino/mixins/duplicable.py +6 -4
  20. lino/mixins/sequenced.py +17 -6
  21. lino/modlib/__init__.py +0 -2
  22. lino/modlib/changes/models.py +21 -10
  23. lino/modlib/checkdata/models.py +59 -24
  24. lino/modlib/comments/fixtures/demo2.py +12 -3
  25. lino/modlib/comments/models.py +7 -7
  26. lino/modlib/comments/ui.py +8 -5
  27. lino/modlib/export_excel/models.py +7 -5
  28. lino/modlib/extjs/__init__.py +2 -2
  29. lino/modlib/extjs/views.py +66 -22
  30. lino/modlib/help/config/makehelp/conf.tpl.py +1 -1
  31. lino/modlib/jinja/mixins.py +73 -0
  32. lino/modlib/jinja/models.py +6 -0
  33. lino/modlib/linod/__init__.py +1 -0
  34. lino/modlib/linod/choicelists.py +21 -0
  35. lino/modlib/linod/consumers.py +13 -4
  36. lino/modlib/linod/fixtures/__init__.py +0 -0
  37. lino/modlib/linod/fixtures/linod.py +32 -0
  38. lino/modlib/linod/management/commands/linod.py +6 -2
  39. lino/modlib/linod/mixins.py +18 -14
  40. lino/modlib/linod/models.py +4 -2
  41. lino/modlib/memo/mixins.py +2 -1
  42. lino/modlib/memo/parser.py +1 -1
  43. lino/modlib/notify/models.py +19 -11
  44. lino/modlib/printing/actions.py +47 -42
  45. lino/modlib/printing/choicelists.py +17 -15
  46. lino/modlib/printing/mixins.py +22 -20
  47. lino/modlib/publisher/models.py +5 -5
  48. lino/modlib/summaries/models.py +3 -2
  49. lino/modlib/system/models.py +28 -29
  50. lino/modlib/uploads/__init__.py +14 -11
  51. lino/modlib/uploads/actions.py +2 -8
  52. lino/modlib/uploads/choicelists.py +10 -10
  53. lino/modlib/uploads/fixtures/std.py +17 -0
  54. lino/modlib/uploads/mixins.py +20 -8
  55. lino/modlib/uploads/models.py +62 -38
  56. lino/modlib/uploads/ui.py +15 -9
  57. lino/utils/__init__.py +0 -1
  58. lino/utils/jscompressor.py +4 -4
  59. lino/utils/media.py +45 -23
  60. lino/utils/report.py +5 -4
  61. lino/utils/restify.py +2 -2
  62. lino/utils/soup.py +26 -8
  63. lino/utils/xml.py +19 -5
  64. {lino-25.2.2.dist-info → lino-25.3.0.dist-info}/METADATA +1 -1
  65. {lino-25.2.2.dist-info → lino-25.3.0.dist-info}/RECORD +68 -65
  66. lino/mixins/uploadable.py +0 -3
  67. lino/utils/requests.py +0 -55
  68. {lino-25.2.2.dist-info → lino-25.3.0.dist-info}/WHEEL +0 -0
  69. {lino-25.2.2.dist-info → lino-25.3.0.dist-info}/licenses/AUTHORS.rst +0 -0
  70. {lino-25.2.2.dist-info → lino-25.3.0.dist-info}/licenses/COPYING +0 -0
lino/mixins/sequenced.py CHANGED
@@ -33,7 +33,7 @@ class MoveByN(actions.Action):
33
33
  This action is available on any :class:`Sequenced` object as
34
34
  :attr:`Sequenced.move_by_n`.
35
35
 
36
- It is currently only used by React to allow for drag and drop reording.
36
+ It is currently only used by React to allow for drag and drop reordering.
37
37
 
38
38
  """
39
39
 
@@ -80,9 +80,11 @@ class MoveUp(actions.Action):
80
80
  # label = _("Up")
81
81
  # label = "\u2191" thin arrow up
82
82
  # label = "\u25b2" # triangular arrow up
83
- label = "\u25B2" # ▲ Black up-pointing triangle
84
- # label = "" #
83
+ label = _("Move up")
84
+ # button_text = "\u25B2" # ▲ Black up-pointing triangle
85
+ button_text = "↑"
85
86
  custom_handler = True
87
+ callable_from = "t"
86
88
  # icon_name = 'arrow_up'
87
89
  # ~ icon_file = 'arrow_up.png'
88
90
  readonly = False
@@ -92,9 +94,12 @@ class MoveUp(actions.Action):
92
94
  return False
93
95
  if not super().get_action_permission(ar, obj, state):
94
96
  return False
97
+ # if ar.order_by is None or "seqno" not in ar.order_by:
98
+ # return False
95
99
  if ar.get_total_count() == 0:
96
100
  return False
97
101
  if ar.data_iterator[0] == obj:
102
+ # print(f"20250305 first of {ar.data_iterator}")
98
103
  return False
99
104
  # print("20161128", obj.seqno, ar.data_iterator.count())
100
105
  return True
@@ -119,14 +124,16 @@ class MoveDown(actions.Action):
119
124
 
120
125
  """
121
126
 
127
+ label = _("Move down")
122
128
  # label = _("Down")
123
- label = "↓"
129
+ button_text = "↓"
124
130
  # label = "\u25bc" # triangular arrow down
125
131
  # label = "\u2193"
126
- label = "\u25BC" # ▼ Black down-pointing triangle
132
+ # button_text = "\u25BC" # ▼ Black down-pointing triangle
127
133
  # icon_name = 'arrow_down'
128
134
  custom_handler = True
129
135
  # ~ icon_file = 'arrow_down.png'
136
+ callable_from = "t"
130
137
  readonly = False
131
138
 
132
139
  def get_action_permission(self, ar, obj, state):
@@ -134,10 +141,13 @@ class MoveDown(actions.Action):
134
141
  return False
135
142
  if not super().get_action_permission(ar, obj, state):
136
143
  return False
144
+ # if ar.order_by is None or "seqno" not in ar.order_by:
145
+ # return False
137
146
  n = ar.get_total_count()
138
147
  if n == 0:
139
148
  return False
140
149
  if ar.data_iterator[n - 1] == obj:
150
+ # print(f"20250305 last of {ar.data_iterator}")
141
151
  return False
142
152
  # ~ if obj.__class__.__name__=='Entry' and obj.seqno == 25:
143
153
  # ~ print 20130706, ar.data_iterator.count(), ar.data_iterator
@@ -315,7 +325,8 @@ class Sequenced(Duplicable):
315
325
 
316
326
  seq_no += 1
317
327
 
318
- ar.success(message=_("Renumbered {} of {} siblings.").format(n, qs.count()))
328
+ ar.success(
329
+ message=_("Renumbered {} of {} siblings.").format(n, qs.count()))
319
330
  ar.set_response(refresh_all=True)
320
331
 
321
332
  @fields.displayfield(_("Move"))
lino/modlib/__init__.py CHANGED
@@ -67,7 +67,5 @@ Enterprise Resources
67
67
  languages
68
68
  office
69
69
  smtpd
70
- uploads
71
-
72
70
 
73
71
  """
@@ -64,7 +64,8 @@ class Change(UserAuthored):
64
64
  related_name="changes_by_object",
65
65
  )
66
66
  object_id = GenericForeignKeyIdField(object_type, blank=True, null=True)
67
- object = GenericForeignKey("object_type", "object_id", verbose_name=_("Object"))
67
+ object = GenericForeignKey(
68
+ "object_type", "object_id", verbose_name=_("Object"))
68
69
 
69
70
  master_type = dd.ForeignKey(
70
71
  "contenttypes.ContentType",
@@ -74,9 +75,11 @@ class Change(UserAuthored):
74
75
  related_name="changes_by_master",
75
76
  )
76
77
  master_id = GenericForeignKeyIdField(master_type, blank=True, null=True)
77
- master = GenericForeignKey("master_type", "master_id", verbose_name=_("Master"))
78
+ master = GenericForeignKey(
79
+ "master_type", "master_id", verbose_name=_("Master"))
78
80
 
79
- diff = dd.RichTextField(_("Changes"), format="plain", blank=True, editable=False)
81
+ diff = dd.RichTextField(_("Changes"), format="plain",
82
+ blank=True, editable=False)
80
83
  changed_fields = dd.CharField(_("Fields"), max_length=250, blank=True)
81
84
 
82
85
  def __str__(self):
@@ -129,7 +132,8 @@ class Changes(dd.Table):
129
132
  if pv.change_type:
130
133
  qs = qs.filter(type=pv.change_type)
131
134
  if pv.date:
132
- qs = qs.filter(time__range=(pv.date, pv.date + datetime.timedelta(1)))
135
+ qs = qs.filter(time__range=(
136
+ pv.date, pv.date + datetime.timedelta(1)))
133
137
  # if settings.SITE.user_model and ar.param_values.user:
134
138
  # qs = qs.filter(user=ar.param_values.user)
135
139
  if pv.object_type:
@@ -167,7 +171,9 @@ def log_change(type, request, master, obj, msg="", changed_fields=""):
167
171
  remove_after = dd.plugins.changes.remove_after
168
172
  if remove_after:
169
173
 
170
- @dd.schedule_daily()
174
+ from lino.modlib.linod.choicelists import schedule_daily
175
+
176
+ @schedule_daily()
171
177
  def delete_older_changes(ar):
172
178
  days = datetime.timedelta(days=remove_after)
173
179
  # django.core.exceptions.FieldError: Cannot resolve keyword 'time_lt' into field. Choices are: changed_fields, diff, id, list_item, master, master_id, master_type, master_type_id, name_column, navigation_panel, object, object_id, object_type, object_type_id, overview, time, type, user, user_id, workflow_buttons
@@ -206,7 +212,8 @@ def on_update(sender=None, watcher=None, request=None, **kw):
206
212
  changes = []
207
213
  for k, old, new in watcher.get_updates(cs.ignored_fields):
208
214
  changed_fields += k + " "
209
- changes.append("%s : %s --> %s" % (k, dd.obj2str(old), dd.obj2str(new)))
215
+ changes.append("%s : %s --> %s" %
216
+ (k, dd.obj2str(old), dd.obj2str(new)))
210
217
  if len(changes) == 0:
211
218
  msg = "(no changes)"
212
219
  elif len(changes) == 1:
@@ -229,7 +236,8 @@ def on_delete(sender=None, request=None, **kw):
229
236
  master = get_master(sender)
230
237
  if master is None:
231
238
  return
232
- log_change(ChangeTypes.delete, request, master, sender, dd.obj2str(sender, True))
239
+ log_change(ChangeTypes.delete, request, master,
240
+ sender, dd.obj2str(sender, True))
233
241
 
234
242
 
235
243
  @receiver(on_ui_created)
@@ -238,7 +246,8 @@ def on_ui_created(sender=None, request=None, **kw):
238
246
  master = get_master(sender)
239
247
  if master is None:
240
248
  return
241
- log_change(ChangeTypes.create, request, master, sender, dd.obj2str(sender, True))
249
+ log_change(ChangeTypes.create, request, master,
250
+ sender, dd.obj2str(sender, True))
242
251
 
243
252
 
244
253
  @receiver(pre_add_child)
@@ -247,7 +256,8 @@ def on_add_child(sender=None, request=None, child=None, **kw):
247
256
  if master is None:
248
257
  return
249
258
  log_change(
250
- ChangeTypes.add_child, request, master, sender, dd.full_model_name(child)
259
+ ChangeTypes.add_child, request, master, sender, dd.full_model_name(
260
+ child)
251
261
  )
252
262
 
253
263
 
@@ -257,7 +267,8 @@ def on_remove_child(sender=None, request=None, child=None, **kw):
257
267
  if master is None:
258
268
  return
259
269
  log_change(
260
- ChangeTypes.remove_child, request, master, sender, dd.full_model_name(child)
270
+ ChangeTypes.remove_child, request, master, sender, dd.full_model_name(
271
+ child)
261
272
  )
262
273
 
263
274
 
@@ -12,6 +12,7 @@ from django.template.defaultfilters import pluralize
12
12
  from lino.core.gfks import gfk2lookup
13
13
  from lino.modlib.gfks.mixins import Controllable
14
14
  from lino.modlib.users.mixins import UserAuthored
15
+ from lino.modlib.linod.choicelists import background_task
15
16
  from lino.core.roles import SiteStaff
16
17
 
17
18
  from lino.api import dd, rt, _
@@ -22,12 +23,27 @@ from .roles import CheckdataUser
22
23
  from lino.core import constants
23
24
 
24
25
 
25
- class UpdateMessage(dd.Action):
26
+ class CheckerAction(dd.Action):
27
+ fix_them = False
28
+
29
+ def run_it(self, ar, fix, checkers, objects):
30
+ if fix is None:
31
+ fix = self.fix_them
32
+ Message = rt.models.checkdata.Message
33
+ gfk = Message.owner
34
+ for obj in objects:
35
+ qs = Message.objects.filter(**gfk2lookup(gfk, obj))
36
+ qs.delete()
37
+ for chk in checkers:
38
+ chk.update_problems(ar, obj, False, fix)
39
+ ar.set_response(refresh=True)
40
+
41
+
42
+ class UpdateMessage(CheckerAction):
26
43
  icon_name = "bell"
27
44
  ui5_icon_name = "sap-icon://bell"
28
45
  label = _("Check data")
29
46
  combo_group = "checkdata"
30
- fix_them = False
31
47
  sort_index = 90
32
48
  # custom_handler = True
33
49
  # select_rows = False
@@ -47,11 +63,11 @@ class UpdateMessage(dd.Action):
47
63
  # has been deleted.
48
64
  obj.delete()
49
65
  else:
50
- qs = Message.objects.filter(
51
- **gfk2lookup(Message.owner, owner, checker=chk)
52
- )
53
- qs.delete()
54
- chk.update_problems(ar, owner, False, fix)
66
+ self.run_it(ar, fix, [chk], [owner])
67
+ # qs = Message.objects.filter(
68
+ # **gfk2lookup(Message.owner, owner, checker=chk))
69
+ # qs.delete()
70
+ # chk.update_problems(ar, owner, False, fix)
55
71
  ar.set_response(refresh_all=True)
56
72
 
57
73
 
@@ -61,12 +77,11 @@ class FixProblem(UpdateMessage):
61
77
  sort_index = 91
62
78
 
63
79
 
64
- class UpdateMessagesByController(dd.Action):
80
+ class UpdateMessagesByController(CheckerAction):
65
81
  icon_name = "bell"
66
82
  ui5_icon_name = "sap-icon://bell"
67
83
  label = _("Check data")
68
84
  combo_group = "checkdata"
69
- fix_them = False
70
85
  required_roles = dd.login_required()
71
86
 
72
87
  def __init__(self, model):
@@ -74,18 +89,19 @@ class UpdateMessagesByController(dd.Action):
74
89
  super().__init__()
75
90
 
76
91
  def run_from_ui(self, ar, fix=None):
77
- if fix is None:
78
- fix = self.fix_them
79
- Message = rt.models.checkdata.Message
80
- gfk = Message.owner
81
- checkers = get_checkers_for(self.model)
82
- for obj in ar.selected_rows:
83
- assert isinstance(obj, self.model)
84
- qs = Message.objects.filter(**gfk2lookup(gfk, obj))
85
- qs.delete()
86
- for chk in checkers:
87
- chk.update_problems(ar, obj, False, fix)
88
- ar.set_response(refresh=True)
92
+ self.run_it(ar, fix, get_checkers_for(self.model), ar.selected_rows)
93
+ # if fix is None:
94
+ # fix = self.fix_them
95
+ # Message = rt.models.checkdata.Message
96
+ # gfk = Message.owner
97
+ # checkers = get_checkers_for(self.model)
98
+ # for obj in ar.selected_rows:
99
+ # assert isinstance(obj, self.model)
100
+ # qs = Message.objects.filter(**gfk2lookup(gfk, obj))
101
+ # qs.delete()
102
+ # for chk in checkers:
103
+ # chk.update_problems(ar, obj, False, fix)
104
+ # ar.set_response(refresh=True)
89
105
 
90
106
 
91
107
  class FixMessagesByController(UpdateMessagesByController):
@@ -93,6 +109,21 @@ class FixMessagesByController(UpdateMessagesByController):
93
109
  fix_them = True
94
110
 
95
111
 
112
+ class FixAllProblems(CheckerAction):
113
+ select_rows = False
114
+ show_in_plain = True
115
+ # http_method = "POST"
116
+ label = _("Fix all data problems")
117
+ button_text = "✓" # u"\u2713"
118
+ fix_them = True
119
+
120
+ def run_from_ui(self, ar, fix=None):
121
+ mi = ar.master_instance
122
+ print(f"20250307 {mi}")
123
+ self.run_it(ar, fix, get_checkers_for(mi.__class__), [mi])
124
+ ar.set_response(refresh=True)
125
+
126
+
96
127
  class Message(Controllable, UserAuthored):
97
128
  class Meta(object):
98
129
  app_label = "checkdata"
@@ -182,6 +213,8 @@ class MessagesByOwner(Messages):
182
213
  column_names = "message checker user #fixable *"
183
214
  default_display_modes = {None: constants.DISPLAY_MODE_SUMMARY}
184
215
 
216
+ fix_all_problems = FixAllProblems()
217
+
185
218
 
186
219
  # This was the first use case of a slave table with something else than a model
187
220
  # instance as its master
@@ -305,8 +338,10 @@ def check_data(ar, args=[], fix=True, prune=False):
305
338
  assert not m._meta.abstract
306
339
  if settings.SITE.is_hidden_plugin(m._meta.app_label):
307
340
  continue
308
- ct = rt.models.contenttypes.ContentType.objects.get_for_model(m)
309
- qs = Message.objects.filter(owner_type=ct, checker__in=checkers)
341
+ ct = rt.models.contenttypes.ContentType.objects.get_for_model(
342
+ m)
343
+ qs = Message.objects.filter(
344
+ owner_type=ct, checker__in=checkers)
310
345
  qs.delete()
311
346
  name = str(m._meta.verbose_name_plural)
312
347
  qs = m.objects.all()
@@ -346,7 +381,7 @@ def check_data(ar, args=[], fix=True, prune=False):
346
381
  ar.logger.info(msg, done, what, found, fixed)
347
382
 
348
383
 
349
- @dd.background_task(every_unit="daily", every=1)
384
+ @background_task(every_unit="daily", every=1)
350
385
  def checkdata(ar):
351
386
  """Run all data checkers."""
352
387
  check_data(ar, fix=False)
@@ -32,9 +32,21 @@ plain1 = "Some plain text."
32
32
  plain2 = "Two paragraphs of plain text.\n\nThe second paragraph."
33
33
  # plain2 += " With an 👁 (U+1F441)." #5855 (Jane fails to store certain unicode characters)
34
34
 
35
+ imageDataURL = """data:image/png;base64,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"""
36
+ body_with_img = f"""\
37
+ <p>Here is an image:</p>
38
+ <p><img src="{imageDataURL}" class="bar"></p>\
39
+ """
40
+
35
41
  BODIES = Cycler(
36
42
  [styled, table, lorem, short_lorem, breaking, cond_comment, plain1, plain2]
37
43
  )
44
+ # Add two empty bodies that will be filled later:
45
+ BODIES.items.insert(0, "")
46
+ BODIES.items.insert(0, "")
47
+
48
+ if dd.is_installed('blogs'):
49
+ BODIES.items.append(body_with_img)
38
50
 
39
51
 
40
52
  def objects():
@@ -44,9 +56,6 @@ def objects():
44
56
  # use_linod = settings.SITE.use_linod
45
57
  # settings.SITE.use_linod = False
46
58
 
47
- # Add two empty bodies that will be filled later:
48
- BODIES.items.insert(0, "")
49
- BODIES.items.insert(0, "")
50
59
  MENTIONED = Cycler()
51
60
  for model in rt.models_by_base(Commentable):
52
61
  if model.memo_command is not None:
@@ -3,6 +3,8 @@
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
 
5
5
  # from html import escape
6
+ from .ui import *
7
+ from lino.modlib.checkdata.choicelists import Checker
6
8
  from django.contrib.humanize.templatetags.humanize import naturaltime
7
9
  from django.db import models
8
10
  from django.db.models import Q
@@ -10,7 +12,7 @@ from django.core import validators
10
12
  from django.utils.html import mark_safe, format_html, SafeString
11
13
  from django.contrib.contenttypes.models import ContentType
12
14
  from django.conf import settings
13
- from lino.utils.html import E, tostring, fromstring
15
+ # from lino.utils.html import E, tostring, fromstring
14
16
 
15
17
  from lino.api import dd, rt, _
16
18
 
@@ -144,7 +146,8 @@ class Comment(
144
146
  u = ar.get_user()
145
147
  if u.is_anonymous:
146
148
  return
147
- mr = rt.models.comments.Reaction.objects.filter(user=u, comment=self).first()
149
+ mr = rt.models.comments.Reaction.objects.filter(
150
+ user=u, comment=self).first()
148
151
  if mr:
149
152
  return mr.emotion
150
153
 
@@ -399,7 +402,8 @@ class Reaction(CreatedModified, UserAuthored, DateRangeObservable):
399
402
 
400
403
  allow_cascaded_delete = "user comment"
401
404
 
402
- comment = dd.ForeignKey("comments.Comment", related_name="reactions_to_this")
405
+ comment = dd.ForeignKey(
406
+ "comments.Comment", related_name="reactions_to_this")
403
407
  emotion = Emotions.field(default="ok")
404
408
 
405
409
  def as_summary_item(self, ar, text=None, **kwargs):
@@ -418,8 +422,6 @@ class Reaction(CreatedModified, UserAuthored, DateRangeObservable):
418
422
  #
419
423
  # mp.register_django_model('comment', Comment)
420
424
 
421
- from lino.modlib.checkdata.choicelists import Checker
422
-
423
425
 
424
426
  class CommentChecker(Checker):
425
427
  # temporary checker to fix #4084 (Comment.owner is empty when replying to a comment)
@@ -436,5 +438,3 @@ class CommentChecker(Checker):
436
438
 
437
439
 
438
440
  CommentChecker.activate()
439
-
440
- from .ui import *
@@ -2,6 +2,7 @@
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
5
6
  from django.utils.translation import ngettext
6
7
  from django.contrib.humanize.templatetags.humanize import naturaltime
7
8
  from django.contrib.contenttypes.models import ContentType
@@ -125,7 +126,8 @@ class Comments(dd.Table):
125
126
 
126
127
  @classmethod
127
128
  def comments_created(cls, user, sd, ed):
128
- pv = dict(user=user, start_date=sd, end_date=ed, observed_event=CommentEvents.created)
129
+ pv = dict(user=user, start_date=sd, end_date=ed,
130
+ observed_event=CommentEvents.created)
129
131
  # pv = dict(start_date=sd, end_date=ed, observed_event=CommentEvents.created)
130
132
  return cls.request(user=user, param_values=pv)
131
133
 
@@ -206,6 +208,7 @@ class CommentsByType(CommentsByX):
206
208
  master_key = "comment_type"
207
209
  column_names = "body created user *"
208
210
 
211
+
209
212
  # TODO: rename CommentsByRFC to CommentsByOwner
210
213
  class CommentsByRFC(CommentsByX):
211
214
  master_key = "owner"
@@ -232,7 +235,8 @@ class CommentsByRFC(CommentsByX):
232
235
  @classmethod
233
236
  def param_defaults(cls, ar, **kw):
234
237
  kw = super().param_defaults(ar, **kw)
235
- kw["reply_to"] = constants.CHOICES_BLANK_FILTER_VALUE
238
+ if ar.display_mode == constants.DISPLAY_MODE_STORY:
239
+ kw["reply_to"] = constants.CHOICES_BLANK_FILTER_VALUE
236
240
  return kw
237
241
 
238
242
  # @classmethod
@@ -275,7 +279,8 @@ class CommentsByMentioned(CommentsByX):
275
279
  assert not cls.model._meta.abstract
276
280
  ct = ContentType.objects.get_for_model(cls.model)
277
281
  mkw = gfk2lookup(Mention.target, mi, owner_type=ct)
278
- mentions = Mention.objects.filter(**mkw).values_list("owner_id", flat=True)
282
+ mentions = Mention.objects.filter(
283
+ **mkw).values_list("owner_id", flat=True)
279
284
  # mentions = [o.comment_id for o in Mention.objects.filter(**mkw)]
280
285
  # print(mkw, mentions)
281
286
  # return super(CommentsByMentioned, cls).get_filter_kw(ar, **kw)
@@ -312,6 +317,4 @@ class ReactionsByComment(Reactions):
312
317
  default_display_modes = {None: constants.DISPLAY_MODE_SUMMARY}
313
318
 
314
319
 
315
- from lino.modlib.publisher.choicelists import PageFillers
316
-
317
320
  PageFillers.add_item(RecentComments)
@@ -86,7 +86,8 @@ def ar2workbook(ar, column_names=None):
86
86
  time = time.strip("-")
87
87
  negative = True
88
88
  time = time.split(":")
89
- value = datetime.timedelta(hours=int(time[0]), minutes=int(time[1]))
89
+ value = datetime.timedelta(
90
+ hours=int(time[0]), minutes=int(time[1]))
90
91
  if negative: # Make negative.
91
92
  value = value - value - value
92
93
  elif iselement(value) or isinstance(value, SafeString):
@@ -111,7 +112,8 @@ def ar2workbook(ar, column_names=None):
111
112
  cell.style = style
112
113
  cell.value = value
113
114
  except ValueError as e:
114
- raise Exception("20190222 {} {}".format(value.__class__, value))
115
+ raise Exception("20190222 {} {}".format(
116
+ value.__class__, value))
115
117
 
116
118
  return workbook
117
119
 
@@ -131,14 +133,14 @@ class ExportExcelAction(actions.Action):
131
133
  def run_from_ui(self, ar, **kw):
132
134
  # Prepare tmp file
133
135
  mf = TmpMediaFile(ar, "xlsx")
134
- settings.SITE.makedirs_if_missing(os.path.dirname(mf.name))
136
+ settings.SITE.makedirs_if_missing(mf.path.parent)
135
137
 
136
138
  # Render
137
- self.render(ar, mf.name)
139
+ self.render(ar, mf.path)
138
140
 
139
141
  # Tell client that the action was successful and that it
140
142
  # should open a new browser window on the generated file.
141
- ar.success(open_url=mf.get_url(ar.request))
143
+ ar.success(open_url=mf.url)
142
144
 
143
145
  def render(self, ar, file):
144
146
  workbook = ar2workbook(ar)
@@ -250,12 +250,12 @@ class Plugin(Plugin):
250
250
  ),
251
251
  url(
252
252
  rx + r"choices/(?P<app_label>\w+)/(?P<rptname>\w+)/"
253
- "(?P<fldname>\w+)$",
253
+ r"(?P<fldname>\w+)$",
254
254
  views.Choices.as_view(),
255
255
  ),
256
256
  url(
257
257
  rx + r"apchoices/(?P<app_label>\w+)/(?P<actor>\w+)/"
258
- "(?P<an>\w+)/(?P<field>\w+)$",
258
+ r"(?P<an>\w+)/(?P<field>\w+)$",
259
259
  views.ActionParamChoices.as_view(),
260
260
  ),
261
261
  # the thread_id can be a negative number: