Projet

Général

Profil

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

Benjamin Dauvergne, 31 août 2022 12:53

Télécharger (6,42 ko)

Voir les différences:

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

 tests/test_users.py | 81 ++++++++++++++++++++++++++++++++++++++++++++-
 wcs/publisher.py    |  6 ++++
 wcs/sql.py          | 58 ++++++++++++++++++++++++++++++++
 3 files changed, 144 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
    user5 = User()
145
    user5.name = 'Alain'
146
    user5.deleted_timestamp = datetime.datetime.now()
147
    user5.store()
148

  
149
    formdata1 = data_class()
150
    formdata1.user_id = user1.id
151
    evo = Evolution()
152
    evo.time = time.localtime()
153
    evo.who = user4.id
154
    formdata1.evolution = [evo]
155
    formdata1.workflow_roles = {'_received': '_user:%s' % user5.id}
156
    formdata1.store()
157

  
158
    carddata1 = card_data_class()
159
    carddata1.user_id = user3.id
160
    carddata1.store()
161

  
162
    assert User.count() == 5
163

  
164
    get_publisher().clean_deleted_users()
165

  
166
    assert {user.name for user in User.select()} == {'Pierre', 'Michel', 'Martin', 'Alain'}
167

  
168
    data_class.wipe()
169
    card_data_class.wipe()
170

  
171
    get_publisher().clean_deleted_users()
172

  
173
    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()
......
511 513
            return value_.get_value()
512 514
        return value_
513 515

  
516
    def clean_deleted_users(self):
517
        for user_id in self.user_class.get_to_delete_ids():
518
            self.user_class.remove_object(user_id)
519

  
514 520

  
515 521
set_publisher_class(WcsPublisher)
516 522
WcsPublisher.register_extra_dir(os.path.join(os.path.dirname(__file__), 'extra'))
wcs/sql.py
3296 3296

  
3297 3297
        return objects
3298 3298

  
3299
    @classmethod
3300
    def get_reference_ids(cls):
3301
        '''Retrieve ids of users reference in some carddata or formdata.'''
3302
        from wcs.carddef import CardDef
3303
        from wcs.formdef import FormDef
3304

  
3305
        referenced_ids = set()
3306

  
3307
        conn, cur = get_connection_and_cursor()
3308

  
3309
        for objectdef in CardDef.select() + FormDef.select():
3310
            data_class = objectdef.data_class()
3311

  
3312
            # referenced in form/card data.user_id
3313
            sql_statement = (
3314
                'SELECT CAST(data.user_id AS INTEGER) FROM %(table)s AS data WHERE data.user_id IS NOT NULL'
3315
                % {
3316
                    'table': data_class._table_name,
3317
                }
3318
            )
3319
            cur.execute(sql_statement)
3320
            referenced_ids.update(user_id for user_id, in cur.fetchall())
3321
            conn.commit()
3322

  
3323
            # referenced in form/card data_evolution.who
3324
            sql_statement = 'SELECT CAST(evolution.who AS INTEGER) FROM %(table)s AS evolution' % {
3325
                'table': '%s_evolutions' % data_class._table_name,
3326
            }
3327
            cur.execute(sql_statement)
3328
            referenced_ids.update(user_id for user_id, in cur.fetchall())
3329
            conn.commit()
3330

  
3331
            # referenced in form/card data.workflow_roles_array
3332
            sql_statement = '''SELECT CAST(SUBSTRING(workflow_role.workflow_role FROM 7) AS INTEGER)
3333
                                 FROM %(table)s AS data, UNNEST(data.workflow_roles_array) AS workflow_role
3334
                                 WHERE SUBSTRING(workflow_role.workflow_role FROM 1 FOR 6) = '_user:' ''' % {
3335
                'table': data_class._table_name,
3336
            }
3337
            cur.execute(sql_statement)
3338
            referenced_ids.update(user_id for user_id, in cur.fetchall())
3339
            conn.commit()
3340
        return referenced_ids
3341

  
3342
    @classmethod
3343
    def get_to_delete_ids(cls):
3344
        '''Retrieve ids of users which are deleted on the IdP and are no more referenced by any form or card.'''
3345

  
3346
        # fetch marked as deleted users
3347
        conn, cur = get_connection_and_cursor()
3348
        sql_statement = 'SELECT users.id FROM users WHERE users.deleted_timestamp IS NOT NULL'
3349
        cur.execute(sql_statement)
3350
        deleted_ids = {user_id for user_id, in cur.fetchall()}
3351
        conn.commit()
3352
        cur.close()
3353

  
3354
        to_delete_ids = deleted_ids.difference(cls.get_reference_ids())
3355
        return to_delete_ids
3356

  
3299 3357

  
3300 3358
class Role(SqlMixin, wcs.roles.Role):
3301 3359
    _table_name = 'roles'
3302
-