Closed benel closed 2 years ago
Young Artist : Permettrait à des psychologues de partager rapidement des dessins selon leur terme de recherche et de contribuer à ce point de vue entre eux.
Cette fonctionnalité est utile pour le projet car il s'agit d'un travail collaboratif il parait donc utile que plusieurs collaborateurs puissent modifier un même point de vue.
@melaniehoneychurch Tout à fait. Cependant pour être tout à fait précis, pour l'instant tout est modifiable par tout le monde (comme un wiki). Cette nouvelle fonctionnalité permettrait donc plutôt d'autoriser uniquement quelques personnes à le faire (par défaut l'auteur, comme sur Google Docs).
@benel Je pense que ce point va de pair avec le ticket :
Register as a contributor #184
En réalisant ces deux points, il nous sera donc possible de n'autoriser que l'auteur par défaut à modifier un point de vue. (Identification par compte d'utilisateur).
Puis si ce dernier le souhaite il pourra autoriser des collaborateurs qui seront qualifiés de "fiables" à modifier son point de vue.
@MaximeD89 Oui c'est ça.
Graines d'artistes : Pourrait permettre à un groupe de personnes de travailler sur le même point de vue. Ce point de vu sera créé/modifié par le groupe et pour le groupe.
@sarah-ngn @Hypertopic/graines-d-artistes-1 Oui, ça a du sens.
On est d'accord que pour l'instant tout le monde peut tout éditer ? Là ça permettrait de décider qui peut le faire.
Etude à l'étranger : Permettre à chaque utilisateur de créer et modifier ses propre viewpoint pour son utilisation personnel.
Compétence EUt+ :
Cette feature est intéressante pour notre projet. Le catalogue est collaboratif, il est donc important d'autoriser les utilisateurs à créer des points de vues. De plus le contributeur pourra choisir de partager ou non les droits de modification de son point de vue.
Groupe Etudes à l'étranger : Avec @ThomasRitaine, nous avons commencé à travailler sur une stratégie d'implémentation. Voici le résultat.
portfolioPage/Portfolio :
portfolioPage/Viewpoint :
Index.js
ViewpointPage/Outliner :
Un système de viewpoint existe déjà, mais ce ne sont pas des entités qui peuvent posséder des attributs tels que le créateur, la date de création, la visibilité (privé, publique…) Ainsi, il va falloir modifier la façon dont sont stockés les points de vue. La liste des attributs que nous voulons ajouter aux points de vue est assez courante, et ne devrait pas poser de problème d’un point de vue algorithmique.
Non, les données dont nous avons besoin ne sont pas directement chargées sur la page. Il va falloir modifier le backend, et créer le type de réponse que nous souhaitons. Par exemple, pour récupérer la liste des viewpoints, nous pourrons avoir une réponse json avec la forme suivante :
{
"pointOfViewList" :
[
{
"id" : cef52507-de32-444a-97fc-2de092ed65d3,
"name" : Mon point de vue,
"group" : Mes points de vue,
"visibility" : public,
"author" : ritainet
},
{
"id" : 123e4567-e89b-12d3-a456-426614174000,
"name" : Mon point de vue,
"group" : Asie,
"visibility" : public,
"author" : beurtonj
}
]
}
L’ajout de champs pour les viewpoints ne nécessite pas de librairie particulière. Il y aura un travail sur l’architecture de la base de données pour ajouter aux points de vue un nom, un auteur, un groupe et une visibilité.
Pas de code testé.
Aucun service extérieur ne sera nécessaire.
Rien à tester.
@Antoine-thz @TheoHoenen
Merci pour la première version de vos scénarios.
Au-delà des problèmes de forme que j'ai indiqué ligne à ligne, je crois qu'il y a un problème plus profond de compréhension de ce que veut dire "Authorize a contributor to edit a viewpoint".
Je vous rappelle que le sujet implicite du verbe d'une fonctionnalité est toujours un utilisateur (ce n'est pas le système qui est "sujet").
Du coup, la phrase complète serait : A autorise B à éditer le point de vue X
.
Dit autrement vos scénarios (les différents cas) doivent être rédigés autour de déclencheurs de ce type :
Quand "alice" autorise "bob" à éditer le point de vue "Équivalences UTT"
@benel
Avec @gb99 nous avons fait à nouveau les ébauches de nos maquettes suite aux commentaire sur les précédentes. N'hésitez pas à nous faire des remarques dans les commentaires 👍
Tout d'abord, l'utilisateur décide de sélectionner un point de vue (ici "Informatique") et clique sur le bouton de modification, qui existe déjà.
On se retrouve sur la page d'édition du point de vue "Informatique" dans laquelle une nouvelle section "Contributeurs" a été créée. Cette section contient :
@benel voici la réponses aux différentes questions de la stratégie d'implémentation que nous avons réalisé avec @Anas9820 (début de la discussion trouvable ici)
Pour la suite de la stratégie d'implémentation nous avons répondu aux trois point mentionnés dans le message précédent:
1) de récupérer la liste des contributeurs autorisés pour un point de vue donné, 2) de récupérer (si c'est possible techniquement, conforme aux règles de sécurité et déjà implémenté) la liste des utilisateurs disponibles (ou à défaut déjà autorisés pour d'autres points de vue), 3) de modifier la liste des contributeurs d'un point de vue donné.
Nous avions convenu lors de la dernière réunion technique qui a suivi la réunion de vendredi dernier que le point n°2 ne serait pas abordé dans le cadre de ce ticket. L'utilisateur devrait donc rentrer le nom exact du contributeur qu'il veut ajouter. Ce choix est fait car la récupération de tous les utilisateur s'avère complexe techniquement. Ce choix est fait également car l'utilisateur serait amené à discuter au préalable avec un utilisateur voulant être un contributeur. Durant cette discussion le futur contributeur aurait simplement à donner son nom afin d'être ajouté ultérieurement.
Nous avons réalisé un module javascript afin d'explorer les possibilités pour les points 1) et 3). Il est trouvable en entier ici: gist entier Ce fichier contient des fonctions utilisés pour tester les fonctionnalités, celles-ci seront sujet à modification car elles ont été écrite dans une perspective d'exploration de l'API et de tests facilités.
Dans ce fichier on peut trouver notamment une fonction qui permet de récupérer la liste des contributeurs autorisés pour un point de vue donné: fonction
// Get contributors of a viewpoint (default id is id of a viewpoint with the test data)
const getContribs = async (id='a76306e4f17ed4f79e7e481eb9a1bd06') => {
let viewpoint = await db.auth('alice', 'whiterabbit').get({_id:id}).catch(_error);
return viewpoint.contributors
}
Cette fonction répond donc au point 1) et permet de récupérer un tableau de nom de personne (ou undefined dans le cas ou aucun contributeur n'est présent)
Pour le point 3) et donc la modification des contributeurs, nous avons réalisé trois fonctions:
// Add contributors to a viewpoint
const addContributors = async(viewpointId, newContributors) => {
// On récupère les contributeurs actuels
const currentContributors = await getContribs(viewpointId)
const set = new Set(currentContributors)
// Ajout des nouveaux contributeurs
newContributors.forEach(c => set.add(c))
// Récupération du viewpoint
let viewpoint = await db.auth('alice', 'whiterabbit').get({_id:viewpointId}).catch(_error);
// Ajout des contributors au viewpoint
viewpoint.contributors = [...set]
// Mise à jour des données
await db.post(viewpoint).catch(_error)
// Affichage des contributeurs mis à jour
console.log(await getContribs(viewpointId))
}
// Remove contributors from a viewpoint
const removeContributors = async (viewpointId, contributorsToRemove) => {
const currentContributors = await getContribs(viewpointId)
const set = new Set(currentContributors)
contributorsToRemove.forEach(c => set.delete(c))
// Récupération du viewpoint
let viewpoint = await db.auth('alice', 'whiterabbit').get({_id:viewpointId}).catch(_error);
// Modification des contributeurs (on remplace l'ancien tableau par le tableau modifié)
viewpoint.contributors = [...set]
// Passage en mode wiki du viewpoint dans le cas ou tous les contributeurs sont supprimés
if (viewpoint.contributors.length === 0)
viewpoint.contributors = undefined
// Mise à jour des données sur le serveur
await db.post(viewpoint).catch(_error)
// Affichage des contributeurs
console.log(await getContribs(viewpointId))
}
// Set contributors to undefined (wiki mode)
const resetContributors = async (viewpointId) => {
let viewpoint = await db.auth('alice', 'whiterabbit').get({_id:viewpointId}).catch(_error);
// On supprime l'attribut contributors du viewpoint
delete viewpoint.contributors
const res = await db.post(viewpoint).catch(_error)
console.log(`Contributors are now: ${res.contributors ? res.contributors : 'everyone (wiki mode)'}`)
}
Lors de la création d'un viewpoint, l'idée serait d'utiliser la première fonction avec le nom de celui-ci afin que celui-ci soit le seul contributeur sur son viewpoint.
Vous pouvez tester toutes ces fonctions en lançant simplement argos & la couchdb. N'hésitez pas à nous faire des remarques dans les commentaires :+1:
@michaelmtre @gb99
Merci pour ces nouvelles maquettes.
OK. Oui, c'est pas mal du tout. Les interactions sont tout à fait raisonnables et décrites de manière suffisamment précise pour une implémentation et des tests.
Peut-être que ceux qui vont implémenter voudront négocier quelques détails de mise en page (les marges notamment) qui compliquent un peu les choses sans que l'on voit très clairement ce que cela apporte). Mais c'est mineur et la négociation pourra avoir lieu à ce moment-là.
@michaelmtre @gb99
Peut-être juste revoir le placement de la zone des contributeurs. En effet, comme il s'agit d'une annexe à la zone principale, vous pourriez réfléchir à la mettre à la droite ou à la gauche de la zone principale... D'autant plus que quand le point de vue est rempli, la page est très chargée verticalement et très peu horizontalement. Ex :
@JacquesMironneau @Anas9820
de récupérer (si c'est possible techniquement, conforme aux règles de sécurité et déjà implémenté) la liste des utilisateurs disponibles (ou à défaut déjà autorisés pour d'autres points de vue),
Nous avions convenu lors de la dernière réunion technique qui a suivi la réunion de vendredi dernier que le point n°2 ne serait pas abordé dans le cadre de ce ticket. L'utilisateur devrait donc rentrer le nom exact du contributeur qu'il veut ajouter. Ce choix est fait car la récupération de tous les utilisateur s'avère complexe techniquement. Ce choix est fait également car l'utilisateur serait amené à discuter au préalable avec un utilisateur voulant être un contributeur. Durant cette discussion le futur contributeur aurait simplement à donner son nom afin d'être ajouté ultérieurement.
Tout à fait. Il était important de garder une trace de cette décision, comme vous le faites là, car c'est un des points majeurs de votre stratégie d'implémentation.
@JacquesMironneau @Anas9820
C'est très bien d'avoir fait tous ces tests avec des extraits de code !
Notez que l'authentification HTTP :
Par ailleurs, pour ce point précis, normalement ce sont des données que vous avez déjà récupérées. Vous pouvez observer dans les outils de développement Web de votre navigateur le résultat des requêtes lancées. Par contre il faudrait identifier l'endroit où est fait la requête dans le code pour ensuite planifier la transmission de ces données jusqu'à votre composant.
Par ailleurs, pour ce point précis, normalement ce sont des données que vous avez déjà récupérées
De quelles données parlez-vous ? Celle d'authentification ?
Par contre il faudrait identifier l'endroit où est fait la requête dans le code pour ensuite planifier la transmission de ces données jusqu'à votre composant.
Vous parlez de la requête d'authentification ? Ou voulez vous dire que la requête récupérant les contributeurs existe déjà dans le code de porphyry ?
@JacquesMironneau @Anas9820
C'est effectivement ce premier bout de code qui correspond à ce que l'on veut faire. Les deux autres, bien qu'intéressants correspondent à de futures fonctionnalités (si certains de votre équipe n'avaient pas encore créé de tickets, c'est l'occasion !).
Ça semble bien faire ce que c'est censé faire... Bravo !
Mais pourriez-vous essayer maintenant de l'écrire dans le "style fonctionnel" de la bibliothèque, c'est à dire, sous la forme d'une séquence d'étapes ou chacune attend le résultat de la précédente avec then
pour devenir les paramètres d'entrée de la suivante ?
Petits conseils :
async
ni await
et d'avoir un seul "fil" de traitement.Si vous bloquez à une des étapes. Indiquez moi l'étape précédente qui fonctionne et la suivante qui ne fonctionne pas et je tenterai de vous "débloquer".
@JacquesMironneau @Anas9820
Par ailleurs, pour ce point précis, normalement ce sont des données que vous avez déjà récupérées
De quelles données parlez-vous ? Celle d'authentification ?
Non, non, je parle bien des contributeurs autorisés du point de vue en édition.
Mais on est d'accord que vous avez quand même besoin de cette étape de lecture avant de faire la modification. Sinon vous risqueriez d'avoir des conflits de mise à jour (s'il y a eu d'autres modifications en parallèle).
Je vous invite d'ailleurs pour l'instant, comme je le disais plus haut, à présenter votre "authentification / lecture / modification en mémoire / modification sur le serveur" en un seul fil d'exécution (un peu comme dans l'exemple "Update an object" de la documentation de la bibliothèque).
D'accord merci je vois ce que voulez dire pour la récupération de données.
Oui je vais réécrire le tout avec des then.
Mais on est d'accord que vous avez quand même besoin de cette étape de lecture avant de faire la modification. Sinon vous risqueriez d'avoir des conflits de mise à jour (s'il y a eu d'autres modifications en parallèle).
La récupération des données inclurait donc uniquement l'id du viewpoint puis dans le composant nous ferions la requête récupérant les contributeurs en fonction de cet id?
@benel voici la version écrite sans async/await
db.auth('alice', 'whiterabbit')
.get({_id:'a76306e4f17ed4f79e7e481eb9a1bd06'})
.then(x => {
const set = new Set(x.contributors)
const newContributors = ['alice','anas','benel']
newContributors.forEach(c => set.add(c))
x.contributors = [...set]
return x;
})
.then(db.post)
.then(x => _log(x.contributors))
.catch(_error);
Est-ce que cela vous convient ?
@JacquesMironneau
La récupération des données inclurait donc uniquement l'id du viewpoint puis dans le composant nous ferions la requête récupérant les contributeurs en fonction de cet id?
Je ne sais pas trop si je comprends votre question. Je reformule :
render
), la requête a déjà été faite. Il faut juste que les contributeurs soient transmis dans l'état de votre composant.Est-ce que cela vous convient ?
Oui c'est beaucoup mieux !!!
Il y a juste le forEach
qui me chagrine un peu. Mais vous pouvez facilement le supprimer en ajoutant non pas plusieurs contributeurs à la fois mais un seul. Oui, je sais bien que ce serait intéressant dans l'absolu. Mais vous préparez l'implémentation d'une fonctionnalité qui n'en mentionne qu'un. Là encore : nouveau ticket !
Je ne sais pas trop si je comprends votre question. Je reformule :
- Pour l'affichage (render), la requête a déjà été faite. Il faut juste que les contributeurs soient transmis dans l'état de votre composant.
- Pour la modification, on refait effectivement une lecture (pour être sûr d'avoir la toute dernière version) et on enchaîne tout de suite avec la modification ciblée et l'écriture.
C'est bien ce que j'avais compris, merci.
Voici la version avec un seul contributeur:
db.auth('alice', 'whiterabbit')
.get({_id:'a76306e4f17ed4f79e7e481eb9a1bd06'})
.then(x => {
x.contributors = [...new Set(x.contributors).add('toto')]
return x;
})
.then(db.post)
.then(x => _log(x.contributors))
.catch(_error);
@JacquesMironneau
$ node
Welcome to Node.js v14.17.0.
Type ".help" for more information.
> let x = {}
undefined
> [...new Set(x.contributors).add('toto')]
[ 'toto' ]
>
Et vous gérez le cas où le point de vue était en mode wiki. Bravo !
@benel Après avoir creuser dans le code de porphyry (plus précisémment dans le Component Outliner) je pense que nous pourrions modifier la fonction _fetchData.
async _fetchData() {
if (!this.changing) {
new Hypertopic((await conf).services)
.get({ _id: this.props.match.params.id })
.then(x => {
// On donc remplacer cette ligne
this.setState({ topics: x.topics, title: x.viewpoint_name });
// par this.setState({ topics: x.topics, title: x.viewpoint_name, contributors: x.contributors });
this.topicTree = new TopicTree(x.topics);
});
} else {
return true;
}
}
De cette manière on pourrait ajouter notre composant dans la méthode render de l'outliner et passer par exemple en props les contributors, et/ou l'id du viewpoint.
@Hypertopic/etudes-a-l-etranger-1 @Hypertopic/competences-eut
Vous aviez remarqué que vous étiez en concurrence sur les mêmes livrables ?
En tout cas, pour ce qui concerne les scénarios, ce sont ceux de @candalc et @Samnoel95 qui sont les plus aboutis. Ce sont donc ceux-là que je vais intégrer.
Pour les autres livrables, essayez d'être "plus coopératifs dans la concurrence". Vous pouvez par exemple :
Voici nos maquette (posté avec du retard désolé) Fait avec @Nicflx
Disclaimer : notre vision de ce ticket dans notre équipe était majoritairement tourné autour de la création d'un point de vue personnel d'où, cf le post ci dessous de Antoine
Etude à l'étranger : Permettre à chaque utilisateur de créer et modifier ses propre viewpoint pour son utilisation personnel.
Voici ce que nous avions imaginé :
Ici on voit donc que l'on peut ajouter un point de vue avec un nom, une description et on peut ajouter plusieurs items via des champs éditables. Il suffit de valider l'insertion (soit par l'appuie de la touche entré ou clic en dehors du champ cliquable, dans la pire des cas on peut ajouter un bouton de validation si pas assez user-friendly) Après cela l'item est bien inséré et on peut continuer à créer de nouveaux items.
@GuenaultAlexandre @Nicflx
notre vision de ce ticket dans notre équipe était majoritairement tourné autour de la création d'un point de vue personnel
Ce n'est pas grave de se tromper (ça peut arriver à tout le monde, à condition de comprendre la raison de l'erreur pour ne plus la refaire. Comment interprétez-vous votre mauvaise compréhension du titre de ce ticket ("authorize" ≠ "create") ?
@benel Je ne me souviens pas exactement comment on en est arrivé à ce problème de compréhension mais si je devais poser une hypothèse sur cela, Il me semble que a un moment donnée on voulais donner la possibilité à certains utilisateurs de modifier les points de vue au cas où certains éléments changent dans le temps et ainsi réduire la charge de travail à ceux qui ont crée les points de vue. Sauf qu'au fur et à mesure des semaines, les réflexions ont évolué, ainsi que notre compréhension des besoins, mais pas les tickets présents sur notre kanban, on a certainement donc confondu le besoin cité précédemment dans ce ticket avec celui qu'on avait à l'origine. Notre erreur fut alors de laisser ce ticket.
Je laisse quelqu'un me corriger si je me trompe mais il me semble bien que c'est ce qu'il s'est passé.
@GuenaultAlexandre @Nicflx
Peut-être aussi qu'à un moment vous avez oublié que le verbe d'une fonctionnalité est une action de l'utilisateur et non du système (c'est l'utilisateur qui autorise
l'édition à un autre utilisateur à éditer et non juste le système qui permet l'édition) ?
Du coup, est-ce que ce ticket garde son intéret pour votre domaine d'application (@Hypertopic/etudes-a-l-etranger-1) ? Et si non, souhaitez-vous planifier dans votre kanban un ticket qui correspondrait plus à ce que vous me disiez à propos des points de vue personnels (la fonctionnalité #50 par exemple).
Félicitations @JacquesMironneau et @Anas9820 🏅 Votre implémentation de la fonctionnalité est désormais intégrée à la branche principale 🎉
La fonctionnalité est en production 🎉
Rules:
Viewpoints with a list of contributors can be edited only by them (but existing viewpoints, without a list or with an empty list, are still writable by any authenticated user).
On creation, a viewpoint has its author as its only contributor.
Any contributor of a viewpoint can authorize another user to contribute.
Note: Porphyry feature is only the user interface part of a "real" authorization performed by Argos (see https://github.com/Hypertopic/Argos/commit/97deb65867ac7fac05d05d7ce51ad4c81e7ff7bb).
Phase 1
Phase 2