# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
import os
from urllib.parse import urlencode
from urllib.request import Request, urlopen
from bs4 import BeautifulSoup
from activity.models import Activity
from django.core.management import BaseCommand
from django.urls import reverse
from django.utils import timezone
class Command(BaseCommand):
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
## Adapté par [[WikiYnerant|ÿnérant]] du script de by 20-100, largement inspiré de la version de Barbichu.
"""
intro_generic = """ * Elle est générée automatiquement par la [[NoteKfet/NoteKfet2020|Note Kfet 2020]]
* 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"))
@staticmethod
def connection(url):
"""Se logue sur le wiki et renvoie le cookie de session"""
parameters = {
'action': 'login',
'login': 'Connexion',
'name': os.getenv("WIKI_USER", "NoteKfet2020"),
'password': os.getenv("WIKI_PASSWORD"),
}
# Il faut encoder ça proprement
data = urlencode(parameters).encode("utf-8")
request = Request(url, data)
# La requête est envoyée en HTTP POST
response = urlopen(request)
# a priori la page elle-même je m'en carre…
response.read(2)
# …ce qui m'intéresse, c'est le cookie qu'elle me file
cookie = response.headers['set-cookie']
return cookie
@staticmethod
def get_edition_ticket(url, cookie):
"""Récupère le ticket d'édition de la page"""
# On crée la requête d'édition…
suffix = "?action=edit&editor=text"
request = Request(url + suffix)
# …avec le cookie
request.add_header("Cookie", cookie)
# On l'envoie
pagecontent = urlopen(request)
html = pagecontent.read()
soup = BeautifulSoup(html, features="lxml")
# On va chercher le formulaire
form = soup.find(name="form", attrs={"id": "editor"})
# On récupère le ticket dedans
ticket = soup.find(name="input", attrs={"name": "ticket"})
return ticket["value"]
@staticmethod
def edit_wiki(page, content, comment=''):
"""Modifie une page du wiki"""
url = "https://wiki.crans.org/" + page
# On se connecte et on récupère le cookie de session
cookie = Command.connection(url)
# On demande l'édition et on récupère le ticket d'édition de la page
ticket = Command.get_edition_ticket(url, cookie)
# On construit la requête
data = {
'button_save': 'Enregistrer les modifications',
'category': '',
'comment': comment.encode("utf-8"),
'savetext': content.encode("utf-8"),
'action': 'edit',
'ticket': ticket
}
request = Request(url, urlencode(data).encode("utf-8"))
request.add_header("Cookie", cookie)
# On la poste
urlopen(request)
@staticmethod
def format_activity(act, raw=True):
"""Wiki-formate une activité, pour le calendrier raw si ``raw``, pour le human-readable sinon."""
if raw:
return """== {title} ==
start:: {start}
end:: {end}
description:: {description} -- {club}
location:: {location}
""".format(
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.replace("\r", "").replace("\n", "<
>"),
club=act.organizer.name,
location=act.location,
)
else:
return "|| {start} || {title} || {description} || {club} || {location} ||".format(
title=act.name,
start=timezone.localtime(act.date_start).strftime("%d/%m/%Y"),
description=act.description.replace("\r", "").replace("\n", "<
>"),
club=act.organizer.name,
location=act.location,
)
@staticmethod
def get_raw_page():
page = "VieBde/PlanningSoirees/LeCalendrier"
header = Command.acl_header + Command.warning_header
header += """= Introduction =
* Cette page a pour but de recenser les activités BDE afin d'être signalées sur le calendrier de la
[[PageAccueil|page d'accueil]] du wiki.
"""
header += Command.intro_generic
body = "\n".join(Command.format_activity(activity) for activity in Activity.objects.filter(valid=True)
.order_by('-date_start').all())
footer = "\n----\nCatégorieCalendrierCampus"
return page, header + body + footer
@staticmethod
def get_human_readable_page():
page = "VieBde/PlanningSoirees"
header = Command.acl_header + Command.warning_header
header += """= Planning de soirées =
== Introduction ==
* Cette page est destinée à accueillir le planning des soirées BDE.
"""
header += Command.intro_generic + "\n"
body = """== Planning des activités à venir ==
||'''Date'''||'''Titre'''||'''Description'''||'''Par''' ||'''Lieu'''||
"""
body += "\n".join(Command.format_activity(activity, False) for activity in Activity.objects
.filter(valid=True, date_end__gte=timezone.now()).order_by('-date_start').all())
body += """\n\n== Planning des activités passées ==
||'''Date'''||'''Titre'''||'''Description'''||'''Par'''||'''Lieu'''||
"""
body += "\n".join(Command.format_activity(activity, False) for activity in Activity.objects
.filter(valid=True, date_end__lt=timezone.now()).order_by('-date_start').all())
return page, header + body
@staticmethod
def refresh_raw_wiki_page(comment="refresh", print_stdout=False, edit_wiki=False):
page, content = Command.get_raw_page()
if print_stdout:
print(content)
if edit_wiki:
Command.edit_wiki(page, content, comment)
@staticmethod
def refresh_human_readable_wiki_page(comment="refresh", print_stdout=False, edit_wiki=False):
page, content = Command.get_human_readable_page()
if print_stdout:
print(content)
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("--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["stdout"], options["wiki"])
if options["human"]:
Command.refresh_human_readable_wiki_page(options["comment"], options["stdout"], options["wiki"])