Refactoring docs to match new url scheme like videos and archives.

This commit is contained in:
Roland 2026-03-20 15:53:21 -06:00
parent 66a891c759
commit 1c79c1c495
No known key found for this signature in database
GPG key ID: 1BA620CE6C9A4680
7 changed files with 28 additions and 49 deletions

View file

@ -2103,12 +2103,8 @@ export async function getDocStatistics() {
return await apiGet(`${DOCS_API}/statistics`);
}
export async function getDoc(docId) {
return await apiGet(`${DOCS_API}/${docId}`);
}
export async function getDocByFileGroup(fileGroupId) {
return await apiGet(`${DOCS_API}/view/${fileGroupId}`);
export async function getDoc(fileGroupId) {
return await apiGet(`${DOCS_API}/${fileGroupId}`);
}
export async function deleteDocs(docIds) {

View file

@ -187,7 +187,7 @@ function DocPage() {
const handleDelete = async () => {
if (doc && doc.id) {
await deleteDocs([doc.id]);
await deleteDocs([docFile.id]);
toast({
type: 'success',
title: 'Document Deleted',
@ -512,7 +512,7 @@ export function DocsRoute() {
text: 'Docs',
to: '/docs',
end: true,
isActive: () => path === '/docs' || /^\/docs\/view\/\d+$/.test(path)
isActive: () => path === '/docs' || /^\/docs\/\d+$/.test(path)
},
{text: 'Subjects', to: '/docs/subjects', isActive: () => path.startsWith('/docs/subjects')},
{text: 'Authors', to: '/docs/authors', isActive: () => path.startsWith('/docs/authors')},
@ -523,7 +523,7 @@ export function DocsRoute() {
<TabLinks links={links}/>
<Routes>
<Route path='/' element={<DocsPage/>}/>
<Route path='view/:fileGroupId' element={<DocPage/>}/>
<Route path=':fileGroupId' element={<DocPage/>}/>
<Route path='subjects' element={<SubjectsPage/>}/>
<Route path='authors' element={<AuthorsPage/>}/>
<Route path='statistics' element={<DocsStatisticsPage/>}/>

View file

@ -75,7 +75,7 @@ function EbookCard({file, sortField}) {
const viewerUrl = isEpub ? `/epub/epub.html?url=${downloadUrl}` : null;
// Link to doc detail page if this is a modeled doc.
const detailUrl = file.model === 'doc' ? `/docs/view/${file.id}` : null;
const detailUrl = file.model === 'doc' ? `/docs/${file.id}` : null;
const color = mimetypeColor(file.mimetype, file.primary_path);
const title = file.title || file.stem || file.name;

View file

@ -9,7 +9,7 @@ import {
fetchSubjects,
filesSearch,
getArchive,
getDocByFileGroup,
getDoc,
getArchiveStatistics,
getChannel,
getConfigs,
@ -352,7 +352,7 @@ export const useDoc = (fileGroupId) => {
const fetchDoc = async () => {
try {
const response = await getDocByFileGroup(fileGroupId);
const response = await getDoc(fileGroupId);
if (response.ok) {
const data = await response.json();
setDocFile(data.file_group);

View file

@ -9,7 +9,7 @@ from wrolpi.common import logger, wrol_mode_check, api_param_limiter
from wrolpi.errors import ValidationError
from wrolpi.schema import JSONErrorResponse
from . import schema
from .lib import get_statistics, _doc_response, _get_doc, _get_doc_by_file_group, _delete_docs, _search_docs
from .lib import get_statistics, _doc_response, _get_doc, _delete_docs, _search_docs
NAME = 'docs'
@ -25,35 +25,26 @@ async def statistics(_: Request):
return json_response(ret, HTTPStatus.OK)
@docs_bp.get('/<doc_id:int>')
@openapi.description('Get a doc by doc ID')
@docs_bp.get('/<file_group_id:int>')
@openapi.description('Get a doc by FileGroup ID')
@openapi.response(HTTPStatus.NOT_FOUND, JSONErrorResponse)
async def get_doc(request: Request, doc_id: int):
async def get_doc(request: Request, file_group_id: int):
session = request.ctx.session
doc = _get_doc(session, doc_id)
doc = _get_doc(session, file_group_id)
return json_response(_doc_response(doc))
@docs_bp.get('/view/<file_group_id:int>')
@openapi.description('Get a doc by file_group ID')
@openapi.response(HTTPStatus.NOT_FOUND, JSONErrorResponse)
async def get_doc_by_file_group(request: Request, file_group_id: int):
session = request.ctx.session
doc = _get_doc_by_file_group(session, file_group_id)
return json_response(_doc_response(doc))
@docs_bp.delete('/<doc_ids:int>', name='doc_delete_one')
@docs_bp.delete('/<doc_ids:[0-9,]+>', name='doc_delete_many')
@openapi.description('Delete Docs')
@docs_bp.delete('/<file_group_ids:int>', name='doc_delete_one')
@docs_bp.delete('/<file_group_ids:[0-9,]+>', name='doc_delete_many')
@openapi.description('Delete Docs by FileGroup IDs')
@openapi.response(HTTPStatus.NOT_FOUND, JSONErrorResponse)
@wrol_mode_check
async def delete_docs(_: Request, doc_ids: str):
async def delete_docs(_: Request, file_group_ids: str):
try:
doc_ids = [int(i) for i in str(doc_ids).split(',')]
file_group_ids = [int(i) for i in str(file_group_ids).split(',')]
except ValueError:
raise ValidationError('Could not parse doc ids')
_delete_docs(*doc_ids)
raise ValidationError('Could not parse file group ids')
_delete_docs(*file_group_ids)
return response.empty()

View file

@ -338,15 +338,7 @@ def _doc_response(doc) -> dict:
}
def _get_doc(session, doc_id: int):
from .models import Doc
doc = session.query(Doc).filter_by(id=doc_id).one_or_none()
if not doc:
raise ValidationError(f'Doc {doc_id} not found')
return doc
def _get_doc_by_file_group(session, file_group_id: int):
def _get_doc(session, file_group_id: int):
from .models import Doc
doc = session.query(Doc).filter_by(file_group_id=file_group_id).one_or_none()
if not doc:
@ -354,11 +346,11 @@ def _get_doc_by_file_group(session, file_group_id: int):
return doc
def _delete_docs(*doc_ids):
def _delete_docs(*file_group_ids):
from .models import Doc
with get_db_session(commit=True) as session:
for doc_id in doc_ids:
doc = session.query(Doc).filter_by(id=doc_id).one_or_none()
for file_group_id in file_group_ids:
doc = session.query(Doc).filter_by(file_group_id=file_group_id).one_or_none()
if doc:
session.delete(doc)

View file

@ -38,7 +38,7 @@ async def test_get_doc(async_client, test_session, test_directory, example_epub,
doc = test_session.query(Doc).first()
assert doc
request, response = await async_client.get(f'/api/docs/{doc.id}')
request, response = await async_client.get(f'/api/docs/{doc.file_group_id}')
assert response.status_code == HTTPStatus.OK
assert response.json['file_group']
@ -71,9 +71,9 @@ async def test_delete_doc(async_client, test_session, test_directory, example_ep
doc = test_session.query(Doc).first()
assert doc
doc_id = doc.id
file_group_id = doc.file_group_id
request, response = await async_client.delete(f'/api/docs/{doc_id}')
request, response = await async_client.delete(f'/api/docs/{file_group_id}')
assert response.status_code == HTTPStatus.NO_CONTENT
assert test_session.query(Doc).filter_by(id=doc_id).one_or_none() is None
assert test_session.query(Doc).filter_by(file_group_id=file_group_id).one_or_none() is None