You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

users.js 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. /**
  2. * @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
  3. *
  4. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  5. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  6. * @author Daniel Calviño Sánchez <danxuliu@gmail.com>
  7. * @author John Molakvoæ <skjnldsv@protonmail.com>
  8. * @author Julius Härtl <jus@bitgrid.net>
  9. * @author Roeland Jago Douma <roeland@famdouma.nl>
  10. * @author Vincent Petry <vincent@nextcloud.com>
  11. * @author Stephan Orbaugh <stephan.orbaugh@nextcloud.com>
  12. *
  13. * @license AGPL-3.0-or-later
  14. *
  15. * This program is free software: you can redistribute it and/or modify
  16. * it under the terms of the GNU Affero General Public License as
  17. * published by the Free Software Foundation, either version 3 of the
  18. * License, or (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU Affero General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU Affero General Public License
  26. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  27. *
  28. */
  29. import { getBuilder } from '@nextcloud/browser-storage'
  30. import { getCapabilities } from '@nextcloud/capabilities'
  31. import { parseFileSize } from '@nextcloud/files'
  32. import { showError } from '@nextcloud/dialogs'
  33. import { generateOcsUrl, generateUrl } from '@nextcloud/router'
  34. import axios from '@nextcloud/axios'
  35. import { GroupSorting } from '../constants/GroupManagement.ts'
  36. import api from './api.js'
  37. import logger from '../logger.ts'
  38. const localStorage = getBuilder('settings').persist(true).build()
  39. const defaults = {
  40. group: {
  41. id: '',
  42. name: '',
  43. usercount: 0,
  44. disabled: 0,
  45. canAdd: true,
  46. canRemove: true,
  47. },
  48. }
  49. const state = {
  50. users: [],
  51. groups: [],
  52. orderBy: GroupSorting.UserCount,
  53. minPasswordLength: 0,
  54. usersOffset: 0,
  55. usersLimit: 25,
  56. disabledUsersOffset: 0,
  57. disabledUsersLimit: 25,
  58. userCount: 0,
  59. showConfig: {
  60. showStoragePath: localStorage.getItem('account_settings__showStoragePath') === 'true',
  61. showUserBackend: localStorage.getItem('account_settings__showUserBackend') === 'true',
  62. showLastLogin: localStorage.getItem('account_settings__showLastLogin') === 'true',
  63. showNewUserForm: localStorage.getItem('account_settings__showNewUserForm') === 'true',
  64. showLanguages: localStorage.getItem('account_settings__showLanguages') === 'true',
  65. },
  66. }
  67. const mutations = {
  68. appendUsers(state, usersObj) {
  69. const existingUsers = state.users.map(({ id }) => id)
  70. const newUsers = Object.values(usersObj)
  71. .filter(({ id }) => !existingUsers.includes(id))
  72. const users = state.users.concat(newUsers)
  73. state.usersOffset += state.usersLimit
  74. state.users = users
  75. },
  76. updateDisabledUsers(state, _usersObj) {
  77. state.disabledUsersOffset += state.disabledUsersLimit
  78. },
  79. setPasswordPolicyMinLength(state, length) {
  80. state.minPasswordLength = length !== '' ? length : 0
  81. },
  82. initGroups(state, { groups, orderBy, userCount }) {
  83. state.groups = groups.map(group => Object.assign({}, defaults.group, group))
  84. state.orderBy = orderBy
  85. state.userCount = userCount
  86. },
  87. addGroup(state, { gid, displayName }) {
  88. try {
  89. if (typeof state.groups.find((group) => group.id === gid) !== 'undefined') {
  90. return
  91. }
  92. // extend group to default values
  93. const group = Object.assign({}, defaults.group, {
  94. id: gid,
  95. name: displayName,
  96. })
  97. state.groups.unshift(group)
  98. } catch (e) {
  99. console.error('Can\'t create group', e)
  100. }
  101. },
  102. renameGroup(state, { gid, displayName }) {
  103. const groupIndex = state.groups.findIndex(groupSearch => groupSearch.id === gid)
  104. if (groupIndex >= 0) {
  105. const updatedGroup = state.groups[groupIndex]
  106. updatedGroup.name = displayName
  107. state.groups.splice(groupIndex, 1, updatedGroup)
  108. }
  109. },
  110. removeGroup(state, gid) {
  111. const groupIndex = state.groups.findIndex(groupSearch => groupSearch.id === gid)
  112. if (groupIndex >= 0) {
  113. state.groups.splice(groupIndex, 1)
  114. }
  115. },
  116. addUserGroup(state, { userid, gid }) {
  117. const group = state.groups.find(groupSearch => groupSearch.id === gid)
  118. const user = state.users.find(user => user.id === userid)
  119. // increase count if user is enabled
  120. if (group && user.enabled && state.userCount > 0) {
  121. group.usercount++
  122. }
  123. const groups = user.groups
  124. groups.push(gid)
  125. },
  126. removeUserGroup(state, { userid, gid }) {
  127. const group = state.groups.find(groupSearch => groupSearch.id === gid)
  128. const user = state.users.find(user => user.id === userid)
  129. // lower count if user is enabled
  130. if (group && user.enabled && state.userCount > 0) {
  131. group.usercount--
  132. }
  133. const groups = user.groups
  134. groups.splice(groups.indexOf(gid), 1)
  135. },
  136. addUserSubAdmin(state, { userid, gid }) {
  137. const groups = state.users.find(user => user.id === userid).subadmin
  138. groups.push(gid)
  139. },
  140. removeUserSubAdmin(state, { userid, gid }) {
  141. const groups = state.users.find(user => user.id === userid).subadmin
  142. groups.splice(groups.indexOf(gid), 1)
  143. },
  144. deleteUser(state, userid) {
  145. const userIndex = state.users.findIndex(user => user.id === userid)
  146. this.commit('updateUserCounts', { user: state.users[userIndex], actionType: 'remove' })
  147. state.users.splice(userIndex, 1)
  148. },
  149. addUserData(state, response) {
  150. const user = response.data.ocs.data
  151. state.users.unshift(user)
  152. this.commit('updateUserCounts', { user, actionType: 'create' })
  153. },
  154. enableDisableUser(state, { userid, enabled }) {
  155. const user = state.users.find(user => user.id === userid)
  156. user.enabled = enabled
  157. this.commit('updateUserCounts', { user, actionType: enabled ? 'enable' : 'disable' })
  158. },
  159. // update active/disabled counts, groups counts
  160. updateUserCounts(state, { user, actionType }) {
  161. // 0 is a special value
  162. if (state.userCount === 0) {
  163. return
  164. }
  165. const disabledGroup = state.groups.find(group => group.id === 'disabled')
  166. switch (actionType) {
  167. case 'enable':
  168. case 'disable':
  169. disabledGroup.usercount += user.enabled ? -1 : 1 // update Disabled Users count
  170. state.userCount += user.enabled ? 1 : -1 // update Active Users count
  171. user.groups.forEach(userGroup => {
  172. const group = state.groups.find(groupSearch => groupSearch.id === userGroup)
  173. group.disabled += user.enabled ? -1 : 1 // update group disabled count
  174. })
  175. break
  176. case 'create':
  177. state.userCount++ // increment Active Users count
  178. user.groups.forEach(userGroup => {
  179. state.groups
  180. .find(groupSearch => groupSearch.id === userGroup)
  181. .usercount++ // increment group total count
  182. })
  183. break
  184. case 'remove':
  185. if (user.enabled) {
  186. state.userCount-- // decrement Active Users count
  187. user.groups.forEach(userGroup => {
  188. const group = state.groups.find(groupSearch => groupSearch.id === userGroup)
  189. if (!group) {
  190. console.warn('User group ' + userGroup + ' does not exist during user removal')
  191. return
  192. }
  193. group.usercount-- // decrement group total count
  194. })
  195. } else {
  196. disabledGroup.usercount-- // decrement Disabled Users count
  197. user.groups.forEach(userGroup => {
  198. const group = state.groups.find(groupSearch => groupSearch.id === userGroup)
  199. group.disabled-- // decrement group disabled count
  200. })
  201. }
  202. break
  203. default:
  204. logger.error(`Unknown action type in updateUserCounts: '${actionType}'`)
  205. // not throwing error to interrupt execution as this is not fatal
  206. }
  207. },
  208. setUserData(state, { userid, key, value }) {
  209. if (key === 'quota') {
  210. const humanValue = parseFileSize(value, true)
  211. state.users.find(user => user.id === userid)[key][key] = humanValue !== null ? humanValue : value
  212. } else {
  213. state.users.find(user => user.id === userid)[key] = value
  214. }
  215. },
  216. /**
  217. * Reset users list
  218. *
  219. * @param {object} state the store state
  220. */
  221. resetUsers(state) {
  222. state.users = []
  223. state.usersOffset = 0
  224. state.disabledUsersOffset = 0
  225. },
  226. setShowConfig(state, { key, value }) {
  227. localStorage.setItem(`account_settings__${key}`, JSON.stringify(value))
  228. state.showConfig[key] = value
  229. },
  230. setGroupSorting(state, sorting) {
  231. const oldValue = state.orderBy
  232. state.orderBy = sorting
  233. // Persist the value on the server
  234. axios.post(
  235. generateUrl('/settings/users/preferences/group.sortBy'),
  236. {
  237. value: String(sorting),
  238. },
  239. ).catch((error) => {
  240. state.orderBy = oldValue
  241. showError(t('settings', 'Could not set group sorting'))
  242. logger.error(error)
  243. })
  244. },
  245. }
  246. const getters = {
  247. getUsers(state) {
  248. return state.users
  249. },
  250. getGroups(state) {
  251. return state.groups
  252. },
  253. getSubadminGroups(state) {
  254. // Can't be subadmin of admin or disabled
  255. return state.groups.filter(group => group.id !== 'admin' && group.id !== 'disabled')
  256. },
  257. getSortedGroups(state) {
  258. const groups = [...state.groups]
  259. if (state.orderBy === GroupSorting.UserCount) {
  260. return groups.sort((a, b) => {
  261. const numA = a.usercount - a.disabled
  262. const numB = b.usercount - b.disabled
  263. return (numA < numB) ? 1 : (numB < numA ? -1 : a.name.localeCompare(b.name))
  264. })
  265. } else {
  266. return groups.sort((a, b) => a.name.localeCompare(b.name))
  267. }
  268. },
  269. getGroupSorting(state) {
  270. return state.orderBy
  271. },
  272. getPasswordPolicyMinLength(state) {
  273. return state.minPasswordLength
  274. },
  275. getUsersOffset(state) {
  276. return state.usersOffset
  277. },
  278. getUsersLimit(state) {
  279. return state.usersLimit
  280. },
  281. getDisabledUsersOffset(state) {
  282. return state.disabledUsersOffset
  283. },
  284. getDisabledUsersLimit(state) {
  285. return state.disabledUsersLimit
  286. },
  287. getUserCount(state) {
  288. return state.userCount
  289. },
  290. getShowConfig(state) {
  291. return state.showConfig
  292. },
  293. }
  294. const CancelToken = axios.CancelToken
  295. let searchRequestCancelSource = null
  296. const actions = {
  297. /**
  298. * search users
  299. *
  300. * @param {object} context store context
  301. * @param {object} options destructuring object
  302. * @param {number} options.offset List offset to request
  303. * @param {number} options.limit List number to return from offset
  304. * @param {string} options.search Search amongst users
  305. * @return {Promise}
  306. */
  307. searchUsers(context, { offset, limit, search }) {
  308. search = typeof search === 'string' ? search : ''
  309. return api.get(generateOcsUrl('cloud/users/details?offset={offset}&limit={limit}&search={search}', { offset, limit, search })).catch((error) => {
  310. if (!axios.isCancel(error)) {
  311. context.commit('API_FAILURE', error)
  312. }
  313. })
  314. },
  315. /**
  316. * Get user details
  317. *
  318. * @param {object} context store context
  319. * @param {string} userId user id
  320. * @return {Promise}
  321. */
  322. getUser(context, userId) {
  323. return api.get(generateOcsUrl(`cloud/users/${userId}`)).catch((error) => {
  324. if (!axios.isCancel(error)) {
  325. context.commit('API_FAILURE', error)
  326. }
  327. })
  328. },
  329. /**
  330. * Get all users with full details
  331. *
  332. * @param {object} context store context
  333. * @param {object} options destructuring object
  334. * @param {number} options.offset List offset to request
  335. * @param {number} options.limit List number to return from offset
  336. * @param {string} options.search Search amongst users
  337. * @param {string} options.group Get users from group
  338. * @return {Promise}
  339. */
  340. getUsers(context, { offset, limit, search, group }) {
  341. if (searchRequestCancelSource) {
  342. searchRequestCancelSource.cancel('Operation canceled by another search request.')
  343. }
  344. searchRequestCancelSource = CancelToken.source()
  345. search = typeof search === 'string' ? search : ''
  346. /**
  347. * Adding filters in the search bar such as in:files, in:users, etc.
  348. * collides with this particular search, so we need to remove them
  349. * here and leave only the original search query
  350. */
  351. search = search.replace(/in:[^\s]+/g, '').trim()
  352. group = typeof group === 'string' ? group : ''
  353. if (group !== '') {
  354. return api.get(generateOcsUrl('cloud/groups/{group}/users/details?offset={offset}&limit={limit}&search={search}', { group: encodeURIComponent(group), offset, limit, search }), {
  355. cancelToken: searchRequestCancelSource.token,
  356. })
  357. .then((response) => {
  358. const usersCount = Object.keys(response.data.ocs.data.users).length
  359. if (usersCount > 0) {
  360. context.commit('appendUsers', response.data.ocs.data.users)
  361. }
  362. return usersCount
  363. })
  364. .catch((error) => {
  365. if (!axios.isCancel(error)) {
  366. context.commit('API_FAILURE', error)
  367. }
  368. })
  369. }
  370. return api.get(generateOcsUrl('cloud/users/details?offset={offset}&limit={limit}&search={search}', { offset, limit, search }), {
  371. cancelToken: searchRequestCancelSource.token,
  372. })
  373. .then((response) => {
  374. const usersCount = Object.keys(response.data.ocs.data.users).length
  375. if (usersCount > 0) {
  376. context.commit('appendUsers', response.data.ocs.data.users)
  377. }
  378. return usersCount
  379. })
  380. .catch((error) => {
  381. if (!axios.isCancel(error)) {
  382. context.commit('API_FAILURE', error)
  383. }
  384. })
  385. },
  386. /**
  387. * Get disabled users with full details
  388. *
  389. * @param {object} context store context
  390. * @param {object} options destructuring object
  391. * @param {number} options.offset List offset to request
  392. * @param {number} options.limit List number to return from offset
  393. * @return {Promise<number>}
  394. */
  395. async getDisabledUsers(context, { offset, limit }) {
  396. const url = generateOcsUrl('cloud/users/disabled?offset={offset}&limit={limit}', { offset, limit })
  397. try {
  398. const response = await api.get(url)
  399. const usersCount = Object.keys(response.data.ocs.data.users).length
  400. if (usersCount > 0) {
  401. context.commit('appendUsers', response.data.ocs.data.users)
  402. context.commit('updateDisabledUsers', response.data.ocs.data.users)
  403. }
  404. return usersCount
  405. } catch (error) {
  406. context.commit('API_FAILURE', error)
  407. }
  408. },
  409. getGroups(context, { offset, limit, search }) {
  410. search = typeof search === 'string' ? search : ''
  411. const limitParam = limit === -1 ? '' : `&limit=${limit}`
  412. return api.get(generateOcsUrl('cloud/groups?offset={offset}&search={search}', { offset, search }) + limitParam)
  413. .then((response) => {
  414. if (Object.keys(response.data.ocs.data.groups).length > 0) {
  415. response.data.ocs.data.groups.forEach(function(group) {
  416. context.commit('addGroup', { gid: group, displayName: group })
  417. })
  418. return true
  419. }
  420. return false
  421. })
  422. .catch((error) => context.commit('API_FAILURE', error))
  423. },
  424. /**
  425. * Get all users with full details
  426. *
  427. * @param {object} context store context
  428. * @param {object} options destructuring object
  429. * @param {number} options.offset List offset to request
  430. * @param {number} options.limit List number to return from offset
  431. * @param {string} options.search -
  432. * @return {Promise}
  433. */
  434. getUsersFromList(context, { offset, limit, search }) {
  435. search = typeof search === 'string' ? search : ''
  436. return api.get(generateOcsUrl('cloud/users/details?offset={offset}&limit={limit}&search={search}', { offset, limit, search }))
  437. .then((response) => {
  438. if (Object.keys(response.data.ocs.data.users).length > 0) {
  439. context.commit('appendUsers', response.data.ocs.data.users)
  440. return true
  441. }
  442. return false
  443. })
  444. .catch((error) => context.commit('API_FAILURE', error))
  445. },
  446. /**
  447. * Get all users with full details from a groupid
  448. *
  449. * @param {object} context store context
  450. * @param {object} options destructuring object
  451. * @param {number} options.offset List offset to request
  452. * @param {number} options.limit List number to return from offset
  453. * @param {string} options.groupid -
  454. * @return {Promise}
  455. */
  456. getUsersFromGroup(context, { groupid, offset, limit }) {
  457. return api.get(generateOcsUrl('cloud/users/{groupId}/details?offset={offset}&limit={limit}', { groupId: encodeURIComponent(groupid), offset, limit }))
  458. .then((response) => context.commit('getUsersFromList', response.data.ocs.data.users))
  459. .catch((error) => context.commit('API_FAILURE', error))
  460. },
  461. getPasswordPolicyMinLength(context) {
  462. if (getCapabilities().password_policy && getCapabilities().password_policy.minLength) {
  463. context.commit('setPasswordPolicyMinLength', getCapabilities().password_policy.minLength)
  464. return getCapabilities().password_policy.minLength
  465. }
  466. return false
  467. },
  468. /**
  469. * Add group
  470. *
  471. * @param {object} context store context
  472. * @param {string} gid Group id
  473. * @return {Promise}
  474. */
  475. addGroup(context, gid) {
  476. return api.requireAdmin().then((response) => {
  477. return api.post(generateOcsUrl('cloud/groups'), { groupid: gid })
  478. .then((response) => {
  479. context.commit('addGroup', { gid, displayName: gid })
  480. return { gid, displayName: gid }
  481. })
  482. .catch((error) => { throw error })
  483. }).catch((error) => {
  484. context.commit('API_FAILURE', { gid, error })
  485. // let's throw one more time to prevent the view
  486. // from adding the user to a group that doesn't exists
  487. throw error
  488. })
  489. },
  490. /**
  491. * Rename group
  492. *
  493. * @param {object} context store context
  494. * @param {string} groupid Group id
  495. * @param {string} displayName Group display name
  496. * @return {Promise}
  497. */
  498. renameGroup(context, { groupid, displayName }) {
  499. return api.requireAdmin().then((response) => {
  500. return api.put(generateOcsUrl('cloud/groups/{groupId}', { groupId: encodeURIComponent(groupid) }), { key: 'displayname', value: displayName })
  501. .then((response) => {
  502. context.commit('renameGroup', { gid: groupid, displayName })
  503. return { groupid, displayName }
  504. })
  505. .catch((error) => { throw error })
  506. }).catch((error) => {
  507. context.commit('API_FAILURE', { groupid, error })
  508. // let's throw one more time to prevent the view
  509. // from renaming the group
  510. throw error
  511. })
  512. },
  513. /**
  514. * Remove group
  515. *
  516. * @param {object} context store context
  517. * @param {string} gid Group id
  518. * @return {Promise}
  519. */
  520. removeGroup(context, gid) {
  521. return api.requireAdmin().then((response) => {
  522. return api.delete(generateOcsUrl('cloud/groups/{groupId}', { groupId: encodeURIComponent(gid) }))
  523. .then((response) => context.commit('removeGroup', gid))
  524. .catch((error) => { throw error })
  525. }).catch((error) => context.commit('API_FAILURE', { gid, error }))
  526. },
  527. /**
  528. * Add user to group
  529. *
  530. * @param {object} context store context
  531. * @param {object} options destructuring object
  532. * @param {string} options.userid User id
  533. * @param {string} options.gid Group id
  534. * @return {Promise}
  535. */
  536. addUserGroup(context, { userid, gid }) {
  537. return api.requireAdmin().then((response) => {
  538. return api.post(generateOcsUrl('cloud/users/{userid}/groups', { userid }), { groupid: gid })
  539. .then((response) => context.commit('addUserGroup', { userid, gid }))
  540. .catch((error) => { throw error })
  541. }).catch((error) => context.commit('API_FAILURE', { userid, error }))
  542. },
  543. /**
  544. * Remove user from group
  545. *
  546. * @param {object} context store context
  547. * @param {object} options destructuring object
  548. * @param {string} options.userid User id
  549. * @param {string} options.gid Group id
  550. * @return {Promise}
  551. */
  552. removeUserGroup(context, { userid, gid }) {
  553. return api.requireAdmin().then((response) => {
  554. return api.delete(generateOcsUrl('cloud/users/{userid}/groups', { userid }), { groupid: gid })
  555. .then((response) => context.commit('removeUserGroup', { userid, gid }))
  556. .catch((error) => { throw error })
  557. }).catch((error) => {
  558. context.commit('API_FAILURE', { userid, error })
  559. // let's throw one more time to prevent
  560. // the view from removing the user row on failure
  561. throw error
  562. })
  563. },
  564. /**
  565. * Add user to group admin
  566. *
  567. * @param {object} context store context
  568. * @param {object} options destructuring object
  569. * @param {string} options.userid User id
  570. * @param {string} options.gid Group id
  571. * @return {Promise}
  572. */
  573. addUserSubAdmin(context, { userid, gid }) {
  574. return api.requireAdmin().then((response) => {
  575. return api.post(generateOcsUrl('cloud/users/{userid}/subadmins', { userid }), { groupid: gid })
  576. .then((response) => context.commit('addUserSubAdmin', { userid, gid }))
  577. .catch((error) => { throw error })
  578. }).catch((error) => context.commit('API_FAILURE', { userid, error }))
  579. },
  580. /**
  581. * Remove user from group admin
  582. *
  583. * @param {object} context store context
  584. * @param {object} options destructuring object
  585. * @param {string} options.userid User id
  586. * @param {string} options.gid Group id
  587. * @return {Promise}
  588. */
  589. removeUserSubAdmin(context, { userid, gid }) {
  590. return api.requireAdmin().then((response) => {
  591. return api.delete(generateOcsUrl('cloud/users/{userid}/subadmins', { userid }), { groupid: gid })
  592. .then((response) => context.commit('removeUserSubAdmin', { userid, gid }))
  593. .catch((error) => { throw error })
  594. }).catch((error) => context.commit('API_FAILURE', { userid, error }))
  595. },
  596. /**
  597. * Mark all user devices for remote wipe
  598. *
  599. * @param {object} context store context
  600. * @param {string} userid User id
  601. * @return {Promise}
  602. */
  603. wipeUserDevices(context, userid) {
  604. return api.requireAdmin().then((response) => {
  605. return api.post(generateOcsUrl('cloud/users/{userid}/wipe', { userid }))
  606. .catch((error) => { throw error })
  607. }).catch((error) => context.commit('API_FAILURE', { userid, error }))
  608. },
  609. /**
  610. * Delete a user
  611. *
  612. * @param {object} context store context
  613. * @param {string} userid User id
  614. * @return {Promise}
  615. */
  616. deleteUser(context, userid) {
  617. return api.requireAdmin().then((response) => {
  618. return api.delete(generateOcsUrl('cloud/users/{userid}', { userid }))
  619. .then((response) => context.commit('deleteUser', userid))
  620. .catch((error) => { throw error })
  621. }).catch((error) => context.commit('API_FAILURE', { userid, error }))
  622. },
  623. /**
  624. * Add a user
  625. *
  626. * @param {object} context store context
  627. * @param {Function} context.commit -
  628. * @param {Function} context.dispatch -
  629. * @param {object} options destructuring object
  630. * @param {string} options.userid User id
  631. * @param {string} options.password User password
  632. * @param {string} options.displayName User display name
  633. * @param {string} options.email User email
  634. * @param {string} options.groups User groups
  635. * @param {string} options.subadmin User subadmin groups
  636. * @param {string} options.quota User email
  637. * @param {string} options.language User language
  638. * @param {string} options.manager User manager
  639. * @return {Promise}
  640. */
  641. addUser({ commit, dispatch }, { userid, password, displayName, email, groups, subadmin, quota, language, manager }) {
  642. return api.requireAdmin().then((response) => {
  643. return api.post(generateOcsUrl('cloud/users'), { userid, password, displayName, email, groups, subadmin, quota, language, manager })
  644. .then((response) => dispatch('addUserData', userid || response.data.ocs.data.id))
  645. .catch((error) => { throw error })
  646. }).catch((error) => {
  647. commit('API_FAILURE', { userid, error })
  648. throw error
  649. })
  650. },
  651. /**
  652. * Get user data and commit addition
  653. *
  654. * @param {object} context store context
  655. * @param {string} userid User id
  656. * @return {Promise}
  657. */
  658. addUserData(context, userid) {
  659. return api.requireAdmin().then((response) => {
  660. return api.get(generateOcsUrl('cloud/users/{userid}', { userid }))
  661. .then((response) => context.commit('addUserData', response))
  662. .catch((error) => { throw error })
  663. }).catch((error) => context.commit('API_FAILURE', { userid, error }))
  664. },
  665. /**
  666. * Enable or disable user
  667. *
  668. * @param {object} context store context
  669. * @param {object} options destructuring object
  670. * @param {string} options.userid User id
  671. * @param {boolean} options.enabled User enablement status
  672. * @return {Promise}
  673. */
  674. enableDisableUser(context, { userid, enabled = true }) {
  675. const userStatus = enabled ? 'enable' : 'disable'
  676. return api.requireAdmin().then((response) => {
  677. return api.put(generateOcsUrl('cloud/users/{userid}/{userStatus}', { userid, userStatus }))
  678. .then((response) => context.commit('enableDisableUser', { userid, enabled }))
  679. .catch((error) => { throw error })
  680. }).catch((error) => context.commit('API_FAILURE', { userid, error }))
  681. },
  682. /**
  683. * Edit user data
  684. *
  685. * @param {object} context store context
  686. * @param {object} options destructuring object
  687. * @param {string} options.userid User id
  688. * @param {string} options.key User field to edit
  689. * @param {string} options.value Value of the change
  690. * @return {Promise}
  691. */
  692. setUserData(context, { userid, key, value }) {
  693. const allowedEmpty = ['email', 'displayname', 'manager']
  694. if (['email', 'language', 'quota', 'displayname', 'password', 'manager'].indexOf(key) !== -1) {
  695. // We allow empty email or displayname
  696. if (typeof value === 'string'
  697. && (
  698. (allowedEmpty.indexOf(key) === -1 && value.length > 0)
  699. || allowedEmpty.indexOf(key) !== -1
  700. )
  701. ) {
  702. return api.requireAdmin().then((response) => {
  703. return api.put(generateOcsUrl('cloud/users/{userid}', { userid }), { key, value })
  704. .then((response) => context.commit('setUserData', { userid, key, value }))
  705. .catch((error) => { throw error })
  706. }).catch((error) => context.commit('API_FAILURE', { userid, error }))
  707. }
  708. }
  709. return Promise.reject(new Error('Invalid request data'))
  710. },
  711. /**
  712. * Send welcome mail
  713. *
  714. * @param {object} context store context
  715. * @param {string} userid User id
  716. * @return {Promise}
  717. */
  718. sendWelcomeMail(context, userid) {
  719. return api.requireAdmin().then((response) => {
  720. return api.post(generateOcsUrl('cloud/users/{userid}/welcome', { userid }))
  721. .then(response => true)
  722. .catch((error) => { throw error })
  723. }).catch((error) => context.commit('API_FAILURE', { userid, error }))
  724. },
  725. }
  726. export default { state, mutations, getters, actions }