serializers.py 43KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102
  1. # TODO - G.M - 28-03-2018 - [Models] Check if this file is needed for Tracimv2,
  2. # if yes, adapt it.
  3. # # -*- coding: utf-8 -*-
  4. # import cherrypy
  5. #
  6. # import types
  7. #
  8. # from babel.dates import format_timedelta
  9. # from babel.dates import format_datetime
  10. #
  11. # from datetime import datetime
  12. # import tg
  13. # from tracim.translation import fake_translator as _
  14. # from tg.util import LazyString
  15. #
  16. # from depot.manager import DepotManager
  17. #
  18. # from tracim.logger import logger
  19. # from tracim.lib.user import CurrentUserGetterApifrom tracim.model.auth import Profile
  20. # from tracim.model.auth import User
  21. # from tracim.model.data import BreadcrumbItem, ActionDescription
  22. # from tracim.model.data import ContentStatus
  23. # from tracim.model.data import ContentRevisionRO
  24. # from tracim.model.data import LinkItem
  25. # from tracim.model.data import NodeTreeItem
  26. # from tracim.model.data import Content
  27. # from tracim.model.data import ContentType
  28. # from tracim.model.data import RoleType
  29. # from tracim.model.data import UserRoleInWorkspace
  30. # from tracim.model.data import VirtualEvent
  31. # from tracim.model.data import Workspace
  32. #
  33. # from tracim.model import data as pmd
  34. # from tracim.lib import CST
  35. #
  36. # #############################################################"
  37. # ##
  38. # ## HERE COMES THE SERIALIZATION CLASSES
  39. # ##
  40. # ## The following code allow to define with high level
  41. # ## of granularity the way models are serialized
  42. # ##
  43. #
  44. # class pod_serializer(object):
  45. # """
  46. # This decorator allow to define a function being a converter of a Model in a Context
  47. #
  48. # """
  49. # def __init__(self, model_class, context):
  50. # """
  51. # :param model_class: the model class to serialize. Should be a class defined in tracim.model.auth or tracim.model.data
  52. # :param context: the Context string which should defined in CTX class
  53. # :return:
  54. # """
  55. # assert hasattr(CTX, context)
  56. # self.context = context
  57. # self.model_class = model_class
  58. #
  59. # def __call__(self, func):
  60. # Context.register_converter(self.context, self.model_class, func)
  61. # return func
  62. #
  63. # class ContextConverterNotFoundException(Exception):
  64. # def __init__(self, context_string, model_class):
  65. # message = 'converter not found (context: {0} - model: {1})'.format(context_string, model_class.__name__)
  66. # Exception.__init__(self, message)
  67. #
  68. # class CTX(object):
  69. # """ constants that are used for serialization / dictification of models"""
  70. # ADMIN_USER = 'ADMIN_USER'
  71. # ADMIN_WORKSPACE = 'ADMIN_WORKSPACE'
  72. # ADMIN_WORKSPACES = 'ADMIN_WORKSPACES'
  73. # CONTENT_LIST = 'CONTENT_LIST'
  74. # CONTENT_HISTORY = 'CONTENT_HISTORY'
  75. # CURRENT_USER = 'CURRENT_USER'
  76. # DEFAULT = 'DEFAULT' # default context. This will allow to define a serialization method to be used by default
  77. # EMAIL_NOTIFICATION = 'EMAIL_NOTIFICATION'
  78. # FILE = 'FILE'
  79. # FILES = 'FILES'
  80. # FOLDER = 'FOLDER'
  81. # FOLDER_CONTENT_LIST = 'FOLDER_CONTENT_LIST'
  82. # FOLDERS = 'FOLDERS'
  83. # MENU_API = 'MENU_API'
  84. # MENU_API_BUILD_FROM_TREE_ITEM = 'MENU_API_BUILD_FROM_TREE_ITEM'
  85. # PAGE = 'PAGE'
  86. # PAGES = 'PAGES'
  87. # SEARCH = 'SEARCH'
  88. # THREAD = 'THREAD'
  89. # THREADS = 'THREADS'
  90. # USER = 'USER'
  91. # USERS = 'USERS'
  92. # WORKSPACE = 'WORKSPACE'
  93. # API_WORKSPACE = 'API_WORKSPACE'
  94. # API_CALENDAR_WORKSPACE = 'API_CALENDAR_WORKSPACE'
  95. # API_CALENDAR_USER = 'API_CALENDAR_USER'
  96. #
  97. #
  98. # class DictLikeClass(dict):
  99. # """
  100. # This class allow to use dictionnary with property like access to values.
  101. # eg.: user = { 'login': 'damien', 'password': 'bob'}
  102. # will be accessible in the templates like following:
  103. # ${user.login}
  104. # ${user.password}
  105. # """
  106. # __getattr__ = dict.__getitem__
  107. # __setattr__ = dict.__setitem__
  108. #
  109. #
  110. # class Context(object):
  111. # """
  112. # Convert a series of mapped objects into ClassLikeDict (a dictionnary which can be accessed through properties)
  113. # example: obj = ClassLikeDict({'foo': 'bar'}) allow to call obj.foo
  114. # """
  115. #
  116. # _converters = dict()
  117. #
  118. # @classmethod
  119. # def register_converter(cls, context_string, model_class, convert_function):
  120. # """
  121. #
  122. # :param context_string:
  123. # :param model_class:
  124. # :param convert_function:
  125. # :return:
  126. # """
  127. # if context_string not in Context._converters:
  128. # Context._converters[context_string] = dict()
  129. #
  130. # if model_class not in Context._converters[context_string]:
  131. # logger.info(Context, 'Registering Serialization feature: [ {2} | {1} | {0} ]'.format(
  132. # convert_function.__name__,
  133. # model_class.__name__,
  134. # context_string))
  135. #
  136. # Context._converters[context_string][model_class] = convert_function
  137. #
  138. # @classmethod
  139. # def get_converter(cls, context_string, model_class):
  140. # """
  141. # :param context_string:
  142. # :param model_class:
  143. # :return:
  144. # """
  145. # try:
  146. # converter = Context._converters[context_string][model_class]
  147. # return converter
  148. # except KeyError:
  149. # if CTX.DEFAULT in Context._converters:
  150. # if model_class in Context._converters[CTX.DEFAULT]:
  151. # return Context._converters[CTX.DEFAULT][model_class]
  152. #
  153. # raise ContextConverterNotFoundException(context_string, model_class)
  154. #
  155. # def __init__(self, context_string, base_url='', current_user=None):
  156. # """
  157. # """
  158. # self.context_string = context_string
  159. # self._current_user = current_user # Allow to define the current user if any
  160. # if not current_user:
  161. # self._current_user = CurrentUserGetterApi.get_current_user()
  162. #
  163. # self._base_url = base_url # real root url like http://mydomain.com:8080
  164. #
  165. # def url(self, base_url='/', params=None, qualified=False) -> str:
  166. # # HACK (REF WSGIDAV.CONTEXT.TG.URL) This is a temporary hack who
  167. # # permit to know we are in WSGIDAV context.
  168. # if not hasattr(cherrypy.request, 'current_user_email'):
  169. # url = tg.url(base_url, params)
  170. # else:
  171. # url = base_url
  172. #
  173. # if self._base_url:
  174. # url = '{}{}'.format(self._base_url, url)
  175. # return url
  176. #
  177. # def get_user(self):
  178. # return self._current_user
  179. #
  180. # def toDict(self, serializableObject, key_value_for_a_list_object='', key_value_for_list_item_nb=''):
  181. # """
  182. # Converts a given object into a recursive dictionnary like structure.
  183. # :param serializableObject: the structure to be serialized. this may be any type of object, or list
  184. # :param key_value_for_a_list_object: if set, then the result will e a dictionnary with the given key.
  185. # :param key_value_for_list_item_nb: in case of serializableObject being a list, then this key allow to add item number as property
  186. # :return:
  187. # """
  188. # result = DictLikeClass()
  189. #
  190. # if serializableObject==None:
  191. # return None
  192. #
  193. # if isinstance(serializableObject, (int, str, LazyString)):
  194. # return serializableObject
  195. #
  196. # if isinstance(serializableObject, (list, tuple, types.GeneratorType)) and not isinstance(serializableObject, str):
  197. # # Case of lists
  198. # list_of_objects = list()
  199. # for item in serializableObject:
  200. # list_of_objects.append(self.toDict(item))
  201. #
  202. # if not key_value_for_a_list_object:
  203. # return list_of_objects
  204. # else:
  205. # result[key_value_for_a_list_object] = list_of_objects
  206. #
  207. # if key_value_for_list_item_nb:
  208. # result[key_value_for_list_item_nb] = len(serializableObject)
  209. # return result
  210. #
  211. # if isinstance(serializableObject, dict):
  212. # # Case of dictionnaries
  213. # for key, value in serializableObject.items():
  214. # result[key] = self.toDict(value)
  215. #
  216. # return result
  217. #
  218. # # Default case now
  219. # if key_value_for_a_list_object:
  220. # serialized_object = self.toDictSpecific(serializableObject)
  221. # result[key_value_for_a_list_object] = serialized_object
  222. # else:
  223. # result = self.toDictSpecific(serializableObject)
  224. #
  225. # return result
  226. #
  227. #
  228. # def toDictSpecific(self, serializableObject):
  229. # """
  230. # Convert to a dictonnary the specific classes. This code will search for the right convert function which
  231. # must have been developped and registered.
  232. #
  233. # :param serializableObject: an object to be serialized
  234. # :return: a ClassLikeDict instance
  235. # """
  236. # converter_function = Context.get_converter(self.context_string, serializableObject.__class__)
  237. # result = converter_function(serializableObject, self) # process the object with the given serializer
  238. #
  239. # assert isinstance(result, DictLikeClass)
  240. # return result
  241. #
  242. #
  243. # ########################################################################################################################
  244. # ## ActionDescription
  245. #
  246. # @pod_serializer(ActionDescription, CTX.DEFAULT)
  247. # def serialize_breadcrumb_item(action: ActionDescription, context: Context):
  248. # return DictLikeClass(
  249. # id = action.id,
  250. # icon = action.icon,
  251. # label = action.label
  252. # )
  253. #
  254. # ########################################################################################################################
  255. # ## BREADCRUMB
  256. #
  257. # @pod_serializer(BreadcrumbItem, CTX.DEFAULT)
  258. # def serialize_breadcrumb_item(item: BreadcrumbItem, context: Context):
  259. # return DictLikeClass(
  260. # icon = item.icon,
  261. # label = item.label,
  262. # url = item.url,
  263. # is_active = item.is_active
  264. # )
  265. #
  266. # ########################################################################################################################
  267. # ## Content
  268. #
  269. # @pod_serializer(ContentRevisionRO, CTX.PAGE)
  270. # @pod_serializer(ContentRevisionRO, CTX.FILE)
  271. # def serialize_version_for_page_or_file(version: ContentRevisionRO, context: Context):
  272. # return DictLikeClass(
  273. # id = version.revision_id,
  274. # label = version.label,
  275. # owner = context.toDict(version.owner),
  276. # created = version.created,
  277. # action = context.toDict(version.get_last_action()),
  278. # )
  279. #
  280. #
  281. # @pod_serializer(Content, CTX.DEFAULT)
  282. # def serialize_breadcrumb_item(content: Content, context: Context):
  283. # return DictLikeClass(
  284. # id = content.content_id,
  285. # label = content.label,
  286. # folder = context.toDict(DictLikeClass(id = content.parent.content_id if content.parent else None)),
  287. # workspace = context.toDict(content.workspace)
  288. # )
  289. #
  290. # @pod_serializer(Content, CTX.EMAIL_NOTIFICATION)
  291. # def serialize_item(content: Content, context: Context):
  292. # if ContentType.Comment==content.type:
  293. # content = content.parent
  294. #
  295. # result = DictLikeClass(
  296. # id = content.content_id,
  297. # label = content.label,
  298. # icon = ContentType.get_icon(content.type),
  299. # status = context.toDict(content.get_status()),
  300. # folder = context.toDict(DictLikeClass(id = content.parent.content_id if content.parent else None)),
  301. # workspace = context.toDict(content.workspace),
  302. # is_deleted = content.is_deleted,
  303. # is_archived = content.is_archived,
  304. # url = context.url('/workspaces/{wid}/folders/{fid}/{ctype}/{cid}'.format(wid = content.workspace_id, fid=content.parent_id, ctype=content.type+'s', cid=content.content_id)),
  305. # last_action = context.toDict(content.get_last_action())
  306. # )
  307. #
  308. # return result
  309. #
  310. #
  311. # @pod_serializer(Content, CTX.MENU_API)
  312. # def serialize_content_for_menu_api(content: Content, context: Context):
  313. # content_id = content.content_id
  314. # workspace_id = content.workspace_id
  315. #
  316. # has_children = False
  317. # if content.type == ContentType.Folder:
  318. # has_children = content.get_child_nb(ContentType.Any) > 0
  319. #
  320. # result = DictLikeClass(
  321. # id = CST.TREEVIEW_MENU.ID_TEMPLATE__FULL.format(workspace_id, content_id),
  322. # children = has_children,
  323. # text = content.get_label(),
  324. # a_attr = { 'href' : context.url(ContentType.fill_url(content))},
  325. # li_attr = { 'title': content.get_label(), 'class': 'tracim-tree-item-is-a-folder' },
  326. # type = content.type,
  327. # state = { 'opened': True if ContentType.Folder!=content.type else False, 'selected': False }
  328. # )
  329. # return result
  330. #
  331. #
  332. # @pod_serializer(Content, CTX.FILES)
  333. # @pod_serializer(Content, CTX.PAGES)
  334. # def serialize_node_for_page_list(content: Content, context: Context):
  335. #
  336. # if content.type==ContentType.Page:
  337. # if not content.parent:
  338. # folder = None
  339. # else:
  340. # folder = Context(CTX.DEFAULT).toDict(content.parent)
  341. #
  342. # result = DictLikeClass(
  343. # id = content.content_id,
  344. # label = content.label,
  345. # status = context.toDict(content.get_status()),
  346. # folder = folder
  347. # )
  348. # return result
  349. #
  350. # if content.type==ContentType.File:
  351. # result = DictLikeClass(
  352. # id = content.content_id,
  353. # label = content.label,
  354. # status = context.toDict(content.get_status()),
  355. # folder = Context(CTX.DEFAULT).toDict(content.parent)
  356. # )
  357. # return result
  358. #
  359. #
  360. # # TODO - DA - 2014-10-16 - THE FOLLOWING CODE SHOULD BE REMOVED
  361. # #
  362. # # if content.type==ContentType.Folder:
  363. # # return DictLikeClass(
  364. # # id = content.content_id,
  365. # # label = content.label,
  366. # # )
  367. #
  368. # raise NotImplementedError('node type / context not implemented: {} {}'. format(content.type, context.context_string))
  369. #
  370. #
  371. # @pod_serializer(Content, CTX.PAGE)
  372. # @pod_serializer(Content, CTX.FILE)
  373. # def serialize_node_for_page(content: Content, context: Context):
  374. #
  375. # if content.type in (ContentType.Page, ContentType.File) :
  376. # data_container = content
  377. #
  378. # # The following properties are overriden by revision values
  379. # if content.revision_to_serialize>0:
  380. # for revision in content.revisions:
  381. # if revision.revision_id==content.revision_to_serialize:
  382. # data_container = revision
  383. # break
  384. #
  385. # result = DictLikeClass(
  386. # id=content.content_id,
  387. # parent=context.toDict(content.parent),
  388. # workspace=context.toDict(content.workspace),
  389. # type=content.type,
  390. # is_new=content.has_new_information_for(context.get_user()),
  391. # content=data_container.description,
  392. # created=data_container.created,
  393. # updated=content.last_revision.updated,
  394. # label=data_container.label,
  395. # icon=ContentType.get_icon(content.type),
  396. # owner=context.toDict(content.first_revision.owner),
  397. # last_modification_author=context.toDict(content.last_revision.owner),
  398. # status=context.toDict(data_container.get_status()),
  399. # links=[],
  400. # revision_nb = len(content.revisions),
  401. # selected_revision='latest' if content.revision_to_serialize<=0 else content.revision_to_serialize,
  402. # history=Context(CTX.CONTENT_HISTORY).toDict(content.get_history(drop_empty_revision=True)), # nopep8
  403. # is_editable=content.is_editable,
  404. # is_deleted=content.is_deleted,
  405. # is_archived=content.is_archived,
  406. # urls = context.toDict({
  407. # 'mark_read': context.url(Content.format_path('/workspaces/{wid}/folders/{fid}/{ctype}s/{cid}/put_read', content)),
  408. # 'mark_unread': context.url(Content.format_path('/workspaces/{wid}/folders/{fid}/{ctype}s/{cid}/put_unread', content))
  409. # })
  410. # )
  411. #
  412. # if content.type == ContentType.File:
  413. # depot = DepotManager.get()
  414. # depot_stored_file = depot.get(data_container.depot_file)
  415. # result.label = content.label
  416. # result['file'] = DictLikeClass(
  417. # name=data_container.file_name,
  418. # size=depot_stored_file.content_length,
  419. # mimetype=data_container.file_mimetype)
  420. # return result
  421. #
  422. # if content.type==ContentType.Folder:
  423. # value = DictLikeClass(
  424. # id=content.content_id,
  425. # label=content.label,
  426. # is_new=content.has_new_information_for(context.get_user()),
  427. # )
  428. # return value
  429. #
  430. # raise NotImplementedError
  431. #
  432. #
  433. # @pod_serializer(VirtualEvent, CTX.CONTENT_HISTORY)
  434. # def serialize_content_for_history(event: VirtualEvent, context: Context):
  435. # urls = DictLikeClass({'delete': None})
  436. # if ContentType.Comment == event.type.id:
  437. # urls = context.toDict({
  438. # 'delete': context.url('/workspaces/{wid}/folders/{fid}/{ctype}/{cid}/comments/{commentid}/put_delete'.format(
  439. # wid = event.ref_object.workspace_id,
  440. # fid=event.ref_object.parent.parent_id,
  441. # ctype=event.ref_object.parent.type+'s',
  442. # cid=event.ref_object.parent.content_id,
  443. # commentid=event.ref_object.content_id))
  444. # })
  445. #
  446. # return DictLikeClass(
  447. # owner=context.toDict(event.owner),
  448. # id=event.id,
  449. # label=event.label,
  450. # type=context.toDict(event.type),
  451. # created=event.created,
  452. # created_as_delta=event.created_as_delta(),
  453. # content=event.content,
  454. # is_new=event.ref_object.has_new_information_for(context.get_user()),
  455. # urls = urls
  456. # )
  457. #
  458. # @pod_serializer(Content, CTX.THREAD)
  459. # def serialize_node_for_thread(item: Content, context: Context):
  460. # if item.type==ContentType.Thread:
  461. # return DictLikeClass(
  462. # content = item.description,
  463. # created = item.created,
  464. # updated = item.last_revision.updated,
  465. # revision_nb = len(item.revisions),
  466. # icon = ContentType.get_icon(item.type),
  467. # id = item.content_id,
  468. # label = item.label,
  469. # links=[],
  470. # owner = context.toDict(item.owner),
  471. # last_modification_author=context.toDict(item.last_revision.owner),
  472. # parent = context.toDict(item.parent),
  473. # selected_revision = 'latest',
  474. # status = context.toDict(item.get_status()),
  475. # type = item.type,
  476. # workspace = context.toDict(item.workspace),
  477. # comments = reversed(context.toDict(item.get_comments())),
  478. # is_new=item.has_new_information_for(context.get_user()),
  479. # history = Context(CTX.CONTENT_HISTORY).toDict(item.get_history(drop_empty_revision=True)), # nopep8
  480. # is_editable=item.is_editable,
  481. # is_deleted=item.is_deleted,
  482. # is_archived=item.is_archived,
  483. # urls = context.toDict({
  484. # 'mark_read': context.url(Content.format_path('/workspaces/{wid}/folders/{fid}/{ctype}s/{cid}/put_read', item)),
  485. # 'mark_unread': context.url(Content.format_path('/workspaces/{wid}/folders/{fid}/{ctype}s/{cid}/put_unread', item))
  486. # }),
  487. # )
  488. #
  489. # if item.type==ContentType.Comment:
  490. # return DictLikeClass(
  491. # is_new=item.has_new_information_for(context.get_user()),
  492. # content = item.description,
  493. # created = item.created,
  494. # created_as_delta = item.created_as_delta(),
  495. # icon = ContentType.get_icon(item.type),
  496. # id = item.content_id,
  497. # label = item.label,
  498. # owner = context.toDict(item.owner),
  499. # # REMOVE parent = context.toDict(item.parent),
  500. # type = item.type,
  501. # urls = context.toDict({
  502. # 'delete': context.url('/workspaces/{wid}/folders/{fid}/{ctype}/{cid}/comments/{commentid}/put_delete'.format(wid = item.workspace_id, fid=item.parent.parent_id, ctype=item.parent.type+'s', cid=item.parent.content_id, commentid=item.content_id))
  503. # })
  504. # )
  505. #
  506. # if item.type==ContentType.Folder:
  507. # return Context(CTX.DEFAULT).toDict(item)
  508. #
  509. #
  510. #
  511. # @pod_serializer(Content, CTX.THREADS)
  512. # def serialize_node_for_thread_list(content: Content, context: Context):
  513. # if content.type==ContentType.Thread:
  514. # return DictLikeClass(
  515. # id = content.content_id,
  516. # url=ContentType.fill_url(content),
  517. # label=content.get_label(),
  518. # status=context.toDict(content.get_status()),
  519. # folder=context.toDict(content.parent),
  520. # workspace=context.toDict(content.workspace) if content.workspace else None,
  521. # comment_nb=len(content.get_comments())
  522. # )
  523. #
  524. # if content.type==ContentType.Folder:
  525. # return Context(CTX.DEFAULT).toDict(content)
  526. #
  527. # raise NotImplementedError
  528. #
  529. # @pod_serializer(Content, CTX.WORKSPACE)
  530. # @pod_serializer(Content, CTX.FOLDERS)
  531. # def serialize_content_for_workspace(content: Content, context: Context):
  532. # thread_nb_all = content.get_child_nb(ContentType.Thread)
  533. # thread_nb_open = content.get_child_nb(ContentType.Thread)
  534. # file_nb_all = content.get_child_nb(ContentType.File)
  535. # file_nb_open = content.get_child_nb(ContentType.File)
  536. # folder_nb_all = content.get_child_nb(ContentType.Folder)
  537. # folder_nb_open = content.get_child_nb(ContentType.Folder)
  538. # page_nb_all = content.get_child_nb(ContentType.Page)
  539. # page_nb_open = content.get_child_nb(ContentType.Page)
  540. #
  541. # content_nb_all = thread_nb_all +\
  542. # thread_nb_open +\
  543. # file_nb_all +\
  544. # file_nb_open +\
  545. # folder_nb_all +\
  546. # folder_nb_open +\
  547. # page_nb_all +\
  548. # page_nb_open
  549. #
  550. #
  551. # result = None
  552. # if content.type==ContentType.Folder:
  553. # result = DictLikeClass(
  554. # id = content.content_id,
  555. # label = content.label,
  556. # thread_nb = DictLikeClass(
  557. # all = thread_nb_all,
  558. # open = thread_nb_open,
  559. # ),
  560. # file_nb = DictLikeClass(
  561. # all = file_nb_all,
  562. # open = file_nb_open,
  563. # ),
  564. # folder_nb = DictLikeClass(
  565. # all = folder_nb_all,
  566. # open = folder_nb_open,
  567. # ),
  568. # page_nb = DictLikeClass(
  569. # all = page_nb_all,
  570. # open = page_nb_open,
  571. # ),
  572. # content_nb = DictLikeClass(all = content_nb_all),
  573. # is_editable=content.is_editable,
  574. # )
  575. #
  576. # return result
  577. #
  578. # @pod_serializer(Content, CTX.FOLDER)
  579. # def serialize_content_for_workspace_and_folder(content: Content, context: Context):
  580. # thread_nb_all = content.get_child_nb(ContentType.Thread)
  581. # thread_nb_open = content.get_child_nb(ContentType.Thread)
  582. # file_nb_all = content.get_child_nb(ContentType.File)
  583. # file_nb_open = content.get_child_nb(ContentType.File)
  584. # folder_nb_all = content.get_child_nb(ContentType.Folder)
  585. # folder_nb_open = content.get_child_nb(ContentType.Folder)
  586. # page_nb_all = content.get_child_nb(ContentType.Page)
  587. # page_nb_open = content.get_child_nb(ContentType.Page)
  588. #
  589. # content_nb_all = thread_nb_all +\
  590. # thread_nb_open +\
  591. # file_nb_all +\
  592. # file_nb_open +\
  593. # folder_nb_all +\
  594. # folder_nb_open +\
  595. # page_nb_all +\
  596. # page_nb_open
  597. #
  598. #
  599. # result = None
  600. # if content.type==ContentType.Folder:
  601. # allowed_content = DictLikeClass(content.properties['allowed_content']),
  602. #
  603. # result = DictLikeClass(
  604. # id=content.content_id,
  605. # label=content.label,
  606. # created=content.created,
  607. # updated=content.last_revision.updated,
  608. # last_modification_author=context.toDict(content.last_revision.owner),
  609. # revision_nb=len(content.revisions),
  610. # workspace=context.toDict(content.workspace),
  611. # allowed_content=DictLikeClass(content.properties['allowed_content']),
  612. # allowed_content_types=context.toDict(content.get_allowed_content_types()),
  613. # selected_revision='latest',
  614. # status=context.toDict(content.get_status()),
  615. # owner=context.toDict(content.owner),
  616. # thread_nb=DictLikeClass(all=thread_nb_all,
  617. # open=thread_nb_open),
  618. # file_nb=DictLikeClass(all=file_nb_all,
  619. # open=file_nb_open),
  620. # folder_nb=DictLikeClass(all=folder_nb_all,
  621. # open=folder_nb_open),
  622. # page_nb=DictLikeClass(all=page_nb_all,
  623. # open=page_nb_open),
  624. # content_nb=DictLikeClass(all = content_nb_all),
  625. # is_archived=content.is_archived,
  626. # is_deleted=content.is_deleted,
  627. # is_editable=content.is_editable,
  628. # )
  629. #
  630. # elif content.type==ContentType.Page:
  631. # result = DictLikeClass(
  632. # id = content.content_id,
  633. # label = content.label,
  634. # created = content.created,
  635. # workspace = context.toDict(content.workspace),
  636. # owner = DictLikeClass(
  637. # id = content.owner.user_id,
  638. # name = content.owner.get_display_name()
  639. # ),
  640. # status = DictLikeClass(id='', label=''), #FIXME - EXPORT DATA
  641. # )
  642. #
  643. # return result
  644. #
  645. #
  646. # @pod_serializer(Content, CTX.CONTENT_LIST)
  647. # def serialize_content_for_general_list(content: Content, context: Context):
  648. # content_type = ContentType(content.type)
  649. #
  650. # last_activity_date = content.get_last_activity_date()
  651. # last_activity_date_formatted = format_datetime(last_activity_date,
  652. # locale=tg.i18n.get_lang()[0])
  653. # last_activity_label = format_timedelta(
  654. # datetime.utcnow() - last_activity_date,
  655. # locale=tg.i18n.get_lang()[0],
  656. # )
  657. # last_activity_label = last_activity_label.replace(' ', '\u00A0') # espace insécable
  658. #
  659. # return DictLikeClass(
  660. # id=content.content_id,
  661. # folder = DictLikeClass({'id': content.parent_id}) if content.parent else None,
  662. # workspace=context.toDict(content.workspace) if content.workspace else None,
  663. # label=content.get_label(),
  664. # url=ContentType.fill_url(content),
  665. # type=DictLikeClass(content_type.toDict()),
  666. # status=context.toDict(content.get_status()),
  667. # is_deleted=content.is_deleted,
  668. # is_archived=content.is_archived,
  669. # is_editable=content.is_editable,
  670. # last_activity = DictLikeClass({'date': last_activity_date,
  671. # 'label': last_activity_date_formatted,
  672. # 'delta': last_activity_label})
  673. # )
  674. #
  675. # @pod_serializer(Content, CTX.FOLDER_CONTENT_LIST)
  676. # def serialize_content_for_folder_content_list(content: Content, context: Context):
  677. # content_type = ContentType(content.type)
  678. #
  679. # last_activity_date = content.get_last_activity_date()
  680. # last_activity_date_formatted = format_datetime(last_activity_date,
  681. # locale=tg.i18n.get_lang()[0])
  682. # last_activity_label = format_timedelta(datetime.utcnow() - last_activity_date,
  683. # locale=tg.i18n.get_lang()[0])
  684. # last_activity_label = last_activity_label.replace(' ', '\u00A0') # espace insécable
  685. #
  686. #
  687. # item = None
  688. # if ContentType.Thread == content.type:
  689. # item = Context(CTX.THREADS).toDict(content)
  690. # item.type = context.toDict(content_type)
  691. # item.folder = DictLikeClass({'id': content.parent_id}) if content.parent else None
  692. # item.workspace = DictLikeClass({'id': content.workspace.workspace_id}) if content.workspace else None
  693. # item.last_activity = DictLikeClass({'date': last_activity_date,
  694. # 'label': last_activity_date_formatted,
  695. # 'delta': last_activity_label})
  696. #
  697. # comments = content.get_comments()
  698. # if len(comments)>1:
  699. # item.notes = _('{nb} messages').format(nb=len(comments))
  700. # else:
  701. # item.notes = _('1 message')
  702. #
  703. # elif ContentType.File == content.type:
  704. # item = Context(CTX.CONTENT_LIST).toDict(content)
  705. # if len(content.revisions)>1:
  706. # item.notes = _('{nb} revisions').format(nb=len(content.revisions))
  707. # else:
  708. # item.notes = _('1 revision')
  709. #
  710. # elif ContentType.Folder == content.type:
  711. # item = Context(CTX.CONTENT_LIST).toDict(content)
  712. # item.notes = ''
  713. #
  714. # folder_nb = content.get_child_nb(ContentType.Folder)
  715. # if folder_nb == 1:
  716. # item.notes += _('1 subfolder<br/>\n')
  717. # elif folder_nb > 1:
  718. # item.notes += _('{} subfolders<br/>').format(folder_nb)
  719. #
  720. # file_nb = content.get_child_nb(ContentType.File, ContentStatus.OPEN)
  721. # if file_nb == 1:
  722. # item.notes += _('1 open file<br/>\n')
  723. # elif file_nb > 1:
  724. # item.notes += _('{} open files<br/>').format(file_nb)
  725. #
  726. # thread_nb = content.get_child_nb(ContentType.Thread, ContentStatus.OPEN)
  727. # if thread_nb == 1:
  728. # item.notes += _('1 open thread<br/>\n')
  729. # elif thread_nb > 1:
  730. # item.notes += _('{} open threads<br/>').format(thread_nb)
  731. #
  732. # page_nb = content.get_child_nb(ContentType.Page, ContentStatus.OPEN)
  733. # if page_nb == 1:
  734. # item.notes += _('1 open page<br/>\n')
  735. # elif page_nb > 1:
  736. # item.notes += _('{} open pages<br/>').format(page_nb)
  737. # else:
  738. # item = Context(CTX.CONTENT_LIST).toDict(content)
  739. # item.notes = ''
  740. #
  741. # item.is_deleted = content.is_deleted
  742. # item.is_archived = content.is_archived
  743. # item.is_editable = content.is_editable
  744. #
  745. # return item
  746. #
  747. #
  748. # @pod_serializer(ContentType, CTX.DEFAULT)
  749. # def serialize_breadcrumb_item(content_type: ContentType, context: Context):
  750. # return DictLikeClass(content_type.toDict())
  751. #
  752. #
  753. # @pod_serializer(Content, CTX.SEARCH)
  754. # def serialize_content_for_search_result(content: Content, context: Context):
  755. #
  756. # def serialize_it():
  757. # nonlocal content
  758. #
  759. # if content.type == ContentType.Comment:
  760. # logger.info('serialize_content_for_search_result', 'Serializing parent class {} instead of {} [content #{}]'.format(content.parent.type, content.type, content.content_id))
  761. # content = content.parent
  762. #
  763. # data_container = content
  764. #
  765. # if content.revision_to_serialize>0:
  766. # for revision in content.revisions:
  767. # if revision.revision_id==content.revision_to_serialize:
  768. # data_container = revision
  769. # break
  770. #
  771. # # FIXME - D.A. - 2015-02-23 - This import should not be there...
  772. # from tracim.lib.content import ContentApi
  773. # breadcrumbs = ContentApi(None).build_breadcrumb(data_container.workspace, data_container.content_id, skip_root=True)
  774. #
  775. # last_comment_datetime = data_container.updated
  776. # comments = data_container.get_comments()
  777. # if comments:
  778. # last_comment_datetime = max(last_comment_datetime, max(comment.updated for comment in comments))
  779. #
  780. # content_type = ContentType(content.type)
  781. # result = DictLikeClass(
  782. # id = content.content_id,
  783. # type = DictLikeClass(content_type.toDict()),
  784. # parent = context.toDict(content.parent),
  785. # workspace = context.toDict(content.workspace),
  786. #
  787. # content = data_container.description,
  788. # content_raw = data_container.description_as_raw_text(),
  789. #
  790. # created = data_container.created,
  791. # created_as_delta = data_container.created_as_delta(),
  792. # label = data_container.label,
  793. # icon = ContentType.get_icon(content.type),
  794. # owner = context.toDict(data_container.owner),
  795. # status = context.toDict(data_container.get_status()),
  796. # breadcrumb = context.toDict(breadcrumbs),
  797. # last_activity=last_comment_datetime,
  798. # last_activity_as_delta=content.datetime_as_delta(last_comment_datetime)
  799. # )
  800. #
  801. # if content.type==ContentType.File:
  802. # result.label = content.label.__str__()
  803. #
  804. # if not result.label or ''==result.label:
  805. # result.label = 'No title'
  806. #
  807. # return result
  808. #
  809. # return serialize_it()
  810. #
  811. #
  812. #
  813. # ########################################################################################################################
  814. # # ContentStatus
  815. #
  816. # @pod_serializer(ContentStatus, CTX.DEFAULT)
  817. # def serialize_content_status(status: ContentStatus, context: Context):
  818. # return DictLikeClass(
  819. # id = status.id,
  820. # label = status.label,
  821. # icon = status.icon,
  822. # css = status.css
  823. # )
  824. #
  825. # ########################################################################################################################
  826. # # LinkItem
  827. #
  828. # @pod_serializer(LinkItem, CTX.DEFAULT)
  829. # def serialize_content_status(link: LinkItem, context: Context):
  830. # return DictLikeClass(
  831. # href = link.href,
  832. # label = link.href,
  833. # )
  834. #
  835. # ########################################################################################################################
  836. # # Profile
  837. # @pod_serializer(Profile, CTX.DEFAULT)
  838. # def serialize_user_list_default(profile: Profile, context: Context):
  839. # return DictLikeClass(
  840. # id = profile.id,
  841. # name = profile.name,
  842. # label = profile.label
  843. # )
  844. #
  845. # ########################################################################################################################
  846. # ## ROLE TYPE
  847. #
  848. #
  849. # @pod_serializer(RoleType, CTX.ADMIN_WORKSPACE)
  850. # @pod_serializer(RoleType, CTX.ADMIN_USER)
  851. # def serialize_role_list_for_select_field_in_workspace(role_type: RoleType, context: Context):
  852. # """
  853. # Actually, roles are serialized as users (with minimal information)
  854. # :param role:
  855. # :param context:
  856. # :return:
  857. # """
  858. # result = DictLikeClass()
  859. # result['id'] = role_type.role_type_id
  860. # result['icon'] = role_type.icon
  861. # result['label'] = role_type.role_label
  862. # result['style'] = role_type.css_style
  863. # return result
  864. #
  865. #
  866. # ########################################################################################################################
  867. # ## USER
  868. #
  869. # @pod_serializer(User, CTX.DEFAULT)
  870. # @pod_serializer(User, CTX.ADMIN_WORKSPACE)
  871. # def serialize_user_default(user: User, context: Context):
  872. # """
  873. # Actually, roles are serialized as users (with minimal information)
  874. # :param role:
  875. # :param context:
  876. # :return:
  877. # """
  878. # result = DictLikeClass()
  879. # result['id'] = user.user_id
  880. # result['name'] = user.get_display_name()
  881. # return result
  882. #
  883. # @pod_serializer(User, CTX.USERS)
  884. # @pod_serializer(User, CTX.ADMIN_WORKSPACE)
  885. # def serialize_user_list_default(user: User, context: Context):
  886. # """
  887. # Actually, roles are serialized as users (with minimal information)
  888. # :param role:
  889. # :param context:
  890. # :return:
  891. # """
  892. # result = DictLikeClass()
  893. # result['id'] = user.user_id
  894. # result['name'] = user.get_display_name()
  895. # result['email'] = user.email
  896. # result['enabled'] = user.is_active
  897. # result['profile'] = user.profile
  898. # result['has_password'] = user.password!=None
  899. # result['timezone'] = user.timezone
  900. # return result
  901. #
  902. #
  903. #
  904. # @pod_serializer(User, CTX.USER)
  905. # @pod_serializer(User, CTX.ADMIN_USER)
  906. # @pod_serializer(User, CTX.CURRENT_USER)
  907. # def serialize_user_for_user(user: User, context: Context):
  908. # """
  909. # Actually, roles are serialized as users (with minimal information)
  910. # :param role:
  911. # :param context:
  912. # :return:
  913. # """
  914. # result = DictLikeClass()
  915. # result['id'] = user.user_id
  916. # result['name'] = user.get_display_name()
  917. # result['email'] = user.email
  918. # result['roles'] = context.toDict(user.get_active_roles())
  919. # result['enabled'] = user.is_active
  920. # result['profile'] = user.profile
  921. # result['calendar_url'] = user.calendar_url
  922. # result['timezone'] = user.timezone
  923. #
  924. # return result
  925. #
  926. # ########################################################################################################################
  927. # ## USER ROLE IN WORKSPACE
  928. #
  929. # @pod_serializer(UserRoleInWorkspace, CTX.ADMIN_WORKSPACE)
  930. # @pod_serializer(UserRoleInWorkspace, CTX.WORKSPACE)
  931. # def serialize_role_in_workspace(role: UserRoleInWorkspace, context: Context):
  932. # """
  933. # Actually, roles are serialized as users (with minimal information)
  934. # :param role:
  935. # :param context:
  936. # :return:
  937. # """
  938. # result = DictLikeClass()
  939. # result['id'] = role.user_id
  940. # result['icon'] = role.icon
  941. # result['name'] = role.user.display_name
  942. # result['role'] = role.role
  943. # result['style'] = role.style
  944. # result['role_description'] = role.role_as_label()
  945. # result['email'] = role.user.email
  946. # result['user'] = context.toDict(role.user)
  947. # result['notifications_subscribed'] = role.do_notify
  948. # return result
  949. #
  950. #
  951. # @pod_serializer(UserRoleInWorkspace, CTX.USER)
  952. # @pod_serializer(UserRoleInWorkspace, CTX.CURRENT_USER)
  953. # @pod_serializer(UserRoleInWorkspace, CTX.ADMIN_USER)
  954. # def serialize_role_in_list_for_user(role: UserRoleInWorkspace, context: Context):
  955. # """
  956. # Actually, roles are serialized as users (with minimal information)
  957. # :param role:
  958. # :param context:
  959. # :return:
  960. # """
  961. # result = DictLikeClass()
  962. # result['id'] = role.role
  963. # result['icon'] = role.icon
  964. # result['label'] = role.role_as_label()
  965. # result['style'] = RoleType(role.role).css_style
  966. # result['workspace'] = context.toDict(role.workspace)
  967. # result['user'] = Context(CTX.DEFAULT).toDict(role.user)
  968. # result['notifications_subscribed'] = role.do_notify
  969. #
  970. # # result['workspace_name'] = role.workspace.label
  971. #
  972. # return result
  973. #
  974. # ########################################################################################################################
  975. # ## WORKSPACE
  976. #
  977. # @pod_serializer(Workspace, CTX.DEFAULT)
  978. # def serialize_workspace_default(workspace: Workspace, context: Context):
  979. # result = DictLikeClass(
  980. # id = workspace.workspace_id,
  981. # label = workspace.label, # FIXME - 2015-08-20 - remove this property
  982. # name = workspace.label, # use name instead of label
  983. # is_deleted=workspace.is_deleted,
  984. # url = context.url('/workspaces/{}'.format(workspace.workspace_id))
  985. # )
  986. # return result
  987. #
  988. # @pod_serializer(Workspace, CTX.USER)
  989. # @pod_serializer(Workspace, CTX.CURRENT_USER)
  990. # def serialize_workspace_in_list_for_one_user(workspace: Workspace, context: Context):
  991. # """
  992. # Actually, roles are serialized as users (with minimal information)
  993. # :param role:
  994. # :param context:
  995. # :return:
  996. # """
  997. # result = DictLikeClass()
  998. # result['id'] = workspace.workspace_id
  999. # result['name'] = workspace.label
  1000. # result['is_deleted'] = workspace.is_deleted
  1001. #
  1002. # return result
  1003. #
  1004. # @pod_serializer(Workspace, CTX.ADMIN_WORKSPACES)
  1005. # def serialize_workspace_in_list(workspace: pmd.Workspace, context: Context):
  1006. # result = DictLikeClass()
  1007. # result['id'] = workspace.workspace_id
  1008. # result['label'] = workspace.label
  1009. # result['description'] = workspace.description
  1010. # result['member_nb'] = len(workspace.roles)
  1011. # result['calendar_enabled'] = workspace.calendar_enabled
  1012. # result['calendar_url'] = workspace.calendar_url
  1013. #
  1014. # return result
  1015. #
  1016. #
  1017. # @pod_serializer(Workspace, CTX.ADMIN_WORKSPACE)
  1018. # @pod_serializer(Workspace, CTX.WORKSPACE)
  1019. # def serialize_workspace_complete(workspace: pmd.Workspace, context: Context):
  1020. # result = DictLikeClass()
  1021. # result['id'] = workspace.workspace_id
  1022. # result['label'] = workspace.label
  1023. # result['description'] = workspace.description
  1024. # result['created'] = workspace.created
  1025. # result['members'] = context.toDict(workspace.roles)
  1026. # result['member_nb'] = len(workspace.roles)
  1027. # result['allowed_content_types'] = context.toDict(workspace.get_allowed_content_types())
  1028. # result['calendar_enabled'] = workspace.calendar_enabled
  1029. # result['calendar_url'] = workspace.calendar_url
  1030. #
  1031. # return result
  1032. #
  1033. # @pod_serializer(Workspace, CTX.MENU_API)
  1034. # def serialize_workspace_for_menu_api(workspace: Workspace, context: Context):
  1035. # result = DictLikeClass(
  1036. # id = CST.TREEVIEW_MENU.ID_TEMPLATE__WORKSPACE_ONLY.format(workspace.workspace_id),
  1037. # children = True, # TODO: make this dynamic
  1038. # text = workspace.label,
  1039. # a_attr = { 'href' : context.url('/workspaces/{}'.format(workspace.workspace_id)) },
  1040. # li_attr = { 'title': workspace.label, 'class': 'tracim-tree-item-is-a-workspace' },
  1041. # type = 'workspace',
  1042. # state = { 'opened': False, 'selected': False }
  1043. # )
  1044. # return result
  1045. #
  1046. # @pod_serializer(NodeTreeItem, CTX.MENU_API_BUILD_FROM_TREE_ITEM)
  1047. # def serialize_node_tree_item_for_menu_api_tree(item: NodeTreeItem, context: Context):
  1048. # if isinstance(item.node, Content):
  1049. # ContentType.fill_url(item.node)
  1050. #
  1051. # return DictLikeClass(
  1052. # id=CST.TREEVIEW_MENU.ID_TEMPLATE__FULL.format(item.node.workspace_id, item.node.content_id),
  1053. # children=True if ContentType.Folder==item.node.type and len(item.children)<=0 else context.toDict(item.children),
  1054. # text=item.node.get_label(),
  1055. # a_attr={'href': context.url(ContentType.fill_url(item.node)) },
  1056. # li_attr={'title': item.node.get_label()},
  1057. # # type='folder',
  1058. # type=item.node.type,
  1059. # state={'opened': True if ContentType.Folder==item.node.type and len(item.children)>0 else False, 'selected': item.is_selected}
  1060. # )
  1061. # elif isinstance(item.node, Workspace):
  1062. # return DictLikeClass(
  1063. # id=CST.TREEVIEW_MENU.ID_TEMPLATE__WORKSPACE_ONLY.format(item.node.workspace_id),
  1064. # children=True if len(item.children)<=0 else context.toDict(item.children),
  1065. # text=item.node.label,
  1066. # a_attr={'href': context.url(ContentType.fill_url_for_workspace(item.node))},
  1067. # li_attr={'title': item.node.get_label()},
  1068. # type='workspace',
  1069. # state={'opened': True if len(item.children)>0 else False, 'selected': item.is_selected}
  1070. # )
  1071. #
  1072. #
  1073. # @pod_serializer(Workspace, CTX.API_WORKSPACE)
  1074. # def serialize_api_workspace(item: Workspace, context: Context):
  1075. # return DictLikeClass(
  1076. # id=item.workspace_id,
  1077. # label=item.label,
  1078. # description=item.description,
  1079. # has_calendar=item.calendar_enabled,
  1080. # )
  1081. #
  1082. #
  1083. # @pod_serializer(Workspace, CTX.API_CALENDAR_WORKSPACE)
  1084. # def serialize_api_calendar_workspace(item: Workspace, context: Context):
  1085. # return DictLikeClass(
  1086. # id=item.workspace_id,
  1087. # label=item.label,
  1088. # description=item.description,
  1089. # type='workspace',
  1090. # )
  1091. #
  1092. #
  1093. # @pod_serializer(User, CTX.API_CALENDAR_USER)
  1094. # def serialize_api_calendar_workspace(item: User, context: Context):
  1095. # from tracim.lib.calendar import CalendarManager # Cyclic import
  1096. # return DictLikeClass(
  1097. # id=item.user_id,
  1098. # label=item.display_name,
  1099. # description=CalendarManager.get_personal_calendar_description(),
  1100. # type='user',
  1101. # )