Skip to content

Commit 9019c56

Browse files
authored
Merge pull request #57079 from Pringels/enhancement/15632/persist-user-management-columns
feat(settings): persist user management column visibility
2 parents 294057e + 31605c7 commit 9019c56

14 files changed

+244
-43
lines changed

apps/settings/lib/ConfigLexicon.php

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121
*/
2222
class ConfigLexicon implements ILexicon {
2323
public const USER_SETTINGS_EMAIL = 'email';
24+
public const USER_LIST_SHOW_STORAGE_PATH = 'user_list_show_storage_path';
25+
public const USER_LIST_SHOW_USER_BACKEND = 'user_list_show_user_backend';
26+
public const USER_LIST_SHOW_LAST_LOGIN = 'user_list_show_last_login';
27+
public const USER_LIST_SHOW_FIRST_LOGIN = 'user_list_show_first_login';
28+
public const USER_LIST_SHOW_NEW_USER_FORM = 'user_list_show_new_user_form';
29+
public const USER_LIST_SHOW_LANGUAGES = 'user_list_show_languages';
2430

2531
public function getStrictness(): Strictness {
2632
return Strictness::IGNORE;
@@ -32,7 +38,55 @@ public function getAppConfigs(): array {
3238

3339
public function getUserConfigs(): array {
3440
return [
35-
new Entry(key: self::USER_SETTINGS_EMAIL, type: ValueType::STRING, defaultRaw: '', definition: 'account mail address', flags: IUserConfig::FLAG_INDEXED),
41+
new Entry(
42+
key: self::USER_SETTINGS_EMAIL,
43+
type: ValueType::STRING,
44+
defaultRaw: '',
45+
definition: 'account mail address',
46+
flags: IUserConfig::FLAG_INDEXED,
47+
),
48+
new Entry(
49+
key: self::USER_LIST_SHOW_STORAGE_PATH,
50+
type: ValueType::BOOL,
51+
defaultRaw: false,
52+
definition: 'Show storage path column in user list',
53+
lazy: true,
54+
),
55+
new Entry(
56+
key: self::USER_LIST_SHOW_USER_BACKEND,
57+
type: ValueType::BOOL,
58+
defaultRaw: false,
59+
definition: 'Show user account backend column in user list',
60+
lazy: true,
61+
),
62+
new Entry(
63+
key: self::USER_LIST_SHOW_LAST_LOGIN,
64+
type: ValueType::BOOL,
65+
defaultRaw: false,
66+
definition: 'Show last login date column in user list',
67+
lazy: true,
68+
),
69+
new Entry(
70+
key: self::USER_LIST_SHOW_FIRST_LOGIN,
71+
type: ValueType::BOOL,
72+
defaultRaw: false,
73+
definition: 'Show first login date column in user list',
74+
lazy: true,
75+
),
76+
new Entry(
77+
key: self::USER_LIST_SHOW_NEW_USER_FORM,
78+
type: ValueType::BOOL,
79+
defaultRaw: false,
80+
definition: 'Show new user form in user list',
81+
lazy: true,
82+
),
83+
new Entry(
84+
key: self::USER_LIST_SHOW_LANGUAGES,
85+
type: ValueType::BOOL,
86+
defaultRaw: false,
87+
definition: 'Show languages in user list',
88+
lazy: true,
89+
),
3690
];
3791
}
3892
}

apps/settings/lib/Controller/UsersController.php

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use OC\Security\IdentityProof\Manager;
2020
use OC\User\Manager as UserManager;
2121
use OCA\Settings\BackgroundJobs\VerifyUserData;
22+
use OCA\Settings\ConfigLexicon;
2223
use OCA\Settings\Events\BeforeTemplateRenderedEvent;
2324
use OCA\Settings\Settings\Admin\Users;
2425
use OCA\User_LDAP\User_Proxy;
@@ -38,9 +39,11 @@
3839
use OCP\AppFramework\Http\TemplateResponse;
3940
use OCP\AppFramework\Services\IInitialState;
4041
use OCP\BackgroundJob\IJobList;
42+
use OCP\Config\IUserConfig;
4143
use OCP\Encryption\IManager;
4244
use OCP\EventDispatcher\IEventDispatcher;
4345
use OCP\Group\ISubAdmin;
46+
use OCP\IAppConfig;
4447
use OCP\IConfig;
4548
use OCP\IGroup;
4649
use OCP\IGroupManager;
@@ -59,13 +62,24 @@ class UsersController extends Controller {
5962
/** Limit for counting users for subadmins, to avoid spending too much time */
6063
private const COUNT_LIMIT_FOR_SUBADMINS = 999;
6164

65+
public const ALLOWED_USER_PREFERENCES = [
66+
ConfigLexicon::USER_LIST_SHOW_STORAGE_PATH,
67+
ConfigLexicon::USER_LIST_SHOW_USER_BACKEND,
68+
ConfigLexicon::USER_LIST_SHOW_FIRST_LOGIN,
69+
ConfigLexicon::USER_LIST_SHOW_LAST_LOGIN,
70+
ConfigLexicon::USER_LIST_SHOW_NEW_USER_FORM,
71+
ConfigLexicon::USER_LIST_SHOW_LANGUAGES,
72+
];
73+
6274
public function __construct(
6375
string $appName,
6476
IRequest $request,
6577
private UserManager $userManager,
6678
private IGroupManager $groupManager,
6779
private IUserSession $userSession,
6880
private IConfig $config,
81+
private IAppConfig $appConfig,
82+
private IUserConfig $userConfig,
6983
private IL10N $l10n,
7084
private IMailer $mailer,
7185
private IFactory $l10nFactory,
@@ -191,12 +205,12 @@ public function usersList(INavigationManager $navigationManager, ISubAdmin $subA
191205
}
192206

193207
/* QUOTAS PRESETS */
194-
$quotaPreset = $this->parseQuotaPreset($this->config->getAppValue('files', 'quota_preset', '1 GB, 5 GB, 10 GB'));
195-
$allowUnlimitedQuota = $this->config->getAppValue('files', 'allow_unlimited_quota', '1') === '1';
208+
$quotaPreset = $this->parseQuotaPreset($this->appConfig->getValueString('files', 'quota_preset', '1 GB, 5 GB, 10 GB'));
209+
$allowUnlimitedQuota = $this->appConfig->getValueBool('files', 'allow_unlimited_quota', true);
196210
if (!$allowUnlimitedQuota && count($quotaPreset) > 0) {
197-
$defaultQuota = $this->config->getAppValue('files', 'default_quota', $quotaPreset[0]);
211+
$defaultQuota = $this->appConfig->getValueString('files', 'default_quota', $quotaPreset[0]);
198212
} else {
199-
$defaultQuota = $this->config->getAppValue('files', 'default_quota', 'none');
213+
$defaultQuota = $this->appConfig->getValueString('files', 'default_quota', 'none');
200214
}
201215

202216
$event = new BeforeTemplateRenderedEvent();
@@ -219,7 +233,7 @@ public function usersList(INavigationManager $navigationManager, ISubAdmin $subA
219233
$serverData['isDelegatedAdmin'] = $isDelegatedAdmin;
220234
$serverData['sortGroups'] = $forceSortGroupByName
221235
? MetaData::SORT_GROUPNAME
222-
: (int)$this->config->getAppValue('core', 'group.sortBy', (string)MetaData::SORT_USERCOUNT);
236+
: (int)$this->appConfig->getValueString('core', 'group.sortBy', (string)MetaData::SORT_USERCOUNT);
223237
$serverData['forceSortGroupByName'] = $forceSortGroupByName;
224238
$serverData['quotaPreset'] = $quotaPreset;
225239
$serverData['allowUnlimitedQuota'] = $allowUnlimitedQuota;
@@ -230,9 +244,13 @@ public function usersList(INavigationManager $navigationManager, ISubAdmin $subA
230244
// Settings
231245
$serverData['defaultQuota'] = $defaultQuota;
232246
$serverData['canChangePassword'] = $canChangePassword;
233-
$serverData['newUserGenerateUserID'] = $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes';
234-
$serverData['newUserRequireEmail'] = $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes';
235-
$serverData['newUserSendEmail'] = $this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes';
247+
$serverData['newUserGenerateUserID'] = $this->appConfig->getValueBool('core', 'newUser.generateUserID', false);
248+
$serverData['newUserRequireEmail'] = $this->appConfig->getValueBool('core', 'newUser.requireEmail', false);
249+
$serverData['newUserSendEmail'] = $this->appConfig->getValueBool('core', 'newUser.sendEmail', true);
250+
$serverData['showConfig'] = [];
251+
foreach (self::ALLOWED_USER_PREFERENCES as $key) {
252+
$serverData['showConfig'][$key] = $this->userConfig->getValueBool($uid, $this->appName, $key, false);
253+
}
236254

237255
$this->initialState->provideInitialState('usersSettings', $serverData);
238256

@@ -250,13 +268,22 @@ public function usersList(INavigationManager $navigationManager, ISubAdmin $subA
250268
*/
251269
#[AuthorizedAdminSetting(settings:Users::class)]
252270
public function setPreference(string $key, string $value): JSONResponse {
253-
$allowed = ['newUser.sendEmail', 'group.sortBy'];
254-
if (!in_array($key, $allowed, true)) {
255-
return new JSONResponse([], Http::STATUS_FORBIDDEN);
271+
switch ($key) {
272+
case 'newUser.sendEmail':
273+
$this->appConfig->setValueBool('core', $key, $value === 'yes');
274+
break;
275+
case 'group.sortBy':
276+
$this->appConfig->setValueString('core', $key, $value);
277+
break;
278+
default:
279+
if (in_array($key, self::ALLOWED_USER_PREFERENCES, true)) {
280+
$this->userConfig->setValueBool($this->userSession->getUser()->getUID(), $this->appName, $key, $value === 'true');
281+
} else {
282+
return new JSONResponse([], Http::STATUS_FORBIDDEN);
283+
}
284+
break;
256285
}
257286

258-
$this->config->setAppValue('core', $key, $value);
259-
260287
return new JSONResponse([]);
261288
}
262289

apps/settings/src/components/UserList.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ export default {
313313
},
314314
315315
closeDialog() {
316-
this.$store.commit('setShowConfig', {
316+
this.$store.dispatch('setShowConfig', {
317317
key: 'showNewUserForm',
318318
value: false,
319319
})

apps/settings/src/components/Users/UserSettingsDialog.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ export default {
297297
},
298298
299299
setShowConfig(key, status) {
300-
this.$store.commit('setShowConfig', { key, value: status })
300+
this.$store.dispatch('setShowConfig', { key, value: status })
301301
},
302302
303303
/**

apps/settings/src/main-apps-users-management.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ sync(store, router)
3030

3131
const pinia = createPinia()
3232

33+
// Migrate legacy local storage settings to the database
34+
store.dispatch('migrateLocalStorage')
35+
3336
export default new Vue({
3437
router,
3538
store,

apps/settings/src/store/users.js

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55

66
import axios from '@nextcloud/axios'
7-
import { getBuilder } from '@nextcloud/browser-storage'
87
import { getCapabilities } from '@nextcloud/capabilities'
98
import { showError } from '@nextcloud/dialogs'
109
import { parseFileSize } from '@nextcloud/files'
@@ -17,8 +16,6 @@ import api from './api.js'
1716

1817
const usersSettings = loadState('settings', 'usersSettings', {})
1918

20-
const localStorage = getBuilder('settings').persist(true).build()
21-
2219
const defaults = {
2320
/**
2421
* @type {import('../views/user-types').IGroup}
@@ -47,12 +44,12 @@ const state = {
4744
disabledUsersLimit: 25,
4845
userCount: usersSettings.userCount ?? 0,
4946
showConfig: {
50-
showStoragePath: localStorage.getItem('account_settings__showStoragePath') === 'true',
51-
showUserBackend: localStorage.getItem('account_settings__showUserBackend') === 'true',
52-
showFirstLogin: localStorage.getItem('account_settings__showFirstLogin') === 'true',
53-
showLastLogin: localStorage.getItem('account_settings__showLastLogin') === 'true',
54-
showNewUserForm: localStorage.getItem('account_settings__showNewUserForm') === 'true',
55-
showLanguages: localStorage.getItem('account_settings__showLanguages') === 'true',
47+
showStoragePath: usersSettings.showConfig?.user_list_show_storage_path,
48+
showUserBackend: usersSettings.showConfig?.user_list_show_user_backend,
49+
showFirstLogin: usersSettings.showConfig?.user_list_show_first_login,
50+
showLastLogin: usersSettings.showConfig?.user_list_show_last_login,
51+
showNewUserForm: usersSettings.showConfig?.user_list_show_new_user_form,
52+
showLanguages: usersSettings.showConfig?.user_list_show_languages,
5653
},
5754
}
5855

@@ -241,7 +238,6 @@ const mutations = {
241238
},
242239

243240
setShowConfig(state, { key, value }) {
244-
localStorage.setItem(`account_settings__${key}`, JSON.stringify(value))
245241
state.showConfig[key] = value
246242
},
247243

@@ -801,6 +797,68 @@ const actions = {
801797
.catch((error) => { throw error })
802798
}).catch((error) => context.commit('API_FAILURE', { userid, error }))
803799
},
800+
/**
801+
* Migrate local storage keys to database
802+
*
803+
* @param {object} context store context
804+
* @param context.commit
805+
*/
806+
migrateLocalStorage({ commit }) {
807+
const preferences = {
808+
showStoragePath: 'user_list_show_storage_path',
809+
showUserBackend: 'user_list_show_user_backend',
810+
showFirstLogin: 'user_list_show_first_login',
811+
showLastLogin: 'user_list_show_last_login',
812+
showNewUserForm: 'user_list_show_new_user_form',
813+
showLanguages: 'user_list_show_languages',
814+
}
815+
816+
for (const [key, dbKey] of Object.entries(preferences)) {
817+
const localKey = `account_settings__${key}`
818+
const localValue = window.localStorage.getItem(localKey)
819+
if (localValue === null) {
820+
continue
821+
}
822+
823+
const value = localValue === 'true'
824+
commit('setShowConfig', { key, value })
825+
826+
axios.post(generateUrl(`/settings/users/preferences/${dbKey}`), {
827+
value: value ? 'true' : 'false',
828+
}).then(() => {
829+
window.localStorage.removeItem(localKey)
830+
}).catch((error) => {
831+
logger.error(`Failed to migrate preference ${key}`, { error })
832+
})
833+
}
834+
},
835+
836+
/**
837+
* Set show config
838+
*
839+
* @param {object} context store context
840+
* @param {object} options destructuring object
841+
* @param {string} options.key Key to set
842+
* @param {boolean} options.value Value to set
843+
*/
844+
setShowConfig(context, { key, value }) {
845+
context.commit('setShowConfig', { key, value })
846+
const keyMap = {
847+
showStoragePath: 'user_list_show_storage_path',
848+
showUserBackend: 'user_list_show_user_backend',
849+
showFirstLogin: 'user_list_show_first_login',
850+
showLastLogin: 'user_list_show_last_login',
851+
showNewUserForm: 'user_list_show_new_user_form',
852+
showLanguages: 'user_list_show_languages',
853+
}
854+
axios.post(generateUrl(`settings/users/preferences/${keyMap[key]}`), { value: value ? 'true' : 'false' })
855+
.catch((error) => logger.error(`Could not update ${key} preference`, { error }))
856+
},
804857
}
805858

806-
export default { state, mutations, getters, actions }
859+
export default {
860+
state,
861+
mutations,
862+
getters,
863+
actions,
864+
}

apps/settings/src/views/UserManagementNavigation.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ const isAdminOrDelegatedAdmin = computed(() => settings.value.isAdmin || setting
149149
* Open the new-user form dialog
150150
*/
151151
function showNewUserMenu() {
152-
store.commit('setShowConfig', {
152+
store.dispatch('setShowConfig', {
153153
key: 'showNewUserForm',
154154
value: true,
155155
})

0 commit comments

Comments
 (0)