mirror of
https://github.com/nextcloud/server.git
synced 2026-06-11 09:42:09 -04:00
Merge pull request #38013 from nextcloud/feat/users/store-load-manager-uid
feat(users): Store and load a user's manager
This commit is contained in:
commit
24403148a9
19 changed files with 270 additions and 19 deletions
|
|
@ -31,15 +31,19 @@ use Exception;
|
|||
use OCP\Accounts\IAccountManager;
|
||||
use OCP\IImage;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use Sabre\VObject\Component\VCard;
|
||||
use Sabre\VObject\Property\Text;
|
||||
|
||||
class Converter {
|
||||
/** @var IAccountManager */
|
||||
private $accountManager;
|
||||
private IUserManager $userManager;
|
||||
|
||||
public function __construct(IAccountManager $accountManager) {
|
||||
public function __construct(IAccountManager $accountManager,
|
||||
IUserManager $userManager) {
|
||||
$this->accountManager = $accountManager;
|
||||
$this->userManager = $userManager;
|
||||
}
|
||||
|
||||
public function createCardFromUser(IUser $user): ?VCard {
|
||||
|
|
@ -102,6 +106,20 @@ class Converter {
|
|||
}
|
||||
}
|
||||
|
||||
// Local properties
|
||||
$managers = $user->getManagerUids();
|
||||
// X-MANAGERSNAME only allows a single value, so we take the first manager
|
||||
if (isset($managers[0])) {
|
||||
$displayName = $this->userManager->getDisplayName($managers[0]);
|
||||
// Only set the manager if a user object is found
|
||||
if ($displayName !== null) {
|
||||
$vCard->add(new Text($vCard, 'X-MANAGERSNAME', $displayName, [
|
||||
'uid' => $managers[0],
|
||||
'X-NC-SCOPE' => IAccountManager::SCOPE_LOCAL,
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
if ($publish && !empty($cloudId)) {
|
||||
$vCard->add(new Text($vCard, 'CLOUD', $cloudId));
|
||||
$vCard->validate();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||
*
|
||||
|
|
@ -33,6 +36,7 @@ use OCP\Accounts\IAccountManager;
|
|||
use OCP\Accounts\IAccountProperty;
|
||||
use OCP\IImage;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Test\TestCase;
|
||||
|
||||
|
|
@ -40,11 +44,14 @@ class ConverterTest extends TestCase {
|
|||
|
||||
/** @var IAccountManager|\PHPUnit\Framework\MockObject\MockObject */
|
||||
private $accountManager;
|
||||
/** @var IUserManager|(IUserManager&MockObject)|MockObject */
|
||||
private IUserManager|MockObject $userManager;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->accountManager = $this->createMock(IAccountManager::class);
|
||||
$this->userManager = $this->createMock(IUserManager::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -96,7 +103,7 @@ class ConverterTest extends TestCase {
|
|||
$user = $this->getUserMock((string)$displayName, $eMailAddress, $cloudId);
|
||||
$accountManager = $this->getAccountManager($user);
|
||||
|
||||
$converter = new Converter($accountManager);
|
||||
$converter = new Converter($accountManager, $this->userManager);
|
||||
$vCard = $converter->createCardFromUser($user);
|
||||
if ($expectedVCard !== null) {
|
||||
$this->assertInstanceOf('Sabre\VObject\Component\VCard', $vCard);
|
||||
|
|
@ -107,6 +114,29 @@ class ConverterTest extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public function testManagerProp(): void {
|
||||
$user = $this->getUserMock("user", "user@domain.tld", "user@cloud.domain.tld");
|
||||
$user->method('getManagerUids')
|
||||
->willReturn(['mgr']);
|
||||
$this->userManager->expects(self::once())
|
||||
->method('getDisplayName')
|
||||
->with('mgr')
|
||||
->willReturn('Manager');
|
||||
$accountManager = $this->getAccountManager($user);
|
||||
|
||||
$converter = new Converter($accountManager, $this->userManager);
|
||||
$vCard = $converter->createCardFromUser($user);
|
||||
|
||||
$this->compareData(
|
||||
[
|
||||
'cloud' => 'user@cloud.domain.tld',
|
||||
'email' => 'user@domain.tld',
|
||||
'x-managersname' => 'Manager',
|
||||
],
|
||||
$vCard->jsonSerialize()
|
||||
);
|
||||
}
|
||||
|
||||
protected function compareData($expected, $data) {
|
||||
foreach ($expected as $key => $value) {
|
||||
$found = false;
|
||||
|
|
@ -182,7 +212,7 @@ class ConverterTest extends TestCase {
|
|||
* @param $fullName
|
||||
*/
|
||||
public function testNameSplitter($expected, $fullName): void {
|
||||
$converter = new Converter($this->accountManager);
|
||||
$converter = new Converter($this->accountManager, $this->userManager);
|
||||
$r = $converter->splitFullName($fullName);
|
||||
$r = implode(';', $r);
|
||||
$this->assertEquals($expected, $r);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ abstract class AUserData extends OCSController {
|
|||
public const USER_FIELD_LOCALE = 'locale';
|
||||
public const USER_FIELD_PASSWORD = 'password';
|
||||
public const USER_FIELD_QUOTA = 'quota';
|
||||
public const USER_FIELD_MANAGER = 'manager';
|
||||
public const USER_FIELD_NOTIFICATION_EMAIL = 'notify_email';
|
||||
|
||||
/** @var IUserManager */
|
||||
|
|
@ -151,6 +152,8 @@ abstract class AUserData extends OCSController {
|
|||
$data['backend'] = $targetUserObject->getBackendClassName();
|
||||
$data['subadmin'] = $this->getUserSubAdminGroupsData($targetUserObject->getUID());
|
||||
$data[self::USER_FIELD_QUOTA] = $this->fillStorageInfo($targetUserObject->getUID());
|
||||
$managerUids = $targetUserObject->getManagerUids();
|
||||
$data[self::USER_FIELD_MANAGER] = empty($managerUids) ? '' : $managerUids[0];
|
||||
|
||||
try {
|
||||
if ($includeScopes) {
|
||||
|
|
|
|||
|
|
@ -338,7 +338,8 @@ class UsersController extends AUserData {
|
|||
array $groups = [],
|
||||
array $subadmin = [],
|
||||
string $quota = '',
|
||||
string $language = ''
|
||||
string $language = '',
|
||||
?string $manager = null,
|
||||
): DataResponse {
|
||||
$user = $this->userSession->getUser();
|
||||
$isAdmin = $this->groupManager->isAdmin($user->getUID());
|
||||
|
|
@ -447,6 +448,15 @@ class UsersController extends AUserData {
|
|||
$this->editUser($userid, self::USER_FIELD_LANGUAGE, $language);
|
||||
}
|
||||
|
||||
/**
|
||||
* null -> nothing sent
|
||||
* '' -> unset manager
|
||||
* else -> set manager
|
||||
*/
|
||||
if ($manager !== null) {
|
||||
$this->editUser($userid, self::USER_FIELD_MANAGER, $manager);
|
||||
}
|
||||
|
||||
// Send new user mail only if a mail is set
|
||||
if ($email !== '') {
|
||||
$newUser->setEMailAddress($email);
|
||||
|
|
@ -800,9 +810,11 @@ class UsersController extends AUserData {
|
|||
|
||||
$permittedFields[] = IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX;
|
||||
|
||||
// If admin they can edit their own quota
|
||||
// If admin they can edit their own quota and manager
|
||||
if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
|
||||
$permittedFields[] = self::USER_FIELD_QUOTA;
|
||||
$permittedFields[] = self::USER_FIELD_MANAGER;
|
||||
|
||||
}
|
||||
} else {
|
||||
// Check if admin / subadmin
|
||||
|
|
@ -836,6 +848,7 @@ class UsersController extends AUserData {
|
|||
$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
|
||||
$permittedFields[] = self::USER_FIELD_QUOTA;
|
||||
$permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
|
||||
$permittedFields[] = self::USER_FIELD_MANAGER;
|
||||
} else {
|
||||
// No rights
|
||||
throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
|
||||
|
|
@ -885,6 +898,9 @@ class UsersController extends AUserData {
|
|||
}
|
||||
$targetUser->setQuota($quota);
|
||||
break;
|
||||
case self::USER_FIELD_MANAGER:
|
||||
$targetUser->setManagerUids([$value]);
|
||||
break;
|
||||
case self::USER_FIELD_PASSWORD:
|
||||
try {
|
||||
if (strlen($value) > IUserManager::MAX_PASSWORD_LENGTH) {
|
||||
|
|
|
|||
|
|
@ -1093,6 +1093,7 @@ class UsersControllerTest extends TestCase {
|
|||
'biography' => 'biography',
|
||||
'profile_enabled' => '1',
|
||||
'notify_email' => null,
|
||||
'manager' => '',
|
||||
];
|
||||
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
|
||||
}
|
||||
|
|
@ -1233,6 +1234,7 @@ class UsersControllerTest extends TestCase {
|
|||
'biography' => 'biography',
|
||||
'profile_enabled' => '1',
|
||||
'notify_email' => null,
|
||||
'manager' => '',
|
||||
];
|
||||
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
|
||||
}
|
||||
|
|
@ -1411,6 +1413,7 @@ class UsersControllerTest extends TestCase {
|
|||
'biography' => 'biography',
|
||||
'profile_enabled' => '1',
|
||||
'notify_email' => null,
|
||||
'manager' => '',
|
||||
];
|
||||
$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1350,6 +1350,8 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
|
|||
minmax($grid-col-min-width, 1fr) // email
|
||||
minmax(1.5*$grid-col-min-width, 1fr) // groups
|
||||
minmax(1.5*$grid-col-min-width, 1fr) // group admins
|
||||
minmax($grid-col-min-width, 1fr) // quota
|
||||
minmax(1.5*$grid-col-min-width, 1fr) // manager
|
||||
repeat(auto-fit, minmax($grid-col-min-width, 1fr));
|
||||
border-bottom: var(--color-border) 1px solid;
|
||||
|
||||
|
|
@ -1394,6 +1396,7 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
|
|||
}
|
||||
}
|
||||
|
||||
.managers,
|
||||
.groups,
|
||||
.subadmins,
|
||||
.quota {
|
||||
|
|
|
|||
|
|
@ -146,6 +146,20 @@
|
|||
<div v-if="showConfig.showStoragePath" class="storageLocation" />
|
||||
<div v-if="showConfig.showUserBackend" class="userBackend" />
|
||||
<div v-if="showConfig.showLastLogin" class="lastLogin" />
|
||||
<div :class="{'icon-loading-small': loading.manager}" class="modal__item managers">
|
||||
<NcMultiselect ref="manager"
|
||||
v-model="newUser.manager"
|
||||
:close-on-select="true"
|
||||
:user-select="true"
|
||||
:options="possibleManagers"
|
||||
:placeholder="t('settings', 'Select user manager')"
|
||||
class="multiselect-vue"
|
||||
@search-change="searchUserManager"
|
||||
label="displayname"
|
||||
track-by="id">
|
||||
<span slot="noResult">{{ t('settings', 'No results') }}</span>
|
||||
</NcMultiselect>
|
||||
</div>
|
||||
<div class="user-actions">
|
||||
<NcButton id="newsubmit"
|
||||
type="primary"
|
||||
|
|
@ -208,7 +222,9 @@
|
|||
class="headerLastLogin lastLogin">
|
||||
{{ t('settings', 'Last login') }}
|
||||
</th>
|
||||
|
||||
<th id="headerManager" class="manager">
|
||||
{{ t('settings', 'Manager') }}
|
||||
</th>
|
||||
<th class="userActions hidden-visually">
|
||||
{{ t('settings', 'User actions') }}
|
||||
</th>
|
||||
|
|
@ -224,6 +240,7 @@
|
|||
:show-config="showConfig"
|
||||
:sub-admins-groups="subAdminsGroups"
|
||||
:user="user"
|
||||
:users="users"
|
||||
:is-dark-theme="isDarkTheme" />
|
||||
|
||||
<InfiniteLoading ref="infiniteLoading" @infinite="infiniteHandler">
|
||||
|
|
@ -268,6 +285,7 @@ const newUser = {
|
|||
password: '',
|
||||
mailAddress: '',
|
||||
groups: [],
|
||||
manager: '',
|
||||
subAdminsGroups: [],
|
||||
quota: defaultQuota,
|
||||
language: {
|
||||
|
|
@ -312,6 +330,7 @@ export default {
|
|||
groups: false,
|
||||
},
|
||||
scrolled: false,
|
||||
possibleManagers: [],
|
||||
searchQuery: '',
|
||||
newUser: Object.assign({}, newUser),
|
||||
}
|
||||
|
|
@ -422,6 +441,10 @@ export default {
|
|||
},
|
||||
},
|
||||
|
||||
async beforeMount() {
|
||||
await this.searchUserManager()
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (!this.settings.canChangePassword) {
|
||||
OC.Notification.showTemporary(t('settings', 'Password change is disabled because the master key is disabled'))
|
||||
|
|
@ -449,6 +472,14 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
async searchUserManager(query) {
|
||||
await this.$store.dispatch('searchUsers', { offset: 0, limit: 10, search: query }).then(response => {
|
||||
const users = response?.data ? Object.values(response?.data.ocs.data.users) : []
|
||||
if (users.length > 0) {
|
||||
this.possibleManagers = users
|
||||
}
|
||||
})
|
||||
},
|
||||
onScroll(event) {
|
||||
this.scrolled = event.target.scrollTo > 0
|
||||
},
|
||||
|
|
@ -532,6 +563,7 @@ export default {
|
|||
subadmin: this.newUser.subAdminsGroups.map(group => group.id),
|
||||
quota: this.newUser.quota.id,
|
||||
language: this.newUser.language.code,
|
||||
manager: this.newUser.manager.id,
|
||||
})
|
||||
.then(() => {
|
||||
this.resetForm()
|
||||
|
|
|
|||
|
|
@ -217,6 +217,22 @@
|
|||
track-by="code"
|
||||
@input="setUserLanguage" />
|
||||
</td>
|
||||
<td :class="{'icon-loading-small': loading.manager}" class="managers">
|
||||
<NcMultiselect ref="manager"
|
||||
v-model="currentManager"
|
||||
:close-on-select="true"
|
||||
:user-select="true"
|
||||
:options="possibleManagers"
|
||||
:placeholder="t('settings', 'Select manager')"
|
||||
class="multiselect-vue"
|
||||
label="displayname"
|
||||
track-by="id"
|
||||
@search-change="searchUserManager"
|
||||
@remove="updateUserManager"
|
||||
@select="updateUserManager">
|
||||
<span slot="noResult">{{ t('settings', 'No results') }}</span>
|
||||
</NcMultiselect>
|
||||
</td>
|
||||
|
||||
<!-- don't show this on edit mode -->
|
||||
<td v-if="showConfig.showStoragePath || showConfig.showUserBackend"
|
||||
|
|
@ -275,6 +291,10 @@ export default {
|
|||
},
|
||||
mixins: [UserRowMixin],
|
||||
props: {
|
||||
users: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
user: {
|
||||
type: Object,
|
||||
required: true,
|
||||
|
|
@ -317,6 +337,8 @@ export default {
|
|||
rand: parseInt(Math.random() * 1000),
|
||||
openedMenu: false,
|
||||
feedbackMessage: '',
|
||||
possibleManagers: [],
|
||||
currentManager: '',
|
||||
editing: false,
|
||||
loading: {
|
||||
all: false,
|
||||
|
|
@ -330,10 +352,12 @@ export default {
|
|||
disable: false,
|
||||
languages: false,
|
||||
wipe: false,
|
||||
manager: false,
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
/* USER POPOVERMENU ACTIONS */
|
||||
userActions() {
|
||||
const actions = [
|
||||
|
|
@ -363,6 +387,12 @@ export default {
|
|||
return actions.concat(this.externalActions)
|
||||
},
|
||||
},
|
||||
async beforeMount() {
|
||||
await this.searchUserManager()
|
||||
if (this.user.manager) {
|
||||
await this.initManager(this.user.manager)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
/* MENU HANDLING */
|
||||
|
|
@ -399,6 +429,34 @@ export default {
|
|||
)
|
||||
},
|
||||
|
||||
filterManagers(managers) {
|
||||
return managers.filter((manager) => manager.id !== this.user.id)
|
||||
},
|
||||
async initManager(userId) {
|
||||
await this.$store.dispatch('getUser', userId).then(response => {
|
||||
this.currentManager = response?.data.ocs.data
|
||||
})
|
||||
},
|
||||
async searchUserManager(query) {
|
||||
await this.$store.dispatch('searchUsers', { offset: 0, limit: 10, search: query }).then(response => {
|
||||
const users = response?.data ? this.filterManagers(Object.values(response?.data.ocs.data.users)) : []
|
||||
if (users.length > 0) {
|
||||
this.possibleManagers = users
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
updateUserManager(manager) {
|
||||
this.loading.manager = true
|
||||
this.$store.dispatch('setUserData', {
|
||||
userid: this.user.id,
|
||||
key: 'manager',
|
||||
value: this.currentManager ? this.currentManager.id : '',
|
||||
}).then(() => {
|
||||
this.loading.manager = false
|
||||
})
|
||||
},
|
||||
|
||||
deleteUser() {
|
||||
const userid = this.user.id
|
||||
OC.dialogs.confirmDestructive(
|
||||
|
|
|
|||
|
|
@ -55,7 +55,9 @@
|
|||
<td v-if="showConfig.showLastLogin" :title="userLastLoginTooltip" class="lastLogin">
|
||||
{{ userLastLogin }}
|
||||
</td>
|
||||
|
||||
<td class="managers">
|
||||
{{ user.manager }}
|
||||
</td>
|
||||
<td class="userActions">
|
||||
<div v-if="canEdit && !loading.all" class="toggleUserActions">
|
||||
<NcActions>
|
||||
|
|
|
|||
|
|
@ -253,6 +253,41 @@ let searchRequestCancelSource = null
|
|||
|
||||
const actions = {
|
||||
|
||||
/**
|
||||
* search users
|
||||
*
|
||||
* @param {object} context store context
|
||||
* @param {object} options destructuring object
|
||||
* @param {number} options.offset List offset to request
|
||||
* @param {number} options.limit List number to return from offset
|
||||
* @param {string} options.search Search amongst users
|
||||
* @return {Promise}
|
||||
*/
|
||||
searchUsers(context, { offset, limit, search }) {
|
||||
search = typeof search === 'string' ? search : ''
|
||||
|
||||
return api.get(generateOcsUrl('cloud/users/details?offset={offset}&limit={limit}&search={search}', { offset, limit, search })).catch((error) => {
|
||||
if (!axios.isCancel(error)) {
|
||||
context.commit('API_FAILURE', error)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Get user details
|
||||
*
|
||||
* @param {object} context store context
|
||||
* @param {string} userId user id
|
||||
* @return {Promise}
|
||||
*/
|
||||
getUser(context, userId) {
|
||||
return api.get(generateOcsUrl(`cloud/users/${userId}`)).catch((error) => {
|
||||
if (!axios.isCancel(error)) {
|
||||
context.commit('API_FAILURE', error)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all users with full details
|
||||
*
|
||||
|
|
@ -548,11 +583,12 @@ const actions = {
|
|||
* @param {string} options.subadmin User subadmin groups
|
||||
* @param {string} options.quota User email
|
||||
* @param {string} options.language User language
|
||||
* @param {string} options.manager User manager
|
||||
* @return {Promise}
|
||||
*/
|
||||
addUser({ commit, dispatch }, { userid, password, displayName, email, groups, subadmin, quota, language }) {
|
||||
addUser({ commit, dispatch }, { userid, password, displayName, email, groups, subadmin, quota, language, manager }) {
|
||||
return api.requireAdmin().then((response) => {
|
||||
return api.post(generateOcsUrl('cloud/users'), { userid, password, displayName, email, groups, subadmin, quota, language })
|
||||
return api.post(generateOcsUrl('cloud/users'), { userid, password, displayName, email, groups, subadmin, quota, language, manager })
|
||||
.then((response) => dispatch('addUserData', userid || response.data.ocs.data.id))
|
||||
.catch((error) => { throw error })
|
||||
}).catch((error) => {
|
||||
|
|
@ -605,8 +641,8 @@ const actions = {
|
|||
* @return {Promise}
|
||||
*/
|
||||
setUserData(context, { userid, key, value }) {
|
||||
const allowedEmpty = ['email', 'displayname']
|
||||
if (['email', 'language', 'quota', 'displayname', 'password'].indexOf(key) !== -1) {
|
||||
const allowedEmpty = ['email', 'displayname', 'manager']
|
||||
if (['email', 'language', 'quota', 'displayname', 'password', 'manager'].indexOf(key) !== -1) {
|
||||
// We allow empty email or displayname
|
||||
if (typeof value === 'string'
|
||||
&& (
|
||||
|
|
|
|||
4
dist/settings-users-8351.js
vendored
4
dist/settings-users-8351.js
vendored
File diff suppressed because one or more lines are too long
2
dist/settings-users-8351.js.map
vendored
2
dist/settings-users-8351.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -159,4 +159,12 @@ class LazyUser implements IUser {
|
|||
public function setQuota($quota) {
|
||||
$this->getUser()->setQuota($quota);
|
||||
}
|
||||
|
||||
public function getManagerUids(): array {
|
||||
return $this->getUser()->getManagerUids();
|
||||
}
|
||||
|
||||
public function setManagerUids(array $uids): void {
|
||||
$this->getUser()->setManagerUids($uids);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,8 +59,12 @@ use OCP\User\Backend\IGetHomeBackend;
|
|||
use OCP\UserInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\GenericEvent;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
|
||||
class User implements IUser {
|
||||
private const CONFIG_KEY_MANAGERS = 'manager';
|
||||
|
||||
/** @var IAccountManager */
|
||||
protected $accountManager;
|
||||
/** @var string */
|
||||
|
|
@ -532,6 +536,27 @@ class User implements IUser {
|
|||
\OC_Helper::clearStorageInfo('/' . $this->uid . '/files');
|
||||
}
|
||||
|
||||
public function getManagerUids(): array {
|
||||
$encodedUids = $this->config->getUserValue(
|
||||
$this->uid,
|
||||
'settings',
|
||||
self::CONFIG_KEY_MANAGERS,
|
||||
'[]'
|
||||
);
|
||||
return json_decode($encodedUids, false, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
public function setManagerUids(array $uids): void {
|
||||
$oldUids = $this->getManagerUids();
|
||||
$this->config->setUserValue(
|
||||
$this->uid,
|
||||
'settings',
|
||||
self::CONFIG_KEY_MANAGERS,
|
||||
json_encode($uids, JSON_THROW_ON_ERROR)
|
||||
);
|
||||
$this->triggerChange('managers', $uids, $oldUids);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the avatar image if it exists
|
||||
*
|
||||
|
|
|
|||
|
|
@ -270,4 +270,21 @@ interface IUser {
|
|||
* @since 9.0.0
|
||||
*/
|
||||
public function setQuota($quota);
|
||||
|
||||
/**
|
||||
* Get the user's manager UIDs
|
||||
*
|
||||
* @since 27.0.0
|
||||
* @return string[]
|
||||
*/
|
||||
public function getManagerUids(): array;
|
||||
|
||||
/**
|
||||
* Set the user's manager UIDs
|
||||
*
|
||||
* @param string[] $uids UIDs of all managers
|
||||
* @return void
|
||||
* @since 27.0.0
|
||||
*/
|
||||
public function setManagerUids(array $uids): void;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue