Skip to content

Commit 0c2cef6

Browse files
author
Kerwin
committed
chore: set user role
fix: register failed (Close #160)
1 parent ebd5df8 commit 0c2cef6

File tree

17 files changed

+216
-65
lines changed

17 files changed

+216
-65
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,11 +417,11 @@ A: 一种可能原因是经过 Nginx 反向代理,开启了 buffer,则 Nginx
417417

418418
<div style="display: flex; gap: 20px;">
419419
<div style="text-align: center">
420-
<img style="max-width: 100%" src="./docs/wechat.png" alt="微信" />
420+
<img style="max-width: 200px" src="./docs/wechat.png" alt="微信" />
421421
<p>WeChat Pay</p>
422422
</div>
423423
<div style="text-align: center">
424-
<img style="max-width: 100%" src="./docs/alipay.png" alt="支付宝" />
424+
<img style="max-width: 200px" src="./docs/alipay.png" alt="支付宝" />
425425
<p>Alipay</p>
426426
</div>
427427
</div>

service/src/index.ts

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import { ObjectId } from 'mongodb'
55
import type { RequestProps } from './types'
66
import type { ChatContext, ChatMessage } from './chatgpt'
77
import { chatConfig, chatReplyProcess, containsSensitiveWords, getRandomApiKey, initAuditService } from './chatgpt'
8-
import { auth } from './middleware/auth'
9-
import { clearConfigCache, getApiKeys, getCacheConfig, getOriginConfig } from './storage/config'
8+
import { auth, getUserId } from './middleware/auth'
9+
import { clearApiKeyCache, clearConfigCache, getApiKeys, getCacheApiKeys, getCacheConfig, getOriginConfig } from './storage/config'
1010
import type { AuditConfig, CHATMODEL, ChatInfo, ChatOptions, Config, KeyConfig, MailConfig, SiteConfig, UsageResponse, UserInfo } from './storage/model'
11-
import { Status, UserRole } from './storage/model'
11+
import { Status, UserRole, chatModelOptions } from './storage/model'
1212
import {
1313
clearChat,
1414
createChatRoom,
@@ -36,12 +36,13 @@ import {
3636
updateUserChatModel,
3737
updateUserInfo,
3838
updateUserPassword,
39+
updateUserRole,
3940
updateUserStatus,
4041
upsertKey,
4142
verifyUser,
4243
} from './storage/mongo'
4344
import { limiter } from './middleware/limiter'
44-
import { isEmail, isNotEmptyString } from './utils/is'
45+
import { hasAnyRole, isEmail, isNotEmptyString } from './utils/is'
4546
import { sendNoticeMail, sendResetPasswordMail, sendTestMail, sendVerifyMail, sendVerifyMailAdmin } from './utils/mail'
4647
import { checkUserResetPassword, checkUserVerify, checkUserVerifyAdmin, getUserResetPasswordUrl, getUserVerifyUrl, getUserVerifyUrlAdmin, md5 } from './utils/security'
4748
import { rootAuth } from './middleware/rootAuth'
@@ -558,8 +559,51 @@ router.post('/session', async (req, res) => {
558559
const allowRegister = (await getCacheConfig()).siteConfig.registerEnabled
559560
if (config.apiModel !== 'ChatGPTAPI' && config.apiModel !== 'ChatGPTUnofficialProxyAPI')
560561
config.apiModel = 'ChatGPTAPI'
562+
const userId = await getUserId(req)
563+
const chatModels: {
564+
label
565+
key: string
566+
value: string
567+
}[] = []
568+
if (userId != null) {
569+
const user = await getUserById(userId)
570+
const keys = (await getCacheApiKeys()).filter(d => hasAnyRole(d.userRoles, user.roles))
571+
572+
const count: { key: string; count: number }[] = []
573+
chatModelOptions.forEach((chatModel) => {
574+
keys.forEach((key) => {
575+
if (key.chatModels.includes(chatModel.value)) {
576+
if (count.filter(d => d.key === chatModel.value).length <= 0) {
577+
count.push({ key: chatModel.value, count: 1 })
578+
}
579+
else {
580+
const thisCount = count.filter(d => d.key === chatModel.value)[0]
581+
thisCount.count++
582+
}
583+
}
584+
})
585+
})
586+
count.forEach((c) => {
587+
const thisChatModel = chatModelOptions.filter(d => d.value === c.key)[0]
588+
chatModels.push({
589+
label: `${thisChatModel.label} (${c.count})`,
590+
key: c.key,
591+
value: c.key,
592+
})
593+
})
594+
}
561595

562-
res.send({ status: 'Success', message: '', data: { auth: hasAuth, allowRegister, model: config.apiModel, title: config.siteConfig.siteTitle } })
596+
res.send({
597+
status: 'Success',
598+
message: '',
599+
data: {
600+
auth: hasAuth,
601+
allowRegister,
602+
model: config.apiModel,
603+
title: config.siteConfig.siteTitle,
604+
chatModels,
605+
},
606+
})
563607
}
564608
catch (error) {
565609
res.send({ status: 'Fail', message: error.message, data: null })
@@ -693,6 +737,17 @@ router.post('/user-status', rootAuth, async (req, res) => {
693737
}
694738
})
695739

740+
router.post('/user-role', rootAuth, async (req, res) => {
741+
try {
742+
const { userId, roles } = req.body as { userId: string; roles: UserRole[] }
743+
await updateUserRole(userId, roles)
744+
res.send({ status: 'Success', message: '更新成功 | Update successfully' })
745+
}
746+
catch (error) {
747+
res.send({ status: 'Fail', message: error.message, data: null })
748+
}
749+
})
750+
696751
router.post('/verify', async (req, res) => {
697752
try {
698753
const { token } = req.body as { token: string }
@@ -873,6 +928,7 @@ router.post('/setting-key-upsert', rootAuth, async (req, res) => {
873928
if (keyConfig._id !== undefined)
874929
keyConfig._id = new ObjectId(keyConfig._id)
875930
await upsertKey(keyConfig)
931+
clearApiKeyCache()
876932
res.send({ status: 'Success', message: '成功 | Successfully' })
877933
}
878934
catch (error) {

service/src/middleware/auth.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import jwt from 'jsonwebtoken'
2+
import type { Request } from 'express'
23
import { getCacheConfig } from '../storage/config'
34
import { getUserById } from '../storage/mongo'
45
import { Status } from '../storage/model'
@@ -27,4 +28,17 @@ const auth = async (req, res, next) => {
2728
}
2829
}
2930

30-
export { auth }
31+
async function getUserId(req: Request): Promise<string | undefined> {
32+
try {
33+
const token = req.header('Authorization').replace('Bearer ', '')
34+
const config = await getCacheConfig()
35+
const info = jwt.verify(token, config.siteConfig.loginSalt.trim())
36+
return info.userId
37+
}
38+
catch (error) {
39+
40+
}
41+
return null
42+
}
43+
44+
export { auth, getUserId }

service/src/storage/config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ export async function getCacheApiKeys(): Promise<KeyConfig[]> {
133133
return Promise.resolve(apiKeysCachedConfig)
134134
}
135135

136+
export function clearApiKeyCache() {
137+
apiKeysCacheExpiration = 0
138+
getCacheApiKeys()
139+
}
140+
136141
export async function getApiKeys() {
137142
const result = await getKeys()
138143
if (result.keys.length <= 0) {

service/src/storage/model.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,27 @@ export const CHATMODELS: CHATMODEL[] = [
6161
'gpt-4-browsing',
6262
]
6363

64+
export const chatModelOptions = [
65+
'gpt-3.5-turbo',
66+
'gpt-3.5-turbo-0301',
67+
'gpt-4',
68+
'gpt-4-0314',
69+
'gpt-4-32k',
70+
'gpt-4-32k-0314',
71+
'text-davinci-002-render-sha-mobile',
72+
'gpt-4-mobile',
73+
'gpt-4-browsing',
74+
].map((model: string) => {
75+
let label = model
76+
if (model === 'text-davinci-002-render-sha-mobile')
77+
label = 'gpt-3.5-mobile'
78+
return {
79+
label,
80+
key: model,
81+
value: model,
82+
}
83+
})
84+
6485
export class ChatRoom {
6586
_id: ObjectId
6687
roomId: number

service/src/storage/mongo.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ export async function getUserById(userId: string): Promise<UserInfo> {
232232
}
233233

234234
function initUserInfo(userInfo: UserInfo) {
235+
if (userInfo == null)
236+
return
235237
if (userInfo.config == null)
236238
userInfo.config = new UserConfig()
237239
if (userInfo.config.chatModel == null)
@@ -252,6 +254,10 @@ export async function updateUserStatus(userId: string, status: Status) {
252254
return await userCol.updateOne({ _id: new ObjectId(userId) }, { $set: { status, verifyTime: new Date().toLocaleString() } })
253255
}
254256

257+
export async function updateUserRole(userId: string, roles: UserRole[]) {
258+
return await userCol.updateOne({ _id: new ObjectId(userId) }, { $set: { roles, verifyTime: new Date().toLocaleString() } })
259+
}
260+
255261
export async function getConfig(): Promise<Config> {
256262
return await configCol.findOne() as Config
257263
}

service/src/utils/is.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export function isTextAudioType(value: any): value is TextAudioType {
3838
|| value === TextAudioType.All
3939
)
4040
}
41+
4142
export function hasAnyRole(userRoles: UserRole[] | undefined, roles: UserRole[]): boolean {
4243
if (!userRoles || userRoles.length === 0 || !roles || roles.length === 0)
4344
return false

src/api/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { AxiosProgressEvent, GenericAbortSignal } from 'axios'
22
import { get, post } from '@/utils/request'
3-
import type { AuditConfig, CHATMODEL, ConfigState, KeyConfig, MailConfig, SiteConfig, Status } from '@/components/common/Setting/model'
3+
import type { AuditConfig, CHATMODEL, ConfigState, KeyConfig, MailConfig, SiteConfig, Status, UserRole } from '@/components/common/Setting/model'
44
import { useAuthStore, useSettingStore } from '@/store'
55

66
export function fetchChatAPI<T = any>(
@@ -142,6 +142,13 @@ export function fetchUpdateUserStatus<T = any>(userId: string, status: Status) {
142142
})
143143
}
144144

145+
export function fetchUpdateUserRole<T = any>(userId: string, roles: UserRole[]) {
146+
return post<T>({
147+
url: '/user-role',
148+
data: { userId, roles },
149+
})
150+
}
151+
145152
export function fetchGetChatRooms<T = any>() {
146153
return get<T>({
147154
url: '/chatrooms',

src/components/common/Setting/Keys.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
import { h, onMounted, reactive, ref } from 'vue'
33
import { NButton, NDataTable, NInput, NModal, NSelect, NSpace, NSwitch, NTag, useDialog, useMessage } from 'naive-ui'
44
import type { CHATMODEL } from './model'
5-
import { KeyConfig, Status, UserRole, apiModelOptions, chatModelOptions, userRoleOptions } from './model'
5+
import { KeyConfig, Status, UserRole, apiModelOptions, userRoleOptions } from './model'
66
import { fetchGetKeys, fetchUpdateApiKeyStatus, fetchUpsertApiKey } from '@/api'
77
import { t } from '@/locales'
8+
import { useAuthStore } from '@/store'
89
910
const ms = useMessage()
1011
const dialog = useDialog()
12+
const authStore = useAuthStore()
1113
const loading = ref(false)
1214
const show = ref(false)
1315
const handleSaving = ref(false)
@@ -254,7 +256,7 @@ onMounted(async () => {
254256
style="width: 100%"
255257
multiple
256258
:value="keyConfig.chatModels"
257-
:options="chatModelOptions"
259+
:options="authStore.session?.chatModels"
258260
@update-value="value => keyConfig.chatModels = value"
259261
/>
260262
</div>

0 commit comments

Comments
 (0)