Browse Source

Merge pull request #1 from lebouquetin/master

Tracim 10 years ago
parent
commit
fb1c574b6f

+ 1 - 1
.gitignore View File

@@ -59,6 +59,6 @@ tracim/data/
59 59
 
60 60
 # Site-local config file
61 61
 development.ini
62
-
62
+track.js
63 63
 # Temporary files
64 64
 *~

+ 115 - 0
tracim/tracim/controllers/content.py View File

@@ -642,3 +642,118 @@ class UserWorkspaceFolderRestController(TIMRestControllerWithBreadcrumb):
642 642
             next_url = self.url(int(folder_id))
643 643
 
644 644
         tg.redirect(next_url)
645
+
646
+    @property
647
+    def _std_url(self):
648
+        return tg.url('/workspaces/{}/folders/{}')
649
+
650
+    @property
651
+    def _parent_url(self):
652
+        return tg.url('/workspaces/{}')
653
+
654
+    @property
655
+    def _item_type_label(self):
656
+        return _('Folder')
657
+
658
+    @property
659
+    def _item_type(self):
660
+        return ContentType.Folder
661
+
662
+
663
+    @tg.require(current_user_is_content_manager())
664
+    @tg.expose()
665
+    def put_archive(self, item_id):
666
+        # TODO - CHECK RIGHTS
667
+        item_id = int(item_id)
668
+        content_api = ContentApi(tmpl_context.current_user)
669
+        item = content_api.get_one(item_id, self._item_type, tmpl_context.workspace)
670
+
671
+        try:
672
+            next_url = self._parent_url.format(item.workspace_id, item.parent_id)
673
+            undo_url = self._std_url.format(item.workspace_id, item.content_id)+'/put_archive_undo'
674
+            msg = _('{} archived. <a class="alert-link" href="{}">Cancel action</a>').format(self._item_type_label, undo_url)
675
+
676
+            content_api.archive(item)
677
+            content_api.save(item, ActionDescription.ARCHIVING)
678
+
679
+            tg.flash(msg, CST.STATUS_OK, no_escape=True) # TODO allow to come back
680
+            tg.redirect(next_url)
681
+        except ValueError as e:
682
+            next_url = self._std_url.format(item.workspace_id, item.parent_id, item.content_id)
683
+            msg = _('{} not archived: {}').format(self._item_type_label, str(e))
684
+            tg.flash(msg, CST.STATUS_ERROR)
685
+            tg.redirect(next_url)
686
+
687
+
688
+    @tg.require(current_user_is_content_manager())
689
+    @tg.expose()
690
+    def put_archive_undo(self, item_id):
691
+        print('AGAGA')
692
+        # TODO - CHECK RIGHTS
693
+        item_id = int(item_id)
694
+        content_api = ContentApi(tmpl_context.current_user, True, True) # Here we do not filter deleted items
695
+        item = content_api.get_one(item_id, self._item_type, tmpl_context.workspace)
696
+        try:
697
+            next_url = self._std_url.format(item.workspace_id, item.content_id)
698
+            msg = _('{} unarchived.').format(self._item_type_label)
699
+            content_api.unarchive(item)
700
+            content_api.save(item, ActionDescription.UNARCHIVING)
701
+
702
+            tg.flash(msg, CST.STATUS_OK)
703
+            tg.redirect(next_url )
704
+
705
+        except ValueError as e:
706
+            msg = _('{} not un-archived: {}').format(self._item_type_label, str(e))
707
+            next_url = self._std_url.format(item.workspace_id, item.content_id)
708
+            # We still use std url because the item has not been archived
709
+            tg.flash(msg, CST.STATUS_ERROR)
710
+            tg.redirect(next_url)
711
+
712
+    @tg.require(current_user_is_content_manager())
713
+    @tg.expose()
714
+    def put_delete(self, item_id):
715
+        # TODO - CHECK RIGHTS
716
+        item_id = int(item_id)
717
+        content_api = ContentApi(tmpl_context.current_user)
718
+        item = content_api.get_one(item_id, self._item_type, tmpl_context.workspace)
719
+        try:
720
+
721
+            next_url = self._parent_url.format(item.workspace_id, item.parent_id)
722
+            undo_url = self._std_url.format(item.workspace_id, item.content_id)+'/put_delete_undo'
723
+            msg = _('{} deleted. <a class="alert-link" href="{}">Cancel action</a>').format(self._item_type_label, undo_url)
724
+            content_api.delete(item)
725
+            content_api.save(item, ActionDescription.DELETION)
726
+
727
+            tg.flash(msg, CST.STATUS_OK, no_escape=True)
728
+            tg.redirect(next_url)
729
+
730
+        except ValueError as e:
731
+            back_url = self._std_url.format(item.workspace_id, item.content_id)
732
+            msg = _('{} not deleted: {}').format(self._item_type_label, str(e))
733
+            tg.flash(msg, CST.STATUS_ERROR)
734
+            tg.redirect(back_url)
735
+
736
+
737
+    @tg.require(current_user_is_content_manager())
738
+    @tg.expose()
739
+    def put_delete_undo(self, item_id):
740
+        # TODO - CHECK RIGHTS
741
+
742
+        item_id = int(item_id)
743
+        content_api = ContentApi(tmpl_context.current_user, True, True) # Here we do not filter deleted items
744
+        item = content_api.get_one(item_id, self._item_type, tmpl_context.workspace)
745
+        try:
746
+            next_url = self._std_url.format(item.workspace_id, item.content_id)
747
+            msg = _('{} undeleted.').format(self._item_type_label)
748
+            content_api.undelete(item)
749
+            content_api.save(item, ActionDescription.UNDELETION)
750
+
751
+            tg.flash(msg, CST.STATUS_OK)
752
+            tg.redirect(next_url)
753
+
754
+        except ValueError as e:
755
+            logger.debug(self, 'Exception: {}'.format(e.__str__))
756
+            back_url = self._parent_url.format(item.workspace_id, item.parent_id)
757
+            msg = _('{} not un-deleted: {}').format(self._item_type_label, str(e))
758
+            tg.flash(msg, CST.STATUS_ERROR)
759
+            tg.redirect(back_url)

