xref: /plugin/structpublish/meta/Assignments.php (revision e31c94d7935dccc7709b66e483c744379995197d)
1910e7e15SAnna Dabrowska<?php
2910e7e15SAnna Dabrowska
3910e7e15SAnna Dabrowskanamespace dokuwiki\plugin\structpublish\meta;
4910e7e15SAnna Dabrowska
5910e7e15SAnna Dabrowska/**
6910e7e15SAnna Dabrowska * Class Assignments
7910e7e15SAnna Dabrowska *
8910e7e15SAnna Dabrowska * Manages the assignment of users to pages and namespaces
9910e7e15SAnna Dabrowska * This is a singleton. Assignment data is only loaded once per request.
10910e7e15SAnna Dabrowska *
11910e7e15SAnna Dabrowska * @see \dokuwiki\plugin\struct\meta\Assignments
12910e7e15SAnna Dabrowska */
13910e7e15SAnna Dabrowskaclass Assignments
14910e7e15SAnna Dabrowska{
15910e7e15SAnna Dabrowska    /** @var \helper_plugin_sqlite|null */
16910e7e15SAnna Dabrowska    protected $sqlite;
17910e7e15SAnna Dabrowska
18910e7e15SAnna Dabrowska    /** @var  array All the assignments patterns */
19910e7e15SAnna Dabrowska    protected $patterns;
20910e7e15SAnna Dabrowska
21910e7e15SAnna Dabrowska    /** @var Assignments */
22910e7e15SAnna Dabrowska    protected static $instance = null;
23910e7e15SAnna Dabrowska
24910e7e15SAnna Dabrowska    /**
25910e7e15SAnna Dabrowska     * Get the singleton instance of the Assignments
26910e7e15SAnna Dabrowska     *
27910e7e15SAnna Dabrowska     * @param bool $forcereload create a new instace to reload the assignment data
28910e7e15SAnna Dabrowska     * @return Assignments
29910e7e15SAnna Dabrowska     */
30910e7e15SAnna Dabrowska    public static function getInstance($forcereload = false)
31910e7e15SAnna Dabrowska    {
32910e7e15SAnna Dabrowska        if (is_null(self::$instance) or $forcereload) {
33910e7e15SAnna Dabrowska            $class = get_called_class();
34910e7e15SAnna Dabrowska            self::$instance = new $class();
35910e7e15SAnna Dabrowska        }
36910e7e15SAnna Dabrowska        return self::$instance;
37910e7e15SAnna Dabrowska    }
38910e7e15SAnna Dabrowska
39910e7e15SAnna Dabrowska    /**
40910e7e15SAnna Dabrowska     * Assignments constructor.
41910e7e15SAnna Dabrowska     *
42910e7e15SAnna Dabrowska     * Not public. Use Assignments::getInstance() instead
43910e7e15SAnna Dabrowska     */
44910e7e15SAnna Dabrowska    protected function __construct()
45910e7e15SAnna Dabrowska    {
46910e7e15SAnna Dabrowska        /** @var \helper_plugin_structpublish_db $helper */
47910e7e15SAnna Dabrowska        $helper = plugin_load('helper', 'struct_db');
48910e7e15SAnna Dabrowska        $this->sqlite = $helper->getDB();
49910e7e15SAnna Dabrowska
50910e7e15SAnna Dabrowska        $this->loadPatterns();
51910e7e15SAnna Dabrowska    }
52910e7e15SAnna Dabrowska    /**
53910e7e15SAnna Dabrowska     * Load existing assignment patterns
54910e7e15SAnna Dabrowska     */
55910e7e15SAnna Dabrowska    protected function loadPatterns()
56910e7e15SAnna Dabrowska    {
57910e7e15SAnna Dabrowska        $sql = 'SELECT * FROM structpublish_assignments_patterns ORDER BY pattern';
58910e7e15SAnna Dabrowska        $res = $this->sqlite->query($sql);
59910e7e15SAnna Dabrowska        $this->patterns = $this->sqlite->res2arr($res);
60910e7e15SAnna Dabrowska        $this->sqlite->res_close($res);
61910e7e15SAnna Dabrowska    }
62910e7e15SAnna Dabrowska
63910e7e15SAnna Dabrowska    /**
64910e7e15SAnna Dabrowska     * Add a new assignment pattern to the pattern table
65910e7e15SAnna Dabrowska     *
66910e7e15SAnna Dabrowska     * @param string $pattern
67910e7e15SAnna Dabrowska     * @param string $user
68910e7e15SAnna Dabrowska     * @param string $status
69910e7e15SAnna Dabrowska     * @return bool
70910e7e15SAnna Dabrowska     */
71910e7e15SAnna Dabrowska    public function addPattern($pattern, $user, $status)
72910e7e15SAnna Dabrowska    {
73910e7e15SAnna Dabrowska        // add the pattern
74910e7e15SAnna Dabrowska        $sql = 'REPLACE INTO structpublish_assignments_patterns (pattern, user, status) VALUES (?,?,?)';
75910e7e15SAnna Dabrowska        $ok = (bool)$this->sqlite->query($sql, [$pattern, $user, $status]);
76910e7e15SAnna Dabrowska
77910e7e15SAnna Dabrowska        // reload patterns
78910e7e15SAnna Dabrowska        $this->loadPatterns();
79910e7e15SAnna Dabrowska
80910e7e15SAnna Dabrowska        // FIXME how to update / propagate assignments?
81910e7e15SAnna Dabrowska
82910e7e15SAnna Dabrowska        return $ok;
83910e7e15SAnna Dabrowska    }
84910e7e15SAnna Dabrowska
85910e7e15SAnna Dabrowska    /**
86910e7e15SAnna Dabrowska     * Remove an existing assignment pattern from the pattern table
87910e7e15SAnna Dabrowska     *
88910e7e15SAnna Dabrowska     * @param string $pattern
89910e7e15SAnna Dabrowska     * @param string $user
90910e7e15SAnna Dabrowska     * @param string $status
91910e7e15SAnna Dabrowska     * @return bool
92910e7e15SAnna Dabrowska     */
93910e7e15SAnna Dabrowska    public function removePattern($pattern, $user, $status)
94910e7e15SAnna Dabrowska    {
95910e7e15SAnna Dabrowska        // remove the pattern
96910e7e15SAnna Dabrowska        $sql = 'DELETE FROM structpublish_assignments_patterns WHERE pattern = ? AND user = ? AND status = ?';
97910e7e15SAnna Dabrowska        $ok = (bool)$this->sqlite->query($sql, [$pattern, $user, $status]);
98910e7e15SAnna Dabrowska
99910e7e15SAnna Dabrowska        // reload patterns
100910e7e15SAnna Dabrowska        $this->loadPatterns();
101910e7e15SAnna Dabrowska
102910e7e15SAnna Dabrowska        // fetch possibly affected pages
103910e7e15SAnna Dabrowska        $sql = 'SELECT pid FROM structpublish_assignments WHERE user = ? AND status = ?';
104910e7e15SAnna Dabrowska        $res = $this->sqlite->query($sql, [$user, $status]);
105910e7e15SAnna Dabrowska        $pagerows = $this->sqlite->res2arr($res);
106910e7e15SAnna Dabrowska        $this->sqlite->res_close($res);
107910e7e15SAnna Dabrowska
108910e7e15SAnna Dabrowska        // reevalute the pages and unassign when needed
109910e7e15SAnna Dabrowska        foreach ($pagerows as $row) {
110910e7e15SAnna Dabrowska            $rules = $this->getPageAssignments($row['pid'], true);
111910e7e15SAnna Dabrowska            // remove assignments matching the rule
112910e7e15SAnna Dabrowska            foreach ($rules as $status => $users) {
113910e7e15SAnna Dabrowska                foreach ($users as $user) {
114910e7e15SAnna Dabrowska                    $this->deassignPage($row['pid'], $user, $status);
115910e7e15SAnna Dabrowska                }
116910e7e15SAnna Dabrowska            }
117910e7e15SAnna Dabrowska        }
118910e7e15SAnna Dabrowska
119910e7e15SAnna Dabrowska        return $ok;
120910e7e15SAnna Dabrowska    }
121910e7e15SAnna Dabrowska
122910e7e15SAnna Dabrowska    /**
123910e7e15SAnna Dabrowska     * Updates all assignments of a given page against the current patterns
124910e7e15SAnna Dabrowska     *
125910e7e15SAnna Dabrowska     * @param string $pid
126910e7e15SAnna Dabrowska     */
127910e7e15SAnna Dabrowska    public function updatePageAssignments($pid)
128910e7e15SAnna Dabrowska    {
129910e7e15SAnna Dabrowska        // reload patterns
130910e7e15SAnna Dabrowska        $this->loadPatterns();
131910e7e15SAnna Dabrowska        $rules = $this->getPageAssignments($pid, true);
132910e7e15SAnna Dabrowska
133910e7e15SAnna Dabrowska        foreach ($rules as $status => $users) {
134910e7e15SAnna Dabrowska            foreach ($users as $user) {
135910e7e15SAnna Dabrowska                $this->assignPage($pid, $user, $status);
136910e7e15SAnna Dabrowska            }
137910e7e15SAnna Dabrowska        }
138910e7e15SAnna Dabrowska
139910e7e15SAnna Dabrowska        // fetch known pages
140910e7e15SAnna Dabrowska        /** @var \helper_plugin_structpublish_db $helper */
141910e7e15SAnna Dabrowska        $helper = plugin_load('helper', 'structpublish_db');
142910e7e15SAnna Dabrowska        $pages = $helper->getPages($pid);
143910e7e15SAnna Dabrowska
144910e7e15SAnna Dabrowska        // FIXME reevalute existing assignments
145910e7e15SAnna Dabrowska    }
146910e7e15SAnna Dabrowska
147910e7e15SAnna Dabrowska    /**
148910e7e15SAnna Dabrowska     * Clear all patterns - deassigns all pages
149910e7e15SAnna Dabrowska     *
150910e7e15SAnna Dabrowska     * This is mostly useful for testing and not used in the interface currently
151910e7e15SAnna Dabrowska     *
152910e7e15SAnna Dabrowska     * @param bool $full fully delete all previous assignments
153910e7e15SAnna Dabrowska     * @return bool
154910e7e15SAnna Dabrowska     */
155910e7e15SAnna Dabrowska    public function clear($full = false)
156910e7e15SAnna Dabrowska    {
157910e7e15SAnna Dabrowska        $sql = 'DELETE FROM structpublish_assignments_patterns';
158910e7e15SAnna Dabrowska        $ok = (bool)$this->sqlite->query($sql);
159910e7e15SAnna Dabrowska
160910e7e15SAnna Dabrowska        if ($full) {
161910e7e15SAnna Dabrowska            $sql = 'DELETE FROM structpublish_assignments';
162910e7e15SAnna Dabrowska        } else {
163910e7e15SAnna Dabrowska            $sql = 'UPDATE structpublish_assignments SET assigned = 0';
164910e7e15SAnna Dabrowska        }
165910e7e15SAnna Dabrowska        $ok = $ok && (bool)$this->sqlite->query($sql);
166910e7e15SAnna Dabrowska
167910e7e15SAnna Dabrowska        // reload patterns
168910e7e15SAnna Dabrowska        $this->loadPatterns();
169910e7e15SAnna Dabrowska
170910e7e15SAnna Dabrowska        return $ok;
171910e7e15SAnna Dabrowska    }
172910e7e15SAnna Dabrowska
173910e7e15SAnna Dabrowska    /**
174910e7e15SAnna Dabrowska     * Add page to assignments
175910e7e15SAnna Dabrowska     *
176910e7e15SAnna Dabrowska     * @param string $page
177910e7e15SAnna Dabrowska     * @param string $user
178910e7e15SAnna Dabrowska     * @param string $status
179910e7e15SAnna Dabrowska     * @return bool
180910e7e15SAnna Dabrowska     */
181910e7e15SAnna Dabrowska    public function assignPage($page, $user = null, $status = null)
182910e7e15SAnna Dabrowska    {
183910e7e15SAnna Dabrowska        $sql = 'REPLACE INTO structpublish_assignments (pid, user, status, assigned) VALUES (?, ?, ?, 1)';
184910e7e15SAnna Dabrowska        return (bool)$this->sqlite->query($sql, [$page, $user, $status]);
185910e7e15SAnna Dabrowska    }
186910e7e15SAnna Dabrowska
187910e7e15SAnna Dabrowska    /**
188910e7e15SAnna Dabrowska     * Remove page from assignments
189910e7e15SAnna Dabrowska     *
190910e7e15SAnna Dabrowska     * @param string $page
191910e7e15SAnna Dabrowska     * @param string $user
192910e7e15SAnna Dabrowska     * @return bool
193910e7e15SAnna Dabrowska     */
194910e7e15SAnna Dabrowska    public function deassignPage($page, $user, $status)
195910e7e15SAnna Dabrowska    {
196910e7e15SAnna Dabrowska        $sql = 'REPLACE INTO structpublish_assignments (pid, user, status, assigned) VALUES (?, ?, ?, 0)';
197910e7e15SAnna Dabrowska        return (bool)$this->sqlite->query($sql, [$page, $user, $status]);
198910e7e15SAnna Dabrowska    }
199910e7e15SAnna Dabrowska
200910e7e15SAnna Dabrowska    /**
201910e7e15SAnna Dabrowska     * Get the whole pattern table
202910e7e15SAnna Dabrowska     *
203910e7e15SAnna Dabrowska     * @return array
204910e7e15SAnna Dabrowska     */
205910e7e15SAnna Dabrowska    public function getAllPatterns()
206910e7e15SAnna Dabrowska    {
207910e7e15SAnna Dabrowska        return $this->patterns;
208910e7e15SAnna Dabrowska    }
209910e7e15SAnna Dabrowska
210910e7e15SAnna Dabrowska    /**
211*e31c94d7SAndreas Gohr     * Returns a list of user/group string lists per status assigned to the given page
212910e7e15SAnna Dabrowska     *
213910e7e15SAnna Dabrowska     * @param string $page
214910e7e15SAnna Dabrowska     * @param bool $checkpatterns Should the current patterns be re-evaluated?
215*e31c94d7SAndreas Gohr     * @return array users assigned [role => [user, ...], ...]
216910e7e15SAnna Dabrowska     */
217910e7e15SAnna Dabrowska    public function getPageAssignments($page, $checkpatterns = true)
218910e7e15SAnna Dabrowska    {
219910e7e15SAnna Dabrowska        $rules = [];
220910e7e15SAnna Dabrowska        $page = cleanID($page);
221910e7e15SAnna Dabrowska
222910e7e15SAnna Dabrowska        if ($checkpatterns) {
223910e7e15SAnna Dabrowska            $helper = plugin_load('helper', 'structpublish_assignments');
224910e7e15SAnna Dabrowska            // evaluate patterns
225910e7e15SAnna Dabrowska            $pns = ':' . getNS($page) . ':';
226910e7e15SAnna Dabrowska            foreach ($this->patterns as $row) {
227910e7e15SAnna Dabrowska                if ($helper->matchPagePattern($row['pattern'], $page, $pns)) {
228910e7e15SAnna Dabrowska                    $rules[$row['status']][] = $row['user'];
229910e7e15SAnna Dabrowska                }
230910e7e15SAnna Dabrowska            }
231910e7e15SAnna Dabrowska        } else {
232910e7e15SAnna Dabrowska            // just select
233910e7e15SAnna Dabrowska            $sql = 'SELECT user, status FROM structpublish_assignments WHERE pid = ? AND assigned = 1';
234910e7e15SAnna Dabrowska            $res = $this->sqlite->query($sql, [$page]);
235910e7e15SAnna Dabrowska            $list = $this->sqlite->res2arr($res);
236910e7e15SAnna Dabrowska            $this->sqlite->res_close($res);
237910e7e15SAnna Dabrowska            foreach ($list as $row) {
238910e7e15SAnna Dabrowska                $rules[$row['status']][] = $row['user'];
239910e7e15SAnna Dabrowska            }
240910e7e15SAnna Dabrowska        }
241910e7e15SAnna Dabrowska
242910e7e15SAnna Dabrowska        return $rules;
243910e7e15SAnna Dabrowska    }
244910e7e15SAnna Dabrowska
245910e7e15SAnna Dabrowska    /**
246910e7e15SAnna Dabrowska     * Get the pages known to struct and their assignment state
247910e7e15SAnna Dabrowska     *
248910e7e15SAnna Dabrowska     * @param bool $assignedonly limit results to currently assigned only
249910e7e15SAnna Dabrowska     * @return array
250910e7e15SAnna Dabrowska     */
251910e7e15SAnna Dabrowska    public function getPages($assignedOnly = false)
252910e7e15SAnna Dabrowska    {
253910e7e15SAnna Dabrowska        $sql = 'SELECT pid, user, status, assigned FROM structpublish_assignments WHERE 1=1';
254910e7e15SAnna Dabrowska
255910e7e15SAnna Dabrowska        $opts = array();
256910e7e15SAnna Dabrowska
257910e7e15SAnna Dabrowska        if ($assignedOnly) {
258910e7e15SAnna Dabrowska            $sql .= ' AND assigned = 1';
259910e7e15SAnna Dabrowska        }
260910e7e15SAnna Dabrowska
261910e7e15SAnna Dabrowska        $sql .= ' ORDER BY pid, user, status';
262910e7e15SAnna Dabrowska
263910e7e15SAnna Dabrowska        $res = $this->sqlite->query($sql, $opts);
264910e7e15SAnna Dabrowska        $list = $this->sqlite->res2arr($res);
265910e7e15SAnna Dabrowska        $this->sqlite->res_close($res);
266910e7e15SAnna Dabrowska
267910e7e15SAnna Dabrowska        $result = array();
268910e7e15SAnna Dabrowska        foreach ($list as $row) {
269910e7e15SAnna Dabrowska            $pid = $row['pid'];
270910e7e15SAnna Dabrowska            $user = $row['user'];
271910e7e15SAnna Dabrowska            $status = $row['status'];
272910e7e15SAnna Dabrowska            if (!isset($result[$pid])) $result[$pid] = array();
273910e7e15SAnna Dabrowska            $result[$pid][$user][$status] = (bool)$row['assigned'];
274910e7e15SAnna Dabrowska        }
275910e7e15SAnna Dabrowska
276910e7e15SAnna Dabrowska        return $result;
277910e7e15SAnna Dabrowska    }
278910e7e15SAnna Dabrowska}
279