Send a notification to users
Email the owners of the given repositories telling them that terms and conditions of the service must be abided. A private redmine note is added to an issue to keep track of these requests. This script must be executed on the Gitea host. Usage: # cat repositories.txt https://forge.chapril.org/user1/repo1 https://forge.chapril.org/userX/repoZ # ./notify_owners.py repositories.txt
This commit is contained in:
parent
7feee73ac1
commit
6a422f6b70
194
notify_owners.py
Executable file
194
notify_owners.py
Executable file
@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import configparser
|
||||
import datetime
|
||||
from email.message import EmailMessage
|
||||
import fileinput
|
||||
import functools
|
||||
import getpass
|
||||
import json
|
||||
import logging
|
||||
import smtplib
|
||||
from time import sleep
|
||||
from string import Template
|
||||
from urllib.parse import urlsplit
|
||||
|
||||
import requests
|
||||
|
||||
SUBJECT = "Licence du dépôt '$repository' hébergé sur la forge Chapril"
|
||||
SUBJECT_TMPL = Template(SUBJECT)
|
||||
|
||||
MAIL = """\
|
||||
Bonjour,
|
||||
|
||||
Je suis animateur bénévole du service forge.chapril.org.
|
||||
|
||||
Sauf erreur de ma part, le dépôt '$repository' [1]
|
||||
ne spécifie pas clairement de licence et n'est donc pas conforme aux
|
||||
conditions générales d'utilisation du service [2].
|
||||
|
||||
Nous vous demandons de bien vouloir vous conformer aux conditions
|
||||
générales d'utilisation du service, à défaut ce dépôt sera supprimé dans
|
||||
15 jours.
|
||||
|
||||
Nous sommes heureux que nos services numériques libres, éthiques et loyaux
|
||||
puissent vous être utiles.
|
||||
|
||||
[1] https://forge.chapril.org/$user/$repository
|
||||
[2] https://www.chapril.org/cgu.html#forgechaprilorg-cpu
|
||||
|
||||
En vous souhaitant, au nom de toute l'équipe du Chapril, un agréable
|
||||
usage de nos services libres, éthique et loyaux.
|
||||
|
||||
--
|
||||
$animsys"""
|
||||
MAIL_TMPL = Template(MAIL)
|
||||
|
||||
AGIR_URL = "https://agir.april.org"
|
||||
FORGE_ML = "forge-support@chapril.org"
|
||||
|
||||
|
||||
def get_db_cursor():
|
||||
import psycopg2
|
||||
|
||||
conn = psycopg2.connect(**db_config_from_gitea(), target_session_attrs="read-only")
|
||||
conn.set_session(readonly=True)
|
||||
assert conn.readonly
|
||||
logging.debug("Connected to gitea database")
|
||||
return conn.cursor()
|
||||
|
||||
|
||||
def db_config_from_gitea():
|
||||
config = configparser.ConfigParser()
|
||||
with open("/etc/gitea/gitea.ini", encoding="utf-8") as giteacfg:
|
||||
# skip the first lines without a section
|
||||
while True:
|
||||
pos = giteacfg.tell()
|
||||
line = giteacfg.readline()
|
||||
try:
|
||||
config.read_string(line)
|
||||
except configparser.MissingSectionHeaderError:
|
||||
pass
|
||||
|
||||
if config.sections():
|
||||
config.clear()
|
||||
break
|
||||
giteacfg.seek(pos)
|
||||
config.read_file(giteacfg)
|
||||
|
||||
db_params = {
|
||||
"options": "-c default_transaction_read_only=on",
|
||||
}
|
||||
|
||||
if ":" in config["database"]["host"]:
|
||||
db_host, db_port = config["database"]["host"].split(":")
|
||||
db_params["host"] = db_host
|
||||
db_params["port"] = db_port
|
||||
else:
|
||||
db_params["host"] = config["database"]["host"]
|
||||
|
||||
for param, gitea_param in (
|
||||
("sslmode", "ssl_mode"),
|
||||
("dbname", "name"),
|
||||
("user", "user"),
|
||||
("password", "passwd"),
|
||||
):
|
||||
if gitea_param in config["database"]:
|
||||
db_params[param] = config["database"][gitea_param]
|
||||
|
||||
if "schema" in config["database"] and config["database"]["schema"]:
|
||||
db_params["options"] += f' -c search_path={config["database"]["schema"]}'
|
||||
|
||||
return db_params
|
||||
|
||||
|
||||
def fetch_mail_from_db(cur, user):
|
||||
query = "select email from public.user where name = %s;"
|
||||
cur.execute(query, (user,))
|
||||
return cur.fetchone()[0]
|
||||
|
||||
|
||||
def notify(smtp, repositories, agir_key, fetch_mail):
|
||||
headers = {"X-Redmine-API-Key": agir_key, "Content-Type": "application/json"}
|
||||
note = Template(
|
||||
json.dumps(
|
||||
{
|
||||
"issue": {
|
||||
"private_notes": True,
|
||||
"notes": f'🔲 "$repository":$url: @$user@ notified by mail '
|
||||
f"({datetime.date.today()})",
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
req = requests.get(f"{AGIR_URL}/users/current.json", headers=headers)
|
||||
req.raise_for_status()
|
||||
sender = req.json()["user"]
|
||||
if "firstname" in sender and "lastname" in sender:
|
||||
animsys = f"{sender['firstname']} {sender['lastname']} " f"({sender['login']})"
|
||||
else:
|
||||
animsys = sender["login"]
|
||||
|
||||
for url in repositories:
|
||||
url = url.strip()
|
||||
if not url:
|
||||
continue
|
||||
if not "/" in url:
|
||||
raise ValueError(f"URL not recognized ({url})")
|
||||
user, repository = urlsplit(url).path.split("/")[1:3]
|
||||
assert user and repository, f"Can not fetch user and repository from {url}"
|
||||
user_email = fetch_mail(user)
|
||||
logging.debug("Mail for '%s' is '%s'", user, user_email)
|
||||
subject = SUBJECT_TMPL.substitute(repository=repository)
|
||||
message = MAIL_TMPL.substitute(
|
||||
user=user, repository=repository, animsys=animsys
|
||||
)
|
||||
|
||||
email = EmailMessage()
|
||||
email.set_content(message)
|
||||
email["Subject"] = subject
|
||||
email["From"] = FORGE_ML
|
||||
email["To"] = user_email
|
||||
email["CC"] = "forge-support@chapril.org"
|
||||
|
||||
smtp.send_message(email)
|
||||
logging.debug("Mail to '%s' (%s) sent for %s.", user, user_email, url)
|
||||
|
||||
issue_api = f"{AGIR_URL}/issues/5615.json"
|
||||
req = requests.put(
|
||||
issue_api,
|
||||
data=note.substitute(user=user, repository=repository, url=url),
|
||||
headers=headers,
|
||||
)
|
||||
req.raise_for_status()
|
||||
logging.debug("Note added to %s for %s", issue_api, url)
|
||||
|
||||
sleep(1) # throttle mail and web notifications!
|
||||
|
||||
|
||||
def main():
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
# In order to use another SMTP server (in such case, fetch_mail may need to
|
||||
# be re-implemented using the Gitea API)
|
||||
#
|
||||
# import ssl
|
||||
# server = input("type your smtp server: ")
|
||||
# login = input("type your smtp login: ")
|
||||
# password = getpass.getpass(prompt="type your password and press enter:")
|
||||
# context = ssl.create_default_context(cafile="/usr/local/share/ca-certificates/own.crt")
|
||||
# with smtplib.smtp_ssl(server, 465, context=context) as smtp:
|
||||
# smtp.login(login, password)
|
||||
|
||||
agir_key = getpass.getpass(prompt="Type agir.april.org API key:")
|
||||
|
||||
repositories = fileinput.input()
|
||||
with smtplib.SMTP("127.0.0.1", 25) as smtp:
|
||||
with get_db_cursor() as cursor:
|
||||
fetch_mail = functools.partial(fetch_mail_from_db, cursor)
|
||||
notify(smtp, repositories, agir_key, fetch_mail)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
2
notify_owners.requirements.txt
Normal file
2
notify_owners.requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
psycopg2-binary
|
||||
requests
|
Loading…
Reference in New Issue
Block a user