Compare commits

...

18 Commits

Author SHA1 Message Date
8f50debb0a Fix CI 2024-10-22 10:10:12 +02:00
c55b3f871e Fix CI 2024-10-22 10:08:29 +02:00
63594b910f Fix CI 2024-10-22 10:03:46 +02:00
6297ce14fd Update changelog 2024-10-22 10:01:51 +02:00
Félix MARQUET
7a48c3da50 Merge pull request #1 from BreizhHardware/dev
V1.4 release
2024-10-22 09:50:26 +02:00
7c2b4e545c Update changelog 2024-10-22 09:49:37 +02:00
d218c7a0bc Add import for json 2024-10-22 09:46:01 +02:00
694bfcaf6b Add docker login possibility 2024-10-22 09:38:53 +02:00
Félix MARQUET
b11bc64e52 Fix 2024-10-21 15:00:13 +00:00
Félix MARQUET
d796d5b24f Remove migration from entrypoint 2024-10-21 16:44:11 +02:00
Félix MARQUET
0be8d008c5 Fix entrypoint persmisson 2024-10-21 16:41:25 +02:00
Félix MARQUET
a14cc1848f Edit CI 2024-10-21 16:26:46 +02:00
Félix MARQUET
350ad9bf6a Update NGINX config with the new route 2024-10-21 16:17:13 +02:00
Félix MARQUET
76de8af42b Change the temp changelog 2024-10-21 16:15:52 +02:00
Félix MARQUET
3cfa54248f Add docker-hub compatibility 2024-10-21 16:15:01 +02:00
a270978728 Add remove repos button and change background color 2024-06-27 14:22:15 +02:00
2a7305a4cf Emergency PUSH 2024-03-05 13:00:23 +01:00
f5fc6e38da Add date and time of the release (use full when adding a new repo) 2024-03-05 12:51:15 +01:00
10 changed files with 515 additions and 37 deletions

77
.github/workflows/create_release.yml vendored Normal file
View File

@@ -0,0 +1,77 @@
name: Docker Build and Release
on:
push:
branches:
- main
jobs:
build-and-push-on-docker-hub:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ secrets.DOCKER_USERNAME }}/github-ntfy:latest
release-on-github:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Get the latest tag
id: get_latest_tag
run: echo "latest_tag=$(git describe --tags `git rev-list --tags --max-count=1`)" >> $GITHUB_ENV
- name: Increment version
id: increment_version
run: |
latest_tag=${{ env.latest_tag }}
if [ -z "$latest_tag" ]; then
new_version="v1.4.1"
else
IFS='.' read -r -a version_parts <<< "${latest_tag#v}"
new_version="v${version_parts[0]}.$((version_parts[1] + 1)).0"
fi
echo "new_version=$new_version" >> $GITHUB_ENV
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.TOKEN }}
with:
tag_name: ${{ env.new_version }}
release_name: Release ${{ env.new_version }}
draft: false
prerelease: false
- name: List files for debugging
run: ls -la
- name: Upload changelog
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./CHANGELOG.md
asset_name: CHANGELOG.md
asset_content_type: text/markdown

6
.gitignore vendored
View File

