logo mona

Rapport IFT3150

Miliya Ai

À propos

C'est un projet de développement d'une application mobile par l'organisme MONA, visant à découvrir, photographier et collectionner de l'art public.

J'ai rejoint l'équipe de développement du serveur MONA dans le cadre du cours projet IFT3150 hiver 2024.

Rapport hebdomadaire

Semaine 1 (Jan 11- Jan 18)

Ma première rencontre avec l'équipe MONA a commencé avec Lena, elle m'a raconté l'histoire et le développement de ce projet. Après cela, j'en ai appris davantage grâce à des vidéos sur YouTube et en téléchargeant l'application sur mon mobile. Dans une série d'actions de fouille, ouvrir la carte de l'application, localiser, trouver une œuvre d'art, prendre une photo, enregistrer et récupérer des médailles. C'est vraiment une app très très cool.

Ce qui est également cool, c'est que notre équipe est également très bien organisée. La communication de groupe via Element peut améliorer l'efficacité du travail. Le cadre de code complet et clair sur Github me permet de démarrer très rapidement le travail de développement.

Tout d'abord, ma tâche principale est de réajuster la structure du site des rapports. Par exemple, certains collègues mettent leurs rapports sur github. Ce que je dois faire, c'est l'unifier sur le domaine picasso.iro.umontreal.ca. Je dois aussi améliorer l'organisation et la fonctionnalité d'interface de l'admin dans le futur et à mesure.

Semaine 2 (Jan 18- Jan 25)

Pour cette semaine, j'ai commencé à toucher les codes. Tout d'abord, j'ai créé cette page HTML pour enregistrer mes propres rapports hebdomadaires. Et j'ai fait la réunion comme d'habitude, mais cette semaine, j'ai rencontré Lena, Simon et Kim. Un grand merci à eux pour me donner une présentation assez détaillée.

En parallèle, j'ai également utilisé TestFlight pour tester la version MONA mobile 4.0(5) sur iOS avec Kim.

Voici un petit résumé et l'image ci-dessous (à compléter).

resume

Avec l'aide de Lena et Simon, ma prochaine étape consistait à avoir un accès via protocole SSH au serveur de production MONA. (Voir le tutoriel)

Ce lundi 22 janvier, j'ai rencontré Simon par Jitsi. Merci à Simon encore une fois. Il a été très patient et méticuleux en m'aidant tout au long du processus d'installation.

Ensuite, je migrerai certains rapports discordants des années précédentes, ainsi que je minimiserai et éviterai d'utiliser des dépendances.

Semaine 3 (Jan 25- Feb 1)

J'ai installé un environnement de développement local.

Cliquez ici pour découvrir les détails de Installation

Pour l'IDE, j'ai choisi PhpStorm, car les projets Laravel sont largement soutenus par les fonctionnalités PhpStorm telles quelles.

Semaine 4 (Feb 1- Feb 8)

Cette semaine, on a réalisé un board Miro pour mieux illustrer la structure de notre côté serveur.

En même temps, on veut transférer les données ouvertes CSV, ce qui de double stocker et de documenter seulement du côté du serveur. Donc, on a pris du temps pour gérer la documentation également.

Voici, j'ai exploré Admin et documenté les bogues, les fonctionnalités.

  1. Tri
      Une fois que vous cliquez sur trier, le contenu de la liste correspondante disparaîtra.
  2. Détail
      On n'arrive pas à voir les détails des artistes parfois.
      On n'arrive pas à voir les détails des œuvres parfois.
  3. edit
      Nous n'avons pas le droit de modifier les informations de l'utilisateur
    user
  4. Filtrer
      Dans l'onglet d'artistes, les filtres ne marchent pas.
  5. modification
      BD Mona doit garder une sorte d'historique/version, on ne peut pas modifier ou supprimer les users.

Semaine 5 (Feb 8- Feb 15)

Cette semaine, j'ai rencontré beaucoup de questions sur le contrôle de version de Git. Tout d’abord, j’ai perdu la connexion à github.com/MaisonMONA. J’ai essayé de me reconnecter plusieurs fois, mais je n’arrive toujours pas. Finalement, j'ai réussi en générant avec github personal access token.

gitconnect

Ensuite, j'ai réglé un problème git reset et d'un article de blogue. J'ai appris beaucoup de choses sur le contrôle de version de Git.

Je n'ai pas fait une grande chose cette semaine, car j'ai deux examens à réviser. Cette semaine, j'ai donc réécrit la sémantique ambiguë du rapport de la semaine dernière, j'ai continué à essayer de corriger le bug et j'ai essayé de pouvoir utiliser des fichiers statiques et log in l'interface admin dans le localhost en utilisant. ./vendor/bin/sail up --build,

Semaine 6 (Feb 17- Feb 24)

Je n'ai pas fait une grande chose cette semaine, car j'ai deux examens à réviser.

    Les bogues pour l'instant:
  1. Comment sont documentés les édits (tests vs corrections réelles) ?
      Implémenter une fonction auxiliaire update pour documenter les modifications, allezPlaceController pour voir les détails
  2. User
    • Lorsque nous cliquons sur le bouton "Voir l'utilisateur en détail", nous verrons des boutons "edit" et "delete", mais en fait, nous n'avons pas le droit de modifier les informations de l'utilisateur, cela doit donc être corrigé. Il faudrait corriger dans UserController
    • On n'a pas de droit de supprimer user non plus
    • Lorsque nous cliquons sur le bouton "Afficher les détails", nous verrons une liste de photos prises par l'utilisateur. Cependant, si ces listes de photos sont placées dans le URL ../users, cela réduira considérablement la lisibilité et l'efficacité d'utilisation de l'interface. Je suggère donc de le placer dans ../users/{..}, qui est l'interface après avoir cliqué sur le bouton "Voir l'utilisateur en détail".
                                  Méthode de modification: enleve Route dans web.php
                                  Route::get('users/{user}', [UserController::class, 'show'] )->name('user.show');
                              
  3. artworks
    • Le bouton «Voir en détail l'œuvre» marche parfois, parfois ne marche pas. ArtworkGrid
  4. places
    • delet et edit ne marchent pasPlaceController, les méthodes ne sont pas implémentées
    • tag
                                  
                                      Route::get('addTagPhoto', [TagPhotoController::class, 'show']);
                                      Route::get('addTagDiscovery', [TagDiscoveryController::class, 'show']);
      
                                      Route::put('form-store-preexisting-tag', [TagPhotoController::class, 'storePreexistingTag']);
                                      Route::put('form-store-new-tag', [TagPhotoController::class, 'storeNewTag']);
      
                                      Route::put('form-store-preexisting-tag-discovery', [TagDiscoveryController::class, 'storePreexistingTag']);
                                      Route::put('form-store-new-tag-discovery', [TagDiscoveryController::class, 'storeNewTag']);
                                  
                              
      Je crois comprendre que bag s'applique à identifier photo et discovery autres que les catégories. TagPhotoController, TagDiscoveryController De plus, je pense que si nous avons vraiment besoin de données telles que des balises, alors nous ajouterons une colonne supplémentaire (en plus du titre, de la note, du territoire, etc.) au tableau pour l'afficher.
  5. artists
    • Pour les artistes, il n'y a de données dedans, on laisse comme ça ou on insère de la donnée?ArtistGrid
  6. heritages
    • create Heritage ne marche pas, parce qu'il n'y a pas de fonction pour l'implémenter dans web.php Route::get('heritages/create', [HeritageController::class, 'create']);
    • edit et delete ne fonctionnent pas non plus, le problème avec les tags revient.
  7. Concernant l'ajustement, j'ai jeté un œil à AdjustmentController et j'ai découvert qu'il ne s'agissait que d'un modèle de contrôleur dans Laravel. Donc, je suppose les développeurs backend de l'époque voulaient laisser un template vide pour développer d'autres modèles, tels que index() pour obtenir toutes les données du modèle « ajustement » dans la base de données sont converties en JSON puis transmises à la vue de admin.adjustments.index pour afficher les données dans la liste, mais évidemment, nous n'avons pas de modèle « ajustement » dans BD.
  8. Delection, pour le bouton Restore, ne marche pas effectivement, car rien n'est implémenté dessus dans DeletionGrid Restore
  9. Dossier rapport, toutes les choses statiques ne marchent pas, ça peut être relié aux permissions du système de fichier.

