Skip to content

Commit

Permalink
v2-Beta16 release
Browse files Browse the repository at this point in the history
  • Loading branch information
kid1194 committed May 29, 2024
1 parent 6ee60a9 commit ac14036
Show file tree
Hide file tree
Showing 14 changed files with 151 additions and 89 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ It supports RTL layout and dark mode out of the box.

⚠️ **v2 is still in BETA stage** ⚠️

![v2 Beta15](https://img.shields.io/badge/v2_Beta15-2024/05/02-green?style=plastic)
![v2 Beta16](https://img.shields.io/badge/v2_Beta16-2024/05/30-green?style=plastic)

**Apologies in advance for any problem or bug you face with this module.**
**Please report any problem or bug you face so it can be fixed.**
Expand Down Expand Up @@ -177,16 +177,17 @@ You can't modify the original fields of a doctype, so create a new field or clon
### Available Field Options
| Option | Description |
| :--- | :--- |
| **dialog_title** 🔴 | Upload dialog title to be displayed ️(🔶Frappe >= v14.0.0).<br /><br />🔹Example: **"Upload Images"**<br />🔹Default: **"Upload"** |
| **dialog_title** | Upload dialog title to be displayed ️(🔶Frappe >= v14.0.0).<br /><br />🔹Example: **"Upload Images"**<br />🔹Default: **"Upload"** |
| **upload_notes** | Upload text to be displayed.<br /><br />🔹Example: **"Only images and videos, with maximum size of 2MB, are allowed to be uploaded"**<br />🔹Default: **""** |
| **disable_file_browser** 🔴 | Disable file browser uploads.<br /><br />⚠️ *(File browser is always disabled in Web Form)*<br /><br />🔹Default: **false** |
| **disable_auto_save** 🔴 | Disable form auto save after upload.<br /><br />🔹Default: **false** |
| **disable_file_browser** | Disable file browser uploads.<br /><br />⚠️ *(File browser is always disabled in Web Form)*<br /><br />🔹Default: **false** |
| **allow_multiple** | Allow multiple uploads.<br /><br />⚠️ *(Field value is a JSON array of files url)*<br /><br />🔹Default: **false** |
| **max_file_size** | Maximum file size (in bytes) that is allowed to be uploaded.<br /><br />🔹Example: **2048** for **2KB**<br />🔹Default: **Value of maximum file size in Frappe's settings** |
| **allowed_file_types** | Array of allowed file types (mimes) or extensions to upload. Prefix escaped RegExp string types with **$**.<br /><br />⚠️ *(File extensions must have a leading dot ".")*<br />⚠️ *(RegExp string types will not be used to in HTML accept attribute)*<br /><br />🔹Example: **["image/*", "video/*", ".pdf", ".doc", "$audio\/([a-z]+)"]**<br />🔹Default: **null** or **["image/*"]** |
| **max_number_of_files** | Maximum number of files allowed to be uploaded if multiple upload is allowed.<br /><br />⚠️ *(Bypassing the maximum attachments of doctype might not work)*<br /><br />🔹Example: **4**<br />🔹Default: **Value of maximum attachments set for the doctype** |
| **crop_image_aspect_ratio** | Crop aspect ratio for images (🔶Frappe >= v14.0.0).<br /><br />🔹Example: **1** or **16/9** or **4/3**<br />🔹Default: **null** |
| **as_public** | Force uploads to be saved in public folder by default.<br /><br />🔹Default: **false** |
| **allowed_filename** 🔴 | Only allow files that match a specific file name to be uploaded.<br /><br />🔹Example: (String)**"picture.png"** or (RegExp String)**"/picture\-([0-9]+)\.png/"**<br />🔹Default: **null** |
| **allowed_filename** | Only allow files that match a specific file name to be uploaded.<br /><br />🔹Example: (String)**"picture.png"** or (RegExp String)**"/picture\-([0-9]+)\.png/"**<br />🔹Default: **null** |
| **allow_reload** | Allow reloading attachments (🔶Frappe >= v13.0.0).<br /><br />🔶 Affect the visibility of the reload button.🔶<br /><br />🔹Default: **true** |
| **allow_remove** | Allow removing and clearing attachments.<br /><br />🔶 Affect the visibility of the remove and clear buttons.🔶<br /><br />🔹Default: **true** |

Expand All @@ -195,6 +196,7 @@ You can't modify the original fields of a doctype, so create a new field or clon
### Available JavaScript Methods
| Method | Description |
| :--- | :--- |
| **auto_save(enable: Boolean)** | Enable/Disable form auto save after upload. |
| **toggle_reload(allow: Boolean !Optional)** | Allow/Deny reloading attachments and toggle the reload button (🔶Frappe >= v13.0.0). |
| **toggle_remove(allow: Boolean !Optional)** | Allow/Deny removing and clearing attachments and toggle the clear and remove buttons. |
| **set_options(options: JSON Object)** | Set or change the plugin options. |
Expand Down
33 changes: 20 additions & 13 deletions frappe_better_attach_control/api/attachment.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@


import frappe
from frappe import _, is_whitelisted
from frappe.utils import cint

from .common import (
is_version_gt,
parse_json_if_valid,
send_console_log
)


_FILE_DOCTYPE_ = "File"
Expand All @@ -33,6 +25,8 @@

@frappe.whitelist(allow_guest=True)
def upload_file():
from frappe_better_attach_control.version import is_version_gt

user = None
ignore_permissions = False

Expand Down Expand Up @@ -91,6 +85,8 @@ def upload_file():
):
filetype = mimetypes.guess_type(filename)[0]
if filetype not in _ALLOWED_MIMETYPES_:
from frappe import _

frappe.throw(_("You can only upload JPG, PNG, PDF, TXT or Microsoft documents."))

elif is_version_gt(12):
Expand All @@ -99,9 +95,11 @@ def upload_file():

if method:
method = frappe.get_attr(method)
is_whitelisted(method)
frappe.is_whitelisted(method)
return method()
else:
from frappe.utils import cint

ret = frappe.get_doc({
"doctype": _FILE_DOCTYPE_,
"attached_to_doctype": doctype,
Expand All @@ -124,10 +122,12 @@ def upload_file():
@frappe.whitelist(methods=["POST"], allow_guest=True)
def remove_files(files):
if files and isinstance(files, str):
from .common import parse_json_if_valid

files = parse_json_if_valid(files)

if not files or not isinstance(files, list):
send_console_log({
_send_console_log({
"message": "Invalid files list",
"data": files
})
Expand All @@ -148,7 +148,7 @@ def remove_files(files):
file_names.append(file)

if not file_urls and not file_names:
send_console_log({
_send_console_log({
"message": "Invalid files path",
"data": files
})
Expand Down Expand Up @@ -176,8 +176,15 @@ def remove_files(files):

return 1

send_console_log({
_send_console_log({
"message": "Files not found",
"data": files
})
return 3
return 3


# [Internal]
def _send_console_log(data):
from .common import send_console_log

send_console_log(data)
19 changes: 5 additions & 14 deletions frappe_better_attach_control/api/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,17 @@
import json

import frappe
from frappe import __version__, _, _dict


__frappe_base_ver__ = int(__version__.split(".")[0])


def is_version_gt(num: int):
return __frappe_base_ver__ > num


def is_version_lt(num: int):
return __frappe_base_ver__ < num
from frappe import _, _dict


def error(msg, throw=True):
from frappe_better_attach_control.version import is_version_lt

title = "Better Attach Control"
if is_version_lt(14):
frappe.log_error(text, title)
frappe.log_error(msg, title)
else:
frappe.log_error(title, text)
frappe.log_error(title, msg)
if throw:
frappe.throw(msg, title=title)

Expand Down
17 changes: 11 additions & 6 deletions frappe_better_attach_control/api/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,18 @@

import frappe

from .common import send_console_log


@frappe.whitelist(methods=["POST"], allow_guest=True)
def get_options(doctype, name, webform):
if not doctype or not isinstance(doctype, str):
send_console_log({
_send_console_log({
"message": "Empty or invalid field doctype",
"data": [doctype, name]
})
return ""

if not name or not isinstance(name, str):
send_console_log({
_send_console_log({
"message": "Empty or invalid field name",
"data": [doctype, name]
})
Expand Down Expand Up @@ -67,8 +65,15 @@ def get_options(doctype, name, webform):
if options and isinstance(options, str):
return options

send_console_log({
_send_console_log({
"message": "Empty or invalid field options",
"data": [doctype, name, options]
})
return ""
return ""


# [Internal]
def _send_console_log(data):
from .common import send_console_log

send_console_log(data)
30 changes: 22 additions & 8 deletions frappe_better_attach_control/api/file_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,9 @@

import frappe
from frappe import _
from frappe.utils import flt, cint, cstr, get_url, get_files_path
from frappe.utils.file_manager import is_safe_path
from frappe.utils import cint, cstr, get_url
from frappe.core.doctype.file.file import URL_PREFIXES

from .common import error, get_cached_value


_FILE_DOCTYPE_ = "File"
_FILE_FIELDS_ = [
Expand Down Expand Up @@ -48,6 +45,8 @@ def _get_files_in_folder(folder, start, page_length):
)

if folder == "Home":
from .common import get_cached_value

attachment_folder = get_cached_value(
_FILE_DOCTYPE_,
"Home/Attachments",
Expand Down Expand Up @@ -87,6 +86,8 @@ def _prepare_files(files):
file = files[i]
file["size"] = 0
if not cint(file["is_folder"]):
from frappe.utils import flt

file["size"] = flt(file["file_size"])
if not file["size"]:
try:
Expand Down Expand Up @@ -114,21 +115,34 @@ def _get_full_path(file):
file_path = f"/files/{file_path}"

if file_path.startswith("/private/files/"):
from frappe.utils import get_files_path

file_path = get_files_path(*file_path.split("/private/files/", 1)[1].split("/"), is_private=1)

elif file_path.startswith("/files/"):
from frappe.utils import get_files_path

file_path = get_files_path(*file_path.split("/files/", 1)[1].split("/"))

elif file_path.startswith(URL_PREFIXES):
pass

elif not file["file_url"]:
error(_("There is some problem with the file url: {0}").format(file_path))
_error(_("There is some problem with the file url: {0}").format(file_path))

from frappe.utils.file_manager import is_safe_path

if not is_safe_path(file_path):
error(_("Cannot access file path {0}").format(file_path))
_error(_("Cannot access file path {0}").format(file_path))

if os.path.sep in file["file_name"]:
error(_("File name cannot have {0}").format(os.path.sep))
_error(_("File name cannot have {0}").format(os.path.sep))

return file_path


# [Internal]
def _error(msg):
from .common import error

return file_path
error(msg)
Loading

0 comments on commit ac14036

Please sign in to comment.