1
0
mirror of https://gitlab.crans.org/bde/nk20-scripts synced 2025-02-18 22:21:21 +00:00

Compare commits

...

19 Commits

Author SHA1 Message Date
Yohann D'ANELLO
654492f9e9 The note account must be active in order to have access to the Rest Framework API 2020-10-20 10:30:38 +02:00
Yohann D'ANELLO
84be9d0062 Note account has a special treatment in potential future NK15 import (compatibility commit) 2020-10-20 00:19:33 +02:00
Yohann D'ANELLO
7e27c3b71b Backups are sent to Zamok 2020-09-08 13:16:03 +02:00
Yohann D'ANELLO
0107dd0a94 Refactor the script to extract the mails that are registered to an events mailing list 2020-09-08 10:11:08 +02:00
Yohann D'ANELLO
e5b76b7c35 Linebreaks are rendered as <<BR>> in the wiki 2020-09-07 13:54:03 +02:00
Yohann D'ANELLO
4506dd4dc0 Plain text mode in reports 2020-09-07 11:02:10 +02:00
Yohann D'ANELLO
bac22dcbac Add __str__ to models, remove null=True in CharField and TextField 2020-09-07 01:06:22 +02:00
Yohann D'ANELLO
4f5a794798 Fix refresh activities cron 2020-09-05 14:28:02 +02:00
Yohann D'ANELLO
69c5c3bb36 Save the list of changed usernames and lost aliases 2020-09-05 13:50:57 +02:00
Yohann D'ANELLO
7479671b3f Don't rebuild systematically migrations 2020-09-05 10:07:20 +02:00
Yohann D'ANELLO
7246f4d18a Change debug option to "print stdout" / "edit wiki" in the Refresh activities script 2020-09-05 00:45:10 +02:00
Yohann D'ANELLO
2a113d22b9 I broke the import script 2020-09-05 00:33:38 +02:00
Yohann D'ANELLO
525f091b0c Test activity app 2020-09-04 21:46:40 +02:00
Yohann D'ANELLO
4e1bcd1808 Send user id and group id in Docker bash 2020-09-02 22:51:59 +02:00
Yohann D'ANELLO
1145f75a96 Add script to launch a Docker bash easily 2020-09-02 15:26:36 +02:00
Yohann D'ANELLO
c1c0a87971 RecurrentTransaction has no longer a category 2020-09-01 15:54:32 +02:00
Yohann D'ANELLO
2b1c05ff98 Prevent also club owners when the note balance is negative 2020-08-31 16:13:23 +02:00
Yohann D'ANELLO
4179cad611 When data is imported from the NK15, prevent users whenever some aliases are deleted 2020-08-24 12:41:51 +02:00
Yohann D'ANELLO
81709539a2 Replace timezone.now().date() by date.today() 2020-08-16 00:35:11 +02:00
11 changed files with 197 additions and 39 deletions

View File

@ -0,0 +1,57 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from datetime import date
from django.contrib.auth.models import User
from django.core.management import BaseCommand
from django.db.models import Q
from member.models import Membership, Club
from wei.models import WEIClub
class Command(BaseCommand):
help = "Get mailing list registrations from the last wei. " \
"Usage: manage.py extract_ml_registrations -t {events,art,sport} -t {fr, en}. " \
"You can write this into a file with a pipe, then paste the document into your mail manager."
def add_arguments(self, parser):
parser.add_argument('--type', '-t', choices=["members", "clubs", "events", "art", "sport"], default="members",
help='Select the type of the mailing list (default members)')
parser.add_argument('--lang', '-l', type=str, choices=['fr', 'en'], default='fr',
help='Select the registred users of the ML of the given language. Useful only for the '
'events mailing list.')
def handle(self, *args, **options):
# TODO: Improve the mailing list extraction system, and link it automatically with Mailman.
if options["type"] == "members":
for membership in Membership.objects.filter(
club__name="BDE",
date_start__lte=date.today(),
date_end__gte=date.today(),
).all():
self.stdout.write(membership.user.email)
return
if options["type"] == "clubs":
for club in Club.objects.all():
self.stdout.write(club.email)
return
# Get the list of mails that want to be registered to the events mailing list.
# Don't filter to valid members, old members can receive these mails as long as they want.
if options["type"] == "events":
for user in User.objects.filter(profile__ml_events_registration=options["lang"]).all():
self.stdout.write(user.email)
return
if options["type"] == "art":
for user in User.objects.filter(profile__ml_art_registration=True).all():
self.stdout.write(user.email)
return
if options["type"] == "sport":
for user in User.objects.filter(profile__ml_sport_registration=True).all():
self.stdout.write(user.email)
return

