Skip to content

Commit 1768d71

Browse files
author
Vitor Mattos
committed
feat: add support to groups
Signed-off-by: Vitor Mattos <vitor@php.rio>
1 parent 3d14896 commit 1768d71

File tree

5 files changed

+187
-1
lines changed

5 files changed

+187
-1
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ This app has no user interface. All configuration is done via Nextcloud's system
6060
//'count_users' => 'SELECT COUNT (*) FROM users',
6161
//'get_home' => '',
6262
//'create_user' => 'INSERT INTO users (local, domain, password_hash) VALUES (split_part(:username, \'@\', 1), split_part(:username, \'@\', 2), :password_hash)',
63+
// 'get_in_groups' => 'SELECT id AS gid, name AS displayname FROM groups WHERE (id ILIKE :search) OR (name ILIKE :search)',
64+
// 'get_groups' => 'SELECT id AS gid, name AS displayname FROM groups WHERE (id ILIKE :search) OR (name ILIKE :search)',
65+
// 'get_user_groups' => "SELECT u.user_login FROM groups g JOIN users u ON g.user_id = u.id WHERE u.user_login = :username",
66+
// 'get_user_in_group' => 'SELECT id AS gid, name AS displayname FROM groups WHERE (id ILIKE :search) OR (name ILIKE :search)',
67+
// 'get_group_exists' => "SELECT EXISTS(SELECT 1 FROM groups WHERE g.name = :group)",
68+
// 'get_group_details' => "SELECT g.name FROM groups WHERE name = :group",
6369
),
6470
//'hash_algorithm_for_new_passwords' => 'bcrypt',
6571
),

appinfo/info.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ these databases. This has not been tested, though.]]></description>
4242
<repository type="git">https://github.com/PanCakeConnaisseur/user_backend_sql_raw</repository>
4343
<screenshot small-thumbnail="https://raw.githubusercontent.com/PanCakeConnaisseur/user_backend_sql_raw/2eb5221f0725a9ab09fde6384dea62463c7c52e5/screenshot-dark-small.jpg">https://raw.githubusercontent.com/PanCakeConnaisseur/user_backend_sql_raw/2eb5221f0725a9ab09fde6384dea62463c7c52e5/screenshot-dark-large.jpg</screenshot>
4444
<dependencies>
45-
<nextcloud min-version="26" max-version="29"/>
45+
<nextcloud min-version="26" max-version="31"/>
4646
</dependencies>
4747
</info>

lib/AppInfo/Application.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use OCP\AppFramework\Bootstrap\IRegistrationContext;
2828
use Psr\Container\ContainerInterface;
2929
use \OCP\AppFramework\App;
30+
use OCP\Server;
3031

3132
class Application extends App implements IBootstrap
3233
{
@@ -46,5 +47,8 @@ public function boot(IBootContext $context): void
4647
$userBackendSqlRaw = $context->getAppContainer()->get(\OCA\UserBackendSqlRaw\UserBackend::class);
4748
$userManager = $context->getAppContainer()->get('OCP\IUserManager');
4849
$userManager->registerBackend($userBackendSqlRaw);
50+
51+
$groupBackend = $context->getAppContainer()->get(\OCA\UserBackendSqlRaw\Backend\GroupBackend::class);
52+
Server::get(\OCP\IGroupManager::class)->addBackend($groupBackend);
4953
}
5054
}

