Add configuration for dsn lifetime in message store.
[mailman.git] / src / mailman / model / uid.py
blob36aed4f64e3c9a2ec60e1a67f80e6f12d37d9e66
1 # Copyright (C) 2011-2023 by the Free Software Foundation, Inc.
3 # This file is part of GNU Mailman.
5 # GNU Mailman is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free
7 # Software Foundation, either version 3 of the License, or (at your option)
8 # any later version.
10 # GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 # more details.
15 # You should have received a copy of the GNU General Public License along with
16 # GNU Mailman. If not, see <https://www.gnu.org/licenses/>.
18 """Unique IDs."""
20 from mailman.database.model import Model
21 from mailman.database.transaction import dbconnection
22 from mailman.database.types import UUID
23 from public import public
24 from sqlalchemy import Column, Integer
27 @public
28 class UID(Model):
29 """Enforce uniqueness of uids through a database table.
31 This is used so that unique ids don't have to be tracked by each
32 individual model object that uses them. So for example, when a user is
33 deleted, we don't have to keep separate track of its uid to prevent it
34 from ever being used again. This class, hooked up to the `UIDFactory`
35 serves that purpose.
37 There is no interface for this class, because it's purely an internal
38 implementation detail.
39 """
41 __tablename__ = 'uid'
43 id = Column(Integer, primary_key=True)
44 uid = Column(UUID, index=True)
46 @dbconnection
47 def __init__(self, store, uid):
48 super().__init__()
49 self.uid = uid
50 store.add(self)
52 def __repr__(self):
53 return '<UID {} at {}>'.format(self.uid, id(self))
55 @staticmethod
56 @dbconnection
57 # Note that the parameter order is deliberately reversed here. Normally,
58 # `store` is the first parameter after `self`, but since this is a
59 # staticmethod and there is no self, the decorator will see the uid in
60 # arg[0].
61 def record(uid, store):
62 """Record the uid in the database.
64 :param uid: The unique id.
65 :type uid: unicode
66 :raises ValueError: if the id is not unique.
67 """
68 existing = store.query(UID).filter_by(uid=uid)
69 if existing.count() != 0:
70 raise ValueError(uid)
71 return UID(uid)
73 @staticmethod
74 @dbconnection
75 def get_total_uid_count(store):
76 return store.query(UID).count()
78 @staticmethod
79 @dbconnection
80 def cull_orphans(store):
81 # Avoid circular imports.
82 from mailman.model.user import User
84 # Delete all uids in this table that are not associated with user
85 # rows.
86 results = store.query(UID).filter(
87 ~UID.uid.in_(store.query(User._user_id)))
88 for uid in results.all():
89 store.delete(uid)