|
@@ -6,8 +6,6 @@
|
6
|
6
|
import datetime
|
7
|
7
|
|
8
|
8
|
import logging
|
9
|
|
-import sqlalchemy as sql
|
10
|
|
-from Database import sqlutils
|
11
|
9
|
import EditorialModel.fieldtypes as ftypes
|
12
|
10
|
from collections import OrderedDict
|
13
|
11
|
|
|
@@ -21,12 +19,6 @@ logger = logging.getLogger('Lodel2.EditorialModel')
|
21
|
19
|
# @pure
|
22
|
20
|
class EmComponent(object):
|
23
|
21
|
|
24
|
|
- ## The name of the engine configuration
|
25
|
|
- # @todo Not a good idea to store it here
|
26
|
|
- dbconf = 'default'
|
27
|
|
- ## The table in wich we store data for this object
|
28
|
|
- # None for EmComponent
|
29
|
|
- table = None
|
30
|
22
|
## Used by EmComponent::modify_rank
|
31
|
23
|
ranked_in = None
|
32
|
24
|
|
|
@@ -53,14 +45,7 @@ class EmComponent(object):
|
53
|
45
|
# @param id_or_name int|str: name or id of the object
|
54
|
46
|
# @throw TypeError if id_or_name is not an integer nor a string
|
55
|
47
|
# @throw NotImplementedError if called with EmComponent
|
56
|
|
- def __init__(self, id_or_name, dbconf = 'default'):
|
57
|
|
-
|
58
|
|
- self.dbconf = dbconf
|
59
|
|
- if self.dbconf:
|
60
|
|
- self.db_engine = sqlutils.get_engine(dbconf)
|
61
|
|
- else:
|
62
|
|
- self.db_engine = False
|
63
|
|
-
|
|
48
|
+ def __init__(self, id_or_name):
|
64
|
49
|
if type(self) == EmComponent:
|
65
|
50
|
raise NotImplementedError('Abstract class')
|
66
|
51
|
|
|
@@ -77,7 +62,6 @@ class EmComponent(object):
|
77
|
62
|
self.name = id_or_name
|
78
|
63
|
else:
|
79
|
64
|
raise TypeError('Bad argument: expecting <int> or <str> but got : ' + str(type(id_or_name)))
|
80
|
|
- self.table = self.__class__.table
|
81
|
65
|
self.populate()
|
82
|
66
|
|
83
|
67
|
## @brief Access an attribute of an EmComponent
|
|
@@ -124,10 +108,9 @@ class EmComponent(object):
|
124
|
108
|
def __eq__(self, other):
|
125
|
109
|
return self.__class__ == other.__class__ and self.uid == other.uid
|
126
|
110
|
|
127
|
|
- ## Lookup in the database properties of the object to populate the properties
|
128
|
|
- # @throw EmComponentNotExistError if the instance is not anymore stored in database
|
|
111
|
+ ## Set all fields
|
129
|
112
|
def populate(self):
|
130
|
|
- records = self._populate_db() # Db query
|
|
113
|
+ records = [] # TODO
|
131
|
114
|
|
132
|
115
|
for record in records:
|
133
|
116
|
for keys in self._fields.keys():
|
|
@@ -136,34 +119,7 @@ class EmComponent(object):
|
136
|
119
|
|
137
|
120
|
super(EmComponent, self).__setattr__('deleted', False)
|
138
|
121
|
|
139
|
|
- #@classmethod
|
140
|
|
- ## Shortcut that return the sqlAlchemy engine
|
141
|
|
- #def db_engine(cls):
|
142
|
|
- # return sqlutils.get_engine(cls.dbconf)
|
143
|
|
-
|
144
|
|
- ## Do the query on the database for EmComponent::populate()
|
145
|
|
- # @throw EmComponentNotExistError if the instance is not anymore stored in database
|
146
|
|
- def _populate_db(self):
|
147
|
|
- dbe = self.db_engine
|
148
|
|
- component = sql.Table(self.table, sqlutils.meta(dbe))
|
149
|
|
- req = sql.sql.select([component])
|
150
|
|
-
|
151
|
|
- if self.uid is None:
|
152
|
|
- req = req.where(component.c.name == self.name)
|
153
|
|
- else:
|
154
|
|
- req = req.where(component.c.uid == self.uid)
|
155
|
|
- conn = dbe.connect()
|
156
|
|
- res = conn.execute(req)
|
157
|
|
-
|
158
|
|
- res = res.fetchall()
|
159
|
|
- conn.close()
|
160
|
|
-
|
161
|
|
- if not res or len(res) == 0:
|
162
|
|
- raise EmComponentNotExistError("No " + self.__class__.__name__ + " found with " + ('name ' + self.name if self.uid is None else 'uid ' + str(self.uid)))
|
163
|
|
-
|
164
|
|
- return res
|
165
|
|
-
|
166
|
|
- ## Insert a new component in the database
|
|
122
|
+ ## Insert a new component
|
167
|
123
|
#
|
168
|
124
|
# This function create and assign a new UID and handle the date_create and date_update values
|
169
|
125
|
# @warning There is a mandatory argument dbconf that indicate wich database configuration to use
|
|
@@ -182,118 +138,45 @@ class EmComponent(object):
|
182
|
138
|
if argname in ['date_update', 'date_create', 'rank', 'uid']: # Automatic properties
|
183
|
139
|
raise TypeError("Invalid argument : " + argname)
|
184
|
140
|
elif argname not in valid_args:
|
185
|
|
- raise TypeError("Unexcepted keyword argument '"+argname+"' for "+cls.__name__+" creation")
|
186
|
|
-
|
|
141
|
+ raise TypeError("Unexcepted keyword argument '" + argname + "' for " + cls.__name__ + " creation")
|
|
142
|
+
|
187
|
143
|
#Check uniq names constraint
|
188
|
144
|
try:
|
189
|
145
|
name = kwargs['name']
|
190
|
146
|
exist = cls(name)
|
191
|
147
|
for kname in kwargs:
|
192
|
148
|
if not (getattr(exist, kname) == kwargs[kname]):
|
193
|
|
- raise EmComponentExistError("An "+cls.__name__+" named "+name+" allready exists with a different "+kname)
|
194
|
|
- logger.info("Trying to create an "+cls.__name__+" that allready exist with same attribute. Returning the existing one")
|
|
149
|
+ raise EmComponentExistError("An " + cls.__name__ + " named " + name + " allready exists with a different " + kname)
|
|
150
|
+ logger.info("Trying to create an " + cls.__name__ + " that allready exist with same attribute. Returning the existing one")
|
195
|
151
|
return exist
|
196
|
152
|
except EmComponentNotExistError:
|
197
|
153
|
pass
|
198
|
|
-
|
199
|
|
- # Mandatory fields check (actual fieldtypes don't allow this check
|
200
|
|
- #for name in cls._fields:
|
201
|
|
- # if cls._fields[name].notNull and cls._fields[name].default == None:
|
202
|
|
- # raise TypeError("Missing argument : "+name)
|
203
|
|
-
|
204
|
|
- if 'dbconf' in kwargs:
|
205
|
|
- if not kwargs['db_engine']:
|
206
|
|
- raise NotImplementedError("Its a nonsense to call create with no database")
|
207
|
|
- dbconf = kwargs['dbconf']
|
208
|
|
- else:
|
209
|
|
- dbconf = 'default'
|
210
|
|
- dbe = sqlutils.get_engine(dbconf)
|
211
|
154
|
|
212
|
|
- kwargs['uid'] = cls.new_uid(dbe)
|
|
155
|
+ kwargs['uid'] = cls.new_uid()
|
213
|
156
|
kwargs['date_update'] = kwargs['date_create'] = datetime.datetime.utcnow()
|
214
|
157
|
|
215
|
|
- conn = dbe.connect()
|
216
|
|
-
|
217
|
158
|
kwargs['rank'] = cls._get_max_rank( kwargs[cls.ranked_in], dbe )+1
|
218
|
159
|
|
219
|
|
- table = sql.Table(cls.table, sqlutils.meta(dbe))
|
220
|
|
- req = table.insert(kwargs)
|
221
|
|
- if not conn.execute(req):
|
222
|
|
- raise RuntimeError("Unable to create the "+cls.__class__.__name__+" EmComponent ")
|
223
|
|
- conn.close()
|
224
|
160
|
return cls(kwargs['name'], dbconf)
|
225
|
161
|
|
226
|
|
- ## Write the representation of the component in the database
|
227
|
|
- # @return bool
|
228
|
|
- # @todo stop using datetime.datetime.utcnow() for date_update update
|
229
|
|
- def save(self):
|
230
|
|
- values = {}
|
231
|
|
- for name, field in self._fields.items():
|
232
|
|
- values[name] = field.to_sql()
|
233
|
|
-
|
234
|
|
- # Don't allow creation date overwritting
|
235
|
|
- #if 'date_create' in values:
|
236
|
|
- #del values['date_create']
|
237
|
|
- #logger.warning("date_create supplied for save, but overwritting of date_create not allowed, the date will not be changed")
|
238
|
|
-
|
239
|
|
- values['date_update'] = datetime.datetime.utcnow()
|
240
|
|
-
|
241
|
|
- self._save_db(values)
|
242
|
|
-
|
243
|
|
- ## Do the query in the datbase for EmComponent::save()
|
244
|
|
- # @param values dict: A dictionnary of the values to insert
|
245
|
|
- # @throw RunTimeError if it was unable to do the Db update
|
246
|
|
- def _save_db(self, values):
|
247
|
|
- """ Do the query on the db """
|
248
|
|
- dbe = self.db_engine
|
249
|
|
- component = sql.Table(self.table, sqlutils.meta(dbe))
|
250
|
|
- req = sql.update(component, values=values).where(component.c.uid == self.uid)
|
251
|
|
-
|
252
|
|
- conn = dbe.connect()
|
253
|
|
- res = conn.execute(req)
|
254
|
|
- conn.close()
|
255
|
|
- if not res:
|
256
|
|
- raise RuntimeError("Unable to save the component in the database")
|
257
|
|
-
|
258
|
|
- ## Delete this component data in the database
|
|
162
|
+ ## Delete this component
|
259
|
163
|
# @return bool : True if deleted False if deletion aborded
|
260
|
164
|
# @throw RunTimeError if it was unable to do the deletion
|
261
|
165
|
def delete(self):
|
262
|
|
- #<SQL>
|
263
|
|
- dbe = self.db_engine
|
264
|
|
- component = sql.Table(self.table, sqlutils.meta(dbe))
|
265
|
|
- req = component.delete().where(component.c.uid == self.uid)
|
266
|
|
- conn = dbe.connect()
|
267
|
|
- res = conn.execute(req)
|
268
|
|
- conn.close()
|
269
|
|
- if not res:
|
270
|
|
- raise RuntimeError("Unable to delete the component in the database")
|
271
|
|
-
|
272
|
|
- #</SQL>
|
273
|
|
- super(EmComponent, self).__setattr__('deleted', True)
|
274
|
|
- return True
|
|
166
|
+ pass
|
275
|
167
|
|
276
|
168
|
## @brief Get the maximum rank given an EmComponent child class and a ranked_in filter
|
277
|
169
|
# @param ranked_in_value mixed: The rank "family"
|
278
|
170
|
# @return -1 if no EmComponent found else return an integer >= 0
|
279
|
171
|
@classmethod
|
280
|
|
- def _get_max_rank(cls, ranked_in_value, dbe):
|
281
|
|
- component = sql.Table(cls.table, sqlutils.meta(dbe))
|
282
|
|
- req = sql.sql.select([component.c.rank]).where(getattr(component.c, cls.ranked_in) == ranked_in_value).order_by(component.c.rank.desc())
|
283
|
|
- c = dbe.connect()
|
284
|
|
- res = c.execute(req)
|
285
|
|
- res = res.fetchone()
|
286
|
|
- c.close()
|
287
|
|
- if res != None:
|
288
|
|
- return res['rank']
|
289
|
|
- else:
|
290
|
|
- return -1
|
|
172
|
+ def _get_max_rank(cls, ranked_in_value):
|
|
173
|
+ pass
|
291
|
174
|
|
292
|
175
|
## Only make a call to the class method
|
293
|
176
|
# @return A positive integer or -1 if no components
|
294
|
177
|
# @see EmComponent::_get_max_rank()
|
295
|
178
|
def get_max_rank(self, ranked_in_value):
|
296
|
|
- return self.__class__._get_max_rank(ranked_in_value, self.db_engine)
|
|
179
|
+ return self.__class__._get_max_rank(ranked_in_value)
|
297
|
180
|
|
298
|
181
|
## Set a new rank for this component
|
299
|
182
|
# @note This function assume that ranks are properly set from 1 to x with no gap
|
|
@@ -334,12 +217,12 @@ class EmComponent(object):
|
334
|
217
|
req = table.update().where(table.c.uid == sql.bindparam('b_uid')).values(rank=sql.bindparam('b_rank'))
|
335
|
218
|
res = conn.execute(req, updated_ranks)
|
336
|
219
|
conn.close()
|
337
|
|
-
|
|
220
|
+
|
338
|
221
|
if res:
|
339
|
222
|
#Instance rank update
|
340
|
223
|
self._fields['rank'].value = new_rank
|
341
|
224
|
return bool(res)
|
342
|
|
-
|
|
225
|
+
|
343
|
226
|
## @brief Modify a rank given a sign and a new_rank
|
344
|
227
|
# - If sign is '=' set the rank to new_rank
|
345
|
228
|
# - If sign is '-' set the rank to cur_rank - new_rank
|