Projet

Général

Profil

0001-users-add-cronjob-to-delete-users-24430.patch

Benjamin Dauvergne, 01 août 2022 15:05

Télécharger (6,28 ko)

Voir les différences:

Subject: [PATCH] users: add cronjob to delete users (#24430)

 tests/test_users.py | 77 ++++++++++++++++++++++++++++++++++++++++++++-
 wcs/publisher.py    |  6 ++++
 wcs/sql.py          | 35 +++++++++++++++++++++
 wcs/users.py        | 15 +++++++++
 4 files changed, 132 insertions(+), 1 deletion(-)
tests/test_users.py
1
import datetime
1 2
import shutil
3
import time
2 4

  
3 5
import pytest
4
from quixote import cleanup
6
from quixote import cleanup, get_publisher
5 7

  
6 8
from wcs import fields
7 9
from wcs.variables import LazyUser
......
92 94
    with pytest.raises(AttributeError):
93 95
        # noqa pylint: disable=pointless-statement
94 96
        user.xxx
97

  
98

  
99
def test_clean_deleted_users():
100
    from wcs.carddef import CardDef
101
    from wcs.formdef import FormDef
102
    from wcs.workflows import Evolution
103

  
104
    User = pub.user_class
105

  
106
    User.wipe()
107
    FormDef.wipe()
108
    CardDef.wipe()
109

  
110
    formdef = FormDef()
111
    formdef.name = 'foobar'
112
    formdef.url_name = 'foobar'
113
    formdef.fields = []
114
    formdef.store()
115
    data_class = formdef.data_class()
116

  
117
    carddef = CardDef()
118
    carddef.name = 'barfoo'
119
    carddef.url_name = 'barfoo'
120
    carddef.fields = []
121
    carddef.store()
122
    card_data_class = carddef.data_class()
123

  
124
    user1 = User()
125
    user1.name = 'Pierre'
126
    user1.deleted_timestamp = datetime.datetime.now()
127
    user1.store()
128

  
129
    user2 = User()
130
    user2.name = 'Jean'
131
    user2.deleted_timestamp = datetime.datetime.now()
132
    user2.store()
133

  
134
    user3 = User()
135
    user3.name = 'Michel'
136
    user3.deleted_timestamp = datetime.datetime.now()
137
    user3.store()
138

  
139
    user4 = User()
140
    user4.name = 'Martin'
141
    user4.deleted_timestamp = datetime.datetime.now()
142
    user4.store()
143

  
144
    formdata1 = data_class()
145
    formdata1.user_id = user1.id
146
    evo = Evolution()
147
    evo.time = time.localtime()
148
    evo.who = user4.id
149
    formdata1.evolution = [evo]
150
    formdata1.store()
151

  
152
    carddata1 = card_data_class()
153
    carddata1.user_id = user3.id
154
    carddata1.store()
155

  
156
    assert User.count() == 4
157

  
158
    get_publisher().clean_deleted_users()
159

  
160
    assert User.count() == 3
161

  
162
    assert {user.name for user in User.select()} == {'Pierre', 'Michel', 'Martin'}
163

  
164
    data_class.wipe()
165
    card_data_class.wipe()
166

  
167
    get_publisher().clean_deleted_users()
168

  
169
    assert User.count() == 0
wcs/publisher.py
123 123
        cls.register_cronjob(
124 124
            CronJob(cls.update_deprecations_report, name='update_deprecations_report', hours=[2], minutes=[0])
125 125
        )
126
        # once a day delete users without any formdata
127
        cls.register_cronjob(CronJob(cls.clean_deleted_users, name='clean_deleted_users', minutes=[0]))
126 128
        # other jobs
127 129
        data_sources.register_cronjob()
128 130
        formdef.register_cronjobs()
......
508 510
            return value_.get_value()
509 511
        return value_
510 512

  
513
    def clean_deleted_users(self):
514
        for user_id in self.user_class.get_to_delete_ids():
515
            self.user_class.remove_object(user_id)
516

  
511 517

  
512 518
set_publisher_class(WcsPublisher)
513 519
WcsPublisher.register_extra_dir(os.path.join(os.path.dirname(__file__), 'extra'))
wcs/sql.py
3264 3264

  
3265 3265
        return objects
3266 3266

  
3267
    @classmethod
3268
    def get_to_delete_ids(cls):
3269
        from wcs.carddef import CardDef
3270
        from wcs.formdef import FormDef
3271

  
3272
        conn, cur = get_connection_and_cursor()
3273
        sql_statement = 'SELECT users.id FROM users WHERE users.deleted_timestamp IS NOT NULL'
3274
        cur.execute(sql_statement)
3275
        deleted_ids = {user_id for user_id, in cur.fetchall()}
3276
        conn.commit()
3277

  
3278
        for carddef in CardDef.select() + FormDef.select():
3279
            # keep only user.id not present in form/card_data.user_id or form/card_evolutions.who columns
3280
            data_class = carddef.data_class()
3281
            sql_statement = '''SELECT users.id
3282
                                 FROM users LEFT JOIN %(table)s ON users.id = CAST(%(table)s.user_id AS INTEGER)
3283
                                WHERE users.deleted_timestamp IS NOT NULL
3284
                                AND %(table)s.id IS NULL''' % {
3285
                'table': data_class._table_name
3286
            }
3287
            cur.execute(sql_statement)
3288
            deleted_ids = deleted_ids & {user_id for user_id, in cur.fetchall()}
3289
            sql_statement = '''SELECT users.id
3290
                                 FROM users LEFT JOIN %(table)s ON users.id = CAST(%(table)s.who AS INTEGER)
3291
                                WHERE users.deleted_timestamp IS NOT NULL
3292
                                AND %(table)s.id IS NULL''' % {
3293
                'table': '%s_evolutions' % data_class._table_name,
3294
            }
3295
            cur.execute(sql_statement)
3296
            deleted_ids = deleted_ids & {user_id for user_id, in cur.fetchall()}
3297
            conn.commit()
3298

  
3299
        cur.close()
3300
        return deleted_ids
3301

  
3267 3302

  
3268 3303
class Role(SqlMixin, wcs.roles.Role):
3269 3304
    _table_name = 'roles'
wcs/users.py
320 320
    def get_full_name(self):
321 321
        return self.display_name
322 322

  
323
    @classmethod
324
    def get_to_delete_ids(cls):
325
        from .formdef import FormDef
326

  
327
        deleted_ids = {user.id for user in cls.select([st.NotNull('deleted_timestamp')])}
328

  
329
        active_ids = set()
330
        for formdef in FormDef.select():
331
            data_class = formdef.data_class()
332
            active_ids.update(
333
                formdata.user_id for formdata in data_class.select(iterator=True) if formdata.user_id
334
            )
335

  
336
        return deleted_ids - active_ids
337

  
323 338

  
324 339
Substitutions.register(
325 340
    'session_user_display_name',
326
-