mirror of
https://github.com/aquatix/digimarks.git
synced 2025-12-06 23:05:10 +01:00
Refactoring to fastapi, reformatting with ruff
This commit is contained in:
@@ -59,5 +59,14 @@ select = [
|
|||||||
"W",
|
"W",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[tool.ruff.flake8-quotes]
|
||||||
|
docstring-quotes = "double"
|
||||||
|
inline-quotes = "single"
|
||||||
|
multiline-quotes = "double"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
# Prefer single quotes over double quotes
|
||||||
|
quote-style = "single"
|
||||||
|
|
||||||
[tool.ruff.mccabe]
|
[tool.ruff.mccabe]
|
||||||
max-complexity = 10
|
max-complexity = 10
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
-r requirements.in
|
-r requirements.in
|
||||||
|
|
||||||
black
|
# black
|
||||||
pylint
|
pylint
|
||||||
ruff
|
ruff
|
||||||
|
|
||||||
|
|||||||
@@ -5,26 +5,27 @@ import hashlib
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
from typing import Optional
|
||||||
from urllib.parse import urljoin, urlparse, urlunparse
|
from urllib.parse import urljoin, urlparse, urlunparse
|
||||||
|
|
||||||
import bs4
|
import bs4
|
||||||
import requests
|
import requests
|
||||||
from dateutil import tz
|
from dateutil import tz
|
||||||
#from flask import (Flask, abort, jsonify, make_response, redirect,
|
|
||||||
|
# from flask import (Flask, abort, jsonify, make_response, redirect,
|
||||||
# render_template, request, url_for)
|
# render_template, request, url_for)
|
||||||
from fastapi import Depends, FastAPI, HTTPException, Request, Response
|
from fastapi import FastAPI, HTTPException, Request, Response
|
||||||
from fastapi.responses import RedirectResponse
|
from fastapi.responses import RedirectResponse
|
||||||
from fastapi.responses import HTMLResponse
|
from fastapi.responses import HTMLResponse
|
||||||
|
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from feedgen.feed import FeedGenerator
|
from feedgen.feed import FeedGenerator
|
||||||
from pydantic import DirectoryPath, FilePath, validator
|
from pydantic import DirectoryPath, FilePath
|
||||||
from pydantic_settings import BaseSettings
|
from pydantic_settings import BaseSettings
|
||||||
from sqlalchemy import VARCHAR, Boolean, Column, DateTime, ForeignKey, Integer, String, Text, create_engine
|
from sqlalchemy import VARCHAR, Boolean, Column, DateTime, Integer, Text, create_engine
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker, Mapped
|
||||||
|
|
||||||
|
|
||||||
DIGIMARKS_USER_AGENT = 'digimarks/2.0.0-dev'
|
DIGIMARKS_USER_AGENT = 'digimarks/2.0.0-dev'
|
||||||
|
|
||||||
@@ -34,7 +35,8 @@ DEFAULT_THEME = 'freshgreen'
|
|||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
"""Configuration needed for digimarks to find its database, favicons, API integrations"""
|
"""Configuration needed for digimarks to find its database, favicons, API integrations"""
|
||||||
|
|
||||||
database_file: FilePath = './bookmarks.db'
|
# database_file: FilePath = './bookmarks.db'
|
||||||
|
database_file: FilePath
|
||||||
media_dir: DirectoryPath
|
media_dir: DirectoryPath
|
||||||
media_url: str = '/static/'
|
media_url: str = '/static/'
|
||||||
|
|
||||||
@@ -44,17 +46,16 @@ class Settings(BaseSettings):
|
|||||||
|
|
||||||
|
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
|
print(settings.model_dump())
|
||||||
|
|
||||||
engine = create_engine(
|
engine = create_engine(f'sqlite:///{settings.database_file}', connect_args={'check_same_thread': False})
|
||||||
f'sqlite:///{settings.database_file}', connect_args={'check_same_thread': False}
|
|
||||||
)
|
|
||||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
|
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
templates = Jinja2Templates(directory="templates")
|
templates = Jinja2Templates(directory='templates')
|
||||||
|
|
||||||
logger = logging.getLogger('digimarks')
|
logger = logging.getLogger('digimarks')
|
||||||
if settings.debug:
|
if settings.debug:
|
||||||
@@ -63,10 +64,10 @@ if settings.debug:
|
|||||||
# CORS configuration
|
# CORS configuration
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
CORSMiddleware,
|
CORSMiddleware,
|
||||||
allow_origins=["*"], # Allow requests from everywhere
|
allow_origins=['*'], # Allow requests from everywhere
|
||||||
allow_credentials=True,
|
allow_credentials=True,
|
||||||
allow_methods=["*"],
|
allow_methods=['*'],
|
||||||
allow_headers=["*"],
|
allow_headers=['*'],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -113,25 +114,28 @@ def clean_tags(tags_list):
|
|||||||
return tags_res
|
return tags_res
|
||||||
|
|
||||||
|
|
||||||
magic_dict = {
|
|
||||||
b"\x1f\x8b\x08": "gz",
|
|
||||||
b"\x42\x5a\x68": "bz2",
|
|
||||||
b"\x50\x4b\x03\x04": "zip"
|
|
||||||
}
|
|
||||||
|
|
||||||
max_len = max(len(x) for x in magic_dict)
|
|
||||||
|
|
||||||
def file_type(filename):
|
def file_type(filename):
|
||||||
with open(filename, "rb") as f:
|
"""Try to determine the file type for the file in `filename`.
|
||||||
|
|
||||||
|
:param str filename: path to file to check
|
||||||
|
:return: zip file type
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
magic_dict = {b'\x1f\x8b\x08': 'gz', b'\x42\x5a\x68': 'bz2', b'\x50\x4b\x03\x04': 'zip'}
|
||||||
|
|
||||||
|
max_len = max(len(x) for x in magic_dict)
|
||||||
|
|
||||||
|
with open(filename, 'rb') as f:
|
||||||
file_start = f.read(max_len)
|
file_start = f.read(max_len)
|
||||||
for magic, filetype in magic_dict.items():
|
for magic, filetype in magic_dict.items():
|
||||||
if file_start.startswith(magic):
|
if file_start.startswith(magic):
|
||||||
return filetype
|
return filetype
|
||||||
return "no match"
|
return 'no match'
|
||||||
|
|
||||||
|
|
||||||
class User(Base):
|
class User(Base):
|
||||||
""" User account """
|
"""User account"""
|
||||||
|
|
||||||
__tablename__ = 'user'
|
__tablename__ = 'user'
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
@@ -142,13 +146,14 @@ class User(Base):
|
|||||||
created_date = Column(DateTime, default=datetime.datetime.now)
|
created_date = Column(DateTime, default=datetime.datetime.now)
|
||||||
|
|
||||||
def generate_key(self):
|
def generate_key(self):
|
||||||
""" Generate userkey """
|
"""Generate userkey"""
|
||||||
self.key = binascii.hexlify(os.urandom(24))
|
self.key = binascii.hexlify(os.urandom(24))
|
||||||
return self.key
|
return self.key
|
||||||
|
|
||||||
|
|
||||||
class Bookmark(Base):
|
class Bookmark(Base):
|
||||||
""" Bookmark instance, connected to User """
|
"""Bookmark instance, connected to User"""
|
||||||
|
|
||||||
__tablename__ = 'bookmark'
|
__tablename__ = 'bookmark'
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
@@ -158,13 +163,15 @@ class Bookmark(Base):
|
|||||||
title = Column(VARCHAR(255), default='')
|
title = Column(VARCHAR(255), default='')
|
||||||
url = Column(VARCHAR(255))
|
url = Column(VARCHAR(255))
|
||||||
note = Column(Text, default='')
|
note = Column(Text, default='')
|
||||||
#image = CharField(default='')
|
# image = CharField(default='')
|
||||||
url_hash = Column(VARCHAR(255) , default='')
|
url_hash = Column(VARCHAR(255), default='')
|
||||||
tags = Column(VARCHAR(255), default='')
|
tags = Column(VARCHAR(255), default='')
|
||||||
starred = Column(Boolean, default=False)
|
starred = Column(Boolean, default=False)
|
||||||
|
|
||||||
# Website (domain) favicon
|
# Website (domain) favicon
|
||||||
favicon = Column(VARCHAR(255), null=True)
|
# favicon = Column(VARCHAR(255), null=True)
|
||||||
|
# favicon = Column(VARCHAR(255))
|
||||||
|
favicon: Mapped[Optional[str]]
|
||||||
|
|
||||||
# Status code: 200 is OK, 404 is not found, for example (showing an error)
|
# Status code: 200 is OK, 404 is not found, for example (showing an error)
|
||||||
HTTP_CONNECTIONERROR = 0
|
HTTP_CONNECTIONERROR = 0
|
||||||
@@ -177,24 +184,25 @@ class Bookmark(Base):
|
|||||||
redirect_uri = None
|
redirect_uri = None
|
||||||
|
|
||||||
created_date = Column(DateTime, default=datetime.datetime.now)
|
created_date = Column(DateTime, default=datetime.datetime.now)
|
||||||
modified_date = Column(DateTime, null=True)
|
# modified_date = Column(DateTime, null=True)
|
||||||
deleted_date = Column(DateTime, null=True)
|
modified_date: Mapped[Optional[datetime.datetime]]
|
||||||
|
# deleted_date = Column(DateTime, null=True)
|
||||||
|
deleted_date: Mapped[Optional[datetime.datetime]]
|
||||||
|
|
||||||
# Bookmark status; deleting doesn't remove from DB
|
# Bookmark status; deleting doesn't remove from DB
|
||||||
VISIBLE = 0
|
VISIBLE = 0
|
||||||
DELETED = 1
|
DELETED = 1
|
||||||
status = Column(Integer, default=VISIBLE)
|
status = Column(Integer, default=VISIBLE)
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = (('created_date', 'desc'),)
|
ordering = (('created_date', 'desc'),)
|
||||||
|
|
||||||
def set_hash(self):
|
def set_hash(self):
|
||||||
""" Generate hash """
|
"""Generate hash"""
|
||||||
self.url_hash = hashlib.md5(self.url.encode('utf-8')).hexdigest()
|
self.url_hash = hashlib.md5(self.url.encode('utf-8')).hexdigest()
|
||||||
|
|
||||||
def set_title_from_source(self) -> str:
|
def set_title_from_source(self) -> str:
|
||||||
""" Request the title by requesting the source url """
|
"""Request the title by requesting the source url"""
|
||||||
try:
|
try:
|
||||||
result = requests.get(self.url, headers={'User-Agent': DIGIMARKS_USER_AGENT})
|
result = requests.get(self.url, headers={'User-Agent': DIGIMARKS_USER_AGENT})
|
||||||
self.http_status = result.status_code
|
self.http_status = result.status_code
|
||||||
@@ -210,7 +218,7 @@ class Bookmark(Base):
|
|||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
def set_status_code(self) -> int:
|
def set_status_code(self) -> int:
|
||||||
""" Check the HTTP status of the url, as it might not exist for example """
|
"""Check the HTTP status of the url, as it might not exist for example"""
|
||||||
try:
|
try:
|
||||||
result = requests.head(self.url, headers={'User-Agent': DIGIMARKS_USER_AGENT}, timeout=30)
|
result = requests.head(self.url, headers={'User-Agent': DIGIMARKS_USER_AGENT}, timeout=30)
|
||||||
self.http_status = result.status_code
|
self.http_status = result.status_code
|
||||||
@@ -219,13 +227,13 @@ class Bookmark(Base):
|
|||||||
return self.http_status
|
return self.http_status
|
||||||
|
|
||||||
def _set_favicon_with_iconsbetterideaorg(self, domain):
|
def _set_favicon_with_iconsbetterideaorg(self, domain):
|
||||||
""" Fetch favicon for the domain """
|
"""Fetch favicon for the domain"""
|
||||||
fileextension = '.png'
|
fileextension = '.png'
|
||||||
meta = requests.head(
|
meta = requests.head(
|
||||||
'http://icons.better-idea.org/icon?size=60&url=' + domain,
|
'http://icons.better-idea.org/icon?size=60&url=' + domain,
|
||||||
allow_redirects=True,
|
allow_redirects=True,
|
||||||
headers={'User-Agent': DIGIMARKS_USER_AGENT},
|
headers={'User-Agent': DIGIMARKS_USER_AGENT},
|
||||||
timeout=15
|
timeout=15,
|
||||||
)
|
)
|
||||||
if meta.url[-3:].lower() == 'ico':
|
if meta.url[-3:].lower() == 'ico':
|
||||||
fileextension = '.ico'
|
fileextension = '.ico'
|
||||||
@@ -233,7 +241,7 @@ class Bookmark(Base):
|
|||||||
'http://icons.better-idea.org/icon?size=60&url=' + domain,
|
'http://icons.better-idea.org/icon?size=60&url=' + domain,
|
||||||
stream=True,
|
stream=True,
|
||||||
headers={'User-Agent': DIGIMARKS_USER_AGENT},
|
headers={'User-Agent': DIGIMARKS_USER_AGENT},
|
||||||
timeout=15
|
timeout=15,
|
||||||
)
|
)
|
||||||
filename = os.path.join(settings.media_dir, 'favicons/', domain + fileextension)
|
filename = os.path.join(settings.media_dir, 'favicons/', domain + fileextension)
|
||||||
with open(filename, 'wb') as out_file:
|
with open(filename, 'wb') as out_file:
|
||||||
@@ -251,18 +259,18 @@ class Bookmark(Base):
|
|||||||
self.favicon = domain + fileextension
|
self.favicon = domain + fileextension
|
||||||
|
|
||||||
def _set_favicon_with_realfavicongenerator(self, domain):
|
def _set_favicon_with_realfavicongenerator(self, domain):
|
||||||
""" Fetch favicon for the domain """
|
"""Fetch favicon for the domain"""
|
||||||
response = requests.get(
|
response = requests.get(
|
||||||
'https://realfavicongenerator.p.rapidapi.com/favicon/icon?platform=android_chrome&site=' + domain,
|
'https://realfavicongenerator.p.rapidapi.com/favicon/icon?platform=android_chrome&site=' + domain,
|
||||||
stream=True,
|
stream=True,
|
||||||
headers={'User-Agent': DIGIMARKS_USER_AGENT, 'X-Mashape-Key': settings.MASHAPE_API_KEY}
|
headers={'User-Agent': DIGIMARKS_USER_AGENT, 'X-Mashape-Key': settings.MASHAPE_API_KEY},
|
||||||
)
|
)
|
||||||
if response.status_code == 404:
|
if response.status_code == 404:
|
||||||
# Fall back to desktop favicon
|
# Fall back to desktop favicon
|
||||||
response = requests.get(
|
response = requests.get(
|
||||||
'https://realfavicongenerator.p.rapidapi.com/favicon/icon?platform=desktop&site=' + domain,
|
'https://realfavicongenerator.p.rapidapi.com/favicon/icon?platform=desktop&site=' + domain,
|
||||||
stream=True,
|
stream=True,
|
||||||
headers={'User-Agent': DIGIMARKS_USER_AGENT, 'X-Mashape-Key': settings.MASHAPE_API_KEY}
|
headers={'User-Agent': DIGIMARKS_USER_AGENT, 'X-Mashape-Key': settings.MASHAPE_API_KEY},
|
||||||
)
|
)
|
||||||
# Debug for the moment
|
# Debug for the moment
|
||||||
print(domain)
|
print(domain)
|
||||||
@@ -293,7 +301,7 @@ class Bookmark(Base):
|
|||||||
self.favicon = domain + fileextension
|
self.favicon = domain + fileextension
|
||||||
|
|
||||||
def set_favicon(self):
|
def set_favicon(self):
|
||||||
""" Fetch favicon for the domain """
|
"""Fetch favicon for the domain"""
|
||||||
u = urlparse(self.url)
|
u = urlparse(self.url)
|
||||||
domain = u.netloc
|
domain = u.netloc
|
||||||
if os.path.isfile(os.path.join(settings.media_dir, 'favicons/', domain + '.png')):
|
if os.path.isfile(os.path.join(settings.media_dir, 'favicons/', domain + '.png')):
|
||||||
@@ -304,11 +312,11 @@ class Bookmark(Base):
|
|||||||
# If file exists, don't re-download it
|
# If file exists, don't re-download it
|
||||||
self.favicon = domain + '.ico'
|
self.favicon = domain + '.ico'
|
||||||
return
|
return
|
||||||
#self._set_favicon_with_iconsbetterideaorg(domain)
|
# self._set_favicon_with_iconsbetterideaorg(domain)
|
||||||
self._set_favicon_with_realfavicongenerator(domain)
|
self._set_favicon_with_realfavicongenerator(domain)
|
||||||
|
|
||||||
def set_tags(self, newtags):
|
def set_tags(self, newtags):
|
||||||
""" Set tags from `tags`, strip and sort them """
|
"""Set tags from `tags`, strip and sort them"""
|
||||||
tags_split = newtags.split(',')
|
tags_split = newtags.split(',')
|
||||||
tags_clean = clean_tags(tags_split)
|
tags_clean = clean_tags(tags_split)
|
||||||
self.tags = ','.join(tags_clean)
|
self.tags = ','.join(tags_clean)
|
||||||
@@ -334,7 +342,7 @@ class Bookmark(Base):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def tags_list(self):
|
def tags_list(self):
|
||||||
""" Get the tags as a list, iterable in template """
|
"""Get the tags as a list, iterable in template"""
|
||||||
if self.tags:
|
if self.tags:
|
||||||
return self.tags.split(',')
|
return self.tags.split(',')
|
||||||
return []
|
return []
|
||||||
@@ -355,7 +363,8 @@ class Bookmark(Base):
|
|||||||
|
|
||||||
|
|
||||||
class PublicTag(Base):
|
class PublicTag(Base):
|
||||||
""" Publicly shared tag """
|
"""Publicly shared tag"""
|
||||||
|
|
||||||
__tablename__ = 'publictag'
|
__tablename__ = 'publictag'
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
@@ -365,12 +374,12 @@ class PublicTag(Base):
|
|||||||
created_date = Column(DateTime, default=datetime.datetime.now)
|
created_date = Column(DateTime, default=datetime.datetime.now)
|
||||||
|
|
||||||
def generate_key(self):
|
def generate_key(self):
|
||||||
""" Generate hash-based key for publicly shared tag """
|
"""Generate hash-based key for publicly shared tag"""
|
||||||
self.tagkey = binascii.hexlify(os.urandom(16))
|
self.tagkey = binascii.hexlify(os.urandom(16))
|
||||||
|
|
||||||
|
|
||||||
def get_tags_for_user(userkey):
|
def get_tags_for_user(userkey):
|
||||||
""" Extract all tags from the bookmarks """
|
"""Extract all tags from the bookmarks"""
|
||||||
bookmarks = Bookmark.select().filter(Bookmark.userkey == userkey, Bookmark.status == Bookmark.VISIBLE)
|
bookmarks = Bookmark.select().filter(Bookmark.userkey == userkey, Bookmark.status == Bookmark.VISIBLE)
|
||||||
tags = []
|
tags = []
|
||||||
for bookmark in bookmarks:
|
for bookmark in bookmarks:
|
||||||
@@ -379,7 +388,7 @@ def get_tags_for_user(userkey):
|
|||||||
|
|
||||||
|
|
||||||
def get_cached_tags(userkey):
|
def get_cached_tags(userkey):
|
||||||
""" Fail-safe way to get the cached tags for `userkey` """
|
"""Fail-safe way to get the cached tags for `userkey`"""
|
||||||
try:
|
try:
|
||||||
return all_tags[userkey]
|
return all_tags[userkey]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -401,15 +410,19 @@ def make_external(request: Request, url):
|
|||||||
|
|
||||||
def _find_bookmarks(userkey, filter_text) -> list[Bookmark]:
|
def _find_bookmarks(userkey, filter_text) -> list[Bookmark]:
|
||||||
"""Look up bookmark for `userkey` which contains `filter_text` in its properties"""
|
"""Look up bookmark for `userkey` which contains `filter_text` in its properties"""
|
||||||
return Bookmark.select().where(
|
return (
|
||||||
|
Bookmark.select()
|
||||||
|
.where(
|
||||||
Bookmark.userkey == userkey,
|
Bookmark.userkey == userkey,
|
||||||
(
|
(
|
||||||
Bookmark.title.contains(filter_text) |
|
Bookmark.title.contains(filter_text)
|
||||||
Bookmark.url.contains(filter_text) |
|
| Bookmark.url.contains(filter_text)
|
||||||
Bookmark.note.contains(filter_text)
|
| Bookmark.note.contains(filter_text)
|
||||||
),
|
),
|
||||||
Bookmark.status == Bookmark.VISIBLE
|
Bookmark.status == Bookmark.VISIBLE,
|
||||||
).order_by(Bookmark.created_date.desc())
|
)
|
||||||
|
.order_by(Bookmark.created_date.desc())
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# @app.errorhandler(404)
|
# @app.errorhandler(404)
|
||||||
@@ -420,93 +433,104 @@ def _find_bookmarks(userkey, filter_text) -> list[Bookmark]:
|
|||||||
|
|
||||||
@app.get('/')
|
@app.get('/')
|
||||||
def index():
|
def index():
|
||||||
""" Homepage, point visitors to project page """
|
"""Homepage, point visitors to project page"""
|
||||||
# theme = themes[DEFAULT_THEME]
|
# theme = themes[DEFAULT_THEME]
|
||||||
# return render_template('index.html', theme=theme)
|
# return render_template('index.html', theme=theme)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def get_bookmarks(request: Request, userkey, filtermethod=None, sortmethod=None):
|
def get_bookmarks(request: Request, user_key, filter_method=None, sort_method=None):
|
||||||
""" User homepage, list their bookmarks, optionally filtered and/or sorted """
|
"""User homepage, list their bookmarks, optionally filtered and/or sorted"""
|
||||||
#return object_list('bookmarks.html', Bookmark.select())
|
# return object_list('bookmarks.html', Bookmark.select())
|
||||||
#user = User.select(key=userkey)
|
# user = User.select(key=userkey)
|
||||||
#if user:
|
# if user:
|
||||||
# bookmarks = Bookmark.select(User=user)
|
# bookmarks = Bookmark.select(User=user)
|
||||||
# return render_template('bookmarks.html', bookmarks)
|
# return render_template('bookmarks.html', bookmarks)
|
||||||
#else:
|
# else:
|
||||||
# abort(404)
|
# abort(404)
|
||||||
message = request.args.get('message')
|
message = request.args.get('message')
|
||||||
bookmarktags = get_cached_tags(userkey)
|
bookmarktags = get_cached_tags(user_key)
|
||||||
|
|
||||||
filter_text = ''
|
filter_text = ''
|
||||||
if request.form:
|
if request.form:
|
||||||
filter_text = request.form['filter_text']
|
filter_text = request.form['filter_text']
|
||||||
|
|
||||||
filter_starred = False
|
filter_starred = False
|
||||||
if filtermethod and filtermethod.lower() == 'starred':
|
if filter_method and filter_method.lower() == 'starred':
|
||||||
filter_starred = True
|
filter_starred = True
|
||||||
|
|
||||||
filter_broken = False
|
filter_broken = False
|
||||||
if filtermethod and filtermethod.lower() == 'broken':
|
if filter_method and filter_method.lower() == 'broken':
|
||||||
filter_broken = True
|
filter_broken = True
|
||||||
|
|
||||||
filter_note = False
|
filter_note = False
|
||||||
if filtermethod and filtermethod.lower() == 'note':
|
if filter_method and filter_method.lower() == 'note':
|
||||||
filter_note = True
|
filter_note = True
|
||||||
|
|
||||||
if filter_text:
|
if filter_text:
|
||||||
bookmarks = _find_bookmarks(userkey, filter_text)
|
bookmarks = _find_bookmarks(user_key, filter_text)
|
||||||
elif filter_starred:
|
elif filter_starred:
|
||||||
bookmarks = Bookmark.select().where(Bookmark.userkey == userkey,
|
bookmarks = (
|
||||||
Bookmark.starred).order_by(Bookmark.created_date.desc())
|
Bookmark.select()
|
||||||
|
.where(Bookmark.userkey == user_key, Bookmark.starred)
|
||||||
|
.order_by(Bookmark.created_date.desc())
|
||||||
|
)
|
||||||
elif filter_broken:
|
elif filter_broken:
|
||||||
bookmarks = Bookmark.select().where(Bookmark.userkey == userkey,
|
bookmarks = (
|
||||||
Bookmark.http_status != 200).order_by(Bookmark.created_date.desc())
|
Bookmark.select()
|
||||||
|
.where(Bookmark.userkey == user_key, Bookmark.http_status != 200)
|
||||||
|
.order_by(Bookmark.created_date.desc())
|
||||||
|
)
|
||||||
elif filter_note:
|
elif filter_note:
|
||||||
bookmarks = Bookmark.select().where(Bookmark.userkey == userkey,
|
bookmarks = (
|
||||||
Bookmark.note != '').order_by(Bookmark.created_date.desc())
|
Bookmark.select()
|
||||||
|
.where(Bookmark.userkey == user_key, Bookmark.note != '')
|
||||||
|
.order_by(Bookmark.created_date.desc())
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
bookmarks = Bookmark.select().where(
|
bookmarks = (
|
||||||
Bookmark.userkey == userkey,
|
Bookmark.select()
|
||||||
Bookmark.status == Bookmark.VISIBLE
|
.where(Bookmark.userkey == user_key, Bookmark.status == Bookmark.VISIBLE)
|
||||||
).order_by(Bookmark.created_date.desc())
|
.order_by(Bookmark.created_date.desc())
|
||||||
|
)
|
||||||
|
|
||||||
return bookmarks, bookmarktags, filter_text, message
|
return bookmarks, bookmarktags, filter_text, message
|
||||||
|
|
||||||
|
|
||||||
@app.get('/<userkey>', response_class=HTMLResponse)
|
@app.get('/{user_key}', response_class=HTMLResponse)
|
||||||
@app.post('/<userkey>', response_class=HTMLResponse)
|
@app.post('/{user_key}', response_class=HTMLResponse)
|
||||||
@app.route('/<userkey>/filter/<filtermethod>', methods=['GET', 'POST'])
|
@app.route('/<user_key>/filter/<filtermethod>', methods=['GET', 'POST'])
|
||||||
@app.route('/<userkey>/sort/<sortmethod>', methods=['GET', 'POST'])
|
@app.route('/<user_key>/sort/<sortmethod>', methods=['GET', 'POST'])
|
||||||
@app.route('/<userkey>/<show_as>', methods=['GET', 'POST'])
|
@app.route('/<user_key>/<show_as>', methods=['GET', 'POST'])
|
||||||
@app.route('/<userkey>/<show_as>/filter/<filtermethod>', methods=['GET', 'POST'])
|
@app.route('/<user_key>/<show_as>/filter/<filtermethod>', methods=['GET', 'POST'])
|
||||||
@app.route('/<userkey>/<show_as>/sort/<sortmethod>', methods=['GET', 'POST'])
|
@app.route('/<user_key>/<show_as>/sort/<sortmethod>', methods=['GET', 'POST'])
|
||||||
def bookmarks_page(request: Request, userkey, filtermethod=None, sortmethod=None, show_as='cards'):
|
def bookmarks_page(request: Request, user_key, filter_method=None, sort_method=None, show_as='cards'):
|
||||||
bookmarks, bookmarktags, filter_text, message = get_bookmarks(request, userkey, filtermethod, sortmethod)
|
bookmarks, bookmarktags, filter_text, message = get_bookmarks(request, user_key, filter_method, sort_method)
|
||||||
theme = get_theme(userkey)
|
theme = get_theme(user_key)
|
||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
'bookmarks.html',
|
'bookmarks.html',
|
||||||
bookmarks=bookmarks,
|
bookmarks=bookmarks,
|
||||||
userkey=userkey,
|
userkey=user_key,
|
||||||
tags=bookmarktags,
|
tags=bookmarktags,
|
||||||
filter_text=filter_text,
|
filter_text=filter_text,
|
||||||
message=message,
|
message=message,
|
||||||
theme=theme,
|
theme=theme,
|
||||||
editable=True, # bookmarks can be edited
|
editable=True, # bookmarks can be edited
|
||||||
showtags=True, # tags should be shown with the bookmarks
|
showtags=True, # tags should be shown with the bookmarks
|
||||||
filtermethod=filtermethod,
|
filtermethod=filter_method,
|
||||||
sortmethod=sortmethod,
|
sortmethod=sort_method,
|
||||||
show_as=show_as, # show list of bookmarks instead of cards
|
show_as=show_as, # show list of bookmarks instead of cards
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get('/<userkey>/js')
|
@app.get('/{user_key}/js')
|
||||||
def bookmarks_js(userkey):
|
def bookmarks_js(user_key):
|
||||||
""" Return list of bookmarks with their favicons, to be used for autocompletion """
|
"""Return list of bookmarks with their favicons, to be used for autocompletion"""
|
||||||
bookmarks = Bookmark.select().where(
|
bookmarks = (
|
||||||
Bookmark.userkey == userkey,
|
Bookmark.select()
|
||||||
Bookmark.status == Bookmark.VISIBLE
|
.where(Bookmark.userkey == user_key, Bookmark.status == Bookmark.VISIBLE)
|
||||||
).order_by(Bookmark.created_date.desc())
|
.order_by(Bookmark.created_date.desc())
|
||||||
|
)
|
||||||
result = []
|
result = []
|
||||||
for bookmark in bookmarks:
|
for bookmark in bookmarks:
|
||||||
result.append({'title': bookmark.title})
|
result.append({'title': bookmark.title})
|
||||||
@@ -521,13 +545,11 @@ def bookmarks_js(userkey):
|
|||||||
|
|
||||||
@app.get('/r/<userkey>/<urlhash>', response_class=HTMLResponse)
|
@app.get('/r/<userkey>/<urlhash>', response_class=HTMLResponse)
|
||||||
def bookmark_redirect(userkey, urlhash):
|
def bookmark_redirect(userkey, urlhash):
|
||||||
""" Securely redirect a bookmark to its url, stripping referrer (if browser plays nice) """
|
"""Securely redirect a bookmark to its url, stripping referrer (if browser plays nice)"""
|
||||||
# @TODO: add counter to this bookmark
|
# @TODO: add counter to this bookmark
|
||||||
try:
|
try:
|
||||||
bookmark = Bookmark.get(
|
bookmark = Bookmark.get(
|
||||||
Bookmark.url_hash == urlhash,
|
Bookmark.url_hash == urlhash, Bookmark.userkey == userkey, Bookmark.status == Bookmark.VISIBLE
|
||||||
Bookmark.userkey == userkey,
|
|
||||||
Bookmark.status == Bookmark.VISIBLE
|
|
||||||
)
|
)
|
||||||
except Bookmark.DoesNotExist:
|
except Bookmark.DoesNotExist:
|
||||||
raise HTTPException(status_code=404, detail='Bookmark not found')
|
raise HTTPException(status_code=404, detail='Bookmark not found')
|
||||||
@@ -554,20 +576,19 @@ def bookmarks_json(request: Request, userkey, filtermethod=None, sortmethod=None
|
|||||||
|
|
||||||
@app.route('/api/v1/<userkey>/<urlhash>')
|
@app.route('/api/v1/<userkey>/<urlhash>')
|
||||||
def bookmark_json(userkey, urlhash):
|
def bookmark_json(userkey, urlhash):
|
||||||
""" Serialise bookmark to json """
|
"""Serialise bookmark to json"""
|
||||||
try:
|
try:
|
||||||
bookmark = Bookmark.get(
|
bookmark = Bookmark.get(
|
||||||
Bookmark.url_hash == urlhash,
|
Bookmark.url_hash == urlhash, Bookmark.userkey == userkey, Bookmark.status == Bookmark.VISIBLE
|
||||||
Bookmark.userkey == userkey,
|
|
||||||
Bookmark.status == Bookmark.VISIBLE
|
|
||||||
)
|
)
|
||||||
return bookmark.to_dict()
|
return bookmark.to_dict()
|
||||||
except Bookmark.DoesNotExist:
|
except Bookmark.DoesNotExist:
|
||||||
raise HTTPException(status_code=404, detail='Bookmark not found')
|
raise HTTPException(status_code=404, detail='Bookmark not found')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/v1/<userkey>/search/<filter_text>')
|
@app.route('/api/v1/<userkey>/search/<filter_text>')
|
||||||
def search_bookmark_titles_json(userkey, filter_text):
|
def search_bookmark_titles_json(userkey, filter_text):
|
||||||
""" Serialise bookmark to json """
|
"""Serialise bookmark to json"""
|
||||||
bookmarks = _find_bookmarks(userkey, filter_text)
|
bookmarks = _find_bookmarks(userkey, filter_text)
|
||||||
result = []
|
result = []
|
||||||
for bookmark in bookmarks:
|
for bookmark in bookmarks:
|
||||||
@@ -578,7 +599,7 @@ def search_bookmark_titles_json(userkey, filter_text):
|
|||||||
@app.get('/<userkey>/<urlhash>', response_class=HTMLResponse)
|
@app.get('/<userkey>/<urlhash>', response_class=HTMLResponse)
|
||||||
@app.get('/<userkey>/<urlhash>/edit', response_class=HTMLResponse)
|
@app.get('/<userkey>/<urlhash>/edit', response_class=HTMLResponse)
|
||||||
def editbookmark(request: Request, userkey, urlhash):
|
def editbookmark(request: Request, userkey, urlhash):
|
||||||
""" Bookmark edit form """
|
"""Bookmark edit form"""
|
||||||
# bookmark = getbyurlhash()
|
# bookmark = getbyurlhash()
|
||||||
try:
|
try:
|
||||||
bookmark = Bookmark.get(Bookmark.url_hash == urlhash, Bookmark.userkey == userkey)
|
bookmark = Bookmark.get(Bookmark.url_hash == urlhash, Bookmark.userkey == userkey)
|
||||||
@@ -598,13 +619,13 @@ def editbookmark(request: Request, userkey, urlhash):
|
|||||||
message=message,
|
message=message,
|
||||||
formaction='edit',
|
formaction='edit',
|
||||||
tags=tags,
|
tags=tags,
|
||||||
theme=theme
|
theme=theme,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get('/<userkey>/add', response_class=HTMLResponse)
|
@app.get('/<userkey>/add', response_class=HTMLResponse)
|
||||||
def addbookmark(request: Request, userkey):
|
def addbookmark(request: Request, userkey):
|
||||||
""" Bookmark add form """
|
"""Bookmark add form"""
|
||||||
url = request.args.get('url')
|
url = request.args.get('url')
|
||||||
if not url:
|
if not url:
|
||||||
url = ''
|
url = ''
|
||||||
@@ -615,18 +636,12 @@ def addbookmark(request: Request, userkey):
|
|||||||
tags = get_cached_tags(userkey)
|
tags = get_cached_tags(userkey)
|
||||||
theme = get_theme(userkey)
|
theme = get_theme(userkey)
|
||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
'edit.html',
|
'edit.html', action='Add bookmark', userkey=userkey, bookmark=bookmark, tags=tags, message=message, theme=theme
|
||||||
action='Add bookmark',
|
|
||||||
userkey=userkey,
|
|
||||||
bookmark=bookmark,
|
|
||||||
tags=tags,
|
|
||||||
message=message,
|
|
||||||
theme=theme
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def updatebookmark(request: Request, userkey, urlhash=None):
|
def updatebookmark(request: Request, userkey, urlhash=None):
|
||||||
""" Add (no urlhash) or edit (urlhash is set) a bookmark """
|
"""Add (no urlhash) or edit (urlhash is set) a bookmark"""
|
||||||
title = request.form.get('title')
|
title = request.form.get('title')
|
||||||
url = request.form.get('url')
|
url = request.form.get('url')
|
||||||
tags = request.form.get('tags')
|
tags = request.form.get('tags')
|
||||||
@@ -643,7 +658,9 @@ def updatebookmark(request: Request, userkey, urlhash=None):
|
|||||||
bookmark, created = Bookmark.get_or_create(url=url, userkey=userkey)
|
bookmark, created = Bookmark.get_or_create(url=url, userkey=userkey)
|
||||||
if not created:
|
if not created:
|
||||||
message = 'Existing bookmark, did not overwrite with new values'
|
message = 'Existing bookmark, did not overwrite with new values'
|
||||||
return RedirectResponse(request.url_for('editbookmark', userkey=userkey, urlhash=bookmark.url_hash, message=message))
|
return RedirectResponse(
|
||||||
|
request.url_for('editbookmark', userkey=userkey, urlhash=bookmark.url_hash, message=message)
|
||||||
|
)
|
||||||
elif url:
|
elif url:
|
||||||
# Existing bookmark, get from DB
|
# Existing bookmark, get from DB
|
||||||
bookmark = Bookmark.get(Bookmark.userkey == userkey, Bookmark.url_hash == urlhash)
|
bookmark = Bookmark.get(Bookmark.userkey == userkey, Bookmark.url_hash == urlhash)
|
||||||
@@ -661,7 +678,7 @@ def updatebookmark(request: Request, userkey, urlhash=None):
|
|||||||
bookmark.set_tags(tags)
|
bookmark.set_tags(tags)
|
||||||
bookmark.note = note
|
bookmark.note = note
|
||||||
bookmark.set_hash()
|
bookmark.set_hash()
|
||||||
#bookmark.fetch_image()
|
# bookmark.fetch_image()
|
||||||
if not title:
|
if not title:
|
||||||
# Title was empty, automatically fetch it from the url, will also update the status code
|
# Title was empty, automatically fetch it from the url, will also update the status code
|
||||||
bookmark.set_title_from_source()
|
bookmark.set_title_from_source()
|
||||||
@@ -680,26 +697,27 @@ def updatebookmark(request: Request, userkey, urlhash=None):
|
|||||||
|
|
||||||
|
|
||||||
@app.route('/<userkey>/adding', methods=['GET', 'POST'])
|
@app.route('/<userkey>/adding', methods=['GET', 'POST'])
|
||||||
#@app.route('/<userkey>/adding')
|
# @app.route('/<userkey>/adding')
|
||||||
def addingbookmark(request: Request, userkey):
|
def adding_bookmark(request: Request, user_key):
|
||||||
""" Add the bookmark from form submit by /add """
|
"""Add the bookmark from form submit by /add"""
|
||||||
tags = get_cached_tags(userkey)
|
tags = get_cached_tags(user_key)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
bookmark = updatebookmark(request, userkey)
|
bookmark = updatebookmark(request, user_key)
|
||||||
if not bookmark:
|
if not bookmark:
|
||||||
return RedirectResponse(request.url_for('addbookmark', userkey=userkey, message='No url provided', tags=tags))
|
return RedirectResponse(
|
||||||
|
request.url_for('addbookmark', userkey=user_key, message='No url provided', tags=tags)
|
||||||
|
)
|
||||||
if type(bookmark).__name__ == 'Response':
|
if type(bookmark).__name__ == 'Response':
|
||||||
return bookmark
|
return bookmark
|
||||||
all_tags[userkey] = get_tags_for_user(userkey)
|
all_tags[user_key] = get_tags_for_user(user_key)
|
||||||
return RedirectResponse(request.url_for('editbookmark', userkey=userkey, urlhash=bookmark.url_hash))
|
return RedirectResponse(request.url_for('editbookmark', userkey=user_key, urlhash=bookmark.url_hash))
|
||||||
return RedirectResponse(request.url_for('addbookmark', userkey=userkey, tags=tags))
|
return RedirectResponse(request.url_for('addbookmark', userkey=user_key, tags=tags))
|
||||||
|
|
||||||
|
|
||||||
@app.route('/<userkey>/<urlhash>/editing', methods=['GET', 'POST'])
|
@app.route('/<userkey>/<urlhash>/editing', methods=['GET', 'POST'])
|
||||||
def editingbookmark(request: Request, userkey, urlhash):
|
def editingbookmark(request: Request, userkey, urlhash):
|
||||||
""" Edit the bookmark from form submit """
|
"""Edit the bookmark from form submit"""
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
bookmark = updatebookmark(request, userkey, urlhash=urlhash)
|
bookmark = updatebookmark(request, userkey, urlhash=urlhash)
|
||||||
all_tags[userkey] = get_tags_for_user(userkey)
|
all_tags[userkey] = get_tags_for_user(userkey)
|
||||||
@@ -709,26 +727,23 @@ def editingbookmark(request: Request, userkey, urlhash):
|
|||||||
|
|
||||||
@app.route('/<userkey>/<urlhash>/delete', methods=['GET', 'POST'])
|
@app.route('/<userkey>/<urlhash>/delete', methods=['GET', 'POST'])
|
||||||
def deletingbookmark(request: Request, userkey, urlhash):
|
def deletingbookmark(request: Request, userkey, urlhash):
|
||||||
""" Delete the bookmark from form submit by <urlhash>/delete """
|
"""Delete the bookmark from form submit by <urlhash>/delete"""
|
||||||
query = Bookmark.update(status=Bookmark.DELETED).where(Bookmark.userkey == userkey, Bookmark.url_hash == urlhash)
|
query = Bookmark.update(status=Bookmark.DELETED).where(Bookmark.userkey == userkey, Bookmark.url_hash == urlhash)
|
||||||
query.execute()
|
query.execute()
|
||||||
query = Bookmark.update(deleted_date=datetime.datetime.now()).where(
|
query = Bookmark.update(deleted_date=datetime.datetime.now()).where(
|
||||||
Bookmark.userkey == userkey,
|
Bookmark.userkey == userkey, Bookmark.url_hash == urlhash
|
||||||
Bookmark.url_hash == urlhash
|
|
||||||
)
|
)
|
||||||
query.execute()
|
query.execute()
|
||||||
message = 'Bookmark deleted. <a href="{}">Undo deletion</a>'.format(request.url_for(
|
message = 'Bookmark deleted. <a href="{}">Undo deletion</a>'.format(
|
||||||
'undeletebookmark',
|
request.url_for('undeletebookmark', userkey=userkey, urlhash=urlhash)
|
||||||
userkey=userkey,
|
)
|
||||||
urlhash=urlhash
|
|
||||||
))
|
|
||||||
all_tags[userkey] = get_tags_for_user(userkey)
|
all_tags[userkey] = get_tags_for_user(userkey)
|
||||||
return RedirectResponse(request.url_for('bookmarks_page', userkey=userkey, message=message))
|
return RedirectResponse(request.url_for('bookmarks_page', userkey=userkey, message=message))
|
||||||
|
|
||||||
|
|
||||||
@app.get('/<userkey>/<urlhash>/undelete')
|
@app.get('/<userkey>/<urlhash>/undelete')
|
||||||
def undeletebookmark(request: Request, userkey, urlhash):
|
def undeletebookmark(request: Request, userkey, urlhash):
|
||||||
""" Undo deletion of the bookmark identified by urlhash """
|
"""Undo deletion of the bookmark identified by urlhash"""
|
||||||
query = Bookmark.update(status=Bookmark.VISIBLE).where(Bookmark.userkey == userkey, Bookmark.url_hash == urlhash)
|
query = Bookmark.update(status=Bookmark.VISIBLE).where(Bookmark.userkey == userkey, Bookmark.url_hash == urlhash)
|
||||||
query.execute()
|
query.execute()
|
||||||
message = 'Bookmark restored'
|
message = 'Bookmark restored'
|
||||||
@@ -738,9 +753,9 @@ def undeletebookmark(request: Request, userkey, urlhash):
|
|||||||
|
|
||||||
@app.get('/<userkey>/tags', response_class=HTMLResponse)
|
@app.get('/<userkey>/tags', response_class=HTMLResponse)
|
||||||
def tags_page(userkey):
|
def tags_page(userkey):
|
||||||
""" Overview of all tags used by user """
|
"""Overview of all tags used by user"""
|
||||||
tags = get_cached_tags(userkey)
|
tags = get_cached_tags(userkey)
|
||||||
#publictags = PublicTag.select().where(Bookmark.userkey == userkey)
|
# publictags = PublicTag.select().where(Bookmark.userkey == userkey)
|
||||||
alltags = []
|
alltags = []
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
try:
|
try:
|
||||||
@@ -748,11 +763,11 @@ def tags_page(userkey):
|
|||||||
except PublicTag.DoesNotExist:
|
except PublicTag.DoesNotExist:
|
||||||
publictag = None
|
publictag = None
|
||||||
|
|
||||||
total = Bookmark.select().where(
|
total = (
|
||||||
Bookmark.userkey == userkey,
|
Bookmark.select()
|
||||||
Bookmark.tags.contains(tag),
|
.where(Bookmark.userkey == userkey, Bookmark.tags.contains(tag), Bookmark.status == Bookmark.VISIBLE)
|
||||||
Bookmark.status == Bookmark.VISIBLE
|
.count()
|
||||||
).count()
|
)
|
||||||
alltags.append({'tag': tag, 'publictag': publictag, 'total': total})
|
alltags.append({'tag': tag, 'publictag': publictag, 'total': total})
|
||||||
totaltags = len(alltags)
|
totaltags = len(alltags)
|
||||||
totalbookmarks = Bookmark.select().where(Bookmark.userkey == userkey, Bookmark.status == Bookmark.VISIBLE).count()
|
totalbookmarks = Bookmark.select().where(Bookmark.userkey == userkey, Bookmark.status == Bookmark.VISIBLE).count()
|
||||||
@@ -773,18 +788,18 @@ def tags_page(userkey):
|
|||||||
totalhttperrorstatus=totalhttperrorstatus,
|
totalhttperrorstatus=totalhttperrorstatus,
|
||||||
totalnotes=totalnotes,
|
totalnotes=totalnotes,
|
||||||
userkey=userkey,
|
userkey=userkey,
|
||||||
theme=theme
|
theme=theme,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get('/<userkey>/tag/<tag>', response_class=HTMLResponse)
|
@app.get('/<userkey>/tag/<tag>', response_class=HTMLResponse)
|
||||||
def tag_page(request: Request, userkey, tag):
|
def tag_page(request: Request, userkey, tag):
|
||||||
""" Overview of all bookmarks with a certain tag """
|
"""Overview of all bookmarks with a certain tag"""
|
||||||
bookmarks = Bookmark.select().where(
|
bookmarks = (
|
||||||
Bookmark.userkey == userkey,
|
Bookmark.select()
|
||||||
Bookmark.tags.contains(tag),
|
.where(Bookmark.userkey == userkey, Bookmark.tags.contains(tag), Bookmark.status == Bookmark.VISIBLE)
|
||||||
Bookmark.status == Bookmark.VISIBLE
|
.order_by(Bookmark.created_date.desc())
|
||||||
).order_by(Bookmark.created_date.desc())
|
)
|
||||||
tags = get_cached_tags(userkey)
|
tags = get_cached_tags(userkey)
|
||||||
pageheader = 'tag: ' + tag
|
pageheader = 'tag: ' + tag
|
||||||
message = request.args.get('message')
|
message = request.args.get('message')
|
||||||
@@ -811,20 +826,24 @@ def tag_page(request: Request, userkey, tag):
|
|||||||
|
|
||||||
|
|
||||||
def get_publictag(tagkey):
|
def get_publictag(tagkey):
|
||||||
""" Return tag and bookmarks in this public tag collection """
|
"""Return tag and bookmarks in this public tag collection"""
|
||||||
this_tag = PublicTag.get(PublicTag.tagkey == tagkey)
|
this_tag = PublicTag.get(PublicTag.tagkey == tagkey)
|
||||||
bookmarks = Bookmark.select().where(
|
bookmarks = (
|
||||||
|
Bookmark.select()
|
||||||
|
.where(
|
||||||
Bookmark.userkey == this_tag.userkey,
|
Bookmark.userkey == this_tag.userkey,
|
||||||
Bookmark.tags.contains(this_tag.tag),
|
Bookmark.tags.contains(this_tag.tag),
|
||||||
Bookmark.status == Bookmark.VISIBLE
|
Bookmark.status == Bookmark.VISIBLE,
|
||||||
).order_by(Bookmark.created_date.desc())
|
)
|
||||||
|
.order_by(Bookmark.created_date.desc())
|
||||||
|
)
|
||||||
return this_tag, bookmarks
|
return this_tag, bookmarks
|
||||||
|
|
||||||
|
|
||||||
@app.get('/pub/<tagkey>', response_class=HTMLResponse)
|
@app.get('/pub/<tagkey>', response_class=HTMLResponse)
|
||||||
def publictag_page(tagkey):
|
def publictag_page(tagkey):
|
||||||
""" Read-only overview of the bookmarks in the userkey/tag of this PublicTag """
|
"""Read-only overview of the bookmarks in the userkey/tag of this PublicTag"""
|
||||||
#this_tag = get_object_or_404(PublicTag.select().where(PublicTag.tagkey == tagkey))
|
# this_tag = get_object_or_404(PublicTag.select().where(PublicTag.tagkey == tagkey))
|
||||||
try:
|
try:
|
||||||
this_tag, bookmarks = get_publictag(tagkey)
|
this_tag, bookmarks = get_publictag(tagkey)
|
||||||
# theme = themes[DEFAULT_THEME]
|
# theme = themes[DEFAULT_THEME]
|
||||||
@@ -835,7 +854,7 @@ def publictag_page(tagkey):
|
|||||||
tag=this_tag.tag,
|
tag=this_tag.tag,
|
||||||
action=this_tag.tag,
|
action=this_tag.tag,
|
||||||
tagkey=tagkey,
|
tagkey=tagkey,
|
||||||
theme=theme
|
theme=theme,
|
||||||
)
|
)
|
||||||
except PublicTag.DoesNotExist:
|
except PublicTag.DoesNotExist:
|
||||||
raise HTTPException(status_code=404, detail='Public tag not found')
|
raise HTTPException(status_code=404, detail='Public tag not found')
|
||||||
@@ -843,7 +862,7 @@ def publictag_page(tagkey):
|
|||||||
|
|
||||||
@app.route('/api/v1/pub/<tagkey>')
|
@app.route('/api/v1/pub/<tagkey>')
|
||||||
def publictag_json(tagkey):
|
def publictag_json(tagkey):
|
||||||
""" json representation of the Read-only overview of the bookmarks in the userkey/tag of this PublicTag """
|
"""Json representation of the Read-only overview of the bookmarks in the userkey/tag of this PublicTag"""
|
||||||
try:
|
try:
|
||||||
this_tag, bookmarks = get_publictag(tagkey)
|
this_tag, bookmarks = get_publictag(tagkey)
|
||||||
result = {
|
result = {
|
||||||
@@ -861,13 +880,13 @@ def publictag_json(tagkey):
|
|||||||
|
|
||||||
@app.get('/pub/<tagkey>/feed')
|
@app.get('/pub/<tagkey>/feed')
|
||||||
async def publictag_feed(request: Request, tagkey: str):
|
async def publictag_feed(request: Request, tagkey: str):
|
||||||
""" rss/atom representation of the Read-only overview of the bookmarks in the userkey/tag of this PublicTag """
|
"""rss/atom representation of the Read-only overview of the bookmarks in the userkey/tag of this PublicTag"""
|
||||||
try:
|
try:
|
||||||
this_tag = PublicTag.get(PublicTag.tagkey == tagkey)
|
this_tag = PublicTag.get(PublicTag.tagkey == tagkey)
|
||||||
bookmarks = Bookmark.select().where(
|
bookmarks = Bookmark.select().where(
|
||||||
Bookmark.userkey == this_tag.userkey,
|
Bookmark.userkey == this_tag.userkey,
|
||||||
Bookmark.tags.contains(this_tag.tag),
|
Bookmark.tags.contains(this_tag.tag),
|
||||||
Bookmark.status == Bookmark.VISIBLE
|
Bookmark.status == Bookmark.VISIBLE,
|
||||||
)
|
)
|
||||||
|
|
||||||
feed = FeedGenerator()
|
feed = FeedGenerator()
|
||||||
@@ -942,7 +961,7 @@ def removepublictag(request: Request, userkey, tag, tagkey):
|
|||||||
|
|
||||||
@app.route('/<systemkey>/adduser')
|
@app.route('/<systemkey>/adduser')
|
||||||
def adduser(systemkey):
|
def adduser(systemkey):
|
||||||
""" Add user endpoint, convenience """
|
"""Add user endpoint, convenience"""
|
||||||
if systemkey == settings.SYSTEMKEY:
|
if systemkey == settings.SYSTEMKEY:
|
||||||
newuser = User()
|
newuser = User()
|
||||||
newuser.generate_key()
|
newuser.generate_key()
|
||||||
@@ -951,12 +970,12 @@ def adduser(systemkey):
|
|||||||
all_tags[newuser.key] = []
|
all_tags[newuser.key] = []
|
||||||
return {'user': f'/{newuser.key.decode("utf-8")}'}
|
return {'user': f'/{newuser.key.decode("utf-8")}'}
|
||||||
else:
|
else:
|
||||||
raise HTTPException(status_code=404, detail='I can''t let you do that Dave')
|
raise HTTPException(status_code=404, detail='I can\'t let you do that Dave')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/<systemkey>/refreshfavicons')
|
@app.route('/<systemkey>/refreshfavicons')
|
||||||
def refreshfavicons(systemkey):
|
def refreshfavicons(systemkey):
|
||||||
""" Add user endpoint, convenience """
|
"""Add user endpoint, convenience"""
|
||||||
if systemkey == settings.SYSTEMKEY:
|
if systemkey == settings.SYSTEMKEY:
|
||||||
bookmarks = Bookmark.select()
|
bookmarks = Bookmark.select()
|
||||||
for bookmark in bookmarks:
|
for bookmark in bookmarks:
|
||||||
@@ -969,17 +988,19 @@ def refreshfavicons(systemkey):
|
|||||||
bookmark.set_favicon()
|
bookmark.set_favicon()
|
||||||
return {'message': 'Done refreshing icons'}
|
return {'message': 'Done refreshing icons'}
|
||||||
else:
|
else:
|
||||||
raise HTTPException(status_code=404, detail='I can''t let you do that Dave')
|
raise HTTPException(status_code=404, detail='I can\'t let you do that Dave')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/<systemkey>/findmissingfavicons')
|
@app.route('/<systemkey>/findmissingfavicons')
|
||||||
def findmissingfavicons(systemkey):
|
def findmissingfavicons(systemkey):
|
||||||
""" Add user endpoint, convenience """
|
"""Add user endpoint, convenience"""
|
||||||
if systemkey == settings.SYSTEMKEY:
|
if systemkey == settings.SYSTEMKEY:
|
||||||
bookmarks = Bookmark.select()
|
bookmarks = Bookmark.select()
|
||||||
for bookmark in bookmarks:
|
for bookmark in bookmarks:
|
||||||
try:
|
try:
|
||||||
if not bookmark.favicon or not os.path.isfile(os.path.join(settings.media_dir, 'favicons', bookmark.favicon)):
|
if not bookmark.favicon or not os.path.isfile(
|
||||||
|
os.path.join(settings.media_dir, 'favicons', bookmark.favicon)
|
||||||
|
):
|
||||||
# This favicon is missing
|
# This favicon is missing
|
||||||
# Clear favicon, so fallback can be used instead of showing a broken image
|
# Clear favicon, so fallback can be used instead of showing a broken image
|
||||||
bookmark.favicon = None
|
bookmark.favicon = None
|
||||||
@@ -991,22 +1012,23 @@ def findmissingfavicons(systemkey):
|
|||||||
print(e)
|
print(e)
|
||||||
return {'message': 'Done finding missing icons'}
|
return {'message': 'Done finding missing icons'}
|
||||||
else:
|
else:
|
||||||
raise HTTPException(status_code=404, detail='I can''t let you do that Dave')
|
raise HTTPException(status_code=404, detail='I can\'t let you do that Dave')
|
||||||
|
|
||||||
|
|
||||||
# Initialisation == create the bookmark, user and public tag tables if they do not exist
|
# Initialisation == create the bookmark, user and public tag tables if they do not exist
|
||||||
Bookmark.create_table(True)
|
# TODO: switch to alembic migrations
|
||||||
User.create_table(True)
|
# Bookmark.create_table(True)
|
||||||
PublicTag.create_table(True)
|
# User.create_table(True)
|
||||||
|
# PublicTag.create_table(True)
|
||||||
|
|
||||||
users = User.select()
|
# users = User.select()
|
||||||
print('Current user keys:')
|
# print('Current user keys:')
|
||||||
for user in users:
|
# for user in users:
|
||||||
all_tags[user.key] = get_tags_for_user(user.key)
|
# all_tags[user.key] = get_tags_for_user(user.key)
|
||||||
usersettings[user.key] = {'theme': user.theme}
|
# usersettings[user.key] = {'theme': user.theme}
|
||||||
print(user.key)
|
# print(user.key)
|
||||||
|
|
||||||
# Run when called standalone
|
# Run when called standalone
|
||||||
if __name__ == '__main__':
|
# if __name__ == '__main__':
|
||||||
# run the application
|
# run the application
|
||||||
app.run(host='0.0.0.0', port=9999, debug=True)
|
# app.run(host='0.0.0.0', port=9999, debug=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user