Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
64.02% covered (warning)
64.02%
726 / 1134
57.55% covered (warning)
57.55%
61 / 106
CRAP
0.00% covered (danger)
0.00%
0 / 2
SeedDMS_Core_Role
26.51% covered (danger)
26.51%
22 / 83
47.06% covered (danger)
47.06%
8 / 17
611.22
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getInstance
83.33% covered (warning)
83.33%
10 / 12
0.00% covered (danger)
0.00%
0 / 1
7.23
 getAllInstances
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
30
 setDMS
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getID
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setName
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 isAdmin
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isGuest
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isUser
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRole
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setRole
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 getNoAccess
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setNoAccess
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 remove
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 isUsed
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 getUsers
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
30
SeedDMS_Core_User
66.98% covered (warning)
66.98%
704 / 1051
59.55% covered (warning)
59.55%
53 / 89
7804.87
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
1
 getInstance
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
8
 getAllInstances
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
7
 isType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setDMS
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDMS
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getID
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLogin
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setLogin
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 getFullName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setFullName
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 getPwd
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setPwd
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 getSecret
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setSecret
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 getPwdExpiration
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setPwdExpiration
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
 getEmail
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setEmail
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 getLanguage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setLanguage
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 getTheme
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setTheme
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 getComment
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setComment
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 getRole
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setRole
80.00% covered (warning)
80.00%
8 / 10
0.00% covered (danger)
0.00%
0 / 1
5.20
 isAdmin
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 isGuest
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 isUser
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 isHidden
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setHidden
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 isDisabled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setDisabled
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 addLoginFailure
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 clearLoginFailures
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 getUsedDiskSpace
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 getQuota
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setQuota
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 getHomeFolder
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setHomeFolder
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 __removeFromProcesses
16.67% covered (danger)
16.67%
18 / 108
0.00% covered (danger)
0.00%
0 / 1
3690.69
 removeFromProcesses
71.43% covered (warning)
71.43%
5 / 7
0.00% covered (danger)
0.00%
0 / 1
2.09
 __transferDocumentsFolders
68.42% covered (warning)
68.42%
13 / 19
0.00% covered (danger)
0.00%
0 / 1
8.54
 transferDocumentsFolders
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
3.10
 __transferEvents
71.43% covered (warning)
71.43%
5 / 7
0.00% covered (danger)
0.00%
0 / 1
3.21
 transferEvents
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 remove
49.45% covered (danger)
49.45%
45 / 91
0.00% covered (danger)
0.00%
0 / 1
105.73
 joinGroup
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
3.04
 leaveGroup
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
3.04
 getGroups
93.33% covered (success)
93.33%
14 / 15
0.00% covered (danger)
0.00%
0 / 1
5.01
 isMemberOfGroup
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasImage
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
4.02
 getImage
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 setImage
83.33% covered (warning)
83.33%
10 / 12
0.00% covered (danger)
0.00%
0 / 1
4.07
 getDocuments
73.33% covered (warning)
73.33%
11 / 15
0.00% covered (danger)
0.00%
0 / 1
4.30
 getDocumentsLocked
73.33% covered (warning)
73.33%
11 / 15
0.00% covered (danger)
0.00%
0 / 1
4.30
 getDocumentsCheckOut
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 getDocumentLinks
64.29% covered (warning)
64.29%
9 / 14
0.00% covered (danger)
0.00%
0 / 1
4.73
 getDocumentFiles
69.23% covered (warning)
69.23%
9 / 13
0.00% covered (danger)
0.00%
0 / 1
4.47
 getDocumentContents
66.67% covered (warning)
66.67%
8 / 12
0.00% covered (danger)
0.00%
0 / 1
4.59
 getFolders
92.31% covered (success)
92.31%
12 / 13
0.00% covered (danger)
0.00%
0 / 1
4.01
 getReviewStatus
79.17% covered (warning)
79.17%
38 / 48
0.00% covered (danger)
0.00%
0 / 1
20.93
 getApprovalStatus
80.00% covered (warning)
80.00%
40 / 50
0.00% covered (danger)
0.00%
0 / 1
20.59
 getReceiptStatus
79.17% covered (warning)
79.17%
38 / 48
0.00% covered (danger)
0.00%
0 / 1
26.38
 getRevisionStatus
82.00% covered (warning)
82.00%
41 / 50
0.00% covered (danger)
0.00%
0 / 1
24.82
 getWorkflowStatus
53.85% covered (warning)
53.85%
14 / 26
0.00% covered (danger)
0.00%
0 / 1
29.62
 getWorkflowsInvolved
70.00% covered (warning)
70.00%
7 / 10
0.00% covered (danger)
0.00%
0 / 1
5.68
 getMandatoryReviewers
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getMandatoryApprovers
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 isMandatoryReviewerOf
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 isMandatoryApproverOf
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 getMandatoryWorkflow
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
4.25
 getMandatoryWorkflows
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
5
 setMandatoryReviewer
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
8
 setMandatoryApprover
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
8
 setMandatoryWorkflow
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 setMandatoryWorkflows
71.43% covered (warning)
71.43%
10 / 14
0.00% covered (danger)
0.00%
0 / 1
5.58
 delMandatoryReviewers
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 delMandatoryApprovers
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 delMandatoryWorkflow
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getSubstitutes
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
30
 getReverseSubstitutes
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
42
 addSubstitute
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
42
 removeSubstitute
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
42
 isSubstitute
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
30
 maySwitchToUser
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
56
 getNotifications
71.43% covered (warning)
71.43%
10 / 14
0.00% covered (danger)
0.00%
0 / 1
5.58
 getKeywordCategories
