Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
707d106
Add content_review behavior
jnptk Feb 13, 2026
0b36d0c
Add vocabularies
jnptk Feb 13, 2026
a991d9b
Fix fieldset not showing
jnptk Feb 17, 2026
c77642d
Wording & stuff
jnptk Feb 17, 2026
848b12f
Add behavior to all default content types
jnptk Feb 17, 2026
94e4902
Add upgrade step
jnptk Feb 17, 2026
d70117f
make format
jnptk Feb 17, 2026
6d47850
Add content_review_default_interval setting to intranet controlpanel
jnptk Feb 18, 2026
417568c
Directly access vocabularies without directives.widget
jnptk Feb 18, 2026
1137d82
Add basic review endpoint
jnptk Feb 18, 2026
8a5b166
Update service permission & allowed context
jnptk Feb 19, 2026
7341f10
Add plone.app.registry to upgrade step
jnptk Feb 19, 2026
d382f08
Remove unused import
jnptk Feb 19, 2026
ca04888
Fix context & update error messages
jnptk Feb 19, 2026
8d7dbb4
Remove unused import
jnptk Feb 19, 2026
1ac5bb6
Add review_status and review_due_date indexes
jnptk Feb 19, 2026
4d939ea
Update upgrade step
jnptk Feb 19, 2026
4696fef
Add querystring criterion
jnptk Feb 19, 2026
c22de8b
Merge branch 'main' into content-review
jnptk Feb 20, 2026
d04b534
Fix upgrade step after merging main
jnptk Feb 20, 2026
e831fd1
Add import step for review_due_date indexer
jnptk Feb 20, 2026
bd7bf93
Add invariant & review_enabled, title & description in fields
jnptk Feb 24, 2026
cb4ab7f
Fix querystring thingie
jnptk Feb 24, 2026
2df48b4
Merge branch 'main' into content-review
jnptk Feb 24, 2026
4d84607
Fix querystring again
jnptk Feb 24, 2026
636ff24
Add default review intervals
jnptk Feb 25, 2026
e615c82
Set default review intervals
jnptk Feb 25, 2026
62fd42e
Implement "approve", "delegate" and "postpone" action in review endpo…
jnptk Feb 25, 2026
18f51ae
First batch of tests
jnptk Feb 25, 2026
c9ee28f
Merge branch 'main' into content-review
jnptk Feb 26, 2026
7cfd169
Set review_comment to readonly
jnptk Feb 26, 2026
3a5ec4a
Require review_interval, set default & default to setting
jnptk Feb 26, 2026
120b14d
Bind to behavior & get vocab from field
jnptk Feb 26, 2026
c2cdb6f
Fix fti test
jnptk Feb 26, 2026
44a4f6a
Add test for content_review_intervals vocabulary
jnptk Feb 26, 2026
d7e99c5
How-To guide (wip)
jnptk Feb 27, 2026
57a27e7
Merge branch 'main' into content-review
jnptk Mar 5, 2026
e574255
Fix upgrade step after merge
jnptk Mar 5, 2026
92747f9
Fix profile version
jnptk Mar 5, 2026
179da61
Combine upgrade steps & move calc_due_date to utils
jnptk Mar 6, 2026
6dbdd79
Formatting
jnptk Mar 6, 2026
c5ea73c
Add script to send a mail if a content objects is due to review
jnptk Mar 6, 2026
49b789a
Merge branch 'main' into content-review
jnptk Mar 17, 2026
5aa11df
Fix version after merge
jnptk Mar 17, 2026
95a9861
Fix upgrade step
jnptk Mar 17, 2026
7da59e8
Send mail in review_reminder script
jnptk Mar 17, 2026
30792fc
Set default review_due_date to today
jnptk Mar 17, 2026
96837ec
Add changelog entries
jnptk Mar 17, 2026
e40467d
Fix [at]review endpoint tests
jnptk Mar 17, 2026
eedb6f2
Properly calculate review_due_date
jnptk Mar 18, 2026
884c7e3
Fix [at]review endpoint to set values persistently
jnptk Mar 18, 2026
e0c31db
More test for [at]review endpoint
jnptk Mar 18, 2026
67575b6
Merge remote-tracking branch 'origin/main' into content-review
davisagli Apr 1, 2026
6287e39
Remove .python-version (duplicates requires-python in pyproject.toml)
davisagli Apr 1, 2026
ab526b9
fix bad merge of upgrade steps
davisagli Apr 1, 2026
1bc3cf3
add review querystring criteria
jnptk Apr 2, 2026
624e311
return record directly in default_review_interval
jnptk Apr 2, 2026
7b2443d
off source reminder email for better testability
jnptk Apr 2, 2026
5f84081
update default review intervals based of lo-fi design
jnptk Apr 2, 2026
2df56db
shorten [at]review reply
jnptk Apr 2, 2026
bf140a6
remove content_review_users vocab test
jnptk Apr 2, 2026
b306b25
assert full vocab in test
jnptk Apr 2, 2026
808c8f4
make format
jnptk Apr 2, 2026
25c20c6
fixes for notify_reviewer
jnptk Apr 7, 2026
881f23b
add path to warning if no user was found
jnptk Apr 7, 2026
2741b54
test calc_due_date
jnptk Apr 7, 2026
231d72b
remove context aware factory (no context needed = no factory needed)
jnptk Apr 7, 2026
d1a6400
fix defaultFactory
davisagli Apr 7, 2026
58a3bd5
Hacky override to get the UI working, we can make it better later
davisagli Apr 7, 2026
f1fdfac
Merge remote-tracking branch 'origin/main' into content-review
davisagli Apr 7, 2026
36bfd5f
Work around bug in plone.restapi that calls defaultFactory with a con…
davisagli Apr 7, 2026
08df685
fix acceptance test
davisagli Apr 7, 2026
2d9a4ba
Remove unneeded explicit commits, disable CSRF protection
davisagli Apr 8, 2026
1d68403
rename doc in service test
jnptk Apr 8, 2026
b93b2c6
add docs for [at]review endpoint
jnptk Apr 9, 2026
c6d63a9
i18n
Tishasoumya-02 Apr 21, 2026
be24f80
Merge branch 'content-review' of github.com:kitconcept/kitconcept.int…
Tishasoumya-02 Apr 21, 2026
6da18b8
don't allow pastDates
Tishasoumya-02 Apr 22, 2026
01553e3
fix lint
Tishasoumya-02 Apr 22, 2026
8759f1b
fix scss lint
Tishasoumya-02 Apr 22, 2026
2bda500
replace semantic-ui with plone-components and other fixes
Tishasoumya-02 Apr 28, 2026
8c1cd21
fix lint
Tishasoumya-02 Apr 28, 2026
a21dcd1
make i18n
Tishasoumya-02 Apr 28, 2026
d99cc6b
lint
Tishasoumya-02 Apr 28, 2026
c76f880
update with main
Tishasoumya-02 Apr 28, 2026
ea751fe
fix styleint
Tishasoumya-02 Apr 28, 2026
a115359
Merge branch 'main' into content-review
Tishasoumya-02 Apr 29, 2026
1d1b3be
update with main
Tishasoumya-02 May 4, 2026
6d9acc4
update accordion export
Tishasoumya-02 May 4, 2026
42d58c8
update form customization to updated form code from volto with autosa…
Tishasoumya-02 May 4, 2026
ddd8604
merge with 'main' into content-review
Tishasoumya-02 Jun 2, 2026
7614b2b
update lockfile
Tishasoumya-02 Jun 2, 2026
12d6904
fix merge conflict in locales
Tishasoumya-02 Jun 3, 2026
4eafc8c
remove the customised components and add the styling
Tishasoumya-02 Jun 4, 2026
42d025d
fix lint and stylelint
Tishasoumya-02 Jun 4, 2026
0754d92
fix
Tishasoumya-02 Jun 4, 2026
405981a
fix
Tishasoumya-02 Jun 4, 2026
6873b9a
Merge branch 'main' into content-review
Tishasoumya-02 Jun 4, 2026
762f6eb
remove onClose prop from DocumentReview component
Tishasoumya-02 Jun 4, 2026
c2d5267
Merge branch 'content-review' of github.com:kitconcept/kitconcept.int…
Tishasoumya-02 Jun 4, 2026
c83a0b7
improve code
iFlameing Jun 8, 2026
41f2f77
add feature flag to toggle the feature on and off
iFlameing Jun 11, 2026
9ad860c
Merge branch 'main' into content-review
iFlameing Jun 11, 2026
1b367f7
update pnpm-lock.yaml
jnptk Jun 15, 2026
b7d8924
integrate review_reminder script into docker using swarm-cronjob
jnptk Jun 15, 2026
07d285c
Merge branch 'main' into content-review
Tishasoumya-02 Jun 16, 2026
6f23570
integrate review_reminder script in demo & persistent stacks
jnptk Jun 17, 2026
9197d57
add docs for configuring the reminder script
jnptk Jun 17, 2026
d12a17e
Merge branch 'main' into content-review
iFlameing Jun 18, 2026
9156591
remove swarm-cronjob from demo.yml
jnptk Jun 19, 2026
9b7a8b4
make sure backend-cron-worker service connects to the same db as back…
jnptk Jun 19, 2026
78bb36d
update docs
jnptk Jun 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/news/330.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implemented content review & reminders features. @jntpk
10 changes: 10 additions & 0 deletions backend/scripts/review_reminder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from kitconcept.intranet.utils.review_due_notifier import nofity_reviewer
from plone import api
from zope.component.hooks import setSite


