# -*- coding: utf-8 -*- """Sample controller with all its actions protected.""" from datetime import datetime # TODO - D.A. - 2013-11-19 # Check if the new import (ie import io instead of cStringIO) # is working correctly #import io as csio # INFO - D.A. - 2013-11-19 # The PIL import is now taken from the pillow # which is the python3 port of PIL # from PIL import Image as pil import tg from tg import expose, flash, require, url, lurl, request, response, redirect, tmpl_context from tg.i18n import ugettext as _, lazy_ugettext as l_ from tg import predicates as tgp from tg.i18n import ugettext as _, lazy_ugettext as l_ from pod.lib.base import BaseController from pod.lib import dbapi as pld from pod.model import data as pmd from pod.model import auth as pma from pod.model import serializers as pms from pod import model as pm from pod.lib.auth import can_read, can_write from pod.controllers import apimenu as pcam FIXME_ERROR_CODE=-1 class PODApiController(BaseController): """Sample controller-wide authorization""" allow_only = tgp.in_group('user', msg=l_('You need to login in order to access this ressource')) menu = pcam.PODApiMenuController() def on_off_to_boolean(self, on_or_off): return True if on_or_off=='on' else False @expose() def create_event(self, parent_id=None, data_label='', data_datetime=None, data_content='', data_reminder_datetime=None, add_reminder=False, inherit_rights='off', **kw): loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) loNewNode = loApiController.createNode(int(parent_id), self.on_off_to_boolean(inherit_rights)) loNewNode.node_type = pmd.PBNodeType.Event loNewNode.data_label = data_label loNewNode.data_content = data_content loNewNode.data_datetime = datetime.strptime(data_datetime, '%d/%m/%Y %H:%M') if add_reminder: loNewNode.data_reminder_datetime = data_reminder_datetime pm.DBSession.flush() redirect(lurl('/document/%i'%(loNewNode.parent_id))) @expose() def create_contact(self, parent_id=None, data_label='', data_content='', inherit_rights='off', **kw): loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) loNewNode = loApiController.createNode(int(parent_id), self.on_off_to_boolean(inherit_rights)) loNewNode.node_type = pmd.PBNodeType.Contact loNewNode.data_label = data_label loNewNode.data_content = data_content pm.DBSession.flush() redirect(lurl('/document/%i'%(loNewNode.parent_id))) @expose() def create_comment(self, parent_id=None, data_label='', data_content='', is_shared='', **kw): loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) loNewNode = loApiController.createNode(int(parent_id), self.on_off_to_boolean(is_shared)) loNewNode.node_type = pmd.PBNodeType.Comment loNewNode.data_label = data_label loNewNode.data_content = data_content if is_shared=='on': loNewNode.is_shared = True pm.DBSession.flush() redirect(lurl('/document/%i'%(loNewNode.parent_id))) @expose() def create_file(self, parent_id=None, data_label='', data_content='', data_file=None, inherit_rights='off', **kw): loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) loNewNode = loApiController.createNode(int(parent_id), self.on_off_to_boolean(inherit_rights)) loNewNode.node_type = pmd.PBNodeType.File loNewNode.data_label = data_label loNewNode.data_content = data_content loNewNode.data_file_name = data_file.filename loNewNode.data_file_mime_type = data_file.type loNewNode.data_file_content = data_file.file.read() pm.DBSession.flush() redirect(lurl('/document/%i'%(loNewNode.parent_id))) @expose() @require(can_read()) def get_file_content(self, node_id=None, **kw): if node_id==None: return else: loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) loFile = loApiController.getNode(node_id) lsContentType = "application/x-download" if loFile.data_file_mime_type!='': tg.response.headers['Content-type'] = str(loFile.data_file_mime_type) tg.response.headers['Content-Type'] = lsContentType tg.response.headers['Content-Disposition'] = str('attachment; filename="%s"'%(loFile.data_file_name)) return loFile.data_file_content @expose() def get_file_content_thumbnail(self, node_id=None, **kw): if node_id==None: return else: loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) loFile = loApiController.getNode(node_id) loJpegBytes = csio.StringIO(loFile.data_file_content) loImage = pil.open(loJpegBytes) loImage.thumbnail([140,140], pil.ANTIALIAS) loResultBuffer = csio.StringIO() loImage.save(loResultBuffer,"JPEG") tg.response.headers['Content-type'] = str(loFile.data_file_mime_type) return loResultBuffer.getvalue() @expose() @require(can_write()) def set_parent_node(self, node_id, new_parent_id, **kw): """ @see reindex_nodes() """ loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) # TODO - D.A. - 2013-11-07 - Check that new parent is accessible by the user !!! loNewNode = loApiController.getNode(node_id) if new_parent_id!='': if new_parent_id==0: new_parent_id = None loNewNode.parent_id = int(new_parent_id) self._updateParentTreePathForNodeAndChildren(loNewNode) pm.DBSession.flush() redirect(lurl('/document/%s'%(node_id))) def _updateParentTreePathForNodeAndChildren(self, moved_node: pmd.PBNode): """ propagate the move to all child nodes and update there node_depth and parent_tree_path properties """ parent_node = moved_node._oParent if parent_node==None: new_parent_tree_path = '/' moved_node.node_depth = 0 else: new_parent_tree_path = '{0}{1}/'.format(parent_node.parent_tree_path, parent_node.node_id) moved_node.node_depth = parent_node.node_depth+1 moved_node.parent_tree_path = new_parent_tree_path for child_node in moved_node._lAllChildren: self._updateParentTreePathForNodeAndChildren(child_node) @expose() @require(can_write()) def move_node_upper(self, node_id=0): loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) loNode = loApiController.getNode(node_id) if loApiController.moveNodeUpper(loNode)==FIXME_ERROR_CODE: flash(_('Document #%s can\'t move upper.')%(node_id)) redirect(lurl('/document/%s'%(node_id))) @expose() @require(can_write()) def move_node_lower(self, node_id=0): loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) loNode = loApiController.getNode(node_id) if loApiController.moveNodeLower(loNode)==FIXME_ERROR_CODE: flash(_('Document #%s can\'t move lower.')%(node_id)) redirect(lurl('/document/%s'%(node_id))) @expose() def create_document(self, parent_id=None, data_label='', data_content='', inherit_rights='off', node_status=''): loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) lsNodeName = 'Document with no name...' if int(parent_id)!=0: loParent = loApiController.getNode(parent_id) lsNodeName = 'Subdocument of (%s)' % loParent.data_label loNewNode = loApiController.createDummyNode(parent_id, self.on_off_to_boolean(inherit_rights)) loNewNode.data_label = lsNodeName loNewNode.data_content = 'insert content...' if data_label!='': loNewNode.data_label = data_label if data_content!='': loNewNode.data_content = data_content if int(parent_id)!=0: loNewNode.parent_id = parent_id if node_status!='': status_item = pmd.PBNodeStatus.getStatusItem(node_status) if status_item in pmd.PBNodeStatus.getChoosableList(): loNewNode.node_status = status_item.status_id pm.DBSession.flush() redirect(lurl('/document/%i'%(loNewNode.node_id))) @expose() @require(can_write()) def edit_status(self, node_id, node_status): loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) loNode = loApiController.getNode(node_id) loNode.node_status = node_status redirect(lurl('/document/%s'%(node_id))) @expose() @require(can_write()) def edit_label_and_content(self, node_id, data_label, data_content): loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) loNode = loApiController.getNode(node_id) loNode.data_label = data_label loNode.data_content = data_content redirect(lurl('/document/%s'%(node_id))) @expose() @require(can_write()) def force_delete_node(self, node_id=None): loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) loNode = loApiController.getNode(node_id) liParentId = loNode.parent_id if loNode.getChildNb()<=0: pm.DBSession.delete(loNode) flash(_('Document #%s has been deleted')%(node_id)) else: flash(_('Document #%s can\'t be deleted because it is not empty.')%(node_id), 'error') redirect(lurl('/document/%s'%(node_id))) redirect(lurl('/document/%i'%(liParentId or 0))) def reindex_nodes(self, back_to_node_id=0): # DA - INFO - 2014-05-26 # # The following query allows to detect which not are not up-to-date anymore. # These up-to-date failure is related to the node_depth and parent_tree_path being out-dated. # This mainly occured when "move node" feature was not working correctly. # # The way to fix the data is the following: # - run mannually the following command # - for each result, call manually /api/set_parent_node?node_id=parent_node_id&new_parent_id=parent_parent_id # sql_query = """ select pn.node_id as child_node_id, pn.parent_id as child_parent_id, pn.parent_tree_path as child_parent_tree_path, pn.node_depth as child_node_depth, pnn.node_id as parent_node_id, pnn.parent_id as parent_parent_id, pnn.parent_tree_path as parent_parent_tree_path, pnn.node_depth as parent_node_depth from pod_nodes as pn, pod_nodes as pnn where pn.parent_id = pnn.node_id and pn.parent_tree_path not like pnn.parent_tree_path||'%' """ return @expose() @require(can_write()) def toggle_share_status(self, node_id): loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) loNode = loApiController.getNode(node_id) if loNode.owner_id==loCurrentUser.user_id: loNode.is_shared = not loNode.is_shared # FIXME - DA. - 2014-05-06 # - if root node, then exception # - this redirect is done in order to be adapted to comment share status toggle redirect(lurl('/document/%s#tab-comments'%(loNode._oParent.node_id))) @expose() @require(can_write()) def set_access_management(self, node_id, is_shared='off', read=[0], write=[0]): llReadAccessGroupIds = [int(liGroupId) for liGroupId in read] llWriteAccessGroupIds = [int(liGroupId) for liGroupId in write] # HACK - D.A. - 2015-058-20 # the 0 values are added in order to get a read and write parameters as list even if only one value is inside # (the default behavior of TG2 is to convert it to a string value if only one value is sent # llReadAccessGroupIds.remove(0) # remove useless value llWriteAccessGroupIds.remove(0) # remove useless value loCurrentUser = pld.PODStaticController.getCurrentUser() loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id) loNode = loApiController.getNode(node_id) is_shared_b = False if is_shared=='off' else True # Only the node owner can modify is_shared if is_shared_b != loNode.is_shared and loNode.owner_id != loCurrentUser.user_id: self.back_with_error(_("You can't share a document that doesn't belong to you.")) else: loNode.is_shared = is_shared_b if not is_shared_b: # SHARE IS OFF, so deactivate the document share (and do not change "shared-with" group configuration pm.DBSession.flush() redirect(lurl('/document/%s#tab-accessmanagement'%(loNode.node_id))) # remove all current shares and set the new ones for loRight in loNode._lRights: pm.DBSession.delete(loRight) pm.DBSession.flush() ldNewRights = dict() for liGroupId in llReadAccessGroupIds: ldNewRights[liGroupId] = pma.Rights.READ_ACCESS for liGroupId in llWriteAccessGroupIds: liOldValue = 0 if liGroupId in ldNewRights: liOldValue = ldNewRights[liGroupId] ldNewRights[liGroupId] = liOldValue + pma.Rights.WRITE_ACCESS user_list = loApiController._getUserIdListForFiltering() comments = pm.DBSession.query(pmd.PBNode).filter(pmd.PBNode.parent_id==node_id).\ filter((pmd.PBNode.owner_id.in_(user_list)) | (pma.user_group_table.c.user_id.in_(user_list))).\ filter(pmd.PBNode.node_type=='comment').all() for comment in comments: pm.DBSession.add(comment) for liGroupId, liRightLevel in ldNewRights.items(): loNewRight = loApiController.createRight() loNewRight.group_id = liGroupId loNewRight.node_id = node_id loNewRight.rights = liRightLevel loNode._lRights.append(loNewRight) for comment in comments: comment_right = loApiController.createRight() comment_right.group_id = liGroupId comment_right.node_id = comment.node_id comment_right.rights = liRightLevel redirect(lurl('/document/%s#tab-accessmanagement'%(loNode.node_id)))