@@ -266,13 +266,14 @@ public function testResolveUsesCurrentUserFromSession(): void {
266266 $ this ->assertSame ('group ' , $ resolved ->getSourceScope ());
267267 }
268268
269- public function testSaveUserPreferenceForUserIdPersistsForTargetUser (): void {
269+ public function testSaveUserPolicyForUserIdPersistsForTargetUser (): void {
270270 $ targetUser = $ this ->createMock (IUser::class);
271271 $ targetUser ->method ('getUID ' )->willReturn ('user1 ' );
272272
273273 $ persistedPolicy = (new PolicyLayer ())
274- ->setScope ('user ' )
275- ->setValue ('ordered_numeric ' );
274+ ->setScope ('user_policy ' )
275+ ->setValue ('ordered_numeric ' )
276+ ->setAllowChildOverride (true );
276277
277278 $ this ->userManager
278279 ->expects ($ this ->once ())
@@ -288,13 +289,14 @@ public function testSaveUserPreferenceForUserIdPersistsForTargetUser(): void {
288289
289290 $ this ->source
290291 ->expects ($ this ->once ())
291- ->method ('saveUserPreference ' )
292+ ->method ('saveUserPolicy ' )
292293 ->with (
293294 SignatureFlowPolicy::KEY ,
294295 $ this ->callback (static function ($ context ): bool {
295296 return $ context ->getUserId () === 'user1 ' ;
296297 }),
297298 'ordered_numeric ' ,
299+ true ,
298300 );
299301
300302 $ this ->source
@@ -308,8 +310,9 @@ public function testSaveUserPreferenceForUserIdPersistsForTargetUser(): void {
308310 $ this ->source ->method ('loadGroupPolicies ' )->willReturn ([]);
309311 $ this ->source ->method ('loadCirclePolicies ' )->willReturn ([]);
310312 $ this ->source
311- ->method ('loadUserPreference ' )
312- ->willReturnOnConsecutiveCalls (null , $ persistedPolicy );
313+ ->method ('loadUserPolicy ' )
314+ ->willReturn ($ persistedPolicy );
315+ $ this ->source ->method ('loadUserPreference ' )->willReturn (null );
313316 $ this ->source ->method ('loadRequestOverride ' )->willReturn (null );
314317
315318 $ service = new PolicyService (
@@ -319,21 +322,23 @@ public function testSaveUserPreferenceForUserIdPersistsForTargetUser(): void {
319322 $ this ->l10n ,
320323 );
321324
322- $ policy = $ service ->saveUserPreferenceForUserId (SignatureFlowPolicy::KEY , 'user1 ' , 'ordered_numeric ' );
325+ $ policy = $ service ->saveUserPolicyForUserId (SignatureFlowPolicy::KEY , 'user1 ' , 'ordered_numeric ' , true );
323326
324327 $ this ->assertInstanceOf (PolicyLayer::class, $ policy );
325328 $ this ->assertSame ($ persistedPolicy , $ policy );
326329 $ this ->assertSame ('ordered_numeric ' , $ policy ->getValue ());
327- $ this ->assertSame ('user ' , $ policy ->getScope ());
330+ $ this ->assertSame ('user_policy ' , $ policy ->getScope ());
331+ $ this ->assertTrue ($ policy ->isAllowChildOverride ());
328332 }
329333
330- public function testSaveUserPreferenceForUserIdAllowsSystemAdminBypassWhenGroupBlocksUsers (): void {
334+ public function testSaveUserPolicyForUserIdAllowsExplicitAssignmentWhenGroupBlocksUsers (): void {
331335 $ targetUser = $ this ->createMock (IUser::class);
332336 $ targetUser ->method ('getUID ' )->willReturn ('user1 ' );
333337
334338 $ persistedPolicy = (new PolicyLayer ())
335- ->setScope ('user ' )
336- ->setValue ('ordered_numeric ' );
339+ ->setScope ('user_policy ' )
340+ ->setValue ('ordered_numeric ' )
341+ ->setAllowChildOverride (false );
337342
338343 $ actor = $ this ->createMock (IUser::class);
339344 $ actor ->method ('getUID ' )->willReturn ('admin ' );
@@ -360,13 +365,14 @@ public function testSaveUserPreferenceForUserIdAllowsSystemAdminBypassWhenGroupB
360365
361366 $ this ->source
362367 ->expects ($ this ->once ())
363- ->method ('saveUserPreference ' )
368+ ->method ('saveUserPolicy ' )
364369 ->with (
365370 SignatureFlowPolicy::KEY ,
366371 $ this ->callback (static function ($ context ): bool {
367372 return $ context ->getUserId () === 'user1 ' ;
368373 }),
369374 'ordered_numeric ' ,
375+ false ,
370376 );
371377
372378 $ this ->source
@@ -388,8 +394,9 @@ public function testSaveUserPreferenceForUserIdAllowsSystemAdminBypassWhenGroupB
388394
389395 $ this ->source ->method ('loadCirclePolicies ' )->willReturn ([]);
390396 $ this ->source
391- ->method ('loadUserPreference ' )
392- ->willReturnOnConsecutiveCalls (null , $ persistedPolicy );
397+ ->method ('loadUserPolicy ' )
398+ ->willReturn ($ persistedPolicy );
399+ $ this ->source ->method ('loadUserPreference ' )->willReturn (null );
393400 $ this ->source ->method ('loadRequestOverride ' )->willReturn (null );
394401
395402 $ service = new PolicyService (
@@ -399,24 +406,19 @@ public function testSaveUserPreferenceForUserIdAllowsSystemAdminBypassWhenGroupB
399406 $ this ->l10n ,
400407 );
401408
402- $ policy = $ service ->saveUserPreferenceForUserId (SignatureFlowPolicy::KEY , 'user1 ' , 'ordered_numeric ' );
409+ $ policy = $ service ->saveUserPolicyForUserId (SignatureFlowPolicy::KEY , 'user1 ' , 'ordered_numeric ' , false );
403410
404411 $ this ->assertInstanceOf (PolicyLayer::class, $ policy );
405412 $ this ->assertSame ($ persistedPolicy , $ policy );
406413 $ this ->assertSame ('ordered_numeric ' , $ policy ->getValue ());
407- $ this ->assertSame ('user ' , $ policy ->getScope ());
414+ $ this ->assertSame ('user_policy ' , $ policy ->getScope ());
415+ $ this ->assertFalse ($ policy ->isAllowChildOverride ());
408416 }
409417
410- public function testSaveUserPreferenceForUserIdBlocksNonAdminWhenGroupDisallowsUserOverrides (): void {
418+ public function testSaveUserPolicyForUserIdDoesNotDependOnGroupChildOverride (): void {
411419 $ targetUser = $ this ->createMock (IUser::class);
412420 $ targetUser ->method ('getUID ' )->willReturn ('user1 ' );
413421
414- $ actor = $ this ->createMock (IUser::class);
415- $ actor ->method ('getUID ' )->willReturn ('manager ' );
416- $ this ->userSession
417- ->method ('getUser ' )
418- ->willReturn ($ actor );
419-
420422 $ this ->userManager
421423 ->expects ($ this ->once ())
422424 ->method ('get ' )
@@ -429,14 +431,17 @@ public function testSaveUserPreferenceForUserIdBlocksNonAdminWhenGroupDisallowsU
429431 ->with ($ targetUser )
430432 ->willReturn (['finance ' ]);
431433
432- $ this ->groupManager
433- ->method ('isAdmin ' )
434- ->with ('manager ' )
435- ->willReturn (false );
436-
437434 $ this ->source
438- ->expects ($ this ->never ())
439- ->method ('saveUserPreference ' );
435+ ->expects ($ this ->once ())
436+ ->method ('saveUserPolicy ' )
437+ ->with (
438+ SignatureFlowPolicy::KEY ,
439+ $ this ->callback (static function ($ context ): bool {
440+ return $ context ->getUserId () === 'user1 ' ;
441+ }),
442+ 'ordered_numeric ' ,
443+ false ,
444+ );
440445
441446 $ this ->source
442447 ->method ('loadSystemPolicy ' )
@@ -456,6 +461,10 @@ public function testSaveUserPreferenceForUserIdBlocksNonAdminWhenGroupDisallowsU
456461 ->setAllowedValues (['ordered_numeric ' ])]);
457462
458463 $ this ->source ->method ('loadCirclePolicies ' )->willReturn ([]);
464+ $ this ->source ->method ('loadUserPolicy ' )->willReturn ((new PolicyLayer ())
465+ ->setScope ('user_policy ' )
466+ ->setValue ('ordered_numeric ' )
467+ ->setAllowChildOverride (false ));
459468 $ this ->source ->method ('loadUserPreference ' )->willReturn (null );
460469 $ this ->source ->method ('loadRequestOverride ' )->willReturn (null );
461470
@@ -466,10 +475,10 @@ public function testSaveUserPreferenceForUserIdBlocksNonAdminWhenGroupDisallowsU
466475 $ this ->l10n ,
467476 );
468477
469- $ this ->expectException (\InvalidArgumentException::class);
470- $ this ->expectExceptionMessage ('Saving a user preference is not allowed for signature_flow ' );
478+ $ policy = $ service ->saveUserPolicyForUserId (SignatureFlowPolicy::KEY , 'user1 ' , 'ordered_numeric ' , false );
471479
472- $ service ->saveUserPreferenceForUserId (SignatureFlowPolicy::KEY , 'user1 ' , 'ordered_numeric ' );
480+ $ this ->assertSame ('user_policy ' , $ policy ?->getScope());
481+ $ this ->assertFalse ($ policy ?->isAllowChildOverride() ?? true );
473482 }
474483
475484 public function testSaveSystemPersistsAllowChildOverrideWhenEnabled (): void {
0 commit comments