mirror of
https://github.com/nextcloud/server.git
synced 2026-04-15 22:11:17 -04:00
refactor(twofactor_backupcodes): migrate frontend to Typescript
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
parent
095e4709b7
commit
95f2d5dbac
9 changed files with 142 additions and 119 deletions
|
|
@ -1,16 +0,0 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import Axios from '@nextcloud/axios'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export function generateCodes() {
|
||||
const url = generateUrl('/apps/twofactor_backupcodes/settings/create')
|
||||
|
||||
return Axios.post(url, {}).then((resp) => resp.data)
|
||||
}
|
||||
28
apps/twofactor_backupcodes/src/service/BackupCodesService.ts
Normal file
28
apps/twofactor_backupcodes/src/service/BackupCodesService.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import axios from '@nextcloud/axios'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
|
||||
export interface ITwoFactorBackupCodesState {
|
||||
enabled: boolean
|
||||
total: number
|
||||
used: number
|
||||
}
|
||||
|
||||
export interface IApiResponse {
|
||||
codes: string[]
|
||||
state: ITwoFactorBackupCodesState
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate new backup codes
|
||||
*/
|
||||
export async function generateCodes(): Promise<IApiResponse> {
|
||||
const url = generateUrl('/apps/twofactor_backupcodes/settings/create')
|
||||
|
||||
const { data } = await axios.post<IApiResponse>(url)
|
||||
return data
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {any} data -
|
||||
*/
|
||||
export function print(data) {
|
||||
const name = OC.theme.name || 'Nextcloud'
|
||||
const newTab = window.open('', t('twofactor_backupcodes', '{name} backup codes', { name }))
|
||||
newTab.document.write('<h1>' + t('twofactor_backupcodes', '{name} backup codes', { name }) + '</h1>')
|
||||
newTab.document.write('<pre>' + data + '</pre>')
|
||||
newTab.print()
|
||||
newTab.close()
|
||||
}
|
||||
39
apps/twofactor_backupcodes/src/service/PrintService.ts
Normal file
39
apps/twofactor_backupcodes/src/service/PrintService.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*!
|
||||
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { getCapabilities } from '@nextcloud/capabilities'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { t } from '@nextcloud/l10n'
|
||||
|
||||
/**
|
||||
* Open a new tab and print the given backup codes
|
||||
*
|
||||
* @param data - The backup codes to print
|
||||
*/
|
||||
export function print(data: string[]): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const name = (getCapabilities() as any).theming.name || 'Nextcloud'
|
||||
const newTab = window.open('', t('twofactor_backupcodes', '{name} backup codes', { name }))
|
||||
if (!newTab) {
|
||||
showError(t('twofactor_backupcodes', 'Unable to open a new tab for printing'))
|
||||
throw new Error('Unable to open a new tab for printing')
|
||||
}
|
||||
|
||||
const heading = newTab.document.createElement('h1')
|
||||
heading.textContent = t('twofactor_backupcodes', '{name} backup codes', { name })
|
||||
const pre = newTab.document.createElement('pre')
|
||||
for (const code of data) {
|
||||
const codeLine = newTab.document.createTextNode(code)
|
||||
pre.appendChild(codeLine)
|
||||
pre.appendChild(newTab.document.createElement('br'))
|
||||
}
|
||||
|
||||
newTab.document.body.innerHTML = ''
|
||||
newTab.document.body.appendChild(heading)
|
||||
newTab.document.body.appendChild(pre)
|
||||
|
||||
newTab.print()
|
||||
newTab.close()
|
||||
}
|
||||
|
|
@ -3,17 +3,17 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { createPinia, PiniaVuePlugin } from 'pinia'
|
||||
import Vue from 'vue'
|
||||
import PersonalSettings from './views/PersonalSettings.vue'
|
||||
import store from './store.js'
|
||||
|
||||
Vue.prototype.t = t
|
||||
Vue.use(PiniaVuePlugin)
|
||||
|
||||
const initialState = loadState('twofactor_backupcodes', 'state')
|
||||
store.replaceState(initialState)
|
||||
|
||||
const pinia = createPinia()
|
||||
const View = Vue.extend(PersonalSettings)
|
||||
new View({
|
||||
store,
|
||||
}).$mount('#twofactor-backupcodes-settings')
|
||||
const app = new View({
|
||||
pinia,
|
||||
})
|
||||
|
||||
app.$mount('#twofactor-backupcodes-settings')
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import Vue from 'vue'
|
||||
import Vuex, { Store } from 'vuex'
|
||||
import { generateCodes } from './service/BackupCodesService.js'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
const state = {
|
||||
enabled: false,
|
||||
total: 0,
|
||||
used: 0,
|
||||
codes: [],
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
setEnabled(state, enabled) {
|
||||
Vue.set(state, 'enabled', enabled)
|
||||
},
|
||||
setTotal(state, total) {
|
||||
Vue.set(state, 'total', total)
|
||||
},
|
||||
setUsed(state, used) {
|
||||
Vue.set(state, 'used', used)
|
||||
},
|
||||
setCodes(state, codes) {
|
||||
Vue.set(state, 'codes', codes)
|
||||
},
|
||||
}
|
||||
|
||||
const actions = {
|
||||
generate({ commit }) {
|
||||
commit('setEnabled', false)
|
||||
|
||||
return generateCodes().then(({ codes, state }) => {
|
||||
commit('setEnabled', state.enabled)
|
||||
commit('setTotal', state.total)
|
||||
commit('setUsed', state.used)
|
||||
commit('setCodes', codes)
|
||||
return true
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export default new Store({
|
||||
strict: !PRODUCTION,
|
||||
state,
|
||||
mutations,
|
||||
actions,
|
||||
})
|
||||
42
apps/twofactor_backupcodes/src/store/index.ts
Normal file
42
apps/twofactor_backupcodes/src/store/index.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { ITwoFactorBackupCodesState } from '../service/BackupCodesService.ts'
|
||||
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { generateCodes } from '../service/BackupCodesService.ts'
|
||||
|
||||
const initialState = loadState<ITwoFactorBackupCodesState>('twofactor_backupcodes', 'state')
|
||||
|
||||
export const useStore = defineStore('twofactor_backupcodes', () => {
|
||||
const enabled = ref(initialState.enabled)
|
||||
const total = ref(initialState.total)
|
||||
const used = ref(initialState.used)
|
||||
const codes = ref<string[]>([])
|
||||
|
||||
/**
|
||||
* Generate new backup codes and update the store state
|
||||
*/
|
||||
async function generate(): Promise<void> {
|
||||
enabled.value = false
|
||||
|
||||
const { codes: newCodes, state } = await generateCodes()
|
||||
enabled.value = state.enabled
|
||||
total.value = state.total
|
||||
used.value = state.used
|
||||
codes.value = newCodes
|
||||
}
|
||||
|
||||
return {
|
||||
enabled,
|
||||
total,
|
||||
used,
|
||||
codes,
|
||||
|
||||
generate,
|
||||
}
|
||||
})
|
||||
|
|
@ -59,11 +59,13 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { confirmPassword } from '@nextcloud/password-confirmation'
|
||||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
|
||||
import { logger } from '../logger.ts'
|
||||
import { logger } from '../service/logger.ts'
|
||||
import { print } from '../service/PrintService.js'
|
||||
import { useStore } from '../store/index.ts'
|
||||
|
||||
export default {
|
||||
name: 'PersonalSettings',
|
||||
|
|
@ -72,6 +74,12 @@ export default {
|
|||
NcLoadingIcon,
|
||||
},
|
||||
|
||||
setup() {
|
||||
return {
|
||||
store: useStore(),
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
generatingCodes: false,
|
||||
|
|
@ -94,19 +102,19 @@ export default {
|
|||
},
|
||||
|
||||
enabled() {
|
||||
return this.$store.state.enabled
|
||||
return this.store.enabled
|
||||
},
|
||||
|
||||
total() {
|
||||
return this.$store.state.total
|
||||
return this.store.total
|
||||
},
|
||||
|
||||
used() {
|
||||
return this.$store.state.used
|
||||
return this.store.used
|
||||
},
|
||||
|
||||
codes() {
|
||||
return this.$store.state.codes
|
||||
return this.store.codes
|
||||
},
|
||||
|
||||
name() {
|
||||
|
|
@ -119,32 +127,23 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
generateBackupCodes() {
|
||||
confirmPassword().then(() => {
|
||||
// Hide old codes
|
||||
this.generatingCodes = true
|
||||
async generateBackupCodes() {
|
||||
await confirmPassword()
|
||||
// Hide old codes
|
||||
this.generatingCodes = true
|
||||
|
||||
this.$store.dispatch('generate').then(() => {
|
||||
this.generatingCodes = false
|
||||
}).catch((err) => {
|
||||
OC.Notification.showTemporary(t('twofactor_backupcodes', 'An error occurred while generating your backup codes'))
|
||||
this.generatingCodes = false
|
||||
throw err
|
||||
})
|
||||
}).catch(logger.error)
|
||||
},
|
||||
|
||||
getPrintData(codes) {
|
||||
if (!codes) {
|
||||
return ''
|
||||
try {
|
||||
await this.store.generate()
|
||||
} catch (error) {
|
||||
logger.error('Error generating backup codes', { error })
|
||||
showError(t('twofactor_backupcodes', 'An error occurred while generating your backup codes'))
|
||||
} finally {
|
||||
this.generatingCodes = false
|
||||
}
|
||||
return codes.reduce((prev, code) => {
|
||||
return prev + code + '<br>'
|
||||
}, '')
|
||||
},
|
||||
|
||||
printCodes() {
|
||||
print(this.getPrintData(this.codes))
|
||||
print(!this.codes || this.codes.length === 0 ? [] : this.codes)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue