Parcourir la source

Merge pull request #472 from anandpdoshi/develop

Refactored handler, catch exceptions, response codes
version-14
Anand Doshi il y a 11 ans
Parent
révision
38f9636e45
19 fichiers modifiés avec 311 ajouts et 268 suppressions
  1. +1
    -18
      frappe/__init__.py
  2. +48
    -55
      frappe/api.py
  3. +54
    -37
      frappe/app.py
  4. +42
    -35
      frappe/auth.py
  5. +7
    -1
      frappe/core/doctype/doctype/doctype.py
  6. +2
    -2
      frappe/core/doctype/doctype/doctype_template.py
  7. +35
    -0
      frappe/exceptions.py
  8. +3
    -28
      frappe/handler.py
  9. +1
    -1
      frappe/hooks.txt
  10. +5
    -0
      frappe/modules/patch_handler.py
  11. BIN
      frappe/public/images/ui/field.jpg
  12. BIN
      frappe/public/images/ui/random-polygons.jpg
  13. BIN
      frappe/public/images/ui/wallpaper.jpg
  14. +3
    -3
      frappe/public/js/frappe/misc/user.js
  15. +1
    -4
      frappe/sessions.py
  16. +5
    -1
      frappe/templates/includes/login.js
  17. +1
    -1
      frappe/templates/pages/login.py
  18. +88
    -68
      frappe/utils/response.py
  19. +15
    -14
      frappe/website/render.py

+ 1
- 18
frappe/__init__.py Voir le fichier

@@ -16,6 +16,7 @@ import json
import semantic_version import semantic_version


from frappe.core.doctype.print_format.print_format import get_html as get_print_html from frappe.core.doctype.print_format.print_format import get_html as get_print_html
from .exceptions import *


local = Local() local = Local()


@@ -71,7 +72,6 @@ form = form_dict = local("form_dict")
request = local("request") request = local("request")
request_method = local("request_method") request_method = local("request_method")
response = local("response") response = local("response")
_response = local("_response")
session = local("session") session = local("session")
user = local("user") user = local("user")
flags = local("flags") flags = local("flags")
@@ -149,21 +149,6 @@ def cache():
_memc = MClient(['localhost:11211']) _memc = MClient(['localhost:11211'])
return _memc 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(): def get_traceback():
import utils import utils
return utils.get_traceback() return utils.get_traceback()
@@ -562,8 +547,6 @@ def repsond_as_web_page(title, html):
local.response['type'] = 'page' local.response['type'] = 'page'
local.response['page_name'] = 'message.html' local.response['page_name'] = 'message.html'
return obj

def build_match_conditions(doctype, as_condition=True): def build_match_conditions(doctype, as_condition=True):
import frappe.widgets.reportview import frappe.widgets.reportview
return frappe.widgets.reportview.build_match_conditions(doctype, as_condition) return frappe.widgets.reportview.build_match_conditions(doctype, as_condition)


+ 48
- 55
frappe/api.py Voir le fichier

@@ -5,7 +5,7 @@ import frappe
import frappe.handler import frappe.handler
import frappe.client import frappe.client
import frappe.widgets.reportview import frappe.widgets.reportview
from frappe.utils.response import build_response, report_error
from frappe.utils.response import build_response


def handle(): def handle():
""" """
@@ -35,63 +35,56 @@ def handle():
if len(parts) > 3: if len(parts) > 3:
name = 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 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 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() 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")

+ 54
- 37
frappe/app.py Voir le fichier

@@ -25,65 +25,82 @@ local_manager = LocalManager([frappe.local])
_site = None _site = None
_sites_path = os.environ.get("SITES_PATH", ".") _sites_path = os.environ.get("SITES_PATH", ".")


def handle_session_stopped():
res = Response("""<html>
<body style="background-color: #EEE;">
<h3 style="width: 900px; background-color: #FFF; border: 2px solid #AAA; padding: 20px; font-family: Arial; margin: 20px auto">
Updating.
We will be back in a few moments...
</h3>
</body>
</html>""")
res.status_code = 503
res.content_type = 'text/html'
return res

@Request.application @Request.application
def application(request): def application(request):
frappe.local.request = request frappe.local.request = request
response = None
try: 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: if frappe.local.form_dict.cmd:
frappe.handler.handle()
response = frappe.handler.handle()
elif frappe.request.path.startswith("/api/"): elif frappe.request.path.startswith("/api/"):
frappe.api.handle()
response = frappe.api.handle()
elif frappe.request.path.startswith('/backups'): 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'): elif frappe.local.request.method in ('GET', 'HEAD'):
frappe.website.render.render(frappe.request.path[1:])
response = frappe.website.render.render(request.path)
else: else:
raise NotFound raise NotFound


except HTTPException, e: except HTTPException, e:
return e return e
except frappe.AuthenticationError, e:
frappe._response.status_code=401
except frappe.SessionStopped, e: 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: 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() 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) application = local_manager.make_middleware(application)

def serve(port=8000, profile=False, site=None, sites_path='.'): def serve(port=8000, profile=False, site=None, sites_path='.'):
global application, _site, _sites_path global application, _site, _sites_path
_site = site _site = site
@@ -102,6 +119,6 @@ def serve(port=8000, profile=False, site=None, sites_path='.'):
application = StaticDataMiddleware(application, { application = StaticDataMiddleware(application, {
'/files': os.path.abspath(sites_path) '/files': os.path.abspath(sites_path)
}) })
run_simple('0.0.0.0', int(port), application, use_reloader=True, run_simple('0.0.0.0', int(port), application, use_reloader=True,
use_debugger=True, use_evalex=True) use_debugger=True, use_evalex=True)

+ 42
- 35
frappe/auth.py Voir le fichier

@@ -2,13 +2,15 @@
# MIT License. See license.txt # MIT License. See license.txt


from __future__ import unicode_literals from __future__ import unicode_literals
import datetime

import frappe import frappe
import frappe.database import frappe.database
import frappe.utils import frappe.utils
import frappe.utils.user import frappe.utils.user
from frappe import conf from frappe import conf
from frappe.sessions import Session from frappe.sessions import Session
from frappe.modules.patch_handler import check_session_stopped


class HTTPRequest: class HTTPRequest:
def __init__(self): def __init__(self):
@@ -33,11 +35,12 @@ class HTTPRequest:


# login # login
frappe.local.login_manager = LoginManager() frappe.local.login_manager = LoginManager()
# write out latest cookies
frappe.local.cookie_manager.init_cookies()


# check status # 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 # load user
self.setup_user() self.setup_user()
@@ -106,20 +109,23 @@ class LoginManager:
self.set_user_info() self.set_user_info()
def set_user_info(self): def set_user_info(self):
# set sid again
frappe.local.cookie_manager.init_cookies()
info = frappe.db.get_value("User", self.user, info = frappe.db.get_value("User", self.user,
["user_type", "first_name", "last_name", "user_image"], as_dict=1) ["user_type", "first_name", "last_name", "user_image"], as_dict=1)
if info.user_type=="Website User": 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" frappe.local.response["message"] = "No App"
else: else:
frappe.local._response.set_cookie("system_user", "yes")
frappe.local.cookie_manager.set_cookie("system_user", "yes")
frappe.local.response['message'] = 'Logged In' frappe.local.response['message'] = 'Logged In'


full_name = " ".join(filter(None, [info.first_name, info.last_name])) full_name = " ".join(filter(None, [info.first_name, info.last_name]))
frappe.response["full_name"] = full_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): def make_session(self, resume=False):
# start session # start session
@@ -161,7 +167,7 @@ class LoginManager:
def run_trigger(self, event='on_login'): def run_trigger(self, event='on_login'):
for method in frappe.get_hooks().get(event, []): 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): def validate_ip_address(self):
"""check if IP Address is valid""" """check if IP Address is valid"""
@@ -212,44 +218,45 @@ class LoginManager:
clear_sessions(user) clear_sessions(user)


