Suite à l’utilisation de Seafile alternative open-source à Dropbox, je me suis posé la question du rajout de fonctionnalité dans cette solution.
1/ Installation de Seafile Community Edition 5.1.3
Pour tester le développement, j’ai utiliser un serveur seafile version 5.1.3 plus petite et plus simple pour commencer à étudier les APIs. Je souhaite intervenir uniquement sur la partie Web appelée Seahub (en rouge sur le diagramme ci-dessous), donc je ne réalise pas une installation « build » comme expliquer par seafile mais une installation classique.
Editer le fichier « .\seafile-server-5.1.3\seahub\seahub\settings.py » pour mettre les variables facilitant le développement:
# DEBUG = False DEBUG = True TEMPLATE_DEBUG = DEBUG
Démarrer ensuite et utiliser Seafile de manière classique pour vérifier que tout est opérationnel.
Après l’installation classique du serveur car je ne souhaite intervenir que sur la partie site web développé en Django et en python, il suffit d’activer les réglages de débogage.
2/ Localisation de la zone d’intervention
La problématique que je rencontre avec Seafile est de comprendre l’organisation du code; où intervenir pour ajouter une fonctionnalité.
En premier lieu, de manière classique en développement web, je cherche avec l’inspecteur de Chrome Developer Tools, la zone HTML qui m’intéresse:
On peut voir que le <div class= »op-containter »> gère la zone où on pourrait rajouter une fonctionnalité sur un fichier stocké dans le Seafile.
Une petite recherche via la console cygwin avec un grep pour trouver le fichier intéressant dans seahub/seahub/templates/js/templates.html
Il y a trois fois le tag que l’on cherche, une fois pour une bibliothèque, une fois pour un dossier et enfin la dernière fois pour un fichier.
Ajoutons donc une nouveau élément à la liste juste après le choix « Ouvrir avec le client »
<li><a class="op open-via-client" href="seafile://openfile?repo_id=<%- repo_id %>&path=<% print(encodeURIComponent(dirent_path)); %>">{% trans "Open via Client" %}</a></li> <!-- PJE --> <li> <a class="op open-diff" href="<% print("http://URL/"); %>">{% trans "Diff" %}</a> </li> <!-- /PJE -->
L’entrée du menu est visible dans l’interface web mais pour l’instant ne renvoie sur aucun site. L’URL que l’on souhaite fabriquer est recopiable depuis la page « Historique » du fichier.
L’URL est de la forme suivante:
http://<Nom_du_serveur:port>/repo/text_diff/<id_de_l_objet>/?p=<chemin_nom_fichier>&commit=<id_commit>
Cela permet de présenter l’interface qui montre les différences entre la dernière version du fichier et l’avant dernière version.
3/ Comment fabriquer cette URL dans le menu associé avec le fichier
Pour repérer le fichier python qui envoie les données, en premier lieu, j’ai remarqué que l’affichage de la liste des fichiers est réalisé en arrière plan du chargement de la page via un appel ajax comme visible dans le Chrome Developer Tools:
en affichant les données envoyé par le serveur django, on peut voir que la liste des données envoyé est réduite:
{ "encrypted": false, "is_virtual": false, "user_perm": "rw", "dirent_list": [ {"obj_id": "79d2a1ab64773b325d2b19fb80a4781af5bd1dd2", "file_icon": "txt.png", "perm": "rw", "last_update": "<time datetime=\"2017-05-24T16:42:46\" is=\"relative-time\" title=\"mer, 24 Mai 2017 16:42:46 +0800\" >Il y a 7 jours</time>", "last_modified": 1495640566, "file_size": "184\u00a0bytes", "is_file": true, "obj_name": "matlab1.txt", "starred": false}, {"obj_id": "b88ab96740ef53249b9d21fb3fa28050842266ba", "file_icon": "word.png", "perm": "rw", "last_update": "<time datetime=\"2016-09-14T12:19:06\" is=\"relative-time\" title=\"mer, 14 Sep 2016 12:19:06 +0800\" >2016-09-14</time>", "last_modified": 1473851946, "file_size": "293,5\u00a0KO", "is_file": true, "obj_name": "seafile-tutorial.doc", "starred": false}], "is_repo_owner": true, "repo_name": "Ma biblioth\u00e8que" }
On peut voir que l’id de commit n’est pas indiqué dans aucun des deux fichiers. Pour fabriquer notre URL cet identifiant ce qui est necéssaire pour construire l’URL.
En localisant avec encore un grep d’où provient la requête Ajax, j’ai ouvert le fichier dans PyCharm Community Edition pour trouver la boucle qui fabrique le fichier Json.
Le fichier ajax.py dans le dossier seahub/views/ajax.py
Et plus particulièrement c’est la fonction list_lib_dir dans ce fichier qui fabrique le fichier JSON. Voici spécifiquement l’endroit qui gère la boucle sur les fichiers:
for f in file_list: f_ = {} f_['is_file'] = True f_['file_icon'] = file_icon_filter(f.obj_name) f_['obj_name'] = f.obj_name f_['last_modified'] = f.last_modified f_['last_update'] = translate_seahub_time(f.last_modified) f_['starred'] = f.starred f_['file_size'] = filesizeformat(f.file_size) f_['obj_id'] = f.obj_id f_['perm'] = f.permission # perm for file in current dir
Nous allons rajouté une propriété à la liste f_ qui s’appellera [‘diff’].
Voici l’instruction qui fabrique une valeur URL pour tester que côté navigateur la récupération s’effectue correctement:
f_['diff'] = 'http://URL/'
Donc côté page html je peux remodifier le fichier template.html pour intégrer la propriété [‘diff’]
<li><a class="op open-diff" href="<% print(dirent.diff); %>">{% trans "Diff" %}</a></li>
Cela doit permettre d’afficher dans le navigateur le choix Diff dans le menu avec une valeur qui provient du programme python.
4/ Code final
Voici le code final pour fabriquer les variables path, obtenir la liste des versions d’un fichier (commits) et ainsi fabriquer l’URL valide:
# PJE path = path + f.obj_name commits = seafile_api.get_file_revisions(repo_id, path, -1, -1) if len(commits) > 1: # http://127.0.0.1:8000/repo/text_diff/b8f97076-d57f-4f49-aaa8-d0531de51f12/?p=/matlab1.txt&commit=c65591a759910cfe4fb76ff18e1047f202424b31 f_['diff'] = SERVICE_URL + "/repo/text_diff/" + repo_id + "/?obj_id=" + f.obj_id \ + "&commit=" + str(commits[0].__getattr__("id") ) + "&p=" + str(path) else: f_['diff'] = '' # /PJE
On peut noter que s’il n’y a pas de versions alors la valeur f_[‘diff’] est créé vide. Cela nous oblige à reprendre la page html pour ne pas afficher l’option Diff dans le menu dans ce cas là:
<li><a class="op open-via-client" href="seafile://openfile?repo_id=<%- repo_id %>&path=<% print(encodeURIComponent(dirent_path)); %>">{% trans "Open via Client" %}</a></li> <!-- PJE --> <% if (dirent.diff != '' ) { %> <li><a class="op open-diff" href="<% print(dirent.diff); %>">{% trans "Diff" %}</a></li> <% } %> <!-- /PJE -->
Voici l’affichage de menu sans l’item Diff :
Il est inutile de présenter une option si elle n’est pas disponible. Une autre solution que je n’ai pas exploré est de présenter l’option dans le menu mais grisée et désactivée.
5/ Debug
J’ai découvert de manière plus ou moins fortuite comment debogger dans PyCharm Community Edition avec Seafile. Après avoir démarré le serveur Seafile avec l’option Debug=True et mis un point d’arrêt dans le code fichier ajax.py, il suffit d’attacher le debogger de Pycharm au programme python qui démarre seahub:
Ensuite en consultant la page web on a le deboggeur qui s’enclenche sur le point d’arrêt. La seule partie du code pour l’instant que je n’arrive pas à tracer se trouve dans le code des pages html écrit dans le langage de template de python. Par contre, j’arrive très bien à activer le deboggage dans le navigateur pour comprendre comme avec les autres langages PHP/Java/Perl/etc. ce qui se passe côté Javascript du navigateur.
6/ Conclusion
Ce le menu fonctionne correctement, il me parait encore un peu complexe de comprendre où intervenir pour que cette « nouvelle fonctionnalité » (elle se trouve ailleurs dans Seahub en fait), soit résistante quelque soit la situation (fichier privé, navigateur peu récent, etc.)
C’est le premier développement que je fais en python avec Seafile, cela me motive pour continuer mai