mirror of
https://github.com/nextcloud/server.git
synced 2026-05-28 04:32:30 -04:00
Merge pull request #60184 from nextcloud/backport/60165/stable33
Some checks are pending
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Integration sqlite / changes (push) Waiting to run
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, --tags ~@large files_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, capabilities_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, collaboration_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, comments_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, dav_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, federation_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, file_conversions) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, files_reminders) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, filesdrop_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, ldap_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, openldap_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, openldap_numerical_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, remoteapi_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, routing_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, setup_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, sharees_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, sharing_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, theming_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, videoverification_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite-summary (push) Blocked by required conditions
Some checks are pending
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Integration sqlite / changes (push) Waiting to run
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, --tags ~@large files_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, capabilities_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, collaboration_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, comments_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, dav_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, federation_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, file_conversions) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, files_reminders) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, filesdrop_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, ldap_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, openldap_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, openldap_numerical_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, remoteapi_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, routing_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, setup_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, sharees_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, sharing_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, theming_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite (stable33, 8.4, stable33, videoverification_features) (push) Blocked by required conditions
Integration sqlite / integration-sqlite-summary (push) Blocked by required conditions
[stable33] fix(core): prompt for password once when installing recommended apps
This commit is contained in:
commit
4b20b90c5d
9 changed files with 201 additions and 39 deletions
|
|
@ -62,8 +62,8 @@
|
|||
import axios from '@nextcloud/axios'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
import { PwdConfirmationMode } from '@nextcloud/password-confirmation'
|
||||
import { generateUrl, imagePath } from '@nextcloud/router'
|
||||
import pLimit from 'p-limit'
|
||||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
|
||||
import logger from '../../logger.js'
|
||||
|
|
@ -147,35 +147,41 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
installApps() {
|
||||
this.installingApps = true
|
||||
|
||||
const limit = pLimit(1)
|
||||
const installing = this.recommendedApps
|
||||
async installApps() {
|
||||
const apps = this.recommendedApps
|
||||
.filter((app) => !app.active && app.isCompatible && app.canInstall && app.isSelected)
|
||||
.map((app) => limit(async () => {
|
||||
logger.info(`installing ${app.id}`)
|
||||
app.loading = true
|
||||
return axios.post(generateUrl('settings/apps/enable'), { appIds: [app.id], groups: [] })
|
||||
.catch((error) => {
|
||||
logger.error(`could not install ${app.id}`, { error })
|
||||
app.isSelected = false
|
||||
app.installationError = true
|
||||
})
|
||||
.then(() => {
|
||||
logger.info(`installed ${app.id}`)
|
||||
app.loading = false
|
||||
app.active = true
|
||||
})
|
||||
}))
|
||||
logger.debug(`installing ${installing.length} recommended apps`)
|
||||
Promise.all(installing)
|
||||
.then(() => {
|
||||
logger.info('all recommended apps installed, redirecting …')
|
||||
if (apps.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
window.location = this.defaultPageUrl
|
||||
this.installingApps = true
|
||||
apps.forEach((app) => {
|
||||
app.loading = true
|
||||
})
|
||||
const appIds = apps.map((app) => app.id)
|
||||
logger.debug(`installing ${apps.length} recommended apps`, { appIds })
|
||||
|
||||
try {
|
||||
await axios.post(
|
||||
generateUrl('settings/apps/enable'),
|
||||
{ appIds, groups: [] },
|
||||
{ confirmPassword: PwdConfirmationMode.Strict },
|
||||
)
|
||||
apps.forEach((app) => {
|
||||
app.loading = false
|
||||
app.active = true
|
||||
})
|
||||
.catch((error) => logger.error('could not install recommended apps', { error }))
|
||||
logger.info('all recommended apps installed, redirecting …')
|
||||
window.location = this.defaultPageUrl
|
||||
} catch (error) {
|
||||
logger.error('could not install recommended apps', { error })
|
||||
apps.forEach((app) => {
|
||||
app.loading = false
|
||||
app.isSelected = false
|
||||
app.installationError = true
|
||||
})
|
||||
this.installingApps = false
|
||||
}
|
||||
},
|
||||
|
||||
customIcon(appId) {
|
||||
|
|
|
|||
|
|
@ -4,11 +4,15 @@
|
|||
*/
|
||||
|
||||
import { getCSPNonce } from '@nextcloud/auth'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { translate as t } from '@nextcloud/l10n'
|
||||
import { addPasswordConfirmationInterceptors } from '@nextcloud/password-confirmation'
|
||||
import Vue from 'vue'
|
||||
import RecommendedApps from './components/setup/RecommendedApps.vue'
|
||||
import logger from './logger.js'
|
||||
|
||||
addPasswordConfirmationInterceptors(axios)
|
||||
|
||||
__webpack_nonce__ = getCSPNonce()
|
||||
|
||||
Vue.mixin({
|
||||
|
|
|
|||
|
|
@ -10,6 +10,32 @@ export function getUnifiedSearchModal() {
|
|||
return cy.get('#unified-search')
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the confirm password dialog (if needed)
|
||||
*
|
||||
* @param adminPassword The admin password for the dialog
|
||||
*/
|
||||
export function handlePasswordConfirmation(adminPassword = 'admin') {
|
||||
const handleModal = (context: Cypress.Chainable) => {
|
||||
return context.contains('.modal-container', 'Authentication required')
|
||||
.if()
|
||||
.within(() => {
|
||||
cy.get('input[type="password"]')
|
||||
.type(adminPassword)
|
||||
cy.findByRole('button', { name: 'Confirm' })
|
||||
.click()
|
||||
})
|
||||
}
|
||||
|
||||
return cy.get('body')
|
||||
.if()
|
||||
.then(() => handleModal(cy.get('body')))
|
||||
.else()
|
||||
// Handle if inside a cy.within
|
||||
.root().closest('body')
|
||||
.then(($body) => handleModal(cy.wrap($body)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the unified search modal
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
*/
|
||||
|
||||
import { randomString } from '../../support/utils/randomString.ts'
|
||||
import { handlePasswordConfirmation } from '../core-utils.ts'
|
||||
|
||||
type RecommendedAppsMode = 'skip' | 'install-success' | 'install-failure'
|
||||
|
||||
/**
|
||||
* DO NOT RENAME THIS FILE to .cy.ts ⚠️
|
||||
|
|
@ -30,6 +33,22 @@ describe('Can install Nextcloud', { testIsolation: true, retries: 0 }, () => {
|
|||
sharedSetup()
|
||||
})
|
||||
|
||||
it('Sqlite - Install recommended apps (success)', () => {
|
||||
cy.visit('/')
|
||||
cy.get('[data-cy-setup-form]').should('be.visible')
|
||||
cy.get('[data-cy-setup-form-field="dbtype-sqlite"] input').check({ force: true })
|
||||
|
||||
sharedSetup('install-success')
|
||||
})
|
||||
|
||||
it('Sqlite - Install recommended apps (failure)', () => {
|
||||
cy.visit('/')
|
||||
cy.get('[data-cy-setup-form]').should('be.visible')
|
||||
cy.get('[data-cy-setup-form-field="dbtype-sqlite"] input').check({ force: true })
|
||||
|
||||
sharedSetup('install-failure')
|
||||
})
|
||||
|
||||
it('MySQL', () => {
|
||||
cy.visit('/')
|
||||
cy.get('[data-cy-setup-form]').should('be.visible')
|
||||
|
|
@ -111,8 +130,12 @@ describe('Can install Nextcloud', { testIsolation: true, retries: 0 }, () => {
|
|||
|
||||
/**
|
||||
* Shared admin setup function for the Nextcloud setup
|
||||
*
|
||||
* @param mode How to handle the recommended apps screen at the end of the
|
||||
* install assistant: skip it, exercise the install button with a
|
||||
* stubbed success response, or stub a failure response.
|
||||
*/
|
||||
function sharedSetup() {
|
||||
function sharedSetup(mode: RecommendedAppsMode = 'skip') {
|
||||
const randAdmin = 'admin-' + randomString(10)
|
||||
|
||||
// mock appstore
|
||||
|
|
@ -141,10 +164,41 @@ function sharedSetup() {
|
|||
.should('be.visible')
|
||||
})
|
||||
|
||||
// Skip the setup apps
|
||||
cy.get('[data-cy-setup-recommended-apps-skip]').click()
|
||||
if (mode === 'skip') {
|
||||
// Skip the setup apps
|
||||
cy.get('[data-cy-setup-recommended-apps-skip]').click()
|
||||
|
||||
// Go to files
|
||||
cy.visit('/apps/files/')
|
||||
cy.get('[data-cy-files-content]').should('be.visible')
|
||||
// Go to files
|
||||
cy.visit('/apps/files/')
|
||||
cy.get('[data-cy-files-content]').should('be.visible')
|
||||
return
|
||||
}
|
||||
|
||||
// Stub the bulk enable endpoint so we exercise the frontend flow without
|
||||
// hitting the real app store.
|
||||
cy.intercept('POST', '**/settings/apps/enable', mode === 'install-success'
|
||||
? { statusCode: 200, body: { data: { update_required: false } } }
|
||||
: { statusCode: 500, body: { data: { message: 'Forced failure' } } }).as('enableApps')
|
||||
|
||||
cy.get('[data-cy-setup-recommended-apps-install]').click()
|
||||
|
||||
// The strict password-confirmation dialog must appear and must result in a
|
||||
// Basic auth header on the enable request.
|
||||
cy.findByRole('dialog', { name: 'Authentication required' })
|
||||
.should('be.visible')
|
||||
handlePasswordConfirmation(randAdmin)
|
||||
cy.wait('@enableApps')
|
||||
.its('request.headers.authorization')
|
||||
.should('match', /^Basic /)
|
||||
|
||||
if (mode === 'install-success') {
|
||||
// Frontend redirects via window.location to the default page.
|
||||
cy.location('pathname', { timeout: 10000 })
|
||||
.should('not.include', '/core/apps/recommended')
|
||||
} else {
|
||||
// Stay on the recommended-apps page and surface the per-app error state.
|
||||
cy.location('pathname').should('include', '/core/apps/recommended')
|
||||
cy.get('[data-cy-setup-recommended-apps]')
|
||||
.should('contain.text', 'App download or installation failed')
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4
dist/core-common.js
vendored
4
dist/core-common.js
vendored
File diff suppressed because one or more lines are too long
2
dist/core-common.js.map
vendored
2
dist/core-common.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/core-recommendedapps.js
vendored
4
dist/core-recommendedapps.js
vendored
File diff suppressed because one or more lines are too long
72
dist/core-recommendedapps.js.license
vendored
72
dist/core-recommendedapps.js.license
vendored
|
|
@ -4,7 +4,12 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||
SPDX-License-Identifier: BSD-3-Clause
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
SPDX-License-Identifier: (MPL-2.0 OR Apache-2.0)
|
||||
SPDX-FileCopyrightText: webfansplz
|
||||
SPDX-FileCopyrightText: perfect-debounce developers
|
||||
SPDX-FileCopyrightText: hookable developers
|
||||
SPDX-FileCopyrightText: escape-html developers
|
||||
SPDX-FileCopyrightText: debounce developers
|
||||
SPDX-FileCopyrightText: atomiks
|
||||
SPDX-FileCopyrightText: Tobias Koppers @sokra
|
||||
SPDX-FileCopyrightText: T. Jameson Little <t.jameson.little@gmail.com>
|
||||
SPDX-FileCopyrightText: Roman Shtylman <shtylman@gmail.com>
|
||||
|
|
@ -13,10 +18,20 @@ SPDX-FileCopyrightText: Matt Zabriskie
|
|||
SPDX-FileCopyrightText: GitHub Inc.
|
||||
SPDX-FileCopyrightText: Feross Aboukhadijeh
|
||||
SPDX-FileCopyrightText: Evan You
|
||||
SPDX-FileCopyrightText: Eduardo San Martin Morote
|
||||
SPDX-FileCopyrightText: Dr.-Ing. Mario Heiderich, Cure53 <mario@cure53.de> (https://cure53.de/)
|
||||
SPDX-FileCopyrightText: David Clark
|
||||
SPDX-FileCopyrightText: Anthony Fu <https://github.com/antfu>
|
||||
SPDX-FileCopyrightText: Anthony Fu <anthonyfu117@hotmail.com>
|
||||
|
||||
|
||||
This file is generated from multiple sources. Included packages:
|
||||
- @floating-ui/core
|
||||
- version: 1.7.5
|
||||
- license: MIT
|
||||
- @floating-ui/utils
|
||||
- version: 0.2.11
|
||||
- license: MIT
|
||||
- @nextcloud/auth
|
||||
- version: 2.6.0
|
||||
- license: GPL-3.0-or-later
|
||||
|
|
@ -26,6 +41,9 @@ This file is generated from multiple sources. Included packages:
|
|||
- @nextcloud/browser-storage
|
||||
- version: 0.5.0
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/capabilities
|
||||
- version: 1.2.1
|
||||
- license: GPL-3.0-or-later
|
||||
- semver
|
||||
- version: 7.7.2
|
||||
- license: ISC
|
||||
|
|
@ -41,6 +59,48 @@ This file is generated from multiple sources. Included packages:
|
|||
- @nextcloud/logger
|
||||
- version: 3.0.3
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/vue
|
||||
- version: 9.6.0
|
||||
- license: AGPL-3.0-or-later
|
||||
- @vue/devtools-shared
|
||||
- version: 8.1.0
|
||||
- license: MIT
|
||||
- @vue/reactivity
|
||||
- version: 3.5.30
|
||||
- license: MIT
|
||||
- @vue/runtime-core
|
||||
- version: 3.5.30
|
||||
- license: MIT
|
||||
- @vue/runtime-dom
|
||||
- version: 3.5.30
|
||||
- license: MIT
|
||||
- @vue/shared
|
||||
- version: 3.5.30
|
||||
- license: MIT
|
||||
- @vueuse/core
|
||||
- version: 14.2.1
|
||||
- license: MIT
|
||||
- @vueuse/shared
|
||||
- version: 14.2.1
|
||||
- license: MIT
|
||||
- perfect-debounce
|
||||
- version: 2.1.0
|
||||
- license: MIT
|
||||
- @vue/devtools-api
|
||||
- version: 8.1.0
|
||||
- license: MIT
|
||||
- @vue/devtools-kit
|
||||
- version: 8.1.0
|
||||
- license: MIT
|
||||
- vue-router
|
||||
- version: 5.0.3
|
||||
- license: MIT
|
||||
- vue
|
||||
- version: 3.5.30
|
||||
- license: MIT
|
||||
- @nextcloud/password-confirmation
|
||||
- version: 6.1.0
|
||||
- license: MIT
|
||||
- @nextcloud/router
|
||||
- version: 3.1.0
|
||||
- license: GPL-3.0-or-later
|
||||
|
|
@ -53,15 +113,24 @@ This file is generated from multiple sources. Included packages:
|
|||
- base64-js
|
||||
- version: 1.5.1
|
||||
- license: MIT
|
||||
- birpc
|
||||
- version: 2.9.0
|
||||
- license: MIT
|
||||
- css-loader
|
||||
- version: 7.1.2
|
||||
- license: MIT
|
||||
- debounce
|
||||
- version: 3.0.0
|
||||
- license: MIT
|
||||
- dompurify
|
||||
- version: 3.4.2
|
||||
- license: (MPL-2.0 OR Apache-2.0)
|
||||
- escape-html
|
||||
- version: 1.0.3
|
||||
- license: MIT
|
||||
- hookable
|
||||
- version: 5.5.3
|
||||
- license: MIT
|
||||
- ieee754
|
||||
- version: 1.2.1
|
||||
- license: BSD-3-Clause
|
||||
|
|
@ -74,6 +143,9 @@ This file is generated from multiple sources. Included packages:
|
|||
- style-loader
|
||||
- version: 4.0.0
|
||||
- license: MIT
|
||||
- tabbable
|
||||
- version: 6.4.0
|
||||
- license: MIT
|
||||
- vue-loader
|
||||
- version: 15.11.1
|
||||
- license: MIT
|
||||
|
|
|
|||
2
dist/core-recommendedapps.js.map
vendored
2
dist/core-recommendedapps.js.map
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue