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