diff --git a/Dockerfile b/Dockerfile index 014b78b..f16bc2c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,6 @@ +# Copyright © 2026 Olaf Kolkman +# SPDX-License-Identifier: GPL-3.0-or-later + FROM python:3.11-slim WORKDIR /app diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f93f9a4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,12 @@ +LinkLog is licensed under the GNU General Public License, version 3 or any later version (GPL-3.0-or-later). + +Copyright (C) 2026 Olaf Kolkman + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program. If not, see . + +The complete license text is available at: +https://www.gnu.org/licenses/gpl-3.0.html diff --git a/LinkLog.svg b/LinkLog.svg index ee95617..f87aede 100644 --- a/LinkLog.svg +++ b/LinkLog.svg @@ -1,4 +1,6 @@ + + diff --git a/Makefile b/Makefile index bf616bd..e88d081 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,6 @@ +# Copyright © 2026 Olaf Kolkman +# SPDX-License-Identifier: GPL-3.0-or-later + SHELL := /bin/sh SOURCE_LOGO := LinkLog.svg diff --git a/README.md b/README.md index 81a6c9a..4b6d0d0 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ For local development: The backend currently uses FastAPI, uvicorn, SQLite, and Pydantic. `httpx2` is included for the Starlette-compatible test client. Jinja2 is included for server-rendered HTML templates. +LinkLog is licensed under the GNU General Public License, version 3 or any later version. See [LICENSE](LICENSE). ## Local Installation @@ -71,6 +72,7 @@ Open these URLs: - User feed: - Profile settings: - Labels: +- About: - Admin page: - Web login: - Health check: diff --git a/VIBE/CHAT_LOG.md b/VIBE/CHAT_LOG.md index a05d127..9fcf775 100644 --- a/VIBE/CHAT_LOG.md +++ b/VIBE/CHAT_LOG.md @@ -451,3 +451,45 @@ Use the Asset Font from google foundry as font for the LinkLog text ### Assistant outcome Applied the Google Foundry `Asset` font to visible LinkLog branding on the web and Firefox popup, retaining graceful local fallbacks for restricted or offline extension contexts. Font declarations, branding references, extension scripts, whitespace checks, and the strict backend suite passed. + +### User +Create an about page and add an entry in the hamburger menu. The about page explains what the linklog does + +### Assistant outcome +Added an `/about` page explaining LinkLog's link capture, cleanup, tagging, filtering, ownership, and Mastodon publishing workflow. Added an always-visible About item to every shared hamburger menu, documented the route, and verified all web routes, scripts, and the strict backend suite with 15 passing tests. + +### User +On the bottom of all files add a copyright statement (Olaf Kolkman) and a link to the git.kolkman.org/LinkLog repository in small print + +### Assistant outcome +Added small-print attribution footers to all seven web templates and both Firefox extension pages. Each footer contains `Copyright Olaf Kolkman` and a link to `https://git.kolkman.org/olaf/Link-Log`, with matching web and extension styling. All web routes, extension footer references, strict backend tests, and whitespace checks passed. + +### User +the link in the site footer must be underlined and in the same color as the other text + +### Assistant outcome +Updated the web footer repository link to remain the same muted color as the surrounding footer text and always display an underline. Added a footer rendering assertion and validated the site. + +### User +Add copyright sign and 2026 to the copyright notices + +### Assistant outcome +Updated all web and Firefox extension footer notices to `© 2026 Olaf Kolkman`, preserving the repository links and small-print styling. Verified all eight user-facing pages, whitespace, and the strict backend suite with 15 passing tests. + +### User +in the footer make the link the same color as the mother text, when clicked use a tint from the Catpuccin theme + +### Assistant outcome +Updated web and extension footer links to inherit the surrounding footer text color, remain underlined, and use Catppuccin lavender/mauve interaction tints for hover, focus, and active click states. Preserved the current repository URL edits and verified the strict backend suite with 15 passing tests. + +### User +Add a GNU License file + +### Assistant outcome +Added a root `LICENSE` file declaring GNU General Public License version 3 or any later version (GPL-3.0-or-later), with Olaf Kolkman copyright attribution and the official GNU license reference. Documented the license in `README.md`. + +### User +Add a copyright statement to source files refer to GNU license + +### Assistant outcome +Added `Copyright © 2026 Olaf Kolkman` and `SPDX-License-Identifier: GPL-3.0-or-later` headers to all 47 non-minified application, test, frontend, extension, build, deployment, and source-logo files. Generated/runtime assets were left untouched. Python and JavaScript compilation, Compose validation, whitespace checks, and the strict backend suite passed with 15 tests. diff --git a/VIBE/PROMPTS.md b/VIBE/PROMPTS.md index 13439ad..856116c 100644 --- a/VIBE/PROMPTS.md +++ b/VIBE/PROMPTS.md @@ -78,6 +78,13 @@ 74. Refine the Plugins Settings page. When the user is logged in it shows all " logged in at " and a sign-out button. If the user is not logged in it shows the form as is now. 75. On the plugin, next to the logo, create a link of the form: [LinkLog](https:///) 76. Use the Asset Font from google foundry as font for the LinkLog text +77. Create an about page and add an entry in the hamburger menu. The about page explains what the linklog does +78. On the bottom of all files add a copyright statement (Olaf Kolkman) and a link to the git.kolkman.org/LinkLog repository in small print +79. the link in the site footer must be underlined and in the same color as the other text +80. Add copyright sign and 2026 to the copyright notices +81. in the footer make the link the same color as the mother text, when clicked use a tint from the Catpuccin theme +82. Add a GNU License file +83. Add a copyright statement to source files refer to GNU license ## Future entries diff --git a/backend/app/__init__.py b/backend/app/__init__.py index 9cb47c3..72d2480 100644 --- a/backend/app/__init__.py +++ b/backend/app/__init__.py @@ -1 +1,4 @@ """LinkLog backend package.""" + +# Copyright © 2026 Olaf Kolkman +# SPDX-License-Identifier: GPL-3.0-or-later diff --git a/backend/app/admin_page.py b/backend/app/admin_page.py index 374bfe8..508b94d 100644 --- a/backend/app/admin_page.py +++ b/backend/app/admin_page.py @@ -1,3 +1,8 @@ +"""Legacy admin page wiring.""" + +# Copyright © 2026 Olaf Kolkman +# SPDX-License-Identifier: GPL-3.0-or-later + from fastapi import FastAPI from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates diff --git a/backend/app/api/admin.py b/backend/app/api/admin.py index 4497103..b71390e 100644 --- a/backend/app/api/admin.py +++ b/backend/app/api/admin.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + import json from uuid import uuid4 diff --git a/backend/app/api/auth.py b/backend/app/api/auth.py index 940133e..f343c9d 100644 --- a/backend/app/api/auth.py +++ b/backend/app/api/auth.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from uuid import uuid4 from fastapi import APIRouter, HTTPException diff --git a/backend/app/api/dependencies.py b/backend/app/api/dependencies.py index a6aeb46..3edc030 100644 --- a/backend/app/api/dependencies.py +++ b/backend/app/api/dependencies.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from fastapi import Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer diff --git a/backend/app/api/links.py b/backend/app/api/links.py index 2c7e7ac..1b1ca51 100644 --- a/backend/app/api/links.py +++ b/backend/app/api/links.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from fastapi import APIRouter, Header, HTTPException, status from pydantic import BaseModel diff --git a/backend/app/api/public.py b/backend/app/api/public.py index ccba0f1..ec075b3 100644 --- a/backend/app/api/public.py +++ b/backend/app/api/public.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from fastapi import APIRouter, Depends from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer diff --git a/backend/app/api/user_config.py b/backend/app/api/user_config.py index 0e3a406..83f778d 100644 --- a/backend/app/api/user_config.py +++ b/backend/app/api/user_config.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + import json from uuid import uuid4 diff --git a/backend/app/core/config.py b/backend/app/core/config.py index 8b502d0..269ba28 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from dataclasses import dataclass import os from pathlib import Path diff --git a/backend/app/core/security.py b/backend/app/core/security.py index 4ca0b20..beb4137 100644 --- a/backend/app/core/security.py +++ b/backend/app/core/security.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from datetime import datetime, timedelta, timezone from hashlib import sha256 diff --git a/backend/app/database.py b/backend/app/database.py index fa05d2b..ebfb4cb 100644 --- a/backend/app/database.py +++ b/backend/app/database.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + import sqlite3 import os from hashlib import sha256 diff --git a/backend/app/frontend.py b/backend/app/frontend.py index 4da2068..8b579fd 100644 --- a/backend/app/frontend.py +++ b/backend/app/frontend.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from fastapi import FastAPI from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles diff --git a/backend/app/main.py b/backend/app/main.py index 0ec2d17..b8ecd7e 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from fastapi import FastAPI from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles @@ -45,6 +48,11 @@ async def labels_page(request: Request): return templates.TemplateResponse(request, 'labels.html', {}) +@app.get('/about', response_class=HTMLResponse) +async def about_page(request: Request): + return templates.TemplateResponse(request, 'about.html', {}) + + @app.get('/login', response_class=HTMLResponse) async def login_page(request: Request): return templates.TemplateResponse(request, 'login.html', {}) diff --git a/backend/app/models/link.py b/backend/app/models/link.py index 8b1d86c..61c7d1c 100644 --- a/backend/app/models/link.py +++ b/backend/app/models/link.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from dataclasses import dataclass, field from datetime import datetime from typing import Optional diff --git a/backend/app/models/user.py b/backend/app/models/user.py index 295accf..3f3fefb 100644 --- a/backend/app/models/user.py +++ b/backend/app/models/user.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from dataclasses import dataclass from datetime import datetime from typing import Optional diff --git a/backend/app/plugins/base.py b/backend/app/plugins/base.py index fbd7426..4d960cb 100644 --- a/backend/app/plugins/base.py +++ b/backend/app/plugins/base.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + class BasePlugin: name = 'base' version = '1.0.0' diff --git a/backend/app/services/auth_service.py b/backend/app/services/auth_service.py index 177649f..a046d0f 100644 --- a/backend/app/services/auth_service.py +++ b/backend/app/services/auth_service.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from datetime import datetime, timezone from hashlib import sha256 diff --git a/backend/app/services/link_service.py b/backend/app/services/link_service.py index 8270ede..c2bd0a8 100644 --- a/backend/app/services/link_service.py +++ b/backend/app/services/link_service.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from datetime import datetime, timezone from uuid import uuid4 diff --git a/backend/app/services/plugin_manager.py b/backend/app/services/plugin_manager.py index a711ce8..3a612af 100644 --- a/backend/app/services/plugin_manager.py +++ b/backend/app/services/plugin_manager.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + import json from urllib.error import HTTPError, URLError from urllib.request import Request, urlopen diff --git a/backend/app/services/token_service.py b/backend/app/services/token_service.py index e542332..2fe9af3 100644 --- a/backend/app/services/token_service.py +++ b/backend/app/services/token_service.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from datetime import datetime, timezone from hashlib import sha256 from uuid import uuid4 diff --git a/backend/tests/test_api.py b/backend/tests/test_api.py index 78b92c0..1a1c518 100644 --- a/backend/tests/test_api.py +++ b/backend/tests/test_api.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + import json import threading from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer @@ -235,6 +238,8 @@ def test_public_and_admin_pages_render_html(): root_page = client.get('/') assert 'LinkLog' in root_page.text assert 'src="/static/logo.svg"' in root_page.text + assert 'class="site-footer"' in root_page.text + assert 'https://git.kolkman.org/' in root_page.text assert 'class="menu-toggle"' in root_page.text assert 'id="auth-menu" class="auth-menu hidden"' in root_page.text assert 'id="auth-home-link" href="/">Home' in root_page.text @@ -259,6 +264,10 @@ def test_public_and_admin_pages_render_html(): assert 'src="/static/logo.svg"' in login_page assert 'id="auth-session" class="auth-session hidden"' in login_page assert 'logout.js?v=3' in login_page + about_page = client.get('/about') + assert about_page.status_code == 200 + assert 'Save the good stuff' in about_page.text + assert 'id="auth-about-link" href="/about"' in about_page.text assert client.get('/admin').status_code == 200 admin_page = client.get('/admin').text assert 'Admin' in admin_page diff --git a/backend/tests/test_database.py b/backend/tests/test_database.py index e90fd56..4ca77fd 100644 --- a/backend/tests/test_database.py +++ b/backend/tests/test_database.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + import sqlite3 from backend.app.database import DEFAULT_TAGS, apply_migrations, get_schema_version, seed_default_tags diff --git a/backend/tests/test_user_config.py b/backend/tests/test_user_config.py index 301a615..0336a21 100644 --- a/backend/tests/test_user_config.py +++ b/backend/tests/test_user_config.py @@ -1,3 +1,6 @@ +## Copyright © 2026 Olaf Kolkman +## SPDX-License-Identifier: GPL-3.0-or-later + from fastapi.testclient import TestClient from backend.app.main import app diff --git a/docker-compose.yml b/docker-compose.yml index 40e5ac7..ffcfbb0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,6 @@ +# Copyright © 2026 Olaf Kolkman +# SPDX-License-Identifier: GPL-3.0-or-later + services: app: build: diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index b420948..0b3c745 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -1,4 +1,7 @@ #!/bin/sh +# Copyright © 2026 Olaf Kolkman +# SPDX-License-Identifier: GPL-3.0-or-later + set -eu chown -R linklog:linklog /app/backend/data diff --git a/frontend/static/admin.js b/frontend/static/admin.js index cdfb09d..2f2dd2e 100644 --- a/frontend/static/admin.js +++ b/frontend/static/admin.js @@ -1,3 +1,6 @@ +// Copyright © 2026 Olaf Kolkman +// SPDX-License-Identifier: GPL-3.0-or-later + (() => { const pluginList = document.querySelector('#plugin-list'); const adminLabelList = document.querySelector('#admin-label-list'); diff --git a/frontend/static/auth-header.js b/frontend/static/auth-header.js index 4bc34e3..416f840 100644 --- a/frontend/static/auth-header.js +++ b/frontend/static/auth-header.js @@ -1,3 +1,6 @@ +// Copyright © 2026 Olaf Kolkman +// SPDX-License-Identifier: GPL-3.0-or-later + (() => { const loginButton = document.querySelector('#auth-login-button'); const profileLink = document.querySelector('#auth-profile-link'); diff --git a/frontend/static/feed.js b/frontend/static/feed.js index fd909ce..3fe7828 100644 --- a/frontend/static/feed.js +++ b/frontend/static/feed.js @@ -1,3 +1,6 @@ +// Copyright © 2026 Olaf Kolkman +// SPDX-License-Identifier: GPL-3.0-or-later + const feedEl = document.getElementById('feed'); const sortSelect = document.getElementById('sort-select'); const userFilter = document.getElementById('user-filter'); diff --git a/frontend/static/login.js b/frontend/static/login.js index 17ce09d..ab760b8 100644 --- a/frontend/static/login.js +++ b/frontend/static/login.js @@ -1,3 +1,6 @@ +// Copyright © 2026 Olaf Kolkman +// SPDX-License-Identifier: GPL-3.0-or-later + const form = document.querySelector('#login-form'); const status = document.querySelector('#login-status'); diff --git a/frontend/static/logout.js b/frontend/static/logout.js index 38208ea..f1e6063 100644 --- a/frontend/static/logout.js +++ b/frontend/static/logout.js @@ -1,3 +1,6 @@ +// Copyright © 2026 Olaf Kolkman +// SPDX-License-Identifier: GPL-3.0-or-later + (() => { const logoutButton = document.querySelector('#logout-button'); diff --git a/frontend/static/profile.js b/frontend/static/profile.js index e09e579..ccd1c0e 100644 --- a/frontend/static/profile.js +++ b/frontend/static/profile.js @@ -1,3 +1,6 @@ +// Copyright © 2026 Olaf Kolkman +// SPDX-License-Identifier: GPL-3.0-or-later + (() => { const profileForm = document.querySelector('#profile-form'); const passwordForm = document.querySelector('#password-form'); diff --git a/frontend/static/style.css b/frontend/static/style.css index b92113c..562aba6 100644 --- a/frontend/static/style.css +++ b/frontend/static/style.css @@ -1,3 +1,6 @@ +/* Copyright © 2026 Olaf Kolkman */ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + @import url('https://fonts.googleapis.com/css2?family=Asset&family=DM+Sans:wght@400;500;600;700&family=Space+Grotesk:wght@500;600;700&display=swap'); :root { @@ -207,6 +210,26 @@ main.container { padding-bottom: 64px; } +.site-footer { + max-width: 960px; + margin: 0 auto; + padding: 0 24px 24px; + color: var(--muted); + font-size: 0.72rem; + text-align: center; +} + +.site-footer a { + color: inherit; + text-decoration: underline; +} + +.site-footer a:hover, +.site-footer a:focus-visible, +.site-footer a:active { + color: var(--lavender); +} + .toolbar { display: flex; flex-wrap: wrap; @@ -459,6 +482,11 @@ button:disabled { box-shadow: var(--shadow); } +.about-content { + display: grid; + gap: 14px; +} + .link-item h2 { margin: 0 0 8px; color: var(--text); @@ -574,6 +602,10 @@ button:disabled { padding-top: 18px; } + .site-footer { + padding: 0 14px 18px; + } + .toolbar { gap: 12px; padding: 14px; diff --git a/frontend/templates/about.html b/frontend/templates/about.html new file mode 100644 index 0000000..4548f11 --- /dev/null +++ b/frontend/templates/about.html @@ -0,0 +1,60 @@ + + + + + + + About LinkLog + + + + + + +
+ + + + +
+ + + + + diff --git a/frontend/templates/admin.html b/frontend/templates/admin.html index f65a7b9..3c41557 100644 --- a/frontend/templates/admin.html +++ b/frontend/templates/admin.html @@ -1,4 +1,6 @@ + + @@ -19,6 +21,7 @@