La suppression d'un compte ayant des contenus associés plante #57

Closed
opened 2020-07-21 23:22:31 +02:00 by Darks · 14 comments
Owner

Étant donné que ça casse des relations dans la BDD, on ne peut pas supprimer un compte qui a des contenus associés.

Il faut créer deux options :

  • tout supprimer
  • passer les contenus en Guest
Étant donné que ça casse des relations dans la BDD, on ne peut pas supprimer un compte qui a des contenus associés. Il faut créer deux options : - tout supprimer - passer les contenus en `Guest`
Darks added the
bug
label 2020-07-21 23:22:31 +02:00
Collaborator

Je propose en Guest pour plusieurs raisons :

  • Les programmes proposés peuvent être intéressant, même si le compte devient cancer.
  • Si on choisit de créer des lien vers l'un des sujet de l'utilisateur depuis un autre topic, on tombera sur un lien mort (mais il aurait pu nous aider), ce qui peut devenir désagréable.

Ainsi, si on le veut, on peut très bien personnaliser la page user de celui-ci en affichant : "Est mort au combat dans la lutte anti-modération." ?

Je propose en Guest pour plusieurs raisons : * Les programmes proposés peuvent être intéressant, même si le compte devient cancer. * Si on choisit de créer des lien vers l'un des sujet de l'utilisateur depuis un autre topic, on tombera sur un lien mort (mais il aurait pu nous aider), ce qui peut devenir désagréable. Ainsi, si on le veut, on peut très bien personnaliser la page user de celui-ci en affichant : `"Est mort au combat dans la lutte anti-modération."` ?
Owner

Je pense que le RGPD nous oblige à donner l'option de tout supprimer. Je propose de mettre l'option sur la page de suppression de compte, en précisant bien que conserver les contenus ne conservera aucune information personnelle et en laissant sur Guest par défaut.

Je pense que le RGPD nous oblige à donner l'option de tout supprimer. Je propose de mettre l'option sur la page de suppression de compte, en précisant bien que conserver les contenus ne conservera aucune information personnelle et en laissant sur Guest par défaut.
Owner

Conséquence immédiate : un programme peut être posté par un invité.

Conséquence immédiate : un programme *peut* être posté par un invité.
Collaborator

Non, un programme peut avoir comme auteur un invité, mais ne peut pas être posté par un invité.

Non, un programme peut avoir comme auteur un invité, mais ne peut pas être posté par un invité.
Owner

Ma remarque n'était pas vraiment sur cette distinction (qui est correcte) mais sur les modification proposées du modèle hier dans #20 : on ne peut pas modifier la contrainte de clé étrangère sur author_id pour interdire les invités parce que ça ne permettrait pas d'implémenter cette fonctionnalité.

Ma remarque n'était pas vraiment sur cette distinction (qui est correcte) mais sur les modification proposées du modèle hier dans #20 : on ne peut pas modifier la contrainte de clé étrangère sur `author_id` pour interdire les invités parce que ça ne permettrait pas d'implémenter cette fonctionnalité.
Collaborator

Et bien, c'est simple, on bloque l'accès au formulaire de post de programme aux Guests ?

Et bien, c'est simple, on bloque l'accès au formulaire de post de programme aux Guests ?
Owner

À postériori du moins. On peut vouloir restreindre l'upload de programmes aux seuls membres.

Par contre en effet ça veut dire qu'ne faut pas surcharger la relation d'auteur dans Program.

Voilà c'est ça. Mais du coup il faut faire gaffe dans toutes les vues et opérations de manipulation de programmes qu'on peut être en train de jouer avec des invités.

> À postériori du moins. On peut vouloir restreindre l'upload de programmes aux seuls membres. > > Par contre en effet ça veut dire qu'ne faut pas surcharger la relation d'auteur dans Program. Voilà c'est ça. Mais du coup il faut faire gaffe dans toutes les vues et opérations de manipulation de programmes qu'on peut être en train de jouer avec des invités.
Collaborator

Bah pourquoi on bloque le fait qu'un invité puisse créer un programme ? On dit que tous les Users peuvent créer un Programme, et ensuite dans la route, on vérifie que la personne actuelle est un membre. On évite les conflits et les administrateurs pourront toujours modifier les anciens programmes ?

Ou autre solution, on crée un compte bidon 'décharge' où on y met tout les topic et programmes d'une personne, et pour ses commentaires, on bascule en Guest ?

Bah pourquoi on bloque le fait qu'un invité puisse créer un programme ? On dit que tous les Users peuvent créer un Programme, et ensuite dans la route, on vérifie que la personne actuelle est un membre. On évite les conflits et les administrateurs pourront toujours modifier les anciens programmes ? Ou autre solution, on crée un compte bidon 'décharge' où on y met tout les topic et programmes d'une personne, et pour ses commentaires, on bascule en Guest ?
Author
Owner

J'ai rien compris, mais en gros :

  • on reste sur l'héritage de Post par Program, sans surcharger la propriété author
  • on restreint l'accès à la publication de programmes par les membres
  • si un compte est supprimé avec l'option de garder les contenus, on créé un Guest du même pseudo, et on lui attribue les contenus
