You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
blog/posts/2015/2015-09-14-owncloud-reminde...

219 lines
8.9 KiB
Markdown

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

<!-- title: Jouons avec Awk, Bash et Owncloud -->
<!-- category: GNU/Linux -->
<!-- tag: planet -->
Un souci de synchronisation du calendrier entre Owncloud et mon téléphone a
été le prétexte à bidouiller une fonctionnalité de rappel des événements par
e-mail.<!-- more --> Pourquoi des e-mail ? Parce que je suis un fana de ce moyen de
communication, la preuve [ici](http://blogduyax.madyanne.fr/du-nouveau-sur-
pecosys.html) et [](http://blogduyax.madyanne.fr/srmail.html).
Donc ce que je veux c'est un joli e-mail le lundi matin qui résume mes rendez-
vous de la semaine (description, date et heure) et puis chaque matin au réveil
un e-mail par événement avec le fichier ICS en pièce jointe. [ICS
késako](https://fr.wikipedia.org/wiki/ICalendar) ? Un vieux mais très actuel
standard de description d'un événement reconnu par la plupart des calendriers.
L'intérêt d'avoir le fichier ICS c'est de pouvoir l'ajouter au calendrier
local du téléphone en un clic et de paramétrer le rappel en connaissance de
cause (le matin on a une petite idée de comment va se profiler sa journée).
Plutôt que de coder dans un langage évolué, je me suis amusé à réaliser cela
avec les outils présent en standard sur GNU/Linux (**Awk** et **Bash**) pour
le backend MySQL d'Owncloud. C'est didactique car il est toujours préférable
de privilégier l'accès aux données par une API qui sera plus ou moins bien
maintenue dans le temps par les développeurs que d'attaquer directement la
base de données. D'abord jetons un oeil à structure de la base de donnée
Owncloud.
La table *oc_clndr_calendars* permet de retrouver l'id de calendrier de notre
utilisateur.
mysql> SELECT * FROM oc_clndr_calendars;
+----+------------+-------------+-----------+--------+------+---------------+---------------+----------+-----------------------+
| id | userid | displayname | uri | active | ctag | calendarorder | calendarcolor | timezone | components |
+----+------------+-------------+-----------+--------+------+---------------+---------------+----------+-----------------------+
| 1 | yax | Personnel | personnel | 1 | 196 | 0 | NULL | NULL | VEVENT,VTODO,VJOURNAL |
+----+------------+-------------+-----------+--------+------+---------------+---------------+----------+-----------------------+
Et la table *oc_clndr_objects* contient les évènements :
mysql> DESC oc_clndr_objects;
+--------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| calendarid | int(10) unsigned | NO | | 0 | |
| objecttype | varchar(40) | NO | | | |
| startdate | datetime | YES | | 1970-01-01 00:00:00 | |
| enddate | datetime | YES | | 1970-01-01 00:00:00 | |
| repeating | int(11) | YES | | 0 | |
| summary | varchar(255) | YES | | NULL | |
| calendardata | longtext | YES | | NULL | |
| uri | varchar(255) | YES | | NULL | |
| lastmodified | int(11) | YES | | 0 | |
+--------------+------------------+------+-----+---------------------+----------------+
On peut récupérer les évènements du jour courant avec la requête suivante :
mysql> SELECT startdate,summary,calendardata FROM oc_clndr_objects WHERE calendarid = 1 AND DATE(startdate) = DATE(NOW()) ORDER by startdate \G;
*************************** 1. row ***************************
startdate: 2015-09-14 10:30:00
summary: Déjeuner avec M.
calendardata: BEGIN:VCALENDAR
VERSION:2.0
PRODID:ownCloud Calendar
CALSCALE:GREGORIAN
BEGIN:VEVENT
UID:95d9221d97
DTSTAMP:20150914T103206Z
CREATED:20150913T170426Z
LAST-MODIFIED:20150914T103206Z
SUMMARY:Déjeuner avec M.
DTSTART;TZID=Europe/Paris:20150914T123000
DTEND;TZID=Europe/Paris:20150914T140000
LOCATION:
DESCRIPTION:
CATEGORIES:
CLASS:PUBLIC
END:VEVENT
END:VCALENDAR
*************************** 2. row ***************************
startdate: 2015-09-14 16:15:00
summary: RV dentiste
calendardata: BEGIN:VCALENDAR
VERSION:2.0
PRODID:ownCloud Calendar
CALSCALE:GREGORIAN
BEGIN:VEVENT
UID:1958bfe4a9
DTSTAMP:20150914T103134Z
CREATED:20150914T103134Z
LAST-MODIFIED:20150914T103134Z
SUMMARY:RV dentiste
DTSTART;TZID=Europe/Paris:20150914T181500
DTEND;TZID=Europe/Paris:20150914T183000
LOCATION:
DESCRIPTION:
CATEGORIES:
END:VEVENT
END:VCALENDAR
Les colonnes intéressantes sont :
- *calendarid* pour filtrer les évènements de notre utilisateur Owncloud
- *summary* : le libellé de l'évènement
- *startdate* : la date de début de l'évènement
- *calendardata* : l'évènement au format iCalendar
Ce qu'on veut c'est générer un shell script qui récupère les informations du
jour et envoie un e-mail par évènement avec le fichier ICS en pièce jointe.
L'envoi est réalisé par l'utilitaire **mpack**. Le résultat final espéré pour
notre exemple est ce script :
``` shell
#
STARTDATE="`date -d '2015-09-14 10:30:00-000' '+%a %e %b %R'`"
SUMMARY="Déjeuner avec M."
echo "BEGIN:VCALENDAR" >event.ics
echo "VERSION:2.0" >> event.ics
echo "PRODID:ownCloud Calendar" >> event.ics
echo "CALSCALE:GREGORIAN" >> event.ics
echo "BEGIN:VEVENT" >> event.ics
echo "UID:95d9221d97" >> event.ics
echo "DTSTAMP:20150914T103206Z" >> event.ics
echo "CREATED:20150913T170426Z" >> event.ics
echo "LAST-MODIFIED:20150914T103206Z" >> event.ics
echo "SUMMARY:Déjeuner avec M." >> event.ics
echo "DTSTART;TZID=Europe/Paris:20150914T123000" >> event.ics
echo "DTEND;TZID=Europe/Paris:20150914T140000" >> event.ics
echo "LOCATION:" >> event.ics
echo "DESCRIPTION:" >> event.ics
echo "CATEGORIES:" >> event.ics
echo "CLASS:PUBLIC" >> event.ics
echo "END:VEVENT" >> event.ics
echo "END:VCALENDAR" >>event.ics
mpack -s "$SUMMARY - $STARTDATE" event.ics $1
#
STARTDATE="`date -d '2015-09-14 16:15:00-000' '+%a %e %b %R'`"
SUMMARY="RV dentiste"
echo "BEGIN:VCALENDAR" >event.ics
echo "VERSION:2.0" >> event.ics
echo "PRODID:ownCloud Calendar" >> event.ics
echo "CALSCALE:GREGORIAN" >> event.ics
echo "BEGIN:VEVENT" >> event.ics
echo "UID:1958bfe4a9" >> event.ics
echo "DTSTAMP:20150914T103134Z" >> event.ics
echo "CREATED:20150914T103134Z" >> event.ics
echo "LAST-MODIFIED:20150914T103134Z" >> event.ics
echo "SUMMARY:RV dentiste" >> event.ics
echo "DTSTART;TZID=Europe/Paris:20150914T181500" >> event.ics
echo "DTEND;TZID=Europe/Paris:20150914T183000" >> event.ics
echo "LOCATION:" >> event.ics
echo "DESCRIPTION:" >> event.ics
echo "CATEGORIES:" >> event.ics
echo "END:VEVENT" >> event.ics
echo "END:VCALENDAR" >>event.ics
mpack -s "$SUMMARY - $STARTDATE" event.ics $1
```
Comment fait-on ? On exécute la requête SQL et on la donne à manger à un
script **awk** qui a pour objectif de générer le shell script ci-dessus. Awk a
été inventé pour ce genre de tâche : prendre un fichier en entrée et le
modifier pour créer un fichier en sortie. Le script est assez opaque si on n'a
jamais pratiqué mais l'idée c'est de décrire la structure du document en
entrée (comment distinguer les enregistrements) et de faire correspondre des
traitements à certains enregistrements qu'on identifie par une expression
régulière.
Voci le script awk complet :
``` awk
BEGIN {
FS="\n"
OFS=""
ORS="\n"
print "#!/bin/sh"
print " "
}
# blank lines
/^$/ { next }
# record header
$1 ~ /^\*\*\*\*/ {
next
}
# summary field
$1 ~ /^[ ]*summary\:/ {
idx = match($1, /summary\:(.*)/)
print "SUMMARY=\"" substr($1, idx + 9) "\""
next
}
# startdate field
$1 ~ /^[ ]*startdate\: / {
match($1, /startdate\: /)
print "STARTDATE=\"`date -d '" substr($1, RSTART + RLENGTH) "-000' '+%a %e %b %R'`\""
next
}
# vcalendar start tag
$1 ~ /^[ ]*calendardata\: / {
match($1, /calendardata\: /)
print "echo \"" substr($1, RSTART + RLENGTH) "\" >event.ics"
next
}
# vcalendar end tag
$1 ~ /^END\:VCALENDAR/ {
print "echo \"" $1 "\" >>event.ics"
print "mpack -s \"$SUMMARY - $STARTDATE\" event.ics $1"
print ""
next
}
# vcalendar body
{
print "echo \"" $0 "\" >> event.ics"
}
```
Il ne reste plus qu'à orchestrer tout cela dans un shell script et de
l'appeler par une tâche **cron**. Le script complet gère les rappels du jour
et les rappels pour la semaine à venir. Il est disponible [sur mon compte
GitHub](https://github.com/kianby/owncloud_calremind).