/*
* Copyright © 2024-2025 The CTAN Team and individual authors
*
* This file is distributed under the 3-clause BSD license.
* See file LICENSE for details.
*/
import { defineStore } from 'pinia'
import { jwtDecode } from "jwt-decode"
/**
* This is the account store.
*
* @author <a href="mailto:gene@ctan.org">Gerd Neugebauer</a>
*/
export const useAccountStore = defineStore('account', {
state: () => ({
/**
* The account name if the current user is logged in.
*/
account: window.localStorage.getItem('ctan.account') || '',
/**
*
*/
error: '',
/**
*
*/
message: null,
/**
*
*/
user: (window.localStorage.getItem('ctan.user')
? JSON.parse(window.localStorage.getItem('ctan.user'))
: {is: {}}
)
/*
// locale: window.localStorage.getItem('ctan.locale') || 'en',
// theme: window.localStorage.getItem('ctan.theme') || 'light',
// listType: window.localStorage.getItem('ctan.list.type') || 'list',
// files: {
// showSpecial
// }
*/
}),
actions: {
/**
* Reset the error status.
*/
clearError () {
this.error = ''
},
/**
* Initialise.
*/
init (message) {
this.message = message
},
/**
* Has the current user the admin role?
*/
isAdmin () {
if (this.account === null ||
this.user === null ||
this.user.is === null ||
!this.user.is.admin) {
throw showError({
fatal: true,
statusCode: 404,
message: 'Page not found.'
})
}
},
/**
* Has the current user the given role?
*/
is (role) {
return this.user !== null &&
this.user.is !== null &&
this.user.is[role]
},
/**
* Is the current user logged in?
*/
isLoggedIn () {
return !!this.account
},
/**
* Retrieve the current JWT.
*/
getToken () {
if (this.user === null) {
return null;
}
return this.user.token
},
/**
* Try to login.
*
* @param {*} account the account name
* @param {*} passwd the password
*/
async login (account, password) {
this.message.beginLoading()
this.error = ''
try {
const data = await $fetch('/api/3.0/user/login', {
method: 'POST',
body: {
account: account,
password: password
}
})
if (data) {
this.account = data.account
this.user = data
} else {
this.error = '401'
this.account = ''
this.user = null
}
} catch (error) {
if (error.toString().includes(' 404 ')) {
this.error = '404'
} else {
this.error = '500'
}
this.account = ''
this.user = null
} finally {
this.message.endLoading()
}
window.localStorage.setItem('ctan.account', this.account)
window.localStorage.setItem('ctan.user', JSON.stringify(this.user))
},
/**
* Sign-out the current user.
* The stored account data is cleared.
*/
logout () {
this.account = ''
this.user = null
window.localStorage.setItem('ctan.account', this.account)
window.localStorage.setItem('ctan.user', JSON.stringify(this.user))
},
/**
* Try to refresh an account.
*
* @param {*} email the email
*/
async refresh (email) {
// TODO
throw showError({
fatal: true,
statusCode: 501,
message: 'Not Implemented'
})
},
/**
* Try to register an account.
*
* @param {*} account the account name
* @param {*} email the email
*/
async register (account, email, name, gender, lang) {
this.message.beginLoading()
this.error = ''
try {
const data = await $fetch('/api/3.0/user/register', {
method: 'POST',
body: {
account: account,
email: email,
gender: gender,
lang: lang,
name: name
}
})
} catch (error) {
this.error = error.toString().replaceAll(/.*: ([0-9]+) .*/g, '$1')
} finally {
this.message.endLoading()
}
},
/**
* Try to remove an account.
*
* @param {*} message the message
*/
async remove (message) {
message.beginLoading()
this.error = ''
try {
await $fetch('/api/3.0/user', {
method: 'DELETE',
body: {
account: this.user.account,
token: this.user.token
}
})
this.logout()
} catch (error) {
this.error = error
this.account = ''
this.user = null
} finally {
message.endLoading()
}
},
/**
* Try to reset the password.
*
* @param {*} account the account name
* @param {*} email the email
*/
async reset (account, email, locale) {
this.message.beginLoading()
this.error = ''
try {
await $fetch('/api/3.0/user/passwd', {
method: 'POST',
body: {
account: account,
email: email,
locale: locale
}
})
} catch (error) {
if (error.toString().includes(' 404 ')) {
this.error = '404'
} else {
this.error = '500'
}
} finally {
this.message.endLoading()
}
},
/**
* Try to set an attribute to a value -- in the client and in the server.
*
* @param {*} attribute the name of the attribute
* @param {*} value the new value
*/
async set (attribute, value) {
const jwtPayload = JSON.parse(window.atob(this.user.token.split('.')[1]))
if (attribute === 'country') {
value = value.value
}
this.message.beginLoading()
this.error = ''
try {
await $fetch('/api/3.0/user/set', {
method: 'POST',
body: {
token: this.user.token,
attribute: attribute,
value: value
}
})
this.user[attribute] = value
window.localStorage.setItem('ctan.user', JSON.stringify(this.user))
} catch (error) {
this.error = error
} finally {
this.message.endLoading()
}
}
}
})