Add user registration with jingrow cloud integration
This commit is contained in:
parent
03d6b988e2
commit
d599021dd5
@ -10,6 +10,12 @@ const router = createRouter({
|
||||
component: () => import('../../views/auth/Login.vue'),
|
||||
meta: { requiresAuth: false }
|
||||
},
|
||||
{
|
||||
path: '/signup',
|
||||
name: 'Signup',
|
||||
component: () => import('../../views/auth/Signup.vue'),
|
||||
meta: { requiresAuth: false }
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
name: 'AppLayout',
|
||||
@ -250,7 +256,7 @@ router.beforeEach(async (to, _from, next) => {
|
||||
|
||||
if (to.meta.requiresAuth && !authStore.isLoggedIn) {
|
||||
next('/login')
|
||||
} else if (to.path === '/login' && authStore.isLoggedIn) {
|
||||
} else if ((to.path === '/login' || to.path === '/signup') && authStore.isLoggedIn) {
|
||||
next('/')
|
||||
} else {
|
||||
next()
|
||||
|
||||
@ -28,13 +28,29 @@
|
||||
"Username": "用户名",
|
||||
"Password": "密码",
|
||||
"Login": "登录",
|
||||
"Sign up": "注册",
|
||||
"Connect to Jingrow SaaS platform": "连接到 Jingrow SaaS 平台",
|
||||
"Please enter username": "请输入用户名",
|
||||
"Please enter password": "请输入密码",
|
||||
"Password must be at least 6 characters": "密码长度不能少于6位",
|
||||
"Username must be at least 3 characters": "用户名至少需要3个字符",
|
||||
"Login successful": "登录成功",
|
||||
"Login failed": "登录失败",
|
||||
"Login failed, please check username and password": "登录失败,请检查用户名和密码",
|
||||
"Create your account": "创建您的账户",
|
||||
"Confirm Password": "确认密码",
|
||||
"Please confirm password": "请确认密码",
|
||||
"Passwords do not match": "两次输入的密码不一致",
|
||||
"Email (Optional)": "邮箱(可选)",
|
||||
"Phone Number": "手机号",
|
||||
"Phone Number (Optional)": "手机号(可选)",
|
||||
"Please enter a valid email address": "请输入有效的邮箱地址",
|
||||
"Please enter phone number": "请输入手机号",
|
||||
"Please enter a valid phone number": "请输入有效的手机号码",
|
||||
"Sign up successful": "注册成功",
|
||||
"Sign up failed": "注册失败",
|
||||
"Sign up failed, please try again": "注册失败,请重试",
|
||||
"Already have an account?": "已有账户?",
|
||||
"System and personal settings": "系统配置和个人设置",
|
||||
"Personal Settings": "个人设置",
|
||||
"Email": "邮箱",
|
||||
|
||||
@ -110,6 +110,84 @@ export const logoutApi = async (): Promise<void> => {
|
||||
}
|
||||
}
|
||||
|
||||
// 注册接口
|
||||
export interface SignupRequest {
|
||||
username: string
|
||||
password: string
|
||||
email?: string
|
||||
phone_number?: string
|
||||
}
|
||||
|
||||
export interface SignupResponse {
|
||||
success: boolean
|
||||
message?: string
|
||||
error?: string
|
||||
user?: UserInfo
|
||||
}
|
||||
|
||||
export const signupApi = async (data: SignupRequest): Promise<SignupResponse> => {
|
||||
try {
|
||||
const response = await fetch(`/jingrow/signup`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
|
||||
// 先克隆响应,以便可以多次读取(如果需要)
|
||||
const responseClone = response.clone()
|
||||
|
||||
let result: any = {}
|
||||
|
||||
// 尝试解析响应体
|
||||
try {
|
||||
result = await response.json()
|
||||
} catch (e) {
|
||||
// 如果JSON解析失败,尝试读取文本
|
||||
try {
|
||||
const text = await responseClone.text()
|
||||
return {
|
||||
success: false,
|
||||
error: text || `注册请求失败 (HTTP ${response.status})`
|
||||
}
|
||||
} catch (textError) {
|
||||
return {
|
||||
success: false,
|
||||
error: `注册请求失败 (HTTP ${response.status})`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果响应不成功,提取错误消息
|
||||
if (!response.ok) {
|
||||
// FastAPI HTTPException 返回格式: {"detail": "错误消息"}
|
||||
const errorMsg = result.detail || `注册请求失败 (HTTP ${response.status})`
|
||||
return { success: false, error: errorMsg }
|
||||
}
|
||||
|
||||
// 检查业务逻辑错误(success 为 false)
|
||||
if (result.success === false) {
|
||||
const errorMsg = result.error || result.message || '注册失败'
|
||||
return { success: false, error: errorMsg }
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: result.message || '注册成功',
|
||||
user: result.user || undefined
|
||||
}
|
||||
} catch (error: any) {
|
||||
// 处理网络错误或其他异常
|
||||
return {
|
||||
success: false,
|
||||
error: error.message || '网络错误,请检查网络连接后重试'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 仅使用会话Cookie的最小鉴权头部(不影响现有API Key逻辑)
|
||||
export function get_session_api_headers() {
|
||||
return {
|
||||
|
||||
@ -12,7 +12,8 @@
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
size="large"
|
||||
size="medium"
|
||||
:show-label="false"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<n-form-item path="username">
|
||||
@ -48,14 +49,18 @@
|
||||
block
|
||||
:loading="loading"
|
||||
@click="handleLogin"
|
||||
class="brand-button"
|
||||
>
|
||||
{{ t('Login') }}
|
||||
</n-button>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
<div class="login-footer">
|
||||
<div class="login-footer" v-if="showSignupLink">
|
||||
<n-text depth="3">
|
||||
<router-link to="/signup" class="signup-link">
|
||||
{{ t('Sign up') }}
|
||||
</router-link>
|
||||
</n-text>
|
||||
</div>
|
||||
</div>
|
||||
@ -76,6 +81,7 @@ const authStore = useAuthStore()
|
||||
|
||||
const formRef = ref()
|
||||
const loading = ref(false)
|
||||
const showSignupLink = ref(false)
|
||||
|
||||
const formData = reactive({
|
||||
username: '',
|
||||
@ -123,6 +129,20 @@ onMounted(async () => {
|
||||
// 如果已经登录,直接跳转
|
||||
if (authStore.isLoggedIn) {
|
||||
router.push('/')
|
||||
return
|
||||
}
|
||||
|
||||
// 检查服务器配置,判断是否显示注册链接
|
||||
try {
|
||||
const response = await fetch('/jingrow/server-config')
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
if (data.success && data.jingrow_server_url === 'https://cloud.jingrow.com') {
|
||||
showSignupLink.value = true
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to get server config:', error)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@ -139,7 +159,7 @@ onMounted(async () => {
|
||||
|
||||
.login-card {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
max-width: 480px;
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 40px;
|
||||
@ -148,7 +168,26 @@ onMounted(async () => {
|
||||
|
||||
.login-header {
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
:deep(.n-form-item) {
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
:deep(.n-form-item:last-child) {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
:deep(.n-form-item:not(.n-form-item--error) .n-form-item__feedback-wrapper) {
|
||||
min-height: 0 !important;
|
||||
margin-top: 0 !important;
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
:deep(.n-form-item--error .n-form-item__feedback-wrapper) {
|
||||
margin-top: 4px !important;
|
||||
min-height: auto !important;
|
||||
}
|
||||
|
||||
.logo {
|
||||
@ -172,4 +211,31 @@ onMounted(async () => {
|
||||
text-align: center;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.signup-link {
|
||||
color: #18a058;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.signup-link:hover {
|
||||
color: #36ad6a;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
:deep(.brand-button) {
|
||||
background-color: #18a058 !important;
|
||||
border-color: #18a058 !important;
|
||||
}
|
||||
|
||||
:deep(.brand-button:hover) {
|
||||
background-color: #36ad6a !important;
|
||||
border-color: #36ad6a !important;
|
||||
}
|
||||
|
||||
:deep(.brand-button:focus) {
|
||||
background-color: #18a058 !important;
|
||||
border-color: #18a058 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
333
apps/jingrow/frontend/src/views/auth/Signup.vue
Normal file
333
apps/jingrow/frontend/src/views/auth/Signup.vue
Normal file
@ -0,0 +1,333 @@
|
||||
<template>
|
||||
<div class="signup-container">
|
||||
<div class="signup-card">
|
||||
<div class="signup-header">
|
||||
<div class="logo">
|
||||
<img src="/logo.svg" :alt="appName" width="48" height="48" />
|
||||
</div>
|
||||
<h1 class="title">{{ appName }}</h1>
|
||||
</div>
|
||||
|
||||
<n-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
size="medium"
|
||||
:show-label="false"
|
||||
@keyup.enter="handleSignup"
|
||||
>
|
||||
<n-form-item path="username">
|
||||
<n-input
|
||||
v-model:value="formData.username"
|
||||
:placeholder="t('Username')"
|
||||
:input-props="{ autocomplete: 'username' }"
|
||||
>
|
||||
<template #prefix>
|
||||
<Icon icon="tabler:user" />
|
||||
</template>
|
||||
</n-input>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item path="password">
|
||||
<n-input
|
||||
v-model:value="formData.password"
|
||||
type="password"
|
||||
:placeholder="t('Password')"
|
||||
:input-props="{ autocomplete: 'new-password' }"
|
||||
show-password-on="click"
|
||||
>
|
||||
<template #prefix>
|
||||
<Icon icon="tabler:lock" />
|
||||
</template>
|
||||
</n-input>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item path="confirmPassword">
|
||||
<n-input
|
||||
v-model:value="formData.confirmPassword"
|
||||
type="password"
|
||||
:placeholder="t('Confirm Password')"
|
||||
:input-props="{ autocomplete: 'new-password' }"
|
||||
show-password-on="click"
|
||||
>
|
||||
<template #prefix>
|
||||
<Icon icon="tabler:lock" />
|
||||
</template>
|
||||
</n-input>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item path="email">
|
||||
<n-input
|
||||
v-model:value="formData.email"
|
||||
:placeholder="t('Email (Optional)')"
|
||||
:input-props="{ autocomplete: 'email', type: 'email' }"
|
||||
>
|
||||
<template #prefix>
|
||||
<Icon icon="tabler:mail" />
|
||||
</template>
|
||||
</n-input>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item path="phoneNumber">
|
||||
<n-input
|
||||
v-model:value="formData.phoneNumber"
|
||||
:placeholder="t('Phone Number')"
|
||||
:input-props="{ autocomplete: 'tel' }"
|
||||
>
|
||||
<template #prefix>
|
||||
<Icon icon="tabler:phone" />
|
||||
</template>
|
||||
</n-input>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item>
|
||||
<n-button
|
||||
type="primary"
|
||||
size="medium"
|
||||
block
|
||||
:loading="loading"
|
||||
@click="handleSignup"
|
||||
class="brand-button"
|
||||
>
|
||||
{{ t('Sign up') }}
|
||||
</n-button>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
<div class="signup-footer">
|
||||
<n-text depth="3">
|
||||
{{ t('Already have an account?') }}
|
||||
<router-link to="/login" class="login-link">
|
||||
{{ t('Login') }}
|
||||
</router-link>
|
||||
</n-text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { NForm, NFormItem, NInput, NButton, NText, useMessage } from 'naive-ui'
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { useAuthStore } from '../../shared/stores/auth'
|
||||
import { t } from '../../shared/i18n'
|
||||
import { signupApi } from '../../shared/api/auth'
|
||||
|
||||
const router = useRouter()
|
||||
const message = useMessage()
|
||||
const authStore = useAuthStore()
|
||||
|
||||
const formRef = ref()
|
||||
const loading = ref(false)
|
||||
|
||||
const formData = reactive({
|
||||
username: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
email: '',
|
||||
phoneNumber: ''
|
||||
})
|
||||
|
||||
const validatePasswordMatch = (_rule: any, value: string) => {
|
||||
if (value !== formData.password) {
|
||||
return new Error(t('Passwords do not match'))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const rules = {
|
||||
username: [
|
||||
{ required: true, message: t('Please enter username'), trigger: 'blur' },
|
||||
{ min: 3, message: t('Username must be at least 3 characters'), trigger: 'blur' }
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: t('Please enter password'), trigger: 'blur' },
|
||||
{ min: 6, message: t('Password must be at least 6 characters'), trigger: 'blur' }
|
||||
],
|
||||
confirmPassword: [
|
||||
{ required: true, message: t('Please confirm password'), trigger: 'blur' },
|
||||
{ validator: validatePasswordMatch, trigger: 'blur' }
|
||||
],
|
||||
email: [
|
||||
{
|
||||
validator: (_rule: any, value: string) => {
|
||||
if (!value) return true
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
||||
if (!emailRegex.test(value)) {
|
||||
return new Error(t('Please enter a valid email address'))
|
||||
}
|
||||
return true
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
phoneNumber: [
|
||||
{ required: true, message: t('Please enter phone number'), trigger: 'blur' },
|
||||
{
|
||||
pattern: /^1[3-9]\d{9}$/,
|
||||
message: t('Please enter a valid phone number'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const handleSignup = async () => {
|
||||
try {
|
||||
await formRef.value?.validate()
|
||||
loading.value = true
|
||||
|
||||
const result = await signupApi({
|
||||
username: formData.username,
|
||||
password: formData.password,
|
||||
email: formData.email || undefined,
|
||||
phone_number: formData.phoneNumber
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
message.success(t('Sign up successful'))
|
||||
if (result.user) {
|
||||
authStore.user = result.user
|
||||
authStore.isAuthenticated = true
|
||||
localStorage.setItem('jingrow_user', JSON.stringify(result.user))
|
||||
localStorage.setItem('jingrow_authenticated', 'true')
|
||||
router.push('/')
|
||||
} else {
|
||||
const loginResult = await authStore.login(formData.username, formData.password)
|
||||
if (loginResult.success) {
|
||||
router.push('/')
|
||||
} else {
|
||||
message.warning(loginResult.error || t('注册成功,但自动登录失败,请手动登录'))
|
||||
router.push('/login')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const errorMsg = result.error || t('Sign up failed')
|
||||
console.error('注册失败:', errorMsg, result)
|
||||
message.error(errorMsg)
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('注册异常:', error)
|
||||
message.error(error.message || t('Sign up failed, please try again'))
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const appName = computed(() => localStorage.getItem('appName') || 'Jingrow')
|
||||
|
||||
onMounted(async () => {
|
||||
// 初始化认证状态
|
||||
await authStore.initAuth()
|
||||
|
||||
// 如果已经登录,直接跳转
|
||||
if (authStore.isLoggedIn) {
|
||||
router.push('/')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.signup-container {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f5f5f5;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.signup-card {
|
||||
width: 100%;
|
||||
max-width: 480px;
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 32px;
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
||||
max-height: calc(100vh - 40px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.signup-header {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
:deep(.n-form-item) {
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
:deep(.n-form-item:last-child) {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/* 只在有错误时才显示反馈区域,减少默认间距 */
|
||||
:deep(.n-form-item:not(.n-form-item--error) .n-form-item__feedback-wrapper) {
|
||||
min-height: 0 !important;
|
||||
margin-top: 0 !important;
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
:deep(.n-form-item--error .n-form-item__feedback-wrapper) {
|
||||
margin-top: 4px !important;
|
||||
min-height: auto !important;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.logo img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: #1f2937;
|
||||
margin: 0 0 6px 0;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 14px;
|
||||
color: #6b7280;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.signup-footer {
|
||||
text-align: center;
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.login-link {
|
||||
color: #18a058;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
margin-left: 4px;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.login-link:hover {
|
||||
color: #36ad6a;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
:deep(.brand-button) {
|
||||
background-color: #18a058 !important;
|
||||
border-color: #18a058 !important;
|
||||
}
|
||||
|
||||
:deep(.brand-button:hover) {
|
||||
background-color: #36ad6a !important;
|
||||
border-color: #36ad6a !important;
|
||||
}
|
||||
|
||||
:deep(.brand-button:focus) {
|
||||
background-color: #18a058 !important;
|
||||
border-color: #18a058 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -4,7 +4,8 @@ from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
import logging
|
||||
|
||||
from jingrow.utils.auth import login, logout, get_user_info, set_context
|
||||
from jingrow.utils.auth import login, logout, get_user_info, set_context, get_jingrow_cloud_url, get_jingrow_cloud_api_headers
|
||||
from jingrow.config import Config
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
@ -13,6 +14,18 @@ class LoginRequest(BaseModel):
|
||||
username: str
|
||||
password: str
|
||||
|
||||
class SignupRequest(BaseModel):
|
||||
username: str
|
||||
password: str
|
||||
email: Optional[str] = None
|
||||
phone_number: Optional[str] = None
|
||||
|
||||
class SignupResponse(BaseModel):
|
||||
success: bool
|
||||
message: str
|
||||
user: Optional[dict] = None
|
||||
session_cookie: Optional[str] = None
|
||||
|
||||
class LoginResponse(BaseModel):
|
||||
success: bool
|
||||
message: str
|
||||
@ -28,16 +41,14 @@ class UserInfoResponse(BaseModel):
|
||||
user_info: Optional[dict] = None
|
||||
message: Optional[str] = None
|
||||
|
||||
# Cookie配置常量
|
||||
COOKIE_CONFIG = {
|
||||
"httponly": True,
|
||||
"samesite": "lax",
|
||||
"secure": False, # 开发环境可以设为False,生产环境建议设为True
|
||||
"secure": False,
|
||||
"path": "/",
|
||||
"max_age": 7 * 24 * 60 * 60 # 7天过期时间(秒)
|
||||
"max_age": 7 * 24 * 60 * 60
|
||||
}
|
||||
|
||||
# 需要清除的cookie列表
|
||||
COOKIES_TO_CLEAR = ["sid", "user_id", "user_image", "full_name", "system_user"]
|
||||
|
||||
def get_session_cookie(request: Request) -> Optional[str]:
|
||||
@ -69,7 +80,7 @@ def create_response_clear_cookies(data: dict) -> JSONResponse:
|
||||
for cookie_name in COOKIES_TO_CLEAR:
|
||||
cookie_kwargs = COOKIE_CONFIG.copy()
|
||||
if cookie_name == "sid":
|
||||
cookie_kwargs.pop("secure", None) # delete_cookie不需要secure参数
|
||||
cookie_kwargs.pop("secure", None)
|
||||
response.delete_cookie(key=cookie_name, **cookie_kwargs)
|
||||
return response
|
||||
|
||||
@ -111,6 +122,78 @@ async def logout_route(session_cookie: Optional[str] = Depends(get_session_cooki
|
||||
logger.error(f"登出异常: {str(e)}", exc_info=True)
|
||||
raise HTTPException(status_code=500, detail=f"登出异常: {str(e)}")
|
||||
|
||||
@router.post("/jingrow/signup", response_model=SignupResponse)
|
||||
async def signup_route(signup_data: SignupRequest):
|
||||
"""注册路由"""
|
||||
import requests
|
||||
|
||||
try:
|
||||
url = f"{get_jingrow_cloud_url()}/api/action/jcloud.api.account.signup_with_username"
|
||||
data = {"username": signup_data.username, "password": signup_data.password}
|
||||
if signup_data.email:
|
||||
data["email"] = signup_data.email
|
||||
if signup_data.phone_number:
|
||||
data["phone_number"] = signup_data.phone_number
|
||||
|
||||
response = requests.post(url, headers=get_jingrow_cloud_api_headers(), json=data, timeout=30)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise HTTPException(status_code=400, detail=f"注册请求失败 (HTTP {response.status_code})")
|
||||
|
||||
try:
|
||||
result = response.json()
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=400, detail="注册失败:无法解析服务器响应")
|
||||
|
||||
message_obj = result.get("message")
|
||||
if not isinstance(message_obj, dict):
|
||||
raise HTTPException(status_code=400, detail="注册失败:服务器响应格式错误")
|
||||
|
||||
success_value = message_obj.get("success")
|
||||
success_message = message_obj.get("message", "注册成功")
|
||||
|
||||
if success_value is False:
|
||||
raise HTTPException(status_code=400, detail=success_message)
|
||||
|
||||
session_cookie = None
|
||||
user_info = None
|
||||
|
||||
try:
|
||||
login_result = login(signup_data.username, signup_data.password)
|
||||
if login_result.get("success"):
|
||||
session_cookie = login_result.get("session_cookie")
|
||||
if session_cookie:
|
||||
user_info_result = get_user_info(session_cookie)
|
||||
if user_info_result.get("success"):
|
||||
user_info = user_info_result.get("user_info")
|
||||
else:
|
||||
pass
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
response_data = {
|
||||
"success": True,
|
||||
"message": success_message,
|
||||
"user": user_info
|
||||
}
|
||||
|
||||
if session_cookie:
|
||||
return create_response_with_cookie(response_data, session_cookie)
|
||||
else:
|
||||
return JSONResponse(content=response_data)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"注册异常: {str(e)}", exc_info=True)
|
||||
raise HTTPException(status_code=500, detail=f"注册异常: {str(e)}")
|
||||
|
||||
@router.get("/jingrow/server-config")
|
||||
async def get_server_config():
|
||||
return {
|
||||
"success": True,
|
||||
"jingrow_server_url": Config.jingrow_server_url
|
||||
}
|
||||
|
||||
@router.get("/jingrow/user-info", response_model=UserInfoResponse)
|
||||
async def get_user_info_route(session_cookie: Optional[str] = Depends(get_session_cookie)):
|
||||
"""获取用户信息路由"""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user