Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
/node_modules
/public/dll
/public/downloads
/public/assets
.idea
.vscode
/log
/app/config/webpack-assets.json
/app/config/webpack-assets.json
package-lock.json
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
12
150 changes: 138 additions & 12 deletions app/controllers/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@ const cacheControl = (ctx) => {
}

const renderLandingPage = async (ctx) => {
const clientId = await network.github.getVerify()
let clientId = null
let loginLink = '#'
try {
clientId = await network.github.getVerify()
loginLink = `https://github.com/login/oauth/authorize?scope=user:email&client_id=${clientId}`
} catch (error) {
logger.warn(`[GitHub Service] Service unavailable: ${error.message}`)
// Fallback for local development without GitHub service
loginLink = '#github-service-unavailable'
}

cacheControl(ctx)
const loginLink = `https://github.com/login/oauth/authorize?scope=user:email&client_id=${clientId}`
logger.info(`[LoginLink] ${loginLink}`)

const { messageCode, messageType } = ctx.request.query
Expand All @@ -28,6 +36,31 @@ const renderLandingPage = async (ctx) => {
})
}

const renderSignupPage = async (ctx) => {
let clientId = null
let loginLink = '#'
try {
clientId = await network.github.getVerify()
loginLink = `https://github.com/login/oauth/authorize?scope=user:email&client_id=${clientId}`
} catch (error) {
logger.warn(`[GitHub Service] Service unavailable: ${error.message}`)
// Fallback for local development without GitHub service
loginLink = '#github-service-unavailable'
}

cacheControl(ctx)
logger.info(`[LoginLink] ${loginLink}`)

const { messageCode, messageType } = ctx.request.query

await ctx.render('user/signup', {
loginLink,
messageCode,
messageType,
title: ctx.__('signupPage.title')
})
}

const render500Page = async (ctx) => {
cacheControl(ctx)
await ctx.render('error/500', {
Expand Down Expand Up @@ -103,15 +136,45 @@ const combineStat = stats => stats.reduce((pre, cur) => {
}, {})

const statistic = async (ctx) => {
const [
users,
githubFields,
resumeFields
] = await Promise.all([
network.user.getUserCount(),
network.stat.getStat({ type: 'github' }),
network.stat.getStat({ type: 'resume' })
])
let users = 0
let githubFields = []
let resumeFields = []

try {
const [
usersResult,
githubResult,
resumeResult
] = await Promise.all([
network.user.getUserCount().catch(() => {
logger.warn('User service not available, using mock data')
return 1234
}),
network.stat.getStat({ type: 'github' }).catch(() => {
logger.warn('Stat service not available for github, using mock data')
return [
{ action: 'pageview', count: 5678 },
{ action: 'share', count: 234 }
]
}),
network.stat.getStat({ type: 'resume' }).catch(() => {
logger.warn('Stat service not available for resume, using mock data')
return [
{ action: 'pageview', count: 3456 },
{ action: 'download', count: 567 }
]
})
])

users = usersResult
githubFields = githubResult
resumeFields = resumeResult
} catch (error) {
logger.error('Error fetching statistics, using fallback data:', error.message)
users = 1234
githubFields = [{ action: 'pageview', count: 5678 }]
resumeFields = [{ action: 'pageview', count: 3456 }]
}

const github = combineStat(githubFields || [])
const resume = combineStat(resumeFields || [])
Expand Down Expand Up @@ -175,6 +238,64 @@ const getIcon = async (ctx, next) => {
await next()
}

/* ===================== Email Authentication Pages ===================== */

const renderForgotPasswordPage = async (ctx) => {
const { messageCode, messageType } = ctx.request.query

cacheControl(ctx)
await ctx.render('user/forgot-password', {
messageCode,
messageType,
title: ctx.__('forgotPasswordPage.title')
})
}

const renderResetPasswordPage = async (ctx) => {
const { token } = ctx.request.query
const { messageCode, messageType } = ctx.request.query

cacheControl(ctx)
await ctx.render('user/reset-password', {
token,
messageCode,
messageType,
title: ctx.__('resetPasswordPage.title')
})
}

const renderVerifyEmailPage = async (ctx) => {
const { token } = ctx.request.query
if (!token) {
cacheControl(ctx)
await ctx.render('user/verify-email', {
success: false,
message: '验证链接无效',
title: ctx.__('verifyEmailPage.title')
})
return
}

try {
// 调用验证API
const result = await network.user.verifyEmail({ token })
cacheControl(ctx)
await ctx.render('user/verify-email', {
success: result.success,
message: result.message,
title: ctx.__('verifyEmailPage.title')
})
} catch (error) {
logger.error('[EMAIL:VERIFY] Verification failed:', error)
cacheControl(ctx)
await ctx.render('user/verify-email', {
success: false,
message: '验证失败,请稍后重试',
title: ctx.__('verifyEmailPage.title')
})
}
}

export default {
getIcon,
statistic,
Expand All @@ -184,5 +305,10 @@ export default {
render500Page,
renderDashboard,
renderLandingPage,
renderInitialPage
renderSignupPage,
renderInitialPage,
// email auth pages
renderForgotPasswordPage,
renderResetPasswordPage,
renderVerifyEmailPage
}
Loading