Update on this: the following is the solution we came up with for this particular use case.
We just created this whitelisted python function:
import frappe, os, urlparse
@frappe.whitelist(allow_guest=True)
def view_attachment(file_name, user):
if not user == frappe.session.user:
frappe.msgprint("Session error.", indicator="red")
user = frappe.get_doc("User", user)
if not user:
frappe.throw("Authorization error.")
cwd = os.getcwd()
attachment = frappe.get_doc("File", file_name)
if attachment:
file_name = attachment.get('file_name')
file_url = attachment.get('file_url')
if not file_name and is_in_erp( file_url ): # to handle web url attachments
parsed_url = urlparse( file_url )
file_url = parsed_url.path
file_name = "Attachment"
if is_public_file( file_url ):
file_path = cwd + "/our.erpinstance.tld/public" + file_url
else:
file_path = cwd + "/our.erpinstance.tld" + file_url
else:
frappe.throw("File not found.")
with open(file_path, "rb") as fileobj:
filedata = fileobj.read()
frappe.local.response.filename = file_name
frappe.local.response.filecontent = filedata
frappe.local.response.type = "download"
def is_public_file(file_path):
if file_path[0:7] == "/files/":
return True
else:
return False
def is_in_erp(a_url):
parsed_url = urlparse(a_url)
if parsed_url.netloc == 'our.erpinstance.tld':
return True
else:
return False
And for the website users to view private files, you then just have to link to the file this way:
(JS)
var request_url = "/api/method/dotted.path.to.your.pymodule.view_attachment"
+ "?file_name="+encodeURIComponent("File Name Here")
+ "&user="+encodeURIComponent(frappe.session.user);
(HTML)
<a href="{{ request_url }}" target="_blank">File Name Here</a>
This sets a document level read permission to the user.
If the customer is logged on the portal then they can access the file over link you have shared