1<?php
2
3use dokuwiki\plugin\structpublish\meta\Assignments;
4
5class helper_plugin_structpublish_db extends DokuWiki_Plugin
6{
7    protected $initialized = false;
8
9    /**
10     * Access the struct database
11     *
12     * Registers our own IS_PUBLISHER function with sqlite
13     *
14     * @return \dokuwiki\plugin\sqlite\SQLiteDB|null
15     */
16    public function getDB()
17    {
18        /** @var helper_plugin_struct_db $struct */
19        $struct = plugin_load('helper', 'struct_db');
20        if (!$struct) {
21            // FIXME show message?
22            return null;
23        }
24        $sqlite = $struct->getDB(false);
25        if (!$sqlite) {
26            return null;
27        }
28
29        // on init
30        if (!$this->initialized) {
31            $sqlite->getPdo()->sqliteCreateFunction('IS_PUBLISHER', [$this, 'isPublisher'], -1);
32            $this->initialized = true;
33        }
34
35        return $sqlite;
36    }
37
38    /**
39     * Get list of all pages known to the plugin
40     *
41     * @return array
42     */
43    public function getPages()
44    {
45        $sqlite = $this->getDB();
46        if (!$sqlite) {
47            return [];
48        }
49
50        $sql = 'SELECT pid FROM titles';
51        $list = $sqlite->queryAll($sql);
52        return array_column($list, 'pid');
53    }
54
55    /**
56     * Returns true if the given page is included in publishing workflows.
57     * If no pid is given, check current page.
58     *
59     * @return bool
60     */
61    public function isPublishable($pid = null)
62    {
63        global $ID;
64        $sqlite = $this->getDB();
65        if (!$sqlite) {
66            return false;
67        }
68
69        if (!$pid) {
70            $pid = $ID;
71        }
72
73        $sql = 'SELECT pid FROM structpublish_assignments WHERE pid = ? AND assigned = 1';
74        return (bool) $sqlite->queryAll($sql, $pid);
75    }
76
77    /**
78     * Check if the current user has the given roles on the current page
79     *
80     * @param string $pid The page ID to check access for
81     * @param string[] $roles Roles needed. Empty for any role
82     * @return bool
83     */
84    public function checkAccess($pid, $roles = [])
85    {
86        return self::userHasRole($pid, '', [], $roles);
87    }
88
89    /**
90     * Function registered in SQLite
91     *
92     * Params are read via function args
93     *
94     * @param ...string $pid, $userId, $groups...
95     * @return int Return an integer instead of boolean for better sqlite compatibility
96     */
97    public function isPublisher()
98    {
99
100        global $USERINFO;
101        global $INPUT;
102
103        $args = func_get_args();
104        $pid = $args[0];
105
106        if (!$pid || !$this->isPublishable($pid)) {
107            return 1;
108        }
109
110        $userId = $args[1] ?? $INPUT->server->str('REMOTE_USER');
111        $grps = $args[2] ?? ($USERINFO['grps'] ?? []);
112
113        return (int)$this->userHasRole(
114            $pid,
115            $userId,
116            $grps
117        );
118    }
119
120    /**
121     * Check if a given user has role assignment for a given page
122     *
123     * @param string $pid Page to check
124     * @param string $userId User login name, current user if empty
125     * @param string[] $grps Groups the user has, current user's groups if empty user
126     * @param string[] $roles Roles the user should have, empty for any role
127     * @return bool
128     */
129    public static function userHasRole($pid, $userId = '', $grps = [], $roles = [])
130    {
131        global $INPUT;
132        global $USERINFO;
133
134        if (blank($userId)) {
135            $userId = $INPUT->server->str('REMOTE_USER');
136            $grps = $USERINFO['grps'] ?? [];
137        }
138
139        $assignments = Assignments::getInstance();
140        $rules = $assignments->getPageAssignments($pid);
141
142        // if no roles are given, any role is fine
143        if (empty($roles)) {
144            return auth_isMember(
145                implode(',', array_merge(...array_values($rules))),
146                $userId,
147                $grps
148            );
149        }
150
151        foreach ($roles as $role) {
152            if (isset($rules[$role])) {
153                $users = $rules[$role];
154                if (auth_isMember(implode(',', $users), $userId, $grps)) {
155                    return true;
156                }
157            }
158        }
159
160        return false;
161    }
162}
163