Files
zhenyi 0d3b53f7a0 feat(auth): add comprehensive authentication system with 2FA support
- Add new auth module with captcha, login, logout, register, and email verification endpoints
- Implement two-factor authentication with TOTP enable, disable, verify, and backup codes regeneration
- Create RSA public key endpoint for secure password encryption
- Add user profile management with get current user and email retrieval
- Integrate OpenAPI documentation for all authentication endpoints
- Implement password reset functionality with email verification flow
- Add comprehensive API response structures with proper error handling
- Configure all auth routes under /api/v1/auth scope with proper tagging
2026-06-07 18:09:38 +08:00

82 lines
2.7 KiB
Rust

use crate::error::AppError;
use crate::models::wiki::WikiPageRevision;
use crate::service::RepoService;
use crate::session::Session;
use super::util::clamp_limit_offset;
impl RepoService {
/// Get the revision history for a page.
pub async fn wiki_get_revisions(
&self,
ctx: &Session,
wk_name: &str,
repo_name: &str,
slug: &str,
limit: i64,
offset: i64,
) -> Result<Vec<WikiPageRevision>, AppError> {
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
let page = self.wiki_get_page(ctx, wk_name, repo_name, slug).await?;
self.ensure_repo_readable(user_uid, &self.resolve_repo(wk_name, repo_name).await?)
.await?;
let (limit, offset) = clamp_limit_offset(limit, offset);
sqlx::query_as::<_, WikiPageRevision>(
"SELECT id, page_id, version, title, content, editor_id, commit_message, created_at \
FROM wiki_page_revision WHERE page_id = $1 ORDER BY version DESC LIMIT $2 OFFSET $3",
)
.bind(page.id)
.bind(limit)
.bind(offset)
.fetch_all(self.ctx.db.reader())
.await
.map_err(AppError::Database)
}
/// Get details for a specific revision version.
pub async fn wiki_get_revision(
&self,
ctx: &Session,
wk_name: &str,
repo_name: &str,
slug: &str,
version: i32,
) -> Result<WikiPageRevision, AppError> {
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
let page = self.wiki_get_page(ctx, wk_name, repo_name, slug).await?;
self.ensure_repo_readable(user_uid, &self.resolve_repo(wk_name, repo_name).await?)
.await?;
sqlx::query_as::<_, WikiPageRevision>(
"SELECT id, page_id, version, title, content, editor_id, commit_message, created_at \
FROM wiki_page_revision WHERE page_id = $1 AND version = $2",
)
.bind(page.id)
.bind(version)
.fetch_optional(self.ctx.db.reader())
.await
.map_err(AppError::Database)?
.ok_or_else(|| AppError::NotFound("Revision not found".into()))
}
/// Compare two revision versions.
pub async fn wiki_compare_revisions(
&self,
ctx: &Session,
wk_name: &str,
repo_name: &str,
slug: &str,
old_version: i32,
new_version: i32,
) -> Result<(WikiPageRevision, WikiPageRevision), AppError> {
let old = self
.wiki_get_revision(ctx, wk_name, repo_name, slug, old_version)
.await?;
let new = self
.wiki_get_revision(ctx, wk_name, repo_name, slug, new_version)
.await?;
Ok((old, new))
}
}