if user == frappe.session.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: class CookieManager:
def __init__(self): 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 if not frappe.local.session.get('sid'): return
import datetime


# sid expires in 3 days # sid expires in 3 days
expires = datetime.datetime.now() + datetime.timedelta(days=3) expires = datetime.datetime.now() + datetime.timedelta(days=3)
if frappe.session.sid: 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: 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): def _update_password(user, password):
frappe.db.sql("""insert into __Auth (user, `password`) frappe.db.sql("""insert into __Auth (user, `password`)
values (%s, password(%s)) values (%s, password(%s))


+ 7
- 1
frappe/core/doctype/doctype/doctype.py Voir le fichier

@@ -129,10 +129,16 @@ class DocType:
self.doc.doctype, self.doc.name), scrub(self.doc.name) + '.py') self.doc.doctype, self.doc.name), scrub(self.doc.name) + '.py')


if not os.path.exists(pypath): 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(pypath, 'w') as pyfile:
with open(os.path.join(get_module_path("core"), "doctype", "doctype", with open(os.path.join(get_module_path("core"), "doctype", "doctype",
"doctype_template.py"), 'r') as srcfile: "doctype_template.py"), 'r') as srcfile:
pyfile.write(srcfile.read())
pyfile.write(srcfile.read().format(app_publisher=app_publisher))
def make_amendable(self): def make_amendable(self):
""" """


+ 2
- 2
frappe/core/doctype/doctype/doctype_template.py Voir le fichier

@@ -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 from __future__ import unicode_literals
import frappe import frappe


+ 35
- 0
frappe/exceptions.py Voir le fichier

@@ -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

+ 3
- 28
frappe/handler.py Voir le fichier

@@ -8,7 +8,7 @@ import frappe.utils
import frappe.sessions import frappe.sessions
import frappe.utils.file_manager import frappe.utils.file_manager
import frappe.widgets.form.run_method 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) @frappe.whitelist(allow_guest=True)
def startup(): def startup():
@@ -64,33 +64,9 @@ def handle():
cmd = frappe.local.form_dict.cmd cmd = frappe.local.form_dict.cmd
if cmd!='login': 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): def execute_cmd(cmd):
"""execute a request as python module""" """execute a request as python module"""
@@ -102,7 +78,6 @@ def execute_cmd(cmd):
raise frappe.PermissionError('Not Allowed, %s' % str(method)) raise frappe.PermissionError('Not Allowed, %s' % str(method))
else: else:
if not method in frappe.whitelisted: if not method in frappe.whitelisted:
frappe._response.status_code = 403
frappe.msgprint('Not Allowed, %s' % str(method)) frappe.msgprint('Not Allowed, %s' % str(method))
raise frappe.PermissionError('Not Allowed, %s' % str(method)) raise frappe.PermissionError('Not Allowed, %s' % str(method))


+ 1
- 1
frappe/hooks.txt Voir le fichier

@@ -1,6 +1,6 @@
app_name = frappe app_name = frappe
app_title = Frappe Framework 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_description = Full Stack Web Application Framwork in Python
app_icon = assets/frappe/images/frappe.svg app_icon = assets/frappe/images/frappe.svg
app_version = 4.0.0-wip app_version = 4.0.0-wip


+ 5
- 0
frappe/modules/patch_handler.py Voir le fichier

