diff --git a/frappe/__init__.py b/frappe/__init__.py
index 8d02238975..8bbb452ab0 100644
--- a/frappe/__init__.py
+++ b/frappe/__init__.py
@@ -16,6 +16,7 @@ import json
import semantic_version
from frappe.core.doctype.print_format.print_format import get_html as get_print_html
+from .exceptions import *
local = Local()
@@ -71,7 +72,6 @@ form = form_dict = local("form_dict")
request = local("request")
request_method = local("request_method")
response = local("response")
-_response = local("_response")
session = local("session")
user = local("user")
flags = local("flags")
@@ -149,21 +149,6 @@ def cache():
_memc = MClient(['localhost:11211'])
return _memc
-class DuplicateEntryError(Exception): pass
-class ValidationError(Exception): pass
-class AuthenticationError(Exception): pass
-class PermissionError(Exception): pass
-class DataError(Exception): pass
-class UnknownDomainError(Exception): pass
-class SessionStopped(Exception): pass
-class MappingMismatchError(ValidationError): pass
-class InvalidStatusError(ValidationError): pass
-class DoesNotExistError(ValidationError): pass
-class MandatoryError(ValidationError): pass
-class InvalidSignatureError(ValidationError): pass
-class RateLimitExceededError(ValidationError): pass
-class OutgoingEmailError(Exception): pass
-
def get_traceback():
import utils
return utils.get_traceback()
@@ -562,8 +547,6 @@ def repsond_as_web_page(title, html):
local.response['type'] = 'page'
local.response['page_name'] = 'message.html'
- return obj
-
def build_match_conditions(doctype, as_condition=True):
import frappe.widgets.reportview
return frappe.widgets.reportview.build_match_conditions(doctype, as_condition)
diff --git a/frappe/api.py b/frappe/api.py
index e8a9358c18..9d306f1280 100644
--- a/frappe/api.py
+++ b/frappe/api.py
@@ -5,7 +5,7 @@ import frappe
import frappe.handler
import frappe.client
import frappe.widgets.reportview
-from frappe.utils.response import build_response, report_error
+from frappe.utils.response import build_response
def handle():
"""
@@ -35,63 +35,56 @@ def handle():
if len(parts) > 3:
name = parts[3]
- try:
- if call=="method":
- frappe.local.form_dict.cmd = doctype
- frappe.handler.handle()
- return
-
- elif call=="resource":
- if "run_method" in frappe.local.form_dict:
- bean = frappe.bean(doctype, name)
+ if call=="method":
+ frappe.local.form_dict.cmd = doctype
+ return frappe.handler.handle()
+
+ elif call=="resource":
+ if "run_method" in frappe.local.form_dict:
+ bean = frappe.bean(doctype, name)
+
+ if frappe.local.request.method=="GET":
+ if not bean.has_permission("read"):
+ frappe.throw("No Permission", frappe.PermissionError)
+ bean.run_method(frappe.local.form_dict.run_method, **frappe.local.form_dict)
+
+ if frappe.local.request.method=="POST":
+ if not bean.has_permission("write"):
+ frappe.throw("No Permission", frappe.PermissionError)
+ bean.run_method(frappe.local.form_dict.run_method, **frappe.local.form_dict)
+ frappe.db.commit()
+ else:
+ if name:
if frappe.local.request.method=="GET":
- if not bean.has_permission("read"):
- frappe.throw("No Permission", frappe.PermissionError)
- bean.run_method(frappe.local.form_dict.run_method, **frappe.local.form_dict)
-
+ frappe.local.response.update({
+ "doclist": frappe.client.get(doctype,
+ name)})
+
if frappe.local.request.method=="POST":
- if not bean.has_permission("write"):
- frappe.throw("No Permission", frappe.PermissionError)
- bean.run_method(frappe.local.form_dict.run_method, **frappe.local.form_dict)
+ frappe.local.response.update({
+ "doclist": frappe.client.insert(frappe.local.form_dict.doclist)})
frappe.db.commit()
-
- else:
- if name:
- if frappe.local.request.method=="GET":
- frappe.local.response.update({
- "doclist": frappe.client.get(doctype,
- name)})
-
- if frappe.local.request.method=="POST":
- frappe.local.response.update({
- "doclist": frappe.client.insert(frappe.local.form_dict.doclist)})
- frappe.db.commit()
-
- if frappe.local.request.method=="PUT":
- frappe.local.response.update({
- "doclist":frappe.client.save(frappe.local.form_dict.doclist)})
- frappe.db.commit()
-
- if frappe.local.request.method=="DELETE":
- frappe.client.delete(doctype, name)
- frappe.local.response.message = "ok"
-
- elif doctype:
- if frappe.local.request.method=="GET":
- frappe.local.response.update({
- "data": frappe.call(frappe.widgets.reportview.execute,
- doctype, **frappe.local.form_dict)})
- else:
- raise frappe.DoesNotExistError
-
- else:
- raise frappe.DoesNotExistError
-
- except frappe.DoesNotExistError, e:
- report_error(404)
- except Exception, e:
- report_error(500)
+ if frappe.local.request.method=="PUT":
+ frappe.local.response.update({
+ "doclist":frappe.client.save(frappe.local.form_dict.doclist)})
+ frappe.db.commit()
+
+ if frappe.local.request.method=="DELETE":
+ frappe.client.delete(doctype, name)
+ frappe.local.response.message = "ok"
+
+ elif doctype:
+ if frappe.local.request.method=="GET":
+ frappe.local.response.update({
+ "data": frappe.call(frappe.widgets.reportview.execute,
+ doctype, **frappe.local.form_dict)})
+
+ else:
+ raise frappe.DoesNotExistError
+
+ else:
+ raise frappe.DoesNotExistError
- build_response()
+ return build_response("json")
diff --git a/frappe/app.py b/frappe/app.py
index 5c0a75210c..95ec261e44 100644
--- a/frappe/app.py
+++ b/frappe/app.py
@@ -25,65 +25,82 @@ local_manager = LocalManager([frappe.local])
_site = None
_sites_path = os.environ.get("SITES_PATH", ".")
-def handle_session_stopped():
- res = Response("""
-
-
- Updating.
- We will be back in a few moments...
-
-
- """)
- res.status_code = 503
- res.content_type = 'text/html'
- return res
-
@Request.application
def application(request):
frappe.local.request = request
+ response = None
try:
- site = _site or get_site_name(request.host)
- frappe.init(site=site, sites_path=_sites_path)
+ rollback = True
- if not frappe.local.conf:
- # site does not exist
- raise NotFound
+ init_site(request)
+ make_form_dict(request)
+ frappe.local.http_request = frappe.auth.HTTPRequest()
- frappe.local.form_dict = frappe._dict({ k:v[0] if isinstance(v, (list, tuple)) else v \
- for k, v in (request.form or request.args).iteritems() })
-
- frappe.local._response = Response()
- frappe.http_request = frappe.auth.HTTPRequest()
-
if frappe.local.form_dict.cmd:
- frappe.handler.handle()
+ response = frappe.handler.handle()
+
elif frappe.request.path.startswith("/api/"):
- frappe.api.handle()
+ response = frappe.api.handle()
+
elif frappe.request.path.startswith('/backups'):
- frappe.utils.response.download_backup(request.path)
+ response = frappe.utils.response.download_backup(request.path)
+
elif frappe.local.request.method in ('GET', 'HEAD'):
- frappe.website.render.render(frappe.request.path[1:])
+ response = frappe.website.render.render(request.path)
+
else:
raise NotFound
except HTTPException, e:
return e
- except frappe.AuthenticationError, e:
- frappe._response.status_code=401
-
except frappe.SessionStopped, e:
- frappe.local._response = handle_session_stopped()
+ response = frappe.utils.response.handle_session_stopped()
+
+ except (frappe.AuthenticationError,
+ frappe.PermissionError,
+ frappe.DoesNotExistError,
+ frappe.DuplicateEntryError,
+ frappe.OutgoingEmailError,
+ frappe.ValidationError), e:
+ response = frappe.utils.response.report_error(e.http_status_code)
+
+ if e.__class__ == frappe.AuthenticationError:
+ frappe.local.login_manager.clear_cookies()
+
+ else:
+ if frappe.local.request.method in ("POST", "PUT") and frappe.db:
+ frappe.db.commit()
+ rollback = False
+
finally:
- _response = frappe.local._response
+ if frappe.local.request.method in ("POST", "PUT") and frappe.db and rollback:
+ frappe.db.rollback()
+
+ # set cookies
+ if response:
+ frappe.local.cookie_manager.flush_cookies(response=response)
+
frappe.destroy()
+
+ return response
+
+def init_site(request):
+ site = _site or get_site_name(request.host)
+ frappe.init(site=site, sites_path=_sites_path)
+
+ if not frappe.local.conf:
+ # site does not exist
+ raise NotFound
+
+def make_form_dict(request):
+ frappe.local.form_dict = frappe._dict({ k:v[0] if isinstance(v, (list, tuple)) else v \
+ for k, v in (request.form or request.args).iteritems() })
- return _response
-
application = local_manager.make_middleware(application)
-
+
def serve(port=8000, profile=False, site=None, sites_path='.'):
global application, _site, _sites_path
_site = site
@@ -102,6 +119,6 @@ def serve(port=8000, profile=False, site=None, sites_path='.'):
application = StaticDataMiddleware(application, {
'/files': os.path.abspath(sites_path)
})
-
+
run_simple('0.0.0.0', int(port), application, use_reloader=True,
use_debugger=True, use_evalex=True)
diff --git a/frappe/auth.py b/frappe/auth.py
index f7be90a07f..a26a0017fa 100644
--- a/frappe/auth.py
+++ b/frappe/auth.py
@@ -2,13 +2,15 @@
# MIT License. See license.txt
from __future__ import unicode_literals
+import datetime
+
import frappe
import frappe.database
import frappe.utils
import frappe.utils.user
from frappe import conf
from frappe.sessions import Session
-
+from frappe.modules.patch_handler import check_session_stopped
class HTTPRequest:
def __init__(self):
@@ -33,11 +35,12 @@ class HTTPRequest:
# login
frappe.local.login_manager = LoginManager()
+
+ # write out latest cookies
+ frappe.local.cookie_manager.init_cookies()
# check status
- if frappe.db.get_global("__session_status")=='stop':
- frappe.msgprint(frappe.db.get_global("__session_status_message"))
- raise frappe.SessionStopped('Session Stopped')
+ check_session_stopped()
# load user
self.setup_user()
@@ -106,20 +109,23 @@ class LoginManager:
self.set_user_info()
def set_user_info(self):
+ # set sid again
+ frappe.local.cookie_manager.init_cookies()
+
info = frappe.db.get_value("User", self.user,
["user_type", "first_name", "last_name", "user_image"], as_dict=1)
if info.user_type=="Website User":
- frappe.local._response.set_cookie("system_user", "no")
+ frappe.local.cookie_manager.set_cookie("system_user", "no")
frappe.local.response["message"] = "No App"
else:
- frappe.local._response.set_cookie("system_user", "yes")
+ frappe.local.cookie_manager.set_cookie("system_user", "yes")
frappe.local.response['message'] = 'Logged In'
full_name = " ".join(filter(None, [info.first_name, info.last_name]))
frappe.response["full_name"] = full_name
- frappe._response.set_cookie("full_name", full_name)
- frappe._response.set_cookie("user_id", self.user)
- frappe._response.set_cookie("user_image", info.user_image or "")
+ frappe.local.cookie_manager.set_cookie("full_name", full_name)
+ frappe.local.cookie_manager.set_cookie("user_id", self.user)
+ frappe.local.cookie_manager.set_cookie("user_image", info.user_image or "")
def make_session(self, resume=False):
# start session
@@ -161,7 +167,7 @@ class LoginManager:
def run_trigger(self, event='on_login'):
for method in frappe.get_hooks().get(event, []):
- frappe.get_attr(method)(self)
+ frappe.call(frappe.get_attr(method), login_manager=self)
def validate_ip_address(self):
"""check if IP Address is valid"""
@@ -212,44 +218,45 @@ class LoginManager:
clear_sessions(user)
if user == frappe.session.user:
- frappe.session.sid = ""
- frappe.local._response.delete_cookie("full_name")
- frappe.local._response.delete_cookie("user_id")
- frappe.local._response.delete_cookie("sid")
- frappe.local._response.set_cookie("full_name", "")
- frappe.local._response.set_cookie("user_id", "")
- frappe.local._response.set_cookie("sid", "")
+ self.clear_cookies()
+
+ def clear_cookies(self):
+ frappe.session.sid = ""
+ frappe.local.cookie_manager.delete_cookie(["full_name", "user_id", "sid", "user_image", "system_user"])
class CookieManager:
def __init__(self):
- pass
+ self.cookies = {}
+ self.to_delete = []
- def set_cookies(self):
+ def init_cookies(self):
if not frappe.local.session.get('sid'): return
- import datetime
# sid expires in 3 days
expires = datetime.datetime.now() + datetime.timedelta(days=3)
if frappe.session.sid:
- frappe.local._response.set_cookie("sid", frappe.session.sid, expires = expires)
+ self.cookies["sid"] = {"value": frappe.session.sid, "expires": expires}
if frappe.session.session_country:
- frappe.local._response.set_cookie('country', frappe.session.get("session_country"))
+ self.cookies["country"] = {"value": frappe.session.get("session_country")}
+
+ def set_cookie(self, key, value, expires=None):
+ self.cookies[key] = {"value": value, "expires": expires}
+
+ def delete_cookie(self, to_delete):
+ if not isinstance(to_delete, (list, tuple)):
+ to_delete = [to_delete]
- def set_remember_me(self):
- from frappe.utils import cint
+ self.to_delete.extend(to_delete)
- if not cint(frappe.form_dict.get('remember_me')): return
+ def flush_cookies(self, response):
+ for key, opts in self.cookies.items():
+ response.set_cookie(key, opts.get("value"), expires=opts.get("expires"))
+
+ # expires yesterday!
+ expires = datetime.datetime.now() + datetime.timedelta(days=-1)
+ for key in set(self.to_delete):
+ response.set_cookie(key, "", expires=expires)
- remember_days = frappe.db.get_value('Control Panel', None,
- 'remember_for_days') or 7
-
- import datetime
- expires = datetime.datetime.now() + \
- datetime.timedelta(days=remember_days)
-
- frappe.local._response.set_cookie["remember_me"] = 1
-
-
def _update_password(user, password):
frappe.db.sql("""insert into __Auth (user, `password`)
values (%s, password(%s))
diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py
index 2f41b6e923..35ba142486 100644
--- a/frappe/core/doctype/doctype/doctype.py
+++ b/frappe/core/doctype/doctype/doctype.py
@@ -129,10 +129,16 @@ class DocType:
self.doc.doctype, self.doc.name), scrub(self.doc.name) + '.py')
if not os.path.exists(pypath):
+ # get app publisher for copyright
+ app = frappe.local.module_app[frappe.scrub(self.doc.module)]
+ if not app:
+ frappe.throw("App not found!")
+ app_publisher = frappe.get_hooks(hook="app_publisher", app_name=app)[0]
+
with open(pypath, 'w') as pyfile:
with open(os.path.join(get_module_path("core"), "doctype", "doctype",
"doctype_template.py"), 'r') as srcfile:
- pyfile.write(srcfile.read())
+ pyfile.write(srcfile.read().format(app_publisher=app_publisher))
def make_amendable(self):
"""
diff --git a/frappe/core/doctype/doctype/doctype_template.py b/frappe/core/doctype/doctype/doctype_template.py
index 7207ead2bf..bb4f563ecf 100644
--- a/frappe/core/doctype/doctype/doctype_template.py
+++ b/frappe/core/doctype/doctype/doctype_template.py
@@ -1,5 +1,5 @@
-# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# GNU General Public License. See license.txt
+# Copyright (c) 2013, {app_publisher}
+# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
diff --git a/frappe/exceptions.py b/frappe/exceptions.py
new file mode 100644
index 0000000000..ecd9957531
--- /dev/null
+++ b/frappe/exceptions.py
@@ -0,0 +1,35 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+
+# BEWARE don't put anything in this file except exceptions
+
+class ValidationError(Exception):
+ http_status_code = 417
+
+class AuthenticationError(Exception):
+ http_status_code = 401
+
+class PermissionError(Exception):
+ http_status_code = 403
+
+class DoesNotExistError(ValidationError):
+ http_status_code = 404
+
+class DuplicateEntryError(Exception):
+ http_status_code = 409
+
+class OutgoingEmailError(Exception):
+ http_status_code = 501
+
+class SessionStopped(Exception):
+ http_status_code = 503
+
+class DataError(Exception): pass
+class UnknownDomainError(Exception): pass
+class MappingMismatchError(ValidationError): pass
+class InvalidStatusError(ValidationError): pass
+class MandatoryError(ValidationError): pass
+class InvalidSignatureError(ValidationError): pass
+class RateLimitExceededError(ValidationError): pass
diff --git a/frappe/handler.py b/frappe/handler.py
index 84b0c85e07..c15c56f000 100755
--- a/frappe/handler.py
+++ b/frappe/handler.py
@@ -8,7 +8,7 @@ import frappe.utils
import frappe.sessions
import frappe.utils.file_manager
import frappe.widgets.form.run_method
-from frappe.utils.response import build_response, report_error
+from frappe.utils.response import build_response
@frappe.whitelist(allow_guest=True)
def startup():
@@ -64,33 +64,9 @@ def handle():
cmd = frappe.local.form_dict.cmd
if cmd!='login':
- status_codes = {
- frappe.PermissionError: 403,
- frappe.AuthenticationError: 401,
- frappe.DoesNotExistError: 404,
- frappe.DuplicateEntryError: 409,
- frappe.SessionStopped: 503,
- frappe.OutgoingEmailError: 501
- }
-
- try:
- execute_cmd(cmd)
- except Exception, e:
- report_error(status_codes.get(e.__class__, 500))
- else:
- if frappe.local.request.method in ("POST", "PUT") and frappe.db:
- frappe.db.commit()
- else:
- # commit for login
- if frappe.local.request.method in ("POST", "PUT") and frappe.db:
- frappe.db.commit()
+ execute_cmd(cmd)
- build_response()
-
- if frappe.db:
- frappe.db.close()
- if frappe._memc:
- frappe._memc.disconnect_all()
+ return build_response("json")
def execute_cmd(cmd):
"""execute a request as python module"""
@@ -102,7 +78,6 @@ def execute_cmd(cmd):
raise frappe.PermissionError('Not Allowed, %s' % str(method))
else:
if not method in frappe.whitelisted:
- frappe._response.status_code = 403
frappe.msgprint('Not Allowed, %s' % str(method))
raise frappe.PermissionError('Not Allowed, %s' % str(method))
diff --git a/frappe/hooks.txt b/frappe/hooks.txt
index 8888baacc9..45cc4912da 100644
--- a/frappe/hooks.txt
+++ b/frappe/hooks.txt
@@ -1,6 +1,6 @@
app_name = frappe
app_title = Frappe Framework
-app_publisher = Web Notes Technologies
+app_publisher = Web Notes Technologies Pvt. Ltd. and Contributors
app_description = Full Stack Web Application Framwork in Python
app_icon = assets/frappe/images/frappe.svg
app_version = 4.0.0-wip
diff --git a/frappe/modules/patch_handler.py b/frappe/modules/patch_handler.py
index 0ff2978246..851bf7b7b5 100644
--- a/frappe/modules/patch_handler.py
+++ b/frappe/modules/patch_handler.py
@@ -114,6 +114,11 @@ def block_user(block):
frappe.db.set_global('__session_status', block and 'stop' or None)
frappe.db.set_global('__session_status_message', block and msg or None)
frappe.db.commit()
+
+def check_session_stopped():
+ if frappe.db.get_global("__session_status")=='stop':
+ frappe.msgprint(frappe.db.get_global("__session_status_message"))
+ raise frappe.SessionStopped('Session Stopped')
def setup():
frappe.db.sql("""CREATE TABLE IF NOT EXISTS `__PatchLog` (
diff --git a/frappe/public/images/ui/field.jpg b/frappe/public/images/ui/field.jpg
deleted file mode 100644
index fd3498eb51..0000000000
Binary files a/frappe/public/images/ui/field.jpg and /dev/null differ
diff --git a/frappe/public/images/ui/random-polygons.jpg b/frappe/public/images/ui/random-polygons.jpg
deleted file mode 100755
index 146382fe81..0000000000
Binary files a/frappe/public/images/ui/random-polygons.jpg and /dev/null differ
diff --git a/frappe/public/images/ui/wallpaper.jpg b/frappe/public/images/ui/wallpaper.jpg
new file mode 100644
index 0000000000..205c2dde5b
Binary files /dev/null and b/frappe/public/images/ui/wallpaper.jpg differ
diff --git a/frappe/public/js/frappe/misc/user.js b/frappe/public/js/frappe/misc/user.js
index 0b52c29511..fa1d2a12c1 100644
--- a/frappe/public/js/frappe/misc/user.js
+++ b/frappe/public/js/frappe/misc/user.js
@@ -30,10 +30,10 @@ frappe.avatar = function(user, large, title) {
});
}
-frappe.ui.set_user_background = function(src) {
- if(!src) src = "assets/frappe/images/ui/random-polygons.jpg";
+frappe.ui.set_user_background = function(src, size) {
+ if(!src) src = "assets/frappe/images/ui/wallpaper.jpg";
frappe.dom.set_style(repl('#page-desktop { \
- background: url("%(src)s") center center fixed; \
+ background: url("%(src)s") center center; \
}', {src:src}))
}
diff --git a/frappe/sessions.py b/frappe/sessions.py
index 0442333742..fdc19b29db 100644
--- a/frappe/sessions.py
+++ b/frappe/sessions.py
@@ -59,7 +59,7 @@ def clear_sessions(user=None, keep_current=False):
user = frappe.session.user
for sid in frappe.db.sql("""select sid from tabSessions where user=%s""", (user,)):
if keep_current and frappe.session.sid==sid[0]:
- pass
+ continue
else:
frappe.cache().delete_value("session:" + sid[0])
frappe.db.sql("""delete from tabSessions where sid=%s""", (sid[0],))
@@ -104,9 +104,6 @@ class Session:
# set local session
frappe.local.session = self.data
- # write out latest cookies
- frappe.local.cookie_manager.set_cookies()
-
def start(self):
"""start a new session"""
# generate sid
diff --git a/frappe/templates/includes/login.js b/frappe/templates/includes/login.js
index 039a15488b..9ec8add689 100644
--- a/frappe/templates/includes/login.js
+++ b/frappe/templates/includes/login.js
@@ -102,7 +102,11 @@ login.login_handlers = {
}
},
401: function(xhr, data) {
- frappe.msgprint("Invalid Login");
+ if(xhr.responseJSON) {
+ data = xhr.responseJSON;
+ }
+ var message = data._server_messages ? JSON.parse(data._server_messages).join("\n") : "Invalid Login";
+ frappe.msgprint(message);
}
}
diff --git a/frappe/templates/pages/login.py b/frappe/templates/pages/login.py
index b4637d6eeb..f98015af41 100644
--- a/frappe/templates/pages/login.py
+++ b/frappe/templates/pages/login.py
@@ -33,7 +33,7 @@ oauth2_providers = {
"redirect_uri": "/api/method/frappe.templates.pages.login.login_via_google",
"auth_url_data": {
- "scope": "https://www.googleapis.com/auth/userinfo.user https://www.googleapis.com/auth/userinfo.email",
+ "scope": "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
"response_type": "code"
},
diff --git a/frappe/utils/response.py b/frappe/utils/response.py
index 7bccb724f3..f137145d42 100644
--- a/frappe/utils/response.py
+++ b/frappe/utils/response.py
@@ -12,6 +12,7 @@ from frappe import _
import frappe.utils
import frappe.sessions
import frappe.model.utils
+import werkzeug.utils
from werkzeug.local import LocalProxy
from werkzeug.wsgi import wrap_file
from werkzeug.wrappers import Response
@@ -20,61 +21,49 @@ from werkzeug.exceptions import NotFound, Forbidden
def report_error(status_code):
if status_code!=404 or frappe.conf.logging:
frappe.errprint(frappe.utils.get_traceback())
- frappe._response.status_code = status_code
- if frappe.request_method == "POST":
- frappe.db.rollback()
+
+ response = build_response("json")
+ response.status_code = status_code
+ return response
-def build_response():
- print_map = {
- 'csv': print_csv,
- 'download': print_raw,
- 'json': print_json,
- 'page': print_page,
+def build_response(response_type=None):
+ response_type_map = {
+ 'csv': as_csv,
+ 'download': as_raw,
+ 'json': as_json,
+ 'page': as_page,
'redirect': redirect
}
- print_map.get(frappe.response.get('type'), print_json)()
-
-def print_page():
- """print web page"""
- from frappe.website.render import render
- render(frappe.response['page_name'])
-
-def print_json():
- make_logs()
- cleanup_docs()
- frappe._response.headers["Content-Type"] = "text/json; charset: utf-8"
- print_zip(json.dumps(frappe.local.response, default=json_handler, separators=(',',':')))
-
-def redirect():
- frappe._response.data = """
- Redirecting...
- Redirecting...
- You should be redirected automatically to target URL: /.
- If not click the link.'""".format(location=frappe.response.location)
-
- frappe._response.headers["Content-Type"] = "text/html; charset: utf-8"
- frappe._response.status_code = frappe.response.status_code or 302
- frappe._response.location = frappe.response.location
+ return response_type_map[frappe.response.get('type') or response_type]()
-def cleanup_docs():
- if frappe.response.get('docs') and type(frappe.response['docs'])!=dict:
- frappe.response['docs'] = frappe.model.utils.compress(frappe.response['docs'])
-
-def print_csv():
- frappe._response.headers["Content-Type"] = \
+def as_csv():
+ response = Response()
+ response.headers["Content-Type"] = \
"text/csv; charset: utf-8"
- frappe._response.headers["Content-Disposition"] = \
+ response.headers["Content-Disposition"] = \
"attachment; filename=%s.csv" % frappe.response['doctype'].replace(' ', '_')
- frappe._response.data = frappe.response['result']
+ response.data = frappe.response['result']
+ return response
-def print_raw():
- frappe._response.headers["Content-Type"] = \
+def as_raw():
+ response = Response()
+ response.headers["Content-Type"] = \
mimetypes.guess_type(frappe.response['filename'])[0] or "application/unknown"
- frappe._response.headers["Content-Disposition"] = \
+ response.headers["Content-Disposition"] = \
"filename=%s" % frappe.response['filename'].replace(' ', '_')
- frappe._response.data = frappe.response['filecontent']
+ response.data = frappe.response['filecontent']
+ return response
+def as_json():
+ make_logs()
+ cleanup_docs()
+ response = Response()
+ response.headers["Content-Type"] = "text/json; charset: utf-8"
+ response = gzip(json.dumps(frappe.local.response, default=json_handler, separators=(',',':')),
+ response=response)
+ return response
+
def make_logs():
"""make strings for msgprint and errprint"""
if frappe.error_log:
@@ -87,15 +76,31 @@ def make_logs():
if frappe.debug_log and frappe.conf.get("logging") or False:
frappe.response['_debug_messages'] = json.dumps(frappe.local.debug_log)
-def print_zip(response):
- response = response.encode('utf-8')
- orig_len = len(response)
+def cleanup_docs():
+ if frappe.response.get('docs') and type(frappe.response['docs'])!=dict:
+ frappe.response['docs'] = frappe.model.utils.compress(frappe.response['docs'])
+
+def gzip(data, response):
+ data = data.encode('utf-8')
+ orig_len = len(data)
if accept_gzip() and orig_len>512:
- response = compressBuf(response)
- frappe._response.headers["Content-Encoding"] = "gzip"
+ data = compressBuf(data)
+ response.headers["Content-Encoding"] = "gzip"
- frappe._response.headers["Content-Length"] = str(len(response))
- frappe._response.data = response
+ response.headers["Content-Length"] = str(len(data))
+ response.data = data
+ return response
+
+def accept_gzip():
+ if "gzip" in frappe.get_request_header("HTTP_ACCEPT_ENCODING", ""):
+ return True
+
+def compressBuf(buf):
+ zbuf = cStringIO.StringIO()
+ zfile = gzip.GzipFile(mode = 'wb', fileobj = zbuf, compresslevel = 5)
+ zfile.write(buf)
+ zfile.close()
+ return zbuf.getvalue()
def json_handler(obj):
"""serialize non-serializable data for json"""
@@ -108,31 +113,30 @@ def json_handler(obj):
else:
raise TypeError, """Object of type %s with value of %s is not JSON serializable""" % \
(type(obj), repr(obj))
-
-def accept_gzip():
- if "gzip" in frappe.get_request_header("HTTP_ACCEPT_ENCODING", ""):
- return True
-
-def compressBuf(buf):
- zbuf = cStringIO.StringIO()
- zfile = gzip.GzipFile(mode = 'wb', fileobj = zbuf, compresslevel = 5)
- zfile.write(buf)
- zfile.close()
- return zbuf.getvalue()
-
+
+def as_page():
+ """print web page"""
+ from frappe.website.render import render
+ return render(frappe.response['page_name'])
+
+def redirect():
+ return werkzeug.utils.redirect(frappe.response.location)
+
def download_backup(path):
try:
frappe.only_for(("System Manager", "Administrator"))
except frappe.PermissionError:
raise Forbidden(_("You need to be logged in and have System Manager Role to be able to access backups."))
- send_private_file(path)
+
+ return send_private_file(path)
def send_private_file(path):
path = os.path.join(frappe.local.conf.get('private_path', 'private'), path.strip("/"))
if frappe.local.request.headers.get('X-Use-X-Accel-Redirect'):
path = '/' + path
- frappe.local._response.headers['X-Accel-Redirect'] = path
+ response = Response()
+ response.headers['X-Accel-Redirect'] = path
else:
filename = os.path.basename(path)
filepath = frappe.utils.get_site_path(path)
@@ -140,6 +144,22 @@ def send_private_file(path):
f = open(filepath, 'rb')
except IOError:
raise NotFound
- frappe.local._response = Response(wrap_file(frappe.local.request.environ, f))
- frappe.local._response.headers.add('Content-Disposition', 'attachment', filename=filename)
- frappe.local._response.headers['Content-Type'] = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
+
+ response = Response(wrap_file(frappe.local.request.environ, f))
+ response.headers.add('Content-Disposition', 'attachment', filename=filename)
+ response.headers['Content-Type'] = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
+
+ return response
+
+def handle_session_stopped():
+ response = Response("""
+
+
+ Updating.
+ We will be back in a few moments...
+
+
+ """)
+ response.status_code = 503
+ response.content_type = 'text/html'
+ return res
diff --git a/frappe/website/render.py b/frappe/website/render.py
index 03b1bb1722..c82d6a8d98 100644
--- a/frappe/website/render.py
+++ b/frappe/website/render.py
@@ -4,17 +4,18 @@
from __future__ import unicode_literals
import frappe
import mimetypes, json
+from werkzeug.wrappers import Response
from frappe.website.context import get_context
from frappe.website.utils import scrub_relative_urls, get_home_page, can_cache
-
from frappe.website.permissions import get_access, clear_permissions
class PageNotFoundError(Exception): pass
def render(path):
"""render html page"""
- path = resolve_path(path)
+ frappe.local.is_ajax = frappe.get_request_header("X-Requested-With")=="XMLHttpRequest"
+ path = resolve_path(path.lstrip("/"))
try:
data = render_page(path)
@@ -22,9 +23,12 @@ def render(path):
path = "error"
data = render_page(path)
- data = set_content_type(data, path)
- frappe._response.data = data
- frappe._response.headers[b"X-Page-Name"] = path.encode("utf-8")
+ # build response
+ response = Response()
+ response.data = set_content_type(response, data, path)
+ response.headers[b"X-Page-Name"] = path.encode("utf-8")
+ response.headers[b"X-From-Cache"] = frappe.local.response.from_cache or False
+ return response
def render_page(path):
"""get page html"""
@@ -39,9 +43,7 @@ def render_page(path):
out = out.get("data")
if out:
- if hasattr(frappe, "_response"):
- frappe._response.headers[b"X-From-Cache"] = True
-
+ frappe.local.response.from_cache = True
return out
return build(path)
@@ -75,8 +77,7 @@ def build_page(path):
return html
def is_ajax():
- return (frappe.get_request_header("X-Requested-With")=="XMLHttpRequest"
- if hasattr(frappe.local, "_response") else False)
+ return getattr(frappe.local, "is_ajax")
def resolve_path(path):
if not path:
@@ -90,17 +91,17 @@ def resolve_path(path):
return path
-def set_content_type(data, path):
+def set_content_type(response, data, path):
if isinstance(data, dict):
- frappe._response.headers[b"Content-Type"] = b"application/json; charset: utf-8"
+ response.headers[b"Content-Type"] = b"application/json; charset: utf-8"
data = json.dumps(data)
return data
- frappe._response.headers[b"Content-Type"] = b"text/html; charset: utf-8"
+ response.headers[b"Content-Type"] = b"text/html; charset: utf-8"
if "." in path and not path.endswith(".html"):
content_type, encoding = mimetypes.guess_type(path)
- frappe._response.headers[b"Content-Type"] = content_type.encode("utf-8")
+ response.headers[b"Content-Type"] = content_type.encode("utf-8")
return data