J'ai rien compris, mais en gros : - on reste sur l'héritage de Post par Program, sans surcharger la propriété `author` - on restreint l'accès à la publication de programmes par les membres - si un compte est supprimé avec l'option de garder les contenus, on créé un `Guest` du même pseudo, et on lui attribue les contenus
Owner

C'est ça. Pour le point 2, on passe par @login_required ou un truc du genre. Il faudra aussi valider lors de la soumission du formulaire parce qu'on aura besoin d'upcaster vers Member.

C'est ça. Pour le point 2, on passe par `@login_required` ou un truc du genre. Il faudra aussi valider lors de la soumission du formulaire parce qu'on aura besoin d'upcaster vers `Member`.
Author
Owner

Le @login_required s'applique lors du GET et lors du POST. Donc pas besoin de checker à la main une fois de plus 😉

Le `@login_required` s'applique lors du `GET` et lors du `POST`. Donc pas besoin de checker à la main une fois de plus :wink:
Author
Owner

Je mets ici les logs d'erreur, parce que ce n'est toujours pas corrigé

nov. 11 19:32:53 aperture-labs uwsgi[514794]: [2020-11-11 19:32:53,141] ERROR in app: Exception on /compte/supprimer [POST]
nov. 11 19:32:53 aperture-labs uwsgi[514794]: Traceback (most recent call last):
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "/usr/lib/python3.8/site-packages/flask/app.py", line 2447, in wsgi_app
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     response = self.full_dispatch_request()
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "/usr/lib/python3.8/site-packages/flask/app.py", line 1952, in full_dispatch_request
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     rv = self.handle_user_exception(e)
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "/usr/lib/python3.8/site-packages/flask/app.py", line 1821, in handle_user_exception
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     reraise(exc_type, exc_value, tb)
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "/usr/lib/python3.8/site-packages/flask/_compat.py", line 39, in reraise
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     raise value
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "/usr/lib/python3.8/site-packages/flask/app.py", line 1950, in full_dispatch_request
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     rv = self.dispatch_request()
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "/usr/lib/python3.8/site-packages/flask/app.py", line 1936, in dispatch_request
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     return self.view_functions[rule.endpoint](**req.view_args)
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "/usr/lib/python3.8/site-packages/flask_login/utils.py", line 272, in decorated_view
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     return func(*args, **kwargs)
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "./app/routes/account/account.py", line 95, in delete_account
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     db.session.commit()
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "/usr/lib/python3.8/site-packages/sqlalchemy/orm/scoping.py", line 163, in do
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     return getattr(self.registry(), name)(*args, **kwargs)
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "/usr/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 1042, in commit
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     self.transaction.commit()
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "/usr/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 504, in commit
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     self._prepare_impl()
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "/usr/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 483, in _prepare_impl
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     self.session.flush()
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "/usr/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 2536, in flush
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     self._flush(objects)
nov. 11 19:32:53 aperture-labs uwsgi[514794]:   File "/usr/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 2627, in _flush
nov. 11 19:32:53 aperture-labs uwsgi[514794]:     assert _reg, "Failed to add object to the flush context!"
nov. 11 19:32:53 aperture-labs uwsgi[514794]: AssertionError: Failed to add object to the flush context!

Edit: à priori ça n'a pas l'air d'être exactement la même erreur. À corriger tout de même.

