CAW1 2017 Projet de Julien DE WISSCHER, Lounes SAADI et Andy PAGES

De Ensiwiki
Aller à : navigation, rechercher
Project schedule.png
Titre du projet Square
Cadre Construction d'application web

Équipe Julien De Wisscher
Andy Pagès
Lounes Saadi
Encadrants Sebastien Viardot


Présentation du projet

Description générale

L'objectif de Square est de mettre à disposition une plateforme de création et de partage de pixel art. Le développement est effectué à l'aide du framework Django.

Cahier des charges

Le projet devra comporter les éléments suivants :

  • Utilisation de l'un des frameworks : play utilisant le patron modèle-vue-contrôleur
  • Gestion des rôles avec des utilisateurs différents ayant des droits et des rôles différenciés (2 rôles au minimum)
  • Site adapté à plusieurs terminaux dont une version mobile (par exemple en utilisant Bootstrap)
  • Mise en place de jeux de tests unitaires : pour tester la partie modèle et contrôleur.
  • Mise en place de jeux de tests fonctionnels avec des technologies de type selenium.
  • Utilisation webservice (cf. https://code.google.com/intl/fr/apis/language/translate/v2/getting_started.html)
  • Optionnel : abonnement rss
  • Optionnel : partie du site en gwt ou avec un framework type smartclient

Spécifications

Cas d'utilisations

En tant que Visiteur, je veux :

  • Créer un compte

En tant qu'Utilisateur, je veux :

  • Créer un pixel art
  • Voir les pixel art de mes amis
  • Voir les pixel art de tout le monde
  • Commenter un pixel art
  • Aimer un pixel art
  • Suivre un ami
  • Accéder à des informations de mon compte
  • Avoir accès à des statistiques
  • Modifier mon compte
  • Supprimer mon compte
  • Être notifié quand un ami publie un pixel art
  • Être notifié quand quelqu'un me suit
  • Être notifié quand quelqu'un aime un de mes pixel art
  • Me connecter / déconnecter

En tant qu'Admin, je veux :

  • Comme un utilisateur
  • Modifier les informations d'un utilisateur
  • Supprimer des utilisateurs
  • Supprimer des pixel art
  • Avoir accès à des statistiques

Diagramme de classes

Square models.jpg

Tables

Profile :


Extension de la classe User de Django ; nous permet de stocker (en plus des informations de base), un avatar, le nombre de Followers, de gens suivis (Followings) et le nombre de publications


PixelArt :


Classe représentant les PixelArt que les Utilisateurs peuvent créer via l'éditeur en lien, puis consulter, liker, commenter. Cet objet contient le PixelArt sous la forme d'un tableau de codes hexadécimaux représentant les couleurs de chaque pixel, le créateur, le nombre de likes, de commentaires, un titre ainsi qu'une date de création.

Nous avons choisi de stocker les nombres de likes/commentaires pour faciliter l'accès à ces données en frontend.


Comments :


Classe représentant les commentaires que l'on peut écrire sur un PixelArt. Elle contient le PixelArt auquel le commentaire se réfère, l'auteur, le contenu texte et la date de publication.


Likes :


Classe représentant les likes que l'on peut "faire" sur un PixelArt. Elle contient le PixelArt auquel le commentaire se réfère et l'auteur.


Following :


Classe représentant la notion de follow présentée auparavant : un utilisateur peut suivre quelqu'un d'autre. Elle contient donc l'Utilisateur à l'origine du Follow, l'Utilisateur suivi, et la date de création.


NotificationsFollowing, NotificationsComment, NotificationsLike :


Ces classes représentent les notifications que reçoive un Utilisateur après (resp.) avoir été suivi, qu'un commentaire ait été publié sur l'un de ses PixelArt, ou qu'un de ses PixelArt ait été liké. Nous avons choisi de créer trois classes distinctes pour faciliter l'utilisation des clefs étrangères et pour plus de clarté niveau backend (API).


Token :


Cette classe est une classe intégrée à Django de base. Elle permet de générer un Token d'authentification associé à un Utilisateur. C'est ce que nous utilisons pour authentifier les Utilisateurs et garantir la sécurité d'accès aux données. Elle contient le Token, l'utilisateur en question et la date de création du Token.


Autres :


Les autres classes ne sont pas présentées ici car, intégrées dans Django, mais non utilisées côté applicatif. Nous avons néanmoins choisi d'afficher le diagramme de classes complet pour montrer l'utilisation que nous avons faîte du framework Django, à savoir en profitant des classes déjà disponibles pour accélérer et rendre plus robuste (les solutions étant éprouvées sur de nombreuses releases) notre développement.


Environnement de développement

Technologies utilisées

  • Python
    • Django
    • Django REST Framework : extension de Django pour faciliter la création d'API Web
      • drfdocs : Librairie pour DRF de génération automatique de documentation
      • django-cors-headers : Libraires pour gérer les CORS headers
  • BDD
    • SQLite
  • Workflow
    • GitHub
    • Travis CI
    • Trello : gestion de tâches d'un projet
    • Postman : utilitaire pour faciliter le test manuel des requêtes sur un API


Pour les technologies utilisées en front, nous avons choisi de séparer totalement le back et le front en utilisant un deuxième serveur grâce à Node.JS et Angular.js. Nous aurions pu utiliser simplement Angular.js sans Node.JS (à l'aide de Yeoman, Grunt, etc..), mais l'utilisation de Node.JS et son package manager npm est une aide conséquente au développement (hot reload) ainsi qu'une structure robuste pour de future évolutions du client. Nous avons développé le front end sous Node.JS v6 et Angular.js 1.6. Enfin, le langage SASS a été utilisé pour générer les fichiers CSS.

Backend

Model, Serializer et View

Django Rest Framework (DRF) est basé sur 3 principes, le Model qui représente l'object en tant que tel, inséré en base de données ; le Serializer qui permet de "sérialiser" les instances en JSON facilement employable dans le cadre d'une API REST et finalement la View qui s'assimilent aux contrôleurs du modèle MVC (elle est atteinte via l'API et exécute les actions demandées).

Ainsi, le diagramme de classes présenté ci-dessus a donné lieu à autant de modèles que de classes.

Concernant les Serializer, nous n'avons pas fait un unique Serializer par modèle, comme le suggère le workflow classique. Par exemple, pour l'accès à un User : si un administrateur veut récupérer un User précis, alors il récupèrera tous les champs. Par contre, si un User veut récupérer un autre User, il est préférable qu'il n'ait pas accès à l'adresse mail par exemple. En ce sens, le Serializer utilisé lorsque la requête provient d'un User est le Serializer "restreint" aux informations de base.

Les Views donnent accès à l'API représenté ci-dessous. Les méthodes sont atteintes via des routes spécifiées dans urls.py.

API

  • Pour les données à passer en paramètre, se référer aux modèles (un POST nécessitera les attributs de la classe en question).
  • Un POST ne nécessite pas de passer l'User couramment authentifié en paramètre : cela est fait automatiquement côté back-end via le Token utilisé par la requête. Cela évite aussi les accès non-autorisés (suppression de données d'un autre User, accès anonymes, etc..).


/users/


  • GET : Retourne tous les users, seulement si l’on est authentifié en tant que superuser
  • POST : Créer un User avec les données passées en paramètre (User)
  • PUT : Modifie les données de l’User couramment authentifié avec les données passées en paramètre


/user/<id_user>


  • GET : Permet de récupérer un User en particulier (l’endpoint diffère si l’on est authentifié en tant qu’admin ou non : admin => tous les champs, User classique => username, first_name, last_name, date_joined)


/user/find/<username>


  • GET : Permet de chercher un utilisateur selon une chaîne de caractère donnée


/pixelarts/


  • GET : Retourne tous les PixelArts nous appartenant
  • POST : Créer un PixelArt avec les données passées en paramètre


/pixelarts/all/


  • GET : Retourne tous les PixelArts


/pixelart/<id_pixel>


  • GET : Retourne le PixelArt
  • PUT : Modifie les données du PixelArt grâce aux données passées en paramètre
  • DELETE : Supprime le PixelArt s’il appartient au User couramment authentifié


/followings/


  • GET : Retourne tous les followings que l’on a (toute la table en BDD si superuser)
  • POST : Créer un Following avec les données passées en paramètre


/following/<id_user>


  • GET : Retourne le Following s'il existe (l'User authentifié est-il un follower de l'User demandé ?)
  • DELETE : Supprime le Following s’il appartient au User authentifié


/followings/pixelarts/


  • GET : Liste tous les PixelArts pour les Users que le User authentifié follow


/likes/


  • GET : Retourne tous les likes que l’on a fait (toute la table en BDD si superuser)
  • POST : Ajouter un Like avec les données passées en paramètre


