data.py 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. # -*- coding: utf-8 -*-
  2. """
  3. """
  4. import os
  5. import re
  6. from datetime import datetime
  7. from hashlib import sha256
  8. __all__ = ['User', 'Group', 'Permission']
  9. from sqlalchemy import Table, ForeignKey, Column, Sequence
  10. from sqlalchemy.types import Unicode, Integer, DateTime, Text
  11. from sqlalchemy.orm import relation, synonym
  12. import tg
  13. from pboard.model import DeclarativeBase, metadata, DBSession
  14. # This is the association table for the many-to-many relationship between
  15. # groups and permissions.
  16. pb_node_table = Table('pb_nodes', metadata,
  17. Column('node_id', Integer, Sequence('pb_nodes__node_id__sequence'), primary_key=True),
  18. Column('parent_id', Integer, ForeignKey('pb_nodes.node_id'), nullable=True, default=None),
  19. Column('node_order', Integer, nullable=True, default=1),
  20. Column('node_type', Unicode(16), unique=False, nullable=False, default=u'data'),
  21. Column('node_status', Unicode(16), unique=False, nullable=False, default=u'new'),
  22. Column('created_at', DateTime, unique=False, nullable=False),
  23. Column('updated_at', DateTime, unique=False, nullable=False),
  24. Column('data_label', Unicode(1024), unique=False, nullable=False, default=u''),
  25. Column('data_content', Text(), unique=False, nullable=False, default=u''),
  26. Column('data_datetime', DateTime, unique=False, nullable=False),
  27. Column('data_reminder_datetime', DateTime, unique=False, nullable=True),
  28. )
  29. """
  30. - node_type
  31. - node_created_at
  32. - node_updated_at
  33. - data_label
  34. - data_content
  35. - data_source_url
  36. - data_status_id
  37. """
  38. class PBNodeStatusItem(object):
  39. def __init__(self, psStatusId, psStatusLabel, psStatusFamily, psIconId, psCssClass): #, psBackgroundColor):
  40. self._sStatusId = psStatusId
  41. self._sStatusLabel = psStatusLabel
  42. self._sStatusFamily = psStatusFamily
  43. self._sIconId = psIconId
  44. self._sCssClass = psCssClass
  45. # self._sBackgroundColor = psBackgroundColor
  46. def getLabel(self):
  47. return self._sStatusLabel
  48. @property
  49. def status_family(self):
  50. return self._sStatusFamily
  51. @property
  52. def icon(self):
  53. return self._sIconId
  54. def getId(self):
  55. return self._sStatusId
  56. @property
  57. def css(self):
  58. return self._sCssClass
  59. @property
  60. def status_id(self):
  61. return self._sStatusId
  62. @property
  63. def icon_id(self):
  64. return self._sIconId
  65. @property
  66. def label(self):
  67. return self._sStatusLabel
  68. class PBNodeStatus(object):
  69. StatusList = dict()
  70. StatusList['immortal'] = PBNodeStatusItem('immortal', 'Information', 'normal', 'icon-g-circle-info', 'pod-status-grey-light')
  71. StatusList['new'] = PBNodeStatusItem('new', 'New', 'open', 'icon-g-lightbulb icon-g-white', 'btn-success')
  72. StatusList['inprogress'] = PBNodeStatusItem('inprogress', 'In progress', 'open', ' icon-g-roundabout icon-g-white', 'btn-info')
  73. StatusList['actiontodo'] = PBNodeStatusItem('actiontodo', 'Waiting for action', 'open', 'icon-g-clock icon-g-white', 'btn-info')
  74. StatusList['standby'] = PBNodeStatusItem('standby', 'Waiting for answer', 'open', 'icon-g-clock icon-g-white', 'btn-warning')
  75. StatusList['hot'] = PBNodeStatusItem('hot', 'Hot', 'open', 'icon-g-warning-sign icon-g-white', 'btn-danger')
  76. StatusList['done'] = PBNodeStatusItem('done', 'Done', 'closed', 'icon-g-ok-2', 'pod-status-grey-light')
  77. StatusList['closed'] = PBNodeStatusItem('closed', 'Closed', 'closed', 'icon-g-lightbulb', 'pod-status-grey-middle')
  78. StatusList['archived'] = PBNodeStatusItem('archived', 'Archived', 'invisible', 'icon-g-wallet', 'pod-status-grey-dark')
  79. StatusList['deleted'] = PBNodeStatusItem('deleted', 'Deleted', 'invisible', 'icon-g-bin', 'pod-status-grey-dark')
  80. @classmethod
  81. def getList(cls):
  82. return [
  83. PBNodeStatus.StatusList['immortal'],
  84. PBNodeStatus.StatusList['new'],
  85. PBNodeStatus.StatusList['actiontodo'],
  86. PBNodeStatus.StatusList['inprogress'],
  87. PBNodeStatus.StatusList['standby'],
  88. PBNodeStatus.StatusList['hot'],
  89. PBNodeStatus.StatusList['done'],
  90. PBNodeStatus.StatusList['closed'],
  91. PBNodeStatus.StatusList['archived'],
  92. PBNodeStatus.StatusList['deleted']
  93. ]
  94. PBNodeStatus.StatusList.values()
  95. @classmethod
  96. def getStatusItem(cls, psStatusId):
  97. return PBNodeStatus.StatusList[psStatusId]
  98. class PBNodeType(object):
  99. Node = 'node'
  100. Folder = 'folder'
  101. Data = 'data'
  102. File = 'file'
  103. Event = 'event'
  104. Contact = 'contact'
  105. Comment = 'comment'
  106. class PBNode(object):
  107. def getChildrenOfType(self, plNodeTypeList, plSortingCriteria):
  108. """return all children nodes of type 'data' or 'node' or 'folder'"""
  109. return DBSession.query(PBNode).filter(PBNode.parent_id==self.node_id).filter(PBNode.node_type.in_(plNodeTypeList)).order_by(plSortingCriteria).all()
  110. def getChildNb(self):
  111. liChildNb = DBSession.query(PBNode).filter(PBNode.parent_id==self.node_id).filter(PBNode.node_type==PBNodeType.Data).count()
  112. return liChildNb
  113. def getChildren(self):
  114. """return all children nodes of type 'data' or 'node' or 'folder'"""
  115. return self.getChildrenOfType([PBNodeType.Node, PBNodeType.Folder, PBNodeType.Data], PBNode.node_order.asc())
  116. def getContacts(self):
  117. """return all children nodes of type 'data' or 'node' or 'folder'"""
  118. return self.getChildrenOfType([PBNodeType.Contact], PBNode.data_label.asc())
  119. def getEvents(self):
  120. return DBSession.query(PBNode).filter(PBNode.parent_id==self.node_id).filter(PBNode.node_type==PBNodeType.Event).order_by(PBNode.data_datetime.desc()).all()
  121. return []
  122. def getIconClass(self):
  123. laIconClass = dict()
  124. laIconClass['node'] = 'icon-g-folder-open'
  125. laIconClass['folder'] = 'icon-g-folder-open'
  126. laIconClass['data'] = 'icon-g-file'
  127. laIconClass['file'] = 'icon-file'
  128. laIconClass['event'] = 'icon-time' # icon-calendar
  129. laIconClass['contact'] = 'icon-user'
  130. laIconClass['comment'] = 'icon-comment'
  131. if self.node_type==PBNodeType.Data and self.getChildNb()>0:
  132. return laIconClass['folder']
  133. else:
  134. return laIconClass[self.node_type]
  135. def getFormattedDateTime(self, poDateTime, psDateTimeFormat = '%d/%m/%Y @ %H:%M'):
  136. return poDateTime.strftime(psDateTimeFormat)
  137. def getFormattedDate(self, poDateTime, psDateTimeFormat = '%d/%m/%Y'):
  138. return poDateTime.strftime(psDateTimeFormat)
  139. def getFormattedTime(self, poDateTime, psDateTimeFormat = '%H:%M'):
  140. return poDateTime.strftime(psDateTimeFormat)
  141. def getStatus(self):
  142. return PBNodeStatus.getStatusItem(self.node_status)
  143. def getTruncatedLabel(self, piCharNb):
  144. lsTruncatedLabel = u''
  145. liMaxLength = int(piCharNb)
  146. if len(self.data_label)>liMaxLength:
  147. lsTruncatedLabel = self.data_label[0:liMaxLength-1]+u'…'
  148. else:
  149. lsTruncatedLabel = self.data_label
  150. return lsTruncatedLabel
  151. def getTagList(self):
  152. loPattern = re.compile('(^|\s|@)@(\w+)')
  153. loResults = re.findall(loPattern, self.data_content)
  154. lsResultList = []
  155. for loResult in loResults:
  156. lsResultList.append(loResult[1].replace('@', '').replace('_', ' '))
  157. return lsResultList
  158. @classmethod
  159. def addTagReplacement(cls, matchobj):
  160. return " <span class='badge'>%s</span> " %(matchobj.group(0).replace('@', '').replace('_', ' '))
  161. @classmethod
  162. def addDocLinkReplacement(cls, matchobj):
  163. return " <a href='%s'>%s</a> " %(tg.url('/dashboard?node=%s')%(matchobj.group(1)), matchobj.group(0))
  164. def getContentWithTags(self):
  165. lsTemporaryResult = re.sub('(^|\s)@@(\w+)', '', self.data_content) # tags with @@ are explicitly removed from the body
  166. lsTemporaryResult = re.sub('#([0-9]*)', PBNode.addDocLinkReplacement, lsTemporaryResult) # tags with @@ are explicitly removed from the body
  167. return re.sub('(^|\s)@(\w+)', PBNode.addTagReplacement, lsTemporaryResult) # then, 'normal tags are transformed as labels'
  168. # FIXME - D.A. - 2013-09-12
  169. # Does not match @@ at end of content.
  170. from sqlalchemy.orm import mapper
  171. mapper(PBNode, pb_node_table)