Log In and Recently Modified
authorAdam Dullage <redacted>
Sat, 27 Apr 2024 16:37:45 +0000 (17:37 +0100)
committerAdam Dullage <redacted>
Sat, 27 Apr 2024 16:37:45 +0000 (17:37 +0100)
client/App.vue
client/api.js
client/components/TextInput.vue
client/tokenStorage.js
client/views/Home.vue
client/views/LogIn.vue

index cbc0cba80ee4b665645ec00c1607f4179cce730d..387db2a4c8508f0310e2e21d0a2a8bea95b775d8 100644 (file)
@@ -12,6 +12,7 @@ import { RouterView, useRoute } from "vue-router";
 import NavBar from "./partials/NavBar.vue";\r
 import { getConfig } from "./api.js";\r
 import { useGlobalStore } from "./globalStore.js";\r
+import { loadStoredToken } from "./tokenStorage.js";\r
 \r
 const globalStore = useGlobalStore();\r
 const route = useRoute();\r
@@ -27,6 +28,7 @@ onBeforeMount(() => {
         console.error(error);\r
       }\r
     });\r
+  loadStoredToken();\r
 });\r
 \r
 const showNavBar = computed(() => {\r
index d95884d6a0120a954476ee6fe5635009b6708925..d56334d3998a0504d60ccbd56e397ae23e307339 100644 (file)
@@ -1,7 +1,7 @@
 import * as constants from "./constants.js";
 
 import axios from "axios";
-import { getToken } from "./tokenStorage.js";
+import { getStoredToken } from "./tokenStorage.js";
 import router from "./router.js";
 
 const api = axios.create();
@@ -10,7 +10,7 @@ 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();
+      const token = getStoredToken();
       config.headers.Authorization = `Bearer ${token}`;
     }
     return config;
@@ -43,3 +43,21 @@ api.interceptors.response.use(
 export function getConfig() {
   return api.get("/api/config");
 }
+
+export function getToken(username, password, totp) {
+  return api.post("/api/token", {
+    username: username,
+    password: totp ? password + totp : password,
+  });
+}
+
+export function getNotes(term, sort, order, limit) {
+  return api.get("/api/search", {
+    params: {
+      term: term,
+      sort: sort,
+      order: order,
+      limit: limit,
+    },
+  });
+}
index 2178e868e096c37fb0e4bef7b0f8cdfd6f55c638..080a6efc03dd4822f4c24df73ce7ccf5d21a47f6 100644 (file)
@@ -3,5 +3,10 @@
     type="text"
     class="w-full rounded rounded-r-none border border-theme-border bg-theme-background-elevated px-3 py-2 focus:outline-none focus:ring-1"
     placeholder="Search"
+    v-model="model"
   />
 </template>
+
+<script setup>
+const model = defineModel()
+</script>
index dc0fc081add4b9993d8a1d35e661c4e70a3fd567..2c4dc131e23830c49cb3200711b93b4f90f767db 100644 (file)
@@ -4,7 +4,7 @@ function getCookieString(token) {
   return `${tokenStorageKey}=${token}; path=/attachments; SameSite=Strict`;
 }
 
-export function setToken(token, persist = false) {
+export function storeToken(token, persist = false) {
   document.cookie = getCookieString(token);
   sessionStorage.setItem(tokenStorageKey, token);
   if (persist === true) {
@@ -12,18 +12,18 @@ export function setToken(token, persist = false) {
   }
 }
 
-export function getToken() {
+export function getStoredToken() {
   return sessionStorage.getItem(tokenStorageKey);
 }
 
-export function loadToken() {
+export function loadStoredToken() {
   const token = localStorage.getItem(tokenStorageKey);
   if (token != null) {
-    setToken(token, false);
+    storeToken(token, false);
   }
 }
 
-export function clearToken() {
+export function clearStoredToken() {
   sessionStorage.removeItem(tokenStorageKey);
   localStorage.removeItem(tokenStorageKey);
   document.cookie =
index f3a4d4d5af28efec9a6f1f492e901cf580124272..ad79b567fef2b127304aaccb4b34029d7c3c0a6f 100644 (file)
@@ -2,12 +2,31 @@
   <div class="h-full">
     <div class="flex h-full flex-col items-center justify-center">
       <Logo class="mb-5" />
-      <SearchInput class="shadow-[0_0_20px] shadow-theme-shadow" />
+      <SearchInput class="mb-5 shadow-[0_0_20px] shadow-theme-shadow" />
+      <div class="flex flex-col items-center min-h-56">
+        <p
+          v-if="notes.length > 0"
+          class="mb-2 text-xs font-bold text-theme-text-very-muted"
+        >
+          RECENTLY MODIFIED
+        </p>
+        <CustomButton v-for="note in notes" :label="note.title" />
+      </div>
     </div>
   </div>
 </template>
 
 <script setup>
+import { ref } from "vue";
+
+import { getNotes } from "../api.js";
+import CustomButton from "../components/CustomButton.vue";
 import Logo from "../components/Logo.vue";
 import SearchInput from "../partials/SearchInput.vue";
+
+const notes = ref([]);
+
+getNotes("*", "lastModified", "desc", 5).then((response) => {
+  notes.value = response.data;
+});
 </script>
index 616e7c5e8e60678b846c6c612769cdaa3e8597b3..49db2ef8bb4c78f37994a62d0d195100451777a0 100644 (file)
@@ -1,11 +1,23 @@
 <template>
   <div class="flex h-full flex-col items-center justify-center">
     <Logo class="mb-5" />
-    <form @submit.prevent="login" class="flex max-w-80 flex-col items-center">
-      <TextInput placeholder="Username" class="mb-1" required />
-      <TextInput placeholder="Password" type="password" class="mb-1" required />
+    <form @submit.prevent="logIn" class="flex max-w-80 flex-col items-center">
+      <TextInput
+        v-model="username"
+        placeholder="Username"
+        class="mb-1"
+        required
+      />
+      <TextInput
+        v-model="password"
+        placeholder="Password"
+        type="password"
+        class="mb-1"
+        required
+      />
       <TextInput
         v-if="globalStore.authType == authTypes.totp"
+        v-model="totp"
         placeholder="2FA Code"
         class="mb-1"
         required
 <script setup>
 import { mdilLogin } from "@mdi/light-js";
 import { ref } from "vue";
-import { useRouter } from "vue-router";
+import { useRouter, useRoute } from "vue-router";
 
+import { getToken } from "../api.js";
 import CustomButton from "../components/CustomButton.vue";
 import Logo from "../components/Logo.vue";
 import TextInput from "../components/TextInput.vue";
 import { authTypes } from "../constants.js";
 import { useGlobalStore } from "../globalStore.js";
+import { storeToken } from "../tokenStorage.js";
+import * as constants from "../constants.js";
 
 const router = useRouter();
+const route = useRoute();
 const globalStore = useGlobalStore();
+
+const username = ref("");
+const password = ref("");
+const totp = ref("");
 const rememberMe = ref(false);
 
-function login() {
-  router.push({ name: "home" });
-  // TODO: Implement login functionality
+function logIn() {
+  getToken(username.value, password.value, totp.value)
+    .then((response) => {
+      storeToken(response.data.access_token, rememberMe.value);
+      const redirectPath = route.query[constants.params.redirect];
+      if (redirectPath) {
+        router.push(redirectPath);
+      } else {
+        router.push({ name: "home" });
+      }
+    })
+    .catch((error) => {
+      console.error(error);
+      // TODO: Trigger error toast
+    });
 }
 </script>
git clone https://git.99rst.org/PROJECT