1
0
mirror of https://codeberg.org/diginaut/digimarks.git synced 2026-02-04 10:20:26 +01:00

4 Commits

4 changed files with 34 additions and 12 deletions

View File

@@ -10,7 +10,7 @@ authors = [
]
description = 'Simple bookmarking service, using a SQLite database to store bookmarks, supporting tags, automatic title fetching and REST API calls.'
readme = "README.rst"
requires-python = ">=3.10"
requires-python = ">=3.11"
keywords = ["bookmarks", "api"]
license = { text = "Apache" }
classifiers = [

View File

@@ -1,7 +1,7 @@
# Core application
fastapi[all]
sqlmodel
sqlalchemy
sqlalchemy[asyncio]
pydantic
pydantic_settings
alembic

View File

@@ -4,7 +4,7 @@ import logging
from collections.abc import Sequence
from contextlib import asynccontextmanager
from datetime import UTC, datetime
from typing import Annotated
from typing import Annotated, AsyncGenerator, cast
import httpx
from fastapi import Depends, FastAPI, HTTPException, Query, Request
@@ -54,22 +54,32 @@ engine = create_async_engine(f'sqlite+aiosqlite:///{settings.database_file}', co
async def get_session() -> AsyncSession:
"""SQLAlchemy session factory."""
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async_session = sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False)
async with async_session() as session:
yield session
# Shorter way of getting the DB session in an endpoint
SessionDep = Annotated[AsyncSession, Depends(get_session)]
@asynccontextmanager
async def lifespan(the_app: FastAPI):
async def lifespan(the_app: FastAPI) -> AsyncGenerator[None, None]:
"""Upon start, initialise an AsyncClient and assign it to an attribute named requests_client on the app object."""
the_app.requests_client = httpx.AsyncClient()
yield
await the_app.requests_client.aclose()
async with httpx.AsyncClient() as requests_client:
the_app.state.requests_client = requests_client
yield
await the_app.state.requests_client.aclose()
async def get_requests_client(request: Request) -> httpx.AsyncClient:
"""Get the httpx client from the application object."""
return cast(httpx.AsyncClient, request.app.state.requests_client)
# Shorter way of getting the httpx client in an endpoint
RequestsDep = Annotated[AsyncSession, Depends(get_requests_client)]
app = FastAPI(lifespan=lifespan)
app.mount('/static', StaticFiles(directory=settings.static_dir), name='static')
app.mount('/content/favicons', StaticFiles(directory=settings.favicons_dir), name='favicons')
@@ -275,12 +285,24 @@ async def bookmarks_changed_since(
)
latest_created_bookmark = result.first()
latest_modification = max(latest_modified_bookmark.modified_date, latest_created_bookmark.created_date)
# There needs to be at least one bookmark of course
if latest_created_bookmark:
latest_created_datetime = latest_created_bookmark.created_date
else:
latest_created_datetime = datetime.min
# We only have a modified datetime when at least one has been edited
if latest_modified_bookmark:
latest_modified_datetime = latest_modified_bookmark.modified_date
else:
latest_modified_datetime = datetime.min
latest_modification = max(latest_modified_datetime, latest_created_datetime)
return {
'current_time': datetime.now(UTC),
'latest_change': latest_modified_bookmark.modified_date,
'latest_created': latest_created_bookmark.created_date,
'latest_change': latest_modified_datetime,
'latest_created': latest_created_datetime,
'latest_modification': latest_modification,
}

View File

@@ -105,7 +105,7 @@ document.addEventListener('alpine:init', () => {
this.cache[this.userKey]['tags'] = await tagsResponse.json();
/* Filter bookmarks by (blacklisted) tags */
await this.filterBookmarksByTags();
this.filterBookmarksByTags();
this.loading = false;
},