esdrt.content 2.0.3__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 (193) hide show
  1. esdrt/content/INTEGRATION.txt +36 -0
  2. esdrt/content/__init__.py +5 -0
  3. esdrt/content/adapters/__init__.py +0 -0
  4. esdrt/content/adapters/configure.zcml +11 -0
  5. esdrt/content/adapters/reference_number.py +42 -0
  6. esdrt/content/browser/__init__.py +1 -0
  7. esdrt/content/browser/attachmentdownload.py +22 -0
  8. esdrt/content/browser/carryover.py +247 -0
  9. esdrt/content/browser/comments.py +22 -0
  10. esdrt/content/browser/configure.zcml +233 -0
  11. esdrt/content/browser/copyfiles.py +22 -0
  12. esdrt/content/browser/get_sample_xls.py +164 -0
  13. esdrt/content/browser/inbox_sections.py +225 -0
  14. esdrt/content/browser/interfaces.py +5 -0
  15. esdrt/content/browser/macros.py +15 -0
  16. esdrt/content/browser/management.py +97 -0
  17. esdrt/content/browser/observation_import.py +383 -0
  18. esdrt/content/browser/statechange.py +529 -0
  19. esdrt/content/browser/statisticsview.py +495 -0
  20. esdrt/content/browser/tableau.py +29 -0
  21. esdrt/content/browser/templates/assign_answerer_form.pt +67 -0
  22. esdrt/content/browser/templates/assign_conclusion_reviewer_form.pt +72 -0
  23. esdrt/content/browser/templates/assign_counterpart_form.pt +99 -0
  24. esdrt/content/browser/templates/carryover.pt +113 -0
  25. esdrt/content/browser/templates/comments.pt +308 -0
  26. esdrt/content/browser/templates/finalisedfolderview.pt +595 -0
  27. esdrt/content/browser/templates/import_observation.pt +28 -0
  28. esdrt/content/browser/templates/inboxreviewfolderview.pt +155 -0
  29. esdrt/content/browser/templates/macros.pt +56 -0
  30. esdrt/content/browser/templates/multi_input.pt +80 -0
  31. esdrt/content/browser/templates/reviewfolder_get_table.pt +108 -0
  32. esdrt/content/browser/templates/reviewfolderview.pt +500 -0
  33. esdrt/content/browser/templates/statisticsview.pt +380 -0
  34. esdrt/content/browser/templates/tableau_dashboard.pt +35 -0
  35. esdrt/content/comment.py +184 -0
  36. esdrt/content/commentanswer.py +131 -0
  37. esdrt/content/commentextender.py +70 -0
  38. esdrt/content/conclusion.py +283 -0
  39. esdrt/content/conclusionsphase2.py +282 -0
  40. esdrt/content/configure.zcml +92 -0
  41. esdrt/content/constants.py +56 -0
  42. esdrt/content/converter.py +41 -0
  43. esdrt/content/crf_code_matching.py +71 -0
  44. esdrt/content/esdrtfile.py +88 -0
  45. esdrt/content/forms.zcml +162 -0
  46. esdrt/content/indexers.py +428 -0
  47. esdrt/content/interfaces.py +8 -0
  48. esdrt/content/ldap_utils.py +44 -0
  49. esdrt/content/locales/README.txt +2 -0
  50. esdrt/content/notifications/__init__.py +0 -0
  51. esdrt/content/notifications/answer_acknowledged.pt +18 -0
  52. esdrt/content/notifications/answer_acknowledged.py +23 -0
  53. esdrt/content/notifications/answer_to_msexperts.pt +18 -0
  54. esdrt/content/notifications/answer_to_msexperts.py +23 -0
  55. esdrt/content/notifications/conclusion_to_comment.pt +18 -0
  56. esdrt/content/notifications/conclusion_to_comment.py +60 -0
  57. esdrt/content/notifications/configure.zcml +7 -0
  58. esdrt/content/notifications/observation_finalisation_denied.pt +18 -0
  59. esdrt/content/notifications/observation_finalisation_denied.py +41 -0
  60. esdrt/content/notifications/observation_finalisation_request.pt +18 -0
  61. esdrt/content/notifications/observation_finalisation_request.py +40 -0
  62. esdrt/content/notifications/observation_finalised.pt +18 -0
  63. esdrt/content/notifications/observation_finalised.py +79 -0
  64. esdrt/content/notifications/observation_finalised_ms_remarks.pt +18 -0
  65. esdrt/content/notifications/observation_finalised_rev_msg.pt +18 -0
  66. esdrt/content/notifications/observation_to_phase2.pt +18 -0
  67. esdrt/content/notifications/observation_to_phase2.py +40 -0
  68. esdrt/content/notifications/observation_to_phase2_rev_msg.pt +18 -0
  69. esdrt/content/notifications/question_answered.py +98 -0
  70. esdrt/content/notifications/question_answered_lr_msg.pt +18 -0
  71. esdrt/content/notifications/question_answered_msexperts_msg.pt +18 -0
  72. esdrt/content/notifications/question_answered_rev_msg.pt +18 -0
  73. esdrt/content/notifications/question_ready_for_approval.pt +18 -0
  74. esdrt/content/notifications/question_ready_for_approval.py +41 -0
  75. esdrt/content/notifications/question_to_counterpart.pt +18 -0
  76. esdrt/content/notifications/question_to_counterpart.py +60 -0
  77. esdrt/content/notifications/question_to_ms.pt +18 -0
  78. esdrt/content/notifications/question_to_ms.py +88 -0
  79. esdrt/content/notifications/question_to_ms_rev_msg.pt +18 -0
  80. esdrt/content/notifications/utils.py +159 -0
  81. esdrt/content/observation.py +2358 -0
  82. esdrt/content/overrides.zcml +17 -0
  83. esdrt/content/patches.py +64 -0
  84. esdrt/content/patches.zcml +34 -0
  85. esdrt/content/permissions.zcml +90 -0
  86. esdrt/content/profiles/default/browserlayer.xml +7 -0
  87. esdrt/content/profiles/default/catalog.xml +155 -0
  88. esdrt/content/profiles/default/diff_tool.xml +43 -0
  89. esdrt/content/profiles/default/ldapsettings.xml +60 -0
  90. esdrt/content/profiles/default/metadata.xml +10 -0
  91. esdrt/content/profiles/default/registry/generic.xml +129 -0
  92. esdrt/content/profiles/default/registry/plone.xml +21 -0
  93. esdrt/content/profiles/default/registry/resources.xml +53 -0
  94. esdrt/content/profiles/default/rolemap.xml +88 -0
  95. esdrt/content/profiles/default/sharing.xml +85 -0
  96. esdrt/content/profiles/default/tinymce.xml +14 -0
  97. esdrt/content/profiles/default/types/Comment.xml +57 -0
  98. esdrt/content/profiles/default/types/CommentAnswer.xml +57 -0
  99. esdrt/content/profiles/default/types/Conclusion.xml +59 -0
  100. esdrt/content/profiles/default/types/ConclusionsPhase2.xml +59 -0
  101. esdrt/content/profiles/default/types/ESDRTFile.xml +57 -0
  102. esdrt/content/profiles/default/types/Folder.xml +6 -0
  103. esdrt/content/profiles/default/types/Observation.xml +61 -0
  104. esdrt/content/profiles/default/types/Question.xml +60 -0
  105. esdrt/content/profiles/default/types/ReviewFolder.xml +60 -0
  106. esdrt/content/profiles/default/types.xml +20 -0
  107. esdrt/content/profiles/default/workflows/esd-answer-workflow/definition.xml +177 -0
  108. esdrt/content/profiles/default/workflows/esd-comment-workflow/definition.xml +170 -0
  109. esdrt/content/profiles/default/workflows/esd-conclusion-phase2-workflow/definition.xml +320 -0
  110. esdrt/content/profiles/default/workflows/esd-conclusion-workflow/definition.xml +324 -0
  111. esdrt/content/profiles/default/workflows/esd-file-workflow/definition.xml +180 -0
  112. esdrt/content/profiles/default/workflows/esd-question-review-workflow/definition.xml +1654 -0
  113. esdrt/content/profiles/default/workflows/esd-review-workflow/definition.xml +1054 -0
  114. esdrt/content/profiles/default/workflows/esd-reviewtool-folder-workflow/definition.xml +350 -0
  115. esdrt/content/profiles/default/workflows.xml +41 -0
  116. esdrt/content/profiles/uninstall/browserlayer.xml +7 -0
  117. esdrt/content/profiles.zcml +30 -0
  118. esdrt/content/question.py +538 -0
  119. esdrt/content/reviewfolder.py +1934 -0
  120. esdrt/content/roles/__init__.py +0 -0
  121. esdrt/content/roles/configure.zcml +38 -0
  122. esdrt/content/roles/localroles.py +301 -0
  123. esdrt/content/roles/localrolesubscriber.py +52 -0
  124. esdrt/content/setuphandlers.py +86 -0
  125. esdrt/content/static/chosen-sprite.png +0 -0
  126. esdrt/content/static/chosen-sprite@2x.png +0 -0
  127. esdrt/content/static/chosen.jquery.js +1211 -0
  128. esdrt/content/static/chosen.min.css +3 -0
  129. esdrt/content/static/cookies.js +77 -0
  130. esdrt/content/static/eea-tabs.css +108 -0
  131. esdrt/content/static/eea-tabs.js +27 -0
  132. esdrt/content/static/esdrt.content.css +760 -0
  133. esdrt/content/static/flags.css +52 -0
  134. esdrt/content/static/flags.png +0 -0
  135. esdrt/content/static/icons/bootstrap-icons.min.css +5 -0
  136. esdrt/content/static/icons/fonts/bootstrap-icons.woff +0 -0
  137. esdrt/content/static/icons/fonts/bootstrap-icons.woff2 +0 -0
  138. esdrt/content/static/inbox_view.css +49 -0
  139. esdrt/content/static/inbox_view.js +50 -0
  140. esdrt/content/static/moment.min.js +6 -0
  141. esdrt/content/static/phase-1.png +0 -0
  142. esdrt/content/static/phase-12.png +0 -0
  143. esdrt/content/static/phase-2.png +0 -0
  144. esdrt/content/subscribers.py +310 -0
  145. esdrt/content/subscribers.zcml +283 -0
  146. esdrt/content/subscriptionconfiguration.py +251 -0
  147. esdrt/content/subscriptions/__init__.py +1 -0
  148. esdrt/content/subscriptions/configure.zcml +24 -0
  149. esdrt/content/subscriptions/dexterity.py +70 -0
  150. esdrt/content/subscriptions/interfaces.py +42 -0
  151. esdrt/content/templates/diffedview.pt +519 -0
  152. esdrt/content/templates/observationview.pt +1399 -0
  153. esdrt/content/templates/subscriptionconfiguration.pt +243 -0
  154. esdrt/content/templates/subscriptionconfigurationreview.pt +120 -0
  155. esdrt/content/tests.py +62 -0
  156. esdrt/content/timeit.py +47 -0
  157. esdrt/content/upgrades/__init__.py +0 -0
  158. esdrt/content/upgrades/configure.zcml +59 -0
  159. esdrt/content/upgrades/evolve_2002.py +10 -0
  160. esdrt/content/upgrades/evolve_2003.py +10 -0
  161. esdrt/content/upgrades/portal_workflow.py +119 -0
  162. esdrt/content/upgrades/reindex_observations.py +31 -0
  163. esdrt/content/upgrades/templates/portal_workflow_apply_and_reindex.pt +101 -0
  164. esdrt/content/utilities/__init__.py +1 -0
  165. esdrt/content/utilities/configure.zcml +22 -0
  166. esdrt/content/utilities/interfaces.py +36 -0
  167. esdrt/content/utilities/ldap_utils.py +177 -0
  168. esdrt/content/utilities/ms_user.py +18 -0
  169. esdrt/content/utilities/question.py +45 -0
  170. esdrt/content/utilities/roles.py +73 -0
  171. esdrt/content/utils.py +102 -0
  172. esdrt/content/views.zcml +237 -0
  173. esdrt/content/vocabularies/__init__.py +0 -0
  174. esdrt/content/vocabularies/configure.zcml +70 -0
  175. esdrt/content/vocabularies/data/conclusion_phase2_reasons.csv +3 -0
  176. esdrt/content/vocabularies/data/conclusion_reasons.csv +3 -0
  177. esdrt/content/vocabularies/data/crf_code.csv +115 -0
  178. esdrt/content/vocabularies/data/eea_member_states.csv +39 -0
  179. esdrt/content/vocabularies/data/fuel.csv +6 -0
  180. esdrt/content/vocabularies/data/gas.csv +7 -0
  181. esdrt/content/vocabularies/data/ghg_source_category.csv +13 -0
  182. esdrt/content/vocabularies/data/ghg_source_sectors.csv +6 -0
  183. esdrt/content/vocabularies/data/highlight.csv +19 -0
  184. esdrt/content/vocabularies/data/parameter.csv +11 -0
  185. esdrt/content/vocabularies/interfaces.py +68 -0
  186. esdrt/content/vocabularies/vocabularies.py +246 -0
  187. esdrt.content-2.0.3-py3.14-nspkg.pth +1 -0
  188. esdrt_content-2.0.3.dist-info/METADATA +1319 -0
  189. esdrt_content-2.0.3.dist-info/RECORD +193 -0
  190. esdrt_content-2.0.3.dist-info/WHEEL +5 -0
  191. esdrt_content-2.0.3.dist-info/entry_points.txt +2 -0
  192. esdrt_content-2.0.3.dist-info/namespace_packages.txt +1 -0
  193. esdrt_content-2.0.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,36 @@
