From: Adam Dullage Date: Sat, 27 Apr 2024 15:31:59 +0000 (+0100) Subject: API X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=b6f3aef1a0638fc82e91701debbda57b82120927;p=flatnotes.git API --- diff --git a/client/App.vue b/client/App.vue index 507633d..bdd0fa9 100644 --- a/client/App.vue +++ b/client/App.vue @@ -5,5 +5,24 @@ diff --git a/client/api.js b/client/api.js new file mode 100644 index 0000000..d95884d --- /dev/null +++ b/client/api.js @@ -0,0 +1,45 @@ +import * as constants from "./constants.js"; + +import axios from "axios"; +import { getToken } from "./tokenStorage.js"; +import router from "./router.js"; + +const api = axios.create(); + +api.interceptors.request.use( + // If the request is not for the token endpoint, add the token to the headers. + function (config) { + if (config.url !== "/api/token") { + const token = getToken(); + config.headers.Authorization = `Bearer ${token}`; + } + return config; + }, + function (error) { + return Promise.reject(error); + }, +); + +api.interceptors.response.use( + function (response) { + return response; + }, + function (error) { + // If the response is a 401 Unauthorized, redirect to the login page. + if ( + error.response?.status === 401 && + router.currentRoute.value.name !== "login" + ) { + const redirectPath = router.currentRoute.value.fullPath; + router.push({ + name: "login", + query: { [constants.params.redirect]: redirectPath }, + }); + } + return Promise.reject(error); + }, +); + +export function getConfig() { + return api.get("/api/config"); +} diff --git a/client/constants.js b/client/constants.js new file mode 100644 index 0000000..25f88f0 --- /dev/null +++ b/client/constants.js @@ -0,0 +1,46 @@ +// Params +export const params = { + searchTerm: "term", + redirect: "redirect", + showHighlights: "showHighlights", + sortBy: "sortBy", +}; + +// Other +export const alphabet = [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", +]; + +export const searchSortOptions = { score: 0, title: 1, lastModified: 2 }; + +export const authTypes = { + none: "none", + readOnly: "read_only", + password: "password", + totp: "totp", +}; diff --git a/client/globalStore.js b/client/globalStore.js new file mode 100644 index 0000000..ca9c6f5 --- /dev/null +++ b/client/globalStore.js @@ -0,0 +1,8 @@ +import { defineStore } from "pinia"; +import { ref } from "vue"; + +export const useGlobalStore = defineStore("global", () => { + const authType = ref("authType"); + + return { authType }; +}); diff --git a/client/index.js b/client/index.js index f7f8f7f..e89ab7a 100644 --- a/client/index.js +++ b/client/index.js @@ -1,7 +1,11 @@ import App from "/App.vue"; import { createApp } from "vue"; +import { createPinia } from 'pinia'; import router from "/router.js"; const app = createApp(App); +const pinia = createPinia() + app.use(router); +app.use(pinia) app.mount("#app"); diff --git a/client/tokenStorage.js b/client/tokenStorage.js new file mode 100644 index 0000000..dc0fc08 --- /dev/null +++ b/client/tokenStorage.js @@ -0,0 +1,31 @@ +const tokenStorageKey = "token"; + +function getCookieString(token) { + return `${tokenStorageKey}=${token}; path=/attachments; SameSite=Strict`; +} + +export function setToken(token, persist = false) { + document.cookie = getCookieString(token); + sessionStorage.setItem(tokenStorageKey, token); + if (persist === true) { + localStorage.setItem(tokenStorageKey, token); + } +} + +export function getToken() { + return sessionStorage.getItem(tokenStorageKey); +} + +export function loadToken() { + const token = localStorage.getItem(tokenStorageKey); + if (token != null) { + setToken(token, false); + } +} + +export function clearToken() { + sessionStorage.removeItem(tokenStorageKey); + localStorage.removeItem(tokenStorageKey); + document.cookie = + getCookieString() + "; expires=Thu, 01 Jan 1970 00:00:00 GMT"; +} diff --git a/client/views/LogIn.vue b/client/views/LogIn.vue index 70ef3c2..616e7c5 100644 --- a/client/views/LogIn.vue +++ b/client/views/LogIn.vue @@ -4,7 +4,12 @@
- +
=0.10.0" } }, + "node_modules/pinia": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.7.tgz", + "integrity": "sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==", + "dependencies": { + "@vue/devtools-api": "^6.5.0", + "vue-demi": ">=0.14.5" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@vue/composition-api": "^1.4.0", + "typescript": ">=4.4.4", + "vue": "^2.6.14 || ^3.3.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/pinia/node_modules/vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/pirates": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", diff --git a/package.json b/package.json index 40e72e9..8b122ad 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@mdi/light-js": "0.2.63", "axios": "1.6.8", "mousetrap": "1.6.5", + "pinia": "2.1.7", "vue": "3.4.24", "vue-router": "4.3.2" }, diff --git a/vite.config.js b/vite.config.js index 6ec45fe..99645b2 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,10 +1,30 @@ import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; +const devApiUrl = "http://127.0.0.1:8000"; + export default defineConfig({ plugins: [vue()], root: "client", server: { port: 8080, + proxy: { + "/api/": { + target: devApiUrl, + changeOrigin: true, + }, + "/docs": { + target: devApiUrl, + changeOrigin: true, + }, + "/openapi.json": { + target: devApiUrl, + changeOrigin: true, + }, + "/health": { + target: devApiUrl, + changeOrigin: true, + }, + }, }, });