63.64% covered (warning)
63.64%
7 / 11
0.00% covered (danger)
0.00%
0 / 1
4.77
1<?php
2declare(strict_types=1);
3
4/**
5 * Implementation of the user object in the document management system
6 *
7 * @category   DMS
8 * @package    SeedDMS_Core
9 * @license    GPL 2
10 * @version    @version@
11 * @author     Uwe Steinmann <uwe@steinmann.cx>
12 * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
13 *             2010-2024 Uwe Steinmann
14 * @version    Release: @package_version@
15 */
16
17/**
18 * Class to represent a role in the document management system
19 *
20 * @category   DMS
21 * @package    SeedDMS_Core
22 * @author     Uwe Steinmann <uwe@steinmann.cx>
23 * @copyright  Copyright (C) 2016 Uwe Steinmann
24 * @version    Release: @package_version@
25 */
26class SeedDMS_Core_Role { /* {{{ */
27    /**
28     * @var integer id of role
29     *
30     * @access protected
31     */
32    var $_id;
33
34    /**
35     * @var string name of role
36     *
37     * @access protected
38     */
39    var $_name;
40
41    /**
42     * @var string role of user. Can be one of SeedDMS_Core_Role::role_user,
43     *      SeedDMS_Core_Role::role_admin, SeedDMS_Core_Role::role_guest
44     *
45     * @access protected
46     */
47    var $_role;
48
49    /**
50     * @var array list of status without access
51     *
52     * @access protected
53     */
54    var $_noaccess;
55
56    /**
57     * @var object reference to the dms instance this user belongs to
58     *
59     * @access protected
60     */
61    var $_dms;
62
63    const role_user = '0';
64    const role_admin = '1';
65    const role_guest = '2';
66
67    function __construct($id, $name, $role, $noaccess=array()) { /* {{{ */
68        $this->_id = $id;
69        $this->_name = $name;
70        $this->_role = $role;
71        $this->_noaccess = $noaccess;
72        $this->_dms = null;
73    } /* }}} */
74
75    /**
76     * Create an instance of a role object
77     *
78     * @param string|integer $id Id, login name, or email of user, depending
79     * on the 3rd parameter.
80     * @param object $dms instance of dms
81     * @param string $by search by name. If 'name' is passed, the method
82     * will search by name instead of id. If this
83     * parameter is left empty, the role will be searched by its Id.
84     *
85     * @return object instance of class SeedDMS_Core_User
86     */
87    public static function getInstance($id, $dms, $by='') { /* {{{ */
88        $db = $dms->getDB();
89
90        switch($by) {
91        case 'name':
92            $queryStr = "SELECT * FROM `tblRoles` WHERE `name` = ".$db->qstr($id);
93            break;
94        default:
95            $queryStr = "SELECT * FROM `tblRoles` WHERE `id` = " . (int) $id;
96        }
97
98        $resArr = $db->getResultArray($queryStr);
99        if (is_bool($resArr) && $resArr == false) return false;
100        if (count($resArr) != 1) return false;
101
102        $resArr = $resArr[0];
103
104        $role = new self($resArr["id"], $resArr["name"], $resArr["role"], $resArr['noaccess'] ? explode(',', $resArr['noaccess']) : array());
105        $role->setDMS($dms);
106        return $role;
107    } /* }}} */
108
109    public static function getAllInstances($orderby, $dms) { /* {{{ */
110        $db = $dms->getDB();
111
112        if($orderby == 'name')
113            $queryStr = "SELECT * FROM `tblRoles` ORDER BY `name`";
114        else
115            $queryStr = "SELECT * FROM `tblRoles` ORDER BY `id`";
116        $resArr = $db->getResultArray($queryStr);
117
118        if (is_bool($resArr) && $resArr == false)
119            return false;
120
121        $roles = array();
122
123        for ($i = 0; $i < count($resArr); $i++) {
124            $role = new self($resArr[$i]["id"], $resArr[$i]["name"], $resArr[$i]["role"], explode(',', $resArr[$i]['noaccess']));
125            $role->setDMS($dms);
126            $roles[$i] = $role;
127        }
128
129        return $roles;
130} /* }}} */
131
132    function setDMS($dms) {
133        $this->_dms = $dms;
134    }
135
136    function getID() { return $this->_id; }
137
138    function getName() { return $this->_name; }
139
140    function setName($newName) { /* {{{ */
141        $db = $this->_dms->getDB();
142
143        $queryStr = "UPDATE `tblRoles` SET `name` =".$db->qstr($newName)." WHERE `id` = " . $this->_id;
144        $res = $db->getResult($queryStr);
145        if (!$res)
146            return false;
147
148        $this->_name = $newName;
149        return true;
150    } /* }}} */
151
152    function isAdmin() { return ($this->_role == SeedDMS_Core_Role::role_admin); }
153
154    function isGuest() { return ($this->_role == SeedDMS_Core_Role::role_guest); }
155
156    function isUser() { return ($this->_role == SeedDMS_Core_Role::role_user); }
157
158    function getRole() { return $this->_role; }
159
160    function setRole($newrole) { /* {{{ */
161        $db = $this->_dms->getDB();
162
163        $queryStr = "UPDATE `tblRoles` SET `role` = " . $newrole . " WHERE `id` = " . $this->_id;
164        if (!$db->getResult($queryStr))
165            return false;
166
167        $this->_role = $newrole;
168        return true;
169    } /* }}} */
170
171    function getNoAccess() { return $this->_noaccess; }
172
173    function setNoAccess($noaccess) { /* {{{ */
174        $db = $this->_dms->getDB();
175
176        $queryStr = "UPDATE `tblRoles` SET `noaccess` = " . $db->qstr($noaccess ? implode(',',$noaccess) : '') . " WHERE `id` = " . $this->_id;
177        if (!$db->getResult($queryStr))
178            return false;
179
180        $this->_noaccess = $noaccess;
181        return true;
182    } /* }}} */
183
184    /**
185     * Delete role
186     *
187     * @return boolean true on success or false in case of an error
188     */
189    function remove() { /* {{{ */
190        $db = $this->_dms->getDB();
191
192        $queryStr = "DELETE FROM `tblRoles` WHERE `id` = " . $this->_id;
193        if (!$db->getResult($queryStr)) {
194            return false;
195        }
196
197        return true;
198    } /* }}} */
199
200    function isUsed() { /* {{{ */
201        $db = $this->_dms->getDB();
202        
203        $queryStr = "SELECT * FROM `tblUsers` WHERE `role`=".$this->_id;
204        $resArr = $db->getResultArray($queryStr);
205        if (is_array($resArr) && count($resArr) == 0)
206            return false;
207        return true;
208    } /* }}} */
209
210    function getUsers() { /* {{{ */
211        $db = $this->_dms->getDB();
212        
213        if (!isset($this->_users)) {
214            $queryStr = "SELECT * FROM `tblUsers` WHERE `role`=".$this->_id;
215            $resArr = $db->getResultArray($queryStr);
216            if (is_bool($resArr) && $resArr == false)
217                return false;
218
219            $this->_users = array();
220
221            $classnamerole = $this->_dms->getClassname('role');
222
223            $classname = $this->_dms->getClassname('user');
224            foreach ($resArr as $row) {
225                $role = $classnamerole::getInstance($row['role'], $this->_dms);
226                $user = new $classname($row["id"], $row["login"], $row["pwd"], $row["fullName"], $row["email"], $row["language"], $row["theme"], $row["comment"], $role, $row['hidden']);
227                $user->setDMS($this->_dms);
228                array_push($this->_users, $user);
229            }
230        }
231        return $this->_users;
232    } /* }}} */
233
234} /* }}} */
235
236/**
237 * Class to represent a user in the document management system
238 *
239 * @category   DMS
240 * @package    SeedDMS_Core
241 * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
242 * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
243 *             2010-2024 Uwe Steinmann
244 * @version    Release: @package_version@
245 */
246class SeedDMS_Core_User { /* {{{ */
247    /**
248     * @var integer id of user
249     *
250     * @access protected
251     */
252    protected $_id;
253
254    /**
255     * @var string login name of user
256     *
257     * @access protected
258     */
259    protected $_login;
260
261    /**
262     * @var string password of user as saved in database (md5)
263     *
264     * @access protected
265     */
266    protected $_pwd;
267
268    /**
269     * @var string secret of user for 2-factor authentication
270     *
271     * @access protected
272     */
273    var $_secret;
274
275    /**
276     * @var string date when password expires
277     *
278     * @access protected
279     */
280    protected $_pwdExpiration;
281
282    /**
283     * @var string full human readable name of user
284     *
285     * @access protected
286     */
287    protected $_fullName;
288
289    /**
290     * @var string email address of user
291     *
292     * @access protected
293     */
294    protected $_email;
295
296    /**
297     * @var string prefered language of user
298     *      possible values are subdirectories within the language directory
299     *
300     * @access protected
301     */
302    protected $_language;
303
304    /**
305     * @var string preselected theme of user
306     *
307     * @access protected
308     */
309    protected $_theme;
310
311    /**
312     * @var string comment of user
313     *
314     * @access protected
315     */
316    protected $_comment;
317
318    /**
319     * @var object SeedDMS_Core_Role
320     *
321     * @access protected
322     */
323    protected $_role;
324
325    /**
326     * @var boolean true if user shall be hidden
327     *
328     * @access protected
329     */
330    protected $_isHidden;
331
332    /**
333     * @var boolean true if user is disabled
334     *
335     * @access protected
336     */
337    protected $_isDisabled;
338
339    /**
340     * @var int number of login failures
341     *
342     * @access protected
343     */
344    protected $_loginFailures;
345
346    /**
347     * @var SeedDMS_Core_Folder home folder
348     *
349     * @access protected
350     */
351    protected $_homeFolder;
352
353    /**
354     * @var array list of users this user can substitute
355     *
356     * @access protected
357     */
358    var $_substitutes;
359
360    /**
361     * @var array reverse list of users this user can substitute
362     *
363     * @access protected
364     */
365    var $_rev_substitutes;
366
367    /**
368     * @var array list of groups
369     *
370     * @access protected
371     */
372    protected $_groups;
373
374    /**
375     * @var SeedDMS_Core_DMS reference to the dms instance this user belongs to
376     *
377     * @access protected
378     */
379    protected $_dms;
380
381    /**
382     * @var int
383     *
384     * @access protected
385     */
386    protected $_quota;
387
388    /**
389     * @var bool
390     *
391     * @access protected
392     */
393    protected $_hasImage;
394
395    /**
396     * SeedDMS_Core_User constructor.
397     * @param $id
398     * @param $login
399     * @param $pwd
400     * @param $fullName
401     * @param $email
402     * @param $language
403     * @param $theme
404     * @param $comment
405     * @param $role
406     * @param int $isHidden
407     * @param int $isDisabled
408     * @param string $pwdExpiration
409     * @param int $loginFailures
410     * @param int $quota
411     * @param null $homeFolder
412     * @param string $secret
413     */
414    public function __construct($id, $login, $pwd, $fullName, $email, $language, $theme, $comment, $role, $isHidden=0, $isDisabled=0, $pwdExpiration='', $loginFailures=0, $quota=0, $homeFolder=null, $secret='') {
415        $this->_id = $id;
416        $this->_login = $login;
417        $this->_pwd = $pwd;
418        $this->_fullName = $fullName;
419        $this->_email = $email;
420        $this->_language = $language;
421        $this->_theme = $theme;
422        $this->_comment = $comment;
423        $this->_role = $role;
424        $this->_isHidden = (bool) $isHidden;
425        $this->_isDisabled = (bool) $isDisabled;
426        $this->_pwdExpiration = $pwdExpiration;
427        $this->_loginFailures = $loginFailures;
428        $this->_quota = $quota;
429        $this->_homeFolder = $homeFolder;
430        $this->_secret = $secret;
431        $this->_substitutes = null;
432        $this->_rev_substitutes = null;
433        $this->_dms = null;
434    }
435
436    /**
437     * Create an instance of a user object
438     *
439     * @param string|integer $id Id, login name, or email of user, depending
440     * on the 3rd parameter.
441     * @param SeedDMS_Core_DMS $dms instance of dms
442     * @param string $by search by [name|email]. If 'name' is passed, the method
443     * will check for the 4th paramater and also filter by email. If this
444     * parameter is left empty, the user will be search by its Id.
445     * @param string $email optional email address if searching for name
446     * @return SeedDMS_Core_User|bool instance of class SeedDMS_Core_User if user was
447     * found, null if user was not found, false in case of error
448     */
449    public static function getInstance($id, $dms, $by='', $email='') { /* {{{ */
450        $db = $dms->getDB();
451
452        switch($by) {
453        case 'name':
454            $queryStr = "SELECT * FROM `tblUsers` WHERE `login` = ".$db->qstr((string) $id);
455            if($email)
456                $queryStr .= " AND `email`=".$db->qstr($email);
457            break;
458        case 'email':
459            $queryStr = "SELECT * FROM `tblUsers` WHERE `email` = ".$db->qstr((string) $id);
460            break;
461        default:
462            $queryStr = "SELECT * FROM `tblUsers` WHERE `id` = " . (int) $id;
463        }
464        $resArr = $db->getResultArray($queryStr);
465
466        if (is_bool($resArr) && $resArr == false) return false;
467        if (count($resArr) != 1) return null;
468
469        $resArr = $resArr[0];
470
471        $classname = $dms->getClassname('role');
472        $role = $classname::getInstance($resArr['role'], $dms);
473
474        $user = new self((int) $resArr["id"], $resArr["login"], $resArr["pwd"], $resArr["fullName"], $resArr["email"], $resArr["language"], $resArr["theme"], $resArr["comment"], $role, $resArr["hidden"], $resArr["disabled"], $resArr["pwdExpiration"], $resArr["loginfailures"], $resArr["quota"], $resArr["homefolder"], $resArr["secret"]);
475        $user->setDMS($dms);
476        return $user;
477    } /* }}} */
478
479    /**
480     * Return all users
481     *
482     * @param $orderby can be `fullname`
483     * @param SeedDMS_Core_DMS $dms
484     * @return SeedDMS_Core_User[]|bool
485     */
486    public static function getAllInstances($orderby, $dms) { /* {{{ */
487        $db = $dms->getDB();
488
489        if($orderby == 'fullname')
490            $queryStr = "SELECT * FROM `tblUsers` ORDER BY `fullName`";
491        else
492            $queryStr = "SELECT * FROM `tblUsers` ORDER BY `login`";
493        $resArr = $db->getResultArray($queryStr);
494
495        if (is_bool($resArr) && $resArr == false)
496            return false;
497
498        $users = array();
499
500        $classname = $dms->getClassname('role');
501        for ($i = 0; $i < count($resArr); $i++) {
502            /** @var SeedDMS_Core_User $user */
503            $role = $classname::getInstance($resArr[$i]['role'], $dms);
504            $user = new self($resArr[$i]["id"], $resArr[$i]["login"], $resArr[$i]["pwd"], $resArr[$i]["fullName"], $resArr[$i]["email"], (isset($resArr[$i]["language"])?$resArr[$i]["language"]:NULL), (isset($resArr[$i]["theme"])?$resArr[$i]["theme"]:NULL), $resArr[$i]["comment"], $role, $resArr[$i]["hidden"], $resArr[$i]["disabled"], $resArr[$i]["pwdExpiration"], $resArr[$i]["loginfailures"], $resArr[$i]["quota"], $resArr[$i]["homefolder"]);
505            $user->setDMS($dms);
506            $users[$i] = $user;
507        }
508
509        return $users;
510} /* }}} */
511
512    /**
513     * Check if this object is of type 'user'.
514     *
515     * @param string $type type of object
516     */
517    public function isType($type) { /* {{{ */
518        return $type == 'user';
519    } /* }}} */
520
521    /**
522     * @param SeedDMS_Core_DMS $dms
523     */
524    public function setDMS($dms) {
525        $this->_dms = $dms;
526    }
527
528    /**
529     * @return SeedDMS_Core_DMS $dms
530     */
531    public function getDMS() {
532        return $this->_dms;
533    }
534
535    /**
536     * Return internal id of user
537     *
538     * @return int
539     */
540    public function getID() { return $this->_id; }
541
542    /**
543     * Return login of user
544     *
545     * @return string
546     */
547    public function getLogin() { return $this->_login; }
548
549    /**
550     * Change login of user
551     *
552     * @param $newLogin new login
553     * @return bool
554     */
555    public function setLogin($newLogin) { /* {{{ */
556        $newLogin = trim($newLogin);
557        if(!$newLogin)
558            return false;
559
560        $db = $this->_dms->getDB();
561
562        $queryStr = "UPDATE `tblUsers` SET `login` =".$db->qstr($newLogin)." WHERE `id` = " . $this->_id;
563        $res = $db->getResult($queryStr);
564        if (!$res)
565            return false;
566
567        $this->_login = $newLogin;
568        return true;
569    } /* }}} */
570
571    /**
572     * Return full name of user
573     *
574     * @return string
575     */
576    public function getFullName() { return $this->_fullName; }
577
578    /**
579     * Set full name of user
580     *
581     * @param $newFullName
582     * @return bool
583     */
584    public function setFullName($newFullName) { /* {{{ */
585        $db = $this->_dms->getDB();
586
587        $queryStr = "UPDATE `tblUsers` SET `fullName` = ".$db->qstr($newFullName)." WHERE `id` = " . $this->_id;
588        $res = $db->getResult($queryStr);
589        if (!$res)
590            return false;
591
592        $this->_fullName = $newFullName;
593        return true;
594    } /* }}} */
595
596    /**
597     * Get encrypted password of user
598     *
599     * @return string
600     */
601    public function getPwd() { return $this->_pwd; }
602
603    /**
604     * Set password of user
605     *
606     * The password must be encrypted before calling this method.
607     *
608     * @param $newPwd new encrypted password
609     * @return bool
610     */
611    public function setPwd($newPwd) { /* {{{ */
612        $db = $this->_dms->getDB();
613
614        $queryStr = "UPDATE `tblUsers` SET `pwd` =".$db->qstr($newPwd)." WHERE `id` = " . $this->_id;
615        $res = $db->getResult($queryStr);
616        if (!$res)
617            return false;
618
619        $this->_pwd = $newPwd;
620        return true;
621    } /* }}} */
622
623    /**
624     * @return string
625     */
626    public function getSecret() { return $this->_secret; }
627
628    /**
629     * @param string $newSecret
630     */
631    public function setSecret($newSecret) { /* {{{ */
632        $db = $this->_dms->getDB();
633
634        $queryStr = "UPDATE `tblUsers` SET `secret` =".$db->qstr($newSecret)." WHERE `id` = " . $this->_id;
635        $res = $db->getResult($queryStr);
636        if (!$res)
637            return false;
638
639        $this->_secret = $newSecret;
640        return true;
641    } /* }}} */
642
643    /**
644     * @return string
645     */
646    public function getPwdExpiration() { return $this->_pwdExpiration; }
647
648    /**
649     * @param $newPwdExpiration
650     * @return bool
651     */
652    public function setPwdExpiration($newPwdExpiration) { /* {{{ */
653        $db = $this->_dms->getDB();
654
655        if(trim($newPwdExpiration) == '' || trim($newPwdExpiration) == 'never') {
656            $newPwdExpiration = null;
657            $queryStr = "UPDATE `tblUsers` SET `pwdExpiration` = NULL WHERE `id` = " . $this->_id;
658        } else {
659            if(trim($newPwdExpiration) == 'now')
660                $newPwdExpiration = date('Y-m-d H:i:s');
661            $queryStr = "UPDATE `tblUsers` SET `pwdExpiration` =".$db->qstr($newPwdExpiration)." WHERE `id` = " . $this->_id;
662        }
663        $res = $db->getResult($queryStr);
664        if (!$res)
665            return false;
666
667        $this->_pwdExpiration = $newPwdExpiration;
668        return true;
669    } /* }}} */
670
671    /**
672     * Get email address of user
673     *
674     * @return string
675     */
676    public function getEmail() { return $this->_email; }
677
678    /**
679     * Change email address of user
680     *
681     * @param $newEmail new email address
682     * @return bool
683     */
684    public function setEmail($newEmail) { /* {{{ */
685        $db = $this->_dms->getDB();
686
687        $queryStr = "UPDATE `tblUsers` SET `email` =".$db->qstr(trim($newEmail))." WHERE `id` = " . $this->_id;
688        $res = $db->getResult($queryStr);
689        if (!$res)
690            return false;
691
692        $this->_email = $newEmail;
693        return true;
694    } /* }}} */
695
696    /**
697     * @return string
698     */
699    public function getLanguage() { return $this->_language; }
700
701    /**
702     * @param $newLanguage
703     * @return bool
704     */
705    public function setLanguage($newLanguage) { /* {{{ */
706        $db = $this->_dms->getDB();
707
708        $queryStr = "UPDATE `tblUsers` SET `language` =".$db->qstr(trim($newLanguage))." WHERE `id` = " . $this->_id;
709        $res = $db->getResult($queryStr);
710        if (!$res)
711            return false;
712
713        $this->_language = $newLanguage;
714        return true;
715    } /* }}} */
716
717    /**
718     * @return string
719     */
720    public function getTheme() { return $this->_theme; }
721
722    /**
723     * @param string $newTheme
724     * @return bool
725     */
726    public function setTheme($newTheme) { /* {{{ */
727        $db = $this->_dms->getDB();
728
729        $queryStr = "UPDATE `tblUsers` SET `theme` =".$db->qstr(trim($newTheme))." WHERE `id` = " . $this->_id;
730        $res = $db->getResult($queryStr);
731        if (!$res)
732            return false;
733
734        $this->_theme = $newTheme;
735        return true;
736    } /* }}} */
737
738    /**
739     * Return comment of user
740     *
741     * @return string
742     */
743    public function getComment() { return $this->_comment; }
744
745    /**
746     * Change comment of user
747     *
748     * @param $newComment new comment
749     * @return bool
750     */
751    public function setComment($newComment) { /* {{{ */
752        $db = $this->_dms->getDB();
753
754        $queryStr = "UPDATE `tblUsers` SET `comment` =".$db->qstr(trim($newComment))." WHERE `id` = " . $this->_id;
755        $res = $db->getResult($queryStr);
756        if (!$res)
757            return false;
758
759        $this->_comment = $newComment;
760        return true;
761    } /* }}} */
762
763    /**
764     * @return string
765     */
766    public function getRole() { return $this->_role; }
767
768    /**
769     * @param integer $newrole
770     * @return bool
771     */
772    public function setRole($newrole) { /* {{{ */
773        $db = $this->_dms->getDB();
774
775        if(!is_object($newrole) || (get_class($newrole) != $this->_dms->getClassname('role')))
776            return false;
777
778        if(is_object($newrole))
779            $queryStr = "UPDATE `tblUsers` SET `role` = " . $newrole->getID() . " WHERE `id` = " . $this->_id;
780        else
781            $queryStr = "UPDATE `tblUsers` SET `role` = " . $newrole . " WHERE `id` = " . $this->_id;
782        if (!$db->getResult($queryStr))
783            return false;
784
785        $this->_role = $newrole;
786        return true;
787    } /* }}} */
788
789    /**
790     * Check, if user is an administrator
791     *
792     * @return bool
793     */
794    public function isAdmin() { return (is_object($this->_role) ? $this->_role->isAdmin() : $this->_role == SeedDMS_Core_Role::role_admin); }
795
796    /**
797     * Check, if user is a guest
798     *
799     * @return bool
800     */
801    public function isGuest() { return (is_object($this->_role) ? $this->_role->isGuest() : $this->_role == SeedDMS_Core_Role::role_guest); }
802
803    /**
804     * Check, if user is a regular user
805     *
806     * @return bool
807     */
808    public function isUser() { return (is_object($this->_role) ? $this->_role->isUser() : $this->_role == SeedDMS_Core_Role::role_user); }
809
810    /**
811     * Check, if user is hidden
812     *
813     * @return bool
814     */
815    public function isHidden() { return $this->_isHidden; }
816
817    /**
818     * Set user hidden
819     *
820     * @param $isHidden
821     * @return bool
822     */
823    public function setHidden($isHidden) { /* {{{ */
824        $db = $this->_dms->getDB();
825
826        $isHidden = ($isHidden) ? "1" : "0";
827        $queryStr = "UPDATE `tblUsers` SET `hidden` = " . intval($isHidden) . " WHERE `id` = " . $this->_id;
828        if (!$db->getResult($queryStr))
829            return false;
830
831        $this->_isHidden = (bool) $isHidden;
832        return true;
833    }     /* }}} */
834
835    /**
836     * Check, if user is disabled
837     *
838     * @return bool|int
839     */
840    public function isDisabled() { return $this->_isDisabled; }
841
842    /**
843     * Disable user
844     *
845     * @param $isDisabled
846     * @return bool
847     */
848    public function setDisabled($isDisabled) { /* {{{ */
849        $db = $this->_dms->getDB();
850
851        $isDisabled = ($isDisabled) ? "1" : "0";
852        $queryStr = "UPDATE `tblUsers` SET `disabled` = " . intval($isDisabled) . " WHERE `id` = " . $this->_id;
853        if (!$db->getResult($queryStr))
854            return false;
855
856        $this->_isDisabled = (bool) $isDisabled;
857        return true;
858    }     /* }}} */
859
860    /**
861     * @return bool|int
862     */
863    public function addLoginFailure() { /* {{{ */
864        $db = $this->_dms->getDB();
865
866        $this->_loginFailures++;
867        $queryStr = "UPDATE `tblUsers` SET `loginfailures` = " . $this->_loginFailures . " WHERE `id` = " . $this->_id;
868        if (!$db->getResult($queryStr))
869            return false;
870
871        return $this->_loginFailures;
872    } /* }}} */
873
874    /**
875     * @return bool
876     */
877    public function clearLoginFailures() { /* {{{ */
878        $db = $this->_dms->getDB();
879
880        $this->_loginFailures = 0;
881        $queryStr = "UPDATE `tblUsers` SET `loginfailures` = " . $this->_loginFailures . " WHERE `id` = " . $this->_id;
882        if (!$db->getResult($queryStr))
883            return false;
884
885        return true;
886    } /* }}} */
887
888    /**
889     * Calculate the disk space for all documents owned by the user
890     * 
891     * This is done by using the internal database field storing the
892     * filesize of a document version.
893     *
894     * @return integer total disk space in Bytes
895     */
896    public function getUsedDiskSpace() { /* {{{ */
897        $db = $this->_dms->getDB();
898
899        $queryStr = "SELECT SUM(`fileSize`) sum FROM `tblDocumentContent` a LEFT JOIN `tblDocuments` b ON a.`document`=b.`id` WHERE b.`owner` = " . $this->_id;
900        $resArr = $db->getResultArray($queryStr);
901        if (is_bool($resArr) && $resArr == false)
902            return false;
903
904        return (int) $resArr[0]['sum'];
905    } /* }}} */
906
907    /**
908     * @return int
909     */
910    public function getQuota() { return $this->_quota; }
911
912    /**
913     * @param integer $quota
914     * @return bool
915     */
916    public function setQuota($quota) { /* {{{ */
917        if (!is_numeric($quota))
918            return false;
919        if($quota < 0)
920            return false;
921
922        $db = $this->_dms->getDB();
923
924        $quota = intval($quota);
925        $queryStr = "UPDATE `tblUsers` SET `quota` = " . $quota . " WHERE `id` = " . $this->_id;
926        if (!$db->getResult($queryStr))
927            return false;
928
929        $this->_quota = $quota;
930        return true;
931    }     /* }}} */
932
933    /**
934     * @return null|SeedDMS_Core_Folder
935     */
936    public function getHomeFolder() { return $this->_homeFolder; }
937
938    /**
939     * @param integer $homefolder
940     * @return bool
941     */
942    public function setHomeFolder($homefolder) { /* {{{ */
943        $db = $this->_dms->getDB();
944        $homefolder = intval($homefolder);
945
946        $queryStr = "UPDATE `tblUsers` SET `homefolder` = " . ($homefolder ? $homefolder : 'NULL') . " WHERE `id` = " . $this->_id;
947        if (!$db->getResult($queryStr))
948            return false;
949
950        $this->_homeFolder = $homefolder;
951        return true;
952    }     /* }}} */
953
954    /**
955     * Remove user from all processes
956     *
957     * This method adds another log entry to the reviews, approvals, receptions, revisions,
958     * which indicates that the user has been deleted from the process. By default it will
959     * do so for each review/approval/reception/revision regardless of its current state unless
960     * the user has been removed already (status=-2). So even
961     * reviews/approvals/receptions/revisions already processed by the user will be added the log
962     * entry. Only, if the last log entry was a removal already, it will not be
963     * added a second time.
964     * This behaviour can be changed by passing a list of states in the optional
965     * argument $states. Only reviews, etc. in the given state will be affected.
966     * This allows to remove the user only if the review, etc. has not been done
967     * (state = 0).
968     *
969     * The last optional parameter $newuser is for replacing the user currently in
970     * charge by another user. If this parameter is passed, the old user will
971     * be deleted first (like described above) and afterwards the new user will
972     * be addded. The deletion of the old user and adding the new user will only
973     * happen if the new user has at least read access on the document. If not,
974     * the document will be skipped and remained unchanged.
975     *
976     * This removal from processes will also take place for older versions of a document.
977     *
978     * This methode was initialy added to remove a user (which is going to be deleted
979     * afterwards) from all processes he or she is still involved in.
980     *
981     * If a new user is passed, then this user will be added as a new reviewer, approver, etc.
982     * Hence, this method does not replace the old user but actually deletes the old user and
983     * adds a new one. Adding the new reviewer, approver, etc. will also be done for old versions
984     * of a document. The same operation could be archieved by first calling
985     * SeedDMS_Core_DocumentVersion::delIndReviewer() followed by SeedDMS_Core_DocumentVersion::addIndReviewer()
986     * but this would require to do for each version of a document and the operation would not
987     * be in a single transaction.
988     *
989     * A new user is only added if the process (review, approval, etc.) is still in its initial
990     * state (have not been reviewed/approved or rejected). Unlike the removal of the user (see above).
991     *
992     * If a new user is given but has no read access on the document the transfer for that
993     * particular document will be skipped. Not even the removal of the user will take place.
994     * 
995     * @param object $user the user doing the removal (needed for entry in
996     *        review and approve log).
997     * @param array $states remove user only from reviews/approvals in one of the states
998     *        e.g. if passing array('review'=>array(0)), the method will operate on
999     *        reviews which has not been touched yet.
1000     * @param object $newuser user who takes over the processes
1001     * @param array $docs remove only processes from docs with the given document ids
1002     * @return boolean true on success or false in case of an error
1003     */
1004    private function __removeFromProcesses($user, $states = array(), $newuser=null, $docs=null) { /* {{{ */
1005        $db = $this->_dms->getDB();
1006
1007        /* Get a list of all reviews, even those of older document versions */
1008        $reviewStatus = $this->getReviewStatus();
1009        $db->startTransaction();
1010        foreach ($reviewStatus["indstatus"] as $ri) {
1011            if(!($doc = $this->_dms->getDocument($ri['documentID'])))
1012                continue;
1013            if($docs) {
1014                if(!in_array($doc->getID(), $docs))
1015                    continue;
1016                if(!$doc->isLatestContent($ri['version']))
1017                    continue;
1018            }
1019            if($newuser && $doc->getAccessMode($newuser) < M_READ)
1020                continue;
1021            if($ri['status'] != -2 && (!isset($states['review']) || in_array($ri['status'], $states['review']))) {
1022                $queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
1023                    "VALUES ('". $ri["reviewID"] ."', '-2', '".(($newuser && $ri['status'] == 0) ? 'Reviewer replaced by '.$newuser->getLogin() : 'Reviewer removed from process')."', ".$db->getCurrentDatetime().", '". $user->getID() ."')";
1024                $res=$db->getResult($queryStr);
1025                if(!$res) {
1026                    $db->rollbackTransaction();
1027                    return false;
1028                }
1029                /* Only reviews not done already can be transferred to a new user */
1030                if($newuser && $ri['status'] == 0) {
1031                    if($version = $doc->getContentByVersion($ri['version'])) {
1032                        $ret = $version->addIndReviewer($newuser, $user);
1033                        /* returns -3 if the user is already a reviewer */ 
1034                        if($ret === false || ($ret < 0 && $ret != -3)) {
1035                            $db->rollbackTransaction();
1036                            return false;
1037                        }
1038                    }
1039                }
1040            }
1041        }
1042        $db->commitTransaction();
1043
1044        /* Get a list of all approvals, even those of older document versions */
1045        $approvalStatus = $this->getApprovalStatus();
1046        $db->startTransaction();
1047        foreach ($approvalStatus["indstatus"] as $ai) {
1048            if(!($doc = $this->_dms->getDocument($ai['documentID'])))
1049                continue;
1050            if($docs) {
1051                if(!in_array($doc->getID(), $docs))
1052                    continue;
1053                if(!$doc->isLatestContent($ai['version']))
1054                    continue;
1055            }
1056            if($newuser && $doc->getAccessMode($newuser) < M_READ)
1057                continue;
1058            if($ai['status'] != -2 && (!isset($states['approval']) || in_array($ai['status'], $states['approval']))) {
1059                $queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
1060                    "VALUES ('". $ai["approveID"] ."', '-2', '".(($newuser && $ai['status'] == 0)? 'Approver replaced by '.$newuser->getLogin() : 'Approver removed from process')."', ".$db->getCurrentDatetime().", '". $user->getID() ."')";
1061                $res=$db->getResult($queryStr);
1062                if(!$res) {
1063                    $db->rollbackTransaction();
1064                    return false;
1065                }
1066                /* Only approvals not done already can be transferred to a new user */
1067                if($newuser && $ai['status'] == 0) {
1068                    if($version = $doc->getContentByVersion($ai['version'])) {
1069                        $ret = $version->addIndReviewer($newuser, $user);
1070                        /* returns -3 if the user is already a reviewer */ 
1071                        if($ret === false || ($ret < 0 && $ret != -3)) {
1072                            $db->rollbackTransaction();
1073                            return false;
1074                        }
1075                    }
1076                }
1077            }
1078        }
1079        $db->commitTransaction();
1080
1081        /* Get a list of all receptions, even those of older document versions */
1082        $receiptStatus = $this->getReceiptStatus();
1083        $db->startTransaction();
1084        foreach ($receiptStatus["indstatus"] as $ri) {
1085            if(!($doc = $this->_dms->getDocument($ri['documentID'])))
1086                continue;
1087            if($docs) {
1088                if(!in_array($doc->getID(), $docs))
1089                    continue;
1090                if(!$doc->isLatestContent($ri['version']))
1091                    continue;
1092            }
1093            if($newuser && $doc->getAccessMode($newuser) < M_READ)
1094                continue;
1095            if($ri['status'] != -2 && (!isset($states['receipt']) || in_array($ri['status'], $states['receipt']))) {
1096                $queryStr = "INSERT INTO `tblDocumentReceiptLog` (`receiptID`, `status`, `comment`, `date`, `userID`) ".
1097                    "VALUES ('". $ri["receiptID"] ."', '-2', '".(($newuser && $ri['status'] == 0) ? 'Recipient replaced by '.$newuser->getLogin() : 'Recipient removed from process')."', ".$db->getCurrentDatetime().", '". $user->getID() ."')";
1098                $res=$db->getResult($queryStr);
1099                if(!$res) {
1100                    $db->rollbackTransaction();
1101                    return false;
1102                }
1103                /* Only receptions not done already can be transferred to a new user */
1104                if($newuser && $ri['status'] == 0) {
1105                    if($doc = $this->_dms->getDocument($ri['documentID'])) {
1106                        if($version = $doc->getContentByVersion($ri['version'])) {
1107                            $ret = $version->addIndRecipient($newuser, $user);
1108                            /* returns -3 if the user is already a recipient */ 
1109                            if($ret === false || ($ret < 0 && $ret != -3)) {
1110                                $db->rollbackTransaction();
1111                                return false;
1112                            }
1113                        }
1114                    }
1115                }
1116            }
1117        }
1118        $db->commitTransaction();
1119
1120        /* Get a list of all revisions, even those of older document versions */
1121        $revisionStatus = $this->getRevisionStatus();
1122        $db->startTransaction();
1123        foreach ($revisionStatus["indstatus"] as $ri) {
1124            if(!($doc = $this->_dms->getDocument($ri['documentID'])))
1125                continue;
1126            if($docs) {
1127                if(!in_array($doc->getID(), $docs))
1128                    continue;
1129                if(!$doc->isLatestContent($ri['version']))
1130                    continue;
1131            }
1132            if($newuser && $doc->getAccessMode($newuser) < M_READ)
1133                continue;
1134            if($ri['status'] != -2 && (!isset($states['revision']) || in_array($ri['status'], $states['revision']))) {
1135                $queryStr = "INSERT INTO `tblDocumentRevisionLog` (`revisionID`, `status`, `comment`, `date`, `userID`) ".
1136                    "VALUES ('". $ri["revisionID"] ."', '-2', '".(($newuser && in_array($ri['status'], array(S_LOG_WAITING, S_LOG_SLEEPING))) ? 'Revisor replaced by '.$newuser->getLogin() : 'Revisor removed from process')."', ".$db->getCurrentDatetime().", '". $user->getID() ."')";
1137                $res=$db->getResult($queryStr);
1138                if(!$res) {
1139                    $db->rollbackTransaction();
1140                    return false;
1141                }
1142                /* Only revisions not already done or sleeping can be transferred to a new user */
1143                if($newuser && in_array($ri['status'], array(S_LOG_WAITING, S_LOG_SLEEPING))) {
1144                    if($doc = $this->_dms->getDocument($ri['documentID'])) {
1145                        if($version = $doc->getContentByVersion($ri['version'])) {
1146                            $ret = $version->addIndRevisor($newuser, $user);
1147                            /* returns -3 if the user is already a revisor */ 
1148                            if($ret === false || ($ret < 0 && $ret != -3)) {
1149                                $db->rollbackTransaction();
1150                                return false;
1151                            }
1152                        }
1153                    }
1154                }
1155            }
1156        }
1157        $db->commitTransaction();
1158
1159        return true;
1160    } /* }}} */
1161
1162    /**
1163     * Remove user from all processes
1164     *
1165     * This includes review, approval and workflow
1166     *
1167     * @param object $user the user doing the removal (needed for entry in
1168     *        review and approve log).
1169     * @param array $states remove user only from reviews/approvals in one of the states
1170     * @param object $newuser user who takes over the processes
1171     * @return boolean true on success or false in case of an error
1172     */
1173    public function removeFromProcesses($user, $states=array(), $newuser=null, $docs=null) { /* {{{ */
1174        $db = $this->_dms->getDB();
1175
1176        $db->startTransaction();
1177        if(!$this->__removeFromProcesses($user, $states, $newuser, $docs)) {
1178            $db->rollbackTransaction();
1179            return false;
1180        }
1181        $db->commitTransaction();
1182        return true;
1183    } /* }}} */
1184
1185    /**
1186     * Transfer documents and folders to another user
1187     *
1188     * @param object $assignToUser the user who is new owner of folders and
1189     *        documents which previously were owned by the delete user.
1190     * @return boolean true on success or false in case of an error
1191     */
1192    private function __transferDocumentsFolders($assignToUser) { /* {{{ */
1193        $db = $this->_dms->getDB();
1194
1195        if(!$assignToUser)
1196            return false;
1197
1198        /* Assign documents of the removed user to the given user */
1199        $queryStr = "UPDATE `tblFolders` SET `owner` = " . $assignToUser->getID() . " WHERE `owner` = " . $this->_id;
1200        if (!$db->getResult($queryStr)) {
1201            return false;
1202        }
1203
1204        $queryStr = "UPDATE `tblDocuments` SET `owner` = " . $assignToUser->getID() . " WHERE `owner` = " . $this->_id;
1205        if (!$db->getResult($queryStr)) {
1206            return false;
1207        }
1208
1209        $queryStr = "UPDATE `tblDocumentContent` SET `createdBy` = " . $assignToUser->getID() . " WHERE `createdBy` = " . $this->_id;
1210        if (!$db->getResult($queryStr)) {
1211            return false;
1212        }
1213
1214        // ... but keep public links
1215        $queryStr = "UPDATE `tblDocumentLinks` SET `userID` = " . $assignToUser->getID() . " WHERE `userID` = " . $this->_id;
1216        if (!$db->getResult($queryStr)) {
1217            return false;
1218        }
1219
1220        // set administrator for deleted user's attachments
1221        $queryStr = "UPDATE `tblDocumentFiles` SET `userID` = " . $assignToUser->getID() . " WHERE `userID` = " . $this->_id;
1222        if (!$db->getResult($queryStr)) {
1223            return false;
1224        }
1225
1226        return true;
1227    } /* }}} */
1228
1229    /**
1230     * Transfer documents and folders to another user
1231     *
1232     * @param object $assignToUser the user who is new owner of folders and
1233     *        documents which previously were owned by the delete user.
1234     * @return boolean true on success or false in case of an error
1235     */
1236    public function transferDocumentsFolders($assignToUser) { /* {{{ */
1237        $db = $this->_dms->getDB();
1238
1239        if($assignToUser->getID() == $this->_id)
1240            return true;
1241
1242        $db->startTransaction();
1243        if(!$this->__transferDocumentsFolders($assignToUser)) {
1244            $db->rollbackTransaction();
1245            return false;
1246        }
1247        $db->commitTransaction();
1248        return true;
1249    } /* }}} */
1250
1251    /**
1252     * Transfer events to another user
1253     *
1254     * @param object $assignToUser the user who is new owner of events
1255     * @return boolean true on success or false in case of an error
1256     */
1257    private function __transferEvents($assignToUser) { /* {{{ */
1258        $db = $this->_dms->getDB();
1259
1260        if(!$assignToUser)
1261            return false;
1262
1263        // set new owner of events
1264        $queryStr = "UPDATE `tblEvents` SET `userID` = " . $assignToUser->getID() . " WHERE `userID` = " . $this->_id;
1265        if (!$db->getResult($queryStr)) {
1266            return false;
1267        }
1268
1269        return true;
1270    } /* }}} */
1271
1272    /**
1273     * Transfer events to another user
1274     *
1275     * @param object $assignToUser the user who is new owner of events
1276     * @return boolean true on success or false in case of an error
1277     */
1278    public function transferEvents($assignToUser) { /* {{{ */
1279        $db = $this->_dms->getDB();
1280
1281        if($assignToUser->getID() == $this->_id)
1282            return true;
1283
1284        $db->startTransaction();
1285        if(!$this->__transferEvents($assignToUser)) {
1286            $db->rollbackTransaction();
1287            return false;
1288        }
1289        $db->commitTransaction();
1290        return true;
1291    } /* }}} */
1292
1293    /**
1294     * Remove the user and also remove all its keywords, notifications, etc.
1295     * Do not remove folders and documents of the user, but assign them
1296     * to a different user.
1297     *
1298     * @param SeedDMS_Core_User $user the user doing the removal (needed for entry in
1299     *        review and approve log).
1300     * @param SeedDMS_Core_User $assignToUser the user who is new owner of folders and
1301     *        documents which previously were owned by the delete user.
1302     * @return boolean true on success or false in case of an error
1303     */
1304    function remove($user, $assignToUser=null) { /* {{{ */
1305        $db = $this->_dms->getDB();
1306
1307        /* Records like folders and documents that formely have belonged to
1308         * the user will assign to another user. If no such user is set,
1309         * the function now returns false and will not use the admin user
1310         * anymore.
1311         */
1312        if(!$assignToUser)
1313            return false;
1314            /** @noinspection PhpUnusedLocalVariableInspection */
1315            $assignTo = $assignToUser->getID();
1316
1317        $db->startTransaction();
1318
1319        // delete private keyword lists
1320        $queryStr = "SELECT `tblKeywords`.`id` FROM `tblKeywords`, `tblKeywordCategories` WHERE `tblKeywords`.`category` = `tblKeywordCategories`.`id` AND `tblKeywordCategories`.`owner` = " . $this->_id;
1321        $resultArr = $db->getResultArray($queryStr);
1322        if (count($resultArr) > 0) {
1323            $queryStr = "DELETE FROM `tblKeywords` WHERE ";
1324            for ($i = 0; $i < count($resultArr); $i++) {
1325                $queryStr .= "id = " . $resultArr[$i]["id"];
1326                if ($i + 1 < count($resultArr))
1327                    $queryStr .= " OR ";
1328            }
1329            if (!$db->getResult($queryStr)) {
1330                $db->rollbackTransaction();
1331                return false;
1332            }
1333        }
1334
1335        $queryStr = "DELETE FROM `tblKeywordCategories` WHERE `owner` = " . $this->_id;
1336        if (!$db->getResult($queryStr)) {
1337            $db->rollbackTransaction();
1338            return false;
1339        }
1340
1341        //Benachrichtigungen entfernen
1342        $queryStr = "DELETE FROM `tblNotify` WHERE `userID` = " . $this->_id;
1343        if (!$db->getResult($queryStr)) {
1344            $db->rollbackTransaction();
1345            return false;
1346        }
1347
1348        // Remove private links on documents ...
1349        $queryStr = "DELETE FROM `tblDocumentLinks` WHERE `userID` = " . $this->_id . " AND `public` = 0";
1350        if (!$db->getResult($queryStr)) {
1351            $db->rollbackTransaction();
1352            return false;
1353        }
1354
1355        /* Assign documents, folders, files, public document links of the removed user to the given user */
1356        if(!$this->__transferDocumentsFolders($assignToUser)) {
1357                $db->rollbackTransaction();
1358                return false;
1359        }
1360
1361        // unlock documents locked by the user
1362        $queryStr = "DELETE FROM `tblDocumentLocks` WHERE `userID` = " . $this->_id;
1363        if (!$db->getResult($queryStr)) {
1364            $db->rollbackTransaction();
1365            return false;
1366        }
1367
1368        // Delete user from all groups
1369        $queryStr = "DELETE FROM `tblGroupMembers` WHERE `userID` = " . $this->_id;
1370        if (!$db->getResult($queryStr)) {
1371            $db->rollbackTransaction();
1372            return false;
1373        }
1374
1375        // User aus allen ACLs streichen
1376        $queryStr = "DELETE FROM `tblACLs` WHERE `userID` = " . $this->_id;
1377        if (!$db->getResult($queryStr)) {
1378            $db->rollbackTransaction();
1379            return false;
1380        }
1381
1382        // Delete image of user
1383        $queryStr = "DELETE FROM `tblUserImages` WHERE `userID` = " . $this->_id;
1384        if (!$db->getResult($queryStr)) {
1385            $db->rollbackTransaction();
1386            return false;
1387        }
1388
1389        // Delete entries in password history
1390        $queryStr = "DELETE FROM `tblUserPasswordHistory` WHERE `userID` = " . $this->_id;
1391        if (!$db->getResult($queryStr)) {
1392            $db->rollbackTransaction();
1393            return false;
1394        }
1395
1396        // Delete entries in password request
1397        $queryStr = "DELETE FROM `tblUserPasswordRequest` WHERE `userID` = " . $this->_id;
1398        if (!$db->getResult($queryStr)) {
1399            $db->rollbackTransaction();
1400            return false;
1401        }
1402
1403        // mandatory review/approve
1404        $queryStr = "DELETE FROM `tblMandatoryReviewers` WHERE `reviewerUserID` = " . $this->_id;
1405        if (!$db->getResult($queryStr)) {
1406            $db->rollbackTransaction();
1407            return false;
1408        }
1409
1410        $queryStr = "DELETE FROM `tblMandatoryApprovers` WHERE `approverUserID` = " . $this->_id;
1411        if (!$db->getResult($queryStr)) {
1412            $db->rollbackTransaction();
1413            return false;
1414        }
1415
1416        $queryStr = "DELETE FROM `tblMandatoryReviewers` WHERE `userID` = " . $this->_id;
1417        if (!$db->getResult($queryStr)) {
1418            $db->rollbackTransaction();
1419            return false;
1420        }
1421
1422        $queryStr = "DELETE FROM `tblMandatoryApprovers` WHERE `userID` = " . $this->_id;
1423        if (!$db->getResult($queryStr)) {
1424            $db->rollbackTransaction();
1425            return false;
1426        }
1427
1428        $queryStr = "DELETE FROM `tblWorkflowMandatoryWorkflow` WHERE `userid` = " . $this->_id;
1429        if (!$db->getResult($queryStr)) {
1430            $db->rollbackTransaction();
1431            return false;
1432        }
1433
1434        $queryStr = "DELETE FROM `tblWorkflowTransitionUsers` WHERE `userid` = " . $this->_id;
1435        if (!$db->getResult($queryStr)) {
1436            $db->rollbackTransaction();
1437            return false;
1438        }
1439
1440        /* Assign events of the removed user to the given user */
1441        if(!$this->__transferEvents($assignToUser)) {
1442                $db->rollbackTransaction();
1443                return false;
1444        }
1445
1446        // Delete user itself
1447        $queryStr = "DELETE FROM `tblUsers` WHERE `id` = " . $this->_id;
1448        if (!$db->getResult($queryStr)) {
1449            $db->rollbackTransaction();
1450            return false;
1451        }
1452
1453        // TODO : update document status if reviewer/approver has been deleted
1454        // "DELETE FROM `tblDocumentApproveLog` WHERE `userID` = " . $this->_id;
1455        // "DELETE FROM `tblDocumentReviewLog` WHERE `userID` = " . $this->_id;
1456
1457        if(!$this->__removeFromProcesses($user)) {
1458                $db->rollbackTransaction();
1459                return false;
1460        }
1461
1462        $db->commitTransaction();
1463        return true;
1464    } /* }}} */
1465
1466    /**
1467     * Make the user a member of a group
1468     * This function uses {@link SeedDMS_Group::addUser} but checks before if
1469     * the user is already a member of the group.
1470     *
1471     * @param SeedDMS_Core_Group $group group to be the member of
1472     * @return boolean true on success or false in case of an error or the user
1473     *        is already a member of the group
1474     */
1475    function joinGroup($group) { /* {{{ */
1476        if ($group->isMember($this))
1477            return false;
1478
1479        if (!$group->addUser($this))
1480            return false;
1481
1482        unset($this->_groups);
1483        return true;
1484    } /* }}} */
1485
1486    /**
1487     * Removes the user from a group
1488     * This function uses {@link SeedDMS_Group::removeUser} but checks before if
1489     * the user is a member of the group at all.
1490     *
1491     * @param SeedDMS_Core_Group $group group to leave
1492     * @return boolean true on success or false in case of an error or the user
1493     *        is not a member of the group
1494     */
1495    function leaveGroup($group) { /* {{{ */
1496        if (!$group->isMember($this))
1497            return false;
1498
1499        if (!$group->removeUser($this))
1500            return false;
1501
1502        unset($this->_groups);
1503        return true;
1504    } /* }}} */
1505
1506    /**
1507     * Get all groups the user is a member of
1508     *
1509     * @return SeedDMS_Core_Group[]|bool list of groups
1510     */
1511    function getGroups() { /* {{{ */
1512        $db = $this->_dms->getDB();
1513
1514        if (!isset($this->_groups))
1515        {
1516            $queryStr = "SELECT `tblGroups`.*, `tblGroupMembers`.`userID` FROM `tblGroups` ".
1517                "LEFT JOIN `tblGroupMembers` ON `tblGroups`.`id` = `tblGroupMembers`.`groupID` ".
1518                "WHERE `tblGroupMembers`.`userID`='". $this->_id ."'";
1519            $resArr = $db->getResultArray($queryStr);
1520            if (is_bool($resArr) && $resArr == false)
1521                return false;
1522
1523            $this->_groups = array();
1524            $classname = $this->_dms->getClassname('group');
1525            foreach ($resArr as $row) {
1526                /** @var SeedDMS_Core_Group $group */
1527                $group = new $classname((int) $row["id"], $row["name"], $row["comment"]);
1528                $group->setDMS($this->_dms);
1529                array_push($this->_groups, $group);
1530            }
1531        }
1532        return $this->_groups;
1533    } /* }}} */
1534
1535    /**
1536     * Checks if user is member of a given group
1537     *
1538     * @param SeedDMS_Core_Group $group
1539     * @return boolean true if user is member of the given group otherwise false
1540     */
1541    function isMemberOfGroup($group) { /* {{{ */
1542        return $group->isMember($this);
1543    } /* }}} */
1544
1545    /**
1546     * Check if user has an image in its profile
1547     *
1548     * @return boolean true if user has a picture of itself
1549     */
1550    function hasImage() { /* {{{ */
1551        if (!isset($this->_hasImage)) {
1552            $db = $this->_dms->getDB();
1553
1554            $queryStr = "SELECT COUNT(*) AS num FROM `tblUserImages` WHERE `userID` = " . $this->_id;
1555            $resArr = $db->getResultArray($queryStr);
1556            if ($resArr === false)
1557                return false;
1558
1559            if ($resArr[0]["num"] == 0)    $this->_hasImage = false;
1560            else $this->_hasImage = true;
1561        }
1562
1563        return $this->_hasImage;
1564    } /* }}} */
1565
1566    /**
1567     * Get the image from the users profile
1568     *
1569     * @return string|null|bool image data as a string or null if no image is set or
1570     * false in case of an error
1571     */
1572    function getImage() { /* {{{ */
1573        $db = $this->_dms->getDB();
1574
1575        $queryStr = "SELECT * FROM `tblUserImages` WHERE `userID` = " . $this->_id;
1576        $resArr = $db->getResultArray($queryStr);
1577        if ($resArr === false)
1578            return false;
1579
1580        if($resArr)
1581            return $resArr[0];
1582        else
1583            return null;
1584    } /* }}} */
1585
1586    /**
1587     * @param $tmpfile
1588     * @param $mimeType
1589     * @return bool
1590     */
1591    function setImage($tmpfile, $mimeType) { /* {{{ */
1592        $db = $this->_dms->getDB();
1593
1594        $fp = fopen($tmpfile, "rb");
1595        if (!$fp) return false;
1596        $content = fread($fp, filesize($tmpfile));
1597        fclose($fp);
1598
1599        if ($this->hasImage())
1600            $queryStr = "UPDATE `tblUserImages` SET `image` = '".base64_encode($content)."', `mimeType` = ".$db->qstr($mimeType)." WHERE `userID` = " . $this->_id;
1601        else
1602            $queryStr = "INSERT INTO `tblUserImages` (`userID`, `image`, `mimeType`) VALUES (" . $this->_id . ", '".base64_encode($content)."', ".$db->qstr($mimeType).")";
1603        if (!$db->getResult($queryStr))
1604            return false;
1605
1606        $this->_hasImage = true;
1607        return true;
1608    } /* }}} */
1609
1610    /**
1611     * Returns all documents of a given user
1612     * @return SeedDMS_Core_Document[]|bool list of documents
1613     */
1614    function getDocuments() { /* {{{ */
1615        $db = $this->_dms->getDB();
1616
1617        $queryStr = "SELECT `tblDocuments`.*, `tblDocumentLocks`.`userID` as `lockUser` ".
1618            "FROM `tblDocuments` ".
1619            "LEFT JOIN `tblDocumentLocks` ON `tblDocuments`.`id`=`tblDocumentLocks`.`document` ".
1620            "WHERE `tblDocuments`.`owner` = " . $this->_id . " ORDER BY `sequence`";
1621
1622        $resArr = $db->getResultArray($queryStr);
1623        if (is_bool($resArr) && !$resArr)
1624            return false;
1625
1626        $documents = array();
1627        $classname = $this->_dms->getClassname('document');
1628        foreach ($resArr as $row) {
1629            /** @var SeedDMS_Core_Document $document */
1630            $document = new $classname((int) $row["id"], $row["name"], $row["comment"], $row["date"], $row["expires"], $row["owner"], $row["folder"], $row["inheritAccess"], $row["defaultAccess"], $row["lockUser"], $row["keywords"], $row["sequence"]);
1631            $document->setDMS($this->_dms);
1632            $documents[] = $document;
1633        }
1634        return $documents;
1635    } /* }}} */
1636
1637    /**
1638     * Returns all documents locked by a given user
1639     *
1640     * @return bool|SeedDMS_Core_Document[] list of documents
1641     */
1642    function getDocumentsLocked() { /* {{{ */
1643        $db = $this->_dms->getDB();
1644
1645        $queryStr = "SELECT `tblDocuments`.*, `tblDocumentLocks`.`userID` as `lockUser` ".
1646            "FROM `tblDocumentLocks` LEFT JOIN `tblDocuments` ON `tblDocuments`.`id` = `tblDocumentLocks`.`document` ".
1647            "WHERE `tblDocumentLocks`.`userID` = '".$this->_id."' ".
1648            "ORDER BY `id` DESC";
1649
1650        $resArr = $db->getResultArray($queryStr);
1651        if (is_bool($resArr) && !$resArr)
1652            return false;
1653
1654        $documents = array();
1655        $classname = $this->_dms->getClassname('document');
1656        foreach ($resArr as $row) {
1657            /** @var SeedDMS_Core_Document $document */
1658            $document = new $classname((int) $row["id"], $row["name"], $row["comment"], $row["date"], $row["expires"], $row["owner"], $row["folder"], $row["inheritAccess"], $row["defaultAccess"], $row["lockUser"], $row["keywords"], $row["sequence"]);
1659            $document->setDMS($this->_dms);
1660            $documents[] = $document;
1661        }
1662        return $documents;
1663    } /* }}} */
1664
1665    /**
1666     * Returns all documents check out by a given user
1667     *
1668     * @param object $user
1669     * @return array list of documents
1670     */
1671    function getDocumentsCheckOut() { /* {{{ */
1672        $db = $this->_dms->getDB();
1673
1674        $queryStr = "SELECT `tblDocuments`.* ".
1675            "FROM `tblDocumentCheckOuts` LEFT JOIN `tblDocuments` ON `tblDocuments`.`id` = `tblDocumentCheckOuts`.`document` ".
1676            "WHERE `tblDocumentCheckOuts`.`userID` = '".$this->_id."' ".
1677            "ORDER BY `id` ASC";
1678
1679        $resArr = $db->getResultArray($queryStr);
1680        if (is_bool($resArr) && !$resArr)
1681            return false;
1682
1683        $documents = array();
1684        $classname = $this->_dms->getClassname('document');
1685        foreach ($resArr as $row) {
1686            $document = new $classname($row["id"], $row["name"], $row["comment"], $row["date"], $row["expires"], $row["owner"], $row["folder"], $row["inheritAccess"], $row["defaultAccess"], $row["lockUser"], $row["keywords"], $row["sequence"]);
1687            $document->setDMS($this->_dms);
1688            $documents[] = $document;
1689        }
1690        return $documents;
1691    } /* }}} */
1692
1693    /**
1694     * Returns all document links of a given user
1695     * @return SeedDMS_Core_DocumentLink[]|bool list of document links
1696     */
1697    function getDocumentLinks() { /* {{{ */
1698        $db = $this->_dms->getDB();
1699
1700        $queryStr = "SELECT * FROM `tblDocumentLinks` ".
1701            "WHERE `userID` = " . $this->_id;
1702
1703        $resArr = $db->getResultArray($queryStr);
1704        if (is_bool($resArr) && !$resArr)
1705            return false;
1706
1707        $links = array();
1708        $classname = 'SeedDMS_Core_DocumentLink';
1709        foreach ($resArr as $row) {
1710            $document = $this->_dms->getDocument($row["document"]);
1711            $target = $this->_dms->getDocument($row["target"]);
1712            /** @var SeedDMS_Core_Document $document */
1713            $link = new $classname((int) $row["id"], $document, $target, $row["userID"], $row["public"]);
1714            $links[] = $link;
1715        }
1716        return $links;
1717    } /* }}} */
1718
1719    /**
1720     * Returns all document files of a given user
1721     * @return SeedDMS_Core_DocumentFile[]|bool list of document files
1722     */
1723    function getDocumentFiles() { /* {{{ */
1724        $db = $this->_dms->getDB();
1725
1726        $queryStr = "SELECT * FROM `tblDocumentFiles` ".
1727            "WHERE `userID` = " . $this->_id;
1728
1729        $resArr = $db->getResultArray($queryStr);
1730        if (is_bool($resArr) && !$resArr)
1731            return false;
1732
1733        $files = array();
1734        $classname = 'SeedDMS_Core_DocumentFile';
1735        foreach ($resArr as $row) {
1736            $document = $this->_dms->getDocument($row["document"]);
1737            /** @var SeedDMS_Core_DocumentFile $file */
1738            $file = new $classname((int) $row["id"], $document, $row["userID"], $row["comment"], $row["date"], $row["dir"], $row["fileType"], $row["mimeType"], $row["orgFileName"], $row["name"],$row["version"],$row["public"]);
1739            $files[] = $file;
1740        }
1741        return $files;
1742    } /* }}} */
1743
1744    /**
1745     * Returns all document contents of a given user
1746     * @return SeedDMS_Core_DocumentContent[]|bool list of document contents
1747     */
1748    function getDocumentContents() { /* {{{ */
1749        $db = $this->_dms->getDB();
1750
1751        $queryStr = "SELECT * FROM `tblDocumentContent` WHERE `createdBy` = " . $this->_id;
1752
1753        $resArr = $db->getResultArray($queryStr);
1754        if (is_bool($resArr) && !$resArr)
1755            return false;
1756
1757        $contents = array();
1758        $classname = $this->_dms->getClassname('documentcontent');
1759        foreach ($resArr as $row) {
1760            $document = $this->_dms->getDocument($row["document"]);
1761            /** @var SeedDMS_Core_DocumentContent $content */
1762            $content = new $classname((int) $row["id"], $document, $row["version"], $row["comment"], $row["date"], $row["createdBy"], $row["dir"], $row["orgFileName"], $row["fileType"], $row["mimeType"], $row['fileSize'], $row['checksum']);
1763            $contents[] = $content;
1764        }
1765        return $contents;
1766    } /* }}} */
1767
1768    /**
1769     * Returns all folders of a given user
1770     * @return SeedDMS_Core_Folder[]|bool list of folders
1771     */
1772    function getFolders() { /* {{{ */
1773        $db = $this->_dms->getDB();
1774
1775        $queryStr = "SELECT * FROM `tblFolders` ".
1776            "WHERE `owner` = " . $this->_id . " ORDER BY `sequence`";
1777
1778        $resArr = $db->getResultArray($queryStr);
1779        if (is_bool($resArr) && !$resArr)
1780            return false;
1781
1782        $folders = array();
1783        $classname = $this->_dms->getClassname('folder');
1784        foreach ($resArr as $row) {
1785            /** @var SeedDMS_Core_Folder $folder */
1786            $folder = new $classname((int) $row["id"], $row["name"], $row['parent'], $row["comment"], $row["date"], $row["owner"], $row["inheritAccess"], $row["defaultAccess"], $row["sequence"]);
1787            $folder->setDMS($this->_dms);
1788            $folders[] = $folder;
1789        }
1790        return $folders;
1791    } /* }}} */
1792
1793    /**
1794     * Get a list of reviews
1795     *
1796     * This function returns a list of all reviews and their latest log entry
1797     * seperated by individuals and groups. If the document id
1798     * is passed, then only this document will be checked for reviews. The
1799     * same is true for the version of a document which limits the list
1800     * further. If you do not limit on a version it will retrieve the status
1801     * for each version, that includes even older versions which has been superseded
1802     * by a new version.
1803     *
1804     * For a detailed description of the result array see
1805     * {link SeedDMS_Core_User::getApprovalStatus} which does the same for
1806     * approvals.
1807     *
1808     * @param int $documentID optional document id for which to retrieve the
1809     *        reviews
1810     * @param int $version optional version of the document
1811     * @return array|bool list of all reviews
1812     */
1813    function getReviewStatus($documentID=null, $version=null) { /* {{{ */
1814        $db = $this->_dms->getDB();
1815
1816        if (!$db->createTemporaryTable("ttreviewid", true)) {
1817            return false;
1818        }
1819
1820        $status = array("indstatus"=>array(), "grpstatus"=>array());
1821
1822        // See if the user is assigned as an individual reviewer.
1823        // Attention: this method didn't use ttreviewid to filter out the latest
1824        // log entry. This was added 2021-09-29 because $group->getReviewStatus()
1825        // does it as well. The check below if the date is larger than the date
1826        // of a previos entry is still required to just take the latest version
1827        // of a document into account.
1828        $queryStr = "SELECT `tblDocumentReviewers`.*, `tblDocumentReviewLog`.`status`, ".
1829            "`tblDocumentReviewLog`.`comment`, `tblDocumentReviewLog`.`date`, ".
1830            "`tblDocumentReviewLog`.`userID` ".
1831            "FROM `tblDocumentReviewers` ".
1832            "LEFT JOIN `tblDocumentReviewLog` USING (`reviewID`) ".
1833            "LEFT JOIN `ttreviewid` on `ttreviewid`.`maxLogID` = `tblDocumentReviewLog`.`reviewLogID` ".
1834            "WHERE `ttreviewid`.`maxLogID`=`tblDocumentReviewLog`.`reviewLogID` ".
1835            ($documentID==null ? "" : "AND `tblDocumentReviewers`.`documentID` = '". (int) $documentID ."' ").
1836            ($version==null ? "" : "AND `tblDocumentReviewers`.`version` = '". (int) $version ."' ").
1837            "AND `tblDocumentReviewers`.`type`='0' ".
1838            "AND `tblDocumentReviewers`.`required`='". $this->_id ."' ".
1839            "ORDER BY `tblDocumentReviewLog`.`reviewLogID` DESC";
1840        $resArr = $db->getResultArray($queryStr);
1841        if (is_bool($resArr) && $resArr === false)
1842            return false;
1843        if (count($resArr)>0) {
1844            foreach ($resArr as $res) {
1845                if(isset($status["indstatus"][$res['documentID']])) {
1846                    if($status["indstatus"][$res['documentID']]['date'] < $res['date']) {
1847                        $status["indstatus"][$res['documentID']] = $res;
1848                    }
1849                } else {
1850                    $status["indstatus"][$res['documentID']] = $res;
1851                }
1852            }
1853        }
1854
1855        // See if the user is the member of a group that has been assigned to
1856        // review the document version.
1857        $queryStr = "SELECT `tblDocumentReviewers`.*, `tblDocumentReviewLog`.`status`, ".
1858            "`tblDocumentReviewLog`.`comment`, `tblDocumentReviewLog`.`date`, ".
1859            "`tblDocumentReviewLog`.`userID` ".
1860            "FROM `tblDocumentReviewers` ".
1861            "LEFT JOIN `tblDocumentReviewLog` USING (`reviewID`) ".
1862            "LEFT JOIN `ttreviewid` on `ttreviewid`.`maxLogID` = `tblDocumentReviewLog`.`reviewLogID` ".
1863            "LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`groupID` = `tblDocumentReviewers`.`required` ".
1864            "WHERE `ttreviewid`.`maxLogID`=`tblDocumentReviewLog`.`reviewLogID` ".
1865            ($documentID==null ? "" : "AND `tblDocumentReviewers`.`documentID` = '". (int) $documentID ."' ").
1866            ($version==null ? "" : "AND `tblDocumentReviewers`.`version` = '". (int) $version ."' ").
1867            "AND `tblDocumentReviewers`.`type`='1' ".
1868            "AND `tblGroupMembers`.`userID`='". $this->_id ."' ".
1869            "ORDER BY `tblDocumentReviewLog`.`reviewLogID` DESC";
1870        $resArr = $db->getResultArray($queryStr);
1871        if (is_bool($resArr) && $resArr === false)
1872            return false;
1873        if (count($resArr)>0) {
1874            foreach ($resArr as $res) {
1875                if(isset($status["grpstatus"][$res['documentID']])) {
1876                    if($status["grpstatus"][$res['documentID']]['date'] < $res['date']) {
1877                        $status["grpstatus"][$res['documentID']] = $res;
1878                    }
1879                } else {
1880                    $status["grpstatus"][$res['documentID']] = $res;
1881                }
1882            }
1883        }
1884        return $status;
1885    } /* }}} */
1886
1887    /**
1888     * Get a list of approvals
1889     *
1890     * This function returns a list of all approvals and their latest log entry
1891     * seperated by individuals and groups. If the document id
1892     * is passed, then only this document will be checked for approvals. The
1893     * same is true for the version of a document which limits the list
1894     * further. If you do not limit on a version it will retrieve the status
1895     * for each version, that includes even older versions which has been superseded
1896     * by a new version.
1897     *
1898     * The result array has two elements:
1899     * - indstatus: which contains the approvals by individuals (users)
1900     * - grpstatus: which contains the approvals by groups
1901     *
1902     * Each element is itself an array of approvals with the following elements
1903     * (it is a combination of fields from tblDocumentApprovers and tblDocumentApproveLog):
1904     * - approveID: unique id of approval
1905     * - documentID: id of document, that needs to be approved
1906     * - version: version of document, that needs to be approved
1907     * - type: 0 for individual approval, 1 for group approval
1908     * - required: id of user who is required to do the approval
1909     * - status: 0 not approved, ....
1910     * - comment: comment given during approval
1911     * - date: date of approval
1912     * - userID: id of user who has done the approval
1913     *
1914     * @param int $documentID optional document id for which to retrieve the
1915     *        approvals
1916     * @param int $version optional version of the document
1917     * @return array|bool list of all approvals
1918     */
1919    function getApprovalStatus($documentID=null, $version=null) { /* {{{ */
1920        $db = $this->_dms->getDB();
1921
1922        if (!$db->createTemporaryTable("ttapproveid")) {
1923            return false;
1924        }
1925
1926        $status = array("indstatus"=>array(), "grpstatus"=>array());
1927
1928        // See if the user is assigned as an individual approver.
1929        // Attention: this method didn't use ttapproveid to filter out the latest
1930        // log entry. This was added 2021-09-29 because $group->getApprovalStatus()
1931        // does it as well. The check below if the date is larger than the date
1932        // of a previos entry is still required to just take the latest version
1933        // of a document into account.
1934        $queryStr =
1935            "SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
1936            "`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
1937            "`tblDocumentApproveLog`.`userID` ".
1938            "FROM `tblDocumentApprovers` ".
1939            "LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
1940            "LEFT JOIN `ttapproveid` on `ttapproveid`.`maxLogID` = `tblDocumentApproveLog`.`approveLogID` ".
1941            "WHERE `ttapproveid`.`maxLogID`=`tblDocumentApproveLog`.`approveLogID` ".
1942            ($documentID==null ? "" : "AND `tblDocumentApprovers`.`documentID` = '". (int) $documentID ."' ").
1943            ($version==null ? "" : "AND `tblDocumentApprovers`.`version` = '". (int) $version ."' ").
1944            "AND `tblDocumentApprovers`.`type`='0' ".
1945            "AND `tblDocumentApprovers`.`required`='". $this->_id ."' ".
1946            "ORDER BY `tblDocumentApproveLog`.`approveLogID` DESC";
1947
1948        $resArr = $db->getResultArray($queryStr);
1949        if (is_bool($resArr) && $resArr == false)
1950            return false;
1951        if (count($resArr)>0) {
1952            foreach ($resArr as $res) {
1953                if(isset($status["indstatus"][$res['documentID']])) {
1954                    if($status["indstatus"][$res['documentID']]['date'] < $res['date']) {
1955                        $status["indstatus"][$res['documentID']] = $res;
1956                    }
1957                } else {
1958                    $status["indstatus"][$res['documentID']] = $res;
1959                }
1960            }
1961        }
1962
1963        // See if the user is the member of a group that has been assigned to
1964        // approve the document version.
1965        $queryStr =
1966            "SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
1967            "`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
1968            "`tblDocumentApproveLog`.`userID` ".
1969            "FROM `tblDocumentApprovers` ".
1970            "LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
1971            "LEFT JOIN `ttapproveid` on `ttapproveid`.`maxLogID` = `tblDocumentApproveLog`.`approveLogID` ".
1972            "LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`groupID` = `tblDocumentApprovers`.`required` ".
1973            "WHERE `ttapproveid`.`maxLogID`=`tblDocumentApproveLog`.`approveLogID` ".
1974            ($documentID==null ? "" : "AND `tblDocumentApprovers`.`documentID` = '". (int) $documentID ."' ").
1975            ($version==null ? "" : "AND `tblDocumentApprovers`.`version` = '". (int) $version ."' ").
1976            "AND `tblDocumentApprovers`.`type`='1' ".
1977            "AND `tblGroupMembers`.`userID`='". $this->_id ."' ".
1978            "ORDER BY `tblDocumentApproveLog`.`approveLogID` DESC";
1979        $resArr = $db->getResultArray($queryStr);
1980        if (is_bool($resArr) && $resArr == false)
1981            return false;
1982        if (count($resArr)>0) {
1983            foreach ($resArr as $res) {
1984                if(isset($status["grpstatus"][$res['documentID']])) {
1985                    if($status["grpstatus"][$res['documentID']]['date'] < $res['date']) {
1986                        $status["grpstatus"][$res['documentID']] = $res;
1987                    }
1988                } else {
1989                    $status["grpstatus"][$res['documentID']] = $res;
1990                }
1991            }
1992        }
1993        return $status;
1994    } /* }}} */
1995
1996    /**
1997     * Get a list of receipts
1998     * This function returns a list of all receipts seperated by individual
1999     * and group receipts. If the document id
2000     * is passed, then only this document will be checked for receipts. The
2001     * same is true for the version of a document which limits the list
2002     * further.
2003     *
2004     * For a detaile description of the result array see
2005     * {link SeedDMS_Core_User::getApprovalStatus} which does the same for
2006     * approvals.
2007     *
2008     * @param int $documentID optional document id for which to retrieve the
2009     *        receipt
2010     * @param int $version optional version of the document
2011     * @return array list of all receipts
2012     */
2013    function getReceiptStatus($documentID=null, $version=null) { /* {{{ */
2014        $db = $this->_dms->getDB();
2015
2016        $status = array("indstatus"=>array(), "grpstatus"=>array());
2017
2018        if (!$db->createTemporaryTable("ttcontentid")) {
2019            return false;
2020        }
2021        // See if the user is assigned as an individual recipient.
2022        // left join with ttcontentid to restrict result on latest version of document
2023        // unless a document and version is given
2024        $queryStr = "SELECT `tblDocumentRecipients`.*, `tblDocumentReceiptLog`.`status`, ".
2025            "`tblDocumentReceiptLog`.`comment`, `tblDocumentReceiptLog`.`date`, ".
2026            "`tblDocumentReceiptLog`.`userID` ".
2027            "FROM `tblDocumentRecipients` ".
2028            "LEFT JOIN `tblDocumentReceiptLog` USING (`receiptID`) ".
2029            "LEFT JOIN `ttcontentid` ON `ttcontentid`.`maxVersion` = `tblDocumentRecipients`.`version` AND `ttcontentid`.`document` = `tblDocumentRecipients`.`documentID` ".
2030            "WHERE `tblDocumentRecipients`.`type`='0' ".
2031            ($documentID==null ? "" : "AND `tblDocumentRecipients`.`documentID` = '". (int) $documentID ."' ").
2032            ($version==null ? "" : "AND `tblDocumentRecipients`.`version` = '". (int) $version ."' ").
2033            ($documentID==null && $version==null ? "AND `ttcontentid`.`maxVersion` = `tblDocumentRecipients`.`version` " : "").
2034            "AND `tblDocumentRecipients`.`required`='". $this->_id ."' ".
2035            "ORDER BY `tblDocumentReceiptLog`.`receiptLogID` DESC";
2036        $resArr = $db->getResultArray($queryStr);
2037        if (is_bool($resArr) && $resArr === false)
2038            return false;
2039        if (count($resArr)>0) {
2040            foreach ($resArr as $res) {
2041                if(isset($status["indstatus"][$res['documentID']])) {
2042                    if($status["indstatus"][$res['documentID']]['date'] < $res['date']) {
2043                        $status["indstatus"][$res['documentID']] = $res;
2044                    }
2045                } else {
2046                    $status["indstatus"][$res['documentID']] = $res;
2047                }
2048            }
2049        }
2050
2051        // See if the user is the member of a group that has been assigned to
2052        // receipt the document version.
2053        $queryStr = "SELECT `tblDocumentRecipients`.*, `tblDocumentReceiptLog`.`status`, ".
2054            "`tblDocumentReceiptLog`.`comment`, `tblDocumentReceiptLog`.`date`, ".
2055            "`tblDocumentReceiptLog`.`userID` ".
2056            "FROM `tblDocumentRecipients` ".
2057            "LEFT JOIN `tblDocumentReceiptLog` USING (`receiptID`) ".
2058            "LEFT JOIN `ttcontentid` ON `ttcontentid`.`maxVersion` = `tblDocumentRecipients`.`version` AND `ttcontentid`.`document` = `tblDocumentRecipients`.`documentID` ".
2059            "LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`groupID` = `tblDocumentRecipients`.`required` ".
2060            "WHERE `tblDocumentRecipients`.`type`='1' ".
2061            ($documentID==null ? "" : "AND `tblDocumentRecipients`.`documentID` = '". (int) $documentID ."' ").
2062            ($version==null ? "" : "AND `tblDocumentRecipients`.`version` = '". (int) $version ."' ").
2063            ($documentID==null && $version==null ? "AND `ttcontentid`.`maxVersion` = `tblDocumentRecipients`.`version` " : "").
2064            "AND `tblGroupMembers`.`userID`='". $this->_id ."' ".
2065            "ORDER BY `tblDocumentReceiptLog`.`receiptLogID` DESC";
2066        $resArr = $db->getResultArray($queryStr);
2067        if (is_bool($resArr) && $resArr === false)
2068            return false;
2069        if (count($resArr)>0) {
2070            foreach ($resArr as $res) {
2071                if(isset($status["grpstatus"][$res['documentID']])) {
2072                    if($status["grpstatus"][$res['documentID']]['date'] < $res['date']) {
2073                        $status["grpstatus"][$res['documentID']] = $res;
2074                    }
2075                } else {
2076                    $status["grpstatus"][$res['documentID']] = $res;
2077                }
2078            }
2079        }
2080        return $status;
2081    } /* }}} */
2082
2083    /**
2084     * Get a list of revisions
2085     * This function returns a list of all revisions seperated by individual
2086     * and group revisions. If the document id
2087     * is passed, then only this document will be checked for revisions. The
2088     * same is true for the version of a document which limits the list
2089     * further.
2090     *
2091     * For a detaile description of the result array see
2092     * {link SeedDMS_Core_User::getApprovalStatus} which does the same for
2093     * approvals.
2094     *
2095     * @param int $documentID optional document id for which to retrieve the
2096     *        revisions
2097     * @param int $version optional version of the document
2098     * @return array list of all revisions. If the result array has no elements,
2099     * then the user was not a revisor. If there elements for 'indstatus' or
2100     * 'grpstatus' then the revision hasn't been started.
2101     */
2102    function getRevisionStatus($documentID=null, $version=null) { /* {{{ */
2103        $db = $this->_dms->getDB();
2104
2105        $status = array("indstatus"=>array(), "grpstatus"=>array());
2106
2107        if (!$db->createTemporaryTable("ttcontentid")) {
2108            return false;
2109        }
2110        // See if the user is assigned as an individual revisor.
2111        // left join with ttcontentid to restrict result on latest version of document
2112        // unless a document and version is given
2113        $queryStr = "SELECT `tblDocumentRevisors`.*, `tblDocumentRevisionLog`.`status`, ".
2114            "`tblDocumentRevisionLog`.`comment`, `tblDocumentRevisionLog`.`date`, ".
2115            "`tblDocumentRevisionLog`.`userID` ".
2116            "FROM `tblDocumentRevisors` ".
2117            "LEFT JOIN `tblDocumentRevisionLog` USING (`revisionID`) ".
2118            "LEFT JOIN `ttcontentid` ON `ttcontentid`.`maxVersion` = `tblDocumentRevisors`.`version` AND `ttcontentid`.`document` = `tblDocumentRevisors`.`documentID` ".
2119            "WHERE `tblDocumentRevisors`.`type`='0' ".
2120            ($documentID==null ? "" : "AND `tblDocumentRevisors`.`documentID` = '". (int) $documentID ."' ").
2121            ($version==null ? "" : "AND `tblDocumentRevisors`.`version` = '". (int) $version ."' ").
2122            ($documentID==null && $version==null ? "AND `ttcontentid`.`maxVersion` = `tblDocumentRevisors`.`version` " : "").
2123            "AND `tblDocumentRevisors`.`required`='". $this->_id ."' ".
2124            "ORDER BY `tblDocumentRevisionLog`.`revisionLogID` DESC";
2125        $resArr = $db->getResultArray($queryStr);
2126        if ($resArr === false)
2127            return false;
2128        if (count($resArr)>0) {
2129            $status['indstatus'] = array();
2130            foreach ($resArr as $res) {
2131                if($res['date']) {
2132                    if(isset($status["indstatus"][$res['documentID']])) {
2133                        if($status["indstatus"][$res['documentID']]['date'] < $res['date']) {
2134                            $status["indstatus"][$res['documentID']] = $res;
2135                        }
2136                    } else {
2137                        $status["indstatus"][$res['documentID']] = $res;
2138                    }
2139                }
2140            }
2141        }
2142
2143        // See if the user is the member of a group that has been assigned to
2144        // revision the document version.
2145        $queryStr = "SELECT `tblDocumentRevisors`.*, `tblDocumentRevisionLog`.`status`, ".
2146            "`tblDocumentRevisionLog`.`comment`, `tblDocumentRevisionLog`.`date`, ".
2147            "`tblDocumentRevisionLog`.`userID` ".
2148            "FROM `tblDocumentRevisors` ".
2149            "LEFT JOIN `tblDocumentRevisionLog` USING (`revisionID`) ".
2150            "LEFT JOIN `ttcontentid` ON `ttcontentid`.`maxVersion` = `tblDocumentRevisors`.`version` AND `ttcontentid`.`document` = `tblDocumentRevisors`.`documentID` ".
2151            "LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`groupID` = `tblDocumentRevisors`.`required` ".
2152            "WHERE `tblDocumentRevisors`.`type`='1' ".
2153            ($documentID==null ? "" : "AND `tblDocumentRevisors`.`documentID` = '". (int) $documentID ."' ").
2154            ($version==null ? "" : "AND `tblDocumentRevisors`.`version` = '". (int) $version ."' ").
2155            ($documentID==null && $version==null ? "AND `ttcontentid`.`maxVersion` = `tblDocumentRevisors`.`version` " : "").
2156            "AND `tblGroupMembers`.`userID`='". $this->_id ."' ".
2157            "ORDER BY `tblDocumentRevisionLog`.`revisionLogID` DESC";
2158        $resArr = $db->getResultArray($queryStr);
2159        if (is_bool($resArr) && $resArr === false)
2160            return false;
2161        if (count($resArr)>0) {
2162            foreach ($resArr as $res) {
2163                if(isset($status["grpstatus"][$res['documentID']])) {
2164                    if($status["grpstatus"][$res['documentID']]['date'] < $res['date']) {
2165                        $status["grpstatus"][$res['documentID']] = $res;
2166                    }
2167                } else {
2168                    $status["grpstatus"][$res['documentID']] = $res;
2169                }
2170            }
2171        }
2172        return $status;
2173    } /* }}} */
2174
2175    /**
2176     * Get a list of documents with a workflow
2177     *
2178     * @param int $documentID optional document id for which to retrieve the
2179     *        reviews
2180     * @param int $version optional version of the document
2181     * @return array|bool list of all workflows
2182     */
2183    function getWorkflowStatus($documentID=null, $version=null) { /* {{{ */
2184        $db = $this->_dms->getDB();
2185
2186        $queryStr = 'SELECT DISTINCT d.*, c.`userid` FROM `tblWorkflowTransitions` a LEFT JOIN `tblWorkflows` b ON a.`workflow`=b.`id` LEFT JOIN `tblWorkflowTransitionUsers` c ON a.`id`=c.`transition` LEFT JOIN `tblWorkflowDocumentContent` d ON b.`id`=d.`workflow` WHERE d.`document` IS NOT NULL AND a.`state`=d.`state` AND c.`userid`='.$this->_id;
2187        if($documentID) {
2188            $queryStr .= ' AND d.`document`='.(int) $documentID;
2189            if($version)
2190                $queryStr .= ' AND d.`version`='.(int) $version;
2191        }
2192        $resArr = $db->getResultArray($queryStr);
2193        if (is_bool($resArr) && $resArr == false)
2194            return false;
2195        $result['u'] = array();
2196        if (count($resArr)>0) {
2197            foreach ($resArr as $res) {
2198                $result['u'][] = $res;
2199            }
2200        }
2201
2202        $queryStr = 'select distinct d.*, c.`groupid` from `tblWorkflowTransitions` a left join `tblWorkflows` b on a.`workflow`=b.`id` left join `tblWorkflowTransitionGroups` c on a.`id`=c.`transition` left join `tblWorkflowDocumentContent` d on b.`id`=d.`workflow` left join `tblGroupMembers` e on c.`groupid` = e.`groupID` where d.`document` is not null and a.`state`=d.`state` and e.`userID`='.$this->_id;
2203        if($documentID) {
2204            $queryStr .= ' AND d.`document`='.(int) $documentID;
2205            if($version)
2206                $queryStr .= ' AND d.`version`='.(int) $version;
2207        }
2208        $resArr = $db->getResultArray($queryStr);
2209        if (is_bool($resArr) && $resArr == false)
2210            return false;
2211        $result['g'] = array();
2212        if (count($resArr)>0) {
2213            foreach ($resArr as $res) {
2214                $result['g'][] = $res;
2215            }
2216        }
2217        return $result;
2218    } /* }}} */
2219
2220    /**
2221     * Get a list of workflows this user is involved as in individual
2222     *
2223     * @return array|bool list of all workflows
2224     */
2225    function getWorkflowsInvolved() { /* {{{ */
2226        $db = $this->_dms->getDB();
2227
2228        $queryStr = 'SELECT DISTINCT b.*, c.`userid` FROM `tblWorkflowTransitions` a LEFT JOIN `tblWorkflows` b ON a.`workflow`=b.`id` LEFT JOIN `tblWorkflowTransitionUsers` c ON a.`id`=c.`transition` WHERE c.`userid`='.$this->_id;
2229        $resArr = $db->getResultArray($queryStr);
2230        if (is_bool($resArr) && $resArr == false)
2231            return false;
2232        $result = array();
2233        if (count($resArr)>0) {
2234            foreach ($resArr as $res) {
2235                $result[] = $this->_dms->getWorkflow((int) $res['id']);
2236            }
2237        }
2238
2239        return $result;
2240    } /* }}} */
2241
2242    /**
2243     * Get a list of mandatory reviewers
2244     * A user which isn't trusted completely may have assigned mandatory
2245     * reviewers (both users and groups).
2246     * Whenever the user inserts a new document the mandatory reviewers are
2247     * filled in as reviewers.
2248     *
2249     * @return array list of arrays with two elements containing the user id
2250     *         (reviewerUserID) and group id (reviewerGroupID) of the reviewer.
2251     */
2252    function getMandatoryReviewers() { /* {{{ */
2253        $db = $this->_dms->getDB();
2254
2255        $queryStr = "SELECT * FROM `tblMandatoryReviewers` WHERE `userID` = " . $this->_id;
2256        $resArr = $db->getResultArray($queryStr);
2257
2258        return $resArr;
2259    } /* }}} */
2260
2261    /**
2262     * Get a list of mandatory approvers
2263     * See {link SeedDMS_Core_User::getMandatoryReviewers}
2264     *
2265     * @return array list of arrays with two elements containing the user id
2266     *         (approverUserID) and group id (approverGroupID) of the approver.
2267     */
2268    function getMandatoryApprovers() { /* {{{ */
2269        $db = $this->_dms->getDB();
2270
2271        $queryStr = "SELECT * FROM `tblMandatoryApprovers` WHERE `userID` = " . $this->_id;
2272        $resArr = $db->getResultArray($queryStr);
2273
2274        return $resArr;
2275    } /* }}} */
2276
2277    /**
2278     * Get a list of users this user is a mandatory reviewer of
2279     *
2280     * This method is the reverse function of getMandatoryReviewers(). It returns
2281     * those user where the current user is a mandatory reviewer.
2282     *
2283     * @return SeedDMS_Core_User[]|bool list of users where this user is a mandatory reviewer.
2284     */
2285    function isMandatoryReviewerOf() { /* {{{ */
2286        $db = $this->_dms->getDB();
2287
2288        $queryStr = "SELECT * FROM `tblMandatoryReviewers` WHERE `reviewerUserID` = " . $this->_id;
2289        $resArr = $db->getResultArray($queryStr);
2290        if (is_bool($resArr) && !$resArr) return false;
2291
2292        $users = array();
2293        foreach($resArr as $res) {
2294            $users[] = self::getInstance($res['userID'], $this->_dms);
2295        }
2296
2297        return $users;
2298    } /* }}} */
2299
2300    /**
2301     * Get a list of users this user is a mandatory approver of
2302     *
2303     * This method is the reverse function of getMandatoryApprovers(). It returns
2304     * those user where the current user is a mandatory approver.
2305     *
2306     * @return SeedDMS_Core_User[]|bool list of users where this user is a mandatory approver.
2307     */
2308    function isMandatoryApproverOf() { /* {{{ */
2309        $db = $this->_dms->getDB();
2310
2311        $queryStr = "SELECT * FROM `tblMandatoryApprovers` WHERE `approverUserID` = " . $this->_id;
2312        $resArr = $db->getResultArray($queryStr);
2313        if (is_bool($resArr) && !$resArr) return false;
2314
2315        $users = array();
2316        foreach($resArr as $res) {
2317            $users[] = self::getInstance($res['userID'], $this->_dms);
2318        }
2319
2320        return $users;
2321    } /* }}} */
2322
2323    /**
2324     * Get the mandatory workflow
2325     * A user which isn't trusted completely may have assigned mandatory
2326     * workflow
2327     * Whenever the user inserts a new document the mandatory workflow is
2328     * filled in as the workflow.
2329     *
2330     * @return SeedDMS_Core_Workflow|bool workflow
2331     */
2332    function getMandatoryWorkflow() { /* {{{ */
2333        $db = $this->_dms->getDB();
2334
2335        $queryStr = "SELECT * FROM `tblWorkflowMandatoryWorkflow` WHERE `userid` = " . $this->_id;
2336        $resArr = $db->getResultArray($queryStr);
2337        if (is_bool($resArr) && !$resArr) return false;
2338
2339        if(!$resArr)
2340            return null;
2341
2342        $workflow = $this->_dms->getWorkflow($resArr[0]['workflow']);
2343        return $workflow;
2344    } /* }}} */
2345
2346    /**
2347     * Get the mandatory workflows
2348     * A user which isn't trusted completely may have assigned mandatory
2349     * workflow
2350     * Whenever the user inserts a new document the mandatory workflow is
2351     * filled in as the workflow.
2352     *
2353     * @return SeedDMS_Core_Workflow[]|bool workflow
2354     */
2355    function getMandatoryWorkflows() { /* {{{ */
2356        $db = $this->_dms->getDB();
2357
2358        $queryStr = "SELECT * FROM `tblWorkflowMandatoryWorkflow` WHERE `userid` = " . $this->_id;
2359        $resArr = $db->getResultArray($queryStr);
2360        if (is_bool($resArr) && !$resArr) return false;
2361
2362        if(!$resArr)
2363            return null;
2364
2365        $workflows = array();
2366        foreach($resArr as $res) {
2367            $workflows[] = $this->_dms->getWorkflow($res['workflow']);
2368        }
2369        return $workflows;
2370    } /* }}} */
2371
2372    /**
2373     * Set a mandatory reviewer
2374     * This function sets a mandatory reviewer if it isn't already set.
2375     *
2376     * @param integer $id id of reviewer
2377     * @param boolean $isgroup true if $id is a group
2378     * @return boolean true on success, otherwise false
2379     */
2380    function setMandatoryReviewer($id, $isgroup=false) { /* {{{ */
2381        $db = $this->_dms->getDB();
2382        $id = (int) $id;
2383
2384        if ($isgroup){
2385
2386            $queryStr = "SELECT * FROM `tblMandatoryReviewers` WHERE `userID` = " . $this->_id . " AND `reviewerGroupID` = " . $id;
2387            $resArr = $db->getResultArray($queryStr);
2388            if (count($resArr)!=0) return true;
2389
2390            $queryStr = "INSERT INTO `tblMandatoryReviewers` (`userID`, `reviewerGroupID`) VALUES (" . $this->_id . ", " . $id .")";
2391            $resArr = $db->getResult($queryStr);
2392            if (is_bool($resArr) && !$resArr) return false;
2393
2394        }else{
2395
2396            $queryStr = "SELECT * FROM `tblMandatoryReviewers` WHERE `userID` = " . $this->_id . " AND `reviewerUserID` = " . $id;
2397            $resArr = $db->getResultArray($queryStr);
2398            if (count($resArr)!=0) return true;
2399
2400            $queryStr = "INSERT INTO `tblMandatoryReviewers` (`userID`, `reviewerUserID`) VALUES (" . $this->_id . ", " . $id .")";
2401            $resArr = $db->getResult($queryStr);
2402            if (is_bool($resArr) && !$resArr) return false;
2403        }
2404
2405        return true;
2406    } /* }}} */
2407
2408    /**
2409     * Set a mandatory approver
2410     * This function sets a mandatory approver if it isn't already set.
2411     *
2412     * @param integer $id id of approver
2413     * @param boolean $isgroup true if $id is a group
2414     * @return boolean true on success, otherwise false
2415     */
2416    function setMandatoryApprover($id, $isgroup=false) { /* {{{ */
2417        $db = $this->_dms->getDB();
2418        $id = (int) $id;
2419
2420        if ($isgroup){
2421
2422            $queryStr = "SELECT * FROM `tblMandatoryApprovers` WHERE `userID` = " . $this->_id . " AND `approverGroupID` = " . $id;
2423            $resArr = $db->getResultArray($queryStr);
2424            if (count($resArr)!=0) return true;
2425
2426            $queryStr = "INSERT INTO `tblMandatoryApprovers` (`userID`, `approverGroupID`) VALUES (" . $this->_id . ", " . $id .")";
2427            $resArr = $db->getResult($queryStr);
2428            if (is_bool($resArr) && !$resArr) return false;
2429
2430        }else{
2431
2432            $queryStr = "SELECT * FROM `tblMandatoryApprovers` WHERE `userID` = " . $this->_id . " AND `approverUserID` = " . $id;
2433            $resArr = $db->getResultArray($queryStr);
2434            if (count($resArr)!=0) return true;
2435
2436            $queryStr = "INSERT INTO `tblMandatoryApprovers` (`userID`, `approverUserID`) VALUES (" . $this->_id . ", " . $id .")";
2437            $resArr = $db->getResult($queryStr);
2438            if (is_bool($resArr) && !$resArr) return false;
2439        }
2440
2441        return true;
2442    } /* }}} */
2443
2444    /**
2445     * Set a mandatory workflow
2446     * This function sets a mandatory workflow if it isn't already set.
2447     *
2448     * @param object $workflow workflow
2449     * @return boolean true on success, otherwise false
2450     */
2451    function setMandatoryWorkflow($workflow) { /* {{{ */
2452        $db = $this->_dms->getDB();
2453
2454        $queryStr = "SELECT * FROM `tblWorkflowMandatoryWorkflow` WHERE `userid` = " . $this->_id . " AND `workflow` = " . (int) $workflow->getID();
2455        $resArr = $db->getResultArray($queryStr);
2456        if (count($resArr)!=0) return true;
2457
2458        $queryStr = "INSERT INTO `tblWorkflowMandatoryWorkflow` (`userid`, `workflow`) VALUES (" . $this->_id . ", " . $workflow->getID() .")";
2459        $resArr = $db->getResult($queryStr);
2460        if (is_bool($resArr) && !$resArr) return false;
2461
2462        return true;
2463    } /* }}} */
2464
2465    /**
2466     * Set a mandatory workflows
2467     * This function sets a list of mandatory workflows.
2468     *
2469     * @param SeedDMS_Core_Workflow[] $workflows list of workflow objects
2470     * @return boolean true on success, otherwise false
2471     */
2472    function setMandatoryWorkflows($workflows) { /* {{{ */
2473        $db = $this->_dms->getDB();
2474
2475        $db->startTransaction();
2476        $queryStr = "DELETE FROM `tblWorkflowMandatoryWorkflow` WHERE `userid` = " . $this->_id;
2477        if (!$db->getResult($queryStr)) {
2478            $db->rollbackTransaction();
2479            return false;
2480        }
2481
2482        foreach($workflows as $workflow) {
2483            $queryStr = "INSERT INTO `tblWorkflowMandatoryWorkflow` (`userid`, `workflow`) VALUES (" . $this->_id . ", " . $workflow->getID() .")";
2484            $resArr = $db->getResult($queryStr);
2485            if (is_bool($resArr) && !$resArr) {
2486                $db->rollbackTransaction();
2487                return false;
2488            }
2489        }
2490
2491        $db->commitTransaction();
2492        return true;
2493    } /* }}} */
2494
2495    /**
2496     * Deletes all mandatory reviewers
2497     *
2498     * @return boolean true on success, otherwise false
2499     */
2500    function delMandatoryReviewers() { /* {{{ */
2501        $db = $this->_dms->getDB();
2502        $queryStr = "DELETE FROM `tblMandatoryReviewers` WHERE `userID` = " . $this->_id;
2503        if (!$db->getResult($queryStr)) return false;
2504        return true;
2505    } /* }}} */
2506
2507    /**
2508     * Deletes all mandatory approvers
2509     *
2510     * @return boolean true on success, otherwise false
2511     */
2512    function delMandatoryApprovers() { /* {{{ */
2513        $db = $this->_dms->getDB();
2514
2515        $queryStr = "DELETE FROM `tblMandatoryApprovers` WHERE `userID` = " . $this->_id;
2516        if (!$db->getResult($queryStr)) return false;
2517        return true;
2518    } /* }}} */
2519
2520    /**
2521     * Deletes the  mandatory workflow
2522     *
2523     * @return boolean true on success, otherwise false
2524     */
2525    function delMandatoryWorkflow() { /* {{{ */
2526        $db = $this->_dms->getDB();
2527        $queryStr = "DELETE FROM `tblWorkflowMandatoryWorkflow` WHERE `userid` = " . $this->_id;
2528        if (!$db->getResult($queryStr)) return false;
2529        return true;
2530    } /* }}} */
2531
2532    /**
2533     * Get all substitutes of the user
2534     *
2535     * These users are substitutes of the current user
2536     *
2537     * @return array list of users
2538     */
2539    function getSubstitutes() { /* {{{ */
2540        $db = $this->_dms->getDB();
2541
2542        if (!isset($this->_substitutes)) {
2543            $queryStr = "SELECT `tblUsers`.* FROM `tblUserSubstitutes` ".
2544                "LEFT JOIN `tblUsers` ON `tblUserSubstitutes`.`substitute` = `tblUsers`.`id` ".
2545                "WHERE `tblUserSubstitutes`.`user`='". $this->_id ."'";
2546            $resArr = $db->getResultArray($queryStr);
2547            if (is_bool($resArr) && $resArr == false)
2548                return false;
2549
2550            $this->_substitutes = array();
2551            $classname = $this->_dms->getClassname('user');
2552            foreach ($resArr as $row) {
2553                $user = new $classname($row["id"], $row["login"], $row["pwd"], $row["fullName"], $row["email"], $row["language"], $row["theme"], $row["comment"], $row["role"], $row["hidden"], $row["disabled"], $row["pwdExpiration"], $row["loginfailures"], $row["quota"], $row["homefolder"]);
2554                $user->setDMS($this->_dms);
2555                array_push($this->_substitutes, $user);
2556            }
2557        }
2558        return $this->_substitutes;
2559    } /* }}} */
2560
2561    /**
2562     * Get all users this user is a substitute of
2563     *
2564     * @return array list of users
2565     */
2566    function getReverseSubstitutes() { /* {{{ */
2567        $db = $this->_dms->getDB();
2568
2569        if (!isset($this->_rev_substitutes)) {
2570            $queryStr = "SELECT `tblUsers`.* FROM `tblUserSubstitutes` ".
2571                "LEFT JOIN `tblUsers` ON `tblUserSubstitutes`.`user` = `tblUsers`.`id` ".
2572                "LEFT JOIN `tblRoles` ON `tblRoles`.`id`=`tblUsers`.`role` ".
2573                "WHERE `tblUserSubstitutes`.`substitute`='". $this->_id ."'";
2574            /* None admins can only be substitutes for regular users, otherwise
2575             * regular users can become admin
2576             */
2577            if(!$this->isAdmin())
2578                $queryStr .= " AND `tblRoles`.`role` = ".SeedDMS_Core_Role::role_user;
2579            $resArr = $db->getResultArray($queryStr);
2580            if (is_bool($resArr) && $resArr == false)
2581                return false;
2582
2583            $this->_rev_substitutes = array();
2584            $classnamerole = $this->_dms->getClassname('role');
2585            $classname = $this->_dms->getClassname('user');
2586            foreach ($resArr as $row) {
2587                $role = $classnamerole::getInstance($row['role'], $this->_dms);
2588                $user = new $classname($row["id"], $row["login"], $row["pwd"], $row["fullName"], $row["email"], $row["language"], $row["theme"], $row["comment"], $role, $row["hidden"], $row["disabled"], $row["pwdExpiration"], $row["loginfailures"], $row["quota"], $row["homefolder"]);
2589                $user->setDMS($this->_dms);
2590                array_push($this->_rev_substitutes, $user);
2591            }
2592        }
2593        return $this->_rev_substitutes;
2594    } /* }}} */
2595
2596    /**
2597     * Add a substitute to the user
2598     *
2599     * @return boolean true if successful otherwise false
2600     */
2601    function addSubstitute($substitute) { /* {{{ */
2602        $db = $this->_dms->getDB();
2603
2604        if(get_class($substitute) != $this->_dms->getClassname('user'))
2605            return false;
2606
2607        $queryStr = "SELECT * FROM `tblUserSubstitutes` WHERE `user`=" . $this->_id . " AND `substitute`=".$substitute->getID();
2608        $resArr = $db->getResultArray($queryStr);
2609        if (is_bool($resArr) && $resArr == false) return false;
2610        if (count($resArr) == 1) return true;
2611
2612        $queryStr = "INSERT INTO `tblUserSubstitutes` (`user`, `substitute`) VALUES (" . $this->_id . ", ".$substitute->getID().")";
2613        if (!$db->getResult($queryStr))
2614            return false;
2615
2616        $this->_substitutes = null;
2617        return true;
2618    } /* }}} */
2619
2620    /**
2621     * Remove a substitute from the user
2622     *
2623     * @return boolean true if successful otherwise false
2624     */
2625    function removeSubstitute($substitute) { /* {{{ */
2626        $db = $this->_dms->getDB();
2627
2628        if(get_class($substitute) != $this->_dms->getClassname('user'))
2629            return false;
2630
2631        $queryStr = "SELECT * FROM `tblUserSubstitutes` WHERE `user`=" . $this->_id . " AND `substitute`=".$substitute->getID();
2632        $resArr = $db->getResultArray($queryStr);
2633        if (is_bool($resArr) && $resArr == false) return false;
2634        if (count($resArr) == 0) return true;
2635
2636        $queryStr = "DELETE FROM `tblUserSubstitutes` WHERE `user`=" . $this->_id . " AND `substitute`=".$substitute->getID();
2637        if (!$db->getResult($queryStr))
2638            return false;
2639
2640        $this->_substitutes = null;
2641        return true;
2642    } /* }}} */
2643
2644    /**
2645     * Check if user is a substitute of the current user
2646     *
2647     * @return boolean true if successful otherwise false
2648     */
2649    function isSubstitute($substitute) { /* {{{ */
2650        $db = $this->_dms->getDB();
2651
2652        if(get_class($substitute) != $this->_dms->getClassname('user'))
2653            return false;
2654
2655        $queryStr = "SELECT * FROM `tblUserSubstitutes` WHERE `user`=" . $this->_id . " AND `substitute`=".$substitute->getID();
2656        $resArr = $db->getResultArray($queryStr);
2657        if (is_bool($resArr) && $resArr == false) return false;
2658        if (count($resArr) == 1) return true;
2659
2660        return false;
2661    } /* }}} */
2662
2663    /**
2664     * Check if user may switch to the given user
2665     *
2666     * Switching to the given user is only allowed if the given user
2667     * is a substitute for the current user.
2668     *
2669     * @return boolean true if successful otherwise false
2670     */
2671    function maySwitchToUser($touser) { /* {{{ */
2672        $db = $this->_dms->getDB();
2673
2674        if(get_class($touser) != $this->_dms->getClassname('user'))
2675            return false;
2676
2677        /* switching to an admin account is always forbitten, unless the
2678         * current user is admin itself
2679         */
2680        if(!$this->isAdmin() && $touser->isAdmin())
2681            return false;
2682
2683        $queryStr = "SELECT * FROM `tblUserSubstitutes` WHERE `substitute`=" . $this->_id . " AND `user`=".$touser->getID();
2684        $resArr = $db->getResultArray($queryStr);
2685        if (is_bool($resArr) && $resArr == false) return false;
2686        if (count($resArr) == 1) return true;
2687
2688        return false;
2689    } /* }}} */
2690
2691    /**
2692     * Get all notifications of user
2693     *
2694     * @param integer $type type of item (T_DOCUMENT or T_FOLDER)
2695     * @return SeedDMS_Core_Notification[]|bool array of notifications
2696     */
2697    function getNotifications($type=0) { /* {{{ */
2698        $db = $this->_dms->getDB();
2699        $queryStr = "SELECT `tblNotify`.* FROM `tblNotify` ".
2700         "WHERE `tblNotify`.`userID` = ". $this->_id;
2701        if($type) {
2702            $queryStr .= " AND `tblNotify`.`targetType` = ". (int) $type;
2703        }
2704
2705        $resArr = $db->getResultArray($queryStr);
2706        if (is_bool($resArr) && !$resArr)
2707            return false;
2708
2709        $notifications = array();
2710        foreach ($resArr as $row) {
2711            $not = new SeedDMS_Core_Notification($row["target"], $row["targetType"], $row["userID"], $row["groupID"]);
2712            $not->setDMS($this);
2713            array_push($notifications, $not);
2714        }
2715
2716        return $notifications;
2717    } /* }}} */
2718
2719    /**
2720     * Return list of personal keyword categories
2721     *
2722     * @return SeedDMS_Core_KeywordCategory[]|bool list of categories or false in case of an error
2723     */
2724    function getKeywordCategories() { /* {{{ */
2725        $db = $this->_dms->getDB();
2726
2727        $queryStr = "SELECT * FROM `tblKeywordCategories` WHERE `owner` = ".$this->_id;
2728
2729        $resArr = $db->getResultArray($queryStr);
2730        if (is_bool($resArr) && !$resArr)
2731            return false;
2732
2733        $categories = array();
2734        foreach ($resArr as $row) {
2735            $cat = new SeedDMS_Core_KeywordCategory((int) $row["id"], $row["owner"], $row["name"]);
2736            $cat->setDMS($this->_dms);
2737            array_push($categories, $cat);
2738        }
2739
2740        return $categories;
2741    } /* }}} */
2742
2743} /* }}} */