From 0463a9ea8a380e35d42fe5352f48b711fabf04eb Mon Sep 17 00:00:00 2001 From: Safwan Samsudeen Date: Wed, 4 Mar 2026 12:48:15 +0530 Subject: [PATCH 01/42] feat: initial patch --- drive/hooks.py | 6 +-- drive/patches/integrate_with_framework.py | 45 +++++++++++++++++++++++ drive/utils/overrides.py | 6 +++ 3 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 drive/patches/integrate_with_framework.py diff --git a/drive/hooks.py b/drive/hooks.py index a8735f62f..53122d7af 100644 --- a/drive/hooks.py +++ b/drive/hooks.py @@ -116,9 +116,9 @@ # --------------- # Override standard doctype classes -# override_doctype_class = { -# "ToDo": "custom_app.utils.overrides.CustomToDo" -# } +override_doctype_class = { + "File": "drive.utils.overrides.File" +} # Document Events # --------------- diff --git a/drive/patches/integrate_with_framework.py b/drive/patches/integrate_with_framework.py new file mode 100644 index 000000000..a369b0fff --- /dev/null +++ b/drive/patches/integrate_with_framework.py @@ -0,0 +1,45 @@ +""" +Create `File` records of all existing `Drive File`s +""" + +import frappe +from drive.utils import get_file_type + + +def execute(files=[]): + if not files: + files = frappe.get_all("Drive File", pluck=["name"]) + for file in files: + file = frappe.get_doc("Drive File", file) + ff_file = frappe.get_doc( + { + "doctype": "File", + "is_drive_file": 1, + "_name": file.name, + "file_name": file.title, + "team": file.team, + "file_url": file.path, + "folder": file.parent_entity, + "is_folder": file.is_group, + "file_size": file.file_size, + "_modified": file._modified, + "status": file.is_active, + "is_private": 1, + } + ) + + + if file.doc: + ff_file.special_file = "Writer Document" + ff_file.special_file_doc = file.doc + # Write eq code for link, slides + # Calculate file type + ff_file.file_type = get_file_type(file.as_dict()) + + settings = {} + if file.color: + settings["color"] = file.color + if not file.allow_download: + settings["forbid_download"] = 1 + ff_file.settings = settings + ff_file.insert() diff --git a/drive/utils/overrides.py b/drive/utils/overrides.py index 2880955d2..da15b2aac 100644 --- a/drive/utils/overrides.py +++ b/drive/utils/overrides.py @@ -2,6 +2,12 @@ from drive.api.permissions import get_teams +from frappe.core.doctype.file.file import File as FrappeFile + +class File(FrappeFile): + def validate(self): + if not self.is_drive_file: + super().validate() def common_filters(func): def decorator(user): From 92c3ae0920ef37e8c3bfb197ee3502e021a222c5 Mon Sep 17 00:00:00 2001 From: Safwan Samsudeen Date: Wed, 4 Mar 2026 13:43:01 +0530 Subject: [PATCH 02/42] feat: export custom fields --- drive/fixtures/custom_field.json | 524 ++++++++++++++++++++++ drive/patches/integrate_with_framework.py | 93 ++-- drive/utils/overrides.py | 7 + 3 files changed, 589 insertions(+), 35 deletions(-) create mode 100644 drive/fixtures/custom_field.json diff --git a/drive/fixtures/custom_field.json b/drive/fixtures/custom_field.json new file mode 100644 index 000000000..6aa3e3fb1 --- /dev/null +++ b/drive/fixtures/custom_field.json @@ -0,0 +1,524 @@ +[ + { + "alignment": "", + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "button_color": "", + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "File", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "section_break_nfot8", + "fieldtype": "Section Break", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "section_break_8", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Drive Properties", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "module": null, + "name": "File-section_break_nfot8", + "no_copy": 0, + "non_negative": 0, + "options": null, + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + }, + { + "alignment": "", + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "button_color": "", + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": "0", + "depends_on": null, + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "File", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "is_drive_file", + "fieldtype": "Check", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "section_break_nfot8", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Is Drive File", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "module": null, + "name": "File-is_drive_file", + "no_copy": 0, + "non_negative": 0, + "options": null, + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + }, + { + "alignment": "", + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "button_color": "", + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "File", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "team", + "fieldtype": "Link", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "is_drive_file", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Drive Team", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "module": null, + "name": "File-team", + "no_copy": 0, + "non_negative": 0, + "options": "Drive Team", + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + }, + { + "alignment": "", + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "button_color": "", + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "File", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "status", + "fieldtype": "Int", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "team", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Status", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "module": null, + "name": "File-status", + "no_copy": 0, + "non_negative": 0, + "options": null, + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + }, + { + "alignment": "", + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "button_color": "", + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "File", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "last_modified", + "fieldtype": "Datetime", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "status", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Last Modified", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "module": null, + "name": "File-last_modified", + "no_copy": 0, + "non_negative": 0, + "options": null, + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + }, + { + "alignment": "", + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "button_color": "", + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "File", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "settings", + "fieldtype": "JSON", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "last_modified", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Settings", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "module": null, + "name": "File-settings", + "no_copy": 0, + "non_negative": 0, + "options": null, + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + }, + { + "alignment": "", + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "button_color": "", + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "File", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "column_break_tapww", + "fieldtype": "Column Break", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "settings", + "is_system_generated": 0, + "is_virtual": 0, + "label": "", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "module": null, + "name": "File-column_break_tapww", + "no_copy": 0, + "non_negative": 0, + "options": null, + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + }, + { + "alignment": "", + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "button_color": "", + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "File", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "special_file", + "fieldtype": "Link", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "column_break_tapww", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Special File", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "module": null, + "name": "File-special_file", + "no_copy": 0, + "non_negative": 0, + "options": "DocType", + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + }, + { + "alignment": "", + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "button_color": "", + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "File", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "special_file_doc", + "fieldtype": "Dynamic Link", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "special_file", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Special File Doc", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "module": null, + "name": "File-special_file_doc", + "no_copy": 0, + "non_negative": 0, + "options": "special_file", + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + } +] \ No newline at end of file diff --git a/drive/patches/integrate_with_framework.py b/drive/patches/integrate_with_framework.py index a369b0fff..eceaddeb1 100644 --- a/drive/patches/integrate_with_framework.py +++ b/drive/patches/integrate_with_framework.py @@ -8,38 +8,61 @@ def execute(files=[]): if not files: - files = frappe.get_all("Drive File", pluck=["name"]) - for file in files: - file = frappe.get_doc("Drive File", file) - ff_file = frappe.get_doc( - { - "doctype": "File", - "is_drive_file": 1, - "_name": file.name, - "file_name": file.title, - "team": file.team, - "file_url": file.path, - "folder": file.parent_entity, - "is_folder": file.is_group, - "file_size": file.file_size, - "_modified": file._modified, - "status": file.is_active, - "is_private": 1, - } - ) - - - if file.doc: - ff_file.special_file = "Writer Document" - ff_file.special_file_doc = file.doc - # Write eq code for link, slides - # Calculate file type - ff_file.file_type = get_file_type(file.as_dict()) - - settings = {} - if file.color: - settings["color"] = file.color - if not file.allow_download: - settings["forbid_download"] = 1 - ff_file.settings = settings - ff_file.insert() + root_files = frappe.get_all("Drive File", filters={'parent_entity': ''}, pluck="name") + + for file_id in root_files: + folder = frappe.get_doc("Drive File", file_id) + migrate_folder(folder) + +def migrate_folder(folder): + print(f'Migrating folder {folder}') + migrate_file(folder) + + for child in folder.get_children(): + if child.is_group or child.doc: + migrate_folder(child) + else: + migrate_file(child) + +def migrate_file(file): + if frappe.db.exists("File", {"is_drive_file": 1, "name": file.name}): + return + + ff_file = frappe.get_doc( + { + "doctype": "File", + "is_drive_file": 1, + "_name": file.name, + "file_name": file.title, + "team": file.team, + "file_url": file.path, + "folder": file.parent_entity, + "is_folder": file.is_group, + "file_size": file.file_size, + "last_modified": file._modified, + "status": file.is_active, + "is_private": 1, + } + ) + + + if file.doc: + ff_file.special_file = "Writer Document" + ff_file.special_file_doc = file.doc + + # Attachment + if frappe.db.get_value('Drive File', file.parent_entity, 'doc'): + ff_file.attached_to_doctype = 'File' + ff_file.attached_to_name = file.parent_entity + # Write eq code for slides + + # Calculate file type + ff_file.file_type = get_file_type(file.as_dict()) + + settings = {} + if file.color: + settings["color"] = file.color + if not file.allow_download: + settings["forbid_download"] = 1 + ff_file.settings = settings + ff_file.insert() \ No newline at end of file diff --git a/drive/utils/overrides.py b/drive/utils/overrides.py index da15b2aac..7bdb3672f 100644 --- a/drive/utils/overrides.py +++ b/drive/utils/overrides.py @@ -8,6 +8,13 @@ class File(FrappeFile): def validate(self): if not self.is_drive_file: super().validate() + + def autoname(self): + if self.is_drive_file and self._name: + self.name = self._name + else: + super().autoname() + def common_filters(func): def decorator(user): From 6c85e2166b743073abd7b7d3374f745a73bc7f91 Mon Sep 17 00:00:00 2001 From: Safwan Samsudeen Date: Wed, 4 Mar 2026 14:09:45 +0530 Subject: [PATCH 03/42] feat: migrate list view --- drive/api/list.py | 64 ++++++++++------------- drive/api/permissions.py | 23 +------- drive/patches/integrate_with_framework.py | 3 +- drive/utils/__init__.py | 24 ++++++++- frappe-ui | 2 +- frontend/src/components/GenericPage.vue | 2 +- frontend/src/components/ListView.vue | 12 ++--- frontend/src/resources/files.js | 2 +- pnpm-workspace.yaml.disabled | 3 -- 9 files changed, 63 insertions(+), 72 deletions(-) delete mode 100644 pnpm-workspace.yaml.disabled diff --git a/drive/api/list.py b/drive/api/list.py index 63a065be6..58100c2ca 100644 --- a/drive/api/list.py +++ b/drive/api/list.py @@ -4,14 +4,13 @@ from pypika import Criterion, CustomFunction, Order from pypika import functions as fn -from drive.utils import MIME_LIST_MAP, default_team, get_file_type, get_home_folder +from drive.utils import MIME_LIST_MAP, default_team, get_file_type, get_home_folder, FILE_FIELDS from drive.utils.api import get_default_access - -from .permissions import ENTITY_FIELDS, get_user_access +from .permissions import get_user_access, user_has_permission DriveUser = frappe.qb.DocType("User") UserGroupMember = frappe.qb.DocType("User Group Member") -DriveFile = frappe.qb.DocType("Drive File") +DriveFile = frappe.qb.DocType("File") DrivePermission = frappe.qb.DocType("Drive Permission") Team = frappe.qb.DocType("Drive Team") TeamMember = frappe.qb.DocType("Drive Team Member") @@ -30,7 +29,6 @@ def files( order_by: str = "modified 1", is_active: bool = True, limit: int = 20, - cursor: str | None = None, favourites_only: bool = False, recents_only: bool = False, shared: str | None = None, @@ -46,33 +44,31 @@ def files( if team == "all": all_teams = True team = None - if not entity_name and team: entity_name = get_home_folder(team)["name"] user = frappe.session.user if frappe.session.user != "Guest" else "" - if entity_name: - entity = frappe.get_doc("Drive File", entity_name) - # Verify that entity exists and is part of the team - if not entity: - frappe.throw( - f"Not found ({entity_name}) ", - frappe.exceptions.PageDoesNotExistError, - ) + entity = frappe.get_doc("Drive File", entity_name) + + # Verify that entity exists and is part of the team + if not entity: + frappe.throw( + f"Not found ({entity_name}) ", + frappe.exceptions.PageDoesNotExistError, + ) - if not team == entity.team: - team = entity.team + if team and not team == entity.team: + frappe.throw("Given team doesn't match the file's team", ValueError) - # Verify that folder is public or that they have access - user_access = get_user_access(entity, user) + # Verify that folder is public or that they have access + if not user_has_permission(entity, "read"): + frappe.throw( + f"You don't have access.", + frappe.exceptions.PermissionError, + ) - if not user_access["read"]: - frappe.throw( - f"You don't have access.", - frappe.exceptions.PermissionError, - ) + query = frappe.qb.from_(DriveFile).where(DriveFile.status == is_active) - query = frappe.qb.from_(DriveFile).where(DriveFile.is_active == is_active) if shared: if shared == "by" or shared == "with": cond = (DrivePermission.entity == DriveFile.name) & ( @@ -89,19 +85,15 @@ def files( (DrivePermission.entity == DriveFile.name) & (DrivePermission.user == user) ) - query = query.select(*ENTITY_FIELDS, DrivePermission.user.as_("shared_team")).where( + query = query.select(*FILE_FIELDS, DrivePermission.user.as_("shared_team")).where( fn.Coalesce(DrivePermission.read, 1).as_("read") == 1 ) - # Cursor pagination - if cursor: - query = query.where((Binary(DriveFile[field]) > cursor if ascending else field < cursor)).limit(limit) - # Cleaner way? if only_parent and (not recents_only and not favourites_only and not shared): - query = query.where(DriveFile.parent_entity == entity_name) + query = query.where(DriveFile.folder == entity_name) elif not all_teams: - query = query.where((DriveFile.team == team) & (DriveFile.parent_entity != "")) + query = query.where((DriveFile.team == team) & (DriveFile.folder != "")) # Get favourites data (only that, if applicable) if favourites_only: @@ -145,18 +137,18 @@ def files( mime_types.extend(MIME_LIST_MAP.get(kind, [])) criterion = [DriveFile.mime_type == mime_type for mime_type in mime_types] if "Folder" in file_kinds: - criterion.append(DriveFile.is_group == 1) + criterion.append(DriveFile.is_folder == 1) query = query.where(Criterion.any(criterion)) if folders: - query = query.where(DriveFile.is_group == 1) + query = query.where(DriveFile.is_folder == 1) res = query.run(as_dict=True) child_count_query = ( frappe.qb.from_(DriveFile) - .where((DriveFile.team == team) & (DriveFile.is_active == 1)) - .select(DriveFile.parent_entity, fn.Count("*").as_("child_count")) - .groupby(DriveFile.parent_entity) + .where((DriveFile.drive_team == team) & (DriveFile.status == 1)) + .select(DriveFile.folder, fn.Count("*").as_("child_count")) + .groupby(DriveFile.folder) ) share_query = ( frappe.qb.from_(DriveFile) diff --git a/drive/api/permissions.py b/drive/api/permissions.py index f6f0b6208..4cb763774 100644 --- a/drive/api/permissions.py +++ b/drive/api/permissions.py @@ -5,30 +5,11 @@ import markdown from frappe.utils import getdate from markdown.extensions.wikilinks import WikiLinkExtension -from pypika import Field -from drive.utils import generate_upward_path, get_default_team, get_file_type, get_valid_breadcrumbs +from drive.utils import generate_upward_path, get_default_team, get_file_type, get_valid_breadcrumbs, FILE_FIELDS from drive.utils.files import FileManager from drive.utils.users import mark_as_viewed -ENTITY_FIELDS = [ - "name", - "title", - "is_group", - "is_link", - "path", - Field("_modified").as_("modified"), - "creation", - "file_size", - "mime_type", - "color", - "doc", - "owner", - "parent_entity", - "team", - "allow_download", -] - NO_ACCESS = { "read": 0, @@ -155,7 +136,7 @@ def get_entity_with_permissions(entity_name: str): entity = frappe.db.get_value( "Drive File", {"is_active": 1, "name": entity_name}, - ENTITY_FIELDS, + FILE_FIELDS, as_dict=1, ) if not entity: diff --git a/drive/patches/integrate_with_framework.py b/drive/patches/integrate_with_framework.py index eceaddeb1..9ec8f4ed4 100644 --- a/drive/patches/integrate_with_framework.py +++ b/drive/patches/integrate_with_framework.py @@ -34,7 +34,8 @@ def migrate_file(file): "is_drive_file": 1, "_name": file.name, "file_name": file.title, - "team": file.team, + # rename field + "drive_team": file.team, "file_url": file.path, "folder": file.parent_entity, "is_folder": file.is_group, diff --git a/drive/utils/__init__.py b/drive/utils/__init__.py index b05527e0e..302aa3a8e 100644 --- a/drive/utils/__init__.py +++ b/drive/utils/__init__.py @@ -4,6 +4,7 @@ import frappe from bs4 import BeautifulSoup +from pypika import Field DriveFile = frappe.qb.DocType("Drive File") MIME_LIST_MAP = { @@ -244,11 +245,12 @@ def get_valid_breadcrumbs(entity_name, user_access): def get_file_type(r): - if r["is_group"]: + if r["is_folder"]: return "Folder" - elif r["is_link"]: + elif r["file_type"] == 'Link': return "Link" else: + return r['file_type'] try: return next(k for (k, v) in MIME_LIST_MAP.items() if r["mime_type"] in v) except StopIteration: @@ -394,3 +396,21 @@ def get_teams(user=None, details=None, exclude_personal=True): return {t: team for t, team in teams_info.items() if not team.personal} return teams_info return teams + + +FILE_FIELDS = [ + "name", + "file_name", + "folder", + "file_url", + "file_size", + "file_type", + "is_folder", + "special_file", + "special_file_doc", + Field("drive_team").as_('team'), + "creation", + Field("last_modified").as_("modified"), + "owner", + "settings", +] \ No newline at end of file diff --git a/frappe-ui b/frappe-ui index 29c3c3a80..f20f6e7c0 160000 --- a/frappe-ui +++ b/frappe-ui @@ -1 +1 @@ -Subproject commit 29c3c3a808bdf583408ba13e2484206f8a21e0c0 +Subproject commit f20f6e7c0ee27452c33689db3dfa765c7b2b2525 diff --git a/frontend/src/components/GenericPage.vue b/frontend/src/components/GenericPage.vue index 35e63dc32..3429e7b3d 100644 --- a/frontend/src/components/GenericPage.vue +++ b/frontend/src/components/GenericPage.vue @@ -209,7 +209,7 @@ watch( if (!val) return rows.value = sortEntities([...val], sortOrder.value) store.commit("setCurrentFolder", { - entities: rows.value.filter?.((k) => k.title[0] !== "."), + entities: rows.value.filter?.((k) => k.file_name[0] !== "."), }) }, { immediate: true, deep: true } diff --git a/frontend/src/components/ListView.vue b/frontend/src/components/ListView.vue index f0cf3497a..df8602489 100644 --- a/frontend/src/components/ListView.vue +++ b/frontend/src/components/ListView.vue @@ -129,12 +129,12 @@ const formattedRows = computed(() => { const selectedColumns = [ { label: __("Name"), - key: "title", - getLabel: ({ row: { title, is_group, document } }) => - title.lastIndexOf(".") === -1 || is_group || document - ? title - : title.slice(0, title.lastIndexOf(".")), - getTooltip: (e) => (e.is_group || e.document ? "" : e.title), + key: "file_name", + getLabel: ({ row: { file_name, is_folder, document } }) => + file_name.lastIndexOf(".") === -1 || is_folder || document + ? file_name + : file_name.slice(0, file_name.lastIndexOf(".")), + getTooltip: (e) => (e.is_folder || e.document ? "" : e.file_name), prefix: ({ row }) => { return getThumbnailUrl(row) }, diff --git a/frontend/src/resources/files.js b/frontend/src/resources/files.js index 19d1a95d0..79cfd1668 100644 --- a/frontend/src/resources/files.js +++ b/frontend/src/resources/files.js @@ -11,7 +11,7 @@ export const COMMON_OPTIONS = { method: "GET", debounce: 500, transform(data) { - return prettyData(data.filter((k) => !k.title.startsWith("."))) + return prettyData(data.filter((k) => !k.file_name.startsWith("."))) }, } diff --git a/pnpm-workspace.yaml.disabled b/pnpm-workspace.yaml.disabled deleted file mode 100644 index dceb4662c..000000000 --- a/pnpm-workspace.yaml.disabled +++ /dev/null @@ -1,3 +0,0 @@ -packages: - - "frontend" - - "frappe-ui" From 3bdfacc0d65bef19f921171a29c109ba6f6cf87d Mon Sep 17 00:00:00 2001 From: Safwan Samsudeen Date: Wed, 4 Mar 2026 14:21:14 +0530 Subject: [PATCH 04/42] fix: rename python variables --- drive/api/embed.py | 2 +- drive/api/files.py | 56 ++++----- drive/api/integration.py | 2 +- drive/api/list.py | 10 +- drive/api/notifications.py | 6 +- drive/api/permissions.py | 6 +- drive/api/scripts.py | 6 +- drive/api/storage.py | 12 +- .../patches/share_creation.py | 10 +- drive/drive/doctype/drive_file/drive_file.py | 52 ++++---- drive/drive/doctype/drive_team/drive_team.py | 4 +- drive/utils/__init__.py | 36 +++--- drive/utils/files.py | 18 +-- drive/utils/users.py | 2 +- drive/www/drive.py | 8 +- frontend/src/components/MoveDialog.vue | 117 +++++++----------- 16 files changed, 164 insertions(+), 183 deletions(-) diff --git a/drive/api/embed.py b/drive/api/embed.py index 57223a188..4d5e2ae48 100644 --- a/drive/api/embed.py +++ b/drive/api/embed.py @@ -28,7 +28,7 @@ def get_file_content(embed_name: str, parent_entity_name: str): drive_entity = frappe.get_value( "Drive File", parent_entity_name, - ["document", "title", "mime_type", "file_size", "owner", "path", "team"], + ["document", "file_name", "mime_type", "file_size", "owner", "path", "team"], as_dict=1, ) diff --git a/drive/api/files.py b/drive/api/files.py index b8791b28d..631642d82 100644 --- a/drive/api/files.py +++ b/drive/api/files.py @@ -137,7 +137,7 @@ def get_thumbnail(entity_name: str): "Drive File", entity_name, [ - "is_group", + "is_folder", "path", "title", "mime_type", @@ -149,7 +149,7 @@ def get_thumbnail(entity_name: str): ], as_dict=1, ) - if not drive_file or drive_file.is_group or drive_file.is_link: + if not drive_file or drive_file.is_folder or drive_file.is_link: return if user_has_permission(drive_file, "read") is False: return @@ -317,9 +317,9 @@ def create_folder(team: str, title: str, parent: str | None = None): { "doctype": "Drive File", "parent_entity": parent, - "is_group": 1, + "is_folder": 1, "title": title, - "is_active": 1, + "status": 1, } ) @@ -348,7 +348,7 @@ def create_folder(team: str, title: str, parent: str | None = None): parent, "folder", lambda _: path, - is_group=True, + is_folder=True, ) return drive_file @@ -371,8 +371,8 @@ def ensure_path(team, fullpath, parent=None): "Drive File", { "title": folder, - "is_group": 1, - "is_active": 1, + "is_folder": 1, + "status": 1, "team": team, "parent_entity": current_parent, }, @@ -402,9 +402,9 @@ def create_link(team: str, title: str, link: str, parent: str | None = None): { "doctype": "Drive File", "parent_entity": parent, - "is_group": 1, + "is_folder": 1, "title": title, - "is_active": 1, + "status": 1, } ) @@ -423,7 +423,7 @@ def create_link(team: str, title: str, link: str, parent: str | None = None): "path": link, "is_link": 1, "mime_type": "link/unknown", - "_modified": frappe.utils.now_datetime(), + "last_modified": frappe.utils.now_datetime(), "parent_entity": parent, } ) @@ -480,18 +480,18 @@ def get_file_content( "Drive File", {"name": entity_name}, [ - "is_group", + "is_folder", "team", "is_link", "path", "title", "mime_type", - "is_active", + "status", "document", ], as_dict=1, ) - if not drive_file or drive_file.is_group or drive_file.is_link or (not transfer and drive_file.is_active != 1): + if not drive_file or drive_file.is_folder or drive_file.is_link or (not transfer and drive_file.status != 1): frappe.throw("Not found", frappe.NotFound) return get_file_internal(drive_file, trigger_download) @@ -622,10 +622,10 @@ def remove_or_restore(entity_names: list[str] | str): frappe.throw(f"Expected list but got {type(entity_names)}", ValueError) manager = FileManager() - def depth_zero_toggle_is_active(doc): + def depth_zero_toggle_status(doc): if not user_has_permission(doc, "write"): raise frappe.PermissionError("You do not have permission to remove this file") - if doc.is_active: + if doc.status: flag = 0 manager.move_to_trash(doc) else: @@ -635,8 +635,8 @@ def depth_zero_toggle_is_active(doc): manager.restore(doc) flag = 1 - doc.is_active = flag - doc._modified = frappe.utils.now_datetime() + doc.status = flag + doc.last_modified = frappe.utils.now_datetime() # Only update parent folder size if parent exists (not root level) if doc.parent_entity: folder_size = frappe.db.get_value("Drive File", doc.parent_entity, "file_size") or 0 @@ -650,13 +650,13 @@ def depth_zero_toggle_is_active(doc): doc.save() for entity in entity_names: - depth_zero_toggle_is_active(frappe.get_doc("Drive File", entity)) + depth_zero_toggle_status(frappe.get_doc("Drive File", entity)) @frappe.whitelist() def delete_entities(entity_names: list[str] | None = None, clear_all: bool = False): if clear_all: - entity_names = frappe.db.get_list("Drive File", {"is_active": 0, "owner": frappe.session.user}, pluck="name") + entity_names = frappe.db.get_list("Drive File", {"status": 0, "owner": frappe.session.user}, pluck="name") elif isinstance(entity_names, str): entity_names = json.loads(entity_names) elif not isinstance(entity_names, list) or not entity_names: @@ -728,7 +728,7 @@ def auto_delete_from_trash(): days_before = (date.today() - timedelta(days=30)).isoformat() result = frappe.db.get_all( "Drive File", - filters={"is_active": 0, "last_modified": ["<", days_before]}, + filters={"status": 0, "last_modified": ["<", days_before]}, fields=["name"], ) delete_entities(result) @@ -738,7 +738,7 @@ def clear_deleted_files(): days_before = (date.today() + timedelta(days=30)).isoformat() result = frappe.db.get_all( "Drive File", - filters={"is_active": -1, "modified": ["<", days_before]}, + filters={"status": -1, "modified": ["<", days_before]}, fields=["name"], ) for entity in result: @@ -785,7 +785,7 @@ def search(query: str): """ SELECT `tabDrive File`.name, `tabDrive File`.title, - `tabDrive File`.is_group, + `tabDrive File`.is_folder, `tabDrive File`.is_link, `tabDrive File`.mime_type, `tabDrive File`.document, @@ -796,7 +796,7 @@ def search(query: str): FROM `tabDrive File` LEFT JOIN `tabUser` ON `tabDrive File`.`owner` = `tabUser`.`name` WHERE `tabDrive File`.team IN %(teams)s - AND `tabDrive File`.`is_active` = 1 + AND `tabDrive File`.`status` = 1 AND `tabDrive File`.`parent_entity` <> '' AND MATCH(title) AGAINST (%(text)s IN BOOLEAN MODE) GROUP BY `tabDrive File`.`name` @@ -829,13 +829,13 @@ def get_new_title(title: str, parent_name: str, folder: bool = False, entity: st entity_title, entity_ext = os.path.splitext(title) filters = { - "is_active": 1, + "status": 1, "parent_entity": parent_name, "title": ["like", f"{entity_title}%{entity_ext}"], } if folder: - filters["is_group"] = 1 + filters["is_folder"] = 1 sibling_entity_titles = frappe.db.get_list( "Drive File", @@ -855,13 +855,13 @@ def get_new_title(title: str, parent_name: str, folder: bool = False, entity: st def get_entity_type(entity_name: str): entity = frappe.db.get_value( "Drive File", - {"is_active": 1, "name": entity_name}, - ["team", "name", "mime_type", "is_group", "doc"], + {"status": 1, "name": entity_name}, + ["team", "name", "mime_type", "is_folder", "doc"], as_dict=1, ) if entity.doc or entity.mime_type == "text/markdown": entity["type"] = "document" - elif entity.is_group: + elif entity.is_folder: entity["type"] = "folder" else: entity["type"] = "file" diff --git a/drive/api/integration.py b/drive/api/integration.py index 99c6f60fc..ad74002ae 100644 --- a/drive/api/integration.py +++ b/drive/api/integration.py @@ -6,7 +6,7 @@ def presentation(doc, event): if file: if event == "on_update": - frappe.get_doc("Drive File", file).rename(doc.title) + frappe.get_doc("Drive File", file).rename(doc.file_name) if event == "on_trash": print("gone, boom boom") frappe.get_doc("Drive File", file).permanent_delete() diff --git a/drive/api/list.py b/drive/api/list.py index 58100c2ca..691b9c6e8 100644 --- a/drive/api/list.py +++ b/drive/api/list.py @@ -27,7 +27,7 @@ def files( team: str, entity_name: str | None = None, order_by: str = "modified 1", - is_active: bool = True, + status: bool = True, limit: int = 20, favourites_only: bool = False, recents_only: bool = False, @@ -67,7 +67,7 @@ def files( frappe.exceptions.PermissionError, ) - query = frappe.qb.from_(DriveFile).where(DriveFile.status == is_active) + query = frappe.qb.from_(DriveFile).where(DriveFile.status == status) if shared: if shared == "by" or shared == "with": @@ -117,11 +117,11 @@ def files( .orderby(DriveFile[field], order=Order.asc if ascending else Order.desc) ) - if not is_active: + if not status: query = query.where(DriveFile.owner == frappe.session.user) if search: # escape wildcards or lower() depending on DB - query = query.where(DriveFile.title.like(f"%{search}%")) + query = query.where(DriveFile.file_name.like(f"%{search}%")) query = query.select(Recents.last_interaction.as_("accessed")) if tag_list: @@ -200,6 +200,6 @@ def files( @frappe.whitelist() def get_transfers(): transfers = frappe.get_list( - "Drive Transfer", filters={"owner": frappe.session.user}, fields=["title", "file_size", "creation", "name"] + "Drive Transfer", filters={"owner": frappe.session.user}, fields=["file_name", "file_size", "creation", "name"] ) return transfers diff --git a/drive/api/notifications.py b/drive/api/notifications.py index 3d4c8bcda..953e498ce 100644 --- a/drive/api/notifications.py +++ b/drive/api/notifications.py @@ -6,7 +6,7 @@ def get_link(entity): if entity.doc: return "/writer/w/" + entity.name - type_ = {True: "f", bool(entity.is_group): "d"} + type_ = {True: "f", bool(entity.is_folder): "d"} return entity.path if entity.is_link else f"/drive/{type_.get(True)}/{entity.name}/" @@ -87,7 +87,7 @@ def notify_share(entity_name, docperm_name): docshare = frappe.get_doc("Drive Permission", docperm_name) author_full_name = frappe.db.get_value("User", {"name": docshare.owner}, ["full_name"]) - entity_type = "document" if entity.doc else "folder" if entity.is_group else "file" + entity_type = "document" if entity.doc else "folder" if entity.is_folder else "file" link = get_link(entity) message = f'{author_full_name} shared a {entity_type} with you: "{entity.title}"' if not frappe.db.exists("User", docshare.user): @@ -105,7 +105,7 @@ def create_notification(from_user: str, to_user: str, type: str, entity: str, me if user_access.get("read") == 0: return - entity_type = "Document" if entity.doc else "Folder" if entity.is_group else "File" + entity_type = "Document" if entity.doc else "Folder" if entity.is_folder else "File" details = { "from_user": from_user, "to_user": to_user, diff --git a/drive/api/permissions.py b/drive/api/permissions.py index 4cb763774..0cc4614e7 100644 --- a/drive/api/permissions.py +++ b/drive/api/permissions.py @@ -60,7 +60,7 @@ def get_user_access(entity: str | Document | frappe._dict, user: str = None, tea "read": 1, "comment": 1, "share": 0, - "upload": int(entity.is_group) and access_level, + "upload": int(entity.is_folder) and access_level, "write": int(access_level == 2 or entity.owner == user), "type": {2: "admin", 1: "user", 0: "guest"}[access_level], } @@ -135,7 +135,7 @@ def get_entity_with_permissions(entity_name: str): """ entity = frappe.db.get_value( "Drive File", - {"is_active": 1, "name": entity_name}, + {"status": 1, "name": entity_name}, FILE_FIELDS, as_dict=1, ) @@ -165,7 +165,7 @@ def get_entity_with_permissions(entity_name: str): manager = FileManager() wrapper = io.TextIOWrapper(manager.get_file(entity)) url_builder = ( - lambda label, base, end: f"/api/method/drive.api.docs.get_wiki_link?team={entity.team}&title={label}" + lambda label, base, end: f"/api/method/drive.api.docs.get_wiki_link?team={entity.team}&file_name={label}" ) with wrapper as r: content = r.read() diff --git a/drive/api/scripts.py b/drive/api/scripts.py index 527d6d905..64be8b6c6 100644 --- a/drive/api/scripts.py +++ b/drive/api/scripts.py @@ -52,12 +52,12 @@ def get_or_create_parent(parent_path, owner): # Now create this parent folder new_parent = create_drive_file( team, - title=parent_path.strip("/").split("/")[-1], + file_name=parent_path.strip("/").split("/")[-1], parent=grandparent, mime_type="folder", entity_path=lambda _: str(parent_path) + "/", file_size=0, - is_group=True, + is_folder=True, owner=owner, ) return new_parent.name @@ -80,7 +80,7 @@ def get_or_create_parent(parent_path, owner): lambda _: actual_path if mime_type != "folder" else actual_path.strip("/") + "/", last_modified=last_modified, file_size=file_size, - is_group=mime_type == "folder", + is_folder=mime_type == "folder", owner=frappe.session.user, ) ) diff --git a/drive/api/storage.py b/drive/api/storage.py index 100fa6b89..e5796d58b 100644 --- a/drive/api/storage.py +++ b/drive/api/storage.py @@ -13,8 +13,8 @@ def storage_breakdown(team: str, owned_only: bool): limit = frappe.get_value("Drive Team", team, "quota" if owned_only else "storage") * MEGA_BYTE filters = { "team": team, - "is_group": False, - "is_active": 1, + "is_folder": False, + "status": 1, "file_size": [">=", limit / 200], } if owned_only: @@ -25,7 +25,7 @@ def storage_breakdown(team: str, owned_only: bool): "Drive File", filters=filters, order_by="file_size desc", - fields=["name", "title", "owner", "file_size", "mime_type", "is_group", "is_link"], + fields=["name", "file_name", "owner", "file_size", "mime_type", "is_folder", "is_link"], ) for r in entities: r["file_type"] = get_file_type(r) @@ -33,7 +33,7 @@ def storage_breakdown(team: str, owned_only: bool): query = ( frappe.qb.from_(DriveFile) .select(DriveFile.mime_type, fn.Sum(DriveFile.file_size).as_("file_size")) - .where((DriveFile.is_group == 0) & (DriveFile.is_active == 1) & (DriveFile.team == team)) + .where((DriveFile.is_folder == 0) & (DriveFile.status == 1) & (DriveFile.team == team)) ) if owned_only: query = query.where(DriveFile.owner == frappe.session.user) @@ -56,9 +56,9 @@ def storage_bar_data(team: str | None = None, entity_name: str | None = None): frappe.qb.from_(DriveFile) .where( (DriveFile.team == team) - & (DriveFile.is_group == 0) + & (DriveFile.is_folder == 0) & (DriveFile.owner == frappe.session.user) - & (DriveFile.is_active == 1) + & (DriveFile.status == 1) ) .select(fn.Coalesce(fn.Sum(DriveFile.file_size), 0).as_("total_size")) ) diff --git a/drive/drive/doctype/drive_entity_activity_log/patches/share_creation.py b/drive/drive/doctype/drive_entity_activity_log/patches/share_creation.py index f07578d54..8c71911b0 100644 --- a/drive/drive/doctype/drive_entity_activity_log/patches/share_creation.py +++ b/drive/drive/doctype/drive_entity_activity_log/patches/share_creation.py @@ -37,26 +37,26 @@ def create_activity_log(share): def update_activity_log(log, share): - title = frappe.db.get_value("Drive File", share.share_name, ["title"]) + file_name = frappe.db.get_value("Drive File", share.share_name, ["file_name"]) owner_fullname = get_fullname(share.owner) if share.everyone: log.document_field = "everyone" - message = f"{owner_fullname} shared {title} with everyone" + message = f"{owner_fullname} shared {file_name} with everyone" log.old_value = False log.new_value = True elif share.public: log.document_field = "public" - message = f"{owner_fullname} shared {title} with publicly" + message = f"{owner_fullname} shared {file_name} with publicly" log.old_value = False log.new_value = True elif share.user_doctype == "User Group": log.document_field = "User Group" - message = f"{owner_fullname} shared {title} with {share.user_name}" + message = f"{owner_fullname} shared {file_name} with {share.user_name}" log.old_value = None log.new_value = share.user_name else: log.document_field = "User" - message = f"{owner_fullname} shared {title} with {share.user_name}" + message = f"{owner_fullname} shared {file_name} with {share.user_name}" log.old_value = None log.new_value = share.user_name log.save() diff --git a/drive/drive/doctype/drive_file/drive_file.py b/drive/drive/doctype/drive_file/drive_file.py index dd408b5c8..79a0a17b4 100644 --- a/drive/drive/doctype/drive_file/drive_file.py +++ b/drive/drive/doctype/drive_file/drive_file.py @@ -9,7 +9,7 @@ from frappe.rate_limiter import rate_limit from drive.api.activity import create_new_activity_log -from drive.api.files import get_new_title +from drive.api.files import get_new_file_name from drive.api.permissions import get_user_access, user_has_permission from drive.api.product import invite_users from drive.utils import generate_upward_path, get_home_folder, update_file_size @@ -27,13 +27,13 @@ def manager(self): def after_insert(self): full_name = frappe.db.get_value("User", {"name": frappe.session.user}, ["full_name"]) - message = f"{full_name} created {self.title}" + message = f"{full_name} created {self.file_name}" create_new_activity_log( entity=self.name, activity_type="create", activity_message=message, - document_field="title", - field_new_value=self.title, + document_field="file_name", + field_new_value=self.file_name, ) def on_trash(self): @@ -43,7 +43,7 @@ def on_trash(self): frappe.db.delete("Drive Notification", {"notif_doctype_name": self.name}) frappe.db.delete("Drive Entity Activity Log", {"entity": self.name}) - if self.is_group or self.document: + if self.is_folder or self.document: for child in self.get_children(): has_write_access = user_has_permission(self, "write") child.delete(ignore_permissions=has_write_access) @@ -59,7 +59,7 @@ def after_delete(self): def on_rollback(self): if self.flags.file_created: - shutil.rmtree(self.path) if self.is_group else self.path.unlink() + shutil.rmtree(self.path) if self.is_folder else self.path.unlink() def get_children(self): """Return a generator that yields child Documents.""" @@ -72,7 +72,7 @@ def decorator(self: DriveFile, *args, **kwargs): # Legacy code kwargs.pop("client", None) res = func(self, *args, **kwargs) - frappe.db.set_value("Drive File", self.name, "_modified", now()) + frappe.db.set_value("Drive File", self.name, "last_modified", now()) return res return decorator @@ -102,7 +102,7 @@ def move(self, new_parent=None, new_team=None): frappe.PermissionError, ) if not ( - frappe.db.get_value("Drive File", new_parent, "is_group") + frappe.db.get_value("Drive File", new_parent, "is_folder") or frappe.db.get_value("Drive File", new_parent, "doc") ): frappe.throw( @@ -123,7 +123,7 @@ def move(self, new_parent=None, new_team=None): update_file_size(self.parent_entity, -self.file_size) update_file_size(new_parent, +self.file_size) self.parent_entity = new_parent - self.title = get_new_title(self.title, new_parent, self.is_group, self.name) + self.file_name = get_new_file_name(self.file_name, new_parent, self.is_folder, self.name) self.team = new_team @@ -138,41 +138,41 @@ def move(self, new_parent=None, new_team=None): self.save() - return frappe.get_value("Drive File", new_parent, ["title", "team", "name", "parent_entity"], as_dict=True) + return frappe.get_value("Drive File", new_parent, ["file_name", "team", "name", "parent_entity"], as_dict=True) @frappe.whitelist() @__update_modified - def rename(self: DriveFile, new_title: str): + def rename(self: DriveFile, new_file_name: str): """ Rename file or folder - :param new_title: New file or folder name + :param new_file_name: New file or folder name :raises FileExistsError: If a file or folder with the same name already exists in the parent folder :return: DriveEntity doc once it's renamed """ - if new_title == self.title: + if new_file_name == self.file_name: return self - validated_name = get_new_title(new_title, self.parent_entity, self.is_group, self.name) - if new_title != validated_name: + validated_name = get_new_file_name(new_file_name, self.parent_entity, self.is_folder, self.name) + if new_file_name != validated_name: return frappe.throw( - f"{'Folder' if self.is_group else 'File'} '{new_title}' already exists\n Try '{validated_name}' ", + f"{'Folder' if self.is_folder else 'File'} '{new_file_name}' already exists\n Try '{validated_name}' ", FileExistsError, ) full_name = frappe.db.get_value("User", {"name": frappe.session.user}, ["full_name"]) - message = f"{full_name} renamed {self.title} to {new_title}" + message = f"{full_name} renamed {self.file_name} to {new_file_name}" create_new_activity_log( entity=self.name, activity_type="rename", activity_message=message, - document_field="title", - field_old_value=self.title, - field_new_value=new_title, + document_field="file_name", + field_old_value=self.file_name, + field_new_value=new_file_name, ) - if len(new_title) > 140: - frappe.throw("Your title can't be more than 140 characters.") - self.title = new_title + if len(new_file_name) > 140: + frappe.throw("Your file_name can't be more than 140 characters.") + self.file_name = new_file_name path = self.manager.rename(self) if self.path and self.mime_type != "frappe/slides": @@ -207,8 +207,8 @@ def permanent_delete(self): if not (write_access or parent_write_access): frappe.throw("Not permitted", frappe.PermissionError) - self.is_active = -1 - if self.is_group: + self.status = -1 + if self.is_folder: for child in self.get_children(): child.permanent_delete() self.save() @@ -344,4 +344,4 @@ def toggle_favourite(self: DriveFile): def on_doctype_update(): - frappe.db.add_index("Drive File", ["title"]) + frappe.db.add_index("Drive File", ["file_name"]) diff --git a/drive/drive/doctype/drive_team/drive_team.py b/drive/drive/doctype/drive_team/drive_team.py index 27ae9bc8c..5709b4b6e 100644 --- a/drive/drive/doctype/drive_team/drive_team.py +++ b/drive/drive/doctype/drive_team/drive_team.py @@ -17,9 +17,9 @@ def after_insert(self): { "name": self.name, "doctype": "Drive File", - "title": f"Drive - {self.name}", + "file_name": f"Drive - {self.name}", "path": "", - "is_group": 1, + "is_folder": 1, "team": self.name, } ) diff --git a/drive/utils/__init__.py b/drive/utils/__init__.py index 302aa3a8e..6fb53f533 100644 --- a/drive/utils/__init__.py +++ b/drive/utils/__init__.py @@ -164,7 +164,7 @@ def generate_upward_path(entity_name, user=None, team=0): """ if user is None: user = frappe.session.user - user = frappe.db.escape(user if user != "Guest" else "") + user = frappe.db.escape(user if user != "Guest" else "") filter_: str if team: @@ -176,7 +176,7 @@ def generate_upward_path(entity_name, user=None, team=0): f"""WITH RECURSIVE generated_path as ( SELECT - `tabDrive File`.title, + `tabDrive File`.file_name, `tabDrive File`.name, `tabDrive File`.team, `tabDrive File`.parent_entity, @@ -188,7 +188,7 @@ def generate_upward_path(entity_name, user=None, team=0): `tabDrive File`.name = %(entity_name)s UNION ALL SELECT - t.title, + t.file_name, t.name, t.team, t.parent_entity, @@ -199,7 +199,7 @@ def generate_upward_path(entity_name, user=None, team=0): JOIN `tabDrive File` as t ON t.name = gp.parent_entity ) SELECT - gp.title, + gp.file_name, gp.name, gp.owner, gp.parent_entity, @@ -247,10 +247,10 @@ def get_valid_breadcrumbs(entity_name, user_access): def get_file_type(r): if r["is_folder"]: return "Folder" - elif r["file_type"] == 'Link': + elif r["file_type"] == "Link": return "Link" else: - return r['file_type'] + return r["file_type"] try: return next(k for (k, v) in MIME_LIST_MAP.items() if r["mime_type"] in v) except StopIteration: @@ -270,46 +270,46 @@ def update_file_size(entity, delta): def if_folder_exists(team, folder_name, parent): values = { - "title": folder_name, - "is_group": 1, - "is_active": 1, + "file_name": folder_name, + "is_folder": 1, + "status": 1, "team": team, "owner": frappe.session.user, "parent_entity": parent, } - existing_folder = frappe.db.get_value("Drive File", values, ["name", "title", "is_group", "is_active"], as_dict=1) + existing_folder = frappe.db.get_value("Drive File", values, ["name", "file_name", "is_folder", "status"], as_dict=1) if existing_folder: return existing_folder.name else: - d = frappe.get_doc({"doctype": "Drive File", **values, "_modified": frappe.utils.now_datetime()}) + d = frappe.get_doc({"doctype": "Drive File", **values, "last_modified": frappe.utils.now_datetime()}) d.insert() return d.name def create_drive_file( team, - title, + file_name, parent, mime_type, entity_path, file_size=0, last_modified=None, document=None, - is_group=False, + is_folder=False, owner=None, ): drive_file = frappe.get_doc( { "doctype": "Drive File", "team": team, - "title": title, + "file_name": file_name, "parent_entity": parent, "file_size": file_size, "mime_type": mime_type, "doc": document, - "is_group": is_group, - "_modified": (datetime.fromtimestamp(last_modified) if last_modified else frappe.utils.now()), + "is_folder": is_folder, + "last_modified": (datetime.fromtimestamp(last_modified) if last_modified else frappe.utils.now()), } ) drive_file.flags.file_created = True @@ -408,9 +408,9 @@ def get_teams(user=None, details=None, exclude_personal=True): "is_folder", "special_file", "special_file_doc", - Field("drive_team").as_('team'), + Field("drive_team").as_("team"), "creation", Field("last_modified").as_("modified"), "owner", "settings", -] \ No newline at end of file +] diff --git a/drive/utils/files.py b/drive/utils/files.py index 62d2e79f8..aec9fb9e8 100644 --- a/drive/utils/files.py +++ b/drive/utils/files.py @@ -192,8 +192,8 @@ def get_disk_path(self, entity: DriveFile, root: dict = None, embed=False): else Path(entity.parent_path) ) if embed: - return parent / ".embeds" / entity.title - return parent / entity.title + return parent / ".embeds" / entity.file_name + return parent / entity.file_name @__not_if_flat def create_folder(self, entity, root): @@ -295,21 +295,21 @@ def fetch_new_files(self, team) -> dict[Path, tuple[str]]: for path, f in basic_files.items(): # Drive-created folders - registered S3 objects - have trailing slashes. - is_group = f.get("Folder") or f["Key"].endswith("/") + is_folder = f.get("Folder") or f["Key"].endswith("/") exists = frappe.get_value( "Drive File", { - "path": f["Key"].rstrip("/") + ("/" if is_group else ""), - "is_active": 1, + "path": f["Key"].rstrip("/") + ("/" if is_folder else ""), + "status": 1, "team": team, - "is_group": int(is_group), + "is_folder": int(is_folder), }, "name", ) if exists: continue - mime_type = "folder" if is_group else mimemapper.get_mime_type(f["Key"], native_first=False) + mime_type = "folder" if is_folder else mimemapper.get_mime_type(f["Key"], native_first=False) # Team path is key, DB path is f["Key"] files[path] = (f["Size"], f["LastModified"].timestamp(), mime_type, f["Key"]) else: @@ -321,7 +321,7 @@ def fetch_new_files(self, team) -> dict[Path, tuple[str]]: path = f.relative_to(self.site_folder) exists = frappe.get_value( "Drive File", - {"path": str(path), "team": team, "is_active": 1}, + {"path": str(path), "team": team, "status": 1}, "name", ) if exists or any(p for p in f.parts if p.startswith(".")): @@ -347,7 +347,7 @@ def get_thumbnail(self, team, name): def __get_trash_path(self, entity: DriveFile): root = get_home_folder(entity.team) - return Path(root["path"]) / ".trash" / entity.title + return Path(root["path"]) / ".trash" / entity.file_name @__not_if_flat def rename(self, entity): diff --git a/drive/utils/users.py b/drive/utils/users.py index 8f6d0b28b..9308741a9 100644 --- a/drive/utils/users.py +++ b/drive/utils/users.py @@ -10,7 +10,7 @@ def mark_as_viewed(entity): if ( frappe.session.user == "Guest" or not frappe.has_permission(doctype="Drive Entity Log", ptype="create", user=frappe.session.user) - or entity.is_group + or entity.is_folder ): return diff --git a/drive/www/drive.py b/drive/www/drive.py index 51c0bca6e..b4fc3b196 100644 --- a/drive/www/drive.py +++ b/drive/www/drive.py @@ -4,7 +4,7 @@ no_cache = 1 -TITLES = {"login": "Login", "signup": "Create an Account"} +file_nameS = {"login": "Login", "signup": "Create an Account"} def get_context(): @@ -28,8 +28,10 @@ def get_context(): context.description = "Open this online." # Ideally add thumbnail, but that might break if there's no thumbnail try: - [title, owner, is_group] = frappe.get_cached_value("Drive File", parts[1], ["title", "owner", "is_group"]) - context.title = "Folder - " + title if is_group else title + [file_name, owner, is_folder] = frappe.get_cached_value( + "Drive File", parts[1], ["title", "owner", "is_folder"] + ) + context.file_name = "Folder - " + file_name if is_folder else title context.description = "Owned by " + frappe.get_cached_value("User", owner, "full_name") except: pass diff --git a/frontend/src/components/MoveDialog.vue b/frontend/src/components/MoveDialog.vue index d9857efb2..1dab892fc 100644 --- a/frontend/src/components/MoveDialog.vue +++ b/frontend/src/components/MoveDialog.vue @@ -1,9 +1,5 @@