lib/Backend/GroupBackend.php

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
/**
3+
* @copyright Copyright (c) 2024 Vitor Mattos <vitor@php.rio>
4+
*
5+
* @license GNU AGPL version 3 or any later version
6+
*
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Affero General Public License as
9+
* published by the Free Software Foundation, either version 3 of the
10+
* License, or (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU Affero General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Affero General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*
20+
*/
21+
22+
namespace OCA\UserBackendSqlRaw\Backend;
23+
24+
use OCA\UserBackendSqlRaw\Config;
25+
use OCA\UserBackendSqlRaw\Db;
26+
use OCP\Group\Backend\ABackend;
27+
use OCP\Group\Backend\IGroupDetailsBackend;
28+
use Psr\Log\LoggerInterface;
29+
30+
class GroupBackend extends ABackend implements IGroupDetailsBackend
31+
{
32+
public function __construct(
33+
private LoggerInterface $logger,
34+
private Config $config,
35+
private Db $db,
36+
) {
37+
}
38+
39+
public function inGroup($uid, $gid): bool
40+
{
41+
$queryFromConfig = $this->config->getQueryInGroup();
42+
if (empty($queryFromConfig)) {
43+
return false;
44+
}
45+
$statement = $this->db->getDbHandle()->prepare($queryFromConfig);
46+
$statement->execute(['username' => $uid, 'group' => $gid]);
47+
$inGroup = $statement->fetchColumn();
48+
return (bool) $inGroup;
49+
}
50+
51+
public function getUserGroups($uid)
52+
{
53+
$queryFromConfig = $this->config->getQueryUserGroups();
54+
if (empty($queryFromConfig)) {
55+
return [];
56+
}
57+
$statement = $this->db->getDbHandle()->prepare($queryFromConfig);
58+
$statement->execute(['username' => $uid]);
59+
$groups = $statement->fetchAll(\PDO::FETCH_COLUMN, 0);
60+
return $groups;
61+
}
62+
63+
public function getGroups($search = '', $limit = -1, $offset = 0)
64+
{
65+
$queryFromConfig = $this->config->getQueryGroups();
66+
if (empty($queryFromConfig)) {
67+
return [];
68+
}
69+
isset($limit) && $limit > 0 ? $limitSegment = ' LIMIT :limit' : $limitSegment = '';
70+
isset($offset) && $offset > 0? $offsetSegment = ' OFFSET :offset' : $offsetSegment = '';
71+
$finalQuery = $queryFromConfig . $limitSegment . $offsetSegment;
72+
$statement = $this->db->getDbHandle()->prepare($finalQuery);
73+
// Because MariaDB can not handle string parameters for LIMIT/OFFSET we have to bind the
74+
// values "manually" instead of passing an array to execute(). This is another instance of
75+
// MariaDB making the code "uglier".
76+
$statement->bindValue(':search', '%' . $search . '%', \PDO::PARAM_STR);
77+
if (isset($limit) && $limit > 0) {
78+
$statement->bindValue(':limit', intval($limit), \PDO::PARAM_INT);
79+
}
80+
if (isset($offset) && $offset > 0) {
81+
$statement->bindValue(':offset', intval($offset), \PDO::PARAM_INT);
82+
}
83+
$statement->execute(['search' => $search]);
84+
$groups = $statement->fetchAll(\PDO::FETCH_COLUMN, 0);
85+
return $groups;
86+
}
87+
88+
public function groupExists($gid)
89+
{
90+
$queryFromConfig = $this->config->getQueryGroupExists();
91+
if (empty($queryFromConfig)) {
92+
return false;
93+
}
94+
$statement = $this->db->getDbHandle()->prepare($queryFromConfig);
95+
$statement->execute(['group' => $gid]);
96+
$groupExists = $statement->fetchColumn();
97+
return (bool) $groupExists;
98+
}
99+
100+
public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0)
101+
{
102+
$queryFromConfig = $this->config->getQueryUsersInGroup();
103+
if (empty($queryFromConfig)) {
104+
return [];
105+
}
106+
isset($limit) && $limit > 0 ? $limitSegment = ' LIMIT :limit' : $limitSegment = '';
107+
isset($offset) && $offset > 0? $offsetSegment = ' OFFSET :offset' : $offsetSegment = '';
108+
$finalQuery = $queryFromConfig . $limitSegment . $offsetSegment;
109+
$statement = $this->db->getDbHandle()->prepare($finalQuery);
110+
// Because MariaDB can not handle string parameters for LIMIT/OFFSET we have to bind the
111+
// values "manually" instead of passing an array to execute(). This is another instance of
112+
// MariaDB making the code "uglier".
113+
$statement->bindValue(':search', '%' . $search . '%', \PDO::PARAM_STR);
114+
if (isset($limit) && $limit > 0) {
115+
$statement->bindValue(':limit', intval($limit), \PDO::PARAM_INT);
116+
}
117+
if (isset($offset) && $offset > 0) {
118+
$statement->bindValue(':offset', intval($offset), \PDO::PARAM_INT);
119+
}
120+
$statement->execute(['group' => $gid, 'search' => $search]);
121+
$groups = $statement->fetchAll(\PDO::FETCH_COLUMN, 0);
122+
return $groups;
123+
}
124+
125+
public function getGroupDetails(string $gid): array
126+
{
127+
$queryFromConfig = $this->config->getQueryGroupDetails();
128+
if (empty($queryFromConfig)) {
129+
return [];
130+
}
131+
$statement = $this->db->getDbHandle()->prepare($queryFromConfig);
132+
$statement->execute(['group' => $gid]);
133+
$groupDetails = $statement->fetchColumn();
134+
if (!$groupDetails) {
135+
return [];
136+
}
137+
return ['displayName' => $groupDetails];
138+
}
139+
}

lib/Config.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ class Config
4848
const CONFIG_KEY_GET_HOME = 'get_home';
4949
const CONFIG_KEY_CREATE_USER = 'create_user';
5050

51+
const CONFIG_KEY_IN_GROUPS = 'get_in_groups';
52+
const CONFIG_KEY_GROUPS = 'get_groups';
53+
const CONFIG_KEY_USER_GROUPS = 'get_user_groups';
54+
const CONFIG_KEY_USERS_IN_GROUP = 'get_user_in_group';
55+
const CONFIG_KEY_GROUP_EXISTS = 'get_group_exists';
56+
const CONFIG_KEY_GROUP_DETAILS = 'get_group_details';
57+
5158
/* @var LoggerInterface */
5259
private $logger;
5360
private $appConfiguration;
@@ -235,6 +242,36 @@ public function getQueryCreateUser()
235242
return $this->getQueryStringOrFalse(self::CONFIG_KEY_CREATE_USER);
236243
}
237244

245+
public function getQueryInGroup()
246+
{
247+
return $this->getQueryStringOrFalse(self::CONFIG_KEY_IN_GROUPS);
248+
}
249+
250+
public function getQueryGroups()
251+
{
252+
return $this->getQueryStringOrFalse(self::CONFIG_KEY_GROUPS);
253+
}
254+
255+
public function getQueryUserGroups()
256+
{
257+
return $this->getQueryStringOrFalse(self::CONFIG_KEY_USER_GROUPS);
258+
}
259+
260+
public function getQueryUsersInGroup()
261+
{
262+
return $this->getQueryStringOrFalse(self::CONFIG_KEY_USERS_IN_GROUP);
263+
}
264+
265+
public function getQueryGroupExists()
266+
{
267+
return $this->getQueryStringOrFalse(self::CONFIG_KEY_GROUP_EXISTS);
268+
}
269+
270+
public function getQueryGroupDetails()
271+
{
272+
return $this->getQueryStringOrFalse(self::CONFIG_KEY_GROUP_DETAILS);
273+
}
274+
238275

239276

240277
/**

0 commit comments

Comments
 (0)