/like/<id_like>


  • GET : Retourne le like demandé
  • DELETE : Supprime le like s’il appartient au User authentifié


/comments/


  • GET : Retourne tous les comments que l’on a fait (toute la table en BDD si superuser)
  • POST : Ajouter un comment avec les données passées en paramètre


/comment/<id_comment>


  • GET : Retourne le comment
  • PUT : Modifie les data du Comment grâce aux données passées en paramètre
  • DELETE : Supprime le Comment s’il appartient au User couramment authentifié


/like_pixel/<id_pixel>


  • GET : Retourne le PixelArt si l'User authentifié actuellement l’a liké, rien sinon
  • DELETE : Supprime le Like sur le PixelArt spécifié (de l’User couramment authentifié)


/pixelart/<id_pixel>/comments


  • GET : Retourne les commentaires d’un PixelArt donné
  • POST : Post un commentaire avec les données passées en paramètre


/pixelart/<id_pixel>/comment/<id_comment>


  • GET : Retourne le commentaire demandé du PixelArt specifié
  • DELETE : Supprime le commentaire spécifié du PixelArt donné


/notifications/


  • GET : Retourne toutes les Notifications qui sont associés à l'User couramment authentifié
  • PUT : Passe toutes les Notifications associées à "noticed"


/auth/


  • POST : Retourne le Token du User envoyé (username, password)


Utilisation d'un WebService

La modélisation de notre backend est déjà sous forme de webservice, donc l'utilisation d'un webservice est réalisée pendant tout notre projet. Mais nous avons souhaité connecter le backend à un webservice externe. Celui-ci permet à l'application de générer des avatars pour la photo de profil des utilisateurs de Square. Le nom de ce webservice est : robohash. Il suffit de faire une requête GET à l'adresse : https://robohash.org/ en rajoutant une chaîne de caractères unique. La chaîne est alors hashée par le webservice. Ce hash lui permet de générer un avatar automatiquement.

Exemple :

https://robohash.org/sebastien_viardot

Retourne : Sebastien viardot.png

Tests

Tests unitaires

Nous utilisons le système de test automatisé que fournit Django ici (basé sur unitest). Les tests sont écrits sous forme de classes puis méthodes dans le fichiers squareapp/tests.py. Ils comportent aussi les tests de l'API.

Pour lancer les tests unitaires, il faut utiliser la commande python manage.py test.


Tests API

Comme expliqué précédemment, les tests de l'API se trouvent dans le fichier squareapp/tests.py. Ils vérifient l'autorisation d'accès aux données (authentifé/non authentifié/tentative d'accès à des données de tiers), ainsi que les résultats "classiques" d'accès aux données en base. Les permissions étant gérées de manière générique pour chaque route, nous avons pris le parti de limiter les tests à quelques cas dans le sens où le comportement est le même partout.

Par soucis de temps, nous n'avons pas eu le temps d'écrire l'intégralité des cas de tests pour toutes les routes utilisables.

Nous avons néanmoins tenté d'écrire un maximum de tests sur les routes générales (e.g /users/). En effet, de /users/ à par exemple /user/<id_user>, la requête ne diffère que d'une requête sur la base avec un paramètre. Le processus est donc le même. Il aurait néanmoins été intéressant et même nécessaire de tester ces fonctions avec une granularité fine pour s'assurer pleinement de la non regression et la fiabilité de notre base de code.

Tests Front

Malheureusement pour des raisons de temps (projets en parallèles, révisions), nous n'avons pas implémenté de tests en front end. Si nous avions eu le temps nous aurions utilisé Protractor [1] pour tester Angular.js efficacement.

Permissions

Les permissions sont gérées de manière classique à la fois du côté frontend et du côté backend :

  • Côté frontend, un cookie est créé grâce à un Token renvoyé par la route /auth/ et est envoyé à chaque requête
  • Côté backend, le Token permet d'identifier l'utilisateur : ainsi on sait s'il essaie d'accéder à des données lui appartenant ou non ; il est donc simple d'autoriser ou de refuser l'accès.

Le Token permet donc de s'abstraire de l'envoie de données malicieuses, car l'utilisateur est obligé d'être authentifié pour envoyer une requête. Les cookies sont stockés en frontend par Angular, aucun lien avec le serveur, ce qui permet de limiter grandement le risque de vol de cookie.

Screencast

https://www.youtube.com/watch?v=t8iBz7MKKfs&feature=youtu.be