@@ -13,7 +13,7 @@ import os, sys, importlib, inspect, json | |||||
from .exceptions import * | from .exceptions import * | ||||
from .utils.jinja import get_jenv, get_template, render_template | from .utils.jinja import get_jenv, get_template, render_template | ||||
__version__ = '7.1.10' | |||||
__version__ = '7.1.11' | |||||
__title__ = "Frappe Framework" | __title__ = "Frappe Framework" | ||||
local = Local() | local = Local() | ||||
@@ -10,7 +10,6 @@ from frappe.utils.response import build_response | |||||
from frappe import _ | from frappe import _ | ||||
from urlparse import urlparse | from urlparse import urlparse | ||||
from urllib import urlencode | from urllib import urlencode | ||||
from frappe.integration_broker.oauth2 import oauth_server | |||||
def handle(): | def handle(): | ||||
""" | """ | ||||
@@ -36,25 +35,7 @@ def handle(): | |||||
`/api/resource/{doctype}/{name}?run_method={method}` will run a whitelisted controller method | `/api/resource/{doctype}/{name}?run_method={method}` will run a whitelisted controller method | ||||
""" | """ | ||||
form_dict = frappe.local.form_dict | |||||
authorization_header = frappe.get_request_header("Authorization").split(" ") if frappe.get_request_header("Authorization") else None | |||||
if authorization_header and authorization_header[0].lower() == "bearer": | |||||
token = authorization_header[1] | |||||
r = frappe.request | |||||
parsed_url = urlparse(r.url) | |||||
access_token = { "access_token": token} | |||||
uri = parsed_url.scheme + "://" + parsed_url.netloc + parsed_url.path + "?" + urlencode(access_token) | |||||
http_method = r.method | |||||
body = r.get_data() | |||||
headers = r.headers | |||||
required_scopes = frappe.db.get_value("OAuth Bearer Token", token, "scopes").split(";") | |||||
valid, oauthlib_request = oauth_server.verify_request(uri, http_method, body, headers, required_scopes) | |||||
if valid: | |||||
frappe.set_user(frappe.db.get_value("OAuth Bearer Token", token, "user")) | |||||
frappe.local.form_dict = form_dict | |||||
validate_oauth() | |||||
parts = frappe.request.path[1:].split("/",3) | parts = frappe.request.path[1:].split("/",3) | ||||
call = doctype = name = None | call = doctype = name = None | ||||
@@ -146,3 +127,25 @@ def handle(): | |||||
raise frappe.DoesNotExistError | raise frappe.DoesNotExistError | ||||
return build_response("json") | return build_response("json") | ||||
def validate_oauth(): | |||||
form_dict = frappe.local.form_dict | |||||
authorization_header = frappe.get_request_header("Authorization").split(" ") if frappe.get_request_header("Authorization") else None | |||||
if authorization_header and authorization_header[0].lower() == "bearer": | |||||
from frappe.integration_broker.oauth2 import get_oauth_server | |||||
token = authorization_header[1] | |||||
r = frappe.request | |||||
parsed_url = urlparse(r.url) | |||||
access_token = { "access_token": token} | |||||
uri = parsed_url.scheme + "://" + parsed_url.netloc + parsed_url.path + "?" + urlencode(access_token) | |||||
http_method = r.method | |||||
body = r.get_data() | |||||
headers = r.headers | |||||
required_scopes = frappe.db.get_value("OAuth Bearer Token", token, "scopes").split(";") | |||||
valid, oauthlib_request = get_oauth_server().verify_request(uri, http_method, body, headers, required_scopes) | |||||
if valid: | |||||
frappe.set_user(frappe.db.get_value("OAuth Bearer Token", token, "user")) | |||||
frappe.local.form_dict = form_dict |
@@ -57,7 +57,14 @@ class Report(Document): | |||||
if self.report_type in ('Query Report', 'Script Report'): | if self.report_type in ('Query Report', 'Script Report'): | ||||
# query and script reports | # query and script reports | ||||
data = frappe.desk.query_report.run(self.name, filters=filters, user=user) | data = frappe.desk.query_report.run(self.name, filters=filters, user=user) | ||||
out.append([d.split(':')[0] for d in data.get('columns')]) | |||||
columns_list = [] | |||||
for d in data.get('columns'): | |||||
if isinstance(d, dict): | |||||
columns_list.append(d.get('label')) | |||||
else: | |||||
columns_list.append(d.split(':')[0]) | |||||
out.append(columns_list) | |||||
out += data.get('result') | out += data.get('result') | ||||
else: | else: | ||||
# standard report | # standard report | ||||
@@ -60,9 +60,19 @@ frappe.ui.form.on('Auto Email Report', { | |||||
<tr><th style="width: 50%">'+__('Filter')+'</th><th>'+__('Value')+'</th></tr>\ | <tr><th style="width: 50%">'+__('Filter')+'</th><th>'+__('Value')+'</th></tr>\ | ||||
</thead><tbody></tbody></table>').appendTo(wrapper); | </thead><tbody></tbody></table>').appendTo(wrapper); | ||||
$('<p class="text-muted small">' + __("Click table to edit") + '</p>').appendTo(wrapper); | $('<p class="text-muted small">' + __("Click table to edit") + '</p>').appendTo(wrapper); | ||||
var filters = JSON.parse(frm.doc.filters || '{}'); | var filters = JSON.parse(frm.doc.filters || '{}'); | ||||
var report_filters = frappe.query_reports[frm.doc.report].filters; | var report_filters = frappe.query_reports[frm.doc.report].filters; | ||||
report_filters_list = [] | |||||
$.each(report_filters, function(key, val){ | |||||
// Remove break fieldtype from the filters | |||||
if(val.fieldtype != 'Break') { | |||||
report_filters_list.push(val) | |||||
} | |||||
}) | |||||
report_filters = report_filters_list; | |||||
report_filters.forEach(function(f) { | report_filters.forEach(function(f) { | ||||
$('<tr><td>' + f.label + '</td><td>'+ frappe.format(filters[f.fieldname], f) +'</td></tr>') | $('<tr><td>' + f.label + '</td><td>'+ frappe.format(filters[f.fieldname], f) +'</td></tr>') | ||||
.appendTo(table.find('tbody')); | .appendTo(table.find('tbody')); | ||||
@@ -6,10 +6,12 @@ from urllib import quote, urlencode | |||||
from urlparse import urlparse | from urlparse import urlparse | ||||
from frappe.integrations.doctype.oauth_provider_settings.oauth_provider_settings import get_oauth_settings | from frappe.integrations.doctype.oauth_provider_settings.oauth_provider_settings import get_oauth_settings | ||||
#Variables required across requests | |||||
oauth_validator = OAuthWebRequestValidator() | |||||
oauth_server = WebApplicationServer(oauth_validator) | |||||
credentials = None | |||||
def get_oauth_server(): | |||||
if not getattr(frappe.local, 'oauth_server', None): | |||||
oauth_validator = OAuthWebRequestValidator() | |||||
frappe.local.oauth_server = WebApplicationServer(oauth_validator) | |||||
return frappe.local.oauth_server | |||||
def get_urlparams_from_kwargs(param_kwargs): | def get_urlparams_from_kwargs(param_kwargs): | ||||
arguments = param_kwargs | arguments = param_kwargs | ||||
@@ -29,10 +31,10 @@ def approve(*args, **kwargs): | |||||
headers = r.headers | headers = r.headers | ||||
try: | try: | ||||
scopes, credentials = oauth_server.validate_authorization_request(uri, http_method, body, headers) | |||||
scopes, frappe.flags.oauth_credentials = get_oauth_server().validate_authorization_request(uri, http_method, body, headers) | |||||
headers, body, status = oauth_server.create_authorization_response(uri=credentials['redirect_uri'], \ | |||||
body=body, headers=headers, scopes=scopes, credentials=credentials) | |||||
headers, body, status = get_oauth_server().create_authorization_response(uri=frappe.flags.oauth_credentials['redirect_uri'], \ | |||||
body=body, headers=headers, scopes=scopes, credentials=frappe.flags.oauth_credentials) | |||||
uri = headers.get('Location', None) | uri = headers.get('Location', None) | ||||
frappe.local.response["type"] = "redirect" | frappe.local.response["type"] = "redirect" | ||||
@@ -50,7 +52,7 @@ def authorize(*args, **kwargs): | |||||
params = get_urlparams_from_kwargs(kwargs) | params = get_urlparams_from_kwargs(kwargs) | ||||
request_url = urlparse(frappe.request.url) | request_url = urlparse(frappe.request.url) | ||||
success_url = request_url.scheme + "://" + request_url.netloc + "/api/method/frappe.integration_broker.oauth2.approve?" + params | success_url = request_url.scheme + "://" + request_url.netloc + "/api/method/frappe.integration_broker.oauth2.approve?" + params | ||||
failure_url = frappe.form_dict["redirect_uri"] + "?error=access_denied" | |||||
failure_url = frappe.form_dict["redirect_uri"] + "?error=access_denied" | |||||
if frappe.session['user']=='Guest': | if frappe.session['user']=='Guest': | ||||
#Force login, redirect to preauth again. | #Force login, redirect to preauth again. | ||||
@@ -65,9 +67,9 @@ def authorize(*args, **kwargs): | |||||
body = r.get_data() | body = r.get_data() | ||||
headers = r.headers | headers = r.headers | ||||
scopes, credentials = oauth_server.validate_authorization_request(uri, http_method, body, headers) | |||||
scopes, frappe.flags.oauth_credentials = get_oauth_server().validate_authorization_request(uri, http_method, body, headers) | |||||
skip_auth = frappe.db.get_value("OAuth Client", credentials['client_id'], "skip_authorization") | |||||
skip_auth = frappe.db.get_value("OAuth Client", frappe.flags.oauth_credentials['client_id'], "skip_authorization") | |||||
unrevoked_tokens = frappe.get_all("OAuth Bearer Token", filters={"status":"Active"}) | unrevoked_tokens = frappe.get_all("OAuth Bearer Token", filters={"status":"Active"}) | ||||
if skip_auth or (oauth_settings["skip_authorization"] == "Auto" and len(unrevoked_tokens)): | if skip_auth or (oauth_settings["skip_authorization"] == "Auto" and len(unrevoked_tokens)): | ||||
@@ -100,7 +102,7 @@ def get_token(*args, **kwargs): | |||||
headers = r.headers | headers = r.headers | ||||
try: | try: | ||||
headers, body, status = oauth_server.create_token_response(uri, http_method, body, headers, credentials) | |||||
headers, body, status = get_oauth_server().create_token_response(uri, http_method, body, headers, frappe.flags.oauth_credentials) | |||||
frappe.local.response = frappe._dict(json.loads(body)) | frappe.local.response = frappe._dict(json.loads(body)) | ||||
except FatalClientError as e: | except FatalClientError as e: | ||||
return e | return e | ||||
@@ -113,9 +115,9 @@ def revoke_token(*args, **kwargs): | |||||
http_method = r.method | http_method = r.method | ||||
body = r.form | body = r.form | ||||
headers = r.headers | headers = r.headers | ||||
headers, body, status = oauth_server.create_revocation_response(uri, headers=headers, body=body, http_method=http_method) | |||||
headers, body, status = get_oauth_server().create_revocation_response(uri, headers=headers, body=body, http_method=http_method) | |||||
frappe.local.response['http_status_code'] = status | frappe.local.response['http_status_code'] = status | ||||
if status == 200: | if status == 200: | ||||
return "success" | return "success" | ||||
@@ -355,7 +355,7 @@ fieldset[disabled] .form-control { | |||||
} | } | ||||
/* jquery ui */ | /* jquery ui */ | ||||
.ui-datepicker { | .ui-datepicker { | ||||
z-index: 100 !important; | |||||
z-index: 9999 !important; | |||||
} | } | ||||
.ui-datepicker .ui-datepicker-header { | .ui-datepicker .ui-datepicker-header { | ||||
border-radius: 0px !important; | border-radius: 0px !important; | ||||
@@ -781,13 +781,19 @@ frappe.views.DocListView = frappe.ui.Listing.extend({ | |||||
toggle_delete: function() { | toggle_delete: function() { | ||||
var me = this; | var me = this; | ||||
if (this.$page.find(".list-delete:checked").length) { | |||||
var no_of_checked_items = this.$page.find(".list-delete:checked").length; | |||||
if (no_of_checked_items) { | |||||
this.page.set_primary_action(__("Delete"), function() { me.delete_items() }, | this.page.set_primary_action(__("Delete"), function() { me.delete_items() }, | ||||
"octicon octicon-trashcan"); | "octicon octicon-trashcan"); | ||||
this.page.btn_primary.addClass("btn-danger"); | this.page.btn_primary.addClass("btn-danger"); | ||||
this.page.checked_items_status.text(no_of_checked_items == 1 | |||||
? __("1 item selected") | |||||
: __("{0} items selected", [no_of_checked_items])) | |||||
this.page.checked_items_status.removeClass("hide"); | |||||
} else { | } else { | ||||
this.page.btn_primary.removeClass("btn-danger"); | this.page.btn_primary.removeClass("btn-danger"); | ||||
this.set_primary_action(); | this.set_primary_action(); | ||||
this.page.checked_items_status.addClass("hide"); | |||||
} | } | ||||
}, | }, | ||||
@@ -12,6 +12,7 @@ | |||||
</div> | </div> | ||||
<div class="text-right col-md-5 col-sm-4 col-xs-6 page-actions"> | <div class="text-right col-md-5 col-sm-4 col-xs-6 page-actions"> | ||||
<!-- ID and icon buttons --> | <!-- ID and icon buttons --> | ||||
<span class="checked-items-status text-ellipsis text-muted small hide hidden-xs hidden-sm" style="margin-right: 20px;">## items selected</span> | |||||
<h6 class="text-ellipsis sub-heading hide text-muted"></h6> | <h6 class="text-ellipsis sub-heading hide text-muted"></h6> | ||||
<span class="page-icon-group hide hidden-xs hidden-sm"></span> | <span class="page-icon-group hide hidden-xs hidden-sm"></span> | ||||
@@ -80,6 +80,7 @@ frappe.ui.Page = Class.extend({ | |||||
this.page_actions = this.wrapper.find(".page-actions"); | this.page_actions = this.wrapper.find(".page-actions"); | ||||
this.checked_items_status = this.page_actions.find(".checked-items-status"); | |||||
this.btn_primary = this.page_actions.find(".primary-action"); | this.btn_primary = this.page_actions.find(".primary-action"); | ||||
this.btn_secondary = this.page_actions.find(".btn-secondary"); | this.btn_secondary = this.page_actions.find(".btn-secondary"); | ||||
@@ -146,7 +146,7 @@ textarea.form-control { | |||||
/* jquery ui */ | /* jquery ui */ | ||||
.ui-datepicker { | .ui-datepicker { | ||||
z-index: 100 !important; | |||||
z-index: 9999 !important; | |||||
} | } | ||||
.ui-datepicker .ui-datepicker-header { | .ui-datepicker .ui-datepicker-header { | ||||