新增全局协作台账并统一工作台管理界面
新增与项目平级的协作台账,提供空白模板、独立账号授权和在线编辑。 复用共享库的访问权限与历史版本界面,拆分信息维护入口并统一工作台卡片样式。 补充在线文档字体构建支持、数据库表结构升级和回归测试。 不包含本地台账内容、账号授权记录或历史文件迁移数据。
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
import uuid
|
||||
|
||||
from fastapi import APIRouter, Depends, File, Form, Query, Response, UploadFile
|
||||
from fastapi.responses import FileResponse
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.deps import get_current_user, get_db_session, require_roles
|
||||
from app.schemas.collaboration import (
|
||||
CollaborationEditorConfigRead, CollaborationExportRecord, CollaborationRevisionRead,
|
||||
CollaborationEditRequestRead, CollaborationEditRequestResolve, CollaborationOwnershipTransferRequest,
|
||||
CollaborationShareLinkRead, CollaborationShareLinkUpdate, CollaborationRevisionUpdate,
|
||||
)
|
||||
from app.schemas.ledger import (
|
||||
LedgerAccessSettings, LedgerCandidateRead, LedgerMemberRead, LedgerMemberUpsert, LedgerRead, LedgerRestore, LedgerSettings,
|
||||
)
|
||||
from app.schemas.onlyoffice import OnlyOfficePreviewConfigRead
|
||||
from app.services import collaboration_service, collaboration_share_service, ledger_service, onlyoffice_collaboration_service, onlyoffice_service
|
||||
|
||||
|
||||
def no_store(response: Response):
|
||||
response.headers["Cache-Control"] = "no-store"
|
||||
|
||||
|
||||
router = APIRouter(dependencies=[Depends(no_store)])
|
||||
|
||||
|
||||
@router.get("", response_model=list[LedgerRead])
|
||||
async def list_ledgers(db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user)):
|
||||
return await ledger_service.list_ledgers(db, user)
|
||||
|
||||
|
||||
@router.post("/initialize", response_model=list[LedgerRead])
|
||||
async def initialize(db: AsyncSession = Depends(get_db_session), user=Depends(require_roles(["ADMIN"]))):
|
||||
return await ledger_service.initialize_ledgers(db, user)
|
||||
|
||||
|
||||
@router.get("/{ledger_id}", response_model=LedgerRead)
|
||||
async def read(ledger_id: uuid.UUID, db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user)):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user)
|
||||
return await ledger_service.read_ledger(db, item, user)
|
||||
|
||||
|
||||
@router.patch("/{ledger_id}", response_model=LedgerRead)
|
||||
async def update(ledger_id: uuid.UUID, payload: LedgerSettings, db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user)):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, manage=True, lock=True)
|
||||
return await ledger_service.update_settings(db, item, payload, user)
|
||||
|
||||
|
||||
@router.post("/{ledger_id}/import", response_model=LedgerRead)
|
||||
async def import_template(
|
||||
ledger_id: uuid.UUID, file: UploadFile = File(...), generation: int = Form(..., ge=1),
|
||||
db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user),
|
||||
):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, manage=True, lock=True)
|
||||
return await ledger_service.import_content(db, item, file, generation, user)
|
||||
|
||||
|
||||
@router.get("/{ledger_id}/members", response_model=list[LedgerMemberRead])
|
||||
async def members(ledger_id: uuid.UUID, db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user)):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, manage=True)
|
||||
return await ledger_service.list_members(db, item)
|
||||
|
||||
|
||||
@router.get("/{ledger_id}/candidates", response_model=list[LedgerCandidateRead])
|
||||
async def candidates(
|
||||
ledger_id: uuid.UUID, keyword: str = Query(default="", max_length=100),
|
||||
db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user),
|
||||
):
|
||||
await ledger_service.get_ledger(db, ledger_id, user, manage=True)
|
||||
return await ledger_service.candidates(db, keyword)
|
||||
|
||||
|
||||
@router.put("/{ledger_id}/members", status_code=204)
|
||||
async def grant(
|
||||
ledger_id: uuid.UUID, payload: LedgerMemberUpsert,
|
||||
db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user),
|
||||
):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, manage=True, lock=True)
|
||||
await ledger_service.set_member(db, item, payload, user)
|
||||
|
||||
|
||||
@router.delete("/{ledger_id}/members/{user_id}", status_code=204)
|
||||
async def revoke(
|
||||
ledger_id: uuid.UUID, user_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user),
|
||||
):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, manage=True, lock=True)
|
||||
await ledger_service.remove_member(db, item, user_id, user)
|
||||
|
||||
|
||||
@router.get("/{ledger_id}/editor-config", response_model=CollaborationEditorConfigRead)
|
||||
async def editor_config(ledger_id: uuid.UUID, db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user)):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, lock=True)
|
||||
return await onlyoffice_collaboration_service.build_editor_config(db, item, user)
|
||||
|
||||
|
||||
@router.patch("/{ledger_id}/access-settings", response_model=LedgerRead)
|
||||
async def access_settings(ledger_id: uuid.UUID, payload: LedgerAccessSettings,
|
||||
db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user)):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, manage=True, lock=True)
|
||||
return await ledger_service.update_access_settings(db, item, payload, user)
|
||||
|
||||
|
||||
@router.get("/{ledger_id}/share-link", response_model=CollaborationShareLinkRead)
|
||||
async def share_link(ledger_id: uuid.UUID, db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user)):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, manage=True, lock=True)
|
||||
return await collaboration_share_service.get_share_link(db, item, user)
|
||||
|
||||
|
||||
@router.put("/{ledger_id}/share-link", response_model=CollaborationShareLinkRead)
|
||||
async def update_share_link(ledger_id: uuid.UUID, payload: CollaborationShareLinkUpdate,
|
||||
db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user)):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, manage=True, lock=True)
|
||||
return await collaboration_share_service.update_share_link(db, item, payload, user)
|
||||
|
||||
|
||||
@router.post("/{ledger_id}/edit-requests", response_model=CollaborationEditRequestRead)
|
||||
async def request_edit(ledger_id: uuid.UUID, db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user)):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, lock=True)
|
||||
return await collaboration_service.create_edit_request(db, item, user)
|
||||
|
||||
|
||||
@router.get("/{ledger_id}/edit-requests", response_model=list[CollaborationEditRequestRead])
|
||||
async def edit_requests(ledger_id: uuid.UUID, db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user)):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, manage=True)
|
||||
return await collaboration_service.list_edit_requests(db, item, user)
|
||||
|
||||
|
||||
@router.post("/{ledger_id}/edit-requests/{request_id}/resolve", response_model=CollaborationEditRequestRead)
|
||||
async def resolve_request(ledger_id: uuid.UUID, request_id: uuid.UUID, payload: CollaborationEditRequestResolve,
|
||||
db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user)):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, manage=True, lock=True)
|
||||
return await collaboration_service.resolve_edit_request(db, item, request_id, payload, user)
|
||||
|
||||
|
||||
@router.post("/{ledger_id}/transfer-ownership", response_model=LedgerRead)
|
||||
async def transfer_owner(ledger_id: uuid.UUID, payload: CollaborationOwnershipTransferRequest,
|
||||
db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user)):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, manage=True, lock=True)
|
||||
item = await collaboration_service.transfer_ownership(db, item, payload, user)
|
||||
return await ledger_service.read_ledger(db, item, user)
|
||||
|
||||
|
||||
@router.post("/{ledger_id}/downloads", status_code=204)
|
||||
async def download_check(
|
||||
ledger_id: uuid.UUID, payload: CollaborationExportRecord,
|
||||
db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user),
|
||||
):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user)
|
||||
await collaboration_service.record_download(db, item, user, payload.file_type)
|
||||
|
||||
|
||||
@router.get("/{ledger_id}/revisions", response_model=list[CollaborationRevisionRead])
|
||||
async def revisions(ledger_id: uuid.UUID, db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user)):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user)
|
||||
return await collaboration_service.list_revisions(db, item)
|
||||
|
||||
|
||||
@router.post("/{ledger_id}/revisions/{revision_id}/restore", response_model=CollaborationRevisionRead)
|
||||
async def restore(
|
||||
ledger_id: uuid.UUID, revision_id: uuid.UUID, payload: LedgerRestore,
|
||||
db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user),
|
||||
):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, manage=True, lock=True)
|
||||
return await ledger_service.restore_revision(db, item, revision_id, payload.generation, user)
|
||||
|
||||
|
||||
@router.patch("/{ledger_id}/revisions/{revision_id}", response_model=CollaborationRevisionRead)
|
||||
async def name_revision(
|
||||
ledger_id: uuid.UUID, revision_id: uuid.UUID, payload: CollaborationRevisionUpdate,
|
||||
db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user),
|
||||
):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, lock=True)
|
||||
return await collaboration_service.update_revision(db, item, revision_id, payload, user)
|
||||
|
||||
|
||||
@router.get("/{ledger_id}/revisions/{revision_id}/download")
|
||||
async def download_revision(
|
||||
ledger_id: uuid.UUID, revision_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user),
|
||||
):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user, lock=True)
|
||||
await collaboration_service.require_file_exporter(db, item, user)
|
||||
revision = await collaboration_service.prepare_revision_preview(db, item, revision_id, user)
|
||||
await collaboration_service.record_download(db, item, user, "xlsx")
|
||||
return FileResponse(revision.file_uri, filename=item.title, media_type=revision.mime_type,
|
||||
headers={"Cache-Control": "no-store"})
|
||||
|
||||
|
||||
@router.get("/{ledger_id}/revisions/{revision_id}/preview-config", response_model=OnlyOfficePreviewConfigRead)
|
||||
async def preview(
|
||||
ledger_id: uuid.UUID, revision_id: uuid.UUID,
|
||||
db: AsyncSession = Depends(get_db_session), user=Depends(get_current_user),
|
||||
):
|
||||
item = await ledger_service.get_ledger(db, ledger_id, user)
|
||||
revision = await collaboration_service.prepare_revision_preview(db, item, revision_id, user)
|
||||
await onlyoffice_service.ensure_onlyoffice_available()
|
||||
return onlyoffice_service.build_preview_config(
|
||||
resource_type="collaboration_revision", resource_id=revision.id, file_name=item.title,
|
||||
file_hash=revision.file_hash, user_id=user.id, user_name=user.full_name,
|
||||
)
|
||||
Reference in New Issue
Block a user