diff --git a/opt - Acceso directo.lnk b/opt - Acceso directo.lnk old mode 100644 new mode 100755 diff --git a/pibiapp/hooks.py b/pibiapp/hooks.py index 716a78f..fc2d2ae 100755 --- a/pibiapp/hooks.py +++ b/pibiapp/hooks.py @@ -89,7 +89,9 @@ doc_events = { "File": { + "before_insert": "pibiapp.nextcloud.nextcloud_link.nextcloud_before_insert", "after_insert": "pibiapp.nextcloud.nextcloud_link.nextcloud_insert", + "on_trash": "pibiapp.nextcloud.nextcloud_link.nextcloud_before_delete", "after_delete": "pibiapp.nextcloud.nextcloud_link.nextcloud_delete" } } diff --git a/pibiapp/nextcloud/nextcloud_apis.py b/pibiapp/nextcloud/nextcloud_apis.py index 6c743b6..65bc786 100755 --- a/pibiapp/nextcloud/nextcloud_apis.py +++ b/pibiapp/nextcloud/nextcloud_apis.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018, Dolores Juliana Fdez Martin +# Copyright (c) 2018-2019, Dolores Juliana Fdez Martin # License: GNU General Public License v3. See license.txt # # This file is part of Pibiapp_Nextcloud. @@ -110,7 +110,7 @@ def mkdirs(self, nc_path): self.cd(old_cwd) def delete(self, path): - self.command('DELETE', path, 204) + self.command('DELETE', path, (204, 404)) def upload(self, local_fileobj, remote_fileobj, nc_path="." ): if nc_path != ".": @@ -155,7 +155,36 @@ def gettag(self, idtag): return root[0][1][0][0].text else: return '' - + + def deletetags(self, idfile, nodelete): + method='PROPFIND' + url = self.baseurl.replace("webdav","dav") + "/systemtags-relations/files/" + str(idfile) + headers = {"Content-Type": "text/xml" } + fullpath = os.path.realpath(__file__).replace("nextcloud_apis.py","tagpropfind.xml") + fullpath = fullpath.replace('xmlc','xml') + xmlfile = open(fullpath,"r") + data = xmlfile.read() + xmlfile.close() + response = self.session.request(method, url, headers=headers, data=data, allow_redirects=False) + if response.status_code >= 400: return '' + root = ET.fromstring(response.content) + i = 1 + while i < len(root): + tag = root[i][1][0][0].text + if not tag in nodelete: + idtag = root[i][1][0][3].text + status_code = self.deletetag(idfile, idtag) + if status_code >= 400: break + i += 1 + return + + def deletetag(self, idfile, idtag): + method='DELETE' + url = self.baseurl.replace("webdav","dav") + "/systemtags-relations/files/" + str(idfile) + "/" + str(idtag) + headers = {"Content-Type": "text/xml" } + response = self.session.request(method, url, headers=headers) + return response.status_code + class OCS(): def __init__(self, ncurl, user, passwd, js=False): self.tojs = "?format=json" if js else "" @@ -213,7 +242,7 @@ def addGroup(self,gid): return self.post(url,msg) def createShare(self,path,shareType,shareWith=None,publicUpload=None,password=None,permissions=None): - url = self.Share_url + "/shares"+self.tojs + url = self.Share_url + "/shares" + self.tojs if publicUpload == True: publicUpload = "true" if (path == None or isinstance(shareType, int) != True) or (shareType in [0,1] and shareWith == None): return False msg = {"path":path,"shareType":shareType} diff --git a/pibiapp/nextcloud/nextcloud_link.py b/pibiapp/nextcloud/nextcloud_link.py index 05e4b80..0860c4c 100755 --- a/pibiapp/nextcloud/nextcloud_link.py +++ b/pibiapp/nextcloud/nextcloud_link.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018, Dolores Juliana Fdez Martin +# Copyright (c) 2018-2019, Dolores Juliana Fdez Martin # License: GNU General Public License v3. See license.txt # # This file is part of Pibiapp_Nextcloud. @@ -23,10 +23,12 @@ import requests from json import dumps from frappe.modules.utils import get_doctype_module, get_module_app +from frappe.desk.tags import DocTags from pibiapp.nextcloud import nextcloud_apis import json import os import time +import sys class nextcloud_link(): def __init__(self): @@ -56,13 +58,9 @@ def __init__(self): def tagging(self, doc, idfile, relational): self.actualizetags() - doctype = doc.attached_to_doctype - module = get_doctype_module(doctype) - name = doc.attached_to_name - self.puttag( doctype, idfile) - self.puttag( module, idfile) - self.puttag( name, idfile) - if relational: self.relationaltags(doctype, name, idfile) + lista = self.listtags(doc, idfile, relational) + for display_name in lista: + self.puttag( display_name, idfile) def puttag(self, display_name, idfile): idtag = self.searchtag( display_name) @@ -107,68 +105,150 @@ def inserttag(self, idtag, display_name): def relationaltags(self, doctype, name, idfile): docntrans = frappe.get_doc(doctype, name) meta = frappe.get_meta(doctype) + lista = "" for lf in meta.get_link_fields(): - name = docntrans.get(lf.fieldname) - if name != "" and name != None: - self.puttag( name, idfile) + tag = docntrans.get(lf.fieldname) + if tag != "" and tag != None: + lista = lista + " # " + tag + lista = lista + DocTags(doctype).get_tags(name).replace("," , " # ") + return lista + + def deletetags(self, doc, idfile, relational=True): + lista = self.listtags(doc, idfile, relational) + status_code = self.webdav.deletetags(idfile, nodelete=lista) + + def listtags(self, doc, idfile, relational): + doctype = doc.attached_to_doctype + module = get_doctype_module(doctype) + name = doc.attached_to_name + lista = doctype + " # " + module + " # " + name + if relational: lista = lista + self.relationaltags(doctype, name, idfile) + return lista.split(" # ") + + def shareModule(self, doc): + # add group for module + data_json = doc.nc.ocs.getGroup(doc.nc.module) + data_string = json.dumps(data_json) + decoded = json.loads(data_string) + isgroup = str(decoded["ocs"]["meta"]["statuscode"]) + if isgroup == '404': + data_json = doc.nc.ocs.addGroup(doc.nc.module) + # add Share group in Nextcloud + shareType = 1 + permit = 1 + data_json = doc.nc.ocs.createShare(doc.nc.pathglobal,shareType,shareWith=doc.nc.module,publicUpload=True,password=None,permissions=permit) + return data_json + @frappe.whitelist() -def nextcloud_insert(doc, method=None): +def nextcloud_before_insert(doc, method=None): + doc.flags.ignore_nc = True nc = nextcloud_link() if not nc.isconnect: return + doc.flags.ignore_file_validate = True doctype = doc.attached_to_doctype module = get_doctype_module(doctype) # Excluded module if module in nc.excludedmodules: return + # File previously attached to another transaction + if not doc.file_name or doc.file_name == None: return + if " NC/f/" in doc.file_name: return + doc.flags.ignore_nc = False site = frappe.local.site if doc.is_private: local_fileobj = "./" + site + doc.file_url else: local_fileobj = "./" + site + "/public" + doc.file_url fileobj = local_fileobj.split('/') uu = len(fileobj) - 1 - # get path - app = get_module_app(module) - path = nc.initialpath + "/" + app + "/" + module + "/" + doctype - pathglobal = path + "/" + fileobj[uu] + doc.nc = nc + doc.nc.module = module + doc.nc.app = get_module_app(module) + doc.nc.path = nc.initialpath + "/" + doc.nc.app + "/" + module + "/" + doctype + doc.nc.pathglobal = doc.nc.path + "/" + fileobj[uu] + doc.nc.local_fileobj = local_fileobj + doc.nc.remote_fileobj=fileobj[uu] + + +@frappe.whitelist() +def nextcloud_insert(doc, method=None): + if doc.flags.ignore_nc: return # upload to nextcloud - nc.webdav.upload(local_fileobj, remote_fileobj=fileobj[uu], nc_path=path) - # add group for module - data_json = nc.ocs.getGroup(module) - data_string = json.dumps(data_json) - decoded = json.loads(data_string) - isgroup = str(decoded["ocs"]["meta"]["statuscode"]) - if isgroup == '404': - data_json = nc.ocs.addGroup(module) - # add Share group in Nextcloud - shareType = 1 - permit = 1 - data_json = nc.ocs.createShare(pathglobal,shareType,shareWith=module,publicUpload=True,password=None,permissions=permit) + if not "http" in doc.nc.local_fileobj: + doc.nc.webdav.upload(local_fileobj=doc.nc.local_fileobj, remote_fileobj=doc.nc.remote_fileobj, nc_path=doc.nc.path) + else: + data = frappe.db.get_value("File", {"file_url": doc.file_url , "file_name": ["like", "%NC/f/%"]}, ["attached_to_doctype", "name", "file_name"], as_dict=True) + if data: + if doc.attached_to_doctype != data.attached_to_doctype: + doctype = data.attached_to_doctype + module = get_doctype_module(doctype) + app = get_module_app(module) + doc.nc.pathglobal = doc.nc.initialpath + "/" + app + "/" + module + "/" + doctype + "/" + doc.file_name + data_json = doc.nc.shareModule(doc) + fname = data.file_name.replace(" NC/f/","#") + doc.file_name = fname.split("#")[0] + " NC(" + data.name + ")/f/" + fname.split("#")[1] + doc.save() + return + data_json = doc.nc.shareModule(doc) # add public Share in Nextcloud - if nc.sharepublic or doc.is_private == False: + if doc.nc.sharepublic or doc.is_private == False: shareType = 3 - data_json = nc.ocs.createShare(pathglobal,shareType) + data_json = doc.nc.ocs.createShare(doc.nc.pathglobal,shareType) if data_json == "": time.sleep(2) - data_json = nc.ocs.createShare(pathglobal,shareType) + data_json = doc.nc.ocs.createShare(doc.nc.pathglobal,shareType) data_string = json.dumps(data_json) decoded = json.loads(data_string) - fileid = str(decoded["ocs"]["data"]["file_source"]) - if nc.sharepublic or doc.is_private == False: + try: + fileid = str(decoded["ocs"]["data"]["file_source"]) + except TypeError: + fname = frappe.db.get_value("File", {"file_name": ["like", doc.file_name + " NC/f/%"]}, "name") + docorigin = frappe.get_doc('File', str(fname)) + if docorigin: + docorigin.content_hash = doc.content_hash + docorigin.flags.ignore_file_validate = True + docorigin.save() + if doc.nc.enabletagging: + fileid = str(docorigin.file_name.replace(" NC/f/","#").split("#")[1]) + doc.nc.deletetags(docorigin, fileid, relational=doc.nc.relationaltagging) + doc.nc.tagging(docorigin, fileid, relational=doc.nc.relationaltagging) + os.remove(doc.nc.local_fileobj) + doc.delete() + frappe.db.commit() + sys.exit() + if doc.nc.sharepublic or doc.is_private == False: urllink = str(decoded["ocs"]["data"]["url"]) else: - urllink = nc.url + "/f/" + fileid + urllink = doc.nc.url + "/f/" + fileid # update doctype file if urllink != None and urllink != "": doc.file_url = urllink doc.file_name = doc.file_name + " NC/f/" + fileid doc.save() - # delete local file - os.remove(local_fileobj) + # delete local file + os.remove(doc.nc.local_fileobj) # tagging - if nc.enabletagging: nc.tagging(doc, fileid, relational=nc.relationaltagging) + if doc.nc.enabletagging: doc.nc.tagging(doc, fileid, relational=doc.nc.relationaltagging) +@frappe.whitelist() +def nextcloud_before_delete(doc, method=None): + doc.flags.ignore_nc = True + nc = nextcloud_link() + if not nc.isconnect: return + doc.flags.ignore_file_validate = True + doctype = doc.attached_to_doctype + module = get_doctype_module(doctype) + # Excluded module + if module in nc.excludedmodules: return + # File previously attached to another transaction + if not doc.file_name or doc.file_name == None: return + if not " NC/f/" in doc.file_name: return + doc.flags.ignore_nc = False + data = frappe.db.get_value("File", {"file_url": doc.file_url , "file_name": ["like", "%NC(%"]}, ["attached_to_doctype", "attached_to_name"], as_dict=True) + if data: + frappe.throw(_("The file can not be deleted while it is related to this transaction: {0} {1}").format(data.attached_to_doctype, data.attached_to_name)) @frappe.whitelist() def nextcloud_delete(doc, method=None): + if doc.flags.ignore_nc: return nc = nextcloud_link() if not nc.isconnect: return doctype = doc.attached_to_doctype