JavaScript : comment surcharger console.log()

J’avais besoin de décaler mes log pour voir rapidement si j’étais, ou pas, à l’intérieur d’une fonction.

Eh oui, après plusieurs années, même si on peut faire des points d’arrêt, JavaScript est là pour répondre à des événements utilisateurs et autres… donc il ne faut souvent pas arrêter pendant l’exécution ou la visualisation d’une page Web… on n’a toujours pas d’autre choix que de faire le bon console.log() des familles qui fait que le développement est extrêmement ralenti…

Je me suis donc crée les fonctions log_in(), log() et log_out().
Ainsi, quand j’entre dans une fonction, j’appelle log_in(), et tous mes log() dans cette fonction seront décalés, ce qui fait que je vois immédiatement où sont appelés mes logs ! Ensuite, ne pas oublier de faire un log_out().

let logLevel = 0;
let log = function () {
    let args = Array.from(arguments);
    if (logLevel > 0) {
        args = [Array(logLevel).fill(' ').join('')].concat(args);
    }
    console.log.apply(null, args);
};
let log_in = function () {
    log.apply(null, arguments);
    logLevel++;
}, log_out = function (s) {
    if (logLevel>0) {
        logLevel--;
    }
    log.apply(null, arguments);
};

Django : comment vérifier si on est en mode debug dans le template

Vous trouverez l’information dans beaucoup de sites, et cela semble très simple : dans votre template, il suffit de faire :

{% if not debug %}Je suis en debug !{% endif %}

En réalité cela ne suffit pas.

Il faut dans votre fichier settings.py, configurer correctement les adresses IP’s qui précisent qu’on est / ou pas / en mode « développement » :

INTERNAL_IPS = ['127.0.0.1', ]

(Notez que ce code peut être largement optimisé et dépendant de l’environnement, par exemple j’ai fait un settings.py qui prend cela en compte)

Linux : comment monter un disque réseau automatiquement

Sous Mint, Lorsque mon PC démarre, je veux qu’il « monte » automatiquement mes disques et qu’il fasse quelques vérifications au passage (dossier existant etc).
Problème : il arrive parfois la même chose que sous Windows, à savoir que si le mount ne fonctionne pas, il faut le faire à la main.
J’ai donc essayé de suivre plusieurs tutoriels et la plupart disaient d’ajouter dans les tâches planifiées (« cronjob« ) une ligne qui commençait par @reboot.

Je ne sais pas pourquoi, mais sur ma version de Mint, il ne connaissait pas @reboot.

Après pas mal de recherches, voici ce que j’ai trouvé, et qui fonctionne parfaitement :

  • Éditer /etc/rc.local
  • Lui ajouter la ligne de commande que l’on veut faire

Donc mon fichier /etc/rc.local j’ai donc deux lignes de code :
/home/olivier/apply.config.perso.sh -f /home/olivier/boot.log
exit 0

(J’ai enlevé les commentaires très importants qu’il y a dans le fichier, à vous de les lire !)
Le code précédent signifie « lance le script /home/olivier/apply.config.perso.sh« .

Et je me suis fait mon script, soit /home/olivier/apply.config.perso.sh :

(Il prend en compte le paramètre « -f » pour préciser le fichier de sortie, comme cela je logue tout, on n’est jamais assez prudent).
# ----------------------------------------------
# command line options
# first save args to pass them later on to other scripts:
args=("$@")
while [ "$1" != "" ]; do
    case $1 in
        -f | --file ) shift
                                # test if output_filename starts with "-":
                                if [[ "$1" =~ ^-.* ]]; then
                                    usage
                                    exit
                                fi
                                # from that point on:
                                # direct all stdout and stderr to $1:
                                exec &>>$1
                                ;;
        -u ) # ignored here, for mount script (later in there)
                                ;;
        -h | --help ) usage
                                exit
                                ;;
        * ) usage
                                exit 1
    esac
    shift
