mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
Viewing an archive or a doc marked it viewed on the request's read transaction. SQLite cannot upgrade a read to a writer once another connection has committed (during a download or refresh), and it does not wait on busy_timeout for that. The archive page returned a 500; the doc page returned 200 but its view was lost when the request's commit failed. Build the response on the read, then record the view in `request.ctx.db.write()`, as the video page already does. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
71 lines
2.2 KiB
Python
71 lines
2.2 KiB
Python
import asyncio
|
|
from http import HTTPStatus
|
|
|
|
from sanic import Request, Blueprint
|
|
from sanic_ext import validate
|
|
from sanic_ext.extensions.openapi import openapi
|
|
|
|
from wrolpi.api_utils import json_response
|
|
from wrolpi.common import logger, api_param_limiter
|
|
from wrolpi.schema import JSONErrorResponse
|
|
from . import schema
|
|
from .lib import get_statistics, _doc_response, _get_doc, _search_docs
|
|
|
|
NAME = 'docs'
|
|
|
|
docs_bp = Blueprint('Docs', '/api/docs')
|
|
|
|
logger = logger.getChild(__name__)
|
|
|
|
|
|
@docs_bp.get('/statistics')
|
|
@openapi.response(HTTPStatus.OK, schema.DocStatisticsResponse)
|
|
async def statistics(request: Request):
|
|
ret = get_statistics(request.ctx.session)
|
|
return json_response(ret, HTTPStatus.OK)
|
|
|
|
|
|
@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, file_group_id: int):
|
|
session = request.ctx.session
|
|
skip_viewed = request.args.get('skip_viewed', '').lower() == 'true'
|
|
doc = _get_doc(session, file_group_id, skip_viewed=True)
|
|
response = _doc_response(doc)
|
|
if not skip_viewed:
|
|
# Marking the doc viewed is a write; it must not upgrade the read above (see `RequestDB.write`).
|
|
with request.ctx.db.write():
|
|
response['file_group']['viewed'] = doc.file_group.set_viewed()
|
|
return json_response(response)
|
|
|
|
|
|
doc_limit_limiter = api_param_limiter(100)
|
|
|
|
|
|
@docs_bp.post('/search')
|
|
@openapi.definition(
|
|
summary='Search docs with filtering',
|
|
body=schema.DocSearchRequest,
|
|
)
|
|
@openapi.response(HTTPStatus.OK, schema.DocSearchResponse)
|
|
@validate(schema.DocSearchRequest)
|
|
async def search_docs(request: Request, body: schema.DocSearchRequest):
|
|
limit = doc_limit_limiter(body.limit)
|
|
offset = body.offset or 0
|
|
file_groups, total = await asyncio.to_thread(
|
|
_search_docs,
|
|
request.ctx.session,
|
|
search_str=body.search_str,
|
|
author=body.author,
|
|
subject=body.subject,
|
|
language=body.language,
|
|
mimetype=body.mimetype,
|
|
limit=limit,
|
|
offset=offset,
|
|
order_by=body.order_by,
|
|
tag_names=body.tag_names,
|
|
deep=body.deep,
|
|
)
|
|
ret = dict(file_groups=file_groups, totals=dict(file_groups=total))
|
|
return json_response(ret)
|