@@ -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', block and 'stop' or None)
frappe.db.set_global('__session_status_message', block and msg or None) frappe.db.set_global('__session_status_message', block and msg or None)
frappe.db.commit() 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(): def setup():
frappe.db.sql("""CREATE TABLE IF NOT EXISTS `__PatchLog` ( frappe.db.sql("""CREATE TABLE IF NOT EXISTS `__PatchLog` (


BIN
frappe/public/images/ui/field.jpg Voir le fichier

Avant Après
Largeur: 1600  |  Hauteur: 1066  |  Taille: 198 KiB

BIN
frappe/public/images/ui/random-polygons.jpg Voir le fichier

Avant Après
Largeur: 1920  |  Hauteur: 1600  |  Taille: 258 KiB

BIN
frappe/public/images/ui/wallpaper.jpg Voir le fichier

Avant Après
Largeur: 1920  |  Hauteur: 1200  |  Taille: 664 KiB

+ 3
- 3
frappe/public/js/frappe/misc/user.js Voir le fichier

@@ -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 { \ frappe.dom.set_style(repl('#page-desktop { \
background: url("%(src)s") center center fixed; \
background: url("%(src)s") center center; \
}', {src:src})) }', {src:src}))
} }




+ 1
- 4
frappe/sessions.py Voir le fichier

@@ -59,7 +59,7 @@ def clear_sessions(user=None, keep_current=False):
user = frappe.session.user user = frappe.session.user
for sid in frappe.db.sql("""select sid from tabSessions where user=%s""", (user,)): for sid in frappe.db.sql("""select sid from tabSessions where user=%s""", (user,)):
if keep_current and frappe.session.sid==sid[0]: if keep_current and frappe.session.sid==sid[0]:
pass
continue
else: else:
frappe.cache().delete_value("session:" + sid[0]) frappe.cache().delete_value("session:" + sid[0])
frappe.db.sql("""delete from tabSessions where sid=%s""", (sid[0],)) frappe.db.sql("""delete from tabSessions where sid=%s""", (sid[0],))
@@ -104,9 +104,6 @@ class Session:
# set local session # set local session
frappe.local.session = self.data frappe.local.session = self.data


# write out latest cookies
frappe.local.cookie_manager.set_cookies()

def start(self): def start(self):
"""start a new session""" """start a new session"""
# generate sid # generate sid


+ 5
- 1
frappe/templates/includes/login.js Voir le fichier

@@ -102,7 +102,11 @@ login.login_handlers = {
} }
}, },
401: function(xhr, data) { 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);
} }
} }




+ 1
- 1
frappe/templates/pages/login.py Voir le fichier

@@ -33,7 +33,7 @@ oauth2_providers = {
"redirect_uri": "/api/method/frappe.templates.pages.login.login_via_google", "redirect_uri": "/api/method/frappe.templates.pages.login.login_via_google",
"auth_url_data": { "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" "response_type": "code"
}, },


+ 88
- 68
frappe/utils/response.py Voir le fichier

@@ -12,6 +12,7 @@ from frappe import _
import frappe.utils import frappe.utils
import frappe.sessions import frappe.sessions
import frappe.model.utils import frappe.model.utils
import werkzeug.utils
from werkzeug.local import LocalProxy from werkzeug.local import LocalProxy
from werkzeug.wsgi import wrap_file from werkzeug.wsgi import wrap_file
from werkzeug.wrappers import Response from werkzeug.wrappers import Response
@@ -20,61 +21,49 @@ from werkzeug.exceptions import NotFound, Forbidden
def report_error(status_code): def report_error(status_code):
if status_code!=404 or frappe.conf.logging: if status_code!=404 or frappe.conf.logging:
frappe.errprint(frappe.utils.get_traceback()) 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 '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 = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: <a href="{location}">/</a>.
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" "text/csv; charset: utf-8"
frappe._response.headers["Content-Disposition"] = \
response.headers["Content-Disposition"] = \
"attachment; filename=%s.csv" % frappe.response['doctype'].replace(' ', '_') "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" 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(' ', '_') "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(): def make_logs():
"""make strings for msgprint and errprint""" """make strings for msgprint and errprint"""
if frappe.error_log: if frappe.error_log:
@@ -87,15 +76,31 @@ def make_logs():
if frappe.debug_log and frappe.conf.get("logging") or False: if frappe.debug_log and frappe.conf.get("logging") or False:
frappe.response['_debug_messages'] = json.dumps(frappe.local.debug_log) 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: 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): def json_handler(obj):
"""serialize non-serializable data for json""" """serialize non-serializable data for json"""
@@ -108,31 +113,30 @@ def json_handler(obj):
else: else:
raise TypeError, """Object of type %s with value of %s is not JSON serializable""" % \ raise TypeError, """Object of type %s with value of %s is not JSON serializable""" % \
(type(obj), repr(obj)) (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): def download_backup(path):
try: try:
frappe.only_for(("System Manager", "Administrator")) frappe.only_for(("System Manager", "Administrator"))
except frappe.PermissionError: except frappe.PermissionError:
raise Forbidden(_("You need to be logged in and have System Manager Role to be able to access backups.")) 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): def send_private_file(path):
path = os.path.join(frappe.local.conf.get('private_path', 'private'), path.strip("/")) path = os.path.join(frappe.local.conf.get('private_path', 'private'), path.strip("/"))