+ 7 - 1
tracim/tracim/model/data.py View File

@@ -331,6 +331,12 @@ class Content(DeclarativeBase):
331 331
     parent = relationship('Content', remote_side=[content_id], backref='children')
332 332
     owner = relationship('User', remote_side=[User.user_id])
333 333
 
334
+    @property
335
+    def valid_children(self):
336
+        for child in self.children:
337
+            if not child.is_deleted and not child.is_archived:
338
+                yield child
339
+
334 340
     @hybrid_property
335 341
     def properties(self):
336 342
         """ return a structure decoded from json content of _properties """
@@ -365,7 +371,7 @@ class Content(DeclarativeBase):
365 371
 
366 372
     def get_child_nb(self, content_type: ContentType, content_status = ''):
367 373
         child_nb = 0
368
-        for child in self.children:
374
+        for child in self.valid_children:
369 375
             if child.type==content_type:
370 376
                 if not content_status:
371 377
                     child_nb = child_nb+1

+ 15 - 5
tracim/tracim/templates/folder_toolbars.mak View File

@@ -16,13 +16,23 @@
16 16
         <p></p>
17 17
     % endif
18 18
     
19
-    <div class="btn-group btn-group-vertical">
20
-        % if user.profile.id>=3 or h.user_role(user, workspace)>=4:
19
+    % if user.profile.id>=3 or h.user_role(user, workspace)>=4:
20
+        <div class="btn-group btn-group-vertical">
21 21
             ## This action is allowed for content managers only
22 22
             <a title="${_('Move current folder')}" class="btn btn-default ${move_disabled}" data-toggle="modal" data-target="#folder-move-modal-dialog" data-remote="${tg.url('/workspaces/{}/folders/{}/location/{}/edit'.format(folder.workspace.id, folder.id, folder.id))}" >${TIM.ICO(32, 'actions/item-move')}</a>
23
-        % endif
24
-    </div>
25
-    <p></p>
23
+        </div>
24
+        <p></p>
25
+    % endif
26
+
27
+    % if user.profile.id>=3 or h.user_role(user, workspace)>=4:
28
+        ## if the user can see the toolbar, it means he is the workspace manager.
29
+        ## So now, we need to know if he alsa has right to delete workspaces
30
+        <div class="btn-group btn-group-vertical">
31
+            <a title="${_('Archive thread')}" class="btn btn-default ${delete_or_archive_disabled}" href="${tg.url('/workspaces/{}/folders/{}/put_archive'.format(folder.workspace.id, folder.id))}">${TIM.ICO(32, 'mimetypes/package-x-generic')}</a>
32
+            <a title="${_('Delete thread')}" class="btn btn-default ${delete_or_archive_disabled}" href="${tg.url('/workspaces/{}/folders/{}/put_delete'.format(folder.workspace.id, folder.id))}">${TIM.ICO(32, 'status/user-trash-full')}</a>
33
+        </div>
34
+        <p></p>
35
+    % endif
26 36
 
27 37
 </%def>
28 38