]>
Commit | Line | Data |
---|---|---|
685e346e A |
1 | from datetime import datetime\r |
2 | from utils import *\r | |
3 | from istring import *\r | |
4 | import traceback\r | |
5 | import inspect\r | |
6 | \r | |
7 | class InvariantCollection(object):\r | |
8 | def __init__(self):\r | |
9 | self.__entries = {}\r | |
10 | \r | |
11 | def __len__(self):\r | |
12 | return len(self.__entries)\r | |
13 | \r | |
14 | def __getitem__(self, key):\r | |
15 | invariant_key = istring(key)\r | |
16 | \r | |
17 | if not self.__contains__(invariant_key):\r | |
18 | raise KeyError('Entry with key %s not present.' % key)\r | |
19 | \r | |
20 | return self.__entries[invariant_key]\r | |
21 | \r | |
22 | def __setitem__(self, key, value):\r | |
23 | self.__entries[istring(key)] = value\r | |
24 | \r | |
25 | def __delitem__(self, key):\r | |
26 | invariant_key = istring(key)\r | |
27 | \r | |
28 | if not self.__contains__(invariant_key):\r | |
29 | raise KeyError('Entry with key %s not present.' % key)\r | |
30 | \r | |
31 | del(self.__entries[invariant_key])\r | |
32 | \r | |
33 | def __iter__(self):\r | |
34 | for entry in self.__entries:\r | |
35 | yield entry\r | |
36 | \r | |
37 | def __contains__(self, item):\r | |
38 | if not isinstance(item, basestring):\r | |
39 | raise TypeError('%s is not an allowed indexing type.' % type(item))\r | |
40 | \r | |
41 | return istring(item) in self.__entries\r | |
42 | \r | |
43 | def list_all(self):\r | |
44 | return [self[item] for item in self]\r | |
45 | \r | |
46 | class CollectionEntity(object):\r | |
47 | def __init__(self, id, ban_source = None, ban_reason = None, ban_date = None, ban_expiry = None):\r | |
48 | self.id = id\r | |
49 | self.ban_source = ban_source\r | |
50 | self.ban_reason = ban_reason\r | |
51 | self.ban_date = ban_date\r | |
52 | self.ban_expiry = ban_expiry\r | |
53 | self.dirty = False\r | |
54 | self.registered = self.banned = False\r | |
55 | \r | |
56 | class CollectionManager(InvariantCollection):\r | |
57 | def __init__(self, type):\r | |
58 | InvariantCollection.__init__(self)\r | |
59 | self.__type = type\r | |
60 | self.__deleted_items = []\r | |
61 | \r | |
62 | self.db_open()\r | |
63 | \r | |
64 | self.load()\r | |
65 | \r | |
66 | def load(self):\r | |
67 | self.cursor.execute("CREATE TABLE IF NOT EXISTS " + self.module.name + "_" + self.name + " (id INT NOT NULL AUTO_INCREMENT, name VARCHAR(51) NOT NULL, PRIMARY KEY (id), UNIQUE KEY (name)) ENGINE=InnoDB")\r | |
68 | \r | |
69 | self.cursor.execute("CREATE TABLE IF NOT EXISTS " + self.module.name + "_" + self.name + "_options (id INT, name VARCHAR(32) NOT NULL, value TINYTEXT, UNIQUE KEY (id, name)) ENGINE=InnoDB")\r | |
70 | #self.cursor.execute("ALTER TABLE " + self.module.name + "_" + self.name + "_options ADD CONSTRAINT FOREIGN KEY IF NOT EXISTS (id) REFERENCES " + self.module.name + "_" + self.name + " (id)")\r | |
71 | \r | |
72 | self.cursor.execute("SELECT id, name FROM " + self.module.name + "_" + self.name)\r | |
73 | r = self.cursor.fetchall()\r | |
74 | \r | |
75 | for row in r:\r | |
76 | id = row[0]\r | |
77 | name = istring(row[1])\r | |
78 | \r | |
79 | self.module.elog.debug('Loading ' + name + ' for ' + self.module.name + '_' + self.name)\r | |
80 | \r | |
81 | self[name] = e = self.__type(id, name)\r | |
82 | \r | |
83 | self.cursor.execute("SELECT name,value FROM " + self.module.name + "_" + self.name + "_options WHERE `id` = %s", (id,))\r | |
84 | r2 = self.cursor.fetchall()\r | |
85 | for row2 in r2:\r | |
86 | setattr(e, row2[0], row2[1])\r | |
87 | \r | |
88 | def __get_attributes(self, obj):\r | |
89 | boring = dir(type('dummy', (object,), {}))\r | |
90 | return [item for item in inspect.getmembers(obj) if item[0] not in boring]\r | |
91 | \r | |
92 | def commit(self):\r | |
93 | try:\r | |
94 | deleted = [(e.id, ) for e in self.list_deleted()]\r | |
95 | changed = [e for e in self.list_dirty()]\r | |
96 | \r | |
97 | if len(deleted) > 0:\r | |
98 | self.cursor.executemany("DELETE FROM " + self.module.name + "_" + self.name + "_options WHERE id = %s", deleted)\r | |
99 | self.cursor.executemany("DELETE FROM " + self.module.name + "_" + self.name + " WHERE id = %s", deleted)\r | |
100 | self.module.elog.commit('Deleted %d %s from database.' % (len(deleted), self.name))\r | |
101 | \r | |
102 | for e in changed:\r | |
103 | if e.id == -1:\r | |
104 | self.cursor.execute("INSERT INTO " + self.module.name + "_" + self.name + " (name) VALUES(%s)", (e.name,))\r | |
105 | e.id = self.cursor.lastrowid\r | |
106 | else: # delete options as we are aboue to re-flush them\r | |
107 | self.cursor.execute("DELETE FROM " + self.module.name + "_" + self.name + "_options WHERE `id` = %s", (e.id,))\r | |
108 | \r | |
109 | for a in self.__get_attributes(e):\r | |
110 | attr_name = a[0]\r | |
111 | attr = getattr(e, attr_name)\r | |
112 | if attr:\r | |
113 | self.cursor.execute("INSERT INTO " + self.module.name + "_" + self.name + "_options (id, name, value) VALUES (%s, %s, %s)", (e.id, attr_name, attr))\r | |
114 | if len(changed) > 0:\r | |
115 | self.module.elog.commit('Committed %d %s to database.' % (len(changed), self.name))\r | |
116 | \r | |
117 | self.clear_deleted()\r | |
118 | \r | |
119 | for e in self.list_all():\r | |
120 | e.dirty = False\r | |
121 | except Exception, err:\r | |
122 | traceback.print_exc()\r | |
123 | self.module.elog.error(self.name + ' commit failed: @b%s@b' % err)\r | |
124 | \r | |
125 | def check(self, item):\r | |
126 | if not item in self:\r | |
127 | return\r | |
128 | \r | |
129 | entity = self[item]\r | |
130 | \r | |
131 | if entity.ban_expiry != None and entity.ban_expiry <= unix_time(datetime.now()):\r | |
132 | self.unban(item)\r | |
133 | \r | |
134 | def is_dirty(self, item):\r | |
135 | self.check(item)\r | |
136 | \r | |
137 | return item in self and self[item].dirty\r | |
138 | \r | |
139 | def is_valid(self, item):\r | |
140 | self.check(item)\r | |
141 | \r | |
142 | return item in self and self[item].registered and not self[item].banned\r | |
143 | \r | |
144 | def is_banned(self, item):\r | |
145 | self.check(item)\r | |
146 | \r | |
147 | return item in self and self[item].banned\r | |
148 | \r | |
149 | def get(self, item, attribute):\r | |
150 | if not item in self:\r | |
151 | return None\r | |
152 | \r | |
153 | return getattr(self[item], attribute)\r | |
154 | \r | |
155 | def set(self, item, attribute, value):\r | |
156 | entity = self.add(item)\r | |
157 | old_value = getattr(entity, attribute)\r | |
158 | \r | |
159 | if old_value != value:\r | |
160 | setattr(entity, attribute, value)\r | |
161 | entity.dirty = True\r | |
162 | \r | |
163 | def add(self, item):\r | |
164 | if not item in self:\r | |
165 | entity = self.__type(-1, item)\r | |
166 | entity.dirty = True\r | |
167 | entity.registered = True\r | |
168 | self[item] = entity\r | |
169 | \r | |
170 | self.on_added(item)\r | |
171 | \r | |
172 | return self[item]\r | |
173 | \r | |
174 | def remove(self, item):\r | |
175 | if not item in self:\r | |
176 | return\r | |
177 | \r | |
178 | entity = self[item]\r | |
179 | \r | |
180 | if entity.banned and entity.registered:\r | |
181 | entity.registered = False\r | |
182 | entity.clear()\r | |
183 | entity.dirty = True\r | |
184 | elif not entity.banned:\r | |
185 | if not item.lower() in self.__deleted_items:\r | |
186 | self.__deleted_items.append(entity)\r | |
187 | \r | |
188 | del(self[item])\r | |
189 | \r | |
190 | self.on_removed(item)\r | |
191 | \r | |
192 | def ban(self, item, source, reason, date, expiry):\r | |
193 | entity = self.add(item)\r | |
194 | entity.banned = True\r | |
195 | entity.ban_source = source\r | |
196 | entity.ban_reason = reason\r | |
197 | entity.ban_date = date\r | |
198 | entity.ban_expiry = expiry\r | |
199 | entity.dirty = True\r | |
200 | \r | |
201 | self.on_banned(item)\r | |
202 | \r | |
203 | def unban(self, item):\r | |
204 | if not item in self or not self[item].banned:\r | |
205 | return\r | |
206 | \r | |
207 | entity = self[item]\r | |
208 | entity.banned = False\r | |
209 | entity.ban_source = None\r | |
210 | entity.ban_reason = None\r | |
211 | entity.ban_date = None\r | |
212 | entity.ban_expiry = None\r | |
213 | \r | |
214 | if not entity.registered:\r | |
215 | self.remove(item)\r | |
216 | else:\r | |
217 | entity.dirty = True\r | |
218 | \r | |
219 | self.on_unbanned(item)\r | |
220 | \r | |
221 | def on_added(self, item):\r | |
222 | pass\r | |
223 | \r | |
224 | def on_removed(self, item):\r | |
225 | pass\r | |
226 | \r | |
227 | def on_banned(self, item):\r | |
228 | pass\r | |
229 | \r | |
230 | def on_unbanned(self, item):\r | |
231 | pass\r | |
232 | \r | |
233 | def clear_deleted(self):\r | |
234 | self.__deleted_items = []\r | |
235 | \r | |
236 | def list_deleted(self):\r | |
237 | return self.__deleted_items\r | |
238 | \r | |
239 | def list_dirty(self):\r | |
240 | items = [item for item in self]\r | |
241 | return [self[item] for item in items if self.is_dirty(item)]\r | |
242 | \r | |
243 | def list_valid(self):\r | |
244 | items = [item for item in self]\r | |
245 | return [self[item] for item in items if self.is_valid(item)]\r | |
246 | \r | |
247 | def list_banned(self):\r | |
248 | items = [item for item in self]\r | |
249 | return [self[item] for item in items if self.is_banned(item)]\r |