done
echo "`(date '+%Y.%m.%d-%Hh%Mm%Ss')` $filename > Applying my own configuration..."
sudo -Hu olivier gsettings set org.cinnamon.settings-daemon.peripherals.keyboard delay 120
sudo -Hu olivier gsettings set org.cinnamon.settings-daemon.peripherals.keyboard repeat-interval 18
if mountpoint -q "/mnt/Olivier"; then
    echo "`(date '+%Y.%m.%d-%Hh%Mm%Ss')` $filename > Already mounted, nothing to do."
else
    delay=1
    while ! mountpoint -q "/mnt/Olivier"; do
        echo "`(date '+%Y.%m.%d-%Hh%Mm%Ss')` $filename > Trying to mount..."
        # re-pass the same arguments via "${args[@]}"
        /home/olivier/mount.diskstation.sh "${args[@]}"
        sleep $delay
        if [ "$delay" -gt 60 ]; then
            echo "`(date '+%Y.%m.%d-%Hh%Mm%Ss')` $filename > Couldn't mount! Too long! Exiting."
            exit 1
        fi
        delay=$((delay+5))
    done
    echo "`(date '+%Y.%m.%d-%Hh%Mm%Ss')` $filename > Successful mount."
fi
echo "`(date '+%Y.%m.%d-%Hh%Mm%Ss')` $filename > Done."

Explications :

Les deux ordres gsettings set org.cinnamon.settings-daemon.peripherals.keyboard modifient la vitesse de mon clavier (qui n’est, de base, pas assez rapide pour moi).

L’ordre /home/olivier/mount.diskstation.sh monte mon disque.

Ensuite je fais une boucle qui vérifie si mon « mount » est réussi ou pas : tant que ce n’est pas le cas, il attend un « compteur » qu’il augmente de 5s à chaque boucle, et tout ça au maximum 60 fois. Si vraiment il n’y arrive pas, il logue le problème et quitte.

Tout fonctionne parfaitement depuis maintenant 2 ans !

Django : faire des pages d’erreur sur mesure (404, 500, etc.)

Lorsque vous voulez faire des pages d’erreur sur mesure, c’est très simple… une fois que vous savez !
En effet, la documentation n’est pas très claire…

Voici un résumé de mon expérience, pour faire des pages d’erreur sur mesure (404, 500, etc.).
Il faut d’abord savoir que les erreurs sont des fonctions appelées (= vous ne pouvez pas le faire via les vues génériques).
Ensuite, la documentation donne un exemple, mais ce n’est pas assez.
Grâce aux raccourcis de Django, vous avez la fonction render() à laquelle vous pouvez passer un template et un contexte (= donc des variables).
Je me suis servi de cela pour créer un dictionnaire qui contient les erreurs, et les passer dans dans le contexte avec la clé title et content.


Voici le code des vues qui affiche une erreur « proprement » :

from django.shortcuts import render
from django.utils.translation import gettext_lazy as _
VIEW_ERRORS = {
    404: {'title': _("404 - Page not found"),
          'content': _("A 404 Not found error indicates..."), },
    500: {'title': _("Internal error"),
          'content': _("A 500 Internal error means..."), },
    403: {'title': _("Permission denied"),
          'content': _("A 403 Forbidden error means ..."), },
    400: {'title': _("Bad request"),
          'content': _("A 400 Bad request error means ..."), }, }
def error_view_handler(request, exception, status):
    return render(request, template_name='errors.html', status=status,
                  context={'error': exception, 'status': status,
                           'title': VIEW_ERRORS[status]['title'],
                           'content': VIEW_ERRORS[status]['content']})
def error_404_view_handler(request, exception=None):
    return error_view_handler(request, exception, 404)
def error_500_view_handler(request, exception=None):
    return error_view_handler(request, exception, 500)
def error_403_view_handler(request, exception=None):
    return error_view_handler(request, exception, 403)
def error_400_view_handler(request, exception=None):
    return error_view_handler(request, exception, 400)


Une fois les vues faites, il faut aller dans la déclaration principale de vos vues. Donc le fichier urls.py qui est la racine de votre projet. Si vous mettez le code ailleurs, il sera ignoré.

Dedans, déclarez vos fonctions qui gèrent les erreurs :

