workspace_controller.py 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. import typing
  2. import transaction
  3. from pyramid.config import Configurator
  4. from pyramid.httpexceptions import HTTPFound
  5. from tracim_backend.lib.core.user import UserApi
  6. from tracim_backend.models.roles import WorkspaceRoles
  7. try: # Python 3.5+
  8. from http import HTTPStatus
  9. except ImportError:
  10. from http import client as HTTPStatus
  11. from tracim_backend import hapic
  12. from tracim_backend.lib.utils.request import TracimRequest
  13. from tracim_backend import BASE_API_V2
  14. from tracim_backend.lib.core.workspace import WorkspaceApi
  15. from tracim_backend.lib.core.content import ContentApi
  16. from tracim_backend.lib.core.userworkspace import RoleApi
  17. from tracim_backend.lib.utils.authorization import require_workspace_role
  18. from tracim_backend.lib.utils.authorization import require_same_user_or_profile
  19. from tracim_backend.lib.utils.authorization import require_profile_or_other_profile_with_workspace_role
  20. from tracim_backend.lib.utils.authorization import require_profile
  21. from tracim_backend.models import Group
  22. from tracim_backend.lib.utils.authorization import require_candidate_workspace_role
  23. from tracim_backend.models.data import UserRoleInWorkspace
  24. from tracim_backend.models.data import ActionDescription
  25. from tracim_backend.models.context_models import UserRoleWorkspaceInContext
  26. from tracim_backend.models.context_models import ContentInContext
  27. from tracim_backend.exceptions import EmptyLabelNotAllowed
  28. from tracim_backend.exceptions import UnallowedSubContent
  29. from tracim_backend.exceptions import EmailValidationFailed
  30. from tracim_backend.exceptions import UserCreationFailed
  31. from tracim_backend.exceptions import UserDoesNotExist
  32. from tracim_backend.exceptions import ContentNotFound
  33. from tracim_backend.exceptions import WorkspacesDoNotMatch
  34. from tracim_backend.exceptions import ParentNotFound
  35. from tracim_backend.views.controllers import Controller
  36. from tracim_backend.lib.utils.utils import password_generator
  37. from tracim_backend.views.core_api.schemas import FilterContentQuerySchema
  38. from tracim_backend.views.core_api.schemas import ContentIdPathSchema
  39. from tracim_backend.views.core_api.schemas import WorkspaceMemberCreationSchema
  40. from tracim_backend.views.core_api.schemas import WorkspaceMemberInviteSchema
  41. from tracim_backend.views.core_api.schemas import RoleUpdateSchema
  42. from tracim_backend.views.core_api.schemas import WorkspaceCreationSchema
  43. from tracim_backend.views.core_api.schemas import WorkspaceModifySchema
  44. from tracim_backend.views.core_api.schemas import WorkspaceAndUserIdPathSchema
  45. from tracim_backend.views.core_api.schemas import ContentMoveSchema
  46. from tracim_backend.views.core_api.schemas import NoContentSchema
  47. from tracim_backend.views.core_api.schemas import ContentCreationSchema
  48. from tracim_backend.views.core_api.schemas import WorkspaceAndContentIdPathSchema
  49. from tracim_backend.views.core_api.schemas import ContentDigestSchema
  50. from tracim_backend.views.core_api.schemas import WorkspaceSchema
  51. from tracim_backend.views.core_api.schemas import WorkspaceIdPathSchema
  52. from tracim_backend.views.core_api.schemas import WorkspaceMemberSchema
  53. from tracim_backend.app_models.contents import CONTENT_TYPES
  54. from tracim_backend.models.revision_protection import new_revision
  55. SWAGGER_TAG_WORKSPACE_ENDPOINTS = 'Workspaces'
  56. class WorkspaceController(Controller):
  57. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  58. @require_workspace_role(UserRoleInWorkspace.READER)
  59. @hapic.input_path(WorkspaceIdPathSchema())
  60. @hapic.output_body(WorkspaceSchema())
  61. def workspace(self, context, request: TracimRequest, hapic_data=None):
  62. """
  63. Get workspace informations
  64. """
  65. app_config = request.registry.settings['CFG']
  66. wapi = WorkspaceApi(
  67. current_user=request.current_user, # User
  68. session=request.dbsession,
  69. config=app_config,
  70. )
  71. return wapi.get_workspace_with_context(request.current_workspace)
  72. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  73. @require_profile(Group.TIM_ADMIN)
  74. @hapic.output_body(WorkspaceSchema(many=True), )
  75. def workspaces(self, context, request: TracimRequest, hapic_data=None):
  76. """
  77. Get list of all workspaces
  78. """
  79. app_config = request.registry.settings['CFG']
  80. wapi = WorkspaceApi(
  81. current_user=request.current_user, # User
  82. session=request.dbsession,
  83. config=app_config,
  84. )
  85. workspaces = wapi.get_all()
  86. return [
  87. wapi.get_workspace_with_context(workspace)
  88. for workspace in workspaces
  89. ]
  90. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  91. @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
  92. @require_workspace_role(UserRoleInWorkspace.WORKSPACE_MANAGER)
  93. @hapic.input_path(WorkspaceIdPathSchema())
  94. @hapic.input_body(WorkspaceModifySchema())
  95. @hapic.output_body(WorkspaceSchema())
  96. def update_workspace(self, context, request: TracimRequest, hapic_data=None): # nopep8
  97. """
  98. Update workspace informations
  99. """
  100. app_config = request.registry.settings['CFG']
  101. wapi = WorkspaceApi(
  102. current_user=request.current_user, # User
  103. session=request.dbsession,
  104. config=app_config,
  105. )
  106. wapi.update_workspace(
  107. request.current_workspace,
  108. label=hapic_data.body.label,
  109. description=hapic_data.body.description,
  110. save_now=True,
  111. )
  112. return wapi.get_workspace_with_context(request.current_workspace)
  113. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  114. @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
  115. @require_profile(Group.TIM_MANAGER)
  116. @hapic.input_body(WorkspaceCreationSchema())
  117. @hapic.output_body(WorkspaceSchema())
  118. def create_workspace(self, context, request: TracimRequest, hapic_data=None): # nopep8
  119. """
  120. create workspace
  121. """
  122. app_config = request.registry.settings['CFG']
  123. wapi = WorkspaceApi(
  124. current_user=request.current_user, # User
  125. session=request.dbsession,
  126. config=app_config,
  127. )
  128. workspace = wapi.create_workspace(
  129. label=hapic_data.body.label,
  130. description=hapic_data.body.description,
  131. save_now=True,
  132. )
  133. return wapi.get_workspace_with_context(workspace)
  134. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  135. @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
  136. @require_profile_or_other_profile_with_workspace_role(
  137. Group.TIM_ADMIN,
  138. Group.TIM_MANAGER,
  139. UserRoleInWorkspace.WORKSPACE_MANAGER,
  140. )
  141. @hapic.input_path(WorkspaceIdPathSchema())
  142. @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT) # nopep8
  143. def delete_workspace(self, context, request: TracimRequest, hapic_data=None): # nopep8
  144. """
  145. delete workspace
  146. """
  147. app_config = request.registry.settings['CFG']
  148. wapi = WorkspaceApi(
  149. current_user=request.current_user, # User
  150. session=request.dbsession,
  151. config=app_config,
  152. )
  153. wapi.delete(request.current_workspace, flush=True)
  154. return
  155. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  156. @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
  157. @require_profile_or_other_profile_with_workspace_role(
  158. Group.TIM_ADMIN,
  159. Group.TIM_MANAGER,
  160. UserRoleInWorkspace.WORKSPACE_MANAGER,
  161. )
  162. @hapic.input_path(WorkspaceIdPathSchema())
  163. @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT) # nopep8
  164. def undelete_workspace(self, context, request: TracimRequest, hapic_data=None): # nopep8
  165. """
  166. restore deleted workspace
  167. """
  168. app_config = request.registry.settings['CFG']
  169. wapi = WorkspaceApi(
  170. current_user=request.current_user, # User
  171. session=request.dbsession,
  172. config=app_config,
  173. show_deleted=True,
  174. )
  175. wapi.undelete(request.current_workspace, flush=True)
  176. return
  177. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  178. @require_workspace_role(UserRoleInWorkspace.READER)
  179. @hapic.input_path(WorkspaceIdPathSchema())
  180. @hapic.output_body(WorkspaceMemberSchema(many=True))
  181. def workspaces_members(
  182. self,
  183. context,
  184. request: TracimRequest,
  185. hapic_data=None
  186. ) -> typing.List[UserRoleWorkspaceInContext]:
  187. """
  188. Get Members of this workspace
  189. """
  190. app_config = request.registry.settings['CFG']
  191. rapi = RoleApi(
  192. current_user=request.current_user,
  193. session=request.dbsession,
  194. config=app_config,
  195. )
  196. roles = rapi.get_all_for_workspace(request.current_workspace)
  197. return [
  198. rapi.get_user_role_workspace_with_context(user_role)
  199. for user_role in roles
  200. ]
  201. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  202. @require_workspace_role(UserRoleInWorkspace.READER)
  203. @hapic.input_path(WorkspaceAndUserIdPathSchema())
  204. @hapic.output_body(WorkspaceMemberSchema())
  205. def workspaces_member_role(
  206. self,
  207. context,
  208. request: TracimRequest,
  209. hapic_data=None
  210. ) -> UserRoleWorkspaceInContext:
  211. """
  212. Get role of user in workspace
  213. """
  214. app_config = request.registry.settings['CFG']
  215. rapi = RoleApi(
  216. current_user=request.current_user,
  217. session=request.dbsession,
  218. config=app_config,
  219. )
  220. role = rapi.get_one(
  221. user_id=hapic_data.path.user_id,
  222. workspace_id=hapic_data.path.workspace_id,
  223. )
  224. return rapi.get_user_role_workspace_with_context(role)
  225. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  226. @require_workspace_role(UserRoleInWorkspace.WORKSPACE_MANAGER)
  227. @hapic.input_path(WorkspaceAndUserIdPathSchema())
  228. @hapic.input_body(RoleUpdateSchema())
  229. @hapic.output_body(WorkspaceMemberSchema())
  230. def update_workspaces_members_role(
  231. self,
  232. context,
  233. request: TracimRequest,
  234. hapic_data=None
  235. ) -> UserRoleWorkspaceInContext:
  236. """
  237. Update Members to this workspace
  238. """
  239. app_config = request.registry.settings['CFG']
  240. rapi = RoleApi(
  241. current_user=request.current_user,
  242. session=request.dbsession,
  243. config=app_config,
  244. )
  245. role = rapi.get_one(
  246. user_id=hapic_data.path.user_id,
  247. workspace_id=hapic_data.path.workspace_id,
  248. )
  249. workspace_role = WorkspaceRoles.get_role_from_slug(hapic_data.body.role)
  250. role = rapi.update_role(
  251. role,
  252. role_level=workspace_role.level
  253. )
  254. return rapi.get_user_role_workspace_with_context(role)
  255. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  256. @require_workspace_role(UserRoleInWorkspace.WORKSPACE_MANAGER)
  257. @hapic.input_path(WorkspaceAndUserIdPathSchema())
  258. @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT) # nopep8
  259. def delete_workspaces_members_role(
  260. self,
  261. context,
  262. request: TracimRequest,
  263. hapic_data=None
  264. ) -> None:
  265. app_config = request.registry.settings['CFG']
  266. rapi = RoleApi(
  267. current_user=request.current_user,
  268. session=request.dbsession,
  269. config=app_config,
  270. )
  271. rapi.delete_one(
  272. user_id=hapic_data.path.user_id,
  273. workspace_id=hapic_data.path.workspace_id,
  274. )
  275. return
  276. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  277. @hapic.handle_exception(UserCreationFailed, HTTPStatus.BAD_REQUEST)
  278. @require_workspace_role(UserRoleInWorkspace.WORKSPACE_MANAGER)
  279. @hapic.input_path(WorkspaceIdPathSchema())
  280. @hapic.input_body(WorkspaceMemberInviteSchema())
  281. @hapic.output_body(WorkspaceMemberCreationSchema())
  282. def create_workspaces_members_role(
  283. self,
  284. context,
  285. request: TracimRequest,
  286. hapic_data=None
  287. ) -> UserRoleWorkspaceInContext:
  288. """
  289. Add Members to this workspace
  290. """
  291. newly_created = False
  292. email_sent = False
  293. app_config = request.registry.settings['CFG']
  294. rapi = RoleApi(
  295. current_user=request.current_user,
  296. session=request.dbsession,
  297. config=app_config,
  298. )
  299. uapi = UserApi(
  300. current_user=request.current_user,
  301. session=request.dbsession,
  302. config=app_config,
  303. )
  304. try:
  305. _, user = uapi.find(
  306. user_id=hapic_data.body.user_id,
  307. email=hapic_data.body.user_email_or_public_name,
  308. public_name=hapic_data.body.user_email_or_public_name
  309. )
  310. except UserDoesNotExist:
  311. try:
  312. # TODO - G.M - 2018-07-05 - [UserCreation] Reenable email
  313. # notification for creation
  314. user = uapi.create_user(
  315. email=hapic_data.body.user_email_or_public_name,
  316. password=password_generator(),
  317. do_notify=True
  318. ) # nopep8
  319. newly_created = True
  320. if app_config.EMAIL_NOTIFICATION_ACTIVATED and \
  321. app_config.EMAIL_NOTIFICATION_PROCESSING_MODE.lower() == 'sync':
  322. email_sent = True
  323. except EmailValidationFailed:
  324. raise UserCreationFailed('no valid mail given')
  325. role = rapi.create_one(
  326. user=user,
  327. workspace=request.current_workspace,
  328. role_level=WorkspaceRoles.get_role_from_slug(hapic_data.body.role).level, # nopep8
  329. with_notif=False,
  330. flush=True,
  331. )
  332. return rapi.get_user_role_workspace_with_context(
  333. role,
  334. newly_created=newly_created,
  335. email_sent=email_sent,
  336. )
  337. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  338. @require_workspace_role(UserRoleInWorkspace.READER)
  339. @hapic.input_path(WorkspaceIdPathSchema())
  340. @hapic.input_query(FilterContentQuerySchema())
  341. @hapic.output_body(ContentDigestSchema(many=True))
  342. def workspace_content(
  343. self,
  344. context,
  345. request: TracimRequest,
  346. hapic_data=None,
  347. ) -> typing.List[ContentInContext]:
  348. """
  349. return list of contents found in the workspace
  350. """
  351. app_config = request.registry.settings['CFG']
  352. content_filter = hapic_data.query
  353. api = ContentApi(
  354. current_user=request.current_user,
  355. session=request.dbsession,
  356. config=app_config,
  357. show_archived=content_filter.show_archived,
  358. show_deleted=content_filter.show_deleted,
  359. show_active=content_filter.show_active,
  360. )
  361. contents = api.get_all(
  362. parent_id=content_filter.parent_id,
  363. workspace=request.current_workspace,
  364. content_type=content_filter.content_type or CONTENT_TYPES.Any_SLUG,
  365. )
  366. contents = [
  367. api.get_content_in_context(content) for content in contents
  368. ]
  369. return contents
  370. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  371. @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
  372. @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
  373. @hapic.handle_exception(UnallowedSubContent, HTTPStatus.BAD_REQUEST)
  374. @hapic.input_path(WorkspaceIdPathSchema())
  375. @hapic.input_body(ContentCreationSchema())
  376. @hapic.output_body(ContentDigestSchema())
  377. def create_generic_empty_content(
  378. self,
  379. context,
  380. request: TracimRequest,
  381. hapic_data=None,
  382. ) -> ContentInContext:
  383. """
  384. create a generic empty content
  385. """
  386. app_config = request.registry.settings['CFG']
  387. creation_data = hapic_data.body
  388. api = ContentApi(
  389. current_user=request.current_user,
  390. session=request.dbsession,
  391. config=app_config
  392. )
  393. parent = None
  394. if creation_data.parent_id:
  395. try:
  396. parent = api.get_one(content_id=creation_data.parent_id, content_type=CONTENT_TYPES.Any_SLUG) # nopep8
  397. except ContentNotFound as exc:
  398. raise ParentNotFound(
  399. 'Parent with content_id {} not found'.format(creation_data.parent_id)
  400. ) from exc
  401. content = api.create(
  402. label=creation_data.label,
  403. content_type_slug=creation_data.content_type,
  404. workspace=request.current_workspace,
  405. parent=parent,
  406. )
  407. api.save(content, ActionDescription.CREATION)
  408. content = api.get_content_in_context(content)
  409. return content
  410. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  411. @require_workspace_role(UserRoleInWorkspace.READER)
  412. @hapic.input_path(WorkspaceAndContentIdPathSchema())
  413. @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.FOUND) # nopep8
  414. def get_content_from_workspace(
  415. self,
  416. context,
  417. request: TracimRequest,
  418. hapic_data=None,
  419. ) -> None:
  420. """
  421. redirect to correct content file endpoint
  422. """
  423. app_config = request.registry.settings['CFG']
  424. content = request.current_content
  425. content_type = CONTENT_TYPES.get_one_by_slug(content.type).slug
  426. # TODO - G.M - 2018-08-03 - Jsonify redirect response ?
  427. raise HTTPFound(
  428. "{base_url}workspaces/{workspace_id}/{content_type}s/{content_id}".format(
  429. base_url=BASE_API_V2,
  430. workspace_id=content.workspace_id,
  431. content_type=content_type,
  432. content_id=content.content_id,
  433. )
  434. )
  435. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  436. @hapic.input_path(ContentIdPathSchema())
  437. @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.FOUND) # nopep8
  438. def get_content(
  439. self,
  440. context,
  441. request: TracimRequest,
  442. hapic_data=None,
  443. ) -> None:
  444. """
  445. redirect to correct content file endpoint
  446. """
  447. app_config = request.registry.settings['CFG']
  448. api = ContentApi(
  449. current_user=request.current_user,
  450. session=request.dbsession,
  451. config=app_config,
  452. )
  453. content = api.get_one(
  454. content_id=hapic_data.path['content_id'],
  455. content_type=CONTENT_TYPES.Any_SLUG
  456. )
  457. content_type = CONTENT_TYPES.get_one_by_slug(content.type).slug
  458. # TODO - G.M - 2018-08-03 - Jsonify redirect response ?
  459. raise HTTPFound(
  460. "{base_url}workspaces/{workspace_id}/{content_type}s/{content_id}".format(
  461. base_url=BASE_API_V2,
  462. workspace_id=content.workspace_id,
  463. content_type=content_type,
  464. content_id=content.content_id,
  465. )
  466. )
  467. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  468. @hapic.handle_exception(WorkspacesDoNotMatch, HTTPStatus.BAD_REQUEST)
  469. @require_workspace_role(UserRoleInWorkspace.CONTENT_MANAGER)
  470. @require_candidate_workspace_role(UserRoleInWorkspace.CONTENT_MANAGER)
  471. @hapic.input_path(WorkspaceAndContentIdPathSchema())
  472. @hapic.input_body(ContentMoveSchema())
  473. @hapic.output_body(ContentDigestSchema())
  474. def move_content(
  475. self,
  476. context,
  477. request: TracimRequest,
  478. hapic_data=None,
  479. ) -> ContentInContext:
  480. """
  481. move a content
  482. """
  483. app_config = request.registry.settings['CFG']
  484. path_data = hapic_data.path
  485. move_data = hapic_data.body
  486. api = ContentApi(
  487. show_archived=True,
  488. show_deleted=True,
  489. current_user=request.current_user,
  490. session=request.dbsession,
  491. config=app_config,
  492. )
  493. content = api.get_one(
  494. path_data.content_id,
  495. content_type=CONTENT_TYPES.Any_SLUG
  496. )
  497. new_parent = api.get_one(
  498. move_data.new_parent_id, content_type=CONTENT_TYPES.Any_SLUG
  499. )
  500. new_workspace = request.candidate_workspace
  501. with new_revision(
  502. session=request.dbsession,
  503. tm=transaction.manager,
  504. content=content
  505. ):
  506. api.move(
  507. content,
  508. new_parent=new_parent,
  509. new_workspace=new_workspace,
  510. must_stay_in_same_workspace=False,
  511. )
  512. updated_content = api.get_one(
  513. path_data.content_id,
  514. content_type=CONTENT_TYPES.Any_SLUG
  515. )
  516. return api.get_content_in_context(updated_content)
  517. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  518. @require_workspace_role(UserRoleInWorkspace.CONTENT_MANAGER)
  519. @hapic.input_path(WorkspaceAndContentIdPathSchema())
  520. @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT) # nopep8
  521. def delete_content(
  522. self,
  523. context,
  524. request: TracimRequest,
  525. hapic_data=None,
  526. ) -> None:
  527. """
  528. delete a content
  529. """
  530. app_config = request.registry.settings['CFG']
  531. path_data = hapic_data.path
  532. api = ContentApi(
  533. show_archived=True,
  534. show_deleted=True,
  535. current_user=request.current_user,
  536. session=request.dbsession,
  537. config=app_config,
  538. )
  539. content = api.get_one(
  540. path_data.content_id,
  541. content_type=CONTENT_TYPES.Any_SLUG
  542. )
  543. with new_revision(
  544. session=request.dbsession,
  545. tm=transaction.manager,
  546. content=content
  547. ):
  548. api.delete(content)
  549. return
  550. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  551. @require_workspace_role(UserRoleInWorkspace.CONTENT_MANAGER)
  552. @hapic.input_path(WorkspaceAndContentIdPathSchema())
  553. @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT) # nopep8
  554. def undelete_content(
  555. self,
  556. context,
  557. request: TracimRequest,
  558. hapic_data=None,
  559. ) -> None:
  560. """
  561. undelete a content
  562. """
  563. app_config = request.registry.settings['CFG']
  564. path_data = hapic_data.path
  565. api = ContentApi(
  566. current_user=request.current_user,
  567. session=request.dbsession,
  568. config=app_config,
  569. show_deleted=True,
  570. show_archived=True,
  571. )
  572. content = api.get_one(
  573. path_data.content_id,
  574. content_type=CONTENT_TYPES.Any_SLUG
  575. )
  576. with new_revision(
  577. session=request.dbsession,
  578. tm=transaction.manager,
  579. content=content
  580. ):
  581. api.undelete(content)
  582. return
  583. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  584. @require_workspace_role(UserRoleInWorkspace.CONTENT_MANAGER)
  585. @hapic.input_path(WorkspaceAndContentIdPathSchema())
  586. @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT) # nopep8
  587. def archive_content(
  588. self,
  589. context,
  590. request: TracimRequest,
  591. hapic_data=None,
  592. ) -> None:
  593. """
  594. archive a content
  595. """
  596. app_config = request.registry.settings['CFG']
  597. path_data = hapic_data.path
  598. api = ContentApi(
  599. show_archived=True,
  600. show_deleted=True,
  601. current_user=request.current_user,
  602. session=request.dbsession,
  603. config=app_config,
  604. )
  605. content = api.get_one(path_data.content_id, content_type=CONTENT_TYPES.Any_SLUG) # nopep8
  606. with new_revision(
  607. session=request.dbsession,
  608. tm=transaction.manager,
  609. content=content
  610. ):
  611. api.archive(content)
  612. return
  613. @hapic.with_api_doc(tags=[SWAGGER_TAG_WORKSPACE_ENDPOINTS])
  614. @require_workspace_role(UserRoleInWorkspace.CONTENT_MANAGER)
  615. @hapic.input_path(WorkspaceAndContentIdPathSchema())
  616. @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT) # nopep8
  617. def unarchive_content(
  618. self,
  619. context,
  620. request: TracimRequest,
  621. hapic_data=None,
  622. ) -> None:
  623. """
  624. unarchive a content
  625. """
  626. app_config = request.registry.settings['CFG']
  627. path_data = hapic_data.path
  628. api = ContentApi(
  629. current_user=request.current_user,
  630. session=request.dbsession,
  631. config=app_config,
  632. show_archived=True,
  633. show_deleted=True,
  634. )
  635. content = api.get_one(
  636. path_data.content_id,
  637. content_type=CONTENT_TYPES.Any_SLUG
  638. )
  639. with new_revision(
  640. session=request.dbsession,
  641. tm=transaction.manager,
  642. content=content
  643. ):
  644. api.unarchive(content)
  645. return
  646. def bind(self, configurator: Configurator) -> None:
  647. """
  648. Create all routes and views using
  649. pyramid configurator for this controller
  650. """
  651. # Workspaces
  652. configurator.add_route('workspaces', '/workspaces', request_method='GET') # nopep8
  653. configurator.add_view(self.workspaces, route_name='workspaces')
  654. # Workspace
  655. configurator.add_route('workspace', '/workspaces/{workspace_id}', request_method='GET') # nopep8
  656. configurator.add_view(self.workspace, route_name='workspace')
  657. # Create workspace
  658. configurator.add_route('create_workspace', '/workspaces', request_method='POST') # nopep8
  659. configurator.add_view(self.create_workspace, route_name='create_workspace') # nopep8
  660. # Delete/Undelete workpace
  661. configurator.add_route('delete_workspace', '/workspaces/{workspace_id}/delete', request_method='PUT') # nopep8
  662. configurator.add_view(self.delete_workspace, route_name='delete_workspace') # nopep8
  663. configurator.add_route('undelete_workspace', '/workspaces/{workspace_id}/undelete', request_method='PUT') # nopep8
  664. configurator.add_view(self.undelete_workspace, route_name='undelete_workspace') # nopep8
  665. # Update Workspace
  666. configurator.add_route('update_workspace', '/workspaces/{workspace_id}', request_method='PUT') # nopep8
  667. configurator.add_view(self.update_workspace, route_name='update_workspace') # nopep8
  668. # Workspace Members (Roles)
  669. configurator.add_route('workspace_members', '/workspaces/{workspace_id}/members', request_method='GET') # nopep8
  670. configurator.add_view(self.workspaces_members, route_name='workspace_members') # nopep8
  671. # Workspace Members (Role) Individual
  672. configurator.add_route('workspace_member_role', '/workspaces/{workspace_id}/members/{user_id}', request_method='GET') # nopep8
  673. configurator.add_view(self.workspaces_member_role, route_name='workspace_member_role') # nopep8
  674. # Update Workspace Members roles
  675. configurator.add_route('update_workspace_member', '/workspaces/{workspace_id}/members/{user_id}', request_method='PUT') # nopep8
  676. configurator.add_view(self.update_workspaces_members_role, route_name='update_workspace_member') # nopep8
  677. # Create Workspace Members roles
  678. configurator.add_route('create_workspace_member', '/workspaces/{workspace_id}/members', request_method='POST') # nopep8
  679. configurator.add_view(self.create_workspaces_members_role, route_name='create_workspace_member') # nopep8
  680. # Delete Workspace Members roles
  681. configurator.add_route('delete_workspace_member', '/workspaces/{workspace_id}/members/{user_id}', request_method='DELETE') # nopep8
  682. configurator.add_view(self.delete_workspaces_members_role, route_name='delete_workspace_member') # nopep8
  683. # Workspace Content
  684. configurator.add_route('workspace_content', '/workspaces/{workspace_id}/contents', request_method='GET') # nopep8
  685. configurator.add_view(self.workspace_content, route_name='workspace_content') # nopep8
  686. # Create Generic Content
  687. configurator.add_route('create_generic_content', '/workspaces/{workspace_id}/contents', request_method='POST') # nopep8
  688. configurator.add_view(self.create_generic_empty_content, route_name='create_generic_content') # nopep8
  689. # Get Content
  690. configurator.add_route('get_content', '/contents/{content_id}', request_method='GET') # nopep8
  691. configurator.add_view(self.get_content, route_name='get_content')
  692. # Get Content From workspace
  693. configurator.add_route('get_content_from_workspace', '/workspaces/{workspace_id}/contents/{content_id}', request_method='GET') # nopep8
  694. configurator.add_view(self.get_content_from_workspace, route_name='get_content_from_workspace') # nopep8
  695. # Move Content
  696. configurator.add_route('move_content', '/workspaces/{workspace_id}/contents/{content_id}/move', request_method='PUT') # nopep8
  697. configurator.add_view(self.move_content, route_name='move_content') # nopep8
  698. # Delete/Undelete Content
  699. configurator.add_route('delete_content', '/workspaces/{workspace_id}/contents/{content_id}/delete', request_method='PUT') # nopep8
  700. configurator.add_view(self.delete_content, route_name='delete_content') # nopep8
  701. configurator.add_route('undelete_content', '/workspaces/{workspace_id}/contents/{content_id}/undelete', request_method='PUT') # nopep8
  702. configurator.add_view(self.undelete_content, route_name='undelete_content') # nopep8
  703. # # Archive/Unarchive Content
  704. configurator.add_route('archive_content', '/workspaces/{workspace_id}/contents/{content_id}/archive', request_method='PUT') # nopep8
  705. configurator.add_view(self.archive_content, route_name='archive_content') # nopep8
  706. configurator.add_route('unarchive_content', '/workspaces/{workspace_id}/contents/{content_id}/unarchive', request_method='PUT') # nopep8
  707. configurator.add_view(self.unarchive_content, route_name='unarchive_content') # nopep8