Skip to content

Commit

Permalink
Add isValid getter to auth store and use it for permission checks (#528)
Browse files Browse the repository at this point in the history
* Remove commented-out code and unnecessary comments in chat store module.

* Sort chat sessions by ID in descending order and sync sessions in chat store.

* Make `addChatSession` method asynchronous and await its calls in chat store and sider component.

* Add `isValid` getter to auth store and use it for permission checks in admin, bot, chat, and snapshot views.

* Refactor snapshot view: remove unused imports, simplify variable names, and improve error handling.

* Add API token fetching function in `web/src/api/token.ts`

* Refactor bot view to use `fetchAPIToken` and improve variable naming.
  • Loading branch information
swuecho authored Sep 9, 2024
1 parent f7b443c commit 3e5a176
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 117 deletions.
10 changes: 10 additions & 0 deletions web/src/api/token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import request from '@/utils/request/axios'

export async function fetchAPIToken() {
try {
const response = await request.get('/token_10years')
return response.data
} catch (error) {
throw error
}
}
7 changes: 7 additions & 0 deletions web/src/store/modules/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ export const useAuthStore = defineStore('auth-store', {
expiresIn: getExpiresIn(),
}),

getters: {
isValid(): boolean {
return !!(this.token && this.expiresIn && this.expiresIn > Date.now() / 1000)
},
},

actions: {
getToken() {
return this.token
Expand All @@ -36,6 +42,7 @@ export const useAuthStore = defineStore('auth-store', {
this.expiresIn = undefined
removeExpiresIn()
},

},
})

Expand Down
75 changes: 37 additions & 38 deletions web/src/views/admin/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ const USER_ROUTE = 'AdminUser'
const MODEL_ROUTE = 'AdminModel'
const MODELRATELIMIT_ROUTUE = 'ModelRateLimit'
const needPermission = computed(() => !authStore.token) // || (!!authStore.token && authStore.expiresIn < Date.now() / 1000))
const needPermission = computed(() => !authStore.isValid)
const collapsed: Ref<boolean> = ref(false)
const activeKey = ref(currentRoute.name?.toString())
const getMobileClass = computed<CSSProperties>(() => {
if (isMobile.value) {
if (isMobile.value) {
return {
zIndex: 50,
}
Expand Down Expand Up @@ -94,40 +94,39 @@ function handleChatHome() {
</script>

<template>
<div class="h-full flex flex-col" :class="getMobileClass">
<header
class="sticky flex flex-shrink-0 items-center justify-between overflow-hidden h-14 z-30 border-b dark:border-neutral-800 bg-white/80 dark:bg-black/20 backdrop-blur">
<h1 v-if="isMobile"
class="flex-1 px-4 pr-6 overflow-hidden cursor-pointer select-none text-ellipsis whitespace-nowrap">
Admin
</h1>
<div v-if="isMobile" class="flex items-center">
<button class="flex items-center justify-center mr-5" @click="handleUpdateCollapsed">
<SvgIcon v-if="collapsed" class="text-2xl" icon="ri:align-justify" />
<SvgIcon v-else class="text-2xl" icon="ri:align-right" />
</button>
</div>
<h1 v-if="!isMobile"
class="flex-1 px-4 pr-6 overflow-hidden cursor-pointer select-none text-ellipsis whitespace-nowrap ml-16">
Admin
</h1>
<HoverButton @click="handleChatHome" class="mr-5">
<span class="text-xl text-[#4f555e] dark:text-white">
<SvgIcon icon="ic:baseline-home" />
</span>
</HoverButton>
</header>
<NLayout has-sider class="flex-1 overflow-y-auto">
<NLayoutSider bordered collapse-mode="width" :width="240" :collapsed="collapsed" :collapsed-width="isMobile ? 0 : 64"
:show-trigger="isMobile ? false : 'arrow-circle'" :style="getMobileClass" @collapse="collapsed = true"
@expand="collapsed = false">
<NMenu v-model:value="activeKey" :collapsed="collapsed" :collapsed-icon-size="22"
:options="menuOptions" />
</NLayoutSider>
<NLayout>
<router-view />
<Permission :visible="needPermission" />
</NLayout>
</NLayout>
</div>
<div class="h-full flex flex-col" :class="getMobileClass">
<header
class="sticky flex flex-shrink-0 items-center justify-between overflow-hidden h-14 z-30 border-b dark:border-neutral-800 bg-white/80 dark:bg-black/20 backdrop-blur">
<h1 v-if="isMobile"
class="flex-1 px-4 pr-6 overflow-hidden cursor-pointer select-none text-ellipsis whitespace-nowrap">
Admin
</h1>
<div v-if="isMobile" class="flex items-center">
<button class="flex items-center justify-center mr-5" @click="handleUpdateCollapsed">
<SvgIcon v-if="collapsed" class="text-2xl" icon="ri:align-justify" />
<SvgIcon v-else class="text-2xl" icon="ri:align-right" />
</button>
</div>
<h1 v-if="!isMobile"
class="flex-1 px-4 pr-6 overflow-hidden cursor-pointer select-none text-ellipsis whitespace-nowrap ml-16">
Admin
</h1>
<HoverButton @click="handleChatHome" class="mr-5">
<span class="text-xl text-[#4f555e] dark:text-white">
<SvgIcon icon="ic:baseline-home" />
</span>
</HoverButton>
</header>
<NLayout has-sider class="flex-1 overflow-y-auto">
<NLayoutSider bordered collapse-mode="width" :width="240" :collapsed="collapsed"
:collapsed-width="isMobile ? 0 : 64" :show-trigger="isMobile ? false : 'arrow-circle'" :style="getMobileClass"
@collapse="collapsed = true" @expand="collapsed = false">
<NMenu v-model:value="activeKey" :collapsed="collapsed" :collapsed-icon-size="22" :options="menuOptions" />
</NLayoutSider>
<NLayout>
<router-view />
<Permission :visible="needPermission" />
</NLayout>
</NLayout>
</div>
</template>
61 changes: 25 additions & 36 deletions web/src/views/bot/all.vue
Original file line number Diff line number Diff line change
@@ -1,33 +1,30 @@
<script setup lang="ts">
import { onMounted, ref, h } from 'vue'
import { computed, onMounted, ref, h } from 'vue'
import { NModal, useDialog, useMessage } from 'naive-ui'
import Search from '../snapshot/components/Search.vue'
import { fetchSnapshotAll, fetchSnapshotDelete } from '@/api'
import { HoverButton, SvgIcon } from '@/components/common'
import { generateAPIHelper, getBotPostLinks } from '@/service/snapshot'
import request from '@/utils/request/axios'
import { fetchAPIToken } from '@/api/token'
import { t } from '@/locales'
import { useAuthStore } from '@/store'
import Permission from '@/views/components/Permission.vue'
const authStore = useAuthStore()
const dialog = useDialog()
const nui_msg = useMessage()
const message = useMessage()
const search_visible = ref(false)
const searchVisible = ref(false)
const apiToken = ref('')
const needPermission = computed(() => !authStore.isValid)
const postsByYearMonth = ref<Record<string, Snapshot.PostLink[]>>({})
onMounted(async () => {
await refreshSnapshot()
try {
const response = await request.get('/token_10years')
if (response.status === 200) {
apiToken.value = response.data.accessToken
}
else {
nui_msg.error('Failed to fetch API token')
}
} catch (error) {
nui_msg.error('Error fetching API token')
}
const data = await fetchAPIToken()
apiToken.value = data.accessToken
})
Expand All @@ -37,52 +34,43 @@ async function refreshSnapshot() {
}
function handleDelete(post: Snapshot.PostLink) {
const dialogBox = dialog.warning({
dialog.warning({
title: t('chat_snapshot.deletePost'),
content: post.title,
positiveText: t('common.yes'),
negativeText: t('common.no'),
onPositiveClick: async () => {
try {
dialogBox.loading = true
await fetchSnapshotDelete(post.uuid)
await refreshSnapshot()
dialogBox.loading = false
nui_msg.success(t('chat_snapshot.deleteSuccess'))
Promise.resolve()
message.success(t('chat_snapshot.deleteSuccess'))
}
catch (error: any) {
nui_msg.error(t('chat_snapshot.deleteFailed'))
}
finally {
dialogBox.loading = false
message.error(t('chat_snapshot.deleteFailed'))
}
},
})
}
function handleShowCode(post: Snapshot.PostLink) {
const code = generateAPIHelper(post.uuid, apiToken.value, window.location.origin)
const dialogBox = dialog.info({
title: t('bot.showCode'),
content: () => h('code', { class: 'whitespace-pre-wrap' }, genAPIHelper(post)),
content: () => h('code', { class: 'whitespace-pre-wrap' }, code),
positiveText: t('common.copy'),
onPositiveClick: () => {
// copy to clipboard
navigator.clipboard.writeText(genAPIHelper(post))
navigator.clipboard.writeText(code)
dialogBox.loading = false
nui_msg.success(t('common.success'))
message.success(t('common.success'))
},
})
}
function post_url(uuid: string): string {
return `#/bot/${uuid}`
}
function genAPIHelper(post: Snapshot.PostLink) {
return generateAPIHelper(post.uuid, apiToken.value, window.location.origin)
function postUrl(uuid: string): string {
return `#/bot/${uuid}`
}
Expand All @@ -103,14 +91,15 @@ function genAPIHelper(post: Snapshot.PostLink) {
</h1>
</div>
<div class="mr-10">
<HoverButton @click="search_visible = true">
<HoverButton @click="searchVisible = true">
<SvgIcon icon="ic:round-search" class="text-2xl" />
</HoverButton>
<NModal v-model:show="search_visible" preset="dialog">
<NModal v-model:show="searchVisible" preset="dialog">
<Search />
</NModal>
</div>
</header>
<Permission :visible="needPermission" />
<div id="scrollRef" ref="scrollRef" class="h-full overflow-hidden overflow-y-auto">
<div class="max-w-screen-xl px-4 py-8 mx-auto">
<div v-for="[yearMonth, postsOfYearMonth] in Object.entries(postsByYearMonth)" :key="yearMonth"
Expand All @@ -132,7 +121,7 @@ function genAPIHelper(post: Snapshot.PostLink) {
<SvgIcon icon="ic:outline-code" />
</div>
</div>
<a :href="post_url(post.uuid)" :title="post.title"
<a :href="postUrl(post.uuid)" :title="post.title"
class="block text-xl font-semibold text-gray-900 hover:text-blue-600 mb-2">{{ post.title }}</a>
</div>
</li>
Expand Down
2 changes: 1 addition & 1 deletion web/src/views/chat/layout/Layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const { isMobile } = useBasicLayout()
const collapsed = computed(() => appStore.siderCollapsed)
// login modal will appear when there is no token
const needPermission = computed(() => !authStore.token) // || (!!authStore.token && authStore.expiresIn < Date.now() / 1000))
const needPermission = computed(() => !authStore.isValid)
const getMobileClass = computed(() => {
if (isMobile.value)
Expand Down
Loading

0 comments on commit 3e5a176

Please sign in to comment.