handler404 = 'app.views.errors.error_404_view_handler'
handler500 = 'app.views.errors.error_500_view_handler'
handler403 = 'app.views.errors.error_403_view_handler'
handler400 = 'app.views.errors.error_400_view_handler'

Et enfin, dans vos templates, créez un fichier errors.html dans lequel vous pouvez construire votre page HTML qui gère l’erreur « proprement », avec, en plus dans le contexte, les variables {{ title }} et {{ content }} qui affichent respectivement le titre et le détail de l’erreur.

Maintenant, comment, en mode « développement », tester ces pages ? Dans la pratique vous ne pouvez pas, car en mode développement, une erreur affiche les informations de déboguage, et pas vos pages !
La solution : faire une URL qui « simule » l’erreur. Exemple avec 404 : vous ajouter dans vos urls : path('404/', error_404_view_handler), et puis d’afficher votre URL adéquate, soit http://localhost:8000/404/ et vous verrez l’erreur !

IUT : projet JavaScript – jQuery à rendre le 12 avril minuit au plus tard

A rendre le dimanche 12 avril minuit au plus tard

Au vu des événements actuels, je reporte la date limite de rendu (qui était le 29 mars 2020) au dimanche 12 avril minuit au plus tard


Comment le rendre

Faites un fichier README.txt et déposez-le ici
Dans le fichier README.txt, précisez :

  • l’adresse de votre site
  • un nom d’utilisateur
  • un mot de passe
  • (et plusieurs nom/mot de passe, s’il y a plusieurs niveaux de droits (administrateur/visiteur etc.))
  • si vous avez utilisé des librairies spécifiques que je vous ai autorisées, merci de le re-préciser

Sujet

Ce que vous voulez tant que c’est dans le cadre de ce que l’on a vu. Vous avez tout le Web comme inspiration !
N’oubliez pas de me donner le nom et le mot de passe pour se connecter !
Si vous gérez des profils différents (admin / user ou autre), donnez moi les noms et mots de passe de différents profils !


Fonctionnalités obligatoires

  • Connexion + déconnexion (vu en cours)
  • Effets jQuery sur les éléments
  • Appels JSON : au moins deux appels en plus de ceux vus en cours

Sujets possibles

  1. Site de partage de photos
  2. Site de cocktails (cf ci-dessus)
  3. e-rated : site d’appréciations (selon des sujets, à définir)
  4. Ask-a-question : site où l’on pose des questions sur des sujets divers, et des gens répondent
  5. Write-a-book-together : site où l’on se connecte et où on peut écrire un livre à plusieurs
  6. Wedding-couple-site : site où l’on uploade + partage des photos de mariage + livre de commandes
  7. Playing-cards-collection : site où on scanne + échange des cartes (Magic the gathering)
  8. Polls-and-surveys : site de création de sondages (= QCM, exemple très beau ici : quipoquiz)
  9. Poems-generator : faire un cadavre exquis qui génère des poèmes + possibilité pour les utilisateurs de les noter / d’ajouter des mots
  10. The-future-of-post-it : faire un carnet de choses à faire pour les utilisateurs, qui envoie des mails de rappels de ces choses à des dates données
  11. Gift-ideas : un site où l’on va faire des idées de cadeaux / suggérer des idées de cadeaux + les noter (les meilleurs ressortent en premier)
  12. Le-bon-recoin : refaire le bon coin en plus simple
  13. Suggest-crawlers : site de suggestions : on clique sur un mot, il en suggère plein d’autres avec + définitions / liens de sites pour chacuns
  14. Tv-fans : site de présentations + notes d’émissions télé
  15. Faire le jeu SokoBan vu en cours, avec la possibilité de login, enregistrement. Pour les appels JSON supplémentaires, lorsque l’utilisateur choisit un tableau, s’en souvenir (= AJAX) et lorsqu’il se reconnecte, le remettre directement. Puis enregistrer son score lorsqu’il a terminé un niveau + montrer les meilleurs scores.