portal = app.Plone
setSite(portal)

with api.env.adopt_roles(["Manager"]):
nofity_reviewer(portal)
7 changes: 7 additions & 0 deletions backend/src/kitconcept/intranet/behaviors/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@
provides=".person.IPersonBehavior"
/>

<plone:behavior
name="kitconcept.intranet.content_review"
title="CLM: Reminders for potentially outdated content"
description="Fields for reviewing content (part of CLM)"
provides=".content_review.IContentReview"
/>

<utility
factory=".person.AcademicTitleFirstLastName"
name="academic_title_first_last"
Expand Down
96 changes: 96 additions & 0 deletions backend/src/kitconcept/intranet/behaviors/content_review.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from kitconcept.intranet import _
from kitconcept.intranet.utils.calc_due_date import calc_due_date
from plone import api
from plone.autoform.interfaces import IFormFieldProvider
from plone.supermodel import model
from zope import schema
from zope.interface import Invalid
from zope.interface import invariant
from zope.interface import provider
from zope.schema.interfaces import IContextAwareDefaultFactory


@provider(IContextAwareDefaultFactory)
def default_review_interval(context) -> str:
return api.portal.get_registry_record(
"kitconcept.intranet.content_review_default_interval"
)


@provider(IFormFieldProvider)
class IContentReview(model.Schema):
"""Content Review behavior"""