@@ -400,3 +400,9 @@ _deps
.nfs*
# End of https://www.toptal.com/developers/gitignore/api/c++,linux,clion,cmake,clion+all
docker-compose.yml
github-ntfy/
github-ntfy/*
*.db

9
CHANGELOG.MD Normal file
View File

@@ -0,0 +1,9 @@
**New features**:
- Change database struct to be able to handle docker hub repos
- Now you can add docker hub repo to your watch list
- You can connect your docker account to bypass the rate limit of the docker hub API
**Breaking changes**:
- Change in the docker-compose file, you need to add the DOCKER_USERNAME and DOCKER_PASSWORD environment variables
**Full Changelog**: https://github.com/BreizhHardware/ntfy_alerts/compare/v1.3...v1.4

View File

@@ -1,6 +1,7 @@
FROM python:3.11.8-alpine3.19
LABEL maintainer="BreizhHardware"
LABEL version_number="1.4"
ADD ntfy.py /
ADD ntfy_api.py /
@@ -10,6 +11,7 @@ ADD index.html /var/www/html/index.html
ADD script.js /var/www/html/script.js
RUN apk add --no-cache sqlite-dev sqlite-libs gcc musl-dev nginx
RUN pip install -r requirements.txt
RUN chmod 700 /entrypoint.sh
# Définir les variables d'environnement pour username et password
ENV USERNAME="" \
@@ -17,6 +19,8 @@ ENV USERNAME="" \
NTFY_URL="" \
GHNTFY_TIMEOUT="3600" \
GHNTFY_TOKEN="" \
DOCKER_USERNAME="" \
DOCKER_PASSWORD="" \
FLASK_ENV=production
# Exposer le port 5000 pour l'API et le port 80 pour le serveur web

View File

@@ -1,11 +1,13 @@
# ntfy_alerts
Personal ntfy alerts system
feel free to contribute and to fork
Feel free to contribute and to fork !
# Python ntfy.py
## Description:
This script is used to watch the github repos and send a notification to the ntfy server when a new release is published.
It can aloso watch Docker Hub repos and do the same as github.
## Utilisation:
auth and ntfy_url are required to be set as environment variables.
@@ -19,7 +21,6 @@ python ntfy.py
## Docker:
If you want to use the docker image you can use the following docker-compose file:
````yaml
version: '3'
services:
github-ntfy:
image: breizhhardware/github-ntfy:latest
@@ -30,6 +31,8 @@ services:
- NTFY_URL=ntfy_url # Required
- GHNTFY_TIMEOUT=timeout # Default is 3600 (1 hour)
- GHNTFY_TOKEN= # Default is empty (Github token)
- DOCKER_USERNAME= # Default is empty (Docker Hub username)
- DOCKER_PASSWORD= # Default is empty (Docker Hub password)
volumes:
- /path/to/github-ntfy:/github-ntfy/
ports:
@@ -44,6 +47,8 @@ Docker Hub repo: https://hub.docker.com/r/breizhhardware/github-ntfy
- [x] Add the watched repos list as a parameter
- [x] Add the application version as a database
- [x] Add the watched repos list as a web interface
- [x] Add Docker Hub compatibility
- [ ] Rework of the web interface
# Bash setup-notify.sh
## Description:
This script is used to setup the ntfy notification system on ssh login for a new server.

View File

@@ -7,37 +7,70 @@
<script src="https://cdn.tailwindcss.com"></script>
<script src="./script.js" defer></script>
</head>
<body class="bg-gradient-to-b from-cyan-500 to-fuchsia-500">
<div class="flex flex-col gap-2 justify-center items-center my-2 h-screen">
<h1 class="text-4xl font-semibold leading-10 text-gray-900">Github-Ntfy</h1>
<h1>Add a repo</h1>
<form id="addRepoForm">
<div class="space-y-12">
<div class="border-b border-gray-900/10 pb-12">
<h2 class="text-base font-semibold leading-7 text-gray-900">Name of the github repo</h2>
<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-4">
<div class="mt-2">
<div class="flex rounded-md shadow-sm ring-1 ring-inset ring-gray-300 focus-within:ring-2 focus-within:ring-inset focus-within:ring-indigo-600 sm:max-w-md">
<span class="flex select-none items-center pl-3 sm:text-sm">github.com/</span>
<input type="text" name="repo" id="repo" autocomplete="repo" class="block flex-1 border-0 bg-transparent py-1.5 pl-1 placeholder:text-gray-600 focus:ring-0 sm:text-sm sm:leading-6" placeholder="BreizhHardware/ntfy_alerts">
<body class="bg-gradient-to-b from-stone-500 to-green-700">
<h1 class="text-4xl font-semibold leading-10 text-gray-900 text-center">Github-Ntfy</h1>
<div class="flex flex-row gap-2 justify-center items-center my-2 h-screen">
<div class="flex flex-col gap-2 justify-center items-center my-2 h-screen border-double border-2 border-white p-2" id="github">
<h1>Add a github repo</h1>
<form id="addRepoForm">
<div class="space-y-12">
<div class="border-b border-gray-900/10 pb-12">
<h2 class="text-base font-semibold leading-7 text-gray-900">Name of the github repo</h2>
<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-4">
<div class="mt-2">
<div class="flex rounded-md shadow-sm ring-1 ring-inset ring-gray-300 focus-within:ring-2 focus-within:ring-inset focus-within:ring-indigo-600 sm:max-w-md">
<span class="flex select-none items-center pl-3 sm:text-sm">github.com/</span>
<input type="text" name="repo" id="repo" autocomplete="repo" class="block flex-1 border-0 bg-transparent py-1.5 pl-1 placeholder:text-gray-600 focus:ring-0 sm:text-sm sm:leading-6" placeholder="BreizhHardware/ntfy_alerts">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="mt-6 flex items-center justify-end gap-x-6">
<button type="button" class="text-sm font-semibold leading-6 text-gray-900">Cancel</button>
<button type="submit" class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Save</button>
</div>
</form>
<div class="mt-8">
<h2 class="text-base font-semibold leading-7 text-gray-900">Watched Github Repositories</h2>
<ul id="watchedReposList" class="mt-4">
<!-- Dynamically populated with JavaScript -->
</ul>
</div>
<div class="mt-6 flex items-center justify-end gap-x-6">
<button type="button" class="text-sm font-semibold leading-6 text-gray-900">Cancel</button>
<button type="submit" class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Save</button>
</div>
<div class="flex flex-col gap-2 justify-center items-center my-2 h-screen border-double border-2 border-white p-2" id="docker">
<h1>Add a docker repo</h1>
<form id="addDockerRepoForm">
<div class="space-y-12">
<div class="border-b border-gray-900/10 pb-12">
<h2 class="text-base font-semibold leading-7 text-gray-900">Name of the docker repo</h2>
<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-4">
<div class="mt-2">
<div class="flex rounded-md shadow-sm ring-1 ring-inset ring-gray-300 focus-within:ring-2 focus-within:ring-inset focus-within:ring-indigo-600 sm:max-w-md">
<span class="flex select-none items-center pl-3 sm:text-sm">hub.docker.com/r/</span>
<input type="text" name="dockerRepo" id="dockerRepo" autocomplete="dockerRepo" class="block flex-1 border-0 bg-transparent py-1.5 pl-1 placeholder:text-gray-600 focus:ring-0 sm:text-sm sm:leading-6" placeholder="breizhhardware/github-ntfy">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="mt-6 flex items-center justify-end gap-x-6">
<button type="button" class="text-sm font-semibold leading-6 text-gray-900">Cancel</button>
<button type="submit" class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Save</button>
</div>
</form>
<div class="mt-8">
<h2 class="text-base font-semibold leading-7 text-gray-900">Watched Docker Repositories</h2>
<ul id="watchedDockerReposList" class="mt-4">
<!-- Dynamically populated with JavaScript -->
</ul>
</div>
</form>
<div class="mt-8">
<h2 class="text-base font-semibold leading-7 text-gray-900">Watched Repositories</h2>
<ul id="watchedReposList" class="mt-4">
<!-- Dynamically populated with JavaScript -->
</ul>
</div>
</div>
<p class="font-semibold leading-10 text-gray-900 text-center">I know this web interface is awfull but I'm not a web designer ^^.</p>
</body>
</html>

View File

@@ -28,5 +28,33 @@ http {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /delete_repo {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /app_docker_repo {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /watched_docker_repos {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /delete_docker_repo {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}

122
ntfy.py
View File

@@ -4,6 +4,7 @@ import os
import logging
import sqlite3
import subprocess
import json
# Configuring the logger
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
@@ -14,6 +15,32 @@ github_headers = {}
if github_token:
github_headers['Authorization'] = f"token {github_token}"
docker_username = os.environ.get('DOCKER_USERNAME')
docker_password = os.environ.get('DOCKER_PASSWORD')
def create_dockerhub_token(username, password):
url = "https://hub.docker.com//v2/users/login"
headers = {"Content-Type": "application/json"}
data = json.dumps({"username": username, "password": password})
response = requests.post(url, headers=headers, data=data)
if response.status_code == 200:
token = response.json().get("token")
if token:
return token
else:
logger.error("Failed to get Docker Hub token.")
else:
logger.error(f"Failed to get Docker Hub token. Status code: {response.status_code}")
return None
docker_token = create_dockerhub_token(docker_username, docker_password)
docker_header = {}
if docker_token:
docker_header['Authorization'] = f"Bearer {docker_token}"
# Connecting to the database to store previous versions
conn = sqlite3.connect('/github-ntfy/ghntfy_versions.db', check_same_thread=False)
cursor = conn.cursor()
@@ -23,6 +50,10 @@ cursor.execute('''CREATE TABLE IF NOT EXISTS versions
(repo TEXT PRIMARY KEY, version TEXT, changelog TEXT)''')
conn.commit()
cursor.execute('''CREATE TABLE IF NOT EXISTS docker_versions
(repo TEXT PRIMARY KEY, digest TEXT, changelog TEXT)''')
conn.commit()
logger.info("Starting version monitoring...")
conn2 = sqlite3.connect('/github-ntfy/watched_repos.db', check_same_thread=False)
@@ -32,6 +63,10 @@ cursor2.execute('''CREATE TABLE IF NOT EXISTS watched_repos
(id INTEGER PRIMARY KEY, repo TEXT)''')
conn2.commit()
cursor2.execute('''CREATE TABLE IF NOT EXISTS docker_watched_repos
(id INTEGER PRIMARY KEY, repo TEXT)''')
conn2.commit()
def get_watched_repos():
cursor2.execute("SELECT * FROM watched_repos")
@@ -42,6 +77,15 @@ def get_watched_repos():
return watched_repos
def get_docker_watched_repos():
cursor2.execute("SELECT * FROM docker_watched_repos")
watched_repos_rows = cursor2.fetchall()
watched_repos = []
for repo in watched_repos_rows:
watched_repos.append(repo[1])
return watched_repos
def start_api():
subprocess.Popen(["python", "ntfy_api.py"])
@@ -54,17 +98,38 @@ def get_latest_releases(watched_repos):
if response.status_code == 200:
release_info = response.json()
changelog = get_changelog(repo)
release_date = release_info.get('published_at', 'Release date not available')
releases.append({
"repo": repo,
"name": release_info["name"],
"tag_name": release_info["tag_name"],
"html_url": release_info["html_url"],
"changelog": changelog
"changelog": changelog,
"published_at": release_date
})
else:
logger.error(f"Failed to fetch release info for {repo}")
return releases
def get_latest_docker_releases(watched_repos):
releases = []
for repo in watched_repos:
url = f"https://hub.docker.com/v2/repositories/{repo_name}/tags/latest"
response = requests.get(url, headers=docker_header)
if response.status_code == 200:
release_info = response.json()
release_date=release_info["last_upated"]
digest = release_date["digest"]
releases.append({
"repo": repo,
"digest": digest,
"html_url": "https://hub.docker.com/r/" + repo,
"published_at": release_date
})
else:
logger.error(f"Failed to fetch Docker Hub info for {repo_name}")
return releases
def get_changelog(repo):
url = f"https://api.github.com/repos/{repo}/releases"
@@ -78,12 +143,14 @@ def get_changelog(repo):
return "Changelog not available"
def send_to_ntfy(releases, auth, url):
def github_send_to_ntfy(releases, auth, url):
for release in releases:
app_name = release['repo'].split('/')[-1] # Getting the application name from the repo
version_number = release['tag_name'] # Getting the version number
app_url = release['html_url'] # Getting the application URL
changelog = release['changelog'] # Getting the changelog
release_date = release['published_at'] # Getting the release date
release_date = release_date.replace("T", " ").replace("Z", "") # Formatting the release date
# Checking if the version has changed since the last time
cursor.execute("SELECT version FROM versions WHERE repo=?", (app_name,))
@@ -92,7 +159,7 @@ def send_to_ntfy(releases, auth, url):
logger.info(f"The version of {app_name} has not changed. No notification sent.")
continue # Move on to the next application
message = f"New version: {version_number}\nFor: {app_name}\nChangelog:\n{changelog}\n{app_url}"
message = f"New version: {version_number}\nFor: {app_name}\nPublished on: {release_date}\nChangelog:\n{changelog}\n{app_url}"
# Updating the previous version for this application
cursor.execute("INSERT OR REPLACE INTO versions (repo, version, changelog) VALUES (?, ?, ?)",
(app_name, version_number, changelog))
@@ -111,6 +178,40 @@ def send_to_ntfy(releases, auth, url):
else:
logger.error(f"Failed to send message to Ntfy. Status code: {response.status_code}")
def docker_send_to_ntfy(releases, auth, url):
for release in releases:
app_name = release['repo'].split('/')[-1] # Getting the application name from the repo
digest_number = release['digest']
app_url = release['html_url'] # Getting the application URL
release_date = release['published_at'] # Getting the release date
release_date = release_date.replace("T", " ").replace("Z", "") # Formatting the release date
# Checking if the version has changed since the last time
cursor.execute("SELECT digest FROM docker_versions WHERE repo=?", (app_name,))
previous_digest = cursor.fetchone()
if previous_digest and previous_digest[0] == digest_number:
logger.info(f"The digest of {app_name} has not changed. No notification sent.")
continue # Move on to the next application
message = f"New version: {digest_number}\nFor: {app_name}\nPublished on: {release_date}\nChangelog:\n{changelog}\n{app_url}"
# Updating the previous digest for this application
cursor.execute("INSERT OR REPLACE INTO docker_versions (repo, digest, changelog) VALUES (?, ?, ?)",
(app_name, digest_number, changelog))
conn.commit()
headers = {
"Authorization": f"Basic {auth}",
"Title": f"New version for {app_name}",
"Priority": "urgent",
"Markdown": "yes",
"Actions": f"view, Update {app_name}, {app_url}, clear=true"}
response = requests.post(f"{url}", headers=headers, data=message)
if response.status_code == 200:
logger.info(f"Message sent to Ntfy for {app_name}")
continue
else:
logger.error(f"Failed to send message to Ntfy. Status code: {response.status_code}")
if __name__ == "__main__":
start_api()
@@ -121,14 +222,19 @@ if __name__ == "__main__":
if auth and ntfy_url:
while True:
watched_repos_list = get_watched_repos()
latest_release = get_latest_releases(watched_repos_list)
if latest_release:
send_to_ntfy(latest_release, auth, ntfy_url)
github_watched_repos_list = get_watched_repos()
github_latest_release = get_latest_releases(github_watched_repos_list)
if github_latest_release:
github_send_to_ntfy(github_latest_release, auth, ntfy_url)
docker_watched_repos_list = get_docker_watched_repos()
docker_latest_release = get_latest_docker_releases(docker_watched_repos_list)
if docker_latest_release:
docker_send_to_ntfy(docker_latest_release, auth, ntfy_url)
time.sleep(timeout) # Wait an hour before checking again
else:
logger.error("Usage: python ntfy.py")
logger.error(
"auth: can be generataed by the folowing command: echo -n 'username:password' | base64 and need to be stored in a file named auth.txt")
"auth: can be generataed by the folowing command: echo -n 'username:password' | base64 and need to be "
"stored in a file named auth.txt")
logger.error("NTFY_URL: the url of the ntfy server need to be stored in an environment variable named NTFY_URL")

View File

@@ -6,7 +6,6 @@ app = Flask(__name__)
CORS(app)
app.logger.setLevel("WARNING")
def get_db_connection():
conn = sqlite3.connect('/github-ntfy/watched_repos.db')
conn.row_factory = sqlite3.Row
@@ -35,12 +34,41 @@ def app_repo():
cursor.execute("SELECT * FROM watched_repos WHERE repo=?", (repo,))
existing_repo = cursor.fetchone()
if existing_repo:
return jsonify({"error": f"The repo {repo} is already in the database."}), 409
return jsonify({"error": f"The GitHub repo {repo} is already in the database."}), 409
# Ajouter le dépôt à la base de données
cursor.execute("INSERT INTO watched_repos (repo) VALUES (?)", (repo,))
conn.commit()
return jsonify({"message": f"The repo {repo} as been added to the watched repos."})
return jsonify({"message": f"The GitHub repo {repo} as been added to the watched repos."})
finally:
# Fermer la connexion à la base de données
close_db_connection(conn)
@app.route('/app_docker_repo', methods=['POST'])
def app_docker_repo():
data = request.json
repo = data.get('repo')
# Vérifier si le champ 'repo' est présent dans les données JSON
if not repo:
return jsonify({"error": "The repo field is required."}), 400
# Établir une connexion à la base de données
conn = get_db_connection()
cursor = conn.cursor()
try:
# Vérifier si le dépôt existe déjà dans la base de données
cursor.execute("SELECT * FROM docker_watched_repos WHERE repo=?", (repo,))
existing_repo = cursor.fetchone()
if existing_repo:
return jsonify({"error": f"The Docker repo {repo} is already in the database."}), 409
# Ajouter le dépôt à la base de données
cursor.execute("INSERT INTO docker_watched_repos (repo) VALUES (?)", (repo,))
conn.commit()
return jsonify({"message": f"The Docker repo {repo} as been added to the watched repos."})
finally:
# Fermer la connexion à la base de données
close_db_connection(conn)
@@ -57,5 +85,74 @@ def get_watched_repos():
return jsonify(watched_repos)
@app.route('/watched_docker_repos', methods=['GET'])
def get_watched_docker_repos():
db = get_db_connection()
cursor = db.cursor()
cursor.execute("SELECT repo FROM docker_watched_repos")
watched_repos = [repo[0] for repo in cursor.fetchall()]
cursor.close()
db.close()
return jsonify(watched_repos)
@app.route('/delete_repo', methods=['POST'])
def delete_repo():
data = request.json
repo = data.get('repo')
# Vérifier si le champ 'repo' est présent dans les données JSON
if not repo:
return jsonify({"error": "The repo field is required."}), 400
# Établir une connexion à la base de données
conn = get_db_connection()
cursor = conn.cursor()
try:
# Vérifier si le dépôt existe dans la base de données
cursor.execute("SELECT * FROM watched_repos WHERE repo=?", (repo,))
existing_repo = cursor.fetchone()
if not existing_repo:
return jsonify({"error": f"The GitHub repo {repo} is not in the database."}), 404
# Supprimer le dépôt de la base de données
cursor.execute("DELETE FROM watched_repos WHERE repo=?", (repo,))
conn.commit()
return jsonify({"message": f"The GitHub repo {repo} as been deleted from the watched repos."})
finally:
# Fermer la connexion à la base de données
close_db_connection(conn)
@app.route('/delete_docker_repo', methods=['POST'])
def delete_docker_repo():
data = request.json
repo = data.get('repo')
# Vérifier si le champ 'repo' est présent dans les données JSON
if not repo:
return jsonify({"error": "The repo field is required."}), 400
# Établir une connexion à la base de données
conn = get_db_connection()
cursor = conn.cursor()
try:
# Vérifier si le dépôt existe dans la base de données
cursor.execute("SELECT * FROM docker_watched_repos WHERE repo=?", (repo,))
existing_repo = cursor.fetchone()
if not existing_repo:
return jsonify({"error": f"The Docker repo {repo} is not in the database."}), 404
# Supprimer le dépôt de la base de données
cursor.execute("DELETE FROM docker_watched_repos WHERE repo=?", (repo,))
conn.commit()
return jsonify({"message": f"The Docker repo {repo} as been deleted from the watched repos."})
finally:
# Fermer la connexion à la base de données
close_db_connection(conn)
if __name__ == "__main__":
app.run(debug=False)

115
script.js
View File

@@ -22,6 +22,30 @@ document.getElementById('addRepoForm').addEventListener('submit', function(event
});
});
document.getElementById('addDockerRepoForm').addEventListener('submit', function(event) {
event.preventDefault();
let repoName = document.getElementById('dockerRepo').value;
fetch('/app_docker_repo', {
method: 'POST',
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json'
},
body: JSON.stringify({repo: repoName})
})
.then(response => {
if (response.ok) {
// Si la requête s'est bien déroulée, actualiser la liste des dépôts surveillés
refreshWatchedRepos();
} else {
throw new Error('Erreur lors de l\'ajout du dépôt');
}
})
.catch(error => {
console.error('Error:', error);
});
});
function refreshWatchedRepos() {
fetch('/watched_repos')
.then(response => response.json())
@@ -32,13 +56,102 @@ function refreshWatchedRepos() {
// Ajouter chaque dépôt surveillé à la liste
data.forEach(repo => {
const listItem = document.createElement('li');
listItem.textContent = repo;
const repoName = document.createElement('span');
repoName.textContent = repo;
repoName.className = 'repo-name';
listItem.appendChild(repoName);
const deleteButton = document.createElement('button');
deleteButton.textContent = ' X';
deleteButton.className = 'delete-btn text-red-500 ml-2';
deleteButton.addEventListener('click', () => {
// Remove the repo from the watched repos
// This is a placeholder. Replace it with your actual code to remove the repo from the watched repos.
removeRepoFromWatchedRepos(repo);
// Remove the repo from the DOM
listItem.remove();
});
listItem.appendChild(deleteButton);
watchedReposList.appendChild(listItem);
});
})
.catch(error => {
console.error('Error:', error);
});
fetch('/watched_docker_repos')
.then(response => response.json())
.then(data => {
const watchedDockerReposList = document.getElementById('watchedDockerReposList');
// Vider la liste actuelle
watchedDockerReposList.innerHTML = '';
// Ajouter chaque dépôt surveillé à la liste
data.forEach(repo => {
const listItem = document.createElement('li');
const repoName = document.createElement('span');
repoName.textContent = repo;
repoName.className = 'repo-name';
listItem.appendChild(repoName);
const deleteButton = document.createElement('button');
deleteButton.textContent = ' X';
deleteButton.className = 'delete-btn text-red-500 ml-2';
deleteButton.addEventListener('click', () => {
// Remove the repo from the watched repos
// This is a placeholder. Replace it with your actual code to remove the repo from the watched repos.
removeDockerRepoFromWatchedRepos(repo);
// Remove the repo from the DOM
listItem.remove();
});
listItem.appendChild(deleteButton);
watchedDockerReposList.appendChild(listItem);
});
})
.catch(error => {
console.error('Error:', error);
});
}
function removeRepoFromWatchedRepos(repo) {
fetch('/delete_repo', {
method: 'POST',
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json'
},
body: JSON.stringify({repo: repo})
})
.then(response => {
if (!response.ok) {
throw new Error('Erreur lors de la suppression du dépôt');
}
})
.catch(error => {
console.error('Error:', error);
});
}
function removeDockerRepoFromWatchedRepos(repo) {
fetch('/delete_docker_repo', {
method: 'POST',
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json'
},
body: JSON.stringify({repo: repo})
})
.then(response => {
if (!response.ok) {
throw new Error('Erreur lors de la suppression du dépôt');
}
})
.catch(error => {
console.error('Error:', error);
});
}
// Appeler la fonction pour charger les dépôts surveillés au chargement de la page