feat: Digest mail notifications settings drawer - EXO-89484 - eXIP7.3.0.22 - #6027
Conversation
|
Update — the two category providers became configuration. The categories SPI moved to a Kernel registry in commons (see Meeds-io/commons#772, last comment): each webapp has its own Spring context, so a Spring-bean SPI could never be implemented by every addon — processes holds no Spring at all. Spaces and Feed are now declared in The four addon categories are open as pure-configuration PRs: Meeds-io/content#897, Meeds-io/task#640, exoplatform/agenda#1070, exoplatform/processes#491 — all blocked on commons#772 merging first. |
|
Third commit added — the platform timezone synchronization (tech spec §4 Timezone). Implemented exactly as ruled in the spec:
7 new unit tests on the service (round-trip, first-page-load null, profile creation, unknown-zone refusal, event broadcast, broadcast-failure isolation). The agenda delegation (deprecate + delegate + remove the duplicated page scripts) is in exoplatform/agenda#1070, which now depends on this PR. |
d71a1ea to
9759b16
Compare
|
Timezone review round — 4 findings, all fixed in
Cleared by the same review: the kernel bridge lookup agenda relies on (adapter keyed on the concrete @service class, lazily resolved from social's Spring context, unreachable fallback in production), the |
3884ad9 to
2858612
Compare
5f9e726 to
906075d
Compare
….0.22 Lets a user choose when he wants his digest and what it talks about. The entry added to the notification settings now opens a drawer holding the two frequencies, each with the list of the categories the installed addons offer. A frequency enabled for the first time proposes everything the user can receive and he unchecks what he doesn't want, an enabled frequency with no category being refused by the drawer as well as by the server. - DigestRest returns the administrator switch, the categories and the choices of the user in a single call, and saves those choices. - The categories are translated on the server, in the bundle the notification plugins of the category already use: the settings page only loads the resource bundles of the platform, so an addon label would never be found in the browser. This is how the notification groups are already displayed. The language is the one of the request, since the social webapp doesn't fill the portal locale of the thread the way the /rest webapp does. - DigestTimeZoneResolver reads the user profile timezone and hands it to the digest, which lives in commons and can't read a profile itself. - Social contributes its two categories, Spaces and Feed. The four other ones come with their own addon. - The entry now opens the drawer through a ref, like the muted spaces one, instead of going through a root event. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…- eXIP7.3.0.22 Follows the digest categories moving to a Kernel registry: Spaces and Feed are now declared in the notification configuration of social, next to the notification plugins they cover, and their two Java classes disappear. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…89484 - eXIP7.3.0.22 The timezone of each user, the one his browser lives in, used to be kept up to date by the agenda addon alone: without agenda, nothing fills it and every digest goes out on the server hour. As decided in the tech spec, the platform now owns the synchronization, and agenda delegates its own copy. - Profile.USER_TIME_ZONE: the new constant naming the profile attribute, the source of truth. - UserTimeZoneService.saveUserTimeZone(username, zoneId) validates the timezone, saves it and broadcasts an event: whatever keeps a copy of the timezone, like the digest work list, refreshes it on that event, a profile listener never firing for this attribute. - POST /social/rest/timezone: the endpoint the browser calls. - The page head publishes eXo.env.portal.userTimezone and the userTimeZoneSync script, loaded on every page, refreshes the platform when the browser disagrees, exactly the way the agenda script did. - The digest reads the timezone through this service, its own resolver disappears. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-89484 - eXIP7.3.0.22 Review fixes on the timezone synchronization: - The userTimeZoneSync module was declared but never required, and a module nobody requires never runs: the agenda script it replaces only ran because its name rode the BaseExtension suffix convention. The head template now requires it explicitly for logged in users. - The timezone read from the profile is validated before being printed in the head script block: the legacy agenda endpoint saved raw bodies without any validation, and a poisoned stored value would have broken the whole block. - The head template uses the Profile.USER_TIME_ZONE constant it introduced. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ies - EXO-89484 - eXIP7.3.0.22 The category declarations covered every notification of their group, but the functional spec lists exactly which notifications the digest considers: only those 12 plugins are declared, nothing else enters a digest. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…0.22 webpack.dev.js carries each developer's own server location and must never be committed, it was swept in by mistake. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…9484 - eXIP7.3.0.22 The core module only runs the tests a suite declares: a test class left out is silently never executed by the build. The two new unit test classes join NoContainerTestSuite. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
82a891f to
3c01199
Compare
Part of eXIP 7.3.0.22 — Digest Mail Notifications. Task EXO-89484 (US03).
Social half of US03. Depends on Meeds-io/commons#772 — merge that one first, this PR compiles against the
DigestCategoryProviderSPI it introduces.What the user gets
The digest entry added in US02 now opens a drawer with the two frequencies. Switching one on proposes every category the user can receive; he unchecks what he doesn't want. Both frequencies carry their own independent list, and the same category block is shown under each, per the design.
An enabled frequency with no category is refused by the drawer (Apply disabled) as well as by the server — an empty digest is never worth an email.
Server side
DigestRestreturns the administrator switch, the categories and the user's own choices in a single call, and saves those choices. When the administrator has not allowed the digest, the payload carries nothing else and the PATCH is refused with a 403.Category labels are translated on the server. The settings page loads only two resource bundles, so an addon label would simply never resolve in the browser.
DigestCategoryLabelResolverreads the label from the bundle the category's own notification plugins already declare — which is exactly how the notification groups are displayed today, and means an addon has nothing new to declare beyond its category provider.The language is taken from the request. The social webapp does not declare
LocalizationFilter, so the portal locale of the thread is empty here — unlike the/restwebapp, where the JAX-RS notification settings service can rely on it.request.getLocale()is what every other Spring controller in this module uses, and a unit test now pins a non-English label.DigestTimeZoneResolverreads theuser.timeZoneprofile attribute and hands it to the digest. Commons owns the digest but cannot read a user profile, so the timezone is resolved here. Note this is the organization profile attribute, not social'sProfile.TIME_ZONE, which nothing writes outside the CSV import.Worth knowing for the review:
user.timeZoneis today written by the agenda addon alone, on every page load. Without agenda nothing fills it and the digest falls back to server time. That is recorded in the javadoc, and moving the synchronization into the platform is planned with the sending itself (US08).Categories
Social contributes Spaces and Feed. The four others — News, Tasks, Agenda, Process — arrive with their own addon PRs, and the drawer shows only what is installed.
Also in here
The digest entry now opens the drawer through a
ref, like the muted-spaces one, instead of the root event US02 left as a placeholder. That closes finding G from the US02 review.Checks
DigestCategoryLabelResolverTestgreen (4 tests, covering the translated label, the English fallback and the two id fallbacks); frontend bundles with webpack; ESLint reports 0 errors on the touched app (the 5 remaining warnings are pre-existing in files this PR does not change).AI contribution
Classified N1 — human-driven, no auto-merge, author ≠ approver.