1
+ Integration Tests
2
+ -----------------
3
+
4
+ This is a DocTest file, using the Python doctest format.
5
+
6
+ In an integration test, here's some of the globals you have to work with::
7
+
8
+ >>> portal
9
+ <PloneSite at /plone>
10
+
11
+ >>> portal_name
12
+ 'plone'
13
+
14
+ >>> folder
15
+ <ATFolder at /plone/Members/test_user_1_>
16
+
17
+ >>> user_name
18
+ 'test_user_1_'
19
+
20
+ >>> user_password
21
+ 'secret'
22
+
23
+ >>> user_role
24
+ 'test_role_1_'
25
+
26
+ >>> app.REQUEST
27
+ <HTTPRequest, URL=http://nohost>
28
+
29
+ >>> app
30
+ <Application at >
31
+
32
+ Now, let's demonstrate a failing test::
33
+
34
+ >>> 1 == 2
35
+ True
36
+
@@ -0,0 +1,5 @@
1
+ from zope.i18nmessageid import MessageFactory
2
+
3
+ # Set up the i18n message factory for our package
4
+ _ = MessageFactory('esdrt.content')
5
+ from . import patches
File without changes
@@ -0,0 +1,11 @@
1
+ <configure
2
+ xmlns="http://namespaces.zope.org/zope"
3
+ xmlns:plone="http://namespaces.plone.org/plone">
4
+
5
+ <adapter
6
+ for="esdrt.content.reviewfolder.IReviewFolder"
7
+ provides="zope.container.interfaces.INameChooser"
8
+ factory=".reference_number.ReferenceNumberCreator"
9
+ />
10
+
11
+ </configure>
@@ -0,0 +1,42 @@
1
+ from zope.component import adapter
2
+ from zope.interface import implementer
3
+
4
+ from esdrt.content.observation import IObservation
5
+ from plone.app.content.interfaces import INameFromTitle
6
+ from plone.app.content.namechooser import NormalizingNameChooser
7
+
8
+
9
+ ATTEMPTS = 100
10
+
11
+
12
+ class INameFromData(INameFromTitle):
13
+ pass
14
+
15
+ @adapter(IObservation)
16
+ @implementer(INameFromData)
17
+ class ReferenceNumberCreator(NormalizingNameChooser):
18
+ """A name chooser for a Zope object manager.
19
+
20
+ If the object is adaptable to or provides INameFromTitle, use the
21
+ title to generate a name.
22
+ """
23
+
24
+ def chooseName(self, name, object):
25
+ parent = self.context
26
+ items = []
27
+ items.append(object.country.upper())
28
+ items.append(object.crf_code)
29
+ items.append(str(object.review_year))
30
+ prename = '-'.join(items)
31
+ number = 1
32
+ observations = [k for k in list(parent.keys()) if k.startswith(prename)]
33
+ if observations:
34
+ observations.sort()
35
+ last_observation = observations[-1]
36
+ number = int(last_observation.split('-')[-1])
37
+ number = number + 1
38
+ last_part = '%04d' % number
39
+ name = prename + '-' + last_part
40
+
41
+ # OFS.ObjectManager.checkValidId fails unless the id is str
42
+ return str(name)
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,22 @@
1
+ from plone.namedfile.browser import Download as Base
2
+ from plone.rfc822.interfaces import IPrimaryFieldInfo
3
+ from zope.publisher.interfaces import NotFound
4
+
5
+
6
+ class Download(Base):
7
+ def _getFile(self):
8
+ if not self.fieldname:
9
+ info = IPrimaryFieldInfo(self.context, None)
10
+ if info is None:
11
+ # Ensure that we have at least a filedname
12
+ raise NotFound(self, '', self.request)
13
+ self.fieldname = info.fieldname
14
+ file = info.value
15
+ else:
16
+ context = getattr(self.context, 'aq_explicit', self.context)
17
+ file = getattr(context, self.fieldname, None)
18
+
19
+ if file is None:
20
+ raise NotFound(self, self.fieldname, self.request)
21
+
22
+ return file
@@ -0,0 +1,247 @@
1
+ from functools import partial
2
+ from itertools import takewhile
3
+ from logging import getLogger
4
+
5
+ import openpyxl
6
+ import plone.api as api
7
+ from DateTime import DateTime
8
+ from Products.CMFCore.utils import getToolByName
9
+ from Products.Five.browser import BrowserView
10
+ from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
11
+ from Products.statusmessages.interfaces import IStatusMessage
12
+ from zope.component.hooks import getSite
13
+
14
+ from esdrt.content.roles.localrolesubscriber import grant_local_roles
15
+
16
+ LOG = getLogger("esdrt.content.carryover")
17
+
18
+
19
+ def _read_col(row, nr):
20
+ val = row[nr].value
21
+ return val.strip() if val else val
22
+
23
+
24
+ def _clear_local_roles(obj):
25
+ obj.__ac_local_roles__ = None
26
+
27
+
28
+ def clear_and_grant_roles(obj):
29
+ """Clear any local roles already granted and grant just those
30
+ that make sense in the current review folder context.
31
+
32
+ [refs #105604] This makes sure that users that were granted
33
+ local roles on the old observation will not continue to
34
+ have them (e.g. CounterPart).
35
+ """
36
+ _clear_local_roles(obj)
37
+ grant_local_roles(obj)
38
+
39
+
40
+ def _copy_obj(target, ob, new_id=None):
41
+ orig_ob = ob
42
+ ob_id = new_id or orig_ob.getId()
43
+ ob = ob._getCopy(target)
44
+ ob._setId(ob_id)
45
+ target._setObject(ob_id, ob, suppress_events=True)
46
+ return target[ob_id]
47
+
48
+
49
+ def _copy_and_flag(context, obj, new_id=None):
50
+ _, _, year, index = (new_id or obj.getId()).split("-")
51
+ ob = _copy_obj(context, obj, new_id=new_id)
52
+ ob.carryover_from = year
53
+ ob.review_year = int(year)
54
+
55
+ LOG.info(
56
+ "Copied %s -> %s",
57
+ obj.absolute_url(1),
58
+ ob.absolute_url(1),
59
+ )
60
+
61
+ return ob
62
+
63
+
64
+ def _obj_from_url(context, site_url, url):
65
+ traversable = str(url.split(site_url)[-1][1:])
66
+ return context.unrestrictedTraverse(traversable)
67
+
68
+
69
+ def replace_conclusion_text(workflows, obj, text):
70
+ wft = workflows["tool"]
71
+ in_phase2 = wft.getInfoFor(obj, "review_state").startswith("phase2")
72
+ conclusion = obj.get_conclusion_phase2() if in_phase2 else obj.get_conclusion()
73
+ if text and conclusion:
74
+ conclusion.text = text
75
+
76
+
77
+ def prepend_qa(target, source):
78
+ source_qa = source.get_question()
79
+ target_qa = target.get_question()
80
+
81
+ if source_qa and target_qa:
82
+ for comment in list(source_qa.values()):
83
+ _copy_obj(target_qa, comment)
84
+
85
+ ordering = target_qa.getOrdering()
86
+ ordering.orderObjects(key="creation_date")
87
+
88
+ elif source_qa and not target_qa:
89
+ _copy_obj(target, source_qa)
90
+
91
+
92
+ def add_to_wh(wf, obj, action, state, actor):
93
+ wh = obj.workflow_history
94
+ wf_id = wf.getId()
95
+ wh[wf_id] = tuple(wh[wf_id]) + (
96
+ {
97
+ "comments": "Carryover force state",
98
+ "actor": actor,
99
+ "time": DateTime(),
100
+ "action": action,
101
+ "review_state": state,
102
+ },
103
+ )
104
+ wf.updateRoleMappingsFor(obj)
105
+
106
+
107
+ def reopen_with_qa(workflows, obj, actor):
108
+ wft = workflows["tool"]
109
+ in_phase2 = wft.getInfoFor(obj, "review_state").startswith("phase2")
110
+
111
+ action_obj = "phase1-reopen"
112
+ action_question = "phase1-reopen"
113
+ new_state_obj = "phase1-carried-over"
114
+ new_state_question = "phase1-draft"
115
+
116
+ add_to_wh(workflows["observation"], obj, action_obj, new_state_obj, actor)
117
+ question = obj.get_question()
118
+ if question:
119
+ add_to_wh(
120
+ workflows["question"],
121
+ question,
122
+ action_question,
123
+ new_state_question,
124
+ actor,
125
+ )
126
+
127
+ if in_phase2:
128
+ wf_conclusion = workflows["conclusion2"]
129
+ conclusion = obj.get_conclusion_phase2()
130
+ else:
131
+ wf_conclusion = workflows["conclusion"]
132
+ conclusion = obj.get_conclusion()
133
+
134
+ if conclusion:
135
+ add_to_wh(wf_conclusion, conclusion, "redraft", "draft", actor)
136
+
137
+
138
+ def override_owner(obj, owner):
139
+ if owner:
140
+ user = api.portal.get_tool("acl_users").getUserById(owner)
141
+ if user:
142
+ userid = user.getId()
143
+ obj.changeOwnership(user)
144
+ obj.setCreators([userid])
145
+ obj.manage_setLocalRoles(
146
+ userid,
147
+ [
148
+ "Owner",
149
+ ],
150
+ )
151
+
152
+
153
+ def catalog_with_children(catalog, obj):
154
+ catalog.catalog_object(obj)
155
+ for child in obj.objectValues():
156
+ catalog_with_children(catalog, child)
157
+
158
+
159
+ def copy_direct(context, catalog, workflows, obj_from_url, row):
160
+ source = _read_col(row, 0)
161
+ conclusion_text = _read_col(row, 1)
162
+ actor = _read_col(row, 2)
163
+ owner = _read_col(row, 3)
164
+
165
+ obj = obj_from_url(source)
166
+ ob = _copy_and_flag(context, obj)
167
+ override_owner(ob, owner)
168
+
169
+ replace_conclusion_text(workflows, ob, conclusion_text)
170
+ clear_and_grant_roles(ob)
171
+ reopen_with_qa(workflows, ob, actor, has_step2=context.enable_steps)
172
+
173
+ catalog_with_children(catalog, ob)
174
+
175
+
176
+ def copy_complex(context, catalog, workflows, obj_from_url, row):
177
+ source = _read_col(row, 0)
178
+ older_source = _read_col(row, 1)
179
+ conclusion_text = _read_col(row, 2)
180
+ actor = _read_col(row, 3)
181
+ owner = _read_col(row, 4)
182
+
183
+ obj = obj_from_url(source)
184
+ older_obj = obj_from_url(older_source)
185
+
186
+ ob = _copy_and_flag(context, obj, older_obj.getId())
187
+ override_owner(ob, owner)
188
+
189
+ replace_conclusion_text(workflows, ob, conclusion_text)
190
+ prepend_qa(ob, older_obj)
191
+ clear_and_grant_roles(ob)
192
+ reopen_with_qa(workflows, ob, actor, has_step2=context.enable_steps)
193
+
194
+ catalog_with_children(catalog, ob)
195
+
196
+
197
+ class CarryOverView(BrowserView):
198
+ index = ViewPageTemplateFile("templates/carryover.pt")
199
+
200
+ def __call__(self):
201
+ return self.index()
202
+
203
+ def start(self, action, xls):
204
+ portal = getSite()
205
+ wb = openpyxl.load_workbook(xls, read_only=True, data_only=True)
206
+ sheet = wb.worksheets[0]
207
+
208
+ sheet_rows = sheet.rows
209
+ next(sheet_rows) # skip first row (header)
210
+ # extract rows with values
211
+ valid_rows = tuple(takewhile(lambda row: any(c.value for c in row), sheet_rows))
212
+
213
+ context = self.context
214
+ site_url = portal.absolute_url()
215
+ obj_from_url = partial(_obj_from_url, context, site_url)
216
+ catalog = getToolByName(portal, "portal_catalog")
217
+ wft = getToolByName(portal, "portal_workflow")
218
+
219
+ wf_obs = wft.getWorkflowById(wft.getChainFor("Observation")[0])
220
+ wf_question = wft.getWorkflowById(wft.getChainFor("Question")[0])
221
+ wf_conclusion = wft.getWorkflowById(wft.getChainFor("Conclusion")[0])
222
+ wf_conclusion2 = wft.getWorkflowById(wft.getChainFor("ConclusionsPhase2")[0])
223
+
224
+ actions = dict(direct=copy_direct, complex=copy_complex)
225
+ workflows = dict(
226
+ tool=wft,
227
+ observation=wf_obs,
228
+ question=wf_question,
229
+ conclusion=wf_conclusion,
230
+ conclusion2=wf_conclusion2,
231
+ )
232
+ copy_func = partial(
233
+ actions[action],
234
+ context,
235
+ catalog,
236
+ workflows,
237
+ obj_from_url,
238
+ )
239
+
240
+ for row in valid_rows:
241
+ copy_func(row)
242
+
243
+ if len(valid_rows) > 0:
244
+ (IStatusMessage(self.request).add("Carryover successfull!", type="info"))
245
+ else:
246
+ (IStatusMessage(self.request).add("No data provided!", type="warn"))
247
+ self.request.RESPONSE.redirect(context.absolute_url())
@@ -0,0 +1,22 @@
1
+ from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
2
+ from plone.app.discussion.browser.comments import CommentForm as BaseForm
3
+ from plone.app.discussion.browser.comments import CommentsViewlet as BaseViewlet
4
+
5
+
6
+ class CommentForm(BaseForm):
7
+
8
+ def updateWidgets(self):
9
+ super(CommentForm, self).updateWidgets()
10
+ self.widgets['text'].rows = 15
11
+
12
+ def updateActions(self):
13
+ super(CommentForm, self).updateActions()
14
+ self.actions['comment'].title = 'Save Comment'
15
+ for k in list(self.actions.keys()):
16
+ self.actions[k].addClass('standardButton')
17
+ self.actions[k].addClass('defaultWFButton')
18
+
19
+
20
+ class CommentsViewlet(BaseViewlet):
21
+ index = ViewPageTemplateFile("./templates/comments.pt")
22
+ form = CommentForm
@@ -0,0 +1,233 @@
1
+ <configure
2
+ xmlns="http://namespaces.zope.org/zope"
3
+ xmlns:browser="http://namespaces.zope.org/browser"
4
+ xmlns:i18n="http://namespaces.zope.org/i18n"
5
+ i18n_domain="esdrt.content">
6
+
7
+ <!-- -*- extra stuff goes here -*- -->
8
+
9
+ <browser:page
10
+ name="tableau_dashboard"
11
+ for="..reviewfolder.IReviewFolder"
12
+ class=".tableau.DashboardView"
13
+ permission="zope2.View"
14
+ />
15
+
16
+ <browser:page
17
+ name="view"
18
+ for="..reviewfolder.IReviewFolder"
19
+ class="..reviewfolder.ReviewFolderView"
20
+ permission="zope2.View"
21
+ template="templates/reviewfolderview.pt"
22
+ />
23
+
24
+ <browser:page
25
+ name="reindex_context"
26
+ for="*"
27
+ class=".management.ReindexContext"
28
+ permission="cmf.ManagePortal"
29
+ />
30
+
31
+ <browser:page
32
+ name="fix_carryover_2026"
33
+ for="*"
34
+ class=".management.FixCarryover"
35
+ permission="cmf.ManagePortal"
36
+ />
37
+
38
+ <browser:page
39
+ name="get_table"
40
+ for="..reviewfolder.IReviewFolder"
41
+ class="..reviewfolder.ReviewFolderBrowserView"
42
+ permission="zope2.View"
43
+ attribute="render"
44
+ />
45
+
46
+ <browser:page
47
+ name="export_as_xls"
48
+ for="..reviewfolder.IReviewFolder"
49
+ class="..reviewfolder.ExportReviewFolderFormView"
50
+ permission="esdrt.content.ExportObservations"
51
+ />
52
+
53
+ <browser:page
54
+ name="inboxview"
55
+ for="..reviewfolder.IReviewFolder"
56
+ class="..reviewfolder.InboxReviewFolderView"
57
+ permission="zope2.View"
58
+ template="templates/inboxreviewfolderview.pt"
59
+ />
60
+
61
+ <browser:page
62
+ name="finalisedfolderview"
63
+ for="..reviewfolder.IReviewFolder"
64
+ class="..reviewfolder.FinalisedFolderView"
65
+ permission="zope2.View"
66
+ template="templates/finalisedfolderview.pt"
67
+ />
68
+
69
+ <browser:page
70
+ name="assign_counterpart_form"
71
+ for="..question.IQuestion"
72
+ class=".statechange.AssignCounterPartForm"
73
+ permission="zope2.View"
74
+ />
75
+
76
+ <browser:page
77
+ name="reassign_counterpart_form"
78
+ for="..question.IQuestion"
79
+ class=".statechange.ReAssignCounterPartForm"
80
+ permission="zope2.View"
81
+ />
82
+
83
+ <browser:page
84
+ name="assign_answerer_form"
85
+ for="..question.IQuestion"
86
+ class=".statechange.AssignAnswererForm"
87
+ permission="zope2.View"
88
+ />
89
+
90
+ <browser:page
91
+ name="select-new-mse"
92
+ for="..question.IQuestion"
93
+ class=".statechange.ReAssignMSExpertsForm"
94
+ permission="zope2.View"
95
+ />
96
+
97
+ <browser:page
98
+ name="request-redraft"
99
+ for="..question.IQuestion"
100
+ class=".statechange.RequestRedraftReasonForm"
101
+ permission="zope2.View"
102
+ />
103
+
104
+ <browser:page
105
+ name="assign_conclusion_reviewer_form"
106
+ for="..observation.IObservation"
107
+ class=".statechange.AssignConclusionReviewerForm"
108
+ permission="zope2.View"
109
+ />
110
+
111
+
112
+ <browser:page
113
+ name="request-finish-observation"
114
+ for="..observation.IObservation"
115
+ class=".statechange.FinishObservationReasonForm"
116
+ permission="zope2.View"
117
+ />
118
+
119
+ <browser:page
120
+ name="deny-finish-observation"
121
+ for="..observation.IObservation"
122
+ class=".statechange.DenyFinishObservationReasonForm"
123
+ permission="zope2.View"
124
+ />
125
+
126
+ <browser:viewletManager
127
+ name="esdrt.content.commentmanager"
128
+ provides=".interfaces.ICommentDiscussion"
129
+ permission="zope2.View"
130
+ class="plone.app.viewletmanager.manager.BaseOrderedViewletManager"
131
+ />
132
+
133
+
134
+ <browser:viewlet
135
+ name="plone.comments"
136
+ for="..comment.IComment"
137
+ layer="plone.app.discussion.interfaces.IDiscussionLayer"
138
+ manager=".interfaces.ICommentDiscussion"
139
+ view="plone.app.layout.globals.interfaces.IViewView"
140
+ class=".comments.CommentsViewlet"
141
+ permission="esdrt.content.ViewCommentDiscussion"
142
+ />
143
+
144
+ <browser:viewlet
145
+ name="plone.comments"
146
+ for="..commentanswer.ICommentAnswer"
147
+ layer="plone.app.discussion.interfaces.IDiscussionLayer"
148
+ manager=".interfaces.ICommentDiscussion"
149
+ view="plone.app.layout.globals.interfaces.IViewView"
150
+ class=".comments.CommentsViewlet"
151
+ permission="esdrt.content.ViewAnswerDiscussion"
152
+ />
153
+
154
+ <browser:viewlet
155
+ name="plone.comments"
156
+ for="..conclusion.IConclusion"
157
+ layer="plone.app.discussion.interfaces.IDiscussionLayer"
158
+ manager=".interfaces.ICommentDiscussion"
159
+ view="plone.app.layout.globals.interfaces.IViewView"
160
+ class=".comments.CommentsViewlet"
161
+ permission="esdrt.content.ViewConclusionDiscussion"
162
+ />
163
+
164
+ <browser:viewlet
165
+ name="plone.comments"
166
+ for="..conclusionsphase2.IConclusionsPhase2"
167
+ layer="plone.app.discussion.interfaces.IDiscussionLayer"
168
+ manager=".interfaces.ICommentDiscussion"
169
+ view="plone.app.layout.globals.interfaces.IViewView"
170
+ class=".comments.CommentsViewlet"
171
+ permission="esdrt.content.ViewConclusionDiscussion"
172
+ />
173
+
174
+ <browser:page
175
+ name="download"
176
+ for="plone.app.discussion.interfaces.IComment"
177
+ class=".attachmentdownload.Download"
178
+ permission="zope2.View"
179
+ />
180
+
181
+ <browser:page
182
+ name="manage_forcing_workflow_state"
183
+ for="*"
184
+ class=".statechange.UpdateWorkflow"
185
+ permission="cmf.ManagePortal"
186
+ />
187
+
188
+ <browser:page
189
+ name="observation_import_form"
190
+ for="esdrt.content.reviewfolder.IReviewFolder"
191
+ template="templates/import_observation.pt"
192
+ permission="cmf.ManagePortal"
193
+ />
194
+
195
+ <browser:page
196
+ name="observation_import"
197
+ for="esdrt.content.reviewfolder.IReviewFolder"
198
+ class=".observation_import.ObservationXLSImport"
199
+ attribute="do_import"
200
+ permission="cmf.ManagePortal"
201
+ />
202
+
203
+ <browser:page
204
+ name="get_sample_xls"
205
+ for="esdrt.content.reviewfolder.IReviewFolder"
206
+ class=".get_sample_xls.GetSampleXLS"
207
+ permission="cmf.ManagePortal"
208
+ />
209
+
210
+ <browser:page
211
+ name="macros"
212
+ for="..reviewfolder.IReviewFolder"
213
+ template="templates/macros.pt"
214
+ class=".macros.MacrosView"
215
+ permission="zope2.View"
216
+ />
217
+
218
+ <browser:page
219
+ name="carryover-form"
220
+ for="esdrt.content.reviewfolder.IReviewFolder"
221
+ class=".carryover.CarryOverView"
222
+ permission="cmf.ManagePortal"
223
+ />
224
+
225
+ <browser:page
226
+ name="carryover"
227
+ for="esdrt.content.reviewfolder.IReviewFolder"
228
+ class=".carryover.CarryOverView"
229
+ permission="cmf.ManagePortal"
230
+ attribute="start"
231
+ />
232
+
233
+ </configure>
@@ -0,0 +1,22 @@
1
+ from Acquisition import aq_inner
2
+ from Acquisition import aq_parent
3
+ from Products.Five import BrowserView
4
+
5
+
6
+ class CopyFileToAnswer(BrowserView):
7
+
8
+ def render(self):
9
+ context = aq_inner(self.context)
10
+ conversation = aq_parent(context)
11
+ answer = aq_parent(conversation)
12
+ file = getattr(context, 'attachment', None)
13
+ candidate_id = file.filename
14
+ while candidate_id in list(answer.keys()):
15
+ candidate_id += '-1'
16
+
17
+ filename = answer.invokeFactory(
18
+ id=candidate_id,
19
+ type_name='ESDRTFile',
20
+ file=file,
21
+ )
22
+ return self.request.response.redirect(context.absolute_url())