Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: migrate to Composition API with SFC Setup and new defaults #716

Merged
merged 5 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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