No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

components.py 10.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. # -*- coding: utf-8 -*-
  2. """ Main object to manipulate Editorial Model
  3. parent of all other EM editing classes
  4. @see EmClass, EmType, EmFieldGroup, EmField
  5. """
  6. import datetime
  7. from Lodel.utils.mlstring import MlString
  8. import logging
  9. import sqlalchemy as sql
  10. from Database import sqlutils
  11. logger = logging.getLogger('Lodel2.EditorialModel')
  12. class EmComponent(object):
  13. dbconf = 'default' #the name of the engine configuration
  14. table = None
  15. ranked_in = None
  16. """ instaciate an EmComponent
  17. @param id_or_name int|str: name or id of the object
  18. @exception TypeError
  19. """
  20. def __init__(self, id_or_name):
  21. if type(self) is EmComponent:
  22. raise EnvironmentError('Abstract class')
  23. if isinstance(id_or_name, int):
  24. self.id = id_or_name
  25. self.name = None
  26. elif isinstance(id_or_name, str):
  27. self.id = None
  28. self.name = id_or_name
  29. self.populate()
  30. else:
  31. raise TypeError('Bad argument: expecting <int> or <str> but got : '+str(type(id_or_name)))
  32. """ Lookup in the database properties of the object to populate the properties
  33. """
  34. def populate(self):
  35. records = self._populateDb() #Db query
  36. for record in records:
  37. row = type('row', (object,), {})()
  38. for k in record.keys():
  39. setattr(row, k, record[k])
  40. self.id = int(row.uid)
  41. self.name = row.name
  42. self.rank = 0 if row.rank is None else int(row.rank)
  43. self.date_update = row.date_update
  44. self.date_create = row.date_create
  45. self.string = MlString.load(row.string)
  46. self.help = MlString.load(row.help)
  47. return row
  48. @classmethod
  49. def getDbE(c):
  50. """ Shortcut that return the sqlAlchemy engine """
  51. return sqlutils.getEngine(c.dbconf)
  52. def _populateDb(self):
  53. """ Do the query on the db """
  54. dbe = self.__class__.getDbE()
  55. component = sql.Table(self.table, sqlutils.meta(dbe))
  56. req = sql.sql.select([component])
  57. if self.id == None:
  58. req = req.where(component.c.name == self.name)
  59. else:
  60. req = req.where(component.c.uid == self.id)
  61. c = dbe.connect()
  62. res = c.execute(req)
  63. c.close()
  64. res = res.fetchall()
  65. if not res or len(res) == 0:
  66. raise EmComponentNotExistError("No component found with "+('name '+self.name if self.id == None else 'id '+self.id ))
  67. return res
  68. ## Insert a new component in the database
  69. # This function create and assign a new UID and handle the date_create value
  70. # @param values The values of the new component
  71. # @return An instance of the created component
  72. #
  73. # @todo Check that the query didn't failed
  74. @classmethod
  75. def create(c, values):
  76. values['uid'] = c.newUid()
  77. values['date_update'] = values['date_create'] = datetime.datetime.utcnow()
  78. dbe = c.getDbE()
  79. conn = dbe.connect()
  80. table = sql.Table(c.table, sqlutils.meta(dbe))
  81. req = table.insert(values)
  82. res = conn.execute(req) #Check res?
  83. conn.close()
  84. return c(values['name']) #Maybe no need to check res because this would fail if the query failed
  85. """ write the representation of the component in the database
  86. @return bool
  87. """
  88. def save(self, values):
  89. values['name'] = self.name
  90. values['rank'] = self.rank
  91. values['date_update'] = datetime.datetime.utcnow()
  92. values['string'] = str(self.string)
  93. values['help']= str(self.help)
  94. #Don't allow creation date overwritting
  95. if 'date_create' in values:
  96. del values['date_create']
  97. logger.warning("date_create supplied for save, but overwritting of date_create not allowed, the date will not be changed")
  98. self._saveDb(values)
  99. def _saveDb(self, values):
  100. """ Do the query on the db """
  101. dbe = self.__class__.getDbE()
  102. component = sql.Table(self.table, sqlutils.meta(dbe))
  103. req = sql.update(component, values = values).where(component.c.uid == self.id)
  104. c = dbe.connect()
  105. res = c.execute(req)
  106. c.close()
  107. if not res:
  108. raise RuntimeError("Unable to save the component in the database")
  109. """ delete this component data in the database
  110. @return bool
  111. """
  112. def delete(self):
  113. #<SQL>
  114. dbe = self.__class__.getDbE()
  115. component = sql.Table(self.table, sqlutils.meta(dbe))
  116. req= component.delete().where(component.c.uid == self.id)
  117. c = dbe.connect()
  118. res = c.execute(req)
  119. c.close
  120. if not res:
  121. raise RuntimeError("Unable to delete the component in the database")
  122. #</SQL>
  123. pass
  124. ## modify_rank
  125. #
  126. # Permet de changer le rank d'un component, soit en lui donnant un rank précis, soit en augmentant ou reduisant sont rank actuelle d'une valleur donné.
  127. #
  128. # @param new_rank int: le rank ou modificateur de rank
  129. # @param sign str: Un charactère qui peut être : '=' pour afecter un rank, '+' pour ajouter le modificateur de rank ou '-' pour soustraire le modificateur de rank.
  130. #
  131. # @return bool: True en cas de réussite False en cas d'echec.
  132. def modify_rank(self, new_rank, sign):
  133. if(type(new_rank) is int):
  134. if(new_rank >= 0):
  135. dbe = self.__class__.getDbE()
  136. component = sql.Table(self.table, sqlutils.meta(dbe))
  137. req = sql.sql.select([component.c.uid, component.c.rank])
  138. if(sign == '='):
  139. req = req.where(getattr(component.c, self.ranked_in) == self.ranked_in and (component.c.rank == new_rank - 1))
  140. c = dbe.connect()
  141. res = c.execute(req)
  142. res = res.fetchone()
  143. if(res):
  144. if(new_rank < self.rank):
  145. req = req.where(getattr(component.c, self.ranked_in) == self.ranked_in and (component.c.rank >= new_rank))
  146. else:
  147. req = req.where(getattr(component.c, self.ranked_in) == self.ranked_in and (component.c.rank <= new_rank ))
  148. c = dbe.connect()
  149. res = c.execute(req)
  150. res = res.fetchall()
  151. vals = list()
  152. vals.append({'id' : self.id, 'rank' : new_rank})
  153. if(new_rank < self.rank):
  154. for row in res:
  155. vals.append({'id' : row.uid, 'rank' : row.rank+1})
  156. else:
  157. for row in res:
  158. vals.append({'id' : row.uid, 'rank' : row.rank-1})
  159. req = component.update().where(component.c.uid == sql.bindparam('id')).values(rank = sql.bindparam('rank'))
  160. c.execute(req, vals)
  161. c.close()
  162. self.rank = new_rank
  163. else:
  164. logger.error("Bad argument")
  165. raise ValueError('new_rank to big, new_rank - 1 doesn\'t exist. new_rank = '+str((new_rank)))
  166. elif(sign == '+'):
  167. req = req.where(getattr(component.c, self.ranked_in) == self.ranked_in and (component.c.rank <= self.rank + new_rank and component.c.rank > self.rank))
  168. c = dbe.connect()
  169. res = c.execute(req)
  170. res = res.fetchall()
  171. vals = list()
  172. vals.append({'id' : self.id, 'rank' : self.rank + new_rank})
  173. for row in res:
  174. vals.append({'id' : row.uid, 'rank' : row.rank - 1})
  175. req = component.update().where(component.c.uid == sql.bindparam('id')).values(rank = sql.bindparam('rank'))
  176. c.execute(req, vals)
  177. c.close()
  178. self.rank += new_rank
  179. elif(sign == '-'):
  180. req = req.where(getattr(component.c, self.ranked_in) == self.ranked_in and (component.c.rank >= self.rank - new_rank and component.c.rank < self.rank))
  181. c = dbe.connect()
  182. res = c.execute(req)
  183. res = res.fetchall()
  184. vals = list()
  185. vals.append({'id' : self.id, 'rank' : self.rank - new_rank})
  186. for row in res:
  187. vals.append({'id' : row.uid, 'rank' : row.rank + 1})
  188. req = component.update().where(component.c.uid == sql.bindparam('id')).values(rank = sql.bindparam('rank'))
  189. c.execute(req, vals)
  190. c.close()
  191. self.rank -= new_rank
  192. else:
  193. logger.error("Bad argument")
  194. raise TypeError('Excepted a string (\'=\' or \'+\' or \'-\') not a '+str(type(new_rank)))
  195. else:
  196. logger.error("Bad argument")
  197. raise ValueError('Excepted a positive int not a negative. new_rank = '+str((new_rank)))
  198. else:
  199. logger.error("Bad argument")
  200. raise TypeError('Excepted a int not a '+str(type(new_rank)))
  201. def __repr__(self):
  202. if self.name is None:
  203. return "<%s #%s, 'non populated'>" % (type(self).__name__, self.id)
  204. else:
  205. return "<%s #%s, '%s'>" % (type(self).__name__, self.id, self.name)
  206. @classmethod
  207. def newUid(c):
  208. """ This function register a new component in uids table
  209. @return The new uid
  210. """
  211. dbe = c.getDbE()
  212. uidtable = sql.Table('uids', sqlutils.meta(dbe))
  213. conn = dbe.connect()
  214. req = uidtable.insert(values={'table':c.table})
  215. res = conn.execute(req)
  216. uid = res.inserted_primary_key[0]
  217. logger.debug("Registering a new UID '"+str(uid)+"' for '"+c.table+"' component")
  218. conn.close()
  219. return uid
  220. class EmComponentNotExistError(Exception):
  221. pass