Pour les sujets qui suivent, ils sont possibles mais plutôt complexes et demandent plus d’investissement. Si vous êtes motivés, demandez-moi plus d’informations, je vous expliquerai les difficultés que vous allez rencontrer.

  1. Turn-by-turn : faire un jeu multijoueurs en tour par tour (jeu de cartes, de poker, ou de plateau etc)
  2. Chat-with-someone : site de chat/discussion
  3. A-maze-ing : site où l’on peut se ballader dans un labyrinthe et essayer d’en trouver la sortie

Sujet imposé si vous n’avez pas d’idée

Cocktails : on se connecte, on a une liste d’éléments (récupérés en JSON) disponibles, on coche ceux qui nous intéressent, on valide, c’est envoyé, et le retour en JSON affiche les cocktails qu’il est possible de faire avec ce que l’on a coché.


Ce que vous devez rendre

Idéalement

Une Url vers un site Web (utilisez Alwaysdata par exemple)

Si vous n’avez pas le choix

Les fichiers source de votre projet


Pour favoriser votre organisation

Utilisez ce que l’on a vu en cours (Google boilerplate)


Librairies autorisées

Interdiction d’utiliser une librairie JavaScript qui ne vienne pas des sites autorisés précédemment


Retard

Après le dimanche 12 avril minuit

Passé ce délai ce sera 1 pt par 2 heures de retard (je prendrai en compte la date de réception du mail).
Pour ceux qui essaient vraiment d’aller jusqu’à la dernière minute, toute heure entamée est comptée comme une heure complète. Exemple : un point en moins si je le reçois le 3 avril à 00:01.
N’oubliez pas de me donner le nom et le mot de passe pour se connecter !


Copier-coller

  • Copie sur une autre personne (« je se savais pas comment implémenter telle ou telle fonctionnalité dont j’avais besoin pour aller plus loin, je l’ai copiée sur un autre ») :
    • si la personne est clairement nommée : note pour la fonctionnalité divisée par 2 (uniquement la moitié du travail a été faite) ;
    • 0 aux deux personnes sinon ;
  • Si je m’aperçois que vous avez bêtement copié collé des sources Internet, je vous convoquerai pour vous demander de m’expliquer la fonctionnalité, et :
    • si vous ne savez pas m’expliquer le code alors 0 ;
    • si vous savez m’expliquer tout le code alors votre note totale sera divisée par vous + le nombre de contributeurs à ce projet, ce qui se rapprochera certainement de 0 aussi.

Voici un exemple de ce que vous pouvez faire, si vous choisissez le projet cocktails.


PDFs

JavaScript
jQuery

Django >= 2.1 : comment faire une administration « sur mesure » et « proprement »

Comment faire simplement une interface d’administration pour le projet entier

Sur les versions de Django < 2.1, il était impossible de surcharger « correctement » l’administration.

  • Créez un fichier admin.py à la racine de votre projet (« à la racine », parce qu’il est « global » à tout le projet)
  • Mettez-y ce code:
    from django.contrib import admin
    class MyProjectAdminSite(admin.AdminSite):
        title_header = 'My project Admin'
        site_header = 'My project administration'

    Bien sûr, changez « MyProject » par le nom de votre projet…
  • Dans settings.py, remplacez 'django.contrib.admin' par 'my_app.apps.MyAppAdminConfig',
  • Dans le fichier apps.py de votre projet, soit my_project/my_app/apps.py, déclarez l’administration comme suit :

    from django.apps import AppConfig
    from django.contrib.admin.apps import AdminConfig
    class MyAppConfig(AppConfig):
        name = 'my_app'
    class MyAppAdminConfig(AdminConfig):
        default_site = 'admin.MyProjectAdminSite'

Quand utiliser __repr__ ou __str__ ?

Cette astuce vient de Dan Bader. Du code, rapidement :

# Émuler ce que fait la std lib :
>>> import datetime
>>> aujourdhui = datetime.date.today()
# Le résultat de __str__ doit être lisible = comme une chaîne :
>>> str(today)
'2017-02-02'
# Le résultat de __repr__ doit lever les ambiguïtés possibles :
>>> repr(today)
'datetime.date(2017, 2, 2)'
# L'interpréteur Python en ligne de commande
# utilise __repr__ pour inspecter les objets :
>>> today
datetime.date(2017, 2, 2)