[TikiWiki-commits] [Git][tikiwiki/tiki][29.x] [BP][FIX] Parsing plugins' data to HTML before rendering into the WYSIWYG editor...

"Baraka Kinywa \(@bkinywa24\) via TikiWiki-cvs" <[email protected]>
Newsgroups gmane.comp.cms.tiki.cvs
Message-ID <68b80819d5aa3_2cdd01877235@gitlab-sidekiq-low-urgency-cpu-bound-v2-dc78c9688-fncfj.mail>

Baraka Kinywa pushed to branch 29.x at Tiki Wiki CMS Groupware / Tiki


Commits:
76065421 by MAGENE Sem Joel at 2025-09-03T12:11:22+03:00
[BP][FIX] Parsing plugins' data to HTML before rendering into the WYSIWYG editor...
---
* [ENH] introduce blending permission scope system
---
* [FIX] merging permission sets when one of them is null/empty

* [FIX] blending permissions cache resolvers by context, so we don't reuse permissions from another object when multiple lookups are done for different objects

* [FIX] phpcs pipeline

* [FIX] accept null values in resolver merge method

* [ENH] introduce blending permission scope system: preference that toggles between traditional strict scope permission where the nearest possible defined scope wins vs blending where scopes are merged from nearest to farthest with additive operation

See merge request tikiwiki/tiki!7181

(cherry picked from commit 7b9acb06da2a3129b785f9b2d347744645a18404)

See merge request tikiwiki/tiki!8480

- - - - -


9 changed files:

- lib/core/Perms.php
- lib/core/Perms/Resolver.php
- lib/core/Perms/Resolver/Default.php
- lib/core/Perms/Resolver/Static.php
- lib/prefs/permission.php
- lib/test/core/Perms/BaseTest.php
- lib/test/core/Perms/Resolver/StaticTest.php
- templates/tiki-objectpermissions.tpl
- tiki-objectpermissions.php


Changes:

=====================================
lib/core/Perms.php
=====================================
@@ -337,26 +337,61 @@ class Perms
 
     private function getResolver(array $context)
     {
+        global $prefs;
+
         $toSet = [];
         $finalResolver = false;
 
-        foreach ($this->factories as $factory) {
-            $hash = $factory->getHash($context);
+        if (isset($prefs['permission_scope_behavior']) && $prefs['permission_scope_behavior'] === 'blending') {
+            // blending permission system
+            foreach (array_reverse($this->factories) as $factory) {
+                $hash = $factory->getHash($context);
 
-            // no hash returned by factory means factory does not support that context
-            if (! $hash) {
-                continue;
-            }
+                // no hash returned by factory means factory does not support that context
+                if (! $hash) {
+                    continue;
+                }
 
-            if (isset($this->hashes[$hash])) {
-                $finalResolver = $this->hashes[$hash];
-            } else {
-                $finalResolver = $factory->getResolver($context);
-                $toSet[$hash] = $finalResolver;
+                // blending mode requires caching by context as previous lookups might interfere
+                // finalResolver because of the merging
+                $hash .= implode('', $context);
+
+                if (isset($this->hashes[$hash])) {
+                    $currentResolver = $this->hashes[$hash];
+                } else {
+                    $currentResolver = $factory->getResolver($context);
+                    $toSet[$hash] = $currentResolver;
+                }
+
+                if ($finalResolver) {
+                    if ($currentResolver) {
+                        $currentResolver->merge($finalResolver);
+                        $finalResolver = $currentResolver;
+                    }
+                } else {
+                    $finalResolver = $currentResolver;
+                }
             }
+        } else {
+            // traditional strict scope based permission system
+            foreach ($this->factories as $factory) {
+                $hash = $factory->getHash($context);
+
+                // no hash returned by factory means factory does not support that context
+                if (! $hash) {
+                    continue;
+                }
 
-            if ($finalResolver) {
-                break;
+                if (isset($this->hashes[$hash])) {
+                    $finalResolver = $this->hashes[$hash];
+                } else {
+                    $finalResolver = $factory->getResolver($context);
+                    $toSet[$hash] = $finalResolver;
+                }
+
+                if ($finalResolver) {
+                    break;
+                }
             }
         }
 


=====================================
lib/core/Perms/Resolver.php
=====================================
@@ -32,6 +32,11 @@ interface Perms_Resolver
      */
     public function applicableGroups();
 
+    /**
+     * Merge another set of resolver permissions into the current one.
+     */
+    public function merge(?Perms_Resolver $another = null);
+
     /*
      * Dump useful resolve information for debugging purposes.
      * @return array of resolved permissions


=====================================
lib/core/Perms/Resolver/Default.php
=====================================
@@ -34,6 +34,14 @@ class Perms_Resolver_Default implements Perms_Resolver
         return ['Anonymous', 'Registered'];
     }
 
+    /**
+     * This does not affect the current resolver as it always returns the same value
+     */
+    public function merge(?Perms_Resolver $another = null)
+    {
+        return;
+    }
+
     public function dump()
     {
         $result = [


=====================================
lib/core/Perms/Resolver/Static.php
=====================================
@@ -65,6 +65,29 @@ class Perms_Resolver_Static implements Perms_Resolver
         return array_keys($this->known);
     }
 
+    /**
+     * Return the known groups with their permissions, used for merging.
+     */
+    public function known()
+    {
+        return $this->known;
+    }
+
+    /**
+     * The result is a union of both sets of permissions - thus additive merge.
+     */
+    public function merge(?Perms_Resolver $another = null)
+    {
+        if (empty($another) || ! method_exists($another, 'known')) {
+            return;
+        }
+        foreach ($another->known() as $group => $perms) {
+            foreach ($perms as $perm => $_) {
+                $this->known[$group][$perm] = true;
+            }
+        }
+    }
+
     public function dump()
     {
         $result = [


=====================================
lib/prefs/permission.php
=====================================
@@ -23,5 +23,16 @@ Alternatively, use the Send to URL field to display a specific page (relative to
             'default' => 'y',
             'tags' => ['basic'],
         ],
+        'permission_scope_behavior' => [
+            'name' => tra('Permission system behavior'),
+            'description' => tra('Traditional strict scope based permission system locks specific object permissions to the closest defined permission set for the object bubbling up through category and parent object permissions to the global set of permissions. The blending scope based permission system allows different levels of permissions to combine on a single object. It is an additive-only permission set, so if you want to restrict specific level permissions over a more permissive global level, you should use the traditional strict scope.'),
+            // TODO: add help icon, doc or dev help page to explain more and link from here
+            'type' => 'list',
+            'options' => [
+                'strict' => tr('Strict scope'),
+                'blending' => tr('Blending scope'),
+            ],
+            'default' => 'strict',
+        ],
     ];
 }


=====================================
lib/test/core/Perms/BaseTest.php
=====================================
@@ -97,6 +97,52 @@ class Perms_BaseTest extends TikiTestCase
         ];
     }
 
+    public function testResolverStrategyDifference()
+    {
+        global $prefs;
+        $old = $prefs['permission_scope_behavior'] ?? 'static';
+        $prefs['permission_scope_behavior'] = 'blending';
+
+        $resetFactories = function () {
+            $perms = new Perms();
+            $perms->setResolverFactories(
+                [
+                    new Perms_ResolverFactory_TestFactory(
+                        ['object'],
+                        [
+                            'test:a' => new Perms_Resolver_Static(['Registered' => ['view']]),
+                        ]
+                    ),
+                    new Perms_ResolverFactory_TestFactory(
+                        ['category'],
+                        [
+                            'test:1' => new Perms_Resolver_Static([
+                                'Anonymous' => ['view'],
+                                'Registered' => ['edit']
+                            ]),
+                        ]
+                    ),
+                ]
+            );
+            $perms->setGroups(['Registered']);
+            Perms::set($perms);
+        };
+        $resetFactories();
+
+        $accessor = Perms::get(['type' => 'test', 'object' => 'a', 'category' => 1]);
+        $this->assertTrue($accessor->edit);
+
+        Perms::getInstance()->clear();
+        $resetFactories();
+
+        $prefs['permission_scope_behavior'] = 'static';
+        $accessor = Perms::get(['type' => 'test', 'object' => 'a', 'category' => 1]);
+        $this->assertFalse($accessor->edit);
+
+        Perms::getInstance()->clear();
+        $prefs['permission_scope_behavior'] = $old;
+    }
+
     public function testResolverNotCalledTwiceWhenFound()
     {
         $mock = $this->createMock('Perms_ResolverFactory');


=====================================
lib/test/core/Perms/Resolver/StaticTest.php
=====================================
@@ -41,4 +41,32 @@ class Perms_Resolver_StaticTest extends TikiTestCase
         $this->assertTrue($static->check('edit', ['Anonymous', 'Registered']));
         $this->assertEquals(['Anonymous', 'Registered'], $static->applicableGroups());
     }
+
+    public function testMergeStatic()
+    {
+        $static = new Perms_Resolver_Static(
+            ['Registered' => ['view']]
+        );
+        $another = new Perms_Resolver_Static([
+            'Anonymous' => ['view'],
+            'Registered' => ['edit']
+        ]);
+
+        $static->merge($another);
+
+        $this->assertTrue($static->check('edit', ['Anonymous', 'Registered']));
+        $this->assertEquals(['Anonymous' => ['view' => true], 'Registered' => ['view' => true, 'edit' => true]], $static->known());
+    }
+
+    public function testMergeStaticAndDefault()
+    {
+        $static = new Perms_Resolver_Static(
+            ['Registered' => ['view']]
+        );
+        $default = new Perms_Resolver_Default(true);
+
+        $static->merge($default);
+
+        $this->assertFalse($static->check('edit', ['Anonymous', 'Registered']));
+    }
 }


=====================================
templates/tiki-objectpermissions.tpl
=====================================
@@ -240,6 +240,20 @@
         </form>
     {/tab}
 
+    {tab name="{tr}Permission Preferences{/tr}"}
+        <form method="post" action="{$smarty.server.SCRIPT_NAME}?{query}">
+        <div>
+            <input type="hidden" name="referer" value="{$referer|escape}">
+
+            {preference name=permission_scope_behavior visible="always"}
+
+            <div class="input_submit_container" style="text-align: center">
+                <input type="submit" class="btn btn-primary btn-sm" name="preference_update" value="{tr}Save{/tr}">
+            </div>
+        </div>
+        </form>
+    {/tab}
+
     {* Quickperms *}
 
     {if $prefs.feature_quick_object_perms eq 'y'}


=====================================
tiki-objectpermissions.php
=====================================
@@ -374,6 +374,11 @@ if (! empty($_SESSION['perms_clipboard'])) {
     }
 }
 
+if (! empty($_POST['preference_update'])) {
+    $tikilib->set_preference('permission_scope_behavior', $_POST['permission_scope_behavior']);
+    TikiLib::lib('cache')->invalidate('allperms');
+}
+
 // Prepare display
 // Get the individual object permissions if any
 $displayedPermissions = get_displayed_permissions();



View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/76065421aa1dffc73239f6c88ca618f31301c311

-- 
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/76065421aa1dffc73239f6c88ca618f31301c311
You're receiving this email because of your account on gitlab.com.

_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.