Completed
Pull Request — master (#9261)
by John
34:10 queued 10:11
created

Database::countDisabledInGroup()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 14
nc 2
nop 1
dl 0
loc 20
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Aaron Wood <[email protected]>
6
 * @author Loki3000 <[email protected]>
7
 * @author Roeland Jago Douma <[email protected]>
8
 *
9
 * @license AGPL-3.0
10
 *
11
 * This code is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU Affero General Public License, version 3,
13
 * as published by the Free Software Foundation.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License, version 3,
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
22
 *
23
 */
24
/*
25
 *
26
 * The following SQL statement is just a help for developers and will not be
27
 * executed!
28
 *
29
 * CREATE TABLE `groups` (
30
 *   `gid` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
31
 *   PRIMARY KEY (`gid`)
32
 * ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
33
 *
34
 * CREATE TABLE `group_user` (
35
 *   `gid` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
36
 *   `uid` varchar(64) COLLATE utf8_unicode_ci NOT NULL
37
 * ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
38
 *
39
 */
40
41
namespace OC\Group;
42
43
use OCP\IDBConnection;
44
45
/**
46
 * Class for group management in a SQL Database (e.g. MySQL, SQLite)
47
 */
48
class Database extends Backend {
49
50
	/** @var string[] */
51
	private $groupCache = [];
52
53
	/** @var IDBConnection */
54
	private $dbConn;
55
56
	/**
57
	 * \OC\Group\Database constructor.
58
	 *
59
	 * @param IDBConnection|null $dbConn
60
	 */
61
	public function __construct(IDBConnection $dbConn = null) {
62
		$this->dbConn = $dbConn;
63
	}
64
65
	/**
66
	 * FIXME: This function should not be required!
67
	 */
68
	private function fixDI() {
69
		if ($this->dbConn === null) {
70
			$this->dbConn = \OC::$server->getDatabaseConnection();
71
		}
72
	}
73
74
	/**
75
	 * Try to create a new group
76
	 * @param string $gid The name of the group to create
77
	 * @return bool
78
	 *
79
	 * Tries to create a new group. If the group name already exists, false will
80
	 * be returned.
81
	 */
82
	public function createGroup( $gid ) {
83
		$this->fixDI();
84
85
		// Add group
86
		$result = $this->dbConn->insertIfNotExist('*PREFIX*groups', [
87
			'gid' => $gid,
88
		]);
89
90
		// Add to cache
91
		$this->groupCache[$gid] = $gid;
92
93
		return $result === 1;
94
	}
95
96
	/**
97
	 * delete a group
98
	 * @param string $gid gid of the group to delete
99
	 * @return bool
100
	 *
101
	 * Deletes a group and removes it from the group_user-table
102
	 */
103
	public function deleteGroup( $gid ) {
104
		$this->fixDI();
105
106
		// Delete the group
107
		$qb = $this->dbConn->getQueryBuilder();
108
		$qb->delete('groups')
109
			->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
110
			->execute();
111
112
		// Delete the group-user relation
113
		$qb = $this->dbConn->getQueryBuilder();
114
		$qb->delete('group_user')
115
			->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
116
			->execute();
117
118
		// Delete the group-groupadmin relation
119
		$qb = $this->dbConn->getQueryBuilder();
120
		$qb->delete('group_admin')
121
			->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
122
			->execute();
123
124
		// Delete from cache
125
		unset($this->groupCache[$gid]);
126
127
		return true;
128
	}
129
130
	/**
131
	 * is user in group?
132
	 * @param string $uid uid of the user
133
	 * @param string $gid gid of the group
134
	 * @return bool
135
	 *
136
	 * Checks whether the user is member of a group or not.
137
	 */
138 View Code Duplication
	public function inGroup( $uid, $gid ) {
139
		$this->fixDI();
140
141
		// check
142
		$qb = $this->dbConn->getQueryBuilder();
143
		$cursor = $qb->select('uid')
144
			->from('group_user')
145
			->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
146
			->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
147
			->execute();
148
149
		$result = $cursor->fetch();
150
		$cursor->closeCursor();
151
152
		return $result ? true : false;
153
	}
154
155
	/**
156
	 * Add a user to a group
157
	 * @param string $uid Name of the user to add to group
158
	 * @param string $gid Name of the group in which add the user
159
	 * @return bool
160
	 *
161
	 * Adds a user to a group.
162
	 */
163
	public function addToGroup( $uid, $gid ) {
164
		$this->fixDI();
165
166
		// No duplicate entries!
167
		if( !$this->inGroup( $uid, $gid )) {
168
			$qb = $this->dbConn->getQueryBuilder();
169
			$qb->insert('group_user')
170
				->setValue('uid', $qb->createNamedParameter($uid))
171
				->setValue('gid', $qb->createNamedParameter($gid))
172
				->execute();
173
			return true;
174
		}else{
175
			return false;
176
		}
177
	}
178
179
	/**
180
	 * Removes a user from a group
181
	 * @param string $uid Name of the user to remove from group
182
	 * @param string $gid Name of the group from which remove the user
183
	 * @return bool
184
	 *
185
	 * removes the user from a group.
186
	 */
187
	public function removeFromGroup( $uid, $gid ) {
188
		$this->fixDI();
189
190
		$qb = $this->dbConn->getQueryBuilder();
191
		$qb->delete('group_user')
192
			->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
193
			->andWhere($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
194
			->execute();
195
196
		return true;
197
	}
198
199
	/**
200
	 * Get all groups a user belongs to
201
	 * @param string $uid Name of the user
202
	 * @return array an array of group names
203
	 *
204
	 * This function fetches all groups a user belongs to. It does not check
205
	 * if the user exists at all.
206
	 */
207
	public function getUserGroups( $uid ) {
208
		//guests has empty or null $uid
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
209
		if ($uid === null || $uid === '') {
210
			return [];
211
		}
212
213
		$this->fixDI();
214
215
		// No magic!
216
		$qb = $this->dbConn->getQueryBuilder();
217
		$cursor = $qb->select('gid')
218
			->from('group_user')
219
			->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
220
			->execute();
221
222
		$groups = [];
223
		while( $row = $cursor->fetch()) {
224
			$groups[] = $row['gid'];
225
			$this->groupCache[$row['gid']] = $row['gid'];
226
		}
227
		$cursor->closeCursor();
228
229
		return $groups;
230
	}
231
232
	/**
233
	 * get a list of all groups
234
	 * @param string $search
235
	 * @param int $limit
236
	 * @param int $offset
237
	 * @return array an array of group names
238
	 *
239
	 * Returns a list with all groups
240
	 */
241
	public function getGroups($search = '', $limit = null, $offset = null) {
242
		$this->fixDI();
243
244
		$query = $this->dbConn->getQueryBuilder();
245
		$query->select('gid')
246
			->from('groups')
247
			->orderBy('gid', 'ASC');
248
249 View Code Duplication
		if ($search !== '') {
250
			$query->where($query->expr()->iLike('gid', $query->createNamedParameter(
251
				'%' . $this->dbConn->escapeLikeParameter($search) . '%'
252
			)));
253
		}
254
255
		$query->setMaxResults($limit)
256
			->setFirstResult($offset);
257
		$result = $query->execute();
258
259
		$groups = [];
260
		while ($row = $result->fetch()) {
261
			$groups[] = $row['gid'];
262
		}
263
		$result->closeCursor();
264
265
		return $groups;
266
	}
267
268
	/**
269
	 * check if a group exists
270
	 * @param string $gid
271
	 * @return bool
272
	 */
273
	public function groupExists($gid) {
274
		$this->fixDI();
275
276
		// Check cache first
277
		if (isset($this->groupCache[$gid])) {
278
			return true;
279
		}
280
281
		$qb = $this->dbConn->getQueryBuilder();
282
		$cursor = $qb->select('gid')
283
			->from('groups')
284
			->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
285
			->execute();
286
		$result = $cursor->fetch();
287
		$cursor->closeCursor();
288
289
		if ($result !== false) {
290
			$this->groupCache[$gid] = $gid;
291
			return true;
292
		}
293
		return false;
294
	}
295
296
	/**
297
	 * get a list of all users in a group
298
	 * @param string $gid
299
	 * @param string $search
300
	 * @param int $limit
301
	 * @param int $offset
302
	 * @return array an array of user ids
303
	 */
304
	public function usersInGroup($gid, $search = '', $limit = null, $offset = null) {
305
		$this->fixDI();
306
307
		$query = $this->dbConn->getQueryBuilder();
308
		$query->select('uid')
309
			->from('group_user')
310
			->where($query->expr()->eq('gid', $query->createNamedParameter($gid)))
311
			->orderBy('uid', 'ASC');
312
313 View Code Duplication
		if ($search !== '') {
314
			$query->andWhere($query->expr()->like('uid', $query->createNamedParameter(
315
				'%' . $this->dbConn->escapeLikeParameter($search) . '%'
316
			)));
317
		}
318
319
		$query->setMaxResults($limit)
320
			->setFirstResult($offset);
321
		$result = $query->execute();
322
323
		$users = [];
324
		while ($row = $result->fetch()) {
325
			$users[] = $row['uid'];
326
		}
327
		$result->closeCursor();
328
329
		return $users;
330
	}
331
332
	/**
333
	 * get the number of all users matching the search string in a group
334
	 * @param string $gid
335
	 * @param string $search
336
	 * @return int|false
337
	 */
338
	public function countUsersInGroup($gid, $search = '') {
339
		$this->fixDI();
340
341
		$query = $this->dbConn->getQueryBuilder();
342
		$query->selectAlias($query->createFunction('COUNT(*)'), 'num_users')
343
			->from('group_user')
344
			->where($query->expr()->eq('gid', $query->createNamedParameter($gid)));
345
346 View Code Duplication
		if ($search !== '') {
347
			$query->andWhere($query->expr()->like('uid', $query->createNamedParameter(
348
				'%' . $this->dbConn->escapeLikeParameter($search) . '%'
349
			)));
350
		}
351
352
		$result = $query->execute();
353
		$count = $result->fetchColumn();
354
		$result->closeCursor();
355
356
		if ($count !== false) {
357
			$count = (int)$count;
358
		}
359
		return $count;
360
	}
361
362
	/**
363
	 * get the number of disabled users in a group
364
	 *
365
	 * @param string $search
0 ignored issues
show
Bug introduced by
There is no parameter named $search. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
366
	 * @return int|bool
367
	 */
368
	public function countDisabledInGroup($gid) {
0 ignored issues
show
Unused Code introduced by
The parameter $gid is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
369
		$this->fixDI();
370
		
371
		$query = $this->dbConn->getQueryBuilder();
372
		$query->select($queryBuilder->createFunction('COUNT(*)'))
0 ignored issues
show
Bug introduced by
The variable $queryBuilder does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
373
			->from('preferences')
374
			->where($query->expr()->eq('appid', $queryBuilder->createNamedParameter('core')))
375
			->andWhere($query->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled')))
376
			->andWhere($query->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR));
377
378
		$result = $query->execute();
379
		$result = (int)$result->fetchColumn();
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
380
		$query->closeCursor();
0 ignored issues
show
Bug introduced by
The method closeCursor() does not seem to exist on object<OCP\DB\QueryBuilder\IQueryBuilder>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
381
382
383
		if ($count !== false) {
0 ignored issues
show
Bug introduced by
The variable $count seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
384
			$count = (int)$count;
0 ignored issues
show
Bug introduced by
The variable $count seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
385
		}
386
		return $count;
0 ignored issues
show
Bug introduced by
The variable $count does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
387
	}
388
389
}
390