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 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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 or component.c.rank >= new_rank - 1))
  140. c = dbe.connect()
  141. res = c.execute(req)
  142. res = res.fetchall()
  143. vals = list()
  144. vals.append({'id' : self.id, 'rank' : new_rank})
  145. for row in res:
  146. vals.append({'id' : row.uid, 'rank' : row.rank+1})
  147. req = component.update().where(component.c.uid == sql.bindparam('id')).values(rank = sql.bindparam('rank'))
  148. c.execute(req, vals)
  149. c.close()
  150. self.rank = new_rank
  151. elif(sign == '+'):
  152. 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))
  153. c = dbe.connect()
  154. res = c.execute(req)
  155. res = res.fetchall()
  156. vals = list()
  157. vals.append({'id' : self.id, 'rank' : self.rank + new_rank})
  158. for row in res:
  159. vals.append({'id' : row.uid, 'rank' : row.rank - 1})
  160. req = component.update().where(component.c.uid == sql.bindparam('id')).values(rank = sql.bindparam('rank'))
  161. c.execute(req, vals)
  162. c.close()
  163. self.rank += new_rank
  164. elif(sign == '-'):
  165. 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))
  166. c = dbe.connect()
  167. res = c.execute(req)
  168. res = res.fetchall()
  169. vals = list()
  170. vals.append({'id' : self.id, 'rank' : self.rank - new_rank})
  171. for row in res:
  172. vals.append({'id' : row.uid, 'rank' : row.rank + 1})
  173. req = component.update().where(component.c.uid == sql.bindparam('id')).values(rank = sql.bindparam('rank'))
  174. c.execute(req, vals)
  175. c.close()
  176. self.rank -= new_rank
  177. else:
  178. logger.error("Bad argument")
  179. raise TypeError('Excepted a string (\'=\' or \'+\' or \'-\') not a '+str(type(new_rank)))
  180. else:
  181. logger.error("Bad argument")
  182. raise ValueError('Excepted a positive int not a negative. new_rank = '+str((new_rank)))
  183. else:
  184. logger.error("Bad argument")
  185. raise TypeError('Excepted a int not a '+str(type(new_rank)))
  186. def __repr__(self):
  187. if self.name is None:
  188. return "<%s #%s, 'non populated'>" % (type(self).__name__, self.id)
  189. else:
  190. return "<%s #%s, '%s'>" % (type(self).__name__, self.id, self.name)
  191. @classmethod
  192. def newUid(c):
  193. """ This function register a new component in uids table
  194. @return The new uid
  195. """
  196. dbe = c.getDbE()
  197. uidtable = sql.Table('uids', sqlutils.meta(dbe))
  198. conn = dbe.connect()
  199. req = uidtable.insert(values={'table':c.table})
  200. res = conn.execute(req)
  201. uid = res.inserted_primary_key[0]
  202. logger.debug("Registering a new UID '"+str(uid)+"' for '"+c.table+"' component")
  203. conn.close()
  204. return uid
  205. class EmComponentNotExistError(Exception):
  206. pass