mirror of
https://github.com/aquatix/digimarks.git
synced 2025-12-06 20:55:10 +01:00
Compare commits
4 Commits
f05525a9cd
...
651a7e4ece
| Author | SHA1 | Date | |
|---|---|---|---|
| 651a7e4ece | |||
| 63ebc33b04 | |||
| 5f2e2c37fa | |||
| 21306f030e |
@@ -30,7 +30,10 @@ necessary packages:
|
||||
git clone https://github.com/aquatix/digimarks.git
|
||||
cd digimarks
|
||||
mkvirtualenv digimarks # or whatever project you are working on
|
||||
pip install -r requirements.txt
|
||||
# If you just want to run it, no need for development dependencies
|
||||
uv sync --active --no-dev
|
||||
# Otherwise, install everything
|
||||
uv sync --active
|
||||
|
||||
|
||||
Migrating from version 1
|
||||
|
||||
@@ -6,20 +6,19 @@ build-backend = "setuptools.build_meta"
|
||||
name = "digimarks"
|
||||
version = "1.1.99"
|
||||
authors = [
|
||||
{name = "Michiel Scholten", email = "michiel@diginaut.net"},
|
||||
{ name = "Michiel Scholten", email = "michiel@diginaut.net" },
|
||||
]
|
||||
description='Simple bookmarking service, using a SQLite database to store bookmarks, supporting tags, automatic title fetching and REST API calls.'
|
||||
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.7"
|
||||
requires-python = ">=3.10"
|
||||
keywords = ["bookmarks", "api"]
|
||||
license = {text = "Apache"}
|
||||
license = { text = "Apache" }
|
||||
classifiers = [
|
||||
"Framework :: FastAPI",
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
]
|
||||
dependencies = [
|
||||
"importlib-metadata; python_version<'3.8'",
|
||||
"fastapi[all]",
|
||||
"sqlmodel",
|
||||
"alembic",
|
||||
@@ -30,6 +29,29 @@ dependencies = [
|
||||
"extract_favicon",
|
||||
"feedgen",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
{include-group = "lint"},
|
||||
{include-group = "pub"},
|
||||
{include-group = "test"}
|
||||
]
|
||||
test = [
|
||||
"pytest>=7.0.0",
|
||||
"pytest-cov>=4.0.0",
|
||||
]
|
||||
lint = [
|
||||
"ruff>=0.1.0",
|
||||
"mypy>=1.0.0",
|
||||
]
|
||||
# Publishing on PyPI
|
||||
pub = [
|
||||
"build",
|
||||
"twine"
|
||||
]
|
||||
server = [
|
||||
"gunicorn>=23.0.0",
|
||||
]
|
||||
# dynamic = ["version"]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
# Core application
|
||||
fastapi[all]
|
||||
sqlmodel
|
||||
sqlalchemy
|
||||
pydantic
|
||||
pydantic_settings
|
||||
alembic
|
||||
aiosqlite
|
||||
|
||||
# Fetch external resources
|
||||
httpx
|
||||
|
||||
# Fetch title etc from links
|
||||
beautifulsoup4
|
||||
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
# Core application
|
||||
fastapi[all]
|
||||
sqlmodel
|
||||
sqlalchemy
|
||||
pydantic
|
||||
pydantic_settings
|
||||
alembic
|
||||
aiosqlite
|
||||
|
||||
# Fetch external resources
|
||||
httpx
|
||||
|
||||
# Fetch title etc from links
|
||||
beautifulsoup4
|
||||
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
"""Bookmark helper functions, like content scrapers, favicon extractor, updater functions."""
|
||||
|
||||
import logging
|
||||
from collections.abc import Sequence
|
||||
from datetime import UTC, datetime
|
||||
from typing import Annotated, Sequence
|
||||
from typing import Annotated
|
||||
from urllib.parse import urlparse, urlunparse
|
||||
|
||||
import bs4
|
||||
import httpx
|
||||
import tags_service
|
||||
import utils
|
||||
from exceptions import BookmarkNotFound
|
||||
from extract_favicon import from_html
|
||||
from fastapi import Query, Request
|
||||
from models import Bookmark, Visibility
|
||||
from pydantic import AnyUrl
|
||||
from sqlmodel import select
|
||||
|
||||
from src.digimarks import tags_service, utils
|
||||
from src.digimarks.exceptions import BookmarkNotFound
|
||||
from src.digimarks.models import Bookmark, Visibility
|
||||
|
||||
DIGIMARKS_USER_AGENT = 'digimarks/2.0.0-dev'
|
||||
|
||||
logger = logging.getLogger('digimarks')
|
||||
@@ -29,7 +30,7 @@ def get_favicon(html_content: str, root_url: str) -> str:
|
||||
# TODO: save the preferred image to file and return
|
||||
|
||||
|
||||
async def set_information_from_source(logger, bookmark: Bookmark, request: Request) -> Bookmark:
|
||||
async def set_information_from_source(bookmark: Bookmark, request: Request) -> Bookmark:
|
||||
"""Request the title by requesting the source url."""
|
||||
logger.info('Extracting information from url %s', bookmark.url)
|
||||
try:
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
"""digimarks main module."""
|
||||
|
||||
import logging
|
||||
from collections.abc import Sequence
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import UTC, datetime
|
||||
from typing import Annotated, Sequence, Type
|
||||
from typing import Annotated
|
||||
|
||||
import bookmarks_service
|
||||
import httpx
|
||||
import tags_service
|
||||
from exceptions import BookmarkNotFound
|
||||
from fastapi import Depends, FastAPI, HTTPException, Query, Request
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from models import DEFAULT_THEME, Bookmark, User, Visibility
|
||||
from pydantic import DirectoryPath, FilePath
|
||||
from pydantic_settings import BaseSettings
|
||||
from sqlalchemy.ext.asyncio import create_async_engine
|
||||
@@ -18,10 +23,6 @@ from sqlalchemy.orm import sessionmaker
|
||||
from sqlmodel import desc, select
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from src.digimarks import bookmarks_service, tags_service
|
||||
from src.digimarks.exceptions import BookmarkNotFound
|
||||
from src.digimarks.models import DEFAULT_THEME, Bookmark, User, Visibility
|
||||
|
||||
DIGIMARKS_VERSION = '2.0.0a1'
|
||||
|
||||
|
||||
@@ -124,7 +125,7 @@ def index(request: Request):
|
||||
|
||||
|
||||
@app.get('/api/v1/admin/{system_key}/users/{user_id}', response_model=User)
|
||||
async def get_user(session: SessionDep, system_key: str, user_id: int) -> Type[User]:
|
||||
async def get_user(session: SessionDep, system_key: str, user_id: int) -> type[User]:
|
||||
"""Show user information."""
|
||||
logger.info('User %d requested', user_id)
|
||||
if system_key != settings.system_key:
|
||||
|
||||
@@ -22,4 +22,12 @@
|
||||
.thumbnail img {
|
||||
/*width: 72px;*/
|
||||
width: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
#bookmarkEditForm fieldset {
|
||||
border: none;
|
||||
}
|
||||
|
||||
#bookmarkEditForm fieldset input, #bookmarkEditForm textarea, #bookmarkEditForm select, #bookmarkEditForm label {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ document.addEventListener('alpine:init', () => {
|
||||
showTags: Alpine.$persist(false).as('showTags'),
|
||||
/* Bookmark that is being edited, used to fill the form, etc. */
|
||||
bookmarkToEdit: Alpine.$persist(null).as('bookmarkToEdit'),
|
||||
bookmarkToEditError: null,
|
||||
|
||||
/* Loading indicator */
|
||||
loading: false,
|
||||
@@ -207,12 +208,42 @@ document.addEventListener('alpine:init', () => {
|
||||
/* Open 'add bookmark' page */
|
||||
console.log('Start adding bookmark');
|
||||
this.bookmarkToEdit = {
|
||||
'url': ''
|
||||
'url': '',
|
||||
'title': '',
|
||||
'note': '',
|
||||
'tags': ''
|
||||
}
|
||||
// this.show_bookmark_details = true;
|
||||
const editFormDialog = document.getElementById("editFormDialog");
|
||||
editFormDialog.showModal();
|
||||
},
|
||||
async bookmarkURLChanged() {
|
||||
console.log('Bookmark URL changed');
|
||||
// let response = await fetch('/api/v1/' + this.userKey + '/autocomplete_bookmark/');
|
||||
try {
|
||||
const response = await fetch('/api/v1/' + this.userKey + '/autocomplete_bookmark/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
// Bookmark form data
|
||||
url: this.bookmarkToEdit.url,
|
||||
title: this.bookmarkToEdit.title,
|
||||
note: this.bookmarkToEdit.note,
|
||||
tags: this.bookmarkToEdit.tags
|
||||
})
|
||||
});
|
||||
const data = await response.json();
|
||||
// TODO: update form fields if needed (auto-fetched title for example
|
||||
console.log(data);
|
||||
this.bookmarkToEditError = 'lolwut';
|
||||
} catch (error) {
|
||||
// enter your logic for when there is an error (ex. error toast)
|
||||
|
||||
console.log(error)
|
||||
}
|
||||
},
|
||||
async saveBookmark() {
|
||||
console.log('Saving bookmark');
|
||||
// this.show_bookmark_details = false;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"""Helper functions for tags used with Bookmark models."""
|
||||
|
||||
from models import Bookmark, Visibility
|
||||
from sqlalchemy import Sequence
|
||||
from sqlmodel import select
|
||||
|
||||
from src.digimarks.models import Bookmark, Visibility
|
||||
|
||||
|
||||
def i_filter_false(predicate, iterable):
|
||||
"""Filter an iterable if predicate returns True.
|
||||
|
||||
@@ -170,8 +170,32 @@
|
||||
</span>
|
||||
</div>
|
||||
#}
|
||||
<form method="dialog">
|
||||
<input type="text" name="">
|
||||
<form method="dialog" id="bookmarkEditForm">
|
||||
<fieldset class="form-group">
|
||||
<label for="bookmark_url">URL</label>
|
||||
<input id="bookmark_url" type="text" name="bookmark_url" placeholder="url"
|
||||
x-on:change.debounce="$store.digimarks.bookmarkURLChanged()"
|
||||
x-model="$store.digimarks.bookmarkToEdit.url">
|
||||
</fieldset>
|
||||
<fieldset class="form-group">
|
||||
<label for="bookmark_title">Title</label>
|
||||
<input id="bookmark_title" type="text" name="bookmark_title"
|
||||
placeholder="title (leave empty for autofetch)"
|
||||
x-model="$store.digimarks.bookmarkToEdit.title">
|
||||
</fieldset>
|
||||
<fieldset class="form-group">
|
||||
<label for="bookmark_note">Note</label>
|
||||
<textarea id="bookmark_note" type="text" name="bookmark_note"
|
||||
x-model="$store.digimarks.bookmarkToEdit.note">
|
||||
</textarea>
|
||||
</fieldset>
|
||||
<fieldset class="form-group">
|
||||
<label for="bookmark_tags">Tags</label>
|
||||
<input id="bookmark_tags" type="text" name="bookmark_tags"
|
||||
placeholder="tags, divided bij comma's"
|
||||
x-model="$store.digimarks.bookmarkToEdit.tags">
|
||||
</fieldset>
|
||||
<p x-show="$store.digimarks.bookmarkToEditError" x-data="$store.digimarks.bookmarkToEditError"></p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" name="strip" id="strip"/>
|
||||
|
||||
Reference in New Issue
Block a user