├── .gitignore ├── MANIFEST.in ├── README.md ├── license.txt ├── pibidav ├── __init__.py ├── config │ ├── __init__.py │ ├── desktop.py │ └── docs.py ├── fixtures │ ├── custom_field.json │ └── workspace.json ├── hooks.py ├── jinja.py ├── modules.txt ├── patches.txt ├── pibidav │ ├── __init__.py │ ├── custom.py │ ├── doctype │ │ ├── __init__.py │ │ ├── attachment_item │ │ │ ├── __init__.py │ │ │ ├── attachment_item.json │ │ │ └── attachment_item.py │ │ ├── file_category │ │ │ ├── __init__.py │ │ │ ├── file_category.js │ │ │ ├── file_category.json │ │ │ ├── file_category.py │ │ │ └── test_file_category.py │ │ ├── folder_set │ │ │ ├── __init__.py │ │ │ ├── folder_set.js │ │ │ ├── folder_set.json │ │ │ ├── folder_set.py │ │ │ ├── folder_set_tree.js │ │ │ └── test_folder_set.py │ │ ├── nextcloud_settings │ │ │ ├── __init__.py │ │ │ ├── nextcloud_settings.js │ │ │ ├── nextcloud_settings.json │ │ │ ├── nextcloud_settings.py │ │ │ └── test_nextcloud_settings.py │ │ ├── pibidav_addon │ │ │ ├── __init__.py │ │ │ ├── pibidav_addon.js │ │ │ ├── pibidav_addon.json │ │ │ ├── pibidav_addon.py │ │ │ └── test_pibidav_addon.py │ │ └── reference_item │ │ │ ├── __init__.py │ │ │ ├── reference_item.json │ │ │ └── reference_item.py │ ├── nextcloud.py │ └── workspace │ │ ├── pibidav │ │ └── pibidav.json │ │ └── pibitools │ │ └── pibitools.json ├── public │ ├── dist │ │ └── js │ │ │ ├── nc_browser.bundle.ZRBKKNDW.js │ │ │ ├── nc_browser.bundle.ZRBKKNDW.js.map │ │ │ ├── pibidav.bundle.VLVM6LDX.js │ │ │ └── pibidav.bundle.VLVM6LDX.js.map │ ├── icons │ │ └── timeless │ │ │ └── icons.svg │ ├── image │ │ ├── background.png │ │ ├── favicon.svg │ │ └── pibiCo_engine_largo.png │ └── js │ │ ├── dist │ │ ├── nc_browser │ │ │ ├── NcBrowser.vue │ │ │ ├── TreeNode.vue │ │ │ └── nc_browser.bundle.js │ │ ├── nc_pibidav.js │ │ └── nc_upload.js │ │ └── pibidav.bundle.js ├── templates │ ├── __init__.py │ └── pages │ │ └── __init__.py ├── translations │ └── es.csv └── www │ └── __init__.py ├── requirements.txt └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.egg-info 4 | *.swp 5 | tags 6 | pibidav/docs/current -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in 2 | include requirements.txt 3 | include *.json 4 | include *.md 5 | include *.py 6 | include *.txt 7 | recursive-include pibidav *.css 8 | recursive-include pibidav *.csv 9 | recursive-include pibidav *.html 10 | recursive-include pibidav *.ico 11 | recursive-include pibidav *.js 12 | recursive-include pibidav *.json 13 | recursive-include pibidav *.md 14 | recursive-include pibidav *.png 15 | recursive-include pibidav *.py 16 | recursive-include pibidav *.svg 17 | recursive-include pibidav *.txt 18 | recursive-exclude pibidav *.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## pibiDAV 2 | pibiDAV is a Frappe App to integrate webDAV with a NextCloud Server, used as (DMS), for a copy of Frappe Files uploaded and tagged to NextCloud while uploading files to Frappe. 3 | ## License 4 | MIT# pibiDAV 5 | ## Requirements 6 | Requires a Frappe server instance (refer to https://github.com/frappe/frappe). It also uses a tweaked code of pyocclient but this is embedded already in pibiDAV. 7 | ## Compatibility 8 | PibiDAV branch version-15 is dedicated for Frappe/ERPNext version-15 only. 9 | ## Installation 10 | From the frappe-bench folder, execute 11 | ``` 12 | $ bench get-app pibidav --branch version-15 https://github.com/pibico/pibidav.git 13 | $ bench install-app pibidav 14 | ``` 15 | If you are using a multi-tenant environment, use the following command 16 | ``` 17 | $ bench --site site_name install-app pibidav 18 | ``` 19 | ## Features 20 | Once is installed, be aware that you will need to set **developer_mode = 1** on your site_config.json file. Also it is a must to have SSL active in both servers Frappe and NextCloud with specific certificates (wildcard *.domain.com* certificates are not valid for this integration). Letsencrypt Certificates are valid for both servers. 21 | This integration app is prepared for including specific and custom doctypes to upload its attachments to NextCloud at the same time than to Frappe. There is a new frappe.ui.component dialog based on vue.js and called frappe.ui.pibiDocs where to draw the NextCloud Tree and select the destination NextCloud Directory to upload the files. 22 | ### 1. Credentials for NextCloud SuperUser, Backup and DocTypes to Integrate with NextCloud 23 | PibiCo works on NextCloud making the Main Company Folders Superestructure as a shared folder from this NextCloud SuperUser that should be a System Manager on Frappe also. Let's explain with some pictures. 24 | ![NC_FolderStructure_Shared_from_SuperUser](https://user-images.githubusercontent.com/69711454/165801352-b4a14016-b360-41ea-9a2c-050ea589580f.JPG) 25 | This Folder Superstructure has children at different levels and are shared with different groups or users also at different level, thus giving access to these folders and below (both user internal to Company or External such as Customers or Suppliers). 26 | ![imagen](https://user-images.githubusercontent.com/69711454/165802115-275c6234-77f5-43fa-b2aa-a1f3942e4693.png) 27 | At this point, let's go to Frappe Server and once logged-in as System Manager or Administrator we'll go to module pibiDAV on side menu, and on Settings Card we'll choose NextCloud Settings. 28 | ![pibiDav_NC_SuperUser_Credentials_and_Settings](https://user-images.githubusercontent.com/69711454/165805974-23fcec72-04c6-4f4e-9ff0-eba250862fb5.JPG) 29 | Once there, we'll activate the NextCloud Enable checkbox (valid also for backup) and fill the credentials of the NextCloud SuperUser in the input fields. 30 | ![imagen](https://user-images.githubusercontent.com/69711454/168047648-0c131b17-ba4e-4f77-af4e-8207d0050159.png) 31 | We can check that our credentials are correct clicking on NC commands button on upper right side of the screen. 32 | ![imagen](https://user-images.githubusercontent.com/69711454/165807198-41a41df3-9a6e-447f-96fa-5ee2040190c2.png) 33 | Now, automatic uploading of frappe backup is enabled and will be uploaded to the destination folder as given in the backups details section. Frappe Backups files are renamed on NextCloud to files beginning by a number that is the weekday of the backup files, as shown in the picture. So, we will have always the last backup and also all the ancient backups for this weekday as versions in NextCloud, as shown in the picture 34 | ![imagen](https://user-images.githubusercontent.com/69711454/165808672-33278ca8-1776-4cb4-bd0e-50ad273aa9e0.png) 35 | It's time now of telling to Frappe which doctypes will be integrated to upload its attachments to NextCloud once they are uploaded in Frappe. This is done on the same NextCloud Settings, but on Settings Section, choosing the Frappe Doctype in the table and also giving the DocFields in that DocType that will be used to Tag Automatically the Files on Frappe and On NextCloud as well. We will choose the Sales Invoice Doctype as an example for this configuration. In this case, we will tag the files with the name, the customer and the tax_id from the customer, but whichever field in the doctype, even custom fields are valid. 36 | ![imagen](https://user-images.githubusercontent.com/69711454/168048312-ecb71229-8937-4fe3-bfe2-fdcac6dd5fc1.png) 37 | ### 2. Credentials for each Frappe User to Use his NextCloud Account Credentials 38 | To get the permissions from NextCloud into Frappe we will fill the User NextCloud Credentials on Frappe User Settings. We'll go through the user settings and will select the Role NextCloud User first. 39 | ![imagen](https://user-images.githubusercontent.com/69711454/165817057-d765dd68-ae4f-4ab9-9edf-2fa438a0d012.png) 40 | After that we will go at the bottom of de User Settings Form to provide the NextCloud User Credentials. In this example is the System Manager or Administrator having the SuperUser NextCloud Credentials for having access to the full NextCloud Folder SuperStructure. 41 | ![imagen](https://user-images.githubusercontent.com/69711454/165817406-eeb6fc05-3fa7-4e14-8798-3712c4a2b26c.png) 42 | ### 3. Hooks for NextCloud Integration 43 | Provided we have access to the frappe-bench folder, we must hook the Doctypes included in the integration, by adding the following code to hooks.py of pibidav app: 44 | ``` 45 | # doctype_calendar_js = {"doctype" : "public/js/doctype_calendar.js"} 46 | 47 | nc_list = ["Customer","Project","Sales Invoice","Purchase Invoice","Supplier","Event"] 48 | doctype_js = {} 49 | for item in nc_list: 50 | doctype_js[item] = "public/js/dist/nc_pibidav.js" 51 | 52 | # Home Pages 53 | # ---------- 54 | ``` 55 | In nc_list variable, we will include whichever doctype to integrate with NextCloud. 56 | #### 2.1 PibiDAV Addon DocType 57 | This new DocType is an extension of existing DocTypes to fill with data given by Attchments, Folders, etc. related to NextCloud and based on its referenced doctype. It is somehow a parallel sheet with data only related to NextCloud Functionalities. It is filled automatically from the different actions derived from NC buttons. 58 | ![imagen](https://user-images.githubusercontent.com/69711454/168050089-1f6a7f44-52a8-4d27-ae64-2c94775a17f3.png) 59 | ### 4. The magic of the NextCloud Integration inside Frappe 60 | It's time now to try the integration of the NextCloud Folder Structure from Frappe to choose the NC Destination Folder of our uploaded files (except website urls). 61 | Let's go to a doctype of the NC Integration List, i.e. a Sales Invoice. On this core doctype, we'll have two new buttons, for enabling NC and for getting the browser dialog to choose the NC destination folder. 62 | ![imagen](https://user-images.githubusercontent.com/69711454/168051235-2f762d9e-30a4-476e-83c8-e8345ca2dd4f.png) 63 | First of all, we must enable the NC Integration, clicking on Enable NC button. With this action we will generate the pbc_sales_invoice doctype parallel to our sales invoice (same name with 'pbc_' before it). 64 | ![imagen](https://user-images.githubusercontent.com/69711454/168051867-32eeaeda-0d05-4525-935f-b464a6cb7a06.png) 65 | We can check the created Addon clicking on the Check Addon Button. And return to the sales invoice clicking on the ref_docname on the addon. 66 | ![imagen](https://user-images.githubusercontent.com/69711454/168052040-b623d8ef-7d4c-4135-8497-ba412e730023.png) 67 | After having saved the original Sales Invoice as draft we can select the NextCloud Destination Folder for our attachments by clicking on the NC Commands Button and selecting Select NC Folder to bring the pop-up dialog for browsing and selecting our NC Folder. 68 | ![imagen](https://user-images.githubusercontent.com/69711454/168052743-ac2bec03-915e-47de-82a7-2e62996b1d64.png) 69 | When we select the NextCloud Destination Folder in the dialog, this folder path will be filled in our addon text nc_folder field to remember the destination till it is changed by a new selection. 70 | While we keep this destination folder, all the attachments uploaded to the Sales Invoice will be also uploaded to NextCloud to this folder. Let's create the pdf from the Sales Invoice, signed electronically outside Frappe and uploaded again as attachment in Frappe/ERPNext 71 | ![imagen](https://user-images.githubusercontent.com/69711454/165823914-8dd352e1-69ce-4698-851e-33f53dadb3e2.png) 72 | We have uploaded the attachment to Frappe/ERPNext as shown in the picture 73 | ![imagen](https://user-images.githubusercontent.com/69711454/165824171-d145445b-9c87-4740-b48d-494ef116c26b.png) 74 | Let's Check if it has been also uploaded to NextCloud on the PBC > Customer > Client > Invoices > 2022 as selected. 75 | ![imagen](https://user-images.githubusercontent.com/69711454/165824625-0d650e18-0c94-4c9e-be7e-7577b1d10968.png) 76 | Looking for details we see the pdf file Sales Invoice uploaded in NextCloud Destination, but also it has been created a shared public Link, tagged with customer, tax_id, doctype and name as we defined in the Settings. Voilà, first integration achieved. Let's check the File uploaded to Frappe, it has all metadata from NextCloud as well, and also has some frappe tags also automatically filled on the upload. 77 | ![imagen](https://user-images.githubusercontent.com/69711454/165825969-f883e0d4-b415-4eba-9885-16ed92073276.png) 78 | ### 5. Create folder structures in NextCloud from template Folder Sets in Frappe. 79 | Another possible integration is through a Folder Set Doctype Tree integrated in pibiDav. Folder Set is a Doctype for making Folder Structures taken as templates for recreating them in the NextCloud Instance from a destination folder as root. Let's see in action, once we have the template folder set created in Frappe. We can select the root folder and enable the nc_enable check and select the destination folder in NextCloud where to recreate this structure, renaming the folders in NextCloud upon its creation. 80 | ![imagen](https://user-images.githubusercontent.com/69711454/165839794-602f4e5c-3e7d-4350-9a12-fa16c31bb75b.png) 81 | We select the destination folder in NextCloud browsing in the dialog. 82 | ![imagen](https://user-images.githubusercontent.com/69711454/165840960-bb937ec7-9b2b-491d-94b4-4d9df0374c8e.png) 83 | And once selected the destination folder, on the tree we click on button Recreate to perform the copy of folders from Frappe to NextCloud. 84 | ![imagen](https://user-images.githubusercontent.com/69711454/165841213-d50cd3e1-089e-4106-a997-c9188a2eeef0.png) 85 | The result is seen on the image for a new Client Structure called CUSTOMER as abbreviation and Customer Name Details as Description for the Folder. 86 | ![imagen](https://user-images.githubusercontent.com/69711454/165841463-62829c06-e4f6-4e13-ae3e-49d5bbe67fee.png) 87 | ![imagen](https://user-images.githubusercontent.com/69711454/165841656-f5b458d8-b15d-47ff-8738-bafe8c5bd08a.png) 88 | 89 | There is an automation to make automatic folders upon creation of selected included doctypes, but try to see if you can make it running. This is an Easter Egg for you to discover. 90 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | License: MIT -------------------------------------------------------------------------------- /pibidav/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | __version__ = '0.0.1' 3 | 4 | -------------------------------------------------------------------------------- /pibidav/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pibico/pibiDAV/660caffafd274f1dcf6c42024d5f67bccd5c8509/pibidav/config/__init__.py -------------------------------------------------------------------------------- /pibidav/config/desktop.py: -------------------------------------------------------------------------------- 1 | from frappe import _ 2 | 3 | def get_data(): 4 | return [ 5 | { 6 | "module_name": "Pibidav", 7 | "color": "grey", 8 | "icon": "octicon octicon-file-directory", 9 | "type": "module", 10 | "label": _("Pibidav") 11 | } 12 | ] 13 | -------------------------------------------------------------------------------- /pibidav/config/docs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Configuration for docs 3 | """ 4 | 5 | # source_link = "https://github.com/[org_name]/pibidav" 6 | # docs_base_url = "https://[org_name].github.io/pibidav" 7 | # headline = "App that does everything" 8 | # sub_heading = "Yes, you got that right the first time, everything" 9 | 10 | def get_context(context): 11 | context.brand_html = "Pibidav" 12 | -------------------------------------------------------------------------------- /pibidav/fixtures/custom_field.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "allow_in_quick_entry": 0, 4 | "allow_on_submit": 0, 5 | "bold": 0, 6 | "collapsible": 0, 7 | "collapsible_depends_on": null, 8 | "columns": 0, 9 | "default": null, 10 | "depends_on": null, 11 | "description": null, 12 | "docstatus": 0, 13 | "doctype": "Custom Field", 14 | "dt": "Tag", 15 | "fetch_from": null, 16 | "fetch_if_empty": 0, 17 | "fieldname": "uploaded_to_nextcloud", 18 | "fieldtype": "Check", 19 | "hidden": 0, 20 | "hide_border": 0, 21 | "hide_days": 0, 22 | "hide_seconds": 0, 23 | "ignore_user_permissions": 0, 24 | "ignore_xss_filter": 0, 25 | "in_global_search": 0, 26 | "in_list_view": 0, 27 | "in_preview": 0, 28 | "in_standard_filter": 0, 29 | "insert_after": "description", 30 | "is_system_generated": 0, 31 | "is_virtual": 0, 32 | "label": "Uploaded To NextCloud", 33 | "length": 0, 34 | "link_filters": null, 35 | "mandatory_depends_on": null, 36 | "modified": "2022-04-27 09:01:18.884151", 37 | "module": "Pibidav", 38 | "name": "Tag-uploaded_to_nextcloud", 39 | "no_copy": 0, 40 | "non_negative": 0, 41 | "options": null, 42 | "permlevel": 0, 43 | "placeholder": null, 44 | "precision": "", 45 | "print_hide": 0, 46 | "print_hide_if_no_value": 0, 47 | "print_width": null, 48 | "read_only": 1, 49 | "read_only_depends_on": null, 50 | "report_hide": 0, 51 | "reqd": 0, 52 | "search_index": 0, 53 | "show_dashboard": 0, 54 | "sort_options": 0, 55 | "translatable": 0, 56 | "unique": 0, 57 | "width": null 58 | }, 59 | { 60 | "allow_in_quick_entry": 0, 61 | "allow_on_submit": 0, 62 | "bold": 0, 63 | "collapsible": 0, 64 | "collapsible_depends_on": null, 65 | "columns": 0, 66 | "default": null, 67 | "depends_on": null, 68 | "description": null, 69 | "docstatus": 0, 70 | "doctype": "Custom Field", 71 | "dt": "Tag", 72 | "fetch_from": null, 73 | "fetch_if_empty": 0, 74 | "fieldname": "tagid", 75 | "fieldtype": "Data", 76 | "hidden": 0, 77 | "hide_border": 0, 78 | "hide_days": 0, 79 | "hide_seconds": 0, 80 | "ignore_user_permissions": 0, 81 | "ignore_xss_filter": 0, 82 | "in_global_search": 0, 83 | "in_list_view": 0, 84 | "in_preview": 0, 85 | "in_standard_filter": 0, 86 | "insert_after": "uploaded_to_nextcloud", 87 | "is_system_generated": 0, 88 | "is_virtual": 0, 89 | "label": "TagId", 90 | "length": 0, 91 | "link_filters": null, 92 | "mandatory_depends_on": null, 93 | "modified": "2022-04-27 09:01:08.998367", 94 | "module": "Pibidav", 95 | "name": "Tag-tagid", 96 | "no_copy": 0, 97 | "non_negative": 0, 98 | "options": null, 99 | "permlevel": 0, 100 | "placeholder": null, 101 | "precision": "", 102 | "print_hide": 0, 103 | "print_hide_if_no_value": 0, 104 | "print_width": null, 105 | "read_only": 1, 106 | "read_only_depends_on": null, 107 | "report_hide": 0, 108 | "reqd": 0, 109 | "search_index": 0, 110 | "show_dashboard": 0, 111 | "sort_options": 0, 112 | "translatable": 0, 113 | "unique": 0, 114 | "width": null 115 | }, 116 | { 117 | "allow_in_quick_entry": 0, 118 | "allow_on_submit": 0, 119 | "bold": 0, 120 | "collapsible": 0, 121 | "collapsible_depends_on": null, 122 | "columns": 0, 123 | "default": null, 124 | "depends_on": null, 125 | "description": null, 126 | "docstatus": 0, 127 | "doctype": "Custom Field", 128 | "dt": "Supplier", 129 | "fetch_from": null, 130 | "fetch_if_empty": 0, 131 | "fieldname": "nextcloud", 132 | "fieldtype": "Link", 133 | "hidden": 0, 134 | "hide_border": 0, 135 | "hide_days": 0, 136 | "hide_seconds": 0, 137 | "ignore_user_permissions": 0, 138 | "ignore_xss_filter": 0, 139 | "in_global_search": 0, 140 | "in_list_view": 0, 141 | "in_preview": 0, 142 | "in_standard_filter": 0, 143 | "insert_after": "pb_abbreviation", 144 | "is_system_generated": 0, 145 | "is_virtual": 0, 146 | "label": "Nextcloud", 147 | "length": 0, 148 | "link_filters": null, 149 | "mandatory_depends_on": null, 150 | "modified": "2024-12-06 21:59:37.115047", 151 | "module": "Pibidav", 152 | "name": "Supplier-custom_pd_nextcloud", 153 | "no_copy": 0, 154 | "non_negative": 0, 155 | "options": "PibiDAV Addon", 156 | "permlevel": 0, 157 | "placeholder": null, 158 | "precision": "", 159 | "print_hide": 0, 160 | "print_hide_if_no_value": 0, 161 | "print_width": null, 162 | "read_only": 0, 163 | "read_only_depends_on": null, 164 | "report_hide": 0, 165 | "reqd": 0, 166 | "search_index": 0, 167 | "show_dashboard": 0, 168 | "sort_options": 0, 169 | "translatable": 0, 170 | "unique": 0, 171 | "width": null 172 | }, 173 | { 174 | "allow_in_quick_entry": 0, 175 | "allow_on_submit": 1, 176 | "bold": 0, 177 | "collapsible": 0, 178 | "collapsible_depends_on": null, 179 | "columns": 0, 180 | "default": null, 181 | "depends_on": null, 182 | "description": null, 183 | "docstatus": 0, 184 | "doctype": "Custom Field", 185 | "dt": "Customer", 186 | "fetch_from": null, 187 | "fetch_if_empty": 0, 188 | "fieldname": "pb_abbreviation", 189 | "fieldtype": "Data", 190 | "hidden": 0, 191 | "hide_border": 0, 192 | "hide_days": 0, 193 | "hide_seconds": 0, 194 | "ignore_user_permissions": 0, 195 | "ignore_xss_filter": 0, 196 | "in_global_search": 1, 197 | "in_list_view": 1, 198 | "in_preview": 0, 199 | "in_standard_filter": 1, 200 | "insert_after": "customer_group", 201 | "is_system_generated": 0, 202 | "is_virtual": 0, 203 | "label": "Abbreviation", 204 | "length": 0, 205 | "link_filters": null, 206 | "mandatory_depends_on": null, 207 | "modified": "2024-12-06 17:30:57.212078", 208 | "module": "Pibidav", 209 | "name": "Customer-custom_pb_abbreviation", 210 | "no_copy": 0, 211 | "non_negative": 0, 212 | "options": null, 213 | "permlevel": 0, 214 | "placeholder": null, 215 | "precision": "", 216 | "print_hide": 0, 217 | "print_hide_if_no_value": 0, 218 | "print_width": null, 219 | "read_only": 0, 220 | "read_only_depends_on": null, 221 | "report_hide": 0, 222 | "reqd": 1, 223 | "search_index": 0, 224 | "show_dashboard": 0, 225 | "sort_options": 0, 226 | "translatable": 0, 227 | "unique": 1, 228 | "width": null 229 | }, 230 | { 231 | "allow_in_quick_entry": 0, 232 | "allow_on_submit": 0, 233 | "bold": 0, 234 | "collapsible": 0, 235 | "collapsible_depends_on": null, 236 | "columns": 0, 237 | "default": null, 238 | "depends_on": null, 239 | "description": null, 240 | "docstatus": 0, 241 | "doctype": "Custom Field", 242 | "dt": "Customer", 243 | "fetch_from": null, 244 | "fetch_if_empty": 0, 245 | "fieldname": "nextcloud", 246 | "fieldtype": "Link", 247 | "hidden": 0, 248 | "hide_border": 0, 249 | "hide_days": 0, 250 | "hide_seconds": 0, 251 | "ignore_user_permissions": 0, 252 | "ignore_xss_filter": 0, 253 | "in_global_search": 0, 254 | "in_list_view": 0, 255 | "in_preview": 0, 256 | "in_standard_filter": 0, 257 | "insert_after": "pb_abbreviation", 258 | "is_system_generated": 0, 259 | "is_virtual": 0, 260 | "label": "Nextcloud", 261 | "length": 0, 262 | "link_filters": null, 263 | "mandatory_depends_on": null, 264 | "modified": "2024-12-08 01:12:24.325454", 265 | "module": "Pibidav", 266 | "name": "Customer-custom_pd_nextcloud", 267 | "no_copy": 0, 268 | "non_negative": 0, 269 | "options": "PibiDAV Addon", 270 | "permlevel": 0, 271 | "placeholder": null, 272 | "precision": "", 273 | "print_hide": 0, 274 | "print_hide_if_no_value": 0, 275 | "print_width": null, 276 | "read_only": 0, 277 | "read_only_depends_on": null, 278 | "report_hide": 0, 279 | "reqd": 0, 280 | "search_index": 0, 281 | "show_dashboard": 0, 282 | "sort_options": 0, 283 | "translatable": 0, 284 | "unique": 0, 285 | "width": null 286 | }, 287 | { 288 | "allow_in_quick_entry": 0, 289 | "allow_on_submit": 0, 290 | "bold": 0, 291 | "collapsible": 0, 292 | "collapsible_depends_on": null, 293 | "columns": 0, 294 | "default": null, 295 | "depends_on": null, 296 | "description": null, 297 | "docstatus": 0, 298 | "doctype": "Custom Field", 299 | "dt": "Supplier", 300 | "fetch_from": "nextcloud.nc_folder_internal_link", 301 | "fetch_if_empty": 0, 302 | "fieldname": "nc_folder_link", 303 | "fieldtype": "Read Only", 304 | "hidden": 0, 305 | "hide_border": 0, 306 | "hide_days": 0, 307 | "hide_seconds": 0, 308 | "ignore_user_permissions": 0, 309 | "ignore_xss_filter": 0, 310 | "in_global_search": 0, 311 | "in_list_view": 0, 312 | "in_preview": 0, 313 | "in_standard_filter": 0, 314 | "insert_after": "is_transporter", 315 | "is_system_generated": 0, 316 | "is_virtual": 0, 317 | "label": "NC Folder Link", 318 | "length": 0, 319 | "link_filters": null, 320 | "mandatory_depends_on": null, 321 | "modified": "2024-12-08 12:07:55.697978", 322 | "module": "Pibidav", 323 | "name": "Supplier-custom_pd_nc_folder_link", 324 | "no_copy": 0, 325 | "non_negative": 0, 326 | "options": null, 327 | "permlevel": 0, 328 | "placeholder": null, 329 | "precision": "", 330 | "print_hide": 0, 331 | "print_hide_if_no_value": 0, 332 | "print_width": null, 333 | "read_only": 0, 334 | "read_only_depends_on": null, 335 | "report_hide": 0, 336 | "reqd": 0, 337 | "search_index": 0, 338 | "show_dashboard": 0, 339 | "sort_options": 0, 340 | "translatable": 0, 341 | "unique": 0, 342 | "width": null 343 | }, 344 | { 345 | "allow_in_quick_entry": 0, 346 | "allow_on_submit": 0, 347 | "bold": 0, 348 | "collapsible": 0, 349 | "collapsible_depends_on": null, 350 | "columns": 0, 351 | "default": null, 352 | "depends_on": null, 353 | "description": null, 354 | "docstatus": 0, 355 | "doctype": "Custom Field", 356 | "dt": "Customer", 357 | "fetch_from": "nextcloud.nc_folder_internal_link", 358 | "fetch_if_empty": 0, 359 | "fieldname": "nc_folder_link", 360 | "fieldtype": "Read Only", 361 | "hidden": 0, 362 | "hide_border": 0, 363 | "hide_days": 0, 364 | "hide_seconds": 0, 365 | "ignore_user_permissions": 0, 366 | "ignore_xss_filter": 0, 367 | "in_global_search": 0, 368 | "in_list_view": 0, 369 | "in_preview": 0, 370 | "in_standard_filter": 0, 371 | "insert_after": "account_manager", 372 | "is_system_generated": 0, 373 | "is_virtual": 0, 374 | "label": "NC Folder Link", 375 | "length": 0, 376 | "link_filters": null, 377 | "mandatory_depends_on": null, 378 | "modified": "2024-12-08 12:11:23.806930", 379 | "module": "Pibidav", 380 | "name": "Customer-custom_pd_nc_folder_link", 381 | "no_copy": 0, 382 | "non_negative": 0, 383 | "options": null, 384 | "permlevel": 0, 385 | "placeholder": null, 386 | "precision": "", 387 | "print_hide": 0, 388 | "print_hide_if_no_value": 0, 389 | "print_width": null, 390 | "read_only": 0, 391 | "read_only_depends_on": null, 392 | "report_hide": 0, 393 | "reqd": 0, 394 | "search_index": 0, 395 | "show_dashboard": 0, 396 | "sort_options": 0, 397 | "translatable": 0, 398 | "unique": 0, 399 | "width": null 400 | }, 401 | { 402 | "allow_in_quick_entry": 0, 403 | "allow_on_submit": 0, 404 | "bold": 0, 405 | "collapsible": 0, 406 | "collapsible_depends_on": null, 407 | "columns": 0, 408 | "default": null, 409 | "depends_on": null, 410 | "description": null, 411 | "docstatus": 0, 412 | "doctype": "Custom Field", 413 | "dt": "File", 414 | "fetch_from": null, 415 | "fetch_if_empty": 0, 416 | "fieldname": "uploaded_to_nextcloud", 417 | "fieldtype": "Check", 418 | "hidden": 0, 419 | "hide_border": 0, 420 | "hide_days": 0, 421 | "hide_seconds": 0, 422 | "ignore_user_permissions": 0, 423 | "ignore_xss_filter": 0, 424 | "in_global_search": 0, 425 | "in_list_view": 0, 426 | "in_preview": 0, 427 | "in_standard_filter": 0, 428 | "insert_after": "uploaded_to_google_drive", 429 | "is_system_generated": 0, 430 | "is_virtual": 0, 431 | "label": "Uploaded To NextCloud", 432 | "length": 0, 433 | "link_filters": null, 434 | "mandatory_depends_on": null, 435 | "modified": "2022-04-14 18:42:39.635285", 436 | "module": "Pibidav", 437 | "name": "File-uploaded_to_nextcloud", 438 | "no_copy": 0, 439 | "non_negative": 0, 440 | "options": null, 441 | "permlevel": 0, 442 | "placeholder": null, 443 | "precision": "", 444 | "print_hide": 0, 445 | "print_hide_if_no_value": 0, 446 | "print_width": null, 447 | "read_only": 1, 448 | "read_only_depends_on": null, 449 | "report_hide": 0, 450 | "reqd": 0, 451 | "search_index": 0, 452 | "show_dashboard": 0, 453 | "sort_options": 0, 454 | "translatable": 0, 455 | "unique": 0, 456 | "width": null 457 | }, 458 | { 459 | "allow_in_quick_entry": 0, 460 | "allow_on_submit": 0, 461 | "bold": 0, 462 | "collapsible": 0, 463 | "collapsible_depends_on": null, 464 | "columns": 0, 465 | "default": null, 466 | "depends_on": null, 467 | "description": null, 468 | "docstatus": 0, 469 | "doctype": "Custom Field", 470 | "dt": "File", 471 | "fetch_from": null, 472 | "fetch_if_empty": 0, 473 | "fieldname": "folder_path", 474 | "fieldtype": "Text", 475 | "hidden": 0, 476 | "hide_border": 0, 477 | "hide_days": 0, 478 | "hide_seconds": 0, 479 | "ignore_user_permissions": 0, 480 | "ignore_xss_filter": 0, 481 | "in_global_search": 0, 482 | "in_list_view": 0, 483 | "in_preview": 0, 484 | "in_standard_filter": 0, 485 | "insert_after": "uploaded_to_nextcloud", 486 | "is_system_generated": 0, 487 | "is_virtual": 0, 488 | "label": "Folder Path", 489 | "length": 0, 490 | "link_filters": null, 491 | "mandatory_depends_on": null, 492 | "modified": "2022-04-14 22:39:14.270549", 493 | "module": "Pibidav", 494 | "name": "File-folder_path", 495 | "no_copy": 0, 496 | "non_negative": 0, 497 | "options": null, 498 | "permlevel": 0, 499 | "placeholder": null, 500 | "precision": "", 501 | "print_hide": 0, 502 | "print_hide_if_no_value": 0, 503 | "print_width": null, 504 | "read_only": 1, 505 | "read_only_depends_on": null, 506 | "report_hide": 0, 507 | "reqd": 0, 508 | "search_index": 0, 509 | "show_dashboard": 0, 510 | "sort_options": 0, 511 | "translatable": 0, 512 | "unique": 0, 513 | "width": null 514 | }, 515 | { 516 | "allow_in_quick_entry": 0, 517 | "allow_on_submit": 0, 518 | "bold": 0, 519 | "collapsible": 0, 520 | "collapsible_depends_on": null, 521 | "columns": 0, 522 | "default": null, 523 | "depends_on": null, 524 | "description": null, 525 | "docstatus": 0, 526 | "doctype": "Custom Field", 527 | "dt": "File", 528 | "fetch_from": null, 529 | "fetch_if_empty": 0, 530 | "fieldname": "share_link", 531 | "fieldtype": "Data", 532 | "hidden": 0, 533 | "hide_border": 0, 534 | "hide_days": 0, 535 | "hide_seconds": 0, 536 | "ignore_user_permissions": 0, 537 | "ignore_xss_filter": 0, 538 | "in_global_search": 0, 539 | "in_list_view": 0, 540 | "in_preview": 0, 541 | "in_standard_filter": 0, 542 | "insert_after": "folder_path", 543 | "is_system_generated": 0, 544 | "is_virtual": 0, 545 | "label": "Share Link", 546 | "length": 0, 547 | "link_filters": null, 548 | "mandatory_depends_on": null, 549 | "modified": "2022-04-17 09:27:40.367685", 550 | "module": "Pibidav", 551 | "name": "File-share_link", 552 | "no_copy": 0, 553 | "non_negative": 0, 554 | "options": null, 555 | "permlevel": 0, 556 | "placeholder": null, 557 | "precision": "", 558 | "print_hide": 0, 559 | "print_hide_if_no_value": 0, 560 | "print_width": null, 561 | "read_only": 1, 562 | "read_only_depends_on": null, 563 | "report_hide": 0, 564 | "reqd": 0, 565 | "search_index": 0, 566 | "show_dashboard": 0, 567 | "sort_options": 0, 568 | "translatable": 0, 569 | "unique": 0, 570 | "width": null 571 | }, 572 | { 573 | "allow_in_quick_entry": 0, 574 | "allow_on_submit": 0, 575 | "bold": 0, 576 | "collapsible": 0, 577 | "collapsible_depends_on": null, 578 | "columns": 0, 579 | "default": null, 580 | "depends_on": null, 581 | "description": null, 582 | "docstatus": 0, 583 | "doctype": "Custom Field", 584 | "dt": "File", 585 | "fetch_from": null, 586 | "fetch_if_empty": 0, 587 | "fieldname": "fileid", 588 | "fieldtype": "Data", 589 | "hidden": 0, 590 | "hide_border": 0, 591 | "hide_days": 0, 592 | "hide_seconds": 0, 593 | "ignore_user_permissions": 0, 594 | "ignore_xss_filter": 0, 595 | "in_global_search": 0, 596 | "in_list_view": 0, 597 | "in_preview": 0, 598 | "in_standard_filter": 0, 599 | "insert_after": "share_link", 600 | "is_system_generated": 0, 601 | "is_virtual": 0, 602 | "label": "FileID", 603 | "length": 0, 604 | "link_filters": null, 605 | "mandatory_depends_on": null, 606 | "modified": "2022-04-26 13:24:09.671191", 607 | "module": "Pibidav", 608 | "name": "File-fileid", 609 | "no_copy": 0, 610 | "non_negative": 0, 611 | "options": null, 612 | "permlevel": 0, 613 | "placeholder": null, 614 | "precision": "", 615 | "print_hide": 0, 616 | "print_hide_if_no_value": 0, 617 | "print_width": null, 618 | "read_only": 1, 619 | "read_only_depends_on": null, 620 | "report_hide": 0, 621 | "reqd": 0, 622 | "search_index": 0, 623 | "show_dashboard": 0, 624 | "sort_options": 0, 625 | "translatable": 0, 626 | "unique": 0, 627 | "width": null 628 | }, 629 | { 630 | "allow_in_quick_entry": 0, 631 | "allow_on_submit": 0, 632 | "bold": 0, 633 | "collapsible": 1, 634 | "collapsible_depends_on": null, 635 | "columns": 0, 636 | "default": null, 637 | "depends_on": null, 638 | "description": null, 639 | "docstatus": 0, 640 | "doctype": "Custom Field", 641 | "dt": "User", 642 | "fetch_from": null, 643 | "fetch_if_empty": 0, 644 | "fieldname": "nextcloud_credentials", 645 | "fieldtype": "Section Break", 646 | "hidden": 0, 647 | "hide_border": 0, 648 | "hide_days": 0, 649 | "hide_seconds": 0, 650 | "ignore_user_permissions": 1, 651 | "ignore_xss_filter": 0, 652 | "in_global_search": 0, 653 | "in_list_view": 0, 654 | "in_preview": 0, 655 | "in_standard_filter": 0, 656 | "insert_after": "generate_keys", 657 | "is_system_generated": 0, 658 | "is_virtual": 0, 659 | "label": "NextCloud Credentials", 660 | "length": 0, 661 | "link_filters": null, 662 | "mandatory_depends_on": null, 663 | "modified": "2022-04-01 19:14:50.269324", 664 | "module": "Pibidav", 665 | "name": "User-nextcloud_credentials", 666 | "no_copy": 0, 667 | "non_negative": 0, 668 | "options": null, 669 | "permlevel": 0, 670 | "placeholder": null, 671 | "precision": "", 672 | "print_hide": 0, 673 | "print_hide_if_no_value": 0, 674 | "print_width": null, 675 | "read_only": 0, 676 | "read_only_depends_on": null, 677 | "report_hide": 0, 678 | "reqd": 0, 679 | "search_index": 0, 680 | "show_dashboard": 0, 681 | "sort_options": 0, 682 | "translatable": 0, 683 | "unique": 0, 684 | "width": null 685 | }, 686 | { 687 | "allow_in_quick_entry": 1, 688 | "allow_on_submit": 0, 689 | "bold": 0, 690 | "collapsible": 0, 691 | "collapsible_depends_on": null, 692 | "columns": 0, 693 | "default": "0", 694 | "depends_on": null, 695 | "description": null, 696 | "docstatus": 0, 697 | "doctype": "Custom Field", 698 | "dt": "User", 699 | "fetch_from": null, 700 | "fetch_if_empty": 0, 701 | "fieldname": "nextcloud_enable", 702 | "fieldtype": "Check", 703 | "hidden": 0, 704 | "hide_border": 0, 705 | "hide_days": 0, 706 | "hide_seconds": 0, 707 | "ignore_user_permissions": 1, 708 | "ignore_xss_filter": 0, 709 | "in_global_search": 0, 710 | "in_list_view": 0, 711 | "in_preview": 0, 712 | "in_standard_filter": 0, 713 | "insert_after": "nextcloud_credentials", 714 | "is_system_generated": 0, 715 | "is_virtual": 0, 716 | "label": "Enable NextCloud", 717 | "length": 0, 718 | "link_filters": null, 719 | "mandatory_depends_on": null, 720 | "modified": "2022-04-01 19:14:50.269324", 721 | "module": "Pibidav", 722 | "name": "User-nextcloud_enable", 723 | "no_copy": 0, 724 | "non_negative": 0, 725 | "options": null, 726 | "permlevel": 0, 727 | "placeholder": null, 728 | "precision": "", 729 | "print_hide": 0, 730 | "print_hide_if_no_value": 0, 731 | "print_width": null, 732 | "read_only": 0, 733 | "read_only_depends_on": null, 734 | "report_hide": 0, 735 | "reqd": 0, 736 | "search_index": 0, 737 | "show_dashboard": 0, 738 | "sort_options": 0, 739 | "translatable": 0, 740 | "unique": 0, 741 | "width": null 742 | }, 743 | { 744 | "allow_in_quick_entry": 1, 745 | "allow_on_submit": 0, 746 | "bold": 0, 747 | "collapsible": 0, 748 | "collapsible_depends_on": null, 749 | "columns": 0, 750 | "default": null, 751 | "depends_on": null, 752 | "description": "NextCloud URL as https://domain.com without / at the end", 753 | "docstatus": 0, 754 | "doctype": "Custom Field", 755 | "dt": "User", 756 | "fetch_from": null, 757 | "fetch_if_empty": 0, 758 | "fieldname": "nextcloud_url", 759 | "fieldtype": "Data", 760 | "hidden": 0, 761 | "hide_border": 0, 762 | "hide_days": 0, 763 | "hide_seconds": 0, 764 | "ignore_user_permissions": 1, 765 | "ignore_xss_filter": 0, 766 | "in_global_search": 0, 767 | "in_list_view": 0, 768 | "in_preview": 0, 769 | "in_standard_filter": 0, 770 | "insert_after": "nextcloud_enable", 771 | "is_system_generated": 0, 772 | "is_virtual": 0, 773 | "label": "NextCloud URL", 774 | "length": 0, 775 | "link_filters": null, 776 | "mandatory_depends_on": null, 777 | "modified": "2022-04-01 19:14:50.979439", 778 | "module": "Pibidav", 779 | "name": "User-nextcloud_url", 780 | "no_copy": 0, 781 | "non_negative": 0, 782 | "options": null, 783 | "permlevel": 0, 784 | "placeholder": null, 785 | "precision": "", 786 | "print_hide": 0, 787 | "print_hide_if_no_value": 0, 788 | "print_width": null, 789 | "read_only": 0, 790 | "read_only_depends_on": null, 791 | "report_hide": 0, 792 | "reqd": 0, 793 | "search_index": 0, 794 | "show_dashboard": 0, 795 | "sort_options": 0, 796 | "translatable": 0, 797 | "unique": 0, 798 | "width": null 799 | }, 800 | { 801 | "allow_in_quick_entry": 1, 802 | "allow_on_submit": 0, 803 | "bold": 0, 804 | "collapsible": 0, 805 | "collapsible_depends_on": null, 806 | "columns": 0, 807 | "default": null, 808 | "depends_on": null, 809 | "description": null, 810 | "docstatus": 0, 811 | "doctype": "Custom Field", 812 | "dt": "User", 813 | "fetch_from": null, 814 | "fetch_if_empty": 0, 815 | "fieldname": "nextcloud_username", 816 | "fieldtype": "Data", 817 | "hidden": 0, 818 | "hide_border": 0, 819 | "hide_days": 0, 820 | "hide_seconds": 0, 821 | "ignore_user_permissions": 1, 822 | "ignore_xss_filter": 0, 823 | "in_global_search": 0, 824 | "in_list_view": 0, 825 | "in_preview": 0, 826 | "in_standard_filter": 0, 827 | "insert_after": "nextcloud_url", 828 | "is_system_generated": 0, 829 | "is_virtual": 0, 830 | "label": "Nextcloud Username", 831 | "length": 0, 832 | "link_filters": null, 833 | "mandatory_depends_on": null, 834 | "modified": "2022-04-01 19:14:51.480230", 835 | "module": "Pibidav", 836 | "name": "User-nextcloud_username", 837 | "no_copy": 0, 838 | "non_negative": 0, 839 | "options": null, 840 | "permlevel": 0, 841 | "placeholder": null, 842 | "precision": "", 843 | "print_hide": 0, 844 | "print_hide_if_no_value": 0, 845 | "print_width": null, 846 | "read_only": 0, 847 | "read_only_depends_on": null, 848 | "report_hide": 0, 849 | "reqd": 0, 850 | "search_index": 0, 851 | "show_dashboard": 0, 852 | "sort_options": 0, 853 | "translatable": 0, 854 | "unique": 0, 855 | "width": null 856 | }, 857 | { 858 | "allow_in_quick_entry": 1, 859 | "allow_on_submit": 0, 860 | "bold": 0, 861 | "collapsible": 0, 862 | "collapsible_depends_on": null, 863 | "columns": 0, 864 | "default": null, 865 | "depends_on": null, 866 | "description": null, 867 | "docstatus": 0, 868 | "doctype": "Custom Field", 869 | "dt": "User", 870 | "fetch_from": null, 871 | "fetch_if_empty": 0, 872 | "fieldname": "nextcloud_token", 873 | "fieldtype": "Password", 874 | "hidden": 0, 875 | "hide_border": 0, 876 | "hide_days": 0, 877 | "hide_seconds": 0, 878 | "ignore_user_permissions": 1, 879 | "ignore_xss_filter": 0, 880 | "in_global_search": 0, 881 | "in_list_view": 0, 882 | "in_preview": 0, 883 | "in_standard_filter": 0, 884 | "insert_after": "nextcloud_username", 885 | "is_system_generated": 0, 886 | "is_virtual": 0, 887 | "label": "NextCloud Token", 888 | "length": 0, 889 | "link_filters": null, 890 | "mandatory_depends_on": null, 891 | "modified": "2022-04-01 19:14:51.997615", 892 | "module": "Pibidav", 893 | "name": "User-nextcloud_token", 894 | "no_copy": 0, 895 | "non_negative": 0, 896 | "options": null, 897 | "permlevel": 0, 898 | "placeholder": null, 899 | "precision": "", 900 | "print_hide": 0, 901 | "print_hide_if_no_value": 0, 902 | "print_width": null, 903 | "read_only": 0, 904 | "read_only_depends_on": null, 905 | "report_hide": 0, 906 | "reqd": 0, 907 | "search_index": 0, 908 | "show_dashboard": 0, 909 | "sort_options": 0, 910 | "translatable": 0, 911 | "unique": 0, 912 | "width": null 913 | } 914 | ] -------------------------------------------------------------------------------- /pibidav/fixtures/workspace.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "charts": [], 4 | "content": "[{\"id\":\"w6ozBdED5x\",\"type\":\"header\",\"data\":{\"text\":\"Inicio > pibiTools
\",\"col\":12}},{\"id\":\"Xyxm-ti2im\",\"type\":\"custom_block\",\"data\":{\"custom_block_name\":\"AI Home\",\"col\":12}}]", 5 | "custom_blocks": [], 6 | "docstatus": 0, 7 | "doctype": "Workspace", 8 | "for_user": "", 9 | "hide_custom": 0, 10 | "icon": "pibico", 11 | "indicator_color": "", 12 | "is_hidden": 0, 13 | "label": "pibiTools", 14 | "links": [], 15 | "modified": "2024-12-07 10:10:19.730958", 16 | "module": "Pibidav", 17 | "name": "pibiTools", 18 | "number_cards": [], 19 | "parent_page": "", 20 | "public": 1, 21 | "quick_lists": [], 22 | "restrict_to_domain": null, 23 | "roles": [], 24 | "sequence_id": 3.0, 25 | "shortcuts": [], 26 | "title": "pibiTools" 27 | }, 28 | { 29 | "charts": [], 30 | "content": "[{\"id\":\"azQJesz1jX\",\"type\":\"header\",\"data\":{\"text\":\"Inicio > pibiTools > pibiDAV
\",\"col\":12}},{\"id\":\"XQTScKtokJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Documents\",\"col\":4}},{\"id\":\"OIx7Apgo_M\",\"type\":\"card\",\"data\":{\"card_name\":\"Configuración\",\"col\":4}}]", 31 | "custom_blocks": [], 32 | "docstatus": 0, 33 | "doctype": "Workspace", 34 | "for_user": "", 35 | "hide_custom": 0, 36 | "icon": "pibidav", 37 | "indicator_color": "", 38 | "is_hidden": 0, 39 | "label": "pibiDAV", 40 | "links": [ 41 | { 42 | "dependencies": null, 43 | "description": null, 44 | "hidden": 0, 45 | "icon": null, 46 | "is_query_report": 0, 47 | "label": "Documents", 48 | "link_count": 4, 49 | "link_to": null, 50 | "link_type": "DocType", 51 | "onboard": 0, 52 | "only_for": null, 53 | "parent": "pibiDAV", 54 | "parentfield": "links", 55 | "parenttype": "Workspace", 56 | "report_ref_doctype": null, 57 | "type": "Card Break" 58 | }, 59 | { 60 | "dependencies": null, 61 | "description": null, 62 | "hidden": 0, 63 | "icon": null, 64 | "is_query_report": 0, 65 | "label": "pibiDAV Addon", 66 | "link_count": 0, 67 | "link_to": "PibiDAV Addon", 68 | "link_type": "DocType", 69 | "onboard": 0, 70 | "only_for": null, 71 | "parent": "pibiDAV", 72 | "parentfield": "links", 73 | "parenttype": "Workspace", 74 | "report_ref_doctype": null, 75 | "type": "Link" 76 | }, 77 | { 78 | "dependencies": null, 79 | "description": null, 80 | "hidden": 0, 81 | "icon": null, 82 | "is_query_report": 0, 83 | "label": "Tag", 84 | "link_count": 0, 85 | "link_to": "Tag", 86 | "link_type": "DocType", 87 | "onboard": 0, 88 | "only_for": null, 89 | "parent": "pibiDAV", 90 | "parentfield": "links", 91 | "parenttype": "Workspace", 92 | "report_ref_doctype": null, 93 | "type": "Link" 94 | }, 95 | { 96 | "dependencies": null, 97 | "description": null, 98 | "hidden": 0, 99 | "icon": null, 100 | "is_query_report": 0, 101 | "label": "Contact", 102 | "link_count": 0, 103 | "link_to": "Contact", 104 | "link_type": "DocType", 105 | "onboard": 0, 106 | "only_for": null, 107 | "parent": "pibiDAV", 108 | "parentfield": "links", 109 | "parenttype": "Workspace", 110 | "report_ref_doctype": null, 111 | "type": "Link" 112 | }, 113 | { 114 | "dependencies": null, 115 | "description": null, 116 | "hidden": 0, 117 | "icon": null, 118 | "is_query_report": 0, 119 | "label": "Event", 120 | "link_count": 0, 121 | "link_to": "Event", 122 | "link_type": "DocType", 123 | "onboard": 0, 124 | "only_for": null, 125 | "parent": "pibiDAV", 126 | "parentfield": "links", 127 | "parenttype": "Workspace", 128 | "report_ref_doctype": null, 129 | "type": "Link" 130 | }, 131 | { 132 | "dependencies": null, 133 | "description": null, 134 | "hidden": 0, 135 | "icon": null, 136 | "is_query_report": 0, 137 | "label": "Configuración", 138 | "link_count": 3, 139 | "link_to": null, 140 | "link_type": "DocType", 141 | "onboard": 0, 142 | "only_for": null, 143 | "parent": "pibiDAV", 144 | "parentfield": "links", 145 | "parenttype": "Workspace", 146 | "report_ref_doctype": null, 147 | "type": "Card Break" 148 | }, 149 | { 150 | "dependencies": null, 151 | "description": null, 152 | "hidden": 0, 153 | "icon": null, 154 | "is_query_report": 0, 155 | "label": "File Category", 156 | "link_count": 0, 157 | "link_to": "File Category", 158 | "link_type": "DocType", 159 | "onboard": 0, 160 | "only_for": null, 161 | "parent": "pibiDAV", 162 | "parentfield": "links", 163 | "parenttype": "Workspace", 164 | "report_ref_doctype": null, 165 | "type": "Link" 166 | }, 167 | { 168 | "dependencies": null, 169 | "description": null, 170 | "hidden": 0, 171 | "icon": null, 172 | "is_query_report": 0, 173 | "label": "NextCloud Settings", 174 | "link_count": 0, 175 | "link_to": "NextCloud Settings", 176 | "link_type": "DocType", 177 | "onboard": 0, 178 | "only_for": null, 179 | "parent": "pibiDAV", 180 | "parentfield": "links", 181 | "parenttype": "Workspace", 182 | "report_ref_doctype": null, 183 | "type": "Link" 184 | }, 185 | { 186 | "dependencies": null, 187 | "description": null, 188 | "hidden": 0, 189 | "icon": null, 190 | "is_query_report": 0, 191 | "label": "Folder Set", 192 | "link_count": 0, 193 | "link_to": "Folder Set", 194 | "link_type": "DocType", 195 | "onboard": 0, 196 | "only_for": null, 197 | "parent": "pibiDAV", 198 | "parentfield": "links", 199 | "parenttype": "Workspace", 200 | "report_ref_doctype": null, 201 | "type": "Link" 202 | } 203 | ], 204 | "modified": "2024-12-06 20:06:36.470352", 205 | "module": "Pibidav", 206 | "name": "pibiDAV", 207 | "number_cards": [], 208 | "parent_page": "pibiTools", 209 | "public": 1, 210 | "quick_lists": [], 211 | "restrict_to_domain": null, 212 | "roles": [ 213 | { 214 | "parent": "pibiDAV", 215 | "parentfield": "roles", 216 | "parenttype": "Workspace", 217 | "role": "Docs Controller" 218 | }, 219 | { 220 | "parent": "pibiDAV", 221 | "parentfield": "roles", 222 | "parenttype": "Workspace", 223 | "role": "Docs User" 224 | }, 225 | { 226 | "parent": "pibiDAV", 227 | "parentfield": "roles", 228 | "parenttype": "Workspace", 229 | "role": "NextCloud User" 230 | } 231 | ], 232 | "sequence_id": 4.0, 233 | "shortcuts": [], 234 | "title": "pibiDAV" 235 | } 236 | ] -------------------------------------------------------------------------------- /pibidav/hooks.py: -------------------------------------------------------------------------------- 1 | from . import __version__ as app_version 2 | 3 | app_name = "pibidav" 4 | app_title = "Pibidav" 5 | app_publisher = "pibiCo" 6 | app_description = "WebDAV, CalDAV and CardDAV Integration between Frappe and NextCloud" 7 | app_icon = "octicon octicon-file-directory" 8 | app_color = "grey" 9 | app_email = "pibico.sl@gmail.com" 10 | app_license = "MIT" 11 | 12 | # Includes in 13 | # ------------------ 14 | 15 | # include js, css files in header of desk.html 16 | # app_include_css = "/assets/pibidav/css/pibidav.css" 17 | app_include_js = "pibidav.bundle.js" 18 | 19 | # include js, css files in header of web template 20 | # web_include_css = "/assets/pibidav/css/pibidav.css" 21 | # web_include_js = "/assets/pibidav/js/pibidav.js" 22 | 23 | # include custom scss in every website theme (without file extension ".scss") 24 | # website_theme_scss = "pibidav/public/scss/website" 25 | 26 | # include js, css files in header of web form 27 | # webform_include_js = {"doctype": "public/js/doctype.js"} 28 | # webform_include_css = {"doctype": "public/css/doctype.css"} 29 | 30 | # include js in page 31 | # page_js = {"page" : "public/js/file.js"} 32 | 33 | app_include_icons = [ 34 | "pibidav/icons/timeless/icons.svg" 35 | ] 36 | 37 | # include js in doctype views 38 | # doctype_js = {"doctype" : "public/js/doctype.js"} 39 | # doctype_list_js = {"doctype" : "public/js/doctype_list.js"} 40 | # doctype_tree_js = {"doctype" : "public/js/doctype_tree.js"} 41 | # doctype_calendar_js = {"doctype" : "public/js/doctype_calendar.js"} 42 | 43 | nc_list = [ 44 | "Contact", 45 | "Event", 46 | "Customer", 47 | "Supplier", 48 | "Project", 49 | "Sales Invoice", 50 | "Sales Order", 51 | "Purchase Invoice", 52 | "Quotation", 53 | "Purchase Order", 54 | "Task", 55 | "Timesheet", 56 | "Item", 57 | "Employee" 58 | ] 59 | 60 | doctype_js = {} 61 | for item in nc_list: 62 | doctype_js[item] = "public/js/dist/nc_pibidav.js" 63 | 64 | # Home Pages 65 | # ---------- 66 | 67 | # application home page (will override Website Settings) 68 | # home_page = "login" 69 | 70 | #brand_html = '
pibiDAV
' 71 | 72 | #website_context = { 73 | # "favicon": "/assets/pibidav/image/favicon.svg", 74 | # "splash_image": "/assets/pibidav/image/pibiCo_engine_largo.png" 75 | #} 76 | 77 | # website user home page (by Role) 78 | # role_home_page = { 79 | # "Role": "home_page" 80 | # } 81 | 82 | # Generators 83 | # ---------- 84 | 85 | # automatically create page for each record of this doctype 86 | # website_generators = ["Web Page"] 87 | 88 | # Installation 89 | # ------------ 90 | 91 | # before_install = "pibidav.install.before_install" 92 | # after_install = "pibidav.install.after_install" 93 | 94 | # Uninstallation 95 | # ------------ 96 | 97 | # before_uninstall = "pibidav.uninstall.before_uninstall" 98 | # after_uninstall = "pibidav.uninstall.after_uninstall" 99 | 100 | # Desk Notifications 101 | # ------------------ 102 | # See frappe.core.notifications.get_notification_config 103 | 104 | # notification_config = "pibidav.notifications.get_notification_config" 105 | 106 | # Permissions 107 | # ----------- 108 | # Permissions evaluated in scripted ways 109 | 110 | # permission_query_conditions = { 111 | # "Event": "frappe.desk.doctype.event.event.get_permission_query_conditions", 112 | # } 113 | # 114 | # has_permission = { 115 | # "Event": "frappe.desk.doctype.event.event.has_permission", 116 | # } 117 | 118 | jinja = { 119 | "methods": [ 120 | "pibidav.jinja.timestamp_to_date", 121 | "pibidav.jinja.ts_to_date" 122 | ] 123 | } 124 | 125 | # DocType Class 126 | # --------------- 127 | # Override standard doctype classes 128 | 129 | # override_doctype_class = { 130 | # "ToDo": "custom_app.overrides.CustomToDo" 131 | # } 132 | 133 | # Document Events 134 | # --------------- 135 | # Hook on document methods and events 136 | 137 | doc_events = { 138 | # "*": { 139 | # "after_insert": "pibidav.pibidav.custom.create_nc_folder" 140 | # }, 141 | "File": { 142 | "after_insert": ["pibidav.pibidav.custom.upload_file_to_nc"] 143 | } 144 | # "*": { 145 | # "on_update": "method", 146 | # "on_cancel": "method", 147 | # "on_trash": "method" 148 | # } 149 | } 150 | 151 | # Scheduled Tasks 152 | # --------------- 153 | 154 | scheduler_events = { 155 | # "all": [ 156 | # "pibidav.tasks.all" 157 | # ], 158 | # "cron": { 159 | # "*/1 * * * *": [ 160 | # "pibidav.pibidav.pibical.sync_outside_caldav" 161 | # ] 162 | # }, 163 | "daily": [ 164 | "pibidav.pibidav.doctype.nextcloud_settings.nextcloud_settings.daily_backup" 165 | ], 166 | # "hourly": [ 167 | # "pibidav.tasks.hourly" 168 | # ], 169 | "weekly": [ 170 | "pibidav.pibidav.doctype.nextcloud_settings.nextcloud_settings.weekly_backup" 171 | ] #, 172 | # "monthly": [ 173 | # "pibidav.tasks.monthly" 174 | # ] 175 | } 176 | 177 | # Testing 178 | # ------- 179 | 180 | # before_tests = "pibidav.install.before_tests" 181 | 182 | # Overriding Methods 183 | # ------------------------------ 184 | # 185 | # override_whitelisted_methods = { 186 | # "frappe.desk.doctype.event.event.get_events": "pibidav.event.get_events" 187 | # } 188 | # 189 | # each overriding function accepts a `data` argument; 190 | # generated from the base implementation of the doctype dashboard, 191 | # along with any modifications made in other Frappe apps 192 | # override_doctype_dashboards = { 193 | # "Task": "pibidav.task.get_dashboard_data" 194 | # } 195 | 196 | # exempt linked doctypes from being automatically cancelled 197 | # 198 | # auto_cancel_exempted_doctypes = ["Auto Repeat"] 199 | 200 | 201 | # User Data Protection 202 | # -------------------- 203 | 204 | user_data_fields = [ 205 | { 206 | "doctype": "{doctype_1}", 207 | "filter_by": "{filter_by}", 208 | "redact_fields": ["{field_1}", "{field_2}"], 209 | "partial": 1, 210 | }, 211 | { 212 | "doctype": "{doctype_2}", 213 | "filter_by": "{filter_by}", 214 | "partial": 1, 215 | }, 216 | { 217 | "doctype": "{doctype_3}", 218 | "strict": False, 219 | }, 220 | { 221 | "doctype": "{doctype_4}" 222 | } 223 | ] 224 | 225 | # Authentication and authorization 226 | # -------------------------------- 227 | 228 | # auth_hooks = [ 229 | # "pibidav.auth.validate" 230 | # ] 231 | 232 | fixtures = [ 233 | { 234 | "dt": "Custom Field", 235 | "filters": {"module": ["like", "Pibidav"]} 236 | }, 237 | { 238 | "dt": "Workspace", 239 | "filters": {"module": ["like", "Pibidav"]} 240 | } 241 | ] 242 | 243 | treeviews = ['Folder Set'] 244 | 245 | 246 | # Translation 247 | # -------------------------------- 248 | 249 | # Make link fields search translated document names for these DocTypes 250 | # Recommended only for DocTypes which have limited documents with untranslated names 251 | # For example: Role, Gender, etc. 252 | # translated_search_doctypes = [] 253 | -------------------------------------------------------------------------------- /pibidav/jinja.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | import frappe 4 | from datetime import tzinfo, timedelta, datetime 5 | 6 | def timestamp_to_date(value, format='%a %H:%M'): 7 | if value: 8 | return datetime.fromtimestamp(int(value)).strftime(format) 9 | 10 | def ts_to_date(value, format='%a %d/%m/%y %H:%M'): 11 | if value: 12 | return datetime.fromtimestamp(int(value)).strftime(format) -------------------------------------------------------------------------------- /pibidav/modules.txt: -------------------------------------------------------------------------------- 1 | Pibidav -------------------------------------------------------------------------------- /pibidav/patches.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pibico/pibiDAV/660caffafd274f1dcf6c42024d5f67bccd5c8509/pibidav/patches.txt -------------------------------------------------------------------------------- /pibidav/pibidav/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pibico/pibiDAV/660caffafd274f1dcf6c42024d5f67bccd5c8509/pibidav/pibidav/__init__.py -------------------------------------------------------------------------------- /pibidav/pibidav/custom.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright (c) 2022, PibiCo and contributors 3 | # For license information, please see license.txt 4 | from __future__ import unicode_literals 5 | import frappe 6 | from frappe import _, msgprint, throw, enqueue 7 | from frappe.utils import cint, cstr 8 | 9 | import json, time, requests, sys, hashlib, re, os 10 | 11 | from datetime import date, datetime, timedelta 12 | 13 | import pibidav.pibidav.nextcloud as nextcloud 14 | 15 | from frappe.utils.password import get_decrypted_password 16 | from frappe.utils.file_manager import get_file_path 17 | 18 | import frappe.desk.doctype.tag.tag as tag 19 | 20 | @frappe.whitelist() 21 | def checkNCuser(): 22 | ncuser = frappe.get_value("NextCloud Settings", "NextCloud Settings", "nc_backup_username") 23 | loggeduser = frappe.get_value("User", frappe.session.user, "nextcloud_username") 24 | if ncuser == loggeduser: 25 | return True 26 | else: 27 | return False 28 | 29 | @frappe.whitelist() 30 | def doCreateFolder(doctype): 31 | data = frappe.db.get_value("Reference Item", {"parent": "NextCloud Settings", "reference_doctype": doctype},['create_nc_folder','nc_enable'], as_dict = 1) 32 | if data is None: 33 | return False 34 | if data.create_nc_folder and data.nc_enable: 35 | return True 36 | else: 37 | return False 38 | 39 | @frappe.whitelist() 40 | def create_nc_folder(dt, dn, abbr, strmain, folder_set, sharing_option=None, secret=None): 41 | doc = frappe.get_doc(doctype=dt, docname=dn) 42 | ## Check docs excluded and included in the NC Integration 43 | docs_excluded = frappe.get_value("NextCloud Settings", "NextCloud Settings", "nc_doctype_excluded") 44 | docs_included = frappe.get_value("NextCloud Settings", "NextCloud Settings", "nc_doctype_included") 45 | nc_url = frappe.get_value("NextCloud Settings", "NextCloud Settings", "nc_backup_url") 46 | if nc_url[-1] != '/': nc_url += '/' 47 | 48 | if dt in docs_excluded or not dt in docs_included: 49 | return "DocType not in NC integration {}".format(docs_included) 50 | 51 | data = frappe.db.get_value("Reference Item", {"parent": "NextCloud Settings", "reference_doctype": dt},['nc_folder','create_nc_folder', 'nc_enable'], as_dict = 1) 52 | node_name = folder_set.strip() 53 | path = data.nc_folder 54 | 55 | if path is None: 56 | return "Failed. Not defined the Default destination Folder in NC Settings" 57 | 58 | if not data.nc_enable: 59 | return "Failed. Not enabled NextCloud Integration in Addon" 60 | 61 | if data.create_nc_folder and data.nc_folder != '' and data.folder_set != '': 62 | pibidav = check_addon(dt,dn) 63 | 64 | ## Get default data from NextCloud Settings 65 | ## Assign data to variables for creating folders in NC 66 | strmain = strmain.strip() 67 | abbreviation = abbr.strip() 68 | digits = 3 69 | if path[-1] != '/': 70 | path += '/' 71 | if path[0] != '/': 72 | return frappe.throw(_("{} Root Destination Folder must start with /. Correct in your NextCloud Settings and retry".format(path))) 73 | 74 | root_path = "{}{} {}/".format(path, abbreviation, strmain) 75 | 76 | ## Create Folders if needed data are filled in logged in as superuser in NC 77 | if node_name and path and abbreviation and strmain: 78 | create_nc_dirs(node_name, path, abbreviation, strmain, digits) 79 | nclog = make_nc_session() 80 | ## Get data fileid from dir 81 | fileinfo = nclog.file_info(root_path, properties=['{http://owncloud.org/ns}fileid']) 82 | if fileinfo: 83 | fileid = fileinfo.attributes['{http://owncloud.org/ns}fileid'] 84 | ## Create internal Link 85 | intlink = nc_url + 'f/' + fileid 86 | nc_folder_internal_link = '' + intlink + '' 88 | pibidav.nc_folder_internal_link = nc_folder_internal_link 89 | 90 | pibidav.nc_folder = root_path 91 | pibidav.nc_folder_internal_link = nc_folder_internal_link 92 | 93 | ## Create shared Link 94 | if secret is not None or sharing_option is not None: 95 | if sharing_option is None: 96 | pibidav.save() 97 | return 98 | share_option = sharing_option.split('-') 99 | share_option = int(share_option[0]) 100 | share_link = nclog.share_file_with_link(path=root_path) 101 | if share_link: 102 | ## Create public link 103 | publink = share_link.get_link() 104 | nc_folder_share_link = '' + publink + '' 106 | pibidav.nc_folder_share_link = nc_folder_share_link 107 | intlink = share_link.get_id() 108 | ## Change perms from read to update 109 | #oth = {'perms': sharing_option, 'secret': secret} 110 | oth = {} 111 | if share_option: 112 | oth = { 'perms': share_option } 113 | pibidav.sharing_option = sharing_option 114 | if secret is not None and secret != '': 115 | oth['password'] = str(secret) 116 | pibidav.secret = secret 117 | nclog.update_share(intlink, **oth) 118 | 119 | pibidav.save() 120 | nclog.logout() 121 | 122 | @frappe.whitelist() 123 | def get_native(parent, filetype): 124 | native_list = frappe.db.get_list('Deliverable Item', 125 | filters={ 126 | 'docstatus': ['<', 2], 127 | 'parent': parent, 128 | 'filetype': filetype 129 | }, 130 | fields=['attachment','delivery_date'], 131 | order_by='delivery_date desc' 132 | ) 133 | 134 | return native_list 135 | 136 | @frappe.whitelist() 137 | def check_nextcloud(): 138 | doc = frappe.get_doc("NextCloud Settings", "NextCloud Settings") 139 | nc_url = doc.nc_backup_url 140 | nc_username = doc.nc_backup_username 141 | nc_token = get_decrypted_password('NextCloud Settings', doc.name, 'nc_backup_token', True) 142 | try: 143 | nc = nextcloud.Client(nc_url) 144 | nc.login(nc_username, nc_token) 145 | frappe.msgprint(_("NextCloud Credentials are correct")) 146 | nc.logout() 147 | except: 148 | frappe.throw(_("NextCloud Credentials not correct, please rectify")) 149 | 150 | def make_nc_session_user(user): 151 | if user.nextcloud_enable: 152 | if user.nextcloud_url and user.nextcloud_username and user.nextcloud_token: 153 | nc_token = get_decrypted_password('User', user.name, 'nextcloud_token', False) 154 | try: 155 | _session = nextcloud.Client(user.nextcloud_url) 156 | _session.login(user.nextcloud_username, nc_token) 157 | return _session 158 | except Exception as err: 159 | frappe.throw(_("Error in login in NC: " + str(err))) 160 | return "Failed" 161 | else: 162 | frappe.msgprint(_("User has errors in credentials for NC")) 163 | return "Failed" 164 | else: 165 | frappe.msgprint(_("User has not enabled NC")) 166 | return "Failed" 167 | 168 | @frappe.whitelist() 169 | def get_nc_nodes(path): 170 | nc_user = frappe.get_doc("User", frappe.session.user) 171 | nc = make_nc_session_user(nc_user) 172 | 173 | if nc == "Failed": 174 | return [{"title": "Check NextCloud User Settings"}] 175 | 176 | ## Get DAV List from NC Server 177 | """nc_nodes = nc.list( 178 | path, 179 | depth=1, 180 | properties=[ 181 | '{DAV:}getetag', 182 | '{DAV:}getlastmodified', 183 | '{http://owncloud.org/ns}fileid' 184 | ] 185 | )""" 186 | nc_nodes = nc.list(path, depth=1, properties=['{http://owncloud.org/ns}fileid']) 187 | 188 | nodes = [] 189 | for row in nc_nodes: 190 | node = {} 191 | if row.file_type == 'dir': 192 | folder = row.path[:-1] 193 | pos = folder.rfind("/") 194 | node['folder'] = 1 195 | node['title'] = folder[pos+1:] 196 | else: 197 | folder = row.path 198 | pos = folder.rfind("/") 199 | node['title'] = folder[pos+1:] 200 | node['path'] = row.path 201 | node['fileid'] = row.attributes['{http://owncloud.org/ns}fileid'] 202 | nodes.append(node) 203 | 204 | #nc.logout() 205 | 206 | return nodes 207 | 208 | def tag_file_fp(doc, method=None): 209 | if doc.attached_to_doctype and doc.attached_to_name: 210 | dctype = doc.attached_to_doctype 211 | dcname = doc.attached_to_name 212 | ## Get DocType attached to File 213 | dt = frappe.get_doc(dctype, dcname) 214 | ## Assign default tag to DocType name to the tag list 215 | tag_list = [dctype] 216 | ## Add user tags to tag list if any 217 | if hasattr(dt, "_user_tags"): 218 | if dt._user_tags is not None: 219 | if len(dt._user_tags) > 0: 220 | user_tags = dt._user_tags.split(',') 221 | for lbl in user_tags: 222 | if lbl is not None and lbl not in tag_list and lbl != "": tag_list.append(lbl) 223 | ## Get all docfields for tagging the DocType from NextCloud Settings 224 | _fields_to_tag = frappe.db.get_value("Reference Item", {"parent": "NextCloud Settings", "reference_doctype": dctype}, "reference_docfield") 225 | ## Assign tags to DocType in Frappe (limited length 60 chars due to NextCloud Limits) 226 | if _fields_to_tag: 227 | fields_to_tag = _fields_to_tag.split(',') 228 | for item in fields_to_tag: 229 | try: 230 | if not ',' in dt.get(item): 231 | fp_tag = dt.get(item) #frappe.db.get_value(dctype, dcname, item) 232 | if fp_tag is not None and fp_tag not in tag_list and fp_tag != "": tag_list.append(fp_tag) 233 | for el in tag_list: 234 | if el != '' and el is not None and len(el) > 0 and len(el) <= 60: tag.add_tag(el, "File", doc.name) 235 | except: 236 | pass 237 | else: 238 | tag.add_tag(dctype, "File", doc.name) 239 | else: 240 | tag_list = [] 241 | 242 | return tag_list 243 | 244 | def get_tagid(session, tag): 245 | taglist = session.list_tags() 246 | for item in taglist: 247 | if item.attributes['{http://owncloud.org/ns}display-name'] == tag: 248 | tag_id = item.attributes['{http://owncloud.org/ns}id'] 249 | return tag_id 250 | 251 | def tag_file_nc(nc_session, filepath, tags): 252 | nc_tags = [] 253 | ## Get fileid fron nc uploaded file 254 | remotefile = nc_session.file_info(filepath, properties=['{http://owncloud.org/ns}fileid']) 255 | if remotefile: 256 | fileid = remotefile.attributes['{http://owncloud.org/ns}fileid'] 257 | ## Write tags to uploaded file 258 | try: 259 | for tag in tags: 260 | res = nc_session.add_tag(tag) 261 | if res == 409: 262 | tagid = get_tagid(nc_session, tag) 263 | else: 264 | tag_res = res.split('/') 265 | tagid = tag_res[len(tag_res)-1] 266 | if not tagid in nc_tags: 267 | nc_tags.append({"display-name": tag, "tagid": tagid}) 268 | ## Add tag to file 269 | nc_session.assign_tag_to_file(fileid, tagid) 270 | except Exception as err: 271 | #return err 272 | nc_tags = [] 273 | pass 274 | return fileid, nc_tags 275 | 276 | @frappe.whitelist() 277 | def upload_file_to_nc(doc, method=None): 278 | ## Tag File in Frappe 279 | _tag_list = tag_file_fp(doc) 280 | ## Method only valid for Files, not WebSites 281 | if 'http' in doc.file_url: 282 | return 283 | ## Check docs excluded and included in the NC Integration 284 | docs_excluded = frappe.get_value("NextCloud Settings", "NextCloud Settings", "nc_doctype_excluded") 285 | docs_included = frappe.get_value("NextCloud Settings", "NextCloud Settings", "nc_doctype_included") 286 | nc_url = frappe.get_value("NextCloud Settings", "NextCloud Settings", "nc_backup_url") 287 | if not nc_url: 288 | return 289 | if not nc_url[-1] == '/': nc_url += '/' 290 | ## Check the file attached to parent docType and its inclusion in the list 291 | dt = doc.attached_to_doctype 292 | if docs_excluded and dt: 293 | if dt in docs_excluded: 294 | return 295 | ## Get name of file attached to doctype and file_name and local server path 296 | dn = doc.attached_to_name 297 | file_name = doc.file_name 298 | local_path = get_file_path(file_name) 299 | ## Method only valid for docTypes not being Files 300 | if dt != 'File' and dn: 301 | ## check whether document has NC addon extension active 302 | document = check_addon(dt,dn) 303 | 304 | #document = frappe.get_doc(dt, dn) 305 | ## Check whether doctype has NextCloud Integration active 306 | if not hasattr(document, "nc_enable"): 307 | return 308 | ## Continues if NC Integration is enabled and NC Destination Folder given 309 | if document.nc_enable and document.nc_folder: 310 | local_site = frappe.utils.get_url() 311 | ## Get current logged user and makes session in NC 312 | nc_user = frappe.get_doc("User", frappe.session.user) 313 | nc = make_nc_session_user(nc_user) 314 | if nc == "Failed": 315 | return frappe.msgprint(_("Error in NC Login")) 316 | ## Continues to upload files to NC 317 | nc_path = document.nc_folder + file_name 318 | nc_args = { 319 | 'remote_path': nc_path, 320 | 'local_source_file': local_path 321 | } 322 | ## Upload file to NC 323 | enqueue(method=nc.put_file,queue='short',timeout=300,now=True,**nc_args) 324 | ## Get Shared Link from NC 325 | share = enqueue(method=nc.share_file_with_link, queue='short', timeout=600, now=True, path=nc_path) 326 | ## Update and save File in frappe updated with NC data 327 | doc.uploaded_to_nextcloud = 1 328 | doc.folder_path = document.nc_folder 329 | doc.share_link = share.get_link() 330 | 331 | fileid, nctags = tag_file_nc(nc, nc_path, _tag_list) 332 | doc.fileid = fileid 333 | ## Register nc tagids into frappe tags 334 | if len(nctags) > 0: 335 | for strtag in nctags: 336 | fptag = frappe.get_doc("Tag", strtag['display-name']) 337 | if fptag: 338 | fptag.uploaded_to_nextcloud = 1 339 | fptag.tagid = strtag['tagid'] 340 | fptag.save() 341 | 342 | doc.save() 343 | nc.logout() 344 | 345 | return {'fname': doc, 'local_path': local_path, 'local_site': share.get_link()} 346 | else: 347 | return 348 | 349 | @frappe.whitelist() 350 | def get_nc_settings(doctype): 351 | use_default = frappe.get_list("Reference Item", {"parent": "NextCloud Settings", "reference_doctype": doctype}, "use_default_folder") 352 | if use_default: 353 | if use_default[0]['use_default_folder']: 354 | path = frappe.get_list("Reference Item", {"parent": "NextCloud Settings", "reference_doctype": doctype}, "nc_folder") 355 | nc_folder = path[0]['nc_folder'] 356 | if nc_folder[-1] != '/': nc_folder + '/' 357 | return nc_folder 358 | 359 | @frappe.whitelist() 360 | def update_attachment_item(dt, dn): 361 | nc_url = frappe.get_value("NextCloud Settings", "NextCloud Settings", "nc_backup_url") 362 | if not nc_url[-1] == '/': nc_url += '/' 363 | ## Get a list of all files attached to doctype and uploaded to NC 364 | attached_to_doctype = frappe.get_list( 365 | doctype = "File", 366 | fields = ["*"], 367 | filters = [ 368 | ["attached_to_doctype", "=", dt], 369 | ["attached_to_name", "=", dn], 370 | ["uploaded_to_nextcloud", "=", 1], 371 | ["docstatus", "<", 1] 372 | ] 373 | ) 374 | 375 | doc = frappe.get_doc("PibiDAV Addon", "pbc_" + dn) 376 | if doc is None: 377 | return 378 | 379 | if len(attached_to_doctype) > 0 and hasattr(doc, "nc_enable"): 380 | if hasattr(doc, "attachment_item"): 381 | attachment_item = doc.attachment_item 382 | if len(attachment_item) > 0: 383 | ## Update attachments uploaded to NC 384 | ## Get all files attached to docname 385 | _attachment_item = [] 386 | for item in attachment_item: 387 | if item.attachment not in _attachment_item: 388 | _attachment_item.append(item.attachment) 389 | for row in attached_to_doctype: 390 | if row.name not in _attachment_item: 391 | nc_link = 'NextCloud' 394 | json_item = { 395 | "attachment": row.name, 396 | "filename": row.file_name, 397 | "uploaded_to_nc": row.uploaded_to_nextcloud, 398 | "nc_path": row.folder_path, 399 | "nc_link": row.share_link, 400 | "nc_private": nc_url + 'apps/files/?fileid=' + row.fileid, 401 | "nc_url": nc_link 402 | } 403 | doc.append("attachment_item", json_item) 404 | doc.save() 405 | frappe.db.commit() 406 | else: 407 | ## Create new attachment item 408 | for row in attached_to_doctype: 409 | nc_link = 'NextCloud' 412 | json_item = { 413 | "attachment": row.name, 414 | "filename": row.file_name, 415 | "uploaded_to_nc": row.uploaded_to_nextcloud, 416 | "nc_path": row.folder_path, 417 | "nc_link": row.share_link, 418 | "nc_private": nc_url + 'apps/files/?fileid=' + row.fileid, 419 | "nc_url": nc_link 420 | } 421 | doc.append("attachment_item", json_item) 422 | doc.save() 423 | frappe.db.commit() 424 | 425 | @frappe.whitelist() 426 | def upload_nc_file(remote_path, local_file): 427 | ## Get bench path 428 | fname = frappe.get_doc('File', local_file) 429 | ## Only applicable if File is not attached to any doctype 430 | if not fname.attached_to_doctype == 'File' or 'http' in fname.file_url: 431 | return 432 | 433 | local_site = frappe.utils.get_url() 434 | local_path = get_file_path(local_file) 435 | nc_user = frappe.get_doc("User", frappe.session.user) 436 | nc = make_nc_session_user(nc_user) 437 | 438 | if nc == "Failed": 439 | return frappe.msgprint(_("Error in NC Login")) 440 | 441 | nc_args = { 442 | 'remote_path': remote_path, 443 | 'local_source_file': local_path 444 | } 445 | enqueue(method=nc.put_file,queue='short',timeout=300,now=True,**nc_args) 446 | 447 | fname.uploaded_to_nextcloud = 1 448 | fname.folder_path = remote_path.replace(fname.file_name, '') 449 | fname.save() 450 | 451 | nc.logout() 452 | 453 | return {'fname': fname, 'local_path': local_path, 'local_site': local_site} 454 | 455 | @frappe.whitelist() 456 | def get_nc_files_in_folder(folder, start=0, page_length=20): 457 | start = cint(start) 458 | page_length = cint(page_length) 459 | if folder == 0: folder = "/" 460 | 461 | nc_user = frappe.get_doc("User", frappe.session.user) 462 | 463 | nc = make_nc_session_user(nc_user) 464 | 465 | if nc == "Failed": 466 | return {"files": ["Enable NextCloud on User Settings"], 467 | "has_more": 0 468 | } 469 | 470 | ## Get DAV List from NC Server 471 | #nc_nodes = nc.list(path, depth=1, properties=['{DAV:}getetag','{DAV:}getlastmodified','{http://owncloud.org/ns}fileid']) 472 | nc_nodes = nc.list(folder, depth=1, properties=['{http://owncloud.org/ns}fileid', '{DAV:}getlastmodified']) 473 | 474 | nodes = [] 475 | for row in nc_nodes: 476 | node = {} 477 | if row.file_type == 'dir': 478 | folder = row.path[:-1] 479 | pos = folder.rfind("/") 480 | node['is_folder'] = 1 481 | node['file_name'] = folder[pos+1:] 482 | else: 483 | folder = row.path 484 | pos = folder.rfind("/") 485 | node['is_folder'] = 0 486 | node['file_name'] = folder[pos+1:] 487 | node['name'] = row.path 488 | node['file_url'] = row.attributes['{http://owncloud.org/ns}fileid'] 489 | node['modified'] = row.attributes['{DAV:}getlastmodified'] 490 | nodes.append(node) 491 | start += 1 492 | if start == page_length: 493 | break 494 | 495 | #nc.logout() 496 | 497 | return { 498 | 'files': nodes[:page_length], 499 | 'has_more': len(nodes) > page_length 500 | } 501 | 502 | @frappe.whitelist() 503 | def make_nc_session(): 504 | nc_settings = frappe.get_doc('NextCloud Settings', 'NextCloud Settings') 505 | if nc_settings.nc_backup_enable: 506 | nc_token = get_decrypted_password('NextCloud Settings', 'NextCloud Settings', 'nc_backup_token', True) 507 | args = { 508 | "verify_certs": False 509 | } 510 | session = nextcloud.Client(nc_settings.nc_backup_url, **args) 511 | session.login(nc_settings.nc_backup_username, nc_token) 512 | return session 513 | else: 514 | frappe.msgprint(_("NextCloud Integration not Enabled")) 515 | 516 | @frappe.whitelist() 517 | def create_nc_group(alias): 518 | ## Login in NC as superuser 519 | nclient = make_nc_session() 520 | ## Create NC Group with name alias 521 | ## Check if group exists first 522 | doGroup = nclient.group_exists(alias.upper()) 523 | if doGroup: 524 | frappe.msgprint(_("NC Group Already Exists")) 525 | else: 526 | res = nclient.create_group(alias.upper()) 527 | if res: 528 | frappe.msgprint(_("NC Group Created")) 529 | else: 530 | frappe.msgprint(_("Error Creating NC Group")) 531 | 532 | @frappe.whitelist() 533 | def create_nc_dirs(node_name, path, abbrv, strmain, digits): 534 | """ Create folders in NC Instance on path 535 | node_name = '(BPJ) Project' 536 | path = "/Projects/" 537 | abbrv = "PRJ22PBC" 538 | ref_doctype = "pb_Project" ?? 539 | strmain = "NC Integration" """ 540 | 541 | ## Include tags as Project Name, abbreviation, Customer 542 | ## ---- 543 | 544 | ## Login in NC as superuser 545 | nclient = make_nc_session() 546 | ## Create root path and recursively the rest as per origin structure in selected node in folder set 547 | root_node = node_name 548 | n = int(digits) 549 | """ 550 | ## Check if selected node is root or not 551 | root_parent = frappe.db.get_value("Folder Set", {"name": node_name}, "root_parent") 552 | if root_parent == root_node: 553 | ## Change title depending on ref_doctype 554 | root_path = path + abbrv + " " + strmain + "/" 555 | else: 556 | root_path = path + node_name[n+1:] + "/" 557 | """ 558 | ## Root path is different from the rest of nodes 559 | root_path = "{}{} {}/".format(path, abbrv, strmain) 560 | ## Create first node in NC 561 | folder = nclient.mkdir(root_path) 562 | ## If dir is created in NC, continues recursively with its children 563 | if folder: 564 | children = get_children(nclient, root_node, root_path, abbrv, n) 565 | else: 566 | frappe.msgprint(_("Error creating root folder in NC")) 567 | 568 | return frappe.msgprint(_("Successfully Created Folders in NC")) 569 | 570 | def get_children(session, parent_node, parent_path, abr, n): 571 | children_list = [] 572 | ## Get all children folders only for given node 573 | children = frappe.get_list( 574 | doctype = "Folder Set", 575 | filters = { 576 | "is_group": 1, 577 | "parent_folder_set": parent_node 578 | }, 579 | fields = ["name", "parent_folder_set", "is_group"], 580 | order_by = "creation asc" 581 | ) 582 | ## Get recursively the rest of children an create folders in NC 583 | if len(children) > 0: 584 | for child in children: 585 | if child.name not in children_list: children_list.append(child.name) 586 | parent_path_child = "{}{} {}/".format(parent_path, abr, child.name[n+1:]) 587 | ## Create folder in NC 588 | folder = session.mkdir(parent_path_child) 589 | ## If folder is created continues recursively 590 | if folder: 591 | get_children(session, child.name, parent_path_child, abr, n) 592 | else: 593 | frappe.msgprint(_("Error creating child folder in NC")) 594 | 595 | return children_list 596 | 597 | def check_addon(dt, dn): 598 | ## First we'll check and create pibiDAV Addon doctype related 599 | addon_list = frappe.db.get_list('PibiDAV Addon', 600 | filters={ 601 | 'docstatus': ['<', 2], 602 | 'name': "pbc_{}".format(dn) 603 | }, 604 | fields=['*'] 605 | ) 606 | if len(addon_list) == 0: 607 | ## Create pibiDAV Addon doctype 608 | pibidav = frappe.new_doc("PibiDAV Addon") 609 | pibidav.ref_doctype = dt 610 | pibidav.ref_docname = dn 611 | ## Get default data from NextCloud Settings 612 | settings = frappe.db.get_value("Reference Item", {"parent": "NextCloud Settings", "reference_doctype": dt},['nc_folder'], as_dict = 1) 613 | if settings is not None: 614 | if settings.use_default_folder and settings.nc_folder: 615 | pibidav.nc_folder = settings.nc_folder 616 | pibidav.insert() 617 | frappe.db.commit() 618 | else: 619 | pibidav = frappe.get_doc("PibiDAV Addon", "pbc_{}".format(dn)) 620 | 621 | return pibidav 622 | 623 | @frappe.whitelist() 624 | def fetch_nc_folder_internal_link_from_addon(addon_name): 625 | pibidav = frappe.get_doc("PibiDAV Addon", addon_name) 626 | if not pibidav.nc_folder: 627 | frappe.throw(_("No NC Folder defined in the Addon.")) 628 | 629 | session = make_nc_session() # Authenticate as superuser 630 | fileinfo = session.file_info(pibidav.nc_folder, properties=['{http://owncloud.org/ns}fileid']) 631 | if fileinfo: 632 | fileid = fileinfo.attributes['{http://owncloud.org/ns}fileid'] 633 | nc_url = frappe.get_value("NextCloud Settings", "NextCloud Settings", "nc_backup_url") 634 | if nc_url[-1] != '/': 635 | nc_url += '/' 636 | intlink = f'{nc_url}f/{fileid}' 637 | pibidav.nc_folder_internal_link = intlink 638 | pibidav.save() 639 | return intlink 640 | else: 641 | frappe.throw(_("Failed to fetch folder metadata from NextCloud.")) 642 | 643 | @frappe.whitelist() 644 | def get_folder_path_from_link(fileid): 645 | """ 646 | Retrieves the full folder path using the fileid. 647 | 648 | :param fileid: File ID from the NextCloud folder link 649 | :return: Full path of the folder or an error message 650 | """ 651 | if not fileid: 652 | frappe.log_error("No fileid provided to get_folder_path_from_link.") 653 | return "Error: fileid is empty." 654 | 655 | try: 656 | # Create a NextCloud session 657 | nc_session = make_nc_session() 658 | if not nc_session or nc_session == "Failed": 659 | frappe.log_error("Failed to establish session with NextCloud.") 660 | return "Error: Unable to establish session with NextCloud." 661 | 662 | # Log the fileid for debugging 663 | frappe.logger().info(f"Fetching directory for fileid: {fileid}") 664 | 665 | # Use the NextCloud session to fetch the folder path 666 | folder_path = nc_session.get_path_from_fileid(fileid) 667 | #nc_session.logout() 668 | 669 | if folder_path: 670 | frappe.logger().info(f"Retrieved folder path for fileid {fileid}: {folder_path}") 671 | return folder_path 672 | else: 673 | frappe.log_error(f"Folder path not found for fileid: {fileid}") 674 | return "Folder path not found." 675 | except Exception as e: 676 | # Log the error with a full traceback for debugging 677 | frappe.log_error(message=f"Error retrieving folder path for fileid {fileid}: {e}", title="NextCloud Path Retrieval Error") 678 | return f"Error retrieving folder path: {e}" 679 | 680 | @frappe.whitelist() 681 | def create_nc_subfolder(parent_folder, folder_name): 682 | try: 683 | session = make_nc_session() 684 | if session == "Failed": 685 | return frappe.throw(_("Error in NC Login")) 686 | 687 | # Ensure parent folder starts with / 688 | if not parent_folder.startswith('/'): 689 | parent_folder = '/' + parent_folder 690 | 691 | # Create full path 692 | new_folder_path = f"{parent_folder}/{folder_name}" 693 | if new_folder_path.startswith('//'): 694 | new_folder_path = new_folder_path[1:] 695 | 696 | # Create folder using NextCloud client 697 | session.mkdir(new_folder_path) 698 | session.logout() 699 | 700 | return new_folder_path 701 | 702 | except Exception as e: 703 | frappe.log_error(message=f"Error creating NextCloud subfolder: {str(e)}", title="NextCloud Folder Creation Error") 704 | return frappe.throw(_("Failed to create folder in NextCloud: {0}").format(str(e))) -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pibico/pibiDAV/660caffafd274f1dcf6c42024d5f67bccd5c8509/pibidav/pibidav/doctype/__init__.py -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/attachment_item/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pibico/pibiDAV/660caffafd274f1dcf6c42024d5f67bccd5c8509/pibidav/pibidav/doctype/attachment_item/__init__.py -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/attachment_item/attachment_item.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "creation": "2022-04-17 09:45:52.593268", 5 | "doctype": "DocType", 6 | "editable_grid": 1, 7 | "engine": "InnoDB", 8 | "field_order": [ 9 | "attachment", 10 | "file_category", 11 | "filename", 12 | "cb_01", 13 | "uploaded_to_nc", 14 | "nc_path", 15 | "nc_link", 16 | "nc_private", 17 | "nc_url" 18 | ], 19 | "fields": [ 20 | { 21 | "fieldname": "attachment", 22 | "fieldtype": "Link", 23 | "in_list_view": 1, 24 | "label": "Attachment", 25 | "options": "File", 26 | "reqd": 1 27 | }, 28 | { 29 | "fieldname": "file_category", 30 | "fieldtype": "Link", 31 | "in_list_view": 1, 32 | "label": "File Type", 33 | "options": "File Category" 34 | }, 35 | { 36 | "fetch_from": "attachment.file_name", 37 | "fieldname": "filename", 38 | "fieldtype": "Data", 39 | "in_list_view": 1, 40 | "label": "Filename", 41 | "read_only": 1 42 | }, 43 | { 44 | "default": "0", 45 | "fetch_from": "attachment.uploaded_to_nextcloud", 46 | "fieldname": "uploaded_to_nc", 47 | "fieldtype": "Check", 48 | "in_list_view": 1, 49 | "label": "Uploaded To NC", 50 | "read_only": 1 51 | }, 52 | { 53 | "fetch_from": "attachment.folder_path", 54 | "fieldname": "nc_path", 55 | "fieldtype": "Text", 56 | "in_list_view": 1, 57 | "label": "NC Path", 58 | "read_only": 1 59 | }, 60 | { 61 | "fetch_from": "attachment.share_link", 62 | "fieldname": "nc_link", 63 | "fieldtype": "Data", 64 | "in_list_view": 1, 65 | "label": "NC Share Link", 66 | "read_only": 1 67 | }, 68 | { 69 | "fieldname": "nc_private", 70 | "fieldtype": "Data", 71 | "in_list_view": 1, 72 | "label": "NC Private Link", 73 | "read_only": 1 74 | }, 75 | { 76 | "fieldname": "nc_url", 77 | "fieldtype": "Read Only", 78 | "label": "NC URL" 79 | }, 80 | { 81 | "fieldname": "cb_01", 82 | "fieldtype": "Column Break", 83 | "label": "NexCloud" 84 | } 85 | ], 86 | "index_web_pages_for_search": 1, 87 | "istable": 1, 88 | "links": [], 89 | "modified": "2022-05-03 17:53:23.263098", 90 | "modified_by": "Administrator", 91 | "module": "Pibidav", 92 | "name": "Attachment Item", 93 | "owner": "Administrator", 94 | "permissions": [], 95 | "sort_field": "modified", 96 | "sort_order": "DESC" 97 | } -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/attachment_item/attachment_item.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, pibiCo and contributors 2 | # For license information, please see license.txt 3 | 4 | # import frappe 5 | from frappe.model.document import Document 6 | 7 | class AttachmentItem(Document): 8 | pass 9 | -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/file_category/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pibico/pibiDAV/660caffafd274f1dcf6c42024d5f67bccd5c8509/pibidav/pibidav/doctype/file_category/__init__.py -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/file_category/file_category.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, pibiCo and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('File Category', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/file_category/file_category.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "autoname": "field:title", 5 | "creation": "2022-04-27 10:19:29.164957", 6 | "doctype": "DocType", 7 | "document_type": "Setup", 8 | "editable_grid": 1, 9 | "engine": "InnoDB", 10 | "field_order": [ 11 | "title", 12 | "description" 13 | ], 14 | "fields": [ 15 | { 16 | "fieldname": "title", 17 | "fieldtype": "Data", 18 | "label": "title", 19 | "unique": 1 20 | }, 21 | { 22 | "fieldname": "description", 23 | "fieldtype": "Text", 24 | "label": "Description" 25 | } 26 | ], 27 | "index_web_pages_for_search": 1, 28 | "links": [], 29 | "modified": "2022-04-28 14:10:20.613874", 30 | "modified_by": "Administrator", 31 | "module": "Pibidav", 32 | "name": "File Category", 33 | "owner": "Administrator", 34 | "permissions": [ 35 | { 36 | "create": 1, 37 | "delete": 1, 38 | "email": 1, 39 | "export": 1, 40 | "print": 1, 41 | "read": 1, 42 | "report": 1, 43 | "role": "System Manager", 44 | "share": 1, 45 | "write": 1 46 | }, 47 | { 48 | "create": 1, 49 | "delete": 1, 50 | "email": 1, 51 | "export": 1, 52 | "print": 1, 53 | "read": 1, 54 | "report": 1, 55 | "role": "Docs Controller", 56 | "share": 1, 57 | "write": 1 58 | }, 59 | { 60 | "email": 1, 61 | "export": 1, 62 | "print": 1, 63 | "read": 1, 64 | "report": 1, 65 | "role": "Docs User", 66 | "share": 1 67 | }, 68 | { 69 | "email": 1, 70 | "export": 1, 71 | "print": 1, 72 | "read": 1, 73 | "report": 1, 74 | "role": "NextCloud User", 75 | "share": 1 76 | }, 77 | { 78 | "read": 1, 79 | "role": "Vendor" 80 | } 81 | ], 82 | "sort_field": "modified", 83 | "sort_order": "DESC", 84 | "track_changes": 1 85 | } -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/file_category/file_category.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, pibiCo and contributors 2 | # For license information, please see license.txt 3 | 4 | # import frappe 5 | from frappe.model.document import Document 6 | 7 | class FileCategory(Document): 8 | pass 9 | -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/file_category/test_file_category.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, pibiCo and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | import unittest 6 | 7 | class TestFileCategory(unittest.TestCase): 8 | pass 9 | -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/folder_set/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pibico/pibiDAV/660caffafd274f1dcf6c42024d5f67bccd5c8509/pibidav/pibidav/doctype/folder_set/__init__.py -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/folder_set/folder_set.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, pibiCo and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Folder Set', { 5 | select_nc_folder: function(frm) { 6 | new frappe.ui.pibiDocs; 7 | } 8 | }); -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/folder_set/folder_set.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "creation": "2022-04-21 19:00:30.884664", 5 | "doctype": "DocType", 6 | "document_type": "Setup", 7 | "editable_grid": 1, 8 | "engine": "InnoDB", 9 | "field_order": [ 10 | "is_group", 11 | "title", 12 | "cb_01", 13 | "select_nc_folder", 14 | "old_parent", 15 | "root_parent", 16 | "parent_folder_set", 17 | "nc_folder", 18 | "lft", 19 | "rgt" 20 | ], 21 | "fields": [ 22 | { 23 | "default": "0", 24 | "fieldname": "is_group", 25 | "fieldtype": "Check", 26 | "label": "Is Folder" 27 | }, 28 | { 29 | "fieldname": "title", 30 | "fieldtype": "Data", 31 | "in_list_view": 1, 32 | "label": "Title", 33 | "reqd": 1, 34 | "unique": 1 35 | }, 36 | { 37 | "fieldname": "cb_01", 38 | "fieldtype": "Column Break" 39 | }, 40 | { 41 | "fieldname": "old_parent", 42 | "fieldtype": "Link", 43 | "label": "Old Parent", 44 | "options": "Folder Set" 45 | }, 46 | { 47 | "fieldname": "root_parent", 48 | "fieldtype": "Link", 49 | "label": "Root Parent", 50 | "options": "Folder Set" 51 | }, 52 | { 53 | "fieldname": "parent_folder_set", 54 | "fieldtype": "Link", 55 | "label": "Parent Folder Set", 56 | "options": "Folder Set" 57 | }, 58 | { 59 | "fieldname": "nc_folder", 60 | "fieldtype": "Text", 61 | "label": "NC Folder" 62 | }, 63 | { 64 | "fieldname": "lft", 65 | "fieldtype": "Int", 66 | "hidden": 1, 67 | "label": "Left", 68 | "no_copy": 1, 69 | "read_only": 1 70 | }, 71 | { 72 | "fieldname": "rgt", 73 | "fieldtype": "Int", 74 | "hidden": 1, 75 | "label": "Right", 76 | "no_copy": 1, 77 | "read_only": 1 78 | }, 79 | { 80 | "fieldname": "select_nc_folder", 81 | "fieldtype": "Button", 82 | "label": "Select NC Folder" 83 | } 84 | ], 85 | "icon": "folder", 86 | "index_web_pages_for_search": 1, 87 | "is_tree": 1, 88 | "links": [], 89 | "modified": "2022-05-11 10:34:30.594028", 90 | "modified_by": "Administrator", 91 | "module": "Pibidav", 92 | "name": "Folder Set", 93 | "nsm_parent_field": "parent_folder_set", 94 | "owner": "Administrator", 95 | "permissions": [ 96 | { 97 | "create": 1, 98 | "delete": 1, 99 | "email": 1, 100 | "export": 1, 101 | "print": 1, 102 | "read": 1, 103 | "report": 1, 104 | "role": "System Manager", 105 | "share": 1, 106 | "write": 1 107 | }, 108 | { 109 | "create": 1, 110 | "delete": 1, 111 | "email": 1, 112 | "export": 1, 113 | "print": 1, 114 | "read": 1, 115 | "report": 1, 116 | "role": "All", 117 | "share": 1, 118 | "write": 1 119 | } 120 | ], 121 | "quick_entry": 1, 122 | "search_fields": "root_parent,parent_folder_set", 123 | "sort_field": "modified", 124 | "sort_order": "DESC", 125 | "title_field": "title" 126 | } -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/folder_set/folder_set.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, pibiCo and contributors 2 | # For license information, please see license.txt 3 | 4 | import frappe 5 | from frappe import _ 6 | from frappe.utils.nestedset import NestedSet 7 | 8 | import frappe.model.rename_doc 9 | 10 | class FolderSet(NestedSet): 11 | def before_save(doc): 12 | if doc.parent_folder_set and doc.parent_folder_set != '': 13 | doc.root_parent = frappe.db.get_value('Folder Set', doc.parent_folder_set, 'root_parent') 14 | 15 | def after_insert(doc): 16 | old_name = doc.name 17 | r = frappe.db.get_value('Folder Set', doc.title, 'name') 18 | if r and r == doc.title: 19 | doc.name = doc.title + ' (' + old_name + ')' 20 | else: 21 | doc.name = doc.title 22 | 23 | if not doc.parent_folder_set or doc.parent_folder_set == '': 24 | doc.root_parent = doc.name 25 | frappe.db.set_value('Folder Set', old_name, { 26 | 'name': doc.name, 27 | 'root_parent': doc.root_parent, 28 | 'title': doc.name 29 | }, update_modified=False) 30 | 31 | @frappe.whitelist() 32 | def get_children(doctype, parent='', **filters): 33 | return _get_children(doctype, parent) 34 | 35 | def _get_children(doctype, parent='', ignore_permissions=False): 36 | parent_field = 'parent_' + doctype.lower().replace(' ', '_') 37 | filters = [['ifnull(`{0}`,"")'.format(parent_field), '=', parent], 38 | ['docstatus', '<' ,'2']] 39 | 40 | meta = frappe.get_meta(doctype) 41 | 42 | return frappe.get_list( 43 | doctype, 44 | fields=[ 45 | 'name as value', 46 | '{0} as title'.format(meta.get('title_field') or 'name'), 47 | 'is_group as expandable' 48 | ], 49 | filters=filters, 50 | order_by='title', 51 | ignore_permissions=ignore_permissions 52 | ) 53 | 54 | @frappe.whitelist() 55 | def rename(old, new, debug=False): 56 | return frappe.model.rename_doc.rename_doc('Folder Set', old, new, debug) -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/folder_set/folder_set_tree.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, pibiCo and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.provide("frappe.treeview_settings"); 5 | frappe.provide('frappe.views'); 6 | 7 | frappe.treeview_settings['Folder Set'] = { 8 | breadcrumbs: "Templates", 9 | title: __('Folder Set'), 10 | get_tree_root: false, 11 | root_label: "", 12 | get_tree_nodes: 'pibidav.pibidav.doctype.folder_set.folder_set.get_children', 13 | filters: [ 14 | { 15 | fieldname: "root_parent", 16 | fieldtype: "Link", 17 | options: "Folder Set", 18 | label: __("Tree"), 19 | default: "BPJ Big Project", 20 | get_query: function() { 21 | var args = [ 22 | ["Folder Set", 'is_group', '=', 1], 23 | ["Folder Set", 'parent_folder_set', '=', ''] 24 | ]; 25 | return {filters: args}; 26 | } 27 | } 28 | ], 29 | post_render: function(treeview) { 30 | treeview.args['is_group'] = 1; 31 | }, 32 | extend_toolbar: false, 33 | toolbar: [ 34 | { 35 | label:__("Edit"), 36 | condition: function(node) { 37 | var me = frappe.views.trees['Folder Set']; 38 | return !node.is_root && me.can_read; 39 | }, 40 | click: function(node) { 41 | var me = frappe.views.trees['Folder Set']; 42 | frappe.set_route("Form", me.doctype, node.label); 43 | } 44 | }, 45 | { 46 | label:__("Add Child"), 47 | condition: function(node) { 48 | var me = frappe.views.trees['Folder Set']; 49 | if (me.can_create && node.expandable && !node.hide_add) { 50 | try { 51 | if (node.parent_node.hide_add) { node.hide_add = true; } 52 | } 53 | catch (e) { } 54 | } 55 | return me.can_create && node.expandable && !node.hide_add; 56 | }, 57 | click: function(node) { 58 | var me = frappe.views.trees['Folder Set']; 59 | me.new_node(); 60 | }//, 61 | //btnClass: "hidden-xs" 62 | }, 63 | { 64 | label:__("Delete"), 65 | async: false, 66 | condition: function(node) { 67 | var allow_delete = true; 68 | var me = frappe.views.trees['Folder Set']; 69 | try { if (node.parent_node.hide_add) { allow_delete = false; } 70 | } catch (e) { } 71 | if (allow_delete && me.can_delete && !node.is_root && !node.hide_add && node.expandable) { 72 | frappe.call({ 73 | method: 'frappe.client.get_value', 74 | args: { 75 | 'doctype': 'Folder Set', 76 | 'filters': {'parent_folder_set' : node.label}, 77 | 'fieldname': [ 'name' ] 78 | }, 79 | async: false, 80 | callback: function(r) { 81 | if (!r.exc) { 82 | if (r.message.name && r.message.name !="" && r.message.name != null) allow_delete = false; 83 | return allow_delete; 84 | } 85 | } 86 | }); 87 | } 88 | return allow_delete && me.can_delete && !node.is_root && !node.hide_add; 89 | }, 90 | click: function(node) { 91 | var me = frappe.views.trees['Folder Set']; 92 | frappe.model.delete_doc(me.doctype, node.label, function() { 93 | node.parent.remove(); 94 | }); 95 | }//, 96 | //btnClass: "hidden-xs" 97 | }, 98 | { 99 | label:__("Recreate"), 100 | condition: function(node) { 101 | var allow_create = true; 102 | var me = frappe.views.trees['Folder Set']; 103 | if (node.is_root) { allow_create = false; } 104 | return allow_create && !node.is_root && !node.hide_add; 105 | }, 106 | click: function(node) { 107 | var upload2nc = true; 108 | frappe.db.get_value('Folder Set', {'name': node.title}, 'nc_folder', (r) => { 109 | let nc_folder = r.nc_folder; 110 | if (nc_folder) { 111 | frappe.call({ 112 | method: "pibidav.pibidav.custom.checkNCuser", 113 | args: { 114 | } 115 | }).then(function(r) { 116 | let isUser = r.message; 117 | if (isUser) { 118 | let d = new frappe.ui.Dialog({ 119 | title: __("Recreate Folders in NC"), 120 | fields: [ 121 | { label: __("Parent Path"), fieldname: "parent_path", fieldtype: "Data", default: nc_folder}, 122 | { label: __("Abbreviation"), fieldname: "abbreviation", fieldtype: "Data", default: "PRJYYABV"}, 123 | { label: __("Root Dir Name"), fieldname: "folder_name", fieldtype: "Data"}, 124 | { label: __("Digits to substitute with abbreviation"), fieldname: "digits", fieldtype: "Int", default: 3} 125 | ], 126 | primary_action_label: __("Create"), 127 | primary_action(values) { 128 | //console.log(values); 129 | frappe.call({ 130 | method: "pibidav.pibidav.custom.create_nc_dirs", 131 | args: { 132 | node_name: node.title, 133 | path: values.parent_path, 134 | abbrv: values.abbreviation, 135 | strmain: values.folder_name, 136 | digits: values.digits 137 | }, 138 | callback: function(r) { 139 | console.log(r.message); 140 | } 141 | }); 142 | d.hide(); 143 | } 144 | }); 145 | d.show(); 146 | } else { 147 | frappe.msgprint(__("Only NextCloud SuperUser can use this method")); 148 | } 149 | }); 150 | } else { 151 | frappe.msgprint(__("First Select your NC Destination Folder")); 152 | } 153 | }); 154 | }//, 155 | //btnClass: "hidden-xs" 156 | } 157 | ] 158 | } 159 | 160 | -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/folder_set/test_folder_set.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, pibiCo and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | import unittest 6 | 7 | class TestFolderSet(unittest.TestCase): 8 | pass 9 | -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/nextcloud_settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pibico/pibiDAV/660caffafd274f1dcf6c42024d5f67bccd5c8509/pibidav/pibidav/doctype/nextcloud_settings/__init__.py -------------------------------------------------------------------------------- /pibidav/pibidav/doctype/nextcloud_settings/nextcloud_settings.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, pibiCo and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('NextCloud Settings', { 5 | refresh: function(frm) { 6 | if (frm.doc.nc_backup_enable && frm.doc.nc_backup_url && frm.doc.nc_backup_username && frm.doc.nc_backup_token) { 7 | // add check credentials button 8 | frm.add_custom_button(__("Check Credentials"), function() { 9 | frappe.call({ 10 | method: "pibidav.pibidav.custom.check_nextcloud", 11 | args: { 12 | doc: frm.doc 13 | } 14 | }); 15 | },__("NC Commands")); 16 | // add backup button 17 | frm.add_custom_button(__("Backup Now"), function() { 18 | frappe.call({ 19 | method: "pibidav.pibidav.doctype.nextcloud_settings.nextcloud_settings.take_backup", 20 | freeze: true 21 | }); 22 | }).addClass("btn-primary"); 23 | } 24 | // Fill DocType Included with Data From Reference Item Table 25 | var includeArr = frm.doc.reference_item; 26 | var inclusion = ''; 27 | for (var i=0; iInicio > pibiTools > pibiDAV
\",\"col\":12}},{\"id\":\"XQTScKtokJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Documents\",\"col\":4}},{\"id\":\"OIx7Apgo_M\",\"type\":\"card\",\"data\":{\"card_name\":\"Configuraci\u00f3n\",\"col\":4}}]", 4 | "creation": "2024-12-06 23:17:35.907677", 5 | "custom_blocks": [], 6 | "docstatus": 0, 7 | "doctype": "Workspace", 8 | "for_user": "", 9 | "hide_custom": 0, 10 | "icon": "pibidav", 11 | "idx": 0, 12 | "indicator_color": "", 13 | "is_hidden": 0, 14 | "label": "pibiDAV", 15 | "links": [ 16 | { 17 | "hidden": 0, 18 | "is_query_report": 0, 19 | "label": "Documents", 20 | "link_count": 4, 21 | "link_type": "DocType", 22 | "onboard": 0, 23 | "type": "Card Break" 24 | }, 25 | { 26 | "hidden": 0, 27 | "is_query_report": 0, 28 | "label": "pibiDAV Addon", 29 | "link_count": 0, 30 | "link_to": "PibiDAV Addon", 31 | "link_type": "DocType", 32 | "onboard": 0, 33 | "type": "Link" 34 | }, 35 | { 36 | "hidden": 0, 37 | "is_query_report": 0, 38 | "label": "Tag", 39 | "link_count": 0, 40 | "link_to": "Tag", 41 | "link_type": "DocType", 42 | "onboard": 0, 43 | "type": "Link" 44 | }, 45 | { 46 | "hidden": 0, 47 | "is_query_report": 0, 48 | "label": "Contact", 49 | "link_count": 0, 50 | "link_to": "Contact", 51 | "link_type": "DocType", 52 | "onboard": 0, 53 | "type": "Link" 54 | }, 55 | { 56 | "hidden": 0, 57 | "is_query_report": 0, 58 | "label": "Event", 59 | "link_count": 0, 60 | "link_to": "Event", 61 | "link_type": "DocType", 62 | "onboard": 0, 63 | "type": "Link" 64 | }, 65 | { 66 | "hidden": 0, 67 | "is_query_report": 0, 68 | "label": "Configuraci\u00f3n", 69 | "link_count": 3, 70 | "link_type": "DocType", 71 | "onboard": 0, 72 | "type": "Card Break" 73 | }, 74 | { 75 | "hidden": 0, 76 | "is_query_report": 0, 77 | "label": "File Category", 78 | "link_count": 0, 79 | "link_to": "File Category", 80 | "link_type": "DocType", 81 | "onboard": 0, 82 | "type": "Link" 83 | }, 84 | { 85 | "hidden": 0, 86 | "is_query_report": 0, 87 | "label": "NextCloud Settings", 88 | "link_count": 0, 89 | "link_to": "NextCloud Settings", 90 | "link_type": "DocType", 91 | "onboard": 0, 92 | "type": "Link" 93 | }, 94 | { 95 | "hidden": 0, 96 | "is_query_report": 0, 97 | "label": "Folder Set", 98 | "link_count": 0, 99 | "link_to": "Folder Set", 100 | "link_type": "DocType", 101 | "onboard": 0, 102 | "type": "Link" 103 | } 104 | ], 105 | "modified": "2024-12-06 23:18:00.867514", 106 | "modified_by": "Administrator", 107 | "module": "Pibidav", 108 | "name": "pibiDAV", 109 | "number_cards": [], 110 | "owner": "Administrator", 111 | "parent_page": "pibiTools", 112 | "public": 1, 113 | "quick_lists": [], 114 | "roles": [ 115 | { 116 | "role": "Docs Controller" 117 | }, 118 | { 119 | "role": "Docs User" 120 | }, 121 | { 122 | "role": "NextCloud User" 123 | } 124 | ], 125 | "sequence_id": 11.0, 126 | "shortcuts": [], 127 | "title": "pibiDAV" 128 | } -------------------------------------------------------------------------------- /pibidav/pibidav/workspace/pibitools/pibitools.json: -------------------------------------------------------------------------------- 1 | { 2 | "charts": [], 3 | "content": "[{\"id\":\"w6ozBdED5x\",\"type\":\"header\",\"data\":{\"text\":\"Inicio > pibiTools
\",\"col\":12}},{\"id\":\"Xyxm-ti2im\",\"type\":\"custom_block\",\"data\":{\"custom_block_name\":\"AI Home\",\"col\":12}}]", 4 | "creation": "2024-12-06 23:53:55.428319", 5 | "custom_blocks": [], 6 | "docstatus": 0, 7 | "doctype": "Workspace", 8 | "for_user": "", 9 | "hide_custom": 0, 10 | "icon": "pibico", 11 | "idx": 0, 12 | "indicator_color": "", 13 | "is_hidden": 0, 14 | "label": "pibiTools", 15 | "links": [], 16 | "modified": "2024-12-07 10:10:19.730958", 17 | "modified_by": "Administrator", 18 | "module": "Pibidav", 19 | "name": "pibiTools", 20 | "number_cards": [], 21 | "owner": "Administrator", 22 | "parent_page": "", 23 | "public": 1, 24 | "quick_lists": [], 25 | "roles": [], 26 | "sequence_id": 3.0, 27 | "shortcuts": [], 28 | "title": "pibiTools" 29 | } -------------------------------------------------------------------------------- /pibidav/public/dist/js/pibidav.bundle.VLVM6LDX.js: -------------------------------------------------------------------------------- 1 | (()=>{frappe.require?frappe.require("nc_browser.bundle.js"):frappe.ready(function(){frappe.require("nc_browser.bundle.js")});})(); 2 | //# sourceMappingURL=pibidav.bundle.VLVM6LDX.js.map 3 | -------------------------------------------------------------------------------- /pibidav/public/dist/js/pibidav.bundle.VLVM6LDX.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": ["../../../../../apps/pibidav/pibidav/public/js/dist/nc_upload.js"], 4 | "sourcesContent": ["// Copyright (c) 2024, pibiCo and Contributors\n// MIT License. See license.txt\n\nif (frappe.require) {\n\tfrappe.require(\"nc_browser.bundle.js\");\n} else {\n\tfrappe.ready(function () {\n\t\tfrappe.require(\"nc_browser.bundle.js\");\n\t});\n}"], 5 | "mappings": "MAGI,OAAO,QACV,OAAO,QAAQ,sBAAsB,EAErC,OAAO,MAAM,UAAY,CACxB,OAAO,QAAQ,sBAAsB,CACtC,CAAC", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /pibidav/public/icons/timeless/icons.svg: -------------------------------------------------------------------------------- 1 | 33 | -------------------------------------------------------------------------------- /pibidav/public/image/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pibico/pibiDAV/660caffafd274f1dcf6c42024d5f67bccd5c8509/pibidav/public/image/background.png -------------------------------------------------------------------------------- /pibidav/public/image/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 30 | 32 | 53 | 57 | 64 | 71 | 77 | 83 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /pibidav/public/image/pibiCo_engine_largo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pibico/pibiDAV/660caffafd274f1dcf6c42024d5f67bccd5c8509/pibidav/public/image/pibiCo_engine_largo.png -------------------------------------------------------------------------------- /pibidav/public/js/dist/nc_browser/NcBrowser.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 264 | 265 | -------------------------------------------------------------------------------- /pibidav/public/js/dist/nc_browser/TreeNode.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 60 | 61 | -------------------------------------------------------------------------------- /pibidav/public/js/dist/nc_browser/nc_browser.bundle.js: -------------------------------------------------------------------------------- 1 | import { createApp, watch } from "vue"; 2 | import NcBrowserComponent from './NcBrowser.vue'; 3 | 4 | class Browser { 5 | constructor(options = {}) { 6 | const { wrapper, targetFolder, ...componentProps } = options; 7 | this.targetFolder = targetFolder; 8 | this.initializeWrapper(wrapper); 9 | this.initializeVueComponent({ 10 | ...componentProps, 11 | root_folder: "/", // Set root folder to / for full navigation 12 | initial_folder: targetFolder // Set initial folder to target 13 | }); 14 | } 15 | 16 | initializeWrapper(wrapper) { 17 | if (!wrapper) { 18 | this.make_dialog(); 19 | } else { 20 | this.wrapper = wrapper.get ? wrapper.get(0) : wrapper; 21 | } 22 | } 23 | 24 | initializeVueComponent(props) { 25 | const app = createApp(NcBrowserComponent, { 26 | show_upload_button: !this.dialog, 27 | root_folder: "/", // Allow full navigation from root 28 | initial_folder: this.targetFolder, // Start at target folder 29 | ...props 30 | }); 31 | this.browser = app.mount(this.wrapper); 32 | this.setupWatchers(); 33 | } 34 | 35 | setupWatchers() { 36 | watch( 37 | () => this.browser.close_dialog, 38 | (close_dialog) => { 39 | if (close_dialog) this.dialog?.hide(); 40 | } 41 | ); 42 | } 43 | 44 | select_folder() { 45 | this.dialog?.get_primary_btn().prop('disabled', true); 46 | return this.browser.select_folder(); 47 | } 48 | 49 | make_dialog() { 50 | this.dialog = new frappe.ui.Dialog({ 51 | title: __('Select NextCloud Folder'), 52 | size: 'large', 53 | primary_action_label: __('Select'), 54 | primary_action: () => this.handlePrimaryAction() 55 | }); 56 | this.wrapper = this.dialog.body; 57 | 58 | this.initializeVueComponent({ 59 | show_browser: true, 60 | root_folder: "/", // Full navigation from root 61 | initial_folder: this.targetFolder // Start at target folder 62 | }); 63 | this.dialog.show(); 64 | this.setupDialogCleanup(); 65 | } 66 | 67 | handlePrimaryAction() { 68 | const nc_folder = this.select_folder(); 69 | const [doctype, docname] = this.getDocumentInfo(); 70 | if (nc_folder.is_folder) { 71 | frappe.db.set_value("PibiDAV Addon", `pbc_${docname}`, { 72 | "nc_folder": nc_folder.path, 73 | "nc_enable": 1 74 | }); 75 | } else { 76 | frappe.msgprint(__('You have selected a file and not a folder'), nc_folder.file_name); 77 | } 78 | this.dialog.hide(); 79 | this.postSelectionAction(doctype); 80 | } 81 | 82 | getDocumentInfo() { 83 | const dtdn = this.wrapper.ownerDocument.body.getAttribute('data-route').replace('Form/', ''); 84 | const pos = dtdn.lastIndexOf('/'); 85 | const docname = dtdn.substr(pos + 1); 86 | const doctype = dtdn.replace('/' + docname, ''); 87 | return [doctype, docname]; 88 | } 89 | 90 | postSelectionAction(doctype) { 91 | if (doctype === 'Folder Set') { 92 | window.location.reload(); 93 | } else { 94 | document.querySelector('.add-attachment-btn').click(); 95 | } 96 | } 97 | 98 | setupDialogCleanup() { 99 | this.dialog.$wrapper.on('hidden.bs.modal', function() { 100 | $(this).data('bs.modal', null); 101 | $(this).remove(); 102 | }); 103 | } 104 | } 105 | 106 | frappe.provide("frappe.ui"); 107 | frappe.ui.pibiDocs = Browser; 108 | export default Browser; -------------------------------------------------------------------------------- /pibidav/public/js/dist/nc_pibidav.js: -------------------------------------------------------------------------------- 1 | frappe.ui.form.on(cur_frm.doctype, { 2 | refresh: function (frm) { 3 | if (!frm.doc.__islocal) { 4 | managePibiDAVAddon(frm); 5 | } 6 | }, 7 | after_save: function (frm) { 8 | handleAfterSave(frm); 9 | } 10 | }); 11 | // Function to manage PibiDAV Addon buttons and actions 12 | function managePibiDAVAddon(frm) { 13 | frappe.db.get_value( 14 | "PibiDAV Addon", 15 | { ref_doctype: frm.doc.doctype, ref_docname: frm.doc.name }, 16 | ["nc_enable"] 17 | ).then(r => { 18 | const nc_enable = r.message?.nc_enable || 0; 19 | if (nc_enable !== 1) { 20 | addNextCloudEnableButton(frm); 21 | } else { 22 | addNextCloudButtons(frm); 23 | } 24 | }); 25 | } 26 | // Add Enable NextCloud Button 27 | function addNextCloudEnableButton(frm) { 28 | frm.add_custom_button(frappe.utils.icon('nextcloud', 'md'), function () { 29 | handleEnableNextCloud(frm); 30 | }) 31 | .addClass("btn btn-primary") 32 | .attr('title', __('Enable NextCloud')); 33 | } 34 | // Add Buttons for Upload, Check, and Disable NextCloud 35 | function addNextCloudButtons(frm) { 36 | frm.add_custom_button(__("Upload to NC"), function () { 37 | handleUploadToNextCloud(frm); 38 | }, __("NC")); 39 | 40 | frm.add_custom_button(__("Check Addon"), function () { 41 | handleCheckAddon(frm); 42 | }, __("NC")); 43 | 44 | frm.add_custom_button(frappe.utils.icon('nextcloud', 'md'), function () { 45 | handleDisableNextCloud(frm); 46 | }) 47 | .addClass("btn btn-danger") 48 | .attr('title', __('Disable NextCloud')); 49 | } 50 | // Handle enabling NextCloud 51 | function handleEnableNextCloud(frm) { 52 | frappe.db.get_value( 53 | "PibiDAV Addon", 54 | { ref_doctype: frm.doc.doctype, ref_docname: frm.doc.name }, 55 | ["name", "nc_folder", "nc_enable"] 56 | ).then(r => { 57 | const addon = r.message || {}; 58 | 59 | if (!addon.name) { 60 | // Addon does not exist, create it first 61 | createAddon(frm, (newAddon) => { 62 | processNextCloudEnable(frm, newAddon); 63 | }); 64 | } else { 65 | // Addon exists, proceed to process enabling 66 | processNextCloudEnable(frm, addon); 67 | } 68 | }); 69 | } 70 | // Process enabling NextCloud 71 | function processNextCloudEnable(frm, addon) { 72 | const nc_parent_folder = frm.doc.nc_parent_folder; 73 | 74 | if (nc_parent_folder) { 75 | frappe.db.set_value("PibiDAV Addon", addon.name, { 76 | nc_enable: 1, 77 | nc_folder_internal_link: nc_parent_folder 78 | }).then(() => { 79 | fetchAndSetFolderPath(nc_parent_folder, addon.name, frm); 80 | }); 81 | } else { 82 | frappe.db.set_value("PibiDAV Addon", addon.name, { nc_enable: 1 }) 83 | .then(() => location.reload()); 84 | } 85 | } 86 | // Handle uploading to NextCloud 87 | function handleUploadToNextCloud(frm) { 88 | frappe.db.get_value( 89 | "PibiDAV Addon", 90 | { ref_doctype: frm.doc.doctype, ref_docname: frm.doc.name }, 91 | ["name", "nc_folder", "nc_folder_internal_link"] 92 | ).then(r => { 93 | const addon = r.message || {}; 94 | if (addon.name) { 95 | openNextCloudBrowser(addon); 96 | } else { 97 | createAddon(frm, () => openNextCloudBrowser({})); 98 | } 99 | }); 100 | } 101 | // Handle checking the Addon 102 | function handleCheckAddon(frm) { 103 | frappe.db.get_value( 104 | "PibiDAV Addon", 105 | { ref_doctype: frm.doc.doctype, ref_docname: frm.doc.name }, 106 | ["name"] 107 | ).then(r => { 108 | const addon = r.message || {}; 109 | if (addon.name) { 110 | frappe.set_route("Form", "PibiDAV Addon", addon.name); 111 | } else { 112 | createAddon(frm, pibidav => { 113 | frappe.set_route("Form", "PibiDAV Addon", pibidav.name); 114 | }); 115 | } 116 | }); 117 | } 118 | // Handle disabling NextCloud 119 | function handleDisableNextCloud(frm) { 120 | frappe.db.set_value("PibiDAV Addon", `pbc_${frm.doc.name}`, { nc_enable: 0 }) 121 | .then(() => location.reload()); 122 | } 123 | // Create or Update Addon with Folder 124 | function createOrUpdateAddonWithFolder(frm, addon) { 125 | const docname = frm.doc.name; 126 | const nc_parent_folder = frm.doc.nc_parent_folder; 127 | const addonName = addon.name || `pbc_${docname}`; 128 | 129 | frappe.db.set_value("PibiDAV Addon", addonName, { 130 | nc_enable: 1, 131 | nc_folder_internal_link: nc_parent_folder 132 | }).then(() => { 133 | fetchAndSetFolderPath(nc_parent_folder, addonName); 134 | }); 135 | } 136 | // Create or Update Addon without Folder 137 | function createOrUpdateAddonWithoutFolder(frm, addon) { 138 | const docname = frm.doc.name; 139 | const addonName = addon.name || `pbc_${docname}`; 140 | 141 | frappe.db.set_value("PibiDAV Addon", addonName, { nc_enable: 1 }) 142 | .then(() => location.reload()); 143 | } 144 | // Fetch and Set Folder Path 145 | function fetchAndSetFolderPath(folderLink, addonName) { 146 | frappe.db.get_value("PibiDAV Addon", addonName, "nc_folder").then(result => { 147 | const currentFolder = result.message.nc_folder; 148 | 149 | // Check if nc_folder is already filled 150 | if (currentFolder && currentFolder.trim() !== "") { 151 | console.log(__('Folder path is already set. No changes made.')); 152 | location.reload(); 153 | } else { 154 | // If not filled, proceed to fetch and set the folder path 155 | frappe.call({ 156 | method: 'pibidav.pibidav.custom.get_folder_path_from_link', 157 | args: { fileid: extractFileId(folderLink) }, 158 | callback: function (r) { 159 | if (!r.exc) { 160 | frappe.db.set_value("PibiDAV Addon", addonName, { 161 | nc_folder: r.message 162 | }).then(() => location.reload()); 163 | } else { 164 | frappe.msgprint(__('Failed to fetch folder path.')); 165 | location.reload(); 166 | } 167 | } 168 | }); 169 | } 170 | }); 171 | } 172 | // Open NextCloud Browser 173 | function openNextCloudBrowser(addon) { 174 | const targetFolder = addon.nc_folder || '/'; // Start at root if no folder is configured 175 | 176 | new frappe.ui.pibiDocs({ 177 | targetFolder: targetFolder, 178 | root_folder: targetFolder 179 | }); 180 | } 181 | // Create Addon 182 | function createAddon(frm, callback) { 183 | frappe.db.insert({ 184 | doctype: "PibiDAV Addon", 185 | ref_doctype: frm.doc.doctype, 186 | ref_docname: frm.doc.name, 187 | nc_enable: 1 188 | }).then(callback); 189 | } 190 | // Handle After Save 191 | function handleAfterSave(frm) { 192 | frappe.db.get_list("PibiDAV Addon", { 193 | filters: { ref_doctype: frm.doc.doctype, ref_docname: frm.doc.name }, 194 | fields: ["nc_enable", "nc_folder_internal_link"] 195 | }).then(res => { 196 | const addon = res[0] || {}; 197 | if (!addon.nc_folder_internal_link && addon.nc_enable) { 198 | createFolderDialog(frm); 199 | } 200 | }); 201 | } 202 | // Create Folder Dialog 203 | function createFolderDialog(frm) { 204 | frappe.call({ 205 | method: "pibidav.pibidav.custom.doCreateFolder", 206 | args: { doctype: frm.doc.doctype } 207 | }).then(r => { 208 | if (r.message) { 209 | openFolderCreationDialog(frm, r.message); 210 | } 211 | }); 212 | } 213 | // Open Folder Creation Dialog 214 | function openFolderCreationDialog(frm, doCreate) { 215 | const defaultData = getDefaultFolderData(frm); 216 | if (doCreate) { 217 | const d = new frappe.ui.Dialog({ 218 | title: __('Create NC Folder'), 219 | fields: getFolderDialogFields(defaultData), 220 | primary_action_label: 'Create', 221 | primary_action(values) { 222 | if (!values.abbreviation || !values.strmain || !values.folder_set) { 223 | frappe.throw(__('Complete all data: Abbreviation, Folder Name, and Folder Set')); 224 | } 225 | createNextCloudFolder(frm, values); 226 | d.hide(); 227 | } 228 | }); 229 | d.show(); 230 | } 231 | } 232 | // Utility Functions 233 | function extractFileId(htmlString) { 234 | const regex = /\/f\/(\d+)/; 235 | const match = htmlString.match(regex); 236 | return match ? match[1] : null; 237 | } 238 | // 239 | function getDefaultFolderData(frm) { 240 | if (frm.doc.doctype === 'Customer') { 241 | return { 242 | folder_name: frm.doc.customer_name, 243 | abbreviation: frm.doc.pb_abbreviation, 244 | folder_set: '(CLI) Plantilla Clientes' 245 | }; 246 | } else if (frm.doc.doctype === 'Supplier') { 247 | return { 248 | folder_name: frm.doc.supplier_name, 249 | abbreviation: frm.doc.pb_abbreviation, 250 | folder_set: '(PRO) Plantilla Proveedores' 251 | }; 252 | } 253 | return {}; 254 | } 255 | // 256 | function getFolderDialogFields(defaultData) { 257 | return [ 258 | { label: __('Enter Abbreviation'), fieldname: 'abbreviation', fieldtype: 'Data', default: defaultData.abbreviation }, 259 | { label: __('Enter Folder Name'), fieldname: 'strmain', fieldtype: 'Data', default: defaultData.folder_name }, 260 | { label: __('Select Folder Set'), fieldname: 'folder_set', fieldtype: 'Link', options: 'Folder Set', filters: { parent_folder_set: '' }, default: defaultData.folder_set }, 261 | { label: __('Sharing Option'), fieldname: 'sharing_option', fieldtype: 'Select', options: ['', '4-Upload Only', '17-Read Only', '31-Upload and Edit'] }, 262 | { label: __('Sharing Password'), fieldname: 'secret', fieldtype: 'Data' } 263 | ]; 264 | } 265 | // 266 | function createNextCloudFolder(frm, values) { 267 | frappe.call({ 268 | method: "pibidav.pibidav.custom.create_nc_folder", 269 | args: { 270 | dt: frm.doc.doctype, 271 | dn: frm.doc.name, 272 | abbr: values.abbreviation, 273 | strmain: values.strmain, 274 | folder_set: values.folder_set, 275 | sharing_option: values.sharing_option, 276 | secret: values.secret || "" 277 | } 278 | }).then(r => { 279 | frappe.msgprint(r.message); 280 | }); 281 | } -------------------------------------------------------------------------------- /pibidav/public/js/dist/nc_upload.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, pibiCo and Contributors 2 | // MIT License. See license.txt 3 | 4 | if (frappe.require) { 5 | frappe.require("nc_browser.bundle.js"); 6 | } else { 7 | frappe.ready(function () { 8 | frappe.require("nc_browser.bundle.js"); 9 | }); 10 | } -------------------------------------------------------------------------------- /pibidav/public/js/pibidav.bundle.js: -------------------------------------------------------------------------------- 1 | // public/js/pibidav.bundle.js 2 | 3 | import './dist/nc_upload.js'; -------------------------------------------------------------------------------- /pibidav/templates/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pibico/pibiDAV/660caffafd274f1dcf6c42024d5f67bccd5c8509/pibidav/templates/__init__.py -------------------------------------------------------------------------------- /pibidav/templates/pages/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pibico/pibiDAV/660caffafd274f1dcf6c42024d5f67bccd5c8509/pibidav/templates/pages/__init__.py -------------------------------------------------------------------------------- /pibidav/translations/es.csv: -------------------------------------------------------------------------------- 1 | 17-Read Only,17-Solo Lectura 2 | 31-Upload and Edit,31-Subida y Edición 3 | 4-Upload Only,4-Subida Unicamente 4 | Abbreviation,Abreviatura 5 | About,Acerca de 6 | About Us Settings,Ajustes Página Acerca de 7 | Accounting,Financiero 8 | "Accounts, Invoices, Taxation, and more.","Cuentas, Facturas, Tasas y más." 9 | Action If Same Rate is Not Maintained,Acción si no se mantiene la misma Tasa 10 | Active,Activo 11 | Activity Type,Identificación Actividad 12 | Add / Remove Columns,Añade / Elimina Columnas 13 | Add a Filter,Añade Filtro 14 | Add Blog Category,Añadir Categoria de Blog 15 | Add Tags,Añade Etiquetas 16 | AI Extract,Extraído IA 17 | Alert Channels,Canales de Alerta 18 | Alert Date,Fecha de Alerta 19 | Alert Gap,Intervalo sin Alerta 20 | Alert Log,Registro de Alertas 21 | Alert Threshold,Umbrales de Alerta 22 | Alerts Active,Alertas Activas 23 | Alerts Received,Alertas Recibidas 24 | Answered,Respondido a Cliente 25 | Apply Filters,Aplicar Filtros 26 | Assets,Bienes/Activos 27 | "Assets, Depreciations, Repairs, and more.","Activos, Depreciaciones, Reparaciones y más." 28 | Assigned,Asignado 29 | Assistant Section,Asistente 30 | Attachment Files,Ficheros Adjuntos 31 | Attachment Item,Ficheros Controlados 32 | Attended,Asistió 33 | Backup Now,Respaldo Ahora 34 | Backup public and private files along with the database and site config,"Respaldo con base de datos, archivos públicos, privados y site_config.json" 35 | Bank Reconciliation Tool,Herramienta de Reconciliación Bancaria 36 | Bill for Rejected Quantity in Purchase Invoice,Factura por cantidad rechazada en la Factura de Compra 37 | Birthdays,Cumpleaños 38 | Blanket Order,Pedido Marco 39 | Blogger,Bloguero 40 | "Blogs, Website View Tracking, and more.","Blogs, Seguimiento de Vistas Web y más." 41 | BOM,LdM 42 | Box,Caja 43 | Build,Desarrollador 44 | by Email,Por Email 45 | by SMS,por SMS 46 | CalDav Calendar,Calendario CalDav 47 | CalDav ID Calendar,Calendario CalDav 48 | CalDav ID URL,ID URL CalDav 49 | Calendar,Calendario 50 | Can Submit,Puede Validar 51 | Cash Flow Statement,Estado de Tesorería 52 | Chairperson,Presidente 53 | Change Abbreviation,Cambiar Abreviatura 54 | Channels,Canales 55 | Chart of Accounts,Plan Contable 56 | Check Addon,Extensión NC 57 | Check Credentials,Comprueba Credenciales 58 | Check Stock Projected Qty,Comprobar la Cantidad de Estocaje Proyectado 59 | Child Data,Datos de Tabla 60 | Child Selector,Selector de Tablas 61 | Column Width,Ancho de Columna 62 | Commented,Comentado por Cliente 63 | Comments Closed,Comentarios Cerrados 64 | Committed Date,Fecha Contrato Proveedor 65 | Communication Date,Fecha Comunicación 66 | Company Fax,Fax Empresa 67 | Company Phone,Teléfono Empresa 68 | Company Website,Web Empresa 69 | "Complete all data Abbreviation, Folder Name and Folder Set","Completa la abreviatura, el nombre de carpeta y la plantilla" 70 | Complete by,Completar el 71 | Configure Account Settings,Configura los Ajustes de Finanzas 72 | Configure Buying Settings.,Configurar los Ajustes de Compras. 73 | Configure Columns,Configurar Columnas 74 | Configure Selling Settings.,Configurar los Ajustes de Ventas. 75 | Configure the action to stop the transaction or just warn if the same rate is not maintained.,Configurar la transacción de paro o sólo advertir de que no se mantiene la misma tasa 76 | Confirm action,Confirma la acción 77 | Connections,Conexiones 78 | Consequent Event,Evento Consecuente 79 | Content Phase,Fase de Creación de Contenido 80 | Contract Number,Numero Contrato 81 | Copy to Clipboard,Copiar al Portapapeles 82 | Create,Crear 83 | Create a Customer,Crear un Cliente 84 | Create a Fixed Asset Item,Crear un Artículo de Activo Fijo 85 | Create a Material Request,Crear una Solicitud de Material 86 | Create a Material Transfer Entry,Crear una Entrada de Transferencia de Material 87 | Create a Product,Crear un Producto 88 | Create a Quotation,Crear una Oferta 89 | Create a Supplier,Crear un Proveedor 90 | Create an Asset,Crear un Activo 91 | Create an Asset Category,Crear una Categoría de Activos 92 | Create and Send Quotation,Crear y Enviar Oferta 93 | Create Blogger,Crear Bloguero 94 | Create Department,Crear Departamento 95 | Create Designation,Crear Puesto 96 | Create Entry,Crear Entrada 97 | Create Holiday List,Crear Listado de Vacaciones 98 | Create in NC,Crear en NC 99 | Create Income Tax Slab,Crear Tabla IRPF 100 | Create Lead,Crear Iniciativa 101 | Create Leave Allocation,Crear Solicitud de Ausencia 102 | Create Leave Application,Crear Peticion de Ausencia 103 | Create Leave Type,Crear Tipo de Ausencia 104 | Create NC Folder,Crear Carpeta NC 105 | Create NC Group,Crear Grupo NC 106 | Create Opportunity,Crear Oportunidad 107 | Create Payroll Period,Crear Período de Nómina 108 | Create Salary Component,Crear Componente Salarial 109 | Create Salary Structure,Crear Estructura Salarial 110 | Create Your First Purchase Invoice ,Crear la primera Factura de Venta 111 | Create your first Purchase Order,Crear tu primera Orden de Compra 112 | Create Your First Sales Invoice ,Crear la primera Factura de Venta 113 | Create your first Sales Order,Crear tu primer Pedido de Venta 114 | Customer Comments,Comentarios Cliente 115 | Customer Date,Fecha Contractual Cliente 116 | Customer name,Denominación Cliente 117 | Customer Number,Numero Cliente 118 | Customer Penalty,Penalizado Cliente 119 | Customer Submission,Fecha Entrega Cliente 120 | Customer Updated,Fecha Actualizada Cliente 121 | Customer Weight,Peso Cliente 122 | Dashboard,Panel Control 123 | Data Import,Importación de Datos 124 | Default In-Transit Warehouse,Almacén en Tránsito por Defecto 125 | Deleted Event in CalDav,Borrado Evento en CalDav 126 | Deleted Event in CalDav Calendar,Borrado el Evento en Calendario CalDav 127 | Deliver To,Transmitir A 128 | Deliverable,Entregable 129 | Deliverable Type,Tipo Entregable 130 | Deliverables,Entregables 131 | Deliverables & Settings,Entregables 132 | Delivery Item,Documentos Entrega 133 | Delivery Note,Albaran 134 | Delivery Purpose,Propósito de Envío 135 | Digits to substitute with abbreviation,Digitos Plantilla a sustituir con Abreviatura 136 | Disable NC,Desactiva NC 137 | Disable NextCloud,Desactiva NextCloud 138 | Discipline,Especialidad 139 | Dispatch Address Name,Dirección de Entrega 140 | Distribution,Distribución 141 | Do you want to save empty doc to prompt?,Quieres gravar primero para ejecutar prompts? 142 | "DocField Names selected for tagging, comma separated without spaces","Nombre de campo elegido para etiquetado, separado por comas y sin espacios" 143 | DocFields to use from selected DocType separated by commas without spaces,Cadena de DocFields del DocType elegido a usar separados por comas y sin espacios 144 | Docs Controller,Control Documentacion 145 | Docs User,Usuario Documentacion 146 | DocType Selection,Selección de DocTypes 147 | DocType Selector,Selector DocTypes 148 | Document Number,Numero Documento 149 | Document Responsible,Responsable del Documento 150 | Document Submission,Transmisión de Documento 151 | Documentation,Documentación 152 | Documents,Documentos 153 | Drag and drop files here or upload from,Arrastra y suelta los archivos aquí o súbelos desde 154 | Due to MicroTemplating never use ' simple quotes in the html code.,Debido al uso de MicroTemplates nunca use comillas simples en el código html 155 | Edit Filters,Editar Filtros 156 | Edition,Edición 157 | Email alert,Alerta por Email 158 | Email Recipients,Receptores Email 159 | Employee Grievance,Queja de Empleado 160 | Employee Onboarding,Oferta de Empleo 161 | Employee Records to be created by,Los registros de Empleados se crean por 162 | "Employee, Leaves, and more.","Empleado, Ausencias y más" 163 | Employees Working on a Holiday,Empleados trabajando en festivo 164 | Enable NC,Activa NC 165 | Enable Website Tracking,Activar Seguimiento Web 166 | Enable NextCloud,Activa NextCloud 167 | Enter Abbreviation,Introduce la Abreviatura 168 | Enter Folder Name,Introduce el Nombre de Carpeta 169 | Error Creating NC Group,Error creando Grupo en NC 170 | Event created successfully.,Evento creado satisfactoriamente. 171 | Event removed successfully.,Evento eliminado correctamente. 172 | Event Stamp,Sello Evento 173 | Event UID,UID Evento 174 | Event updated successfully.,Evento actualizado correctamente. 175 | "Exact DocType Name wihout quotes, whithout spaces and separated by comma (i.e. Sales Invoice,Purchase Order)",Nombre de DocType Exacto sin espacios y separado por comas 176 | Feed Data,Datos a Alimentar 177 | Feeding Section,Sección Asistencia 178 | Fields to Tag,Campos para Etiquetado 179 | File Category,Categoría Archivado 180 | File List,Lista Archivos 181 | File Structure,Estructuras Carpetas 182 | Filename,Nombre Archivo 183 | filter,filtro 184 | Finally Approved,Aprobado Cliente 185 | First Select your NC Destination Folder,Primero Selecciona tu Carpeta Destino NC 186 | Fixed Asset Defaults,Configuración de Activos 187 | Folder Path,Ruta de Carpeta 188 | Folder Set,Plantillas Carpetas 189 | Follow Up Process,Seguimiento 190 | Free,Libre 191 | From Opportunity,Desde Oportunidad 192 | Generate Vcard Book,Generar Libro de Contactos 193 | Go to Page,Ir a la Página 194 | GPT Response,Respuesta GPT 195 | Grievance Type,Tipo de Queja 196 | Hero with Right Image,Heroe con Imagen a la Derecha 197 | Hour,Hora 198 | HR Settings,Configuración de RRHH 199 | HTML Code,Código HTML 200 | ID Number,Número ID 201 | "If checked, Rejected Quantity will be included while making Purchase Invoice from Purchase Receipt.","Si se marca, la cantidad rechazada será incluida al hacerse la factura de Compra desde el Albarán de Compra." 202 | Import .eml,Importar .eml 203 | Import .msg,Importar .msg 204 | Import vCard,Importar vCard 205 | Importing Contacts,Importando Contactos 206 | Inclusions,Inclusiones 207 | Integrate vCard Book,Integrar libro vCard 208 | Internal Comments,Comentarios Internos 209 | Introduction to Assets,Introducción a los Activos 210 | Introduction to Buying,Introducción a Compras 211 | Introduction to CRM,Introducción al CRM 212 | Introduction to Selling,Introducción a Ventas 213 | Introduction to Website,Introducción al Sitio Web 214 | "Inventory, Warehouses, Analysis, and more.","Inventario, Almacenamientos, Análisis y Más" 215 | Invitation Accepted,Invitación Aceptada 216 | Invitations,Invitaciones 217 | is Group,es Carpeta 218 | Is HTML,es HTML 219 | Is SuperStructure,Es Superestructura 220 | Is Translation,Es Traducción? 221 | Issuer Native,Edición Nativa 222 | Item,Producto 223 | Item Name,Nombre del Producto 224 | Language,Idioma 225 | Last Seen,Ultima Actividad 226 | "Lead, Opportunity, Customer, and more.","Iniciativa, Oportunidad, Cliente y más." 227 | Leaderboard,Cuadro de Honor 228 | Learn about Web Pages,Aprender sobre Páginas Web 229 | Leave Application,Petición de Ausencia 230 | Let's Set Up the Assets Module.,Configurar el Módulo de Activos. 231 | Let's Set Up the Buying Module.,Configuremos el Módulo de Compras 232 | Let's Set Up the Human Resource Module.,Configuremos el módulo de RRHH 233 | Let's Set Up the Payroll Module.,Configurar el Módulo de Nómina 234 | Let's Set Up the Selling Module.,Configuremos el Módulo de Ventas. 235 | Let's Set Up the Stock Module.,Configuremos el Módulo de Productos 236 | Let's Set Up Your Accounts and Taxes.,Configuremos Cuentas e Impuestos 237 | Let's Set Up Your CRM.,Configurar el CRM 238 | Let's Set Up Your Website.,Configuremos su Sitio Web 239 | Let’s create a stock opening entry,Creemos una entrada de apertura de stock 240 | Let’s create your first warehouse ,Creemos tu primer almacen 241 | Lets create a Tax Template for Sales ,Crear una Plantilla de Impuestos en Ventas 242 | Library,Biblioteca 243 | LifeCycle Status,Ciclo de Vida 244 | Like,Contiene 245 | List,Lista 246 | List of DocFields separated by commas without spaces to produce automatic file tagging in FP and NC,Lista de DocField separados por comas y sin espacios para asignar etiquetas automáticas en FP y NC a los archivos 247 | List View,Vista Lista 248 | Lists,Listados 249 | Location,Localización 250 | Lower Value,Valor Inferior 251 | Mail Signature,Firma de Correo 252 | Make a Sales Tax Template,Crear una plantilla de Impuestos en Ventas 253 | Manage eMails,Gestión eMails 254 | Manage Stock Movements,Gestionar movimientos de Artículos 255 | Masters,Maestros 256 | Minute of Meeting,Acta de Reunión 257 | Minutes Section,Registros/Actas 258 | Modules,Módulos 259 | Month,Mes 260 | MQTT Settings,Ajustes MQTT 261 | My Device,Mi Equipo 262 | My Profile,Mi Perfil 263 | My Settings,Mis Ajustes 264 | Name,ID 265 | name,ID 266 | Native,Original Nativo 267 | Native Files,Archivos Originales 268 | Native multipart,Multiparte nativo 269 | Native pdf,pdf Nativo 270 | NC Commands,Ordenes NC 271 | NC Doctypes Excluded,DocTypes Excluidos de NC 272 | NC Doctypes Included,DocTypes incluidos para NC 273 | NC Enable,Activa NC 274 | NC File List,Lista Archivos NC 275 | NC File Upload,Subir Archivos a NC 276 | NC Folder,Carpeta NC 277 | NC Folder Creation,Creación de Carpetas en NC 278 | NC Folder Internal Link,Enlace Interno Carpeta NC 279 | NC Folder Share Link,Enlace Compartido Carpeta NC 280 | NC Group Already Exists,Grupo NC ya Existe 281 | NC Group Created,Grupo NC Creado 282 | NC Path,Ruta NC 283 | NC Private Link,Enlace privado NC 284 | NC Share Link,Enlace Compartido NC 285 | New Chart,Nuevo Gráfico 286 | New Shortcut,Nuevo Atajo 287 | NextCloud Backup Credentials,Credenciales NextCloud Backup 288 | NextCloud Backup Enable,Activa NextCloud Backup 289 | NextCloud Credentials,Credenciales NextCloud 290 | NextCloud Credentials are correct,Credenciales NC correctas 291 | NextCloud Settings,Ajustes NextCloud 292 | No contacts selected.,No hay contactos seleccionados. 293 | No message associated,No hay asociado ningún mensaje 294 | Non Participant,No Participante 295 | OCR Extract,Extraído OCR 296 | OCR Extraction in progress,Extracción OCR en ejecución 297 | Off From Time,Fuera Desde 298 | Off To Time,Fuera Hasta 299 | Only one recipient can be provided,Solo se puede proporcionar un destinatario 300 | Optional,Opcional 301 | Overview,Información General 302 | Page Title,Título de Página 303 | Parent File Structure,Nodo Padre 304 | Parent Folder,Carpeta Padre 305 | Parent Path,Ruta Padre 306 | Parties,Participantes 307 | Pending Close,Comentarios pendientes cierre 308 | Phase,Fase 309 | Please provide a proper prompt,Por favor proporciona un prompt adecuado 310 | PO Name,Denominación Orden Compra 311 | prepare eMail,Preparar eMail 312 | Print Language,Idioma de Impresión 313 | Production Phase,Fase de Producción 314 | Production Unit,Unidad Producida 315 | "Products, Purchases, Analysis, and more.","Productos, Compras, Análisis y más" 316 | Profile,Perfil 317 | Published,Publicado 318 | Purchase an Asset Item,Comprar un Activo 319 | Purchase Receipt,Albarán de Compra 320 | QR Key,Llavero RFID/QR 321 | QR Keys,Llaveros RFID 322 | QRKey,Llave RFID/QR 323 | Qualification Stamp,Sello Calificación 324 | Queued for Backup. It may take a long time depending on your backup files size. Rest Easy!!!,Copia de Respaldo en cola. Puede llevar mucho tiempo dependiendo del tamaño de los archivos 325 | Quick Access,Acceso Rápido 326 | Quotation,Oferta 327 | Rate per Minute,Tasa por minuto 328 | Raw File,Archivo Fuente 329 | Rebuild Tree,Reconstruir Árbol 330 | Recipient,Destinatario 331 | Recreate,Recrea 332 | Recreate Folders in NC,Recrea las carpetas en NC 333 | Refresh Files List,Refrescar Indice NC 334 | Reminders,Recordatorios 335 | Rendered HTML,HTML 336 | Report,Informe 337 | Report an Issue,Informar de una Incidencia 338 | Report View,Vista Informe 339 | Reports & Masters,Informes y Maestros 340 | Request for Quotation,Petición de Oferta 341 | Required,Requerido 342 | Reset Customizations,Eliminar Personalizaciones 343 | Reset to default,Resetear por Defecto 344 | Restrict Backdated Leave Application ,Restringir Solicitudes de Vacaciones Retroactivas 345 | Retail,Al por menor 346 | Retirement Age,Edad de Jubilación 347 | Review Chart of Accounts,Revisar Plan Contable 348 | Review Process,Proceso de Revision 349 | Review Stock Settings,Revisar los Ajustes de Productos 350 | RFI Answer,Respuesta Solicitud Información 351 | RFI Answered,Solicitud Información Respondida 352 | RFI Closed,Solicitud de Información Cerrada 353 | RFI Pending,Solicitud Informacion Pendiente 354 | RFI Request,Solicitud Informacion 355 | RFID Tag,Control Llaves Tag 356 | Role Allowed to Override Stop Action,Rol permitido para sobreescribir Acción de Paro 357 | Root Dir Name,Nombre Directorio Raiz 358 | "Salary, Compensation, and more.","Salrios, Compensaciones y más" 359 | Sales Order,Pedido de Venta 360 | Save Customizations,Guardar Personalizaciones 361 | Secret,Clave 362 | Seed,Germen 363 | Select NC Folder,Elige Carpeta NC 364 | Select NextCloud Destination Folder,Elige la carpeta de destino en NextCloud 365 | Select NextCloud Folder,Elige la carpeta de destino en NextCloud 366 | Send Email,Enviar Correo 367 | Select Folder Set,Elige la Plantilla de Carpeta 368 | Send Invitation,Enviar Invitación 369 | Send Leave Notification,Enviar Notificación de Ausente 370 | Sensor Log,Registro de Sensores 371 | Sensor Readings,Lecturas de Sensor 372 | Sent Or Received,Enviado o Recibido 373 | Serial,N.Serie 374 | Set all private,Establecer todos privados 375 | Set all public,Establecer todos públicos 376 | Set the frequency for holiday reminders,Establecer la frecuencia de los recordatorios de Vacaciones 377 | Set up your Warehouse,Configurar tu Almacenamiento 378 | Settings Section,Sección de Ajustes 379 | Setup a Warehouse,Configurar un Almacenamiento 380 | Share Link,Enlace Compartido 381 | Share URL,Comparte URL 382 | Sharing Option,Opción Compartir 383 | Sharing Password,Clave Compartición 384 | Sharing password must be greater than 10 chars long and not usual,La clave de compartición debe ser mayor de 10 caracteres y no comun 385 | Shipping Address Name,Dirección de Despacho 386 | Shortener,Recorte 387 | Show Form Tour,Mostrar un Tour en Formulario 388 | Show Preview,Previsualización 389 | Show Saved,Mostrar Guardados 390 | Signature Item,Firmas de Correo 391 | Signature Picture,Imagen Firma 392 | SMS alert,Alerta por SMS 393 | SMS Recipients,Receptores SMS 394 | Source Lang,Idioma Origen 395 | Spain,España 396 | Standard with Numbers,Estándar con Numeración 397 | Standard Working Hours,Horas de Trabajo Normales 398 | Start and End Dates,Control Actividad 399 | Stock,Productos 400 | Submitted,Transmitido 401 | Summarization,Sumarización 402 | Superseeded,Superado 403 | Supplier Attachments,Archivos de Proveedor 404 | Supplier Delivery,Fecha Entrega Proveedor 405 | Supplier Number,Numero Proveedor 406 | Supplier Penalty,Penalizado Proveedor 407 | Supplier Weight,Peso Proveedor 408 | Sure you want to ask chatGPT?,Seguro de preguntar a chatGPT 409 | Sync with CalDav,Sincronizar con CalDav 410 | Synchronization successful.,Sincronización correcta. 411 | System User,Usuario del Sistema 412 | Take a walk through Stock Settings,Dar un paseo por los Ajustes de Productos 413 | Target Lang,Idioma Destino 414 | Team Members Subtitle,Subtítulos Miembros del Equipo 415 | This is based on Alerts received from this Sensor,Mapa basado en Alertas recibidas desde este Sensor 416 | Timesheet,Parte de Trabajo 417 | to Customer,Envio a Cliente 418 | To Customer,A Cliente 419 | to External,Envio a Terceros 420 | To ReIssue,A reeditar 421 | To Review,A Revisar 422 | Toggle Full Width,Alterna Vista Completa 423 | Toggle Theme,Ajustar Aspecto 424 | Tools,Herramientas 425 | Transaction Feed,Alimentar Transacción 426 | Transcription Language,Idioma Destino 427 | Tree,Árbol 428 | Unit of Measure (UOM),Unidad de Medida (UdM) 429 | UOM,UdM 430 | Update Settings,Actualizar Ajustes 431 | Update Stock Opening Balance,Actualizar el Balance de Apertura de Estocaje 432 | Updated Date,Fecha actualizada Proveedor 433 | Updated/Created Event in Calendar,Actualizado/Creado un Evento de Calendario 434 | Upload to NC,Subir a NC 435 | Upload to NextCloud,Subir a NextCloud 436 | Uploaded To NC,Subido a NC 437 | Uploaded To NextCloud,Subido a NextCloud 438 | Upper Value,Valor Superior 439 | User Forum,Foro de Usuarios 440 | User Prompt,Prompt de Usuario 441 | Validated,Validado 442 | vCard Create,Crear vCard 443 | vCard Download,Descargar vCard 444 | vCard Integration,Integración vCard 445 | vCard QR Code,Código QR vCard 446 | vCard Text,Texto vCard 447 | Vendor,Proveedor 448 | Watch Tutorial,Ver el Tutorial 449 | Watch Video,Mirar el Video 450 | Web Page,Página Web 451 | Work Anniversaries ,Aniversarios de Trabajo 452 | Work Place,Area de Control 453 | WorkCenter,Area de Control 454 | WorkCenter Occupancy,Ocupacion Area 455 | WorkCenter Schedule,Horario Area 456 | Workship,Area de Control 457 | Workship Occupancy,Ocupación de Área 458 | Workship Schedule,Horario Area 459 | You can only reply to one message at a time,Sólo puedes responder a un mensaje de cada vez 460 | You have selected a file and not a folder,Se ha seleccionado un archivo y no una carpeta 461 | You must select one message,Debes elegir un mensaje 462 | NC Folder Link,Enlace Carpeta NC 463 | Fetch NC Folder Link,Obtener Enlace Carpeta NC 464 | -------------------------------------------------------------------------------- /pibidav/www/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pibico/pibiDAV/660caffafd274f1dcf6c42024d5f67bccd5c8509/pibidav/www/__init__.py -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # frappe -- https://github.com/frappe/frappe is installed via 'bench init' 2 | frappe 3 | payments 4 | erpnext 5 | hrms -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | with open("requirements.txt") as f: 4 | install_requires = f.read().strip().split("\n") 5 | 6 | # get version from __version__ variable in pibidav/__init__.py 7 | from pibidav import __version__ as version 8 | 9 | setup( 10 | name="pibidav", 11 | version=version, 12 | description="WebDAV, CalDAV and CardDAV Integration between Frappe and NextCloud", 13 | author="pibiCo", 14 | author_email="pibico.sl@gmail.com", 15 | packages=find_packages(), 16 | zip_safe=False, 17 | include_package_data=True, 18 | install_requires=install_requires 19 | ) 20 | --------------------------------------------------------------------------------