Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions lib/Listener/AnnotationNotificationListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class AnnotationNotificationListener implements IEventListener
* @param AnnotationNotificationDispatcher $dispatcher Dispatcher used to fire notifications.
*
* @return void
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-1
*/
public function __construct(
private readonly AnnotationNotificationDispatcher $dispatcher
Expand All @@ -55,6 +57,8 @@ public function __construct(
* @param Event $event Inbound dispatcher event.
*
* @return void
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-1
*/
public function handle(Event $event): void
{
Expand Down Expand Up @@ -110,6 +114,8 @@ public function handle(Event $event): void
* @param Event $event Inbound dispatcher event.
*
* @return \OCA\OpenRegister\Db\ObjectEntity|null Object instance, or null when none could be derived.
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-1
*/
private function extractObject(Event $event): ?\OCA\OpenRegister\Db\ObjectEntity
{
Expand Down
33 changes: 33 additions & 0 deletions lib/Service/Notification/AnnotationNotificationDispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ class AnnotationNotificationDispatcher
* @param NotificationDispatchLogMapper|null $dispatchLogMapper Optional dispatch-log mapper for idempotency-key dedup.
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList) DI-injected dependencies.
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-1
*/
public function __construct(
private readonly SchemaMapper $schemaMapper,
Expand Down Expand Up @@ -105,6 +107,8 @@ public function __construct(
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-1
*/
public function dispatch(ObjectEntity $object, string $trigger, array $context=[]): void
{
Expand Down Expand Up @@ -393,6 +397,8 @@ public function dispatch(ObjectEntity $object, string $trigger, array $context=[
* @return void
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-1
*/
private function dispatchBroadcastChannel(
string $channel,
Expand Down Expand Up @@ -470,6 +476,8 @@ private function dispatchBroadcastChannel(
* @param array<string, mixed>|null $rateLimit Per-rule override block.
*
* @return bool True when the dispatch may proceed.
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-3
*/
private function rateLimitAllows(string $ruleId, string $recipient, ?array $rateLimit): bool
{
Expand All @@ -496,6 +504,7 @@ private function rateLimitAllows(string $ruleId, string $recipient, ?array $rate
* @return bool True when the dispatch may proceed.
*
* @spec openspec/changes/notificatie-engine/tasks.md
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-4
*/
private function coalesceAllows(string $ruleId, string $recipient, ?array $coalesce): bool
{
Expand Down Expand Up @@ -532,6 +541,8 @@ private function coalesceAllows(string $ruleId, string $recipient, ?array $coale
* @return bool True when the dispatch may proceed (claim succeeded
* or mapper unavailable); false when a competing
* dispatcher already claimed this (slug, key).
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-5
*/
private function claimIdempotencyKey(string $slug, string $key): bool
{
Expand Down Expand Up @@ -590,6 +601,8 @@ private function claimIdempotencyKey(string $slug, string $key): bool
* @param array<string, mixed> $data Pre-fetched object data array.
*
* @return string The resolved key.
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-5
*/
private function resolveIdempotencyKey(string $template, ObjectEntity $object, array $data): string
{
Expand Down Expand Up @@ -640,6 +653,7 @@ static function (array $matches) use ($object, $data): string {
* @return void
*
* @spec openspec/changes/notificatie-engine/tasks.md
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-1
*/
private function recordHistory(
string $ruleId,
Expand Down Expand Up @@ -702,6 +716,7 @@ private function recordHistory(
* @return void
*
* @spec openspec/changes/notificatie-engine/tasks.md
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-1
*/
private function recordHistoryAcrossChannels(
string $ruleId,
Expand Down Expand Up @@ -938,6 +953,8 @@ private function emitWebhook(
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-1
*/
private function matches(array $triggerSpec, string $trigger, array $context): bool
{
Expand Down Expand Up @@ -1017,6 +1034,8 @@ private function matches(array $triggerSpec, string $trigger, array $context): b
* @return bool True when the value satisfies every declared operator.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-1
*/
private function numericConditionMatches(mixed $value, array $operators): bool
{
Expand Down Expand Up @@ -1053,6 +1072,8 @@ private function numericConditionMatches(mixed $value, array $operators): bool
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-2
*/
private function resolveRecipients(array $recipientsSpec, array $data, ?ObjectEntity $object=null, array $context=[]): array
{
Expand Down Expand Up @@ -1187,6 +1208,8 @@ private function resolveRecipients(array $recipientsSpec, array $data, ?ObjectEn
* @return array<int, string>
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-2
*/
private function resolveObjectAclRecipients(ObjectEntity $object, string $permission): array
{
Expand Down Expand Up @@ -1249,6 +1272,8 @@ private function resolveObjectAclRecipients(ObjectEntity $object, string $permis
* @param array<string, mixed> $context Per-event context passed through to the resolver.
*
* @return array<int, string>
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-2
*/
private function resolveExpressionRecipients(string $resolverTag, ObjectEntity $object, array $context): array
{
Expand Down Expand Up @@ -1288,6 +1313,8 @@ private function resolveExpressionRecipients(string $resolverTag, ObjectEntity $
* @param string $uid Candidate Nextcloud user identifier.
*
* @return bool True when the uid corresponds to a real Nextcloud user.
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-2
*/
private function userExists(string $uid): bool
{
Expand Down Expand Up @@ -1339,6 +1366,8 @@ private function userExists(string $uid): bool
* @return array<int, string>
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-2
*/
private function extractUidsFromRelation(mixed $value): array
{
Expand Down Expand Up @@ -1660,6 +1689,8 @@ private function emitActivity(string $uid, string $objectId, string $name, strin
* @param ObjectEntity $object The object whose schema should be looked up.
*
* @return Schema|null The resolved schema, or null when missing/unresolvable.
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-1
*/
private function loadSchema(ObjectEntity $object): ?Schema
{
Expand All @@ -1681,6 +1712,8 @@ private function loadSchema(ObjectEntity $object): ?Schema
* @param Schema $schema The schema whose annotation should be read.
*
* @return array<string, mixed>|null
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-1
*/
private function getAnnotation(Schema $schema): ?array
{
Expand Down
16 changes: 16 additions & 0 deletions lib/Service/Notification/NotificationCoalescer.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ class NotificationCoalescer
* @param IAppConfig $appConfig App-config reader for kill switch.
* @param LoggerInterface $logger Logger for silenced-dispatch info events.
* @param callable|null $timeProvider Optional time source (defaults to time()).
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-4
*/
public function __construct(
ICacheFactory $cacheFactory,
Expand Down Expand Up @@ -130,6 +132,8 @@ public function __construct(
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-4
*/
public function shouldDispatch(string $ruleId, string $recipient, ?array $perRuleOverride): bool
{
Expand Down Expand Up @@ -218,6 +222,8 @@ public function shouldDispatch(string $ruleId, string $recipient, ?array $perRul
* @param string $recipient Recipient identifier.
*
* @return array{count:int,opened:int}|null Null when no state exists.
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-4
*/
public function inspect(string $ruleId, string $recipient): ?array
{
Expand Down Expand Up @@ -255,6 +261,8 @@ public function inspect(string $ruleId, string $recipient): ?array
* Whether the coalescer is enabled. Defaults to ON.
*
* @return bool True when the coalescer should run.
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-4
*/
private function isEnabled(): bool
{
Expand All @@ -274,6 +282,8 @@ private function isEnabled(): bool
* @param array<string, mixed> $perRuleOverride The rule's `coalesce` config block.
*
* @return int Window length in seconds (0 = disabled).
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-4
*/
private function resolveWindowSeconds(array $perRuleOverride): int
{
Expand All @@ -296,6 +306,8 @@ private function resolveWindowSeconds(array $perRuleOverride): int
* @param array<string, mixed> $perRuleOverride The rule's `coalesce` config block.
*
* @return int|null Max events (null = no cap).
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-4
*/
private function resolveMaxEvents(array $perRuleOverride): ?int
{
Expand All @@ -319,6 +331,8 @@ private function resolveMaxEvents(array $perRuleOverride): ?int
* @param string $recipient Recipient identifier.
*
* @return string The cache key.
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-4
*/
private function key(string $ruleId, string $recipient): string
{
Expand All @@ -334,6 +348,8 @@ private function key(string $ruleId, string $recipient): string
* @param int $opened Unix timestamp the window opened.
*
* @return void
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-4
*/
private function persist(string $key, int $count, int $opened): void
{
Expand Down
12 changes: 12 additions & 0 deletions lib/Service/Notification/RateLimiter.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ class RateLimiter
* @param IAppConfig $appConfig App-config reader for kill switch + defaults.
* @param LoggerInterface $logger Logger for dropped-dispatch info events.
* @param callable|null $timeProvider Optional time source (defaults to time()).
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-3
*/
public function __construct(
ICacheFactory $cacheFactory,
Expand Down Expand Up @@ -126,6 +128,8 @@ public function __construct(
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-3
*/
public function tryConsume(string $ruleId, string $recipient, ?array $perRuleOverride=null): bool
{
Expand Down Expand Up @@ -198,6 +202,8 @@ public function tryConsume(string $ruleId, string $recipient, ?array $perRuleOve
* Whether the limiter is enabled. Defaults to ON.
*
* @return bool True when the limiter should run.
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-3
*/
private function isEnabled(): bool
{
Expand All @@ -221,6 +227,8 @@ private function isEnabled(): bool
* @return array{0:int,1:int} Tuple of (bucketSize, refillSeconds).
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-3
*/
private function resolveLimits(?array $perRuleOverride): array
{
Expand Down Expand Up @@ -281,6 +289,8 @@ private function resolveLimits(?array $perRuleOverride): array
* @param string $recipient Recipient identifier.
*
* @return string Cache key.
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-3
*/
private function key(string $ruleId, string $recipient): string
{
Expand All @@ -298,6 +308,8 @@ private function key(string $ruleId, string $recipient): string
* @param int $lastRefill Last refill timestamp.
*
* @return void
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-3
*/
private function persist(string $key, float $tokens, int $lastRefill): void
{
Expand Down
2 changes: 2 additions & 0 deletions lib/Service/Notification/RecipientResolverInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ interface RecipientResolverInterface
* @param array<string, mixed> $context Trigger-specific extras (action, from, to, aggregation, ...).
*
* @return array<int, string> List of Nextcloud uids.
*
* @spec openspec/changes/retrofit-2026-05-24-notificatie-engine/tasks.md#task-2
*/
public function resolve(ObjectEntity $object, array $context): array;
}//end interface
Loading
Loading