View File

@ -6,6 +6,7 @@ import psycopg2.extras as pge
import datetime
import json
from django.template.loader import render_to_string
from django.utils.timezone import make_aware, now
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
@ -33,6 +34,11 @@ MAP_IDBDE = {
# some Aliases have been created in the fixtures
ALIAS_SET = {a[0] for a in Alias.objects.all().values_list("normalized_name")}
# Some people might loose some aliases due to normalization. We warn them on them.
LOST_ALIASES = {}
# In some rare cases, the username might be in conflict with some others. We change them and warn the users.
CHANGED_USERNAMES = []
note_user_type = ContentType.objects.get(app_label="note", model="noteuser")
note_club_type = ContentType.objects.get(app_label="note", model="noteclub")
@ -85,9 +91,10 @@ class Command(ImportCommand):
pseudo = row["pseudo"]
pseudo_norm = Alias.normalize(pseudo)
self.update_line(idx, n, pseudo)
# clean pseudo (normalized pseudo must be unique)
if pseudo_norm in ALIAS_SET:
# clean pseudo (normalized pseudo must be unique and not empty)
if not pseudo_norm or pseudo_norm in ALIAS_SET:
pseudo = pseudo + str(row["idbde"])
CHANGED_USERNAMES.append((pk_note, row["idbde"], pseudo))
else:
ALIAS_SET.add(pseudo_norm)
# clean date
@ -95,7 +102,7 @@ class Command(ImportCommand):
"pk": pk_note,
"balance": row['solde'],
"last_negative": None,
"is_active": True,
"is_active": not row["bloque"],
"display_image": "pic/default.png",
}
if row["last_negatif"] is not None:
@ -107,6 +114,11 @@ class Command(ImportCommand):
else:
passwd_nk15 = ''
# Note account should have no password and be active
if int(row["idbde"]) == 3508:
passwd_nk15 = "ipbased$127.0.0.1"
row["bloque"] = False
if row["idbde"] not in MAP_IDBDE_PROMOTION:
# NK12 bug. Applying default values
MAP_IDBDE_PROMOTION[row["idbde"]] = {"promo": 2014,
@ -119,7 +131,7 @@ class Command(ImportCommand):
"first_name": row["prenom"],
"last_name": row["nom"],
"email": row["mail"],
"is_active": True, # temporary
"is_active": not row["bloque"],
"date_joined": make_aware(MAP_IDBDE_PROMOTION[row["idbde"]]["created_at"]),
}
profile_dict = {
@ -131,7 +143,7 @@ class Command(ImportCommand):
"registration_valid": True,
"email_confirmed": True,
"promotion": MAP_IDBDE_PROMOTION[row["idbde"]]["promo"],
"report_frequency": row["report_period"],
"report_frequency": max(row["report_period"], 0),
"last_report": make_aware(row["previous_report_date"]),
}
note_dict["created_at"] = make_aware(MAP_IDBDE_PROMOTION[row["idbde"]]["created_at"])
@ -206,7 +218,9 @@ class Command(ImportCommand):
alias_norm = Alias.normalize(alias_name)
self.update_line(idx, n, alias_norm)
# clean pseudo (normalized pseudo must be unique)
if alias_norm in ALIAS_SET:
if not alias_norm or alias_norm in ALIAS_SET:
LOST_ALIASES.setdefault(MAP_IDBDE[row["idbde"]], [])
LOST_ALIASES[MAP_IDBDE[row["idbde"]]].append(alias_name)
continue
else:
ALIAS_SET.add(alias_norm)
@ -237,3 +251,7 @@ class Command(ImportCommand):
filename = kwargs["save"]
with open(filename, 'w') as fp:
json.dump(MAP_IDBDE, fp, sort_keys=True, indent=2)
with open(filename + ".changed-usernames", 'w') as fp:
json.dump(CHANGED_USERNAMES, fp, sort_keys=True, indent=2)
with open(filename + ".removed-aliases", 'w') as fp:
json.dump(LOST_ALIASES, fp, sort_keys=True, indent=2)

