Skip to content

Commit

Permalink
Merge pull request #716 from nextcloud/refactor/composition-api
Browse files Browse the repository at this point in the history
refactor: migrate to Composition API with SFC Setup and new defaults
  • Loading branch information
ShGKme authored Jul 16, 2024
2 parents 470982b + fe1119e commit 0d5512d
Show file tree
Hide file tree
Showing 14 changed files with 513 additions and 583 deletions.
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ module.exports = {
// All Rules enabled
/** Vue / Uncategorized */
'vue/attribute-hyphenation': 'error',
'vue/block-order': ['error', { order: ['script', 'template', 'style'] }], // Follow new Vue standards
'vue/component-api-style': ['error', ['script-setup']], // Follow new Vue standards
'vue/component-name-in-template-casing': 'error',
'vue/component-options-name-casing': 'error',
// 'vue/custom-event-name-casing': 'error',
Expand Down
281 changes: 135 additions & 146 deletions src/authentication/renderer/AuthenticationApp.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,141 @@
- SPDX-License-Identifier: AGPL-3.0-or-later
-->

<script setup>
import { computed, ref } from 'vue'
import MdiArrowRight from 'vue-material-design-icons/ArrowRight.vue'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
import { translate as t } from '@nextcloud/l10n'
import { getCapabilities } from '../../shared/ocs.service.js'
import { appData } from '../../app/AppData.js'
import { MIN_REQUIRED_NEXTCLOUD_VERSION, MIN_REQUIRED_TALK_VERSION } from '../../constants.js'
import { refetchAppData } from '../../app/appData.service.js'

const version = window.TALK_DESKTOP.packageInfo.version
const rawServerUrl = ref(process.env.NODE_ENV !== 'production' ? process.env.NEXTCLOUD_DEV_SERVER_HOSTS?.split?.(' ')?.[0] : '')

const serverUrl = computed(() => {
const addHTTPS = (url) => url.startsWith('http') ? url : `https://${url}`
const removeIndexPhp = (url) => url.includes('/index.php') ? url.slice(0, url.indexOf('/index.php')) : url
const removeTrailingSlash = (url) => url.endsWith('/') ? url.slice(0, -1) : url
return removeTrailingSlash(removeIndexPhp(addHTTPS(rawServerUrl.value))).trim()
})

/** @type {import('vue').Ref<'idle'|'loading'|'error'|'success'>} */
const state = ref('idle')
const stateText = ref('')

/**
* Switch state to success
*/
function setSuccess() {
state.value = 'success'
stateText.value = t('talk_desktop', 'Logged in successfully')
}

/**
* Switch state to loading
*/
function setLoading() {
state.value = 'loading'
stateText.value = ''
}

/**
* Switch state to error
* @param {string} error - Error message
*/
function setError(error) {
state.value = 'error'
stateText.value = error
}

/**
* Login
*/
async function login() {
setLoading()

// Check if valid URL
try {
// new URL will throw an exception on invalid URL
// eslint-disable-next-line no-new
new URL(serverUrl.value)
} catch {
return setError(t('talk_desktop', 'Invalid server address'))
}

// Prepare to request the server
window.TALK_DESKTOP.disableWebRequestInterceptor()
window.TALK_DESKTOP.enableWebRequestInterceptor(serverUrl.value, { enableCors: true })
appData.reset()
appData.serverUrl = serverUrl.value

// Check if there is Nextcloud server and get capabilities
let capabilitiesResponse
try {
capabilitiesResponse = await getCapabilities()
} catch {
return setError(t('talk_desktop', 'Nextcloud server not found'))
}

// Check if Talk is installed and enabled
const talkCapabilities = capabilitiesResponse.capabilities.spreed
if (!talkCapabilities) {
return setError(t('talk_desktop', 'Nextcloud Talk is not installed in the server'))
}

// Check versions compatibilities
const createVersionError = (componentName, minRequiredVersion, foundVersion) => t('talk_desktop', '{componentName} {minRequiredVersion} or higher is required but {foundVersion} is installed', {
componentName,
minRequiredVersion,
foundVersion,
})
if (capabilitiesResponse.version.major < MIN_REQUIRED_NEXTCLOUD_VERSION) {
return setError(createVersionError('Nextcloud', MIN_REQUIRED_NEXTCLOUD_VERSION, capabilitiesResponse.version.string))
}
if (parseInt(talkCapabilities.version.split('.')[0]) < MIN_REQUIRED_TALK_VERSION) {
// TODO: use semver package and check not only major version?
return setError(createVersionError('Nextcloud Talk', MIN_REQUIRED_TALK_VERSION, talkCapabilities.version,
))
}

// Login with web view
let credentials
try {
const maybeCredentials = await window.TALK_DESKTOP.openLoginWebView(serverUrl.value)
if (maybeCredentials instanceof Error) {
return setError(maybeCredentials.message)
}
credentials = maybeCredentials
} catch (error) {
console.error(error)
return setError(t('talk_desktop', 'Unexpected error'))
}

// Add credentials to the request
window.TALK_DESKTOP.enableWebRequestInterceptor(serverUrl.value, { enableCors: true, enableCookies: true, credentials })
// Save credentials
appData.credentials = credentials

// Get user's metadata and update capabilities for an authenticated user
try {
await refetchAppData(appData)
} catch (error) {
// A network connection was lost after successful requests or something unexpected went wrong
console.error(error)
return setError(t('talk_desktop', 'Login was successful but something went wrong.'))
}

// Yay!
appData.persist()
setSuccess()
await window.TALK_DESKTOP.login()
}
</script>

<template>
<div class="wrapper">
<div class="spacer">
Expand Down Expand Up @@ -53,152 +188,6 @@
</div>
</template>

<script>
import MdiArrowRight from 'vue-material-design-icons/ArrowRight.vue'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
import { translate as t } from '@nextcloud/l10n'
import { getCapabilities } from '../../shared/ocs.service.js'
import { appData } from '../../app/AppData.js'
import { MIN_REQUIRED_NEXTCLOUD_VERSION, MIN_REQUIRED_TALK_VERSION } from '../../constants.js'
import { refetchAppData } from '../../app/appData.service.js'

export default {
name: 'AuthenticationApp',

components: {
MdiArrowRight,
NcButton,
NcLoadingIcon,
NcTextField,
},

setup() {
return {
version: window.TALK_DESKTOP.packageInfo.version,
}
},

data() {
return {
rawServerUrl: process.env.NODE_ENV !== 'production' ? process.env.NEXTCLOUD_DEV_SERVER_HOSTS?.split?.(' ')?.[0] : '',
/** @type {'idle'|'loading'|'error'|'success'} */
state: 'idle',
stateText: '',
}
},

computed: {
serverUrl() {
const addHTTPS = (url) => url.startsWith('http') ? url : `https://${url}`
const removeIndexPhp = (url) => url.includes('/index.php') ? url.slice(0, url.indexOf('/index.php')) : url
const removeTrailingSlash = (url) => url.endsWith('/') ? url.slice(0, -1) : url
return removeTrailingSlash(removeIndexPhp(addHTTPS(this.rawServerUrl))).trim()
},
},

methods: {
t,

setSuccess() {
this.state = 'success'
this.stateText = t('talk_desktop', 'Logged in successfully')
},

setLoading() {
this.state = 'loading'
this.stateText = ''
},

setError(error) {
this.state = 'error'
this.stateText = error
},

async login() {
this.setLoading()

// Check if valid URL
try {
// new URL will throw an exception on invalid URL
// eslint-disable-next-line no-new
new URL(this.serverUrl)
} catch {
return this.setError(t('talk_desktop', 'Invalid server address'))
}

// Prepare to request the server
window.TALK_DESKTOP.disableWebRequestInterceptor()
window.TALK_DESKTOP.enableWebRequestInterceptor(this.serverUrl, { enableCors: true })
appData.reset()
appData.serverUrl = this.serverUrl

// Check if there is Nextcloud server and get capabilities
let capabilitiesResponse
try {
capabilitiesResponse = await getCapabilities()
} catch {
return this.setError(t('talk_desktop', 'Nextcloud server not found'))
}

// Check if Talk is installed and enabled
const talkCapabilities = capabilitiesResponse.capabilities.spreed
if (!talkCapabilities) {
return this.setError(t('talk_desktop', 'Nextcloud Talk is not installed in the server'))
}

// Check versions compatibilities
const createVersionError = (componentName, minRequiredVersion, foundVersion) => t('talk_desktop', '{componentName} {minRequiredVersion} or higher is required but {foundVersion} is installed', {
componentName,
minRequiredVersion,
foundVersion,
})
if (capabilitiesResponse.version.major < MIN_REQUIRED_NEXTCLOUD_VERSION) {
return this.setError(createVersionError('Nextcloud', MIN_REQUIRED_NEXTCLOUD_VERSION, capabilitiesResponse.version.string))
}
if (parseInt(talkCapabilities.version.split('.')[0]) < MIN_REQUIRED_TALK_VERSION) {
// TODO: use semver package and check not only major version?
return this.setError(createVersionError('Nextcloud Talk', MIN_REQUIRED_TALK_VERSION, talkCapabilities.version,
))
}

// Login with web view
let credentials
try {
const maybeCredentials = await window.TALK_DESKTOP.openLoginWebView(this.serverUrl)
if (maybeCredentials instanceof Error) {
return this.setError(maybeCredentials.message)
}
credentials = maybeCredentials
} catch (error) {
console.error(error)
return this.setError(t('talk_desktop', 'Unexpected error'))
}

// Add credentials to the request
window.TALK_DESKTOP.enableWebRequestInterceptor(this.serverUrl, { enableCors: true, enableCookies: true, credentials })
// Save credentials
appData.credentials = credentials

// Get user's metadata and update capabilities for an authenticated user
try {
await refetchAppData(appData)
} catch (error) {
// A network connection was lost after successful requests or something unexpected went wrong
console.error(error)
return this.setError(t('talk_desktop', 'Login was successful but something went wrong.'))
}

// Yay!
appData.persist()
this.setSuccess()
await window.TALK_DESKTOP.login()
},
},
}
</script>

<style scoped>
.wrapper {
height: 100vh;
Expand Down
Loading

0 comments on commit 0d5512d

Please sign in to comment.