diff options
Diffstat (limited to 'apps/settings/src/service')
-rw-r--r-- | apps/settings/src/service/PersonalInfo/EmailService.js | 49 | ||||
-rw-r--r-- | apps/settings/src/service/PersonalInfo/PersonalInfoService.js | 29 | ||||
-rw-r--r-- | apps/settings/src/service/ProfileService.js | 24 | ||||
-rw-r--r-- | apps/settings/src/service/WebAuthnRegistrationSerice.js | 54 | ||||
-rw-r--r-- | apps/settings/src/service/WebAuthnRegistrationSerice.ts | 57 | ||||
-rw-r--r-- | apps/settings/src/service/groups.ts | 83 | ||||
-rw-r--r-- | apps/settings/src/service/rebuild-navigation.js | 123 |
7 files changed, 164 insertions, 255 deletions
diff --git a/apps/settings/src/service/PersonalInfo/EmailService.js b/apps/settings/src/service/PersonalInfo/EmailService.js index 017c0518f60..0adbe5225bc 100644 --- a/apps/settings/src/service/PersonalInfo/EmailService.js +++ b/apps/settings/src/service/PersonalInfo/EmailService.js @@ -1,31 +1,16 @@ /** - * @copyright 2021, Christopher Ng <chrng8@gmail.com> - * - * @author Christopher Ng <chrng8@gmail.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ -import axios from '@nextcloud/axios' import { getCurrentUser } from '@nextcloud/auth' import { generateOcsUrl } from '@nextcloud/router' -import confirmPassword from '@nextcloud/password-confirmation' +import { confirmPassword } from '@nextcloud/password-confirmation' +import axios from '@nextcloud/axios' + +import { ACCOUNT_PROPERTY_ENUM, SCOPE_SUFFIX } from '../../constants/AccountPropertyConstants.ts' -import { ACCOUNT_PROPERTY_ENUM, SCOPE_SUFFIX } from '../../constants/AccountPropertyConstants' +import '@nextcloud/password-confirmation/dist/style.css' /** * Save the primary email of the user @@ -131,26 +116,6 @@ export const updateAdditionalEmail = async (prevEmail, newEmail) => { } /** - * Save the federation scope for the primary email of the user - * - * @param {string} scope the federation scope - * @return {object} - */ -export const savePrimaryEmailScope = async (scope) => { - const userId = getCurrentUser().uid - const url = generateOcsUrl('cloud/users/{userId}', { userId }) - - await confirmPassword() - - const res = await axios.put(url, { - key: `${ACCOUNT_PROPERTY_ENUM.EMAIL}${SCOPE_SUFFIX}`, - value: scope, - }) - - return res.data -} - -/** * Save the federation scope for the additional email of the user * * @param {string} email the additional email diff --git a/apps/settings/src/service/PersonalInfo/PersonalInfoService.js b/apps/settings/src/service/PersonalInfo/PersonalInfoService.js index da86414da00..f2eaac91301 100644 --- a/apps/settings/src/service/PersonalInfo/PersonalInfoService.js +++ b/apps/settings/src/service/PersonalInfo/PersonalInfoService.js @@ -1,31 +1,16 @@ /** - * @copyright 2021, Christopher Ng <chrng8@gmail.com> - * - * @author Christopher Ng <chrng8@gmail.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ -import axios from '@nextcloud/axios' import { getCurrentUser } from '@nextcloud/auth' import { generateOcsUrl } from '@nextcloud/router' -import confirmPassword from '@nextcloud/password-confirmation' +import { confirmPassword } from '@nextcloud/password-confirmation' +import axios from '@nextcloud/axios' + +import { SCOPE_SUFFIX } from '../../constants/AccountPropertyConstants.ts' -import { SCOPE_SUFFIX } from '../../constants/AccountPropertyConstants' +import '@nextcloud/password-confirmation/dist/style.css' /** * Save the primary account property value for the user diff --git a/apps/settings/src/service/ProfileService.js b/apps/settings/src/service/ProfileService.js index f84135dd9d2..3e6c7cd622f 100644 --- a/apps/settings/src/service/ProfileService.js +++ b/apps/settings/src/service/ProfileService.js @@ -1,29 +1,13 @@ /** - * @copyright 2021 Christopher Ng <chrng8@gmail.com> - * - * @author Christopher Ng <chrng8@gmail.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ import axios from '@nextcloud/axios' import { getCurrentUser } from '@nextcloud/auth' import { generateOcsUrl } from '@nextcloud/router' -import confirmPassword from '@nextcloud/password-confirmation' +import { confirmPassword } from '@nextcloud/password-confirmation' +import '@nextcloud/password-confirmation/dist/style.css' /** * Save the visibility of the profile parameter diff --git a/apps/settings/src/service/WebAuthnRegistrationSerice.js b/apps/settings/src/service/WebAuthnRegistrationSerice.js deleted file mode 100644 index 185dbd8cf28..00000000000 --- a/apps/settings/src/service/WebAuthnRegistrationSerice.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @copyright 2020, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -import axios from '@nextcloud/axios' -import { generateUrl } from '@nextcloud/router' - -/** - * - */ -export async function startRegistration() { - const url = generateUrl('/settings/api/personal/webauthn/registration') - - const resp = await axios.get(url) - return resp.data -} - -/** - * @param {any} name - - * @param {any} data - - */ -export async function finishRegistration(name, data) { - const url = generateUrl('/settings/api/personal/webauthn/registration') - - const resp = await axios.post(url, { name, data }) - return resp.data -} - -/** - * @param {any} id - - */ -export async function removeRegistration(id) { - const url = generateUrl(`/settings/api/personal/webauthn/registration/${id}`) - - await axios.delete(url) -} diff --git a/apps/settings/src/service/WebAuthnRegistrationSerice.ts b/apps/settings/src/service/WebAuthnRegistrationSerice.ts new file mode 100644 index 00000000000..0d1689ab90a --- /dev/null +++ b/apps/settings/src/service/WebAuthnRegistrationSerice.ts @@ -0,0 +1,57 @@ +/** + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import type { PublicKeyCredentialCreationOptionsJSON, RegistrationResponseJSON } from '@simplewebauthn/browser' + +import { translate as t } from '@nextcloud/l10n' +import { generateUrl } from '@nextcloud/router' +import { startRegistration as registerWebAuthn } from '@simplewebauthn/browser' + +import axios, { isAxiosError } from '@nextcloud/axios' +import logger from '../logger' + +/** + * Start registering a new device + * @return The device attributes + */ +export async function startRegistration() { + const url = generateUrl('/settings/api/personal/webauthn/registration') + + try { + logger.debug('Fetching webauthn registration data') + const { data } = await axios.get<PublicKeyCredentialCreationOptionsJSON>(url) + logger.debug('Start webauthn registration') + const attrs = await registerWebAuthn({ optionsJSON: data }) + return attrs + } catch (e) { + logger.error(e as Error) + if (isAxiosError(e)) { + throw new Error(t('settings', 'Could not register device: Network error')) + } else if ((e as Error).name === 'InvalidStateError') { + throw new Error(t('settings', 'Could not register device: Probably already registered')) + } + throw new Error(t('settings', 'Could not register device')) + } +} + +/** + * @param name Name of the device + * @param data Device attributes + */ +export async function finishRegistration(name: string, data: RegistrationResponseJSON) { + const url = generateUrl('/settings/api/personal/webauthn/registration') + + const resp = await axios.post(url, { name, data: JSON.stringify(data) }) + return resp.data +} + +/** + * @param id Remove registered device with that id + */ +export async function removeRegistration(id: string | number) { + const url = generateUrl(`/settings/api/personal/webauthn/registration/${id}`) + + await axios.delete(url) +} diff --git a/apps/settings/src/service/groups.ts b/apps/settings/src/service/groups.ts new file mode 100644 index 00000000000..a8cfd842451 --- /dev/null +++ b/apps/settings/src/service/groups.ts @@ -0,0 +1,83 @@ +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import type { IGroup } from '../views/user-types.d.ts' + +import axios from '@nextcloud/axios' +import { generateOcsUrl } from '@nextcloud/router' +import { CancelablePromise } from 'cancelable-promise' + +interface Group { + id: string + displayname: string + usercount: number + disabled: number + canAdd: boolean + canRemove: boolean +} + +const formatGroup = (group: Group): Required<IGroup> => ({ + id: group.id, + name: group.displayname, + usercount: group.usercount, + disabled: group.disabled, + canAdd: group.canAdd, + canRemove: group.canRemove, +}) + +/** + * Search groups + * + * @param {object} options Options + * @param {string} options.search Search query + * @param {number} options.offset Offset + * @param {number} options.limit Limit + */ +export const searchGroups = ({ search, offset, limit }): CancelablePromise<Required<IGroup>[]> => { + const controller = new AbortController() + return new CancelablePromise(async (resolve, reject, onCancel) => { + onCancel(() => controller.abort()) + try { + const { data } = await axios.get( + generateOcsUrl('/cloud/groups/details?search={search}&offset={offset}&limit={limit}', { search, offset, limit }), { + signal: controller.signal, + }, + ) + const groups: Group[] = data.ocs?.data?.groups ?? [] + const formattedGroups = groups.map(formatGroup) + resolve(formattedGroups) + } catch (error) { + reject(error) + } + }) +} + +/** + * Load user groups + * + * @param {object} options Options + * @param {string} options.userId User id + */ +export const loadUserGroups = async ({ userId }): Promise<Required<IGroup>[]> => { + const url = generateOcsUrl('/cloud/users/{userId}/groups/details', { userId }) + const { data } = await axios.get(url) + const groups: Group[] = data.ocs?.data?.groups ?? [] + const formattedGroups = groups.map(formatGroup) + return formattedGroups +} + +/** + * Load user subadmin groups + * + * @param {object} options Options + * @param {string} options.userId User id + */ +export const loadUserSubAdminGroups = async ({ userId }): Promise<Required<IGroup>[]> => { + const url = generateOcsUrl('/cloud/users/{userId}/subadmins/details', { userId }) + const { data } = await axios.get(url) + const groups: Group[] = data.ocs?.data?.groups ?? [] + const formattedGroups = groups.map(formatGroup) + return formattedGroups +} diff --git a/apps/settings/src/service/rebuild-navigation.js b/apps/settings/src/service/rebuild-navigation.js index 57cb1e439bd..56317f7f5e1 100644 --- a/apps/settings/src/service/rebuild-navigation.js +++ b/apps/settings/src/service/rebuild-navigation.js @@ -1,5 +1,10 @@ +/** + * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ import axios from '@nextcloud/axios' import { generateOcsUrl } from '@nextcloud/router' +import { emit } from '@nextcloud/event-bus' export default () => { return axios.get(generateOcsUrl('core/navigation', 2) + '/apps?format=json') @@ -8,123 +13,7 @@ export default () => { return } - const addedApps = {} - const navEntries = data.ocs.data - const container = document.querySelector('#navigation #apps ul') - - // remove disabled apps - navEntries.forEach((entry) => { - if (!container.querySelector('li[data-id="' + entry.id + '"]')) { - addedApps[entry.id] = true - } - }) - - container.querySelectorAll('li[data-id]').forEach((el, index) => { - const id = el.dataset.id - // remove all apps that are not in the correct order - if (!navEntries[index] || (navEntries[index] && navEntries[index].id !== id)) { - el.remove() - document.querySelector(`#appmenu li[data-id=${id}]`).remove() - } - }) - - let previousEntry = {} - // add enabled apps to #navigation and #appmenu - navEntries.forEach((entry) => { - if (container.querySelector(`li[data-id="${entry.id}"]`) === null) { - const li = document.createElement('li') - li.dataset.id = entry.id - const img = `<svg width="20" height="20" viewBox="0 0 20 20" alt=""> - <defs> - <filter id="invertMenuMore-${entry.id}"><feColorMatrix in="SourceGraphic" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"></feColorMatrix></filter> - <mask id="hole"> - <rect width="100%" height="100%" fill="white"></rect> - <circle r="4.5" cx="17" cy="3" fill="black"></circle> - </mask> - </defs> - <image x="0" y="0" width="16" height="16" filter="url(#invertMenuMore-${entry.id})" preserveAspectRatio="xMinYMin meet" xlink:href="${entry.icon}" class="app-icon" /> - </svg>` - - const imgElement = document.createElement('template') - imgElement.innerHTML = img - - const a = document.createElement('a') - a.setAttribute('href', entry.href) - - const filename = document.createElement('span') - filename.appendChild(document.createTextNode(entry.name)) - - const loading = document.createElement('div') - loading.setAttribute('class', 'unread-counter') - loading.style.display = 'none' - - // draw attention to the newly added app entry - // by flashing twice the more apps menu - if (addedApps[entry.id]) { - a.classList.add('animated') - } - - a.prepend(imgElement.content.firstChild, loading, filename) - li.append(a) - - // add app icon to the navigation - const previousElement = document.querySelector(`#navigation li[data-id=${previousEntry.id}]`) - if (previousElement) { - previousElement.insertAdjacentElement('afterend', li) - } else { - document.querySelector('#navigation #apps ul').prepend(li) - } - } - - if (document.getElementById('appmenu').querySelector(`li[data-id="${entry.id}"]`) === null) { - const li = document.createElement('li') - li.dataset.id = entry.id - // Generating svg embedded image (see layout.user.php) - let img - if (OCA.Theming && OCA.Theming.inverted) { - img = `<svg width="20" height="20" viewBox="0 0 20 20" alt=""> - <defs> - <filter id="invert"><feColorMatrix in="SourceGraphic" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" /></filter> - </defs> - <image x="0" y="0" width="20" height="20" preserveAspectRatio="xMinYMin meet" filter="url(#invert)" xlink:href="${entry.icon}" class="app-icon" /> - </svg>` - } else { - img = `<svg width="20" height="20" viewBox="0 0 20 20" alt=""> - <image x="0" y="0" width="20" height="20" preserveAspectRatio="xMinYMin meet" xlink:href="${entry.icon}" class="app-icon" /> - </svg>` - } - const imgElement = document.createElement('template') - imgElement.innerHTML = img - - const a = document.createElement('a') - a.setAttribute('href', entry.href) - - const filename = document.createElement('span') - filename.appendChild(document.createTextNode(entry.name)) - - const loading = document.createElement('div') - loading.setAttribute('class', 'icon-loading-dark') - loading.style.display = 'none' - - // draw attention to the newly added app entry - // by flashing twice the more apps menu - if (addedApps[entry.id]) { - a.classList.add('animated') - } - - a.prepend(loading, filename, imgElement.content.firstChild) - li.append(a) - - // add app icon to the navigation - const previousElement = document.querySelector('#appmenu li[data-id=' + previousEntry.id + ']') - if (previousElement) { - previousElement.insertAdjacentElement('afterend', li) - } else { - document.queryElementById('appmenu').prepend(li) - } - } - previousEntry = entry - }) + emit('nextcloud:app-menu.refresh', { apps: data.ocs.data }) window.dispatchEvent(new Event('resize')) }) } |