View File

@ -107,7 +107,6 @@ class Command(ImportCommand):
def _template_transaction(self, row, obj_dict, child_dict):
if self.buttons.get(row["description"]):
child_dict["category_id"] = self.buttons[row["description"]][1]
child_dict["template_id"] = self.buttons[row["description"]][0]
# elif self.categories.get(row["categorie"]):
# child_dict["category_id"] = self.categories[row["categorie"]]
@ -215,7 +214,7 @@ class Command(ImportCommand):
"amount": row["montant"],
"created_at": date,
"destination_alias": "",
"invalidity_reason": None,
"invalidity_reason": "",
"quantity": row["quantite"],
"reason": row["description"],
"source_alias": "",
@ -317,6 +316,12 @@ class Command(ImportCommand):
)
bulk_mgr.done()
# Note account has a different treatment
for m in Membership.objects.filter(user_username="note").all():
m.date_end = "3142-12-12"
m.roles.set([20]) # PC Kfet role
m.save()
@timed
@transaction.atomic
def import_remittances(self, cur, chunk_size):

View File

@ -13,7 +13,7 @@ from activity.models import Activity
class Command(BaseCommand):
acl_header = "#acl NoteKfet2015:read,write,admin NoteKfet2020:read,write,admin All:read Default\n"
acl_header = "#acl NoteKfet2020:read,write,admin All:read Default\n"
warning_header = """## NE PAS ÉDITER CETTE PAGE MANUELLEMENT
## ELLE EST GÉNÉRÉE AUTOMATIQUEMENT PAR LA NOTE KFET 2020
@ -24,7 +24,7 @@ class Command(BaseCommand):
* Ne pas éditer cette page manuellement, toute modification sera annulée automatiquement.
* Pour annoncer un nouvel événement, rendez-vous sur {activities_url}
""".format(activities_url="https://" + os.getenv("NOTE_URL") + reverse("activity:activity_list"))
""".format(activities_url="https://" + os.getenv("NOTE_URL", "") + reverse("activity:activity_list"))
@staticmethod
def connection(url):
@ -100,7 +100,7 @@ class Command(BaseCommand):
title=act.name,
start=timezone.localtime(act.date_start).strftime("%Y-%m-%d %H:%M"),
end=timezone.localtime(act.date_end).strftime("%Y-%m-%d %H:%M"),
description=act.description,
description=act.description.replace("\r", "").replace("\n", "<<BR>>"),
club=act.organizer.name,
location=act.location,
)
@ -108,7 +108,7 @@ class Command(BaseCommand):
return "|| {start} || {title} || {description} || {club} || {location} ||".format(
title=act.name,
start=timezone.localtime(act.date_start).strftime("%d/%m/%Y"),
description=act.description,
description=act.description.replace("\r", "").replace("\n", "<<BR>>"),
club=act.organizer.name,
location=act.location,
)
@ -150,30 +150,31 @@ class Command(BaseCommand):
return page, header + body
@staticmethod
def refresh_raw_wiki_page(comment="refresh", debug=True):
def refresh_raw_wiki_page(comment="refresh", print_stdout=False, edit_wiki=False):
page, content = Command.get_raw_page()
if debug:
if print_stdout:
print(content)
else:
if edit_wiki:
Command.edit_wiki(page, content, comment)
@staticmethod
def refresh_human_readable_wiki_page(comment="refresh", debug=True):
def refresh_human_readable_wiki_page(comment="refresh", print_stdout=False, edit_wiki=False):
page, content = Command.get_human_readable_page()
if debug:
if print_stdout:
print(content)
else:
if edit_wiki:
Command.edit_wiki(page, content, comment)
def add_arguments(self, parser):
parser.add_argument("--human", "-H", action="store_true", help="Save human readable page")
parser.add_argument("--raw", "-r", action="store_true", help="Save raw page, for the calendar")
parser.add_argument("--comment", "-c", action="store", type=str, default="", help="Comment of the modification")
parser.add_argument("--debug", "-d", action="store_true", help="Don't commit to the wiki, render in stdout")
parser.add_argument("--stdout", "-o", action="store_true", help="Render the wiki page in stdout")
parser.add_argument("--wiki", "-w", action="store_true", help="Send modifications to the wiki")
def handle(self, *args, **options):
if options["raw"]:
Command.refresh_raw_wiki_page(options["comment"], options["debug"])
Command.refresh_raw_wiki_page(options["comment"], options["stdout"], options["wiki"])
if options["human"]:
Command.refresh_human_readable_wiki_page(options["comment"], options["debug"])
Command.refresh_human_readable_wiki_page(options["comment"], options["stdout"], options["wiki"])

View File

@ -1,13 +1,15 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from datetime import date
from django.core.mail import send_mail
from django.core.management import BaseCommand
from django.db.models import Q
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.translation import activate
from note.models import NoteUser
from note.models import NoteUser, Note
class Command(BaseCommand):
@ -19,9 +21,10 @@ class Command(BaseCommand):
def handle(self, *args, **options):
activate('fr')
notes = NoteUser.objects.filter(
notes = Note.objects.filter(
Q(noteuser__user__memberships__date_end__gte=date.today()) | Q(noteclub__isnull=False),
balance__lte=-options["negative_amount"],
user__memberships__date_end__gte=timezone.now().date(),
is_active=True,
).order_by('balance').distinct().all()
if options["spam"]:

View File

@ -14,8 +14,15 @@ from note.tables import HistoryTable
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('--notes', '-n', type=int, nargs='+', help='Select note ids')
parser.add_argument('--debug', '-d', action='store_true', help='Debug mode, print mails in stdout')
def handle(self, *args, **options):
activate('fr')
if "notes" in options:
notes = NoteUser.objects.filter(pk__in=options["notes"]).all()
else:
notes = NoteUser.objects.filter(
user__memberships__date_end__gte=timezone.now(),
user__profile__report_frequency__gt=0,
@ -41,11 +48,16 @@ class Command(BaseCommand):
context = dict(
user=note.user,
table=table,
last_transactions=last_transactions,
incoming=incoming,
outcoming=outcoming,
diff=incoming - outcoming,
now=now,
last_report=last_report,
)
plain = render_to_string("note/mails/weekly_report.txt", context)
html = render_to_string("note/mails/weekly_report.html", context)
note.user.email_user("[Note Kfet] Rapport de la Note Kfet", html, html_message=html)
if options["debug"]:
self.stdout.write(plain)
else:
note.user.email_user("[Note Kfet] Rapport de la Note Kfet", plain, html_message=html)

View File

@ -1,11 +1,9 @@
#!/bin/bash
# Create backups directory
[[ -d /var/www/note_kfet/backups ]] || (mkdir /var/www/note_kfet/backups && chown www-data:www-data /var/www/note_kfet/backups)
# Create temporary backups directory
[[ -d /tmp/note-backups ]] || mkdir /tmp/note-backups
date=$(date +%Y-%m-%d)
# Backup database and save it as tar archive
su postgres -c "pg_dump -F t note_db" | tee "/var/www/note_kfet/backups/$date.tar" > /dev/null
su postgres -c "pg_dump -F t note_db" | tee "/tmp/note-backups/$date.tar" > /dev/null
# Compress backup as gzip
gzip "/var/www/note_kfet/backups/$date.tar"
chown www-data:www-data "/var/www/note_kfet/backups/$date.tar.gz"
# Delete backups that have more than 30 days
find /var/www/note_kfet/backups -type f -mtime +30 -exec rm {} \;
gzip "/tmp/note-backups/$date.tar"
scp "/tmp/note-backups/$date.tar.gz" "club-bde@zamok.crans.org:backup/$date.tar.gz"

12
shell/docker_bash Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash
if [ -r Dockerfile ]; then
if [ -w /var/run/docker.sock ]; then
docker build -t nk20 .
docker run -it -u $(id -u):$(id -g) --rm -v "$(pwd):/var/www/note_kfet/" -p 80:8080 nk20 bash
else
echo "Merci de rejoindre le groupe docker (ou lancez ce script en sudo) afin de pouvoir vous connecter au socket Docker."
fi
else
echo "N'exécutez ce fichier que dans la racine de votre projet, afin de pouvoir localiser le fichier Dockerfile."
fi

View File

@ -3,7 +3,5 @@ sudo service postgresql stop
sudo service postgresql start
sudo -u postgres sh -c "dropdb note_db && psql -c 'CREATE DATABASE note_db OWNER note;'";
echo 'reset db';
find apps/ -path "*/migrations/*.py*" -not -name "__init__.py" -delete
./manage.py makemigrations
./manage.py migrate
./manage.py loaddata initial

View File

@ -0,0 +1,27 @@
Bonjour {{ user.first_name }} {{ user.last_name }},
Ce message vous est envoyé automatiquement par la Note Kfet du BDE de
l'ENS Cachan, à laquelle vous êtes inscrit·e. Si vous n'êtes plus
adhérent·e, vous n'êtes pas nécessairement concerné·e par la suite
de ce message.
La Note Kfet 2020 vient d'être déployée, succédant à la Note Kfet 2015.
Les données ont été migrées.
Toutefois, la nouvelle note utilise un algorithme de normalisation des alias
permettant de rechercher plus facilement un nom de note, et empêchant la
création d'un alias trop proche d'un autre.
Nous vous informons que les alias suivants ont été supprimés de votre compte,
jugés trop proches d'autres alias déjà existants :
{{ aliases_list|join:", " }}
Nous nous excusons pour le désagrément, et espérons que vous pourrez
profiter de la nouvelle Note Kfet.
Cordialement,
--
Le BDE

View File

@ -0,0 +1,27 @@
Bonjour {{ user.first_name }} {{ user.last_name }},
Ce message vous est envoyé automatiquement par la Note Kfet du BDE de
l'ENS Cachan, à laquelle vous êtes inscrit·e. Si vous n'êtes plus
adhérent·e, vous n'êtes pas nécessairement concerné·e par la suite
de ce message.
La Note Kfet 2020 vient d'être déployée, succédant à la Note Kfet 2015.
Les données ont été migrées.
Toutefois, la nouvelle note utilise un algorithme de normalisation des alias
permettant de rechercher plus facilement un nom de note, et empêchant la
création d'un alias trop proche d'un autre.
Nous vous informons que votre pseudo {{ old_username }} fait pas partie des
alias problématiques. Il a été remplacé par le pseudo {{ new_username }},
que vous devrez utiliser pour pouvoir vous connecter. Il sera ensuite
possible de modifier votre pseudo.
Nous nous excusons pour le désagrément, et espérons que vous pourrez
profiter de la nouvelle Note Kfet.
Cordialement,
--
Le BDE