xref: /plugin/structpublish/meta/Assignments.php (revision 31e730e145521fb7010758415a11c928f44439b8)
1910e7e15SAnna Dabrowska<?php
2910e7e15SAnna Dabrowska
3910e7e15SAnna Dabrowskanamespace dokuwiki\plugin\structpublish\meta;
4910e7e15SAnna Dabrowska
5f734c62fSAnna Dabrowskause dokuwiki\plugin\sqlite\SQLiteDB;
6f734c62fSAnna Dabrowska
7910e7e15SAnna Dabrowska/**
8910e7e15SAnna Dabrowska * Class Assignments
9910e7e15SAnna Dabrowska *
10910e7e15SAnna Dabrowska * Manages the assignment of users to pages and namespaces
11910e7e15SAnna Dabrowska * This is a singleton. Assignment data is only loaded once per request.
12910e7e15SAnna Dabrowska *
13910e7e15SAnna Dabrowska * @see \dokuwiki\plugin\struct\meta\Assignments
14910e7e15SAnna Dabrowska */
15910e7e15SAnna Dabrowskaclass Assignments
16910e7e15SAnna Dabrowska{
17f734c62fSAnna Dabrowska    /** @var SQLiteDB */
18910e7e15SAnna Dabrowska    protected $sqlite;
19910e7e15SAnna Dabrowska
20910e7e15SAnna Dabrowska    /** @var  array All the assignments patterns */
21910e7e15SAnna Dabrowska    protected $patterns;
22910e7e15SAnna Dabrowska
23910e7e15SAnna Dabrowska    /** @var Assignments */
24910e7e15SAnna Dabrowska    protected static $instance = null;
25910e7e15SAnna Dabrowska
26910e7e15SAnna Dabrowska    /**
27910e7e15SAnna Dabrowska     * Get the singleton instance of the Assignments
28910e7e15SAnna Dabrowska     *
29*31e730e1SAnna Dabrowska     * @param bool $forcereload create a new instance to reload the assignment data
30910e7e15SAnna Dabrowska     * @return Assignments
31910e7e15SAnna Dabrowska     */
32910e7e15SAnna Dabrowska    public static function getInstance($forcereload = false)
33910e7e15SAnna Dabrowska    {
34910e7e15SAnna Dabrowska        if (is_null(self::$instance) or $forcereload) {
35910e7e15SAnna Dabrowska            $class = get_called_class();
36910e7e15SAnna Dabrowska            self::$instance = new $class();
37910e7e15SAnna Dabrowska        }
38910e7e15SAnna Dabrowska        return self::$instance;
39910e7e15SAnna Dabrowska    }
40910e7e15SAnna Dabrowska
41910e7e15SAnna Dabrowska    /**
42910e7e15SAnna Dabrowska     * Assignments constructor.
43910e7e15SAnna Dabrowska     *
44910e7e15SAnna Dabrowska     * Not public. Use Assignments::getInstance() instead
45910e7e15SAnna Dabrowska     */
46910e7e15SAnna Dabrowska    protected function __construct()
47910e7e15SAnna Dabrowska    {
48910e7e15SAnna Dabrowska        /** @var \helper_plugin_structpublish_db $helper */
49910e7e15SAnna Dabrowska        $helper = plugin_load('helper', 'struct_db');
50910e7e15SAnna Dabrowska        $this->sqlite = $helper->getDB();
51910e7e15SAnna Dabrowska
52910e7e15SAnna Dabrowska        $this->loadPatterns();
53910e7e15SAnna Dabrowska    }
548b0ba635SAndreas Gohr
55910e7e15SAnna Dabrowska    /**
56910e7e15SAnna Dabrowska     * Load existing assignment patterns
57910e7e15SAnna Dabrowska     */
58910e7e15SAnna Dabrowska    protected function loadPatterns()
59910e7e15SAnna Dabrowska    {
60910e7e15SAnna Dabrowska        $sql = 'SELECT * FROM structpublish_assignments_patterns ORDER BY pattern';
61f734c62fSAnna Dabrowska        $this->patterns = $this->sqlite->queryAll($sql);
62910e7e15SAnna Dabrowska    }
63910e7e15SAnna Dabrowska
64910e7e15SAnna Dabrowska    /**
65910e7e15SAnna Dabrowska     * Add a new assignment pattern to the pattern table
66910e7e15SAnna Dabrowska     *
67910e7e15SAnna Dabrowska     * @param string $pattern
68910e7e15SAnna Dabrowska     * @param string $user
69910e7e15SAnna Dabrowska     * @param string $status
70910e7e15SAnna Dabrowska     * @return bool
71910e7e15SAnna Dabrowska     */
72910e7e15SAnna Dabrowska    public function addPattern($pattern, $user, $status)
73910e7e15SAnna Dabrowska    {
74910e7e15SAnna Dabrowska        // add the pattern
75910e7e15SAnna Dabrowska        $sql = 'REPLACE INTO structpublish_assignments_patterns (pattern, user, status) VALUES (?,?,?)';
76910e7e15SAnna Dabrowska        $ok = (bool) $this->sqlite->query($sql, [$pattern, $user, $status]);
77910e7e15SAnna Dabrowska
78910e7e15SAnna Dabrowska        // reload patterns
79910e7e15SAnna Dabrowska        $this->loadPatterns();
80910e7e15SAnna Dabrowska
81e6d97799SAnna Dabrowska        // update assignments
82126b0b8eSAnna Dabrowska        // fetch known pages
83126b0b8eSAnna Dabrowska        /** @var \helper_plugin_structpublish_db $dbHelper */
84126b0b8eSAnna Dabrowska        $dbHelper = plugin_load('helper', 'structpublish_db');
85126b0b8eSAnna Dabrowska        $pids = $dbHelper->getPages();
86126b0b8eSAnna Dabrowska
8750372189SAnna Dabrowska        // wrap in transaction
8850372189SAnna Dabrowska        $this->sqlite->query('BEGIN TRANSACTION');
8950372189SAnna Dabrowska
90126b0b8eSAnna Dabrowska        foreach ($pids as $pid) {
91126b0b8eSAnna Dabrowska            $this->updatePageAssignments($pid);
92126b0b8eSAnna Dabrowska        }
93910e7e15SAnna Dabrowska
9450372189SAnna Dabrowska        $ok = $ok && $this->sqlite->query('COMMIT TRANSACTION');
9550372189SAnna Dabrowska        if (!$ok) {
9650372189SAnna Dabrowska            $this->sqlite->query('ROLLBACK TRANSACTION');
9750372189SAnna Dabrowska        }
9850372189SAnna Dabrowska
99910e7e15SAnna Dabrowska        return $ok;
100910e7e15SAnna Dabrowska    }
101910e7e15SAnna Dabrowska
102910e7e15SAnna Dabrowska    /**
103910e7e15SAnna Dabrowska     * Remove an existing assignment pattern from the pattern table
104910e7e15SAnna Dabrowska     *
105910e7e15SAnna Dabrowska     * @param string $pattern
106910e7e15SAnna Dabrowska     * @param string $user
107910e7e15SAnna Dabrowska     * @param string $status
108910e7e15SAnna Dabrowska     * @return bool
109910e7e15SAnna Dabrowska     */
110910e7e15SAnna Dabrowska    public function removePattern($pattern, $user, $status)
111910e7e15SAnna Dabrowska    {
112910e7e15SAnna Dabrowska        // remove the pattern
113910e7e15SAnna Dabrowska        $sql = 'DELETE FROM structpublish_assignments_patterns WHERE pattern = ? AND user = ? AND status = ?';
114910e7e15SAnna Dabrowska        $ok = (bool) $this->sqlite->query($sql, [$pattern, $user, $status]);
115910e7e15SAnna Dabrowska
116910e7e15SAnna Dabrowska        // reload patterns
117910e7e15SAnna Dabrowska        $this->loadPatterns();
118910e7e15SAnna Dabrowska
119910e7e15SAnna Dabrowska        // fetch possibly affected pages
120910e7e15SAnna Dabrowska        $sql = 'SELECT pid FROM structpublish_assignments WHERE user = ? AND status = ?';
121f734c62fSAnna Dabrowska        $pagerows = $this->sqlite->queryAll($sql, [$user, $status]);
122910e7e15SAnna Dabrowska
12347759c1cSAnna Dabrowska        // remove page assignments matching the pattern being removed
12447759c1cSAnna Dabrowska        $ok = true;
125910e7e15SAnna Dabrowska        foreach ($pagerows as $row) {
12647759c1cSAnna Dabrowska            $ok = $ok && $this->deassignPage($row['pid'], $user, $status);
127910e7e15SAnna Dabrowska        }
128910e7e15SAnna Dabrowska
129910e7e15SAnna Dabrowska        return $ok;
130910e7e15SAnna Dabrowska    }
131910e7e15SAnna Dabrowska
132910e7e15SAnna Dabrowska    /**
133910e7e15SAnna Dabrowska     * Updates all assignments of a given page against the current patterns
134910e7e15SAnna Dabrowska     *
135910e7e15SAnna Dabrowska     * @param string $pid
136910e7e15SAnna Dabrowska     */
137126b0b8eSAnna Dabrowska    public function updatePageAssignments($pid, $reload = false)
138910e7e15SAnna Dabrowska    {
139126b0b8eSAnna Dabrowska        if ($reload) {
140910e7e15SAnna Dabrowska            $this->loadPatterns();
141126b0b8eSAnna Dabrowska        }
142910e7e15SAnna Dabrowska        $rules = $this->getPageAssignments($pid, true);
143910e7e15SAnna Dabrowska
144910e7e15SAnna Dabrowska        foreach ($rules as $status => $users) {
145910e7e15SAnna Dabrowska            foreach ($users as $user) {
146910e7e15SAnna Dabrowska                $this->assignPage($pid, $user, $status);
147910e7e15SAnna Dabrowska            }
148910e7e15SAnna Dabrowska        }
149910e7e15SAnna Dabrowska
150f1c406c2SAnna Dabrowska        // FIXME reevalute existing assignments for exclusion
151910e7e15SAnna Dabrowska    }
152910e7e15SAnna Dabrowska
153910e7e15SAnna Dabrowska    /**
154910e7e15SAnna Dabrowska     * Clear all patterns - deassigns all pages
155910e7e15SAnna Dabrowska     *
156910e7e15SAnna Dabrowska     * This is mostly useful for testing and not used in the interface currently
157910e7e15SAnna Dabrowska     *
158910e7e15SAnna Dabrowska     * @param bool $full fully delete all previous assignments
159910e7e15SAnna Dabrowska     * @return bool
160910e7e15SAnna Dabrowska     */
161910e7e15SAnna Dabrowska    public function clear($full = false)
162910e7e15SAnna Dabrowska    {
163910e7e15SAnna Dabrowska        $sql = 'DELETE FROM structpublish_assignments_patterns';
164910e7e15SAnna Dabrowska        $ok = (bool) $this->sqlite->query($sql);
165910e7e15SAnna Dabrowska
166910e7e15SAnna Dabrowska        if ($full) {
167910e7e15SAnna Dabrowska            $sql = 'DELETE FROM structpublish_assignments';
168910e7e15SAnna Dabrowska        } else {
169910e7e15SAnna Dabrowska            $sql = 'UPDATE structpublish_assignments SET assigned = 0';
170910e7e15SAnna Dabrowska        }
171910e7e15SAnna Dabrowska        $ok = $ok && (bool) $this->sqlite->query($sql);
172910e7e15SAnna Dabrowska
173910e7e15SAnna Dabrowska        // reload patterns
174910e7e15SAnna Dabrowska        $this->loadPatterns();
175910e7e15SAnna Dabrowska
176910e7e15SAnna Dabrowska        return $ok;
177910e7e15SAnna Dabrowska    }
178910e7e15SAnna Dabrowska
179910e7e15SAnna Dabrowska    /**
180910e7e15SAnna Dabrowska     * Add page to assignments
181910e7e15SAnna Dabrowska     *
182910e7e15SAnna Dabrowska     * @param string $page
183910e7e15SAnna Dabrowska     * @param string $user
184910e7e15SAnna Dabrowska     * @param string $status
185910e7e15SAnna Dabrowska     * @return bool
186910e7e15SAnna Dabrowska     */
187910e7e15SAnna Dabrowska    public function assignPage($page, $user = null, $status = null)
188910e7e15SAnna Dabrowska    {
189910e7e15SAnna Dabrowska        $sql = 'REPLACE INTO structpublish_assignments (pid, user, status, assigned) VALUES (?, ?, ?, 1)';
190910e7e15SAnna Dabrowska        return (bool) $this->sqlite->query($sql, [$page, $user, $status]);
191910e7e15SAnna Dabrowska    }
192910e7e15SAnna Dabrowska
193910e7e15SAnna Dabrowska    /**
194910e7e15SAnna Dabrowska     * Remove page from assignments
195910e7e15SAnna Dabrowska     *
196910e7e15SAnna Dabrowska     * @param string $page
197910e7e15SAnna Dabrowska     * @param string $user
198910e7e15SAnna Dabrowska     * @return bool
199910e7e15SAnna Dabrowska     */
200910e7e15SAnna Dabrowska    public function deassignPage($page, $user, $status)
201910e7e15SAnna Dabrowska    {
20247759c1cSAnna Dabrowska        $sql = 'UPDATE structpublish_assignments SET assigned = 0 WHERE pid = ? AND user = ? AND status = ?';
203910e7e15SAnna Dabrowska        return (bool) $this->sqlite->query($sql, [$page, $user, $status]);
204910e7e15SAnna Dabrowska    }
205910e7e15SAnna Dabrowska
206910e7e15SAnna Dabrowska    /**
207910e7e15SAnna Dabrowska     * Get the whole pattern table
208910e7e15SAnna Dabrowska     *
209910e7e15SAnna Dabrowska     * @return array
210910e7e15SAnna Dabrowska     */
211910e7e15SAnna Dabrowska    public function getAllPatterns()
212910e7e15SAnna Dabrowska    {
213910e7e15SAnna Dabrowska        return $this->patterns;
214910e7e15SAnna Dabrowska    }
215910e7e15SAnna Dabrowska
216910e7e15SAnna Dabrowska    /**
217e31c94d7SAndreas Gohr     * Returns a list of user/group string lists per status assigned to the given page
218910e7e15SAnna Dabrowska     *
219910e7e15SAnna Dabrowska     * @param string $page
220910e7e15SAnna Dabrowska     * @param bool $checkpatterns Should the current patterns be re-evaluated?
221e31c94d7SAndreas Gohr     * @return array users assigned [role => [user, ...], ...]
222910e7e15SAnna Dabrowska     */
223910e7e15SAnna Dabrowska    public function getPageAssignments($page, $checkpatterns = true)
224910e7e15SAnna Dabrowska    {
225910e7e15SAnna Dabrowska        $rules = [];
226910e7e15SAnna Dabrowska        $page = cleanID($page);
227910e7e15SAnna Dabrowska
228910e7e15SAnna Dabrowska        if ($checkpatterns) {
229910e7e15SAnna Dabrowska            $helper = plugin_load('helper', 'structpublish_assignments');
230910e7e15SAnna Dabrowska            // evaluate patterns
231910e7e15SAnna Dabrowska            $pns = ':' . getNS($page) . ':';
232910e7e15SAnna Dabrowska            foreach ($this->patterns as $row) {
233910e7e15SAnna Dabrowska                if ($helper->matchPagePattern($row['pattern'], $page, $pns)) {
234910e7e15SAnna Dabrowska                    $rules[$row['status']][] = $row['user'];
235910e7e15SAnna Dabrowska                }
236910e7e15SAnna Dabrowska            }
237910e7e15SAnna Dabrowska        } else {
238910e7e15SAnna Dabrowska            // just select
239910e7e15SAnna Dabrowska            $sql = 'SELECT user, status FROM structpublish_assignments WHERE pid = ? AND assigned = 1';
240f734c62fSAnna Dabrowska            $list = $this->sqlite->queryAll($sql, [$page]);
241910e7e15SAnna Dabrowska            foreach ($list as $row) {
242910e7e15SAnna Dabrowska                $rules[$row['status']][] = $row['user'];
243910e7e15SAnna Dabrowska            }
244910e7e15SAnna Dabrowska        }
245910e7e15SAnna Dabrowska
246910e7e15SAnna Dabrowska        return $rules;
247910e7e15SAnna Dabrowska    }
248910e7e15SAnna Dabrowska
249910e7e15SAnna Dabrowska    /**
250910e7e15SAnna Dabrowska     * Get the pages known to struct and their assignment state
251910e7e15SAnna Dabrowska     *
252910e7e15SAnna Dabrowska     * @param bool $assignedonly limit results to currently assigned only
253910e7e15SAnna Dabrowska     * @return array
254910e7e15SAnna Dabrowska     */
255910e7e15SAnna Dabrowska    public function getPages($assignedOnly = false)
256910e7e15SAnna Dabrowska    {
257910e7e15SAnna Dabrowska        $sql = 'SELECT pid, user, status, assigned FROM structpublish_assignments WHERE 1=1';
258910e7e15SAnna Dabrowska
259910e7e15SAnna Dabrowska        $opts = array();
260910e7e15SAnna Dabrowska
261910e7e15SAnna Dabrowska        if ($assignedOnly) {
262910e7e15SAnna Dabrowska            $sql .= ' AND assigned = 1';
263910e7e15SAnna Dabrowska        }
264910e7e15SAnna Dabrowska
265910e7e15SAnna Dabrowska        $sql .= ' ORDER BY pid, user, status';
266910e7e15SAnna Dabrowska
267f734c62fSAnna Dabrowska        $list = $this->sqlite->queryAll($sql, $opts);
268910e7e15SAnna Dabrowska
269910e7e15SAnna Dabrowska        $result = array();
270910e7e15SAnna Dabrowska        foreach ($list as $row) {
271910e7e15SAnna Dabrowska            $pid = $row['pid'];
272910e7e15SAnna Dabrowska            $user = $row['user'];
273910e7e15SAnna Dabrowska            $status = $row['status'];
2748b0ba635SAndreas Gohr            if (!isset($result[$pid])) {
2758b0ba635SAndreas Gohr                $result[$pid] = array();
2768b0ba635SAndreas Gohr            }
277910e7e15SAnna Dabrowska            $result[$pid][$user][$status] = (bool) $row['assigned'];
278910e7e15SAnna Dabrowska        }
279910e7e15SAnna Dabrowska
280910e7e15SAnna Dabrowska        return $result;
281910e7e15SAnna Dabrowska    }
282364fb00aSAnna Dabrowska
283364fb00aSAnna Dabrowska    /**
284f734c62fSAnna Dabrowska     * @return SQLiteDB
285364fb00aSAnna Dabrowska     */
286364fb00aSAnna Dabrowska    public function getSqlite()
287364fb00aSAnna Dabrowska    {
288364fb00aSAnna Dabrowska        return $this->sqlite;
289364fb00aSAnna Dabrowska    }
290910e7e15SAnna Dabrowska}
291