1
0
mirror of https://github.com/aquatix/digimarks.git synced 2025-12-06 23:05:10 +01:00

Only fetch new bookmarks and tags when cache is not up-to-date

This commit is contained in:
2025-05-06 14:44:25 +02:00
parent 127284716e
commit 3642753266
3 changed files with 86 additions and 16 deletions

View File

@@ -19,7 +19,7 @@ from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from pydantic import AnyUrl, DirectoryPath, FilePath
from pydantic_settings import BaseSettings
from sqlmodel import AutoString, Field, Session, SQLModel, create_engine, select
from sqlmodel import AutoString, Field, Session, SQLModel, create_engine, desc, select
DIGIMARKS_USER_AGENT = 'digimarks/2.0.0-dev'
DIGIMARKS_VERSION = '2.0.0a1'
@@ -381,7 +381,11 @@ def get_bookmark(
url_hash: str,
) -> Bookmark:
"""Show bookmark details."""
bookmark = session.exec(select(Bookmark).where(Bookmark.userkey == user_key, Bookmark.url_hash == url_hash)).first()
bookmark = session.exec(
select(Bookmark).where(
Bookmark.userkey == user_key, Bookmark.url_hash == url_hash, Bookmark.status != Visibility.DELETED
)
).first()
# bookmark = session.get(Bookmark, {'url_hash': url_hash, 'userkey': user_key})
return bookmark
@@ -450,13 +454,42 @@ def delete_bookmark(
return {'ok': True}
@app.get('/api/v1/{user_key}/latest_changes/')
def bookmarks_changed_since(
session: SessionDep,
user_key: str,
):
"""Last update on server, so the (browser) client knows whether to fetch an update."""
latest_modified_bookmark = session.exec(
select(Bookmark)
.where(Bookmark.userkey == user_key, Bookmark.status != Visibility.DELETED)
.order_by(desc(Bookmark.modified_date))
).first()
latest_created_bookmark = session.exec(
select(Bookmark)
.where(Bookmark.userkey == user_key, Bookmark.status != Visibility.DELETED)
.order_by(desc(Bookmark.created_date))
).first()
latest_modification = max(latest_modified_bookmark.modified_date, latest_created_bookmark.created_date)
return {
'current_time': datetime.now(UTC),
'latest_change': latest_modified_bookmark.modified_date,
'latest_created': latest_created_bookmark.created_date,
'latest_modification': latest_modification,
}
@app.get('/api/v1/{user_key}/tags/')
def list_tags_for_user(
session: SessionDep,
user_key: str,
) -> list[str]:
"""List all tags in use by the user."""
bookmarks = session.exec(select(Bookmark).where(Bookmark.userkey == user_key)).all()
bookmarks = session.exec(
select(Bookmark).where(Bookmark.userkey == user_key, Bookmark.status != Visibility.DELETED)
).all()
tags = []
for bookmark in bookmarks:
tags += bookmark.tags_list

View File

@@ -9,12 +9,18 @@ document.addEventListener('alpine:init', () => {
bookmarks: [],
tags: [],
tryout: 'hey',
/* Loading indicator */
loading: false,
/* Search filter */
search: '',
/* Sort on ~ */
sort_title_asc: Alpine.$persist(false).as('sort_title_asc'),
sort_title_desc: Alpine.$persist(false).as('sort_title_desc'),
sort_created_asc: Alpine.$persist(false).as('sort_created_asc'),
sort_created_desc: Alpine.$persist(false).as('sort_created_desc'),
async init() {
/** Initialise the application after loading */
// if (this.userKey in this.cache) {
@@ -28,28 +34,47 @@ document.addEventListener('alpine:init', () => {
}, 1000);
},
async loadCache() {
console.log('Loading bookmarks from cache for user "' + this.userKey + '"');
this.bookmarks = this.cache[this.userKey]['bookmarks'] || [];
if (this.userKey in this.cache) {
console.log('Loading bookmarks from cache for user "' + this.userKey + '"');
this.bookmarks = this.cache[this.userKey]['bookmarks'] || [];
}
},
async getBookmarks() {
/** Get the bookmarks from the backend */
this.loading = true;
if (!(this.userKey in this.cache)) {
/* There is no cache for this userKey yet, create on */
console.log('Creating cache for user "' + this.userKey + '"');
this.cache[this.userKey] = {'bookmarks': [], 'latest_changes': {}};
}
let latest_status_response = await fetch('/api/v1/' + this.userKey + '/latest_changes/');
let latest_status_result = await latest_status_response.json();
let should_fetch = false;
let latest_modification_in_cache = this.cache[this.userKey].latest_changes.latest_modification || "0000-00-00";
should_fetch = latest_status_result.latest_modification > latest_modification_in_cache;
this.cache[this.userKey].latest_changes = latest_status_result;
if (!should_fetch) {
console.log('Cache is up-to-date');
this.loading = false;
return;
}
console.log('Fetching latest bookmarks from backend for user "' + this.userKey + '"...');
let response = await fetch('/api/v1/' + this.userKey + '/bookmarks/?limit=10000');
let result = await response.json();
console.log(result);
this.bookmarks = result;
if (!(this.userKey in this.cache)) {
/* There is no cache for this userKey yet, create on */
console.log('caching');
this.cache[this.userKey] = {'bookmarks': []};
}
/* Cache the bookmarks to Local Storage */
this.cache[this.userKey]['bookmarks'] = result;
let tags_response = await fetch('/api/v1/' + this.userKey + '/tags/');
let tags_result = await tags_response.json();
this.cache[this.userKey]['tags'] = tags_result;
this.loading = false;
},
get filteredItems() {
get filteredBookmarks() {
// return this.cache[this.userKey]['bookmarks'].filter(
// i => i.title.includes(this.search)
// )
@@ -58,6 +83,11 @@ document.addEventListener('alpine:init', () => {
i => i.title.match(new RegExp(this.search, "i"))
)
},
get filteredTags() {
return this.cache[this.userKey].tags.filter(
i => i.match(new RegExp(this.search, "i"))
)
},
async sortAlphabetically(order = 'asc') {
if (order === 'desc') {
this.bookmarks.sort((a, b) => b.title.localeCompare(a.title));

View File

@@ -31,10 +31,17 @@
</p>
<ul x-cloak>
<template x-for="bookmark in $store.digimarks.filteredItems" :key="bookmark.id">
<template x-for="bookmark in $store.digimarks.filteredBookmarks" :key="bookmark.id">
<li><a x-text="bookmark.title" x-bind:href="bookmark.url" target="_blank"></a></li>
</template>
</ul>
<h2>tags</h2>
<ul x-cloak>
<template x-for="tag in $store.digimarks.filteredTags" :key="tag">
<li x-text="tag"></li>
</template>
</ul>
</main>
</div>
{% endblock %}