Je mets ici les logs d'erreur, parce que ce n'est toujours pas corrigé ``` nov. 11 19:32:53 aperture-labs uwsgi[514794]: [2020-11-11 19:32:53,141] ERROR in app: Exception on /compte/supprimer [POST] nov. 11 19:32:53 aperture-labs uwsgi[514794]: Traceback (most recent call last): nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "/usr/lib/python3.8/site-packages/flask/app.py", line 2447, in wsgi_app nov. 11 19:32:53 aperture-labs uwsgi[514794]: response = self.full_dispatch_request() nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "/usr/lib/python3.8/site-packages/flask/app.py", line 1952, in full_dispatch_request nov. 11 19:32:53 aperture-labs uwsgi[514794]: rv = self.handle_user_exception(e) nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "/usr/lib/python3.8/site-packages/flask/app.py", line 1821, in handle_user_exception nov. 11 19:32:53 aperture-labs uwsgi[514794]: reraise(exc_type, exc_value, tb) nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "/usr/lib/python3.8/site-packages/flask/_compat.py", line 39, in reraise nov. 11 19:32:53 aperture-labs uwsgi[514794]: raise value nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "/usr/lib/python3.8/site-packages/flask/app.py", line 1950, in full_dispatch_request nov. 11 19:32:53 aperture-labs uwsgi[514794]: rv = self.dispatch_request() nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "/usr/lib/python3.8/site-packages/flask/app.py", line 1936, in dispatch_request nov. 11 19:32:53 aperture-labs uwsgi[514794]: return self.view_functions[rule.endpoint](**req.view_args) nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "/usr/lib/python3.8/site-packages/flask_login/utils.py", line 272, in decorated_view nov. 11 19:32:53 aperture-labs uwsgi[514794]: return func(*args, **kwargs) nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "./app/routes/account/account.py", line 95, in delete_account nov. 11 19:32:53 aperture-labs uwsgi[514794]: db.session.commit() nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "/usr/lib/python3.8/site-packages/sqlalchemy/orm/scoping.py", line 163, in do nov. 11 19:32:53 aperture-labs uwsgi[514794]: return getattr(self.registry(), name)(*args, **kwargs) nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "/usr/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 1042, in commit nov. 11 19:32:53 aperture-labs uwsgi[514794]: self.transaction.commit() nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "/usr/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 504, in commit nov. 11 19:32:53 aperture-labs uwsgi[514794]: self._prepare_impl() nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "/usr/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 483, in _prepare_impl nov. 11 19:32:53 aperture-labs uwsgi[514794]: self.session.flush() nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "/usr/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 2536, in flush nov. 11 19:32:53 aperture-labs uwsgi[514794]: self._flush(objects) nov. 11 19:32:53 aperture-labs uwsgi[514794]: File "/usr/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 2627, in _flush nov. 11 19:32:53 aperture-labs uwsgi[514794]: assert _reg, "Failed to add object to the flush context!" nov. 11 19:32:53 aperture-labs uwsgi[514794]: AssertionError: Failed to add object to the flush context! ``` --- Edit: à priori ça n'a pas l'air d'être exactement la même erreur. À corriger tout de même.
Owner

Pour information, on ne peut pas (genre absolument pas) faire db.session.delete() sur un objet complexe à cause de ses dépendances. J'ai commencé à implémenter sur les différents modèles une méthode .delete() qui supprime les sous-objets ou les références aux sous-objets.

C'était notamment nécessaire pour supprimer et recréer les forums. Dans ce cas, on supprime les messages, threads, topics récursivement.

Pour les utilisateurs, il faut faire pareil, mais c'est plus compliqué parce qu'il faut d'abord migrer les contenus (comme on en a discuté plus haut).

Pour information, on ne peut pas (genre absolument pas) faire `db.session.delete()` sur un objet complexe à cause de ses dépendances. J'ai commencé à implémenter sur les différents modèles une méthode `.delete()` qui supprime les sous-objets ou les références aux sous-objets. C'était notamment nécessaire pour supprimer et recréer les forums. Dans ce cas, on supprime les messages, threads, topics récursivement. Pour les utilisateurs, il faut faire pareil, mais c'est plus compliqué parce qu'il faut d'abord migrer les contenus (comme on en a discuté plus haut).
Lephenixnoir self-assigned this 2021-07-08 09:18:14 +02:00
Owner

Le commit précédent ajoute quelques méthodes à Member pour gérer la suppression et migration des contenus :

  • generate_guest_name() donne un nom d'invité. Le format est<membre>_<numéro><numéro> commence à 0 et augmente jusqu'à ce qu'un nom disponible soit trouvé. J'ai imaginé <membre>_ mais ça me semble plus courant comme nom d'invité, et moins il y a de collisions plus c'est simple.

  • transfer_posts(self, other) transfère tous les posts : commentaires, topics, programmes pour l'instant.

  • delete_posts() supprime tous les posts (y compris les commentaires d'autres membres sur les fils possédés par le membre).

  • Et enfin delete() supprime tout le reste, comme d'hab. Donc la suppression c'est soit transfer_posts() soit delete_posts(), suivi de delete().

Le formulaire de suppression de compte a été modifié à la fois côté membre et côté admin. J'ai testé à peu près tous les cas (nom déjà utilisé, suppression par le membre, suppression par l'admin, commentaire anonymé, topic anonymé, commentaire externe supprimé par un topic supprimé, etc).

Le commit précédent ajoute quelques méthodes à `Member` pour gérer la suppression et migration des contenus : * `generate_guest_name()` donne un nom d'invité. Le format est`<membre>_<numéro>` où `<numéro>` commence à 0 et augmente jusqu'à ce qu'un nom disponible soit trouvé. J'ai imaginé `<membre>_` mais ça me semble plus courant comme nom d'invité, et moins il y a de collisions plus c'est simple. * `transfer_posts(self, other)` transfère tous les posts : commentaires, topics, programmes pour l'instant. * `delete_posts()` supprime tous les posts (y compris les commentaires d'autres membres sur les fils possédés par le membre). * Et enfin `delete()` supprime tout le reste, comme d'hab. Donc la suppression c'est soit `transfer_posts()` soit `delete_posts()`, suivi de `delete()`. Le formulaire de suppression de compte a été modifié à la fois côté membre et côté admin. J'ai testé à peu près tous les cas (nom déjà utilisé, suppression par le membre, suppression par l'admin, commentaire anonymé, topic anonymé, commentaire externe supprimé par un topic supprimé, etc).
Sign in to join this conversation.
No description provided.