Initial
This commit is contained in:
37
LICENSE
37
LICENSE
@@ -1,26 +1,25 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
MIT License
|
||||
|
||||
---
|
||||
Copyright (c) Patrick Asmus (scriptos)
|
||||
|
||||
Copyright ©
|
||||
|
||||
Name: Patrick Asmus (scriptos)
|
||||
Email: support@techniverse.net
|
||||
Website: https://www.patrick-asmus.de
|
||||
Blog: https://www.cleveradmin.de
|
||||
Email: support@techniverse.net
|
||||
|
||||
---
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
83
README.md
83
README.md
@@ -4,10 +4,10 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h1 align="center">Name des Projekts</h1>
|
||||
<h1 align="center">Kutt Links Cleanup</h1>
|
||||
|
||||
<h4 align="center">
|
||||
Kurzbeschreibung des Projekts/Anwendung, um die es geht
|
||||
Bash-Script zum automatischen Aufräumen anonymer Links in einer selbst gehosteten Kutt-Instanz.
|
||||
</h4>
|
||||
|
||||
<h6 align="center">
|
||||
@@ -22,7 +22,84 @@
|
||||
<br><br>
|
||||
|
||||
|
||||
CONTENT BEREICH
|
||||
## Was macht das Script?
|
||||
|
||||
Anonyme Links (ohne Account erstellt) werden gelöscht, wenn sie beispielhaft seit **365 Tagen nicht mehr aufgerufen** wurden. Als Referenzdatum gilt:
|
||||
|
||||
- Der **letzte Aufruf** (letzter Eintrag in der `visits`-Tabelle)
|
||||
- Falls der Link **nie aufgerufen** wurde: das **Erstelldatum**
|
||||
|
||||
Links von eingeloggten Usern werden **nie** angefasst.
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- Kutt läuft als Docker-Setup mit einem PostgreSQL-Container namens `kutt-db`
|
||||
- Der ausführende User hat Zugriff auf `docker exec`
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. Script ablegen
|
||||
|
||||
```bash
|
||||
mkdir -p /home/docker-projekte/kutt/scripts
|
||||
cp kutt-links-cleanup.sh /home/docker-projekte/kutt/scripts/
|
||||
chmod +x /home/docker-projekte/kutt/scripts/kutt-links-cleanup.sh
|
||||
```
|
||||
|
||||
### 2. Cronjob einrichten
|
||||
|
||||
Täglich um 03:00 Uhr ausführen:
|
||||
|
||||
```bash
|
||||
crontab -e
|
||||
```
|
||||
|
||||
Folgende Zeile hinzufügen:
|
||||
|
||||
```
|
||||
0 3 * * * /home/docker-projekte/kutt/scripts/kutt-links-cleanup.sh >> /home/docker-projekte/kutt/scripts/cleanup.log 2>&1
|
||||
```
|
||||
|
||||
## Verwendung
|
||||
|
||||
### Dry Run (nur anzeigen, nichts löschen)
|
||||
|
||||
```bash
|
||||
./kutt-links-cleanup.sh --dry-run
|
||||
```
|
||||
|
||||
Zeigt alle Links an, die gelöscht werden würden — ohne etwas zu verändern.
|
||||
|
||||
### Ausführen (Links löschen)
|
||||
|
||||
```bash
|
||||
./kutt-links-cleanup.sh
|
||||
```
|
||||
|
||||
### Log prüfen
|
||||
|
||||
```bash
|
||||
cat /home/docker-projekte/kutt/scripts/cleanup.log
|
||||
```
|
||||
|
||||
## Konfiguration
|
||||
|
||||
Die Variablen stehen am Anfang des Scripts:
|
||||
|
||||
| Variable | Standard | Beschreibung |
|
||||
|---|---|---|
|
||||
| `CONTAINER` | `kutt-db` | Name des PostgreSQL-Containers |
|
||||
| `DB_USER` | `kutt` | Datenbank-Benutzer |
|
||||
| `DB_NAME` | `kutt` | Datenbank-Name |
|
||||
| `MAX_AGE_DAYS` | `365` | Tage ohne Zugriff bis zur Löschung |
|
||||
|
||||
## Technische Details
|
||||
|
||||
- Gelöschte Links sind sofort aus der Kutt-Oberfläche verschwunden
|
||||
- Zugehörige Visit-Statistiken werden automatisch mitgelöscht (`ON DELETE CASCADE`)
|
||||
- Kutt nutzt Redis nur für Rate-Limiting, nicht als Link-Cache — es gibt kein Cache-Problem nach dem Löschen
|
||||
- Die freigewordenen Short-Link-Adressen können danach wieder vergeben werden
|
||||
|
||||
|
||||
|
||||
<br><br>
|
||||
|
||||
63
kutt-links-cleanup.sh
Normal file
63
kutt-links-cleanup.sh
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Löscht anonyme Kutt-Links die seit %MAX_AGE_DAYS% Tagen nicht mehr aufgerufen wurden.
|
||||
# Als Referenzdatum gilt der letzte Visit oder — falls nie aufgerufen — das Erstelldatum.
|
||||
#
|
||||
# Nutzung: Per Cron z.B. täglich ausführen.
|
||||
# 0 3 * * * /home/docker-projekte/kutt/scripts/kutt-links-cleanup.sh
|
||||
#
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
CONTAINER="kutt-db"
|
||||
DB_USER="kutt"
|
||||
DB_NAME="kutt"
|
||||
MAX_AGE_DAYS=365
|
||||
DRY_RUN="${1:-}"
|
||||
|
||||
SQL_SELECT="
|
||||
SELECT l.id, l.address, l.target,
|
||||
COALESCE(MAX(v.created_at), l.created_at) AS last_activity
|
||||
FROM links l
|
||||
LEFT JOIN visits v ON v.link_id = l.id
|
||||
WHERE l.user_id IS NULL
|
||||
GROUP BY l.id
|
||||
HAVING COALESCE(MAX(v.created_at), l.created_at) < NOW() - INTERVAL '${MAX_AGE_DAYS} days'
|
||||
ORDER BY last_activity;
|
||||
"
|
||||
|
||||
SQL_DELETE="
|
||||
DELETE FROM links
|
||||
WHERE id IN (
|
||||
SELECT l.id
|
||||
FROM links l
|
||||
LEFT JOIN visits v ON v.link_id = l.id
|
||||
WHERE l.user_id IS NULL
|
||||
GROUP BY l.id
|
||||
HAVING COALESCE(MAX(v.created_at), l.created_at) < NOW() - INTERVAL '${MAX_AGE_DAYS} days'
|
||||
);
|
||||
"
|
||||
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') — Cleanup anonymer Links (älter als ${MAX_AGE_DAYS} Tage ohne Zugriff)"
|
||||
|
||||
if [ "$DRY_RUN" = "--dry-run" ]; then
|
||||
echo "DRY RUN — es wird nichts gelöscht."
|
||||
docker exec "$CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" -c "$SQL_SELECT"
|
||||
else
|
||||
CANDIDATES=$(docker exec "$CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" -t -A -c "
|
||||
SELECT COUNT(*) FROM links l
|
||||
LEFT JOIN visits v ON v.link_id = l.id
|
||||
WHERE l.user_id IS NULL
|
||||
GROUP BY l.id
|
||||
HAVING COALESCE(MAX(v.created_at), l.created_at) < NOW() - INTERVAL '${MAX_AGE_DAYS} days';
|
||||
" | wc -l)
|
||||
|
||||
if [ "$CANDIDATES" -eq 0 ]; then
|
||||
echo "Keine abgelaufenen anonymen Links gefunden."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "${CANDIDATES} Link(s) werden gelöscht..."
|
||||
docker exec "$CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" -c "$SQL_DELETE"
|
||||
echo "Fertig."
|
||||
fi
|
||||
Reference in New Issue
Block a user