Perdu la connexion logger

            ./vendor/bin/sail artisan migrate
            
                laravel.test-1  | 2024-02-15 03:22:04,954 INFO spawned: 'php' with pid 15
                selenium-1      | 03:22:05.093 INFO [LoggingOptions.configureLogEncoding] - Using the system default encoding
                selenium-1      | 03:22:05.114 INFO [OpenTelemetryTracer.createTracer] - Using OpenTelemetry for tracing
                selenium-1      | 03:22:05.816 INFO [NodeOptions.getSessionFactories] - Detected 8 available processors
                selenium-1      | 03:22:05.901 INFO [NodeOptions.report] - Adding chrome for {"browserName": "chrome","browserVersion": "120.0","goog:chromeOptions": {"binary": "\u002fusr\u002fbin\u002fgoogle-chrome"},"platformName": "linux","se:noVncPort": 7900,"se:vncEnabled": true} 1 times
                selenium-1      | 03:22:05.933 INFO [Node.] - Binding additional locator mechanisms: relative
                laravel.test-1  | 2024-02-15 03:22:05,957 INFO success: php entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
                selenium-1      | 03:22:05.972 INFO [GridModel.setAvailability] - Switching Node 338f38f7-1df6-4736-8f13-4bc842c79722 (uri: http://172.20.0.2:4444) from DOWN to UP
                selenium-1      | 03:22:05.973 INFO [LocalDistributor.add] - Added node 338f38f7-1df6-4736-8f13-4bc842c79722 at http://172.20.0.2:4444. Health check every 120s
                laravel.test-1  | PHP Deprecated:  Using ${var} in strings is deprecated, use {$var} instead in /var/www/html/app/Console/Commands/RestoreDatabase.php on line 50
            
        

Semaine 7 (Feb 22- Feb 29)

Cette semaine, j'ai résolu le problème de l'admin qui ne pouvait pas se connecter sur localhost. En gros, pour créer un nouveau compte admin, il suffit de créer un nouveau compte régulier via l'API, puis de l'élever en administrateur via SQL:

            
                ./vendor/bin/sail up -d
                curl -X POST -F 'username=Miliya' -F 'password=MiliyaAi' -F 'password_confirmation=MiliyaAi' http://localhost/api/v3/register
            
        

curl Envoyer ou recevoir des données et interagir avec le serveur -X POST Une requête HTTP (POST) pour créer l'utilisateur afin d'éviter de hasher le mot de passe à la mitaine. -F Précisez les champs à envoyer 'username=Miliya' et 'password=MiliyaAi pour créer un nouveau compte http://localhost/api/v3/register est l'URL à laquelle la demande est envoyée. Cette adresse est endpoint de l'API, dans ce cas le chemin api/v3/register sur le serveur local.

On peut ensuite modifier l'entrée de ce user dans la base de données pour lui donner des privilèges admin. Pour faire les requêtes SQL:

            En passant, j'ai mis une faute de frappe dans ma commande, donc je recommence
            
                docker-compose up -d
                .vendor/bin/sail mariadb
                UPDATE users SET role='admin' WHERE username='Miliya'
            
        

J'ai aussi fait une copie de schéma de la BD sur miro cette semaine: j'ai ajouté quelques détails sur les étapes que les utilisateurs et les administrateurs doivent suivre depuis la connexion jusqu'à l'utilisation (telles que comment ils passent par MVC, comment référencer l'API et BD, etc.), et j'ai commenté quelques suggestions pour rendre le flux plus clair.

Semaine 8 (Feb 29- Mar 12)

Au cours des deux dernières semaines (y compris la semaine de lecture), J'ai continué d'améliorer la table d'infrastructure sur Miro. Nous devons apporter un nouveau changement maintenant, à savoir le système de contrôle de version de la base de données. Par exemple, si on veut créer une trace de mise à jour → si une publication contient une nouvelle photo qui remplace l'ancienne photo, nous voulons connaître l'historique (comment ça marche, mécanique, etc.).

            On peut concevoir une table de base de données pour stocker des informations historiques.
            Ce tableau peut contenir les champs suivants (ex: pour la table des places):
            
                Table "place_user" {
                 "place_id" bigint(20) [not null]
                  "user_id" bigint(20) [not null]
                  "rating" tinyint(3) [default: NULL]
                  "comment" text [default: NULL]
                  "photo" varchar(191) [default: NULL]
                  "created_at" timestamp [default: NULL]
                  "updated_at" timestamp [default: NULL]
                }
            
            
                place_user_history{
                    "user_id",
                    "place_id"
                    "old_photo".
                    "new_photo"
                    "created_at"
                }
            
            Créez un modèle Laravel pour cette nouvelle table:
            
                php artisan make:model PlaceUserHistory
            
            Logique de mise à jour: lorsqu'une image de lieu est remplacée, un nouvel enregistrement est inséré dans
            la table place_user_history. Cela peut être fait en écoutant l'événement de mise à jour du modèle ou en
            ajoutant du code directement dans la logique de mise à jour.

            
                use App\Models\PlaceUserHistory;
                public function update(Request $request, Place $place)
                {
                    $old_photo = $place->photo;
                    $place->update($request->all());
                    $new_photo = $place->photo;
                    PlaceUserHistory::create([
                        'user_id' => Auth::id(),
                        'place_id' => $place->id,
                        'old_photo' => $old_photo,
                        'new_photo' => $new_photo
                    ]);
                    return redirect()->route('places.index');
                }
            

            Requête d'historique: afin d'afficher l'historique de mise à jour des images dans un certain endroit,
            on peut créer une méthode pour interroger la table place_user_histories et trier par le champ créé_at pour
            obtenir l'historique de toutes les modifications d'image dans l'endroit.

            
                use App\Models\PlaceUserHistory;
                public function getPlaceUpdateHistory(Place $place)
                {
                    $histories = PlaceUserHistory::where('place_id', $place->id)->orderBy('created_at', 'desc')->get();
                    return view('places.history', compact('histories'));
                }
            
        

Après la réunion avec Lena, nous avons besoin d'un modèle plus général pouvant demander le repeuplement de l'API, permettant aux utilisateurs de conserver les dernières données, tout en pouvant également afficher l'historique des modifications dans l'interface d'administration. Il m'est venu à l'esprit que puisque nous avons déjà une table de versions dans la base de données existante, ce serait un bon point de départ. Ce concept peut être étendu pour suivre chaque version de chaque entité (par exemple, artwork, place, heritage)

            Lors du stockage de l'état d'une entité sous forme d'instantané JSON, cela signifie qu'à un moment précis,
            tout ou partie des données de l'entité est convertie en chaîne au format JSON puis stockée dans la base de
            données. Ce type d'instantané peut capturer et enregistrer l'état exact de l'entité avant et après
            modification pour faciliter la récupération, l'audit ou la comparaison ultérieure des données.
            
                Table "entity_histories" {
                  "id" bigint(20) [pk, not null, increment]
                  "entity_type" varchar(191) [not null] // stocker le type d'entité: 'artwork', 'place', 'heritage'
                  "entity_id" bigint(20) [not null] // stocker l'ID de l'entité
                  "version_id" bigint(20) [not null] // référence à la version de l'entité
                  "action_type" varchar(191) [not null] // 'create', 'update', 'delete'
                  "snapshot" longtext [not null] // stocker l'état de l'entité à ce moment
                  "action_timestamp" timestamp [default: current_timestamp()] // l'heure à laquelle l'action a été effectuée
                  "action_by_user_id" bigint(20) [not null] // référence à l'utilisateur qui a effectué l'action
                  "created_at" timestamp [default: NULL]
                  "updated_at" timestamp [default: NULL]
                }
            

            Un exemple de logique de mise à jour pour l'entité Artwork:
            
                // $artwork est l'entité Artwork à mettre à jour
                $artwork->rating = $newTitle; // mise à jour du rating
                $artwork->save(); // enregistrer la mise à jour

                // Créer un enregistrement d'historique pour la mise à jour
                $history = new EntityHistory();
                $history->entity_type = 'artwork';
                $history->entity_id = $artwork->id;
                $history->version_id = createNewVersionId(); // C'est une fonction pour générer un nouvel ID de version
                $history->action_type = 'update';
                $history->snapshot = json_encode($artwork); // générer un instantané JSON de l'entité
                $history->action_by_user_id = $currentUser->id; // l'utilisateur actuel qui a effectué l'action
                $history->save(); // enregistrer l'enregistrement d'historique
            

            Côté client, nous pouvons utiliser «soft delete», une méthode de gestion des enregistrements
            de base de données qui permet de marquer les données comme « supprimées » sans être définitivement supprimées.

            1. Ajoutez le champ delete_at au fichier de migration
            Ajoutez un champ delete_at pour les modèles nécessitant une suppression logicielle,
            qui contient l'horodatage du moment où l'enregistrement a été marqué pour suppression.
            Si l'enregistrement n'a pas été supprimé, ce champ reste vide (ou NULL)
            
                Schema::table('artwork', function (Blueprint $table) {
                    $table->softDeletes();
                });
            

            2. Utilisez le trait SoftDeletes dans le modèle
            Utilisez le trait Illuminate\Database\Eloquent\SoftDeletes dans le modèle de Laravel. Cela permettra la suppression logicielle du modèle.
            par exemple: dans Artwork.php(Models/Artwork/Artwork.php)
            
                use Illuminate\Database\Eloquent\SoftDeletes;
                class Artwork extends Model
                {
                    use SoftDeletes;
                }
            
            Une fois SoftDeletes activé, lorsque la méthode delete() est appelée, Laravel ne supprimera pas réellement
            l'enregistrement de la base de données, mais définira le champ delete_at sur l'horodatage actuel.
            Le dossier est alors considéré comme « supprimé »

            3. Interroger les enregistrements supprimés de manière logicielle
            Lorsque softdelete est activée, la requête par défaut ne renverra pas les enregistrements supprimés. Si on veut faire
            une requête pour interroger tous les enregistrements, y compris les softdelets, on peut utiliser la méthode withTrashed:
            
                 $artworks = Artwork::withTrashed()->get();
            
            Si on veut interroger uniquement les enregistrements supprimés, on peut utiliser la méthode onlyTrashed:
            
                $artworks = Artwork::onlyTrashed()->get();
            

            4. Récupérer les enregistrements supprimés de manière softdelete
            Si on veut restaurer des enregistrements 'supprimés', on peut utiliser la méthode de restauration:
            
                $artwork = Artwork::withTrashed()->find($id);
                $artwork->restore();
            
        

Interroger les versions historiques: interroger tous les enregistrements de l'identifiant d'entité et du type d'entité spécifiés via la table entités_histories

            Si nous avons le modèle EntityHistory correspondant à la table entity_histories
            
                use Illuminate\Database\Eloquent\Model;

                class EntityHistory extends Model
                {
                    protected $table = 'entity_histories';
                }
            

            Ensuite, Créer un contrôleur pour interroger les versions historiques:
            
                use App\Models\EntityHistory;
                use Illuminate\Http\Request;

                class EntityHistoryController extends Controller
                {
                    /**
                     * Get the history of an entity
                     *
                     * @param    \Illuminate\Http\Request  $request
                     * @return  \Illuminate\Http\Response
                     */
                    public function showEntityHistory(Request $request)
                    {
                        $entityType = $request->input('entity_type');
                        $entityId = $request->input('entity_id');

                        // Query the entity history
                        $histories = EntityHistory::where('entity_type', $entityType)
                            ->where('entity_id', $entityId)
                            ->orderBy('action_timestamp', 'desc')
                            ->get();

                        // Return the history to the view
                        return response()->json($histories);
                    }
                }
            
        

Semaine 9 (Mar 12- Mar 19)

Amélioration sur BD google slide

Et modélisation UML, veuillez vous référer au dossier «miliya»

Semaine 10 (Mar 19- Mar 26)

interface admin google slide

Semaine 11 (Mar 26- Avr 2)

interface admin + serveur google slide

Semaine 12 (Avr 2- Avr 9)

interface admin + serveur (Avancé) google slide

Semaine 13 (Avr 9- Avr 16)

Modélisation UML pour interface admin et User (Diagramme de cas d'utilisation, diagramme d'activité) google slide

Rapport final

Tutorial

SSH(à l'aide de Simon Janssen, copyright réservé par le courriel de Simon aussi)

Générer une paire de clés ssh privé/publique avec la commande (ici ed25519 est id_mona)

            
                ssh-keygen -t ed25519
            
        

Exemple:

            
                miliya.ai@miliyaaidemac ~ % ssh-keygen -t ed25519
                Generating public/private ed25519 key pair.
            
        

Ensuite, il va demander de stocker dans quel dossier et en mettant

            
                ~/.ssh/id_mona
            
        

Exemple:

            
                Enter file in which to save the key (/Users/miliya.ai/.ssh/id_ed25519):
                Enter passphrase (empty for no passphrase):
                Enter same passphrase again:
                Your identification has been saved in /Users/miliya.ai/.ssh/id_ed25519
                Your public key has been saved in /Users/miliya.ai/.ssh/id_ed25519.pub
            
            Peu important après...

Finalement, envoyer la clé publique,le contenu du fichier (~/.ssh/id_mona.pub) et demander à Raouf (bencherr bencherr@iro.umontreal.ca) avec l'appui de Lena

            
            Host arcade
                Hostname arcade.iro.umontreal.ca
                User {ton-username-du-DIRO} (https://support.iro.umontreal.ca/mdp/)
            Host picasso
                HostName picasso
                ProxyJump arcade
                User mona
                IdentityFile ~/.ssh/id_mona
        

Exemple:

            
                Host arcade
                    HostName arcade.iro.umontreal.ca
                    User aimiliya
                Host picasso
                    Hostname picasso
                    ProxyJump arcade
                    User mona
                    IdentityFile ~/.ssh/ed25519
        

Installation

Tout d’abord, afin de mieux utiliser Laravel, le framework de développement web PHP, nous utiliserons Laravel Sail, une interface légère en ligne de commande qui interagit avec l’environnement de développement Docker.

Bien sûr, vérifier si on a bien installé Docker en utilisant

            docker-compose --version 
            Ça l'aire bon si ça affiche comme:
            Docker Compose version v2.17.3
        

Téléchargez et exécutez maintenant la commande du script via curl et exécutez le script avec l'interpréteur Bash.

            curl -s " https://laravel.build/mona-server?with=mariadb,redis,meilisearch,selenium" | bash
        Cloner le dépôt github
            git clone git@github.com:MaisonMONA/mona-server.git
        Tourner au ton compte github maintenant, dans le volet SSH and GPG keys, ajouter ton SSH keys
        

Installez le package laravel/sail dans le projet Laravel Sail et marquez-le comme package de dépendances pour l'environnement de développement.

            ./vendor/bin/sail composer require laravel/sail --dev 
        

Utilisez Composer pour installer le package laravel/sanctum dans le projet Laravel Sail afin d'utiliser l'authentification Sanctum dans le projet

            ./vendor/bin/sail composer require laravel/sanctum
        

Ça devrait bon maintenant, Let's gogogogo

1. ./vendor/bin/sail up: Cette commande est utilisée pour démarrer l'environnement Sail. Il démarrera tous les services définis dans le projet (tels que les serveurs Web, les bases de données, etc.) et les laissera s'exécuter dans des conteneurs Docker. Habituellement, l'exécution de cette commande affichera la sortie du journal du service dans la fenêtre actuelle du terminal, ce qui facilitera la visualisation de l'état d'exécution du service.

2. ./vendor/bin/sail up -d : Cette commande est similaire à la commande précédente, mais utilise l'option `-d`, qui signifie « détaché » (mode détaché). Cela entraînera le démarrage de l'environnement Sail en arrière-plan et la sortie du journal du service ne sera pas affichée dans la fenêtre du terminal actuel. Cela maintient la fenêtre du terminal disponible et non occupée par la sortie du journal du service.

3. ./vendor/bin/sail down: Cette commande est utilisée pour arrêter l'environnement Sail. L'exécution de cette commande arrêtera tous les services définis dans le projet et supprimera les conteneurs Docker associés. Cela peut être utilisé pour libérer des ressources lorsque le service n'est plus nécessaire pour s'exécuter, ou pour nettoyer lorsque l'environnement doit être redémarré.