model.fieldset(
"Content Review & Reminders",
label=_("label_review_fieldset", "Content Review & Reminders"),
fields=[
"review_timeless",
"review_status",
"review_interval",
"review_assignee",
"review_due_date",
"review_completed_date",
],
)

review_timeless = schema.Bool(
title=_(
"label_review_timeless",
default="Timeless content - exclude from review reminders",
),
required=False,
default=False,
)

review_status = schema.Choice(
title=_("label_review_status", default="Status"),
values=("Up-to-date", "Due", "Changes requested"),
default="Up-to-date",
required=False,
readonly=True,
Comment thread
davisagli marked this conversation as resolved.
)

review_interval = schema.Choice(
title=_("label_review_interval", default="Review Interval"),
vocabulary="kitconcept.intranet.vocabularies.content_review_intervals",
required=False,
defaultFactory=default_review_interval,
)

review_assignee = schema.Choice(
title=_("label_review_assignee", default="Reviewer"),
description=_(
"help_review_assignee",
default="... will be notified as soon as the review is due. Unless otherwise specified, the content owner is considered the responsible person.",
),
vocabulary="plone.app.vocabularies.Users",
required=False,
)

review_due_date = schema.Date(
title=_("label_review_due_date", default="Next review on"),
required=False,
defaultFactory=calc_due_date,
)

