From 5273b429c371b9db51db089d543a3cf0541d1d08 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 4 Oct 2018 23:33:09 +0200 Subject: [PATCH 3/4] users: add cronjob to delete users (#24430) --- tests/test_users.py | 41 +++++++++++++++++++++++++++++++++++++++- wcs/publisher.py | 6 ++++++ wcs/sql.py | 12 ++++++++++++ wcs/users.py | 46 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 1 deletion(-) diff --git a/tests/test_users.py b/tests/test_users.py index 2215ecb4..e06f62f2 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -7,7 +7,7 @@ import time import pytest -from quixote import cleanup +from quixote import cleanup, get_publisher from wcs import publisher from wcs import fields @@ -78,3 +78,42 @@ def test_user_formdef_getattr(): with pytest.raises(AttributeError): user.xxx + + +def test_clean_deleted_users(): + from wcs.formdef import FormDef + from wcs.qommon import storage as st + + User = pub.user_class + + User.wipe() + FormDef.wipe() + + formdef = FormDef() + formdef.name = 'foobar' + formdef.url_name = 'foobar' + formdef.fields = [] + formdef.store() + data_class = formdef.data_class() + + user1 = User() + user1.name = 'Pierre' + user1.deleted = True + user1.store() + + user2 = User() + user2.name = 'Jean' + user2.deleted = True + user2.store() + + formdata1 = data_class() + formdata1.user_id = user1.id + formdata1.store() + + assert User.count() == 2 + + get_publisher().clean_deleted_users() + + assert User.count() == 1 + assert len(User.select([st.Equal('name', 'Pierre')])) == 1 + assert len(User.select([st.Equal('name', 'Jean')])) == 0 diff --git a/wcs/publisher.py b/wcs/publisher.py index d33a7ff0..625a823e 100644 --- a/wcs/publisher.py +++ b/wcs/publisher.py @@ -124,6 +124,7 @@ class WcsPublisher(StubWcsPublisher): super(WcsPublisher, cls).register_cronjobs() # every hour: check for global action timeouts cls.register_cronjob(CronJob(cls.apply_global_action_timeouts, minutes=[0])) + cls.register_cronjob(CronJob(cls.clean_deleted_users, minutes=[0])) def is_using_postgresql(self): return bool(self.has_site_option('postgresql') and self.cfg.get('postgresql', {})) @@ -359,6 +360,11 @@ class WcsPublisher(StubWcsPublisher): from . import sql sql.cleanup_connection() + def clean_deleted_users(self): + for user_id in self.user_class.get_to_delete_ids(): + self.user_class.remove_object(user_id) + + set_publisher_class(WcsPublisher) WcsPublisher.register_extra_dir(os.path.join(os.path.dirname(__file__), 'extra')) diff --git a/wcs/sql.py b/wcs/sql.py index ec402c4c..7446f9af 100644 --- a/wcs/sql.py +++ b/wcs/sql.py @@ -1960,6 +1960,18 @@ class SqlUser(SqlMixin, wcs.users.User): return objects + @classmethod + def get_to_delete_ids(cls): + from .formdef import FormDef + + deleted_ids = set(str(user.id) for user in cls.select([Equal('deleted', True)])) + for formdef in FormDef.select(): + for formdata in formdef.data_class().select([Contains('user_id', deleted_ids)], iterator=True): + user_id = str(formdata.user_id) + if user_id in deleted_ids: + deleted_ids.remove(str(formdata.user_id)) + return deleted_ids + class Session(SqlMixin, wcs.sessions.BasicSession): _table_name = 'sessions' diff --git a/wcs/users.py b/wcs/users.py index de6c5b8e..ad5355ee 100644 --- a/wcs/users.py +++ b/wcs/users.py @@ -254,6 +254,52 @@ class User(StorableObject): self.form_data = {} self.store() + @classmethod + def get_to_delete_ids(cls): + from .formdef import FormDef + + deleted_ids = set(str(user.id) for user in cls.select([st.Equal('deleted', True)])) + for formdef in FormDef.select(): + data_class = formdef.data_class() + formdatas = data_class.select( + [st.Contains('user_id', deleted_ids)], + iterator=True) + for formdata in formdatas: + user_id = str(formdata.user_id) + if user_id in deleted_ids: + deleted_ids.remove(str(formdata.user_id)) + return deleted_ids + + @classmethod + def clean_deleted_users_sql(cls): + from wcs.sql import AnyFormData + from wcs.formdef import FormDef + + deleted = cls.select([st.Equal('deleted', True)]) + deleted_ids = set(str(u.id) for u in deleted) + active_ids = set() + if FormDef.count(): + # without any FormDef global views are not created. + active_ids = set(f.user_id for f in AnyFormData.select( + [st.Contains('user_id', deleted_ids)], iterator=True)) + to_delete_ids = deleted_ids - active_ids + for user_id in to_delete_ids: + cls.remove_object(user_id) + + @classmethod + def clean_deleted_users_pickle(cls): + from wcs.formdef import FormDef + + deleted = cls.select([st.Equal('deleted', True)]) + deleted_ids = set(str(u.id) for u in deleted) + active_ids = set() + for formdef in FormDef.select(): + for formdata in formdef.data_class().select([st.Contains('user_id', deleted_ids)], iterator=True): + active_ids.add(str(formdata.user_id)) + to_delete_ids = deleted_ids - active_ids + for user_id in to_delete_ids: + cls.remove_object(user_id) + Substitutions.register('session_user_display_name', category=N_('User'), comment=N_('Session User Display Name')) Substitutions.register('session_user_email', category=N_('User'), comment=N_('Session User Email')) -- 2.24.0