if frappe.local.request.headers.get('X-Use-X-Accel-Redirect'): if frappe.local.request.headers.get('X-Use-X-Accel-Redirect'):
path = '/' + path path = '/' + path
frappe.local._response.headers['X-Accel-Redirect'] = path
response = Response()
response.headers['X-Accel-Redirect'] = path
else: else:
filename = os.path.basename(path) filename = os.path.basename(path)
filepath = frappe.utils.get_site_path(path) filepath = frappe.utils.get_site_path(path)
@@ -140,6 +144,22 @@ def send_private_file(path):
f = open(filepath, 'rb') f = open(filepath, 'rb')
except IOError: except IOError:
raise NotFound 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("""<html>
<body style="background-color: #EEE;">
<h3 style="width: 900px; background-color: #FFF; border: 2px solid #AAA; padding: 20px; font-family: Arial; margin: 20px auto">
Updating.
We will be back in a few moments...
</h3>
</body>
</html>""")
response.status_code = 503
response.content_type = 'text/html'
return res

+ 15
- 14
frappe/website/render.py Voir le fichier

@@ -4,17 +4,18 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
import mimetypes, json import mimetypes, json
from werkzeug.wrappers import Response


from frappe.website.context import get_context from frappe.website.context import get_context
from frappe.website.utils import scrub_relative_urls, get_home_page, can_cache from frappe.website.utils import scrub_relative_urls, get_home_page, can_cache

from frappe.website.permissions import get_access, clear_permissions from frappe.website.permissions import get_access, clear_permissions


class PageNotFoundError(Exception): pass class PageNotFoundError(Exception): pass


def render(path): def render(path):
"""render html page""" """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: try:
data = render_page(path) data = render_page(path)
@@ -22,9 +23,12 @@ def render(path):
path = "error" path = "error"
data = render_page(path) 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): def render_page(path):
"""get page html""" """get page html"""
@@ -39,9 +43,7 @@ def render_page(path):
out = out.get("data") out = out.get("data")
if out: if out:
if hasattr(frappe, "_response"):
frappe._response.headers[b"X-From-Cache"] = True
frappe.local.response.from_cache = True
return out return out
return build(path) return build(path)
@@ -75,8 +77,7 @@ def build_page(path):
return html return html
def is_ajax(): 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): def resolve_path(path):
if not path: if not path:
@@ -90,17 +91,17 @@ def resolve_path(path):
return path return path


def set_content_type(data, path):
def set_content_type(response, data, path):
if isinstance(data, dict): 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) data = json.dumps(data)
return 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"): if "." in path and not path.endswith(".html"):
content_type, encoding = mimetypes.guess_type(path) 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 return data




Chargement…
Annuler
Enregistrer