review_completed_date = schema.Date(
title=_("label_review_completed_date", default="Last review on"),
required=False,
readonly=True,
)

review_comment = schema.Text(
title=_("label_review_comment", default="Comment"),
required=False,
Comment thread
jnptk marked this conversation as resolved.
readonly=True,
)

@invariant
def validate_due_date_field(data):
is_timeless = getattr(data, "review_timeless", False)
has_due_date = getattr(data, "review_due_date", None)
if not is_timeless and not has_due_date:
raise Invalid("You have to set a due date if the content is not timeless")
elif is_timeless and has_due_date:
raise Invalid("Cannot set due date if content is timeless")
17 changes: 17 additions & 0 deletions backend/src/kitconcept/intranet/controlpanels/intranet.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,20 @@ class IIntranetSettings(Interface):
defaultFactory=list,
)

enable_content_review = schema.Bool(
title=_("Enable Content Review"),
description=_("Enable content review reminders globally for the Intranet."),
required=False,
default=False,
)

content_review_default_interval = schema.Choice(
title=_("Default review interval"),
vocabulary="kitconcept.intranet.vocabularies.content_review_intervals",
required=True,
default="6m",
)
Comment thread
jnptk marked this conversation as resolved.


class IntranetSettingsEditForm(RegistryEditForm):
schema = IIntranetSettings
Expand Down Expand Up @@ -140,3 +154,6 @@ def __call__(self, data):
data["kitconcept.intranet.enable_content_rating"] = (
settings.enable_content_rating
)
data["kitconcept.intranet.enable_content_review"] = (
settings.enable_content_review
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2026-02-25 14:14+0000\n"
"POT-Creation-Date: 2026-06-11 08:48+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand Down Expand Up @@ -40,7 +40,7 @@ msgstr "Akademischer Titel"

#: kitconcept/intranet/behaviors/person.py:66
msgid "Academic Title, First and Last Name"
msgstr ""
msgstr "Akademischer Titel, Vor- und Nachname"

#: kitconcept/intranet/behaviors/configure.zcml:49
msgid "Add the intranet-specific person fields"
Expand All @@ -62,6 +62,10 @@ msgstr "Zulässige E-Mail-Domains"
msgid "Allowed Iframe Domains"
msgstr "Zulässige Iframe-Domains"

#: kitconcept/intranet/behaviors/configure.zcml:56
msgid "CLM: Reminders for potentially outdated content"
msgstr "CLM: Hinweise auf möglicherweise veraltete Inhalte"

#: kitconcept/intranet/profiles/default/workflows/simple_intranet_workflow/definition.xml
#: kitconcept/intranet/profiles/restricted/workflows/simple_intranet_workflow/definition.xml
msgid "Can only be seen and edited by the owner."
Expand All @@ -71,6 +75,10 @@ msgstr "Kann nur vom Eigentümer angesehen und bearbeitet werden."
msgid "Default Feedback Email"
msgstr "Standard-Feedback-E-Mail"

#: kitconcept/intranet/controlpanels/intranet.py:98
msgid "Default review interval"
msgstr "Standard-Überprüfungsintervall"

#: kitconcept/intranet/behaviors/person.py:30
msgid "Department"
msgstr "Abteilung"
Expand All @@ -96,6 +104,10 @@ msgstr "E-Mail-Adresse, die in Feedback-Formularen verwendet wird, wenn keine an
msgid "Enable Content Rating"
msgstr "Inhaltsbewertung aktivieren"

#: kitconcept/intranet/controlpanels/intranet.py:91
msgid "Enable Content Review"
msgstr "Inhaltsprüfung aktivieren"

#: kitconcept/intranet/behaviors/votes.py:23
msgid "Enable Likes"
msgstr "Likes aktivieren"
Expand All @@ -112,10 +124,30 @@ msgstr "Sticky-Feedback-Button aktivieren"
msgid "Enable content rating globally for the Intranet"
msgstr "Inhaltsbewertung für das Intranet global aktivieren"

#: kitconcept/intranet/controlpanels/intranet.py:92
msgid "Enable content review reminders globally for the Intranet."
msgstr "Aktivieren Sie die Erinnerungen zur Inhaltsüberprüfung für das gesamte Intranet."

#: kitconcept/intranet/controlpanels/intranet.py:68
msgid "Enable or disable the sticky feedback button on all pages."
msgstr "Aktivieren oder deaktivieren Sie die Sticky-Feedback-Schaltfläche auf allen Seiten."

#: kitconcept/intranet/vocabularies/content_review.py:12
msgid "Every 2 years"
msgstr "Alle 2 Jahre"

#: kitconcept/intranet/vocabularies/content_review.py:9
msgid "Every 3 months"
msgstr "Alle 3 Monate"

#: kitconcept/intranet/vocabularies/content_review.py:10
msgid "Every 6 months"
msgstr "Alle 6 Monate"

#: kitconcept/intranet/vocabularies/content_review.py:11
msgid "Every year"
msgstr "Jedes Jahr"

#: kitconcept/intranet/controlpanels/intranet.py:21
msgid "External Search URL"
msgstr "Externe Such-URL"
Expand All @@ -132,6 +164,10 @@ msgstr "Felder für Standort"
msgid "Fields for Organisational Unit"
msgstr "Felder für Organisationseinheit"

#: kitconcept/intranet/behaviors/configure.zcml:56
msgid "Fields for reviewing content (part of CLM)"
msgstr "Felder zur Überprüfung von Inhalten (Teil von CLM)"

#: kitconcept/intranet/profiles/default/workflows/simple_intranet_workflow/definition.xml
#: kitconcept/intranet/profiles/restricted/workflows/simple_intranet_workflow/definition.xml
msgid "If you submitted the item by mistake or want to perform additional edits, this will take it back."
Expand All @@ -145,7 +181,7 @@ msgstr "Öffentlicher Intranet-Workflow"
msgid "Intranet Restricted Workflow"
msgstr "Intranet-beschränkter Workflow"

#: kitconcept/intranet/controlpanels/intranet.py:93
#: kitconcept/intranet/controlpanels/intranet.py:107
msgid "Intranet Settings"
msgstr "Intranet-Einstellungen"

Expand All @@ -167,7 +203,7 @@ msgstr "Lebenszyklusmanagement-Felder"

#: kitconcept/intranet/behaviors/votes.py:10
msgid "Likes"
msgstr ""
msgstr "Likes"

#: kitconcept/intranet/controlpanels/intranet.py:61
msgid "List of allowed email domains for feedback forms."
Expand All @@ -178,7 +214,7 @@ msgid "List of user IDs"
msgstr "Liste der Benutzer-IDs"

#: kitconcept/intranet/behaviors/configure.zcml:28
#: kitconcept/intranet/behaviors/location.py:19
#: kitconcept/intranet/behaviors/location.py:18
#: kitconcept/intranet/profiles/default/types/Location.xml
msgid "Location"
msgstr "Standort"
Expand All @@ -198,7 +234,7 @@ msgid "No responsible person or default feedback email is configured. Please con
msgstr "Es ist keine verantwortliche Person oder Standard-Feedback-E-Mail konfiguriert. Bitte wenden Sie sich an den Website-Administrator."

#: kitconcept/intranet/behaviors/configure.zcml:35
#: kitconcept/intranet/behaviors/organisational_unit.py:19
#: kitconcept/intranet/behaviors/organisational_unit.py:18
#: kitconcept/intranet/profiles/default/types/Organisational_Unit.xml
msgid "Organisational Unit"
msgstr "Organisationseinheit"
Expand Down Expand Up @@ -266,6 +302,10 @@ msgstr "Stellt Ihren Artikel in eine Überprüfungswarteschlange, damit er auf d
msgid "Retract"
msgstr "Zurückziehen"

#: kitconcept/intranet/profiles/default/registry/querystring.xml
msgid "Review"
msgstr "Rezension"

#: kitconcept/intranet/profiles/default/workflows/simple_intranet_workflow/definition.xml
#: kitconcept/intranet/profiles/restricted/workflows/simple_intranet_workflow/definition.xml
msgid "Reviewer publishes content"
Expand Down Expand Up @@ -369,7 +409,17 @@ msgstr "Nach Standort filtern"
#. Default: "Filter by responsibilities"
#: kitconcept/intranet/profiles/default/registry/querystring.xml
msgid "help_responsibilities_filter"
msgstr ""
msgstr "Nach Aufgaben filtern"

#. Default: "... will be notified as soon as the review is due. Unless otherwise specified, the content owner is considered the responsible person."
#: kitconcept/intranet/behaviors/content_review.py:63
msgid "help_review_assignee"
msgstr "... wird benachrichtigt, sobald die Überprüfung fällig ist. Sofern nicht anders angegeben, gilt der Inhaber der Inhalte als verantwortliche Person."

#. Default: "Filter by review status"
#: kitconcept/intranet/profiles/default/registry/querystring.xml
msgid "help_review_status_filter"
msgstr "Nach Prüfstatus filtern"

#. Default: "Describe what others can contact you about. Focus on topics, tasks, or questions you are responsible for, such as advising on specific funding programs, supporting application processes, or clarifying formal requirements. Write in a way that allows colleagues without detailed organisational knowledge to understand whether you are the right contact."
#: kitconcept/intranet/behaviors/person.py:46
Expand Down Expand Up @@ -428,6 +478,47 @@ msgstr "Zuständigkeiten"
msgid "label_responsible"
msgstr "Inhaltseigentümer:"

#. Default: "Reviewer"
#: kitconcept/intranet/behaviors/content_review.py:62
msgid "label_review_assignee"
msgstr "Rezensent"

#. Default: "Comment"
#: kitconcept/intranet/behaviors/content_review.py:84
msgid "label_review_comment"
msgstr "Kommentar"

#. Default: "Last review on"
#: kitconcept/intranet/behaviors/content_review.py:78
msgid "label_review_completed_date"
msgstr "Zuletzt überprüft am"

#. Default: "Next review on"
#: kitconcept/intranet/behaviors/content_review.py:72
msgid "label_review_due_date"
msgstr "Nächste Rezension zu"

#. Default: "Content Review & Reminders"
#: kitconcept/intranet/behaviors/content_review.py:26
msgid "label_review_fieldset"
msgstr "Inhaltsüberprüfung und Erinnerungen"

#. Default: "Review Interval"
#: kitconcept/intranet/behaviors/content_review.py:55
msgid "label_review_interval"
msgstr "Überprüfungsintervall"

#. Default: "Status"
#: kitconcept/intranet/behaviors/content_review.py:47
#: kitconcept/intranet/profiles/default/registry/querystring.xml
msgid "label_review_status"
msgstr "Status"

#. Default: "Timeless content - exclude from review reminders"
#: kitconcept/intranet/behaviors/content_review.py:38
msgid "label_review_timeless"
msgstr "Zeitlose Inhalte – von Überprüfungserinnerungen ausschließen"

#. Default: "Responsibilities & Expertise"
#: kitconcept/intranet/behaviors/person.py:37
msgid "label_schema_responsibility_categorization"
Expand Down
Loading
Loading