I am trying to use ERPNext’s File module as a document management system, and it has most of the pieces I need, except for folder-level permissions.
Currently, there is no way to restrict specific users or roles to a particular folder—either they can see ALL non-private files or NONE of them.
To get around this, I created a new Doctype, Role_Folder_Test, which basically just uses two link fields to create an association between a role and a folder.
I then edited the has_permission block in Frappe/Core/Doctype/File/File.py to check if there is an association between that particular folder and a role that the current user has. If so, has_access = True. This check is used in addition to those existing in the original source code. Here is the section I modified:
And it ALMOST works, but not entirely: While it does affect a user’s ability to OPEN a file within a given folder, they are still able to SEE the folder itself and all of its contents; it only blocks you once you actually click a file.
That’s where I’m stuck—I looked around some other functions inside file.py, but nothing immediately stood out as controlling which files and folders are shown to the user.
Here is the actual code block:
def has_permission(doc, ptype=None, user=None):
has_access = False
user = (user or frappe.session.user)
data = frappe.db.sql(
"""
select
RFT.file
from
tabUser U
inner join `tabHas Role` `HR` ON U.name = HR.parent
inner join `tabRole_Folder_Test` `RFT` ON HR.role = RFT.role
where 1=1
AND HR.parentType = 'User'
AND U.name = %(name)s
AND RFT.file = %(docName)s
""", {
'name' : user,
'docName': doc.name
}
)
if ptype == "create":
has_access = frappe.has_permission("File", "create", user=user)
if data:
has_access = True;
if doc.owner in [user, "Guest"] or user == "Administrator":
has_access = True
if doc.attached_to_doctype and doc.attached_to_name:
attached_to_doctype = doc.attached_to_doctype
attached_to_name = doc.attached_to_name
try:
ref_doc = frappe.get_doc(attached_to_doctype, attached_to_name)
if ptype in ["write", "create", "delete"]:
has_access = ref_doc.has_permission("write")
if ptype == "delete" and not has_access:
frappe.throw(
("Cannot delete file as it belongs to {0} {1} for which you do not have permissions").format(doc.attached_to_doctype, doc.attached_to_name),
frappe.PermissionError,)
else:
has_access = ref_doc.has_permission("read")
except frappe.DoesNotExistError:
# if parent doc is not created before file is created
# we cannot check its permission so we will use file's permission
pass
return has_access
(Also, I’ve read a lot of threads about other people trying to make document management systems, and have seen several recommendations of using the NextCloud integration. I’m not opposed to that, if I can’t get this working, but I don’t need most enterprise DMS features, so I’d prefer to get it all working inside ERPNext unless it ends up being more manual work)