瀏覽代碼

[fix] refactor integration services (#2087)

* [fix] refactor integration services

* [fix] patch fix

* [fix] added redirect url.

* [fix] custom redirect to and reditect message for paypal and service setup information

* [minor][fix] remove ldap dependancy from requirements
version-14
Saurabh 8 年之前
committed by Rushabh Mehta
父節點
當前提交
205ae26751
共有 31 個檔案被更改,包括 1433 行新增763 行删除
  1. +2
    -3
      frappe/config/setup.py
  2. +1
    -1
      frappe/hooks.py
  3. +28
    -104
      frappe/integration_broker/doctype/integration_service/integration_service.js
  4. +4
    -132
      frappe/integration_broker/doctype/integration_service/integration_service.json
  5. +12
    -65
      frappe/integration_broker/doctype/integration_service/integration_service.py
  6. +0
    -0
      frappe/integrations/doctype/dropbox_settings/__init__.py
  7. +64
    -0
      frappe/integrations/doctype/dropbox_settings/dropbox_settings.js
  8. +241
    -0
      frappe/integrations/doctype/dropbox_settings/dropbox_settings.json
  9. +88
    -97
      frappe/integrations/doctype/dropbox_settings/dropbox_settings.py
  10. +12
    -0
      frappe/integrations/doctype/dropbox_settings/test_dropbox_settings.py
  11. +0
    -0
      frappe/integrations/doctype/ldap_settings/__init__.py
  12. +31
    -0
      frappe/integrations/doctype/ldap_settings/ldap_settings.js
  13. +162
    -0
      frappe/integrations/doctype/ldap_settings/ldap_settings.json
  14. +168
    -0
      frappe/integrations/doctype/ldap_settings/ldap_settings.py
  15. +0
    -0
      frappe/integrations/doctype/paypal_settings/__init__.py
  16. +31
    -0
      frappe/integrations/doctype/paypal_settings/paypal_settings.js
  17. +190
    -0
      frappe/integrations/doctype/paypal_settings/paypal_settings.json
  18. +98
    -76
      frappe/integrations/doctype/paypal_settings/paypal_settings.py
  19. +0
    -0
      frappe/integrations/doctype/razorpay_settings/__init__.py
  20. +33
    -0
      frappe/integrations/doctype/razorpay_settings/razorpay_settings.js
  21. +137
    -0
      frappe/integrations/doctype/razorpay_settings/razorpay_settings.json
  22. +73
    -56
      frappe/integrations/doctype/razorpay_settings/razorpay_settings.py
  23. +0
    -139
      frappe/integrations/ldap_auth.py
  24. +1
    -0
      frappe/patches.txt
  25. +52
    -0
      frappe/patches/v7_1/refactor_integration_broker.py
  26. +0
    -48
      frappe/public/js/integrations/dropbox_integration.js
  27. +0
    -15
      frappe/public/js/integrations/ldap_auth.js
  28. +0
    -21
      frappe/public/js/integrations/paypal.js
  29. +4
    -4
      frappe/templates/pages/integrations/razorpay_checkout.py
  30. +1
    -1
      frappe/www/login.py
  31. +0
    -1
      requirements.txt

+ 2
- 3
frappe/config/setup.py 查看文件

@@ -222,9 +222,8 @@ def get_data():
}, },
{ {
"type": "doctype", "type": "doctype",
"name": "Dropbox Backup",
"description": _("Manage cloud backups on Dropbox"),
"hide_count": True
"name": "Integration Service",
"description": _("Centralize access to Integrations"),
} }
] ]
}, },


+ 1
- 1
frappe/hooks.py 查看文件

@@ -176,4 +176,4 @@ bot_parsers = [
setup_wizard_exception = "frappe.desk.page.setup_wizard.setup_wizard.email_setup_wizard_exception" setup_wizard_exception = "frappe.desk.page.setup_wizard.setup_wizard.email_setup_wizard_exception"
before_write_file = "frappe.limits.validate_space_limit" before_write_file = "frappe.limits.validate_space_limit"


integration_services = ["PayPal", "Razorpay", "Dropbox Integration", "LDAP Auth"]
integration_services = ["PayPal", "Razorpay", "Dropbox", "LDAP"]

+ 28
- 104
frappe/integration_broker/doctype/integration_service/integration_service.js 查看文件

@@ -1,6 +1,13 @@
// Copyright (c) 2016, Frappe Technologies and contributors // Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt // For license information, please see license.txt


frappe.provide("frappe.integration_service");

{% include 'frappe/integrations/doctype/razorpay_settings/razorpay_settings.js' %}
{% include 'frappe/integrations/doctype/paypal_settings/paypal_settings.js' %}
{% include 'frappe/integrations/doctype/dropbox_settings/dropbox_settings.js' %}
{% include 'frappe/integrations/doctype/ldap_settings/ldap_settings.js' %}

frappe.ui.form.on('Integration Service', { frappe.ui.form.on('Integration Service', {
onload: function(frm) { onload: function(frm) {
frappe.call({ frappe.call({
@@ -13,119 +20,36 @@ frappe.ui.form.on('Integration Service', {


refresh: function(frm){ refresh: function(frm){
if (frm.doc.service){ if (frm.doc.service){
frm.events.load_js_resouce(frm);
frm.events.setup_custom_buttons(frm);
frm.events.setup_service_details(frm);
} }
}, },

load_js_resouce: function(frm){
frappe.call({
method: 'frappe.integration_broker.doctype.integration_service.integration_service.get_js_resouce',
args: {
'service': frm.doc.service
},
callback: function(r) {
$(frm.fields_dict.custom_settings.wrapper).empty();

if (r.message.js){
frm.clear_custom_buttons();
frappe.require(r.message.js, function(){
service_name = frm.doc.service.toLowerCase().replace(/ /g, "_");
frappe.integration_service[service_name].load(frm);

$(frm.fields_dict.scheduler_events_html.wrapper).empty();

if (frappe.integration_service[service_name].scheduler_job_helper) {
frm.scheduler_helper = frappe.integration_service[service_name].scheduler_job_helper();
frm.events.render_scheduler_jobs(frm);
}
})
}

frm.events.load_parameters(frm);
}
})
},
load_parameters: function(frm) {
var form = frm;

frappe.call({
method: 'frappe.integration_broker.doctype.integration_service.integration_service.get_service_parameters',
args: {
'service': frm.doc.service
},
callback: function(r) {
frm.fields = r.message.parameters;
frm.scheduler_jobs = r.message.scheduled_jobs;
frm.events.show_properties(frm);
}
setup_custom_buttons: function(frm) {
frm.add_custom_button(__("{0} Settings", [frm.doc.service]), function(){
frappe.set_route("List", frm.doc.service + " Settings");
}); });
},
edit_settings: function(frm) {
frm.events.setup_dialog(frm);
},

setup_dialog: function(frm){
var d = new frappe.ui.Dialog({
title:__('Custom Settings'),
fields: frm.fields
frm.add_custom_button(__("Show Log"), function(){
frappe.route_options = {"integration_request_service": frm.doc.service};
frappe.set_route("List", "Integration Request");
}); });

// set_value
if(frm.doc.custom_settings_json){
d.set_values(JSON.parse(frm.doc.custom_settings_json));
}

d.set_primary_action(__("Set"), function() {
var btn = this;
var v = d.get_values();
if(!v) return;

frm.set_value("custom_settings_json", JSON.stringify(v));
frm.refresh_field("custom_settings_json");
d.hide();
frm.events.show_properties(frm);
})

d.show();
}, },
show_properties:function(frm){
var frm = frm;
var table_wrapper = frm.fields_dict.custom_settings.wrapper;
frm.settings = frm.doc.custom_settings_json ? JSON.parse(frm.doc.custom_settings_json) : {};
setup_service_details: function(frm) {
var service_name = frm.doc.service.toLowerCase().replace(/ /g, "_");
var service_handelr = service_name + "_settings";
service_handelr = new frappe.integration_service[service_handelr]();
service_handelr.get_service_info(frm);
$(table_wrapper).empty();
$(table_wrapper).append('\
<table class="table table-bordered" style="cursor: pointer;">\
<thead>\
<tr>\
<th class="text-muted"> Parameter </th>\
<th class="text-muted"> Value </th>\
</tr>\
</thead> \
<tbody></tbody> \
</table>')

frm.fields.forEach(function(d){
var df = d;
$row = $("<tr>").appendTo($(table_wrapper).find("tbody"));
$("<td>").appendTo($row).html(__(d.label)).css("font-size", "12px");
pwd_length = frm.settings[d.fieldname] ? frm.settings[d.fieldname].length : 0
value = (d.fieldtype == "Password") ? "*".repeat(pwd_length) : frm.settings[d.fieldname];
$("<td>").appendTo($row).html(value).css("font-size", "12px");
});
var scheduler_job_info = service_handelr.get_scheduler_job_info();
frm.events.render_scheduler_jobs(frm, scheduler_job_info);
$(table_wrapper).find(".table-bordered").click(function(){
frm.events.setup_dialog(frm);
})
}, },
render_scheduler_jobs: function(frm) {
render_scheduler_jobs: function(frm, scheduler_job_info) {
var schduler_job_view = frm.fields_dict.scheduler_events_html.wrapper; var schduler_job_view = frm.fields_dict.scheduler_events_html.wrapper;

$(schduler_job_view).empty(); $(schduler_job_view).empty();
$(schduler_job_view).append('\ $(schduler_job_view).append('\
<table class="table table-bordered">\ <table class="table table-bordered">\
@@ -137,8 +61,8 @@ frappe.ui.form.on('Integration Service', {
</thead> \ </thead> \
<tbody></tbody> \ <tbody></tbody> \
</table>') </table>')
$.each(frm.scheduler_helper, function(evnt, help){
$.each(scheduler_job_info, function(evnt, help){
$row = $("<tr>").appendTo($(schduler_job_view).find("tbody")); $row = $("<tr>").appendTo($(schduler_job_view).find("tbody"));
$("<td>").appendTo($row).html(evnt).css("font-size", "12px"); $("<td>").appendTo($row).html(evnt).css("font-size", "12px");
$("<td>").appendTo($row).html(help).css("font-size", "12px"); $("<td>").appendTo($row).html(help).css("font-size", "12px");


+ 4
- 132
frappe/integration_broker/doctype/integration_service/integration_service.json 查看文件

@@ -70,34 +70,8 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "use_test_account",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Use Test Account",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_4",
"fieldtype": "Column Break",
"fieldname": "section_break_3",
"fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@@ -143,109 +117,6 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "custom_settings",
"fieldtype": "HTML",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "edit_settings",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Edit Settings",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "custom_settings_json",
"fieldtype": "Code",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@@ -308,7 +179,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2016-09-24 05:48:04.652766",
"modified": "2016-10-06 06:14:48.271314",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Integration Broker", "module": "Integration Broker",
"name": "Integration Service", "name": "Integration Service",
@@ -325,6 +196,7 @@
"export": 1, "export": 1,
"if_owner": 0, "if_owner": 0,
"import": 0, "import": 0,
"is_custom": 0,
"permlevel": 0, "permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,


+ 12
- 65
frappe/integration_broker/doctype/integration_service/integration_service.py 查看文件

@@ -13,35 +13,16 @@ from frappe.utils import get_request_session
class IntegrationService(Document): class IntegrationService(Document):
def on_update(self): def on_update(self):
if self.enabled: if self.enabled:
self.enable_service()
self.install_fixtures()

def get_controller(self):
if not getattr(self, '_controller', None):
self._controller = get_integration_controller(self.service, setup=False)
return self._controller

def get_parameters(self):
parameters = {}
if self.custom_settings_json:
parameters = json.loads(self.custom_settings_json)
return parameters
if not self.flags.ignore_mandatory:
self.enable_service()
self.install_fixtures()


def install_fixtures(self): def install_fixtures(self):
pass pass


def enable_service(self): def enable_service(self):
if not self.flags.ignore_mandatory:
self.get_controller().enable(self.get_parameters(), self.use_test_account)

def setup_events_and_parameters(self):
self.parameters = []
for d in self.get_controller().parameters_template:
self.parameters.append({'label': d.label, "value": d.value})

self.events = []
for d in self.get_controller()._events:
self.parameters.append({'event': d.event, 'enabled': d.enabled})
service_doc = "{0} Settings".format(self.service)
frappe.get_doc(service_doc).enable()


#rest request handler #rest request handler
def get_request(self, url, auth=None, data=None): def get_request(self, url, auth=None, data=None):
@@ -99,46 +80,12 @@ class IntegrationService(Document):


return integration_request return integration_request


@frappe.whitelist()
def get_service_parameters(service):
controller = get_integration_controller(service, setup=False)
return {
'parameters': controller.parameters_template,
}

@frappe.whitelist()
def get_js_resouce(service):
controller = get_integration_controller(service, setup=False)
return {
"js": getattr(controller, "js", "")
}

def get_integration_controller(service_name, setup=True):
def get_integration_controller(service_name):
'''Returns integration controller module from app_name.integrations.{service}''' '''Returns integration controller module from app_name.integrations.{service}'''
def load_from_app(app, service_name):
try:
controller_module = frappe.get_module("{app}.integrations.{service}"
.format(app=app, service=service_name.strip().lower().replace(' ','_')))
controller = controller_module.Controller(setup=setup)

# make default properites and frappe._dictify
for key in ('events', 'parameters_template'):
tmp = []
for d in getattr(controller, key, []):
tmp.append(frappe._dict(d))
setattr(controller, key, tmp)

return controller

except ImportError:
pass

for app in frappe.get_installed_apps():
controller = load_from_app(app, service_name)
if controller:
return controller

frappe.throw(_("Module {service} not found".format(service=service_name)))
try:
return frappe.get_doc("{0} Settings".format(service_name))
except Exception:
frappe.throw(_("Module {service} not found".format(service=service_name)))


@frappe.whitelist() @frappe.whitelist()
def get_integration_services(): def get_integration_services():
@@ -150,11 +97,11 @@ def get_integration_services():


def trigger_integration_service_events(): def trigger_integration_service_events():
for service in frappe.get_all("Integration Service", filters={"enabled": 1}, fields=["name"]): for service in frappe.get_all("Integration Service", filters={"enabled": 1}, fields=["name"]):
controller = get_integration_controller(service.name, setup=False)
controller = get_integration_controller(service.name)


if hasattr(controller, "scheduled_jobs"): if hasattr(controller, "scheduled_jobs"):
for job in controller.scheduled_jobs: for job in controller.scheduled_jobs:
for event, handlers in job.items(): for event, handlers in job.items():
for handler in handlers: for handler in handlers:
if handler not in get_jobs(): if handler not in get_jobs():
enqueue(handler, queue='short', event=event)
enqueue(handler, queue='short', event=event)

+ 0
- 0
frappe/integrations/doctype/dropbox_settings/__init__.py 查看文件


+ 64
- 0
frappe/integrations/doctype/dropbox_settings/dropbox_settings.js 查看文件

@@ -0,0 +1,64 @@
// Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.provide("frappe.integration_service")

frappe.ui.form.on('Dropbox Settings', {
refresh: function(frm) {
frm.clear_custom_buttons();
frm.events.take_backup(frm);
},
allow_dropbox_access: function(frm) {
if (frm.doc.app_access_key && frm.doc.app_secret_key) {
frappe.call({
method: "frappe.integrations.doctype.dropbox_settings.dropbox_settings.get_dropbox_authorize_url",
freeze: true,
callback: function(r) {
if(!r.exc) {
frm.save();
window.open(r.message.url);
}
}
})
}
else {
frappe.msgprint(__("Please enter values for App Access Key and App Secret Key"))
}
},

take_backup: function(frm) {
if (frm.doc.app_access_key && frm.doc.app_secret_key && frm.doc.dropbox_access_key && frm.doc.dropbox_access_secret) {
frm.add_custom_button(__("Take Backup Now"), function(frm){
frappe.call({
method: "frappe.integrations.dropbox_integration.take_backup",
freeze: true
})
}).addClass("btn-primary")
}
}
});

frappe.integration_service.dropbox_settings = Class.extend({
init: function(frm) {
},
get_scheduler_job_info: function() {
return {
"Daily": "Take backup of database and files to dropbox on daily basis",
"Weekly": "Take backup of database and files to dropbox on weekly basis"
}
},
get_service_info: function(frm) {
frappe.call({
method: "frappe.integrations.doctype.dropbox_settings.dropbox_settings.get_service_details",
callback: function(r){
var integration_service_help = frm.fields_dict.integration_service_help.wrapper;
$(integration_service_help).empty();
$(integration_service_help).append(r.message);
}
})
}
})

+ 241
- 0
frappe/integrations/doctype/dropbox_settings/dropbox_settings.json 查看文件

@@ -0,0 +1,241 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2016-09-21 10:12:57.399174",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "System",
"editable_grid": 1,
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "send_notifications_to",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Send Notifications To",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "backup_frequency",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Backup Frequency",
"length": 0,
"no_copy": 0,
"options": "\nDaily\nWeekly",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "app_access_key",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "App Access Key",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "app_secret_key",
"fieldtype": "Password",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "App Secret Key",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allow_dropbox_access",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Allow Dropbox Access",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "dropbox_access_key",
"fieldtype": "Password",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Dropbox Access Key",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "dropbox_access_secret",
"fieldtype": "Password",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Dropbox Access Secret",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 1,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2016-09-22 03:55:40.716643",
"modified_by": "Administrator",
"module": "Integrations",
"name": "Dropbox Settings",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 1,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
}

frappe/integrations/dropbox_integration.py → frappe/integrations/doctype/dropbox_settings/dropbox_settings.py 查看文件

@@ -1,58 +1,20 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
import frappe import frappe
import os
from frappe import _ from frappe import _
from frappe.integration_broker.integration_controller import IntegrationController
from frappe.utils import (cint, split_emails, get_request_site_address, cstr,
get_files_path, get_backups_path, encode)
import os, json
from frappe.utils.backups import new_backup from frappe.utils.backups import new_backup
from frappe.utils.background_jobs import enqueue from frappe.utils.background_jobs import enqueue
from frappe.utils import (cint, split_emails, get_request_site_address, cstr,
get_files_path, get_backups_path, encode)
from frappe.integration_broker.doctype.integration_service.integration_service import IntegrationService


ignore_list = [".DS_Store"] ignore_list = [".DS_Store"]


class Controller(IntegrationController):
service_name = 'Dropbox Integration'
parameters_template = [
{
"label": "App Access Key",
'fieldname': 'app_access_key',
'reqd': 1,
'default': '',
'fieldtype': "Data"
},
{
"label": "App Secret Key",
'fieldname': 'app_secret_key',
'reqd': 1,
'default': '',
'fieldtype': "Password"
},
{
"label": "Dropbox Access Key",
'fieldname': 'dropbox_access_key',
'reqd': 1,
'default': '****',
'fieldtype': "Password"
},
{
"label": "Dropbox Secret Key",
'fieldname': 'dropbox_access_secret',
'reqd': 1,
'default': '****',
'fieldtype': "Password"
},
{
"label": "Backup Frequency",
"fieldname": "backup_frequency",
"options": "\nDaily\nWeekly",
"default": "",
"reqd": 1,
"fieldtype":'Select'
}
]

js = "assets/frappe/js/integrations/dropbox_integration.js"

# do also changes in dropbox_integration.js scheduler job helper
class DropboxSettings(IntegrationService):
scheduled_jobs = [ scheduled_jobs = [
{ {
"daily_long": [ "daily_long": [
@@ -64,10 +26,17 @@ class Controller(IntegrationController):
} }
] ]
def enable(self, parameters, use_test_account=0):
def validate(self):
if not self.flags.ignore_mandatory:
self.validate_dropbox_credentails()

def on_update(self):
pass

def enable(self):
""" enable service """ """ enable service """
self.parameters = parameters
self.validate_dropbox_credentails()
if not self.flags.ignore_mandatory:
self.validate_dropbox_credentails()


def validate_dropbox_credentails(self): def validate_dropbox_credentails(self):
try: try:
@@ -80,30 +49,71 @@ class Controller(IntegrationController):
from dropbox import session from dropbox import session
except: except:
raise Exception(_("Please install dropbox python module")) raise Exception(_("Please install dropbox python module"))
parameters = frappe._dict(self.parameters)
if not (parameters["app_access_key"] or parameters["app_secret_key"]):
if not (self.app_access_key or self.app_secret_key):
raise Exception(_("Please set Dropbox access keys in your site config")) raise Exception(_("Please set Dropbox access keys in your site config"))

sess = session.DropboxSession(parameters["app_access_key"], parameters["app_secret_key"], "app_folder")
sess = session.DropboxSession(self.app_access_key,
self.get_password(fieldname="app_secret_key", raise_exception=False), "app_folder")


return sess return sess


@frappe.whitelist()
def get_service_details():
return """
<div>
Steps to enable dropbox backup service:
<ol>
<li> Create a dropbox app then get App Key and App Secret,
<a href="https://www.dropbox.com/developers/apps" target="_blank">
https://www.dropbox.com/developers/apps
</a>
</li>
<br>
<li> Setup credentials on Dropbox Settings doctype.
Click on
<button class="btn btn-default btn-xs disabled"> Dropbox Settings </button>
top right corner
</li>
<br>
<li> After settings up App key and App Secret, generate access token
<button class="btn btn-default btn-xs disabled"> Allow Dropbox Access </button>
</li>
<br>
<li>
After saving settings,
<label>
<span class="input-area">
<input type="checkbox" class="input-with-feedback" checked disabled>
</span>
<span class="label-area small">Enable</span>
</label>
Dropbox Integration Service and Save a document.
</li>
</ol>
<p>
After enabling service, system will take backup of files and database on daily or weekly basis
as per set on Dropbox Settings page and upload it to your dropbox.
</p>
</div>
"""

#get auth token #get auth token
@frappe.whitelist() @frappe.whitelist()
def get_dropbox_authorize_url(): def get_dropbox_authorize_url():
doc = frappe.get_doc("Integration Service", "Dropbox Integration")
Controller.parameters = json.loads(doc.custom_settings_json)

sess = Controller().get_dropbox_session()
doc = frappe.get_doc("Dropbox Settings")
sess = doc.get_dropbox_session()
request_token = sess.obtain_request_token() request_token = sess.obtain_request_token()


setup_parameter({
doc.update({
"dropbox_access_key": request_token.key, "dropbox_access_key": request_token.key,
"dropbox_access_secret": request_token.secret "dropbox_access_secret": request_token.secret
}, doc)
})
doc.save(ignore_permissions=False)


return_address = get_request_site_address(True) \ return_address = get_request_site_address(True) \
+ "?cmd=frappe.integrations.dropbox_integration.dropbox_callback"
+ "?cmd=frappe.integrations.doctype.dropbox_settings.dropbox_settings.dropbox_callback"


url = sess.build_authorize_url(request_token, return_address) url = sess.build_authorize_url(request_token, return_address)


@@ -113,34 +123,20 @@ def get_dropbox_authorize_url():
"dropbox_access_secret": request_token.secret "dropbox_access_secret": request_token.secret
} }


def setup_parameter(request_token, doc):
parameters = Controller().parameters
for key in ["dropbox_access_key", "dropbox_access_secret"]:
for parameter in Controller().parameters:
if key == parameter:
parameters[key] = request_token[key]

doc.custom_settings_json = json.dumps(parameters)
doc.save(ignore_permissions=True)
frappe.db.commit()

@frappe.whitelist(allow_guest=True) @frappe.whitelist(allow_guest=True)
def dropbox_callback(oauth_token=None, not_approved=False): def dropbox_callback(oauth_token=None, not_approved=False):
doc = frappe.get_doc("Integration Service", "Dropbox Integration")
Controller.parameters = json.loads(doc.custom_settings_json)
doc = frappe.get_doc("Dropbox Settings")


parameters = Controller().get_parameters()
if not not_approved: if not not_approved:
if parameters["dropbox_access_key"]==oauth_token:
sess = Controller().get_dropbox_session()
sess.set_request_token(parameters["dropbox_access_key"], parameters["dropbox_access_secret"])
if doc.get_password(fieldname="dropbox_access_key", raise_exception=False)==oauth_token:
sess = doc.get_dropbox_session()
sess.set_request_token(doc.get_password(fieldname="dropbox_access_key", raise_exception=False),
doc.get_password(fieldname="dropbox_access_secret", raise_exception=False))

access_token = sess.obtain_access_token() access_token = sess.obtain_access_token()


setup_parameter({
"dropbox_access_key": access_token.key,
"dropbox_access_secret": access_token.secret
}, doc)
frappe.db.set_value("Dropbox Settings", None, "dropbox_access_key", access_token.key)
frappe.db.set_value("Dropbox Settings", None, "dropbox_access_secret", access_token.secret)


frappe.db.commit() frappe.db.commit()
else: else:
@@ -157,7 +153,7 @@ def dropbox_callback(oauth_token=None, not_approved=False):
@frappe.whitelist() @frappe.whitelist()
def take_backup(): def take_backup():
"Enqueue longjob for taking backup to dropbox" "Enqueue longjob for taking backup to dropbox"
enqueue("frappe.integrations.dropbox_integration.take_backup_to_dropbox", queue='long')
enqueue("frappe.integrations.doctype.dropbox_settings.dropbox_settings.take_backup_to_dropbox", queue='long')
frappe.msgprint(_("Queued for backup. It may take a few minutes to an hour.")) frappe.msgprint(_("Queued for backup. It may take a few minutes to an hour."))


def take_backups_daily(): def take_backups_daily():
@@ -167,16 +163,13 @@ def take_backups_weekly():
take_backups_if("Weekly") take_backups_if("Weekly")


def take_backups_if(freq): def take_backups_if(freq):
custom_settings_json = frappe.db.get_value("Dropbox Backup", None, "custom_settings_json")
if custom_settings_json:
custom_settings_json = json.loads(custom_settings_json)
if custom_settings_json["backup_frequency"] == freq:
take_backup_to_dropbox()
if frappe.db.get_value("Dropbox Settings", None, "backup_frequency") == freq:
take_backup_to_dropbox()


def take_backup_to_dropbox(): def take_backup_to_dropbox():
did_not_upload, error_log = [], [] did_not_upload, error_log = [], []
try: try:
if cint(frappe.db.get_value("Integration Service", "Dropbox Integration", "enabled")):
if cint(frappe.db.get_value("Integration Service", "Dropbox", "enabled")):
did_not_upload, error_log = backup_to_dropbox() did_not_upload, error_log = backup_to_dropbox()
if did_not_upload: raise Exception if did_not_upload: raise Exception


@@ -235,13 +228,11 @@ def backup_to_dropbox():


def get_dropbox_client(previous_dropbox_client=None): def get_dropbox_client(previous_dropbox_client=None):
from dropbox import client from dropbox import client
doc = frappe.get_doc("Integration Service", "Dropbox Integration")
Controller.parameters = json.loads(doc.custom_settings_json)

sess = Controller().get_dropbox_session()
doc = frappe.get_doc("Dropbox Settings")
sess = doc.get_dropbox_session()


parameters = Controller().get_parameters()
sess.set_token(parameters["dropbox_access_key"], parameters["dropbox_access_secret"])
sess.set_token(doc.get_password(fieldname="dropbox_access_key", raise_exception=False),
doc.get_password(fieldname="dropbox_access_secret", raise_exception=False))


dropbox_client = client.DropboxClient(sess) dropbox_client = client.DropboxClient(sess)



+ 12
- 0
frappe/integrations/doctype/dropbox_settings/test_dropbox_settings.py 查看文件

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals

import frappe
import unittest

# test_records = frappe.get_test_records('Dropbox Settings')

class TestDropboxSettings(unittest.TestCase):
pass

+ 0
- 0
frappe/integrations/doctype/ldap_settings/__init__.py 查看文件


+ 31
- 0
frappe/integrations/doctype/ldap_settings/ldap_settings.js 查看文件

@@ -0,0 +1,31 @@
// Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.provide("frappe.integration_service")

frappe.ui.form.on('LDAP Settings', {
refresh: function(frm) {

}
});

frappe.integration_service.ldap_settings = Class.extend({
init: function(frm) {
},
get_scheduler_job_info: function() {
return {}
},
get_service_info: function(frm) {
frappe.call({
method: "frappe.integrations.doctype.ldap_settings.ldap_settings.get_service_details",
callback: function(r){
var integration_service_help = frm.fields_dict.integration_service_help.wrapper;
$(integration_service_help).empty();
$(integration_service_help).append(r.message);
}
})
}
})

+ 162
- 0
frappe/integrations/doctype/ldap_settings/ldap_settings.json 查看文件

@@ -0,0 +1,162 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2016-09-22 04:16:48.829658",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "System",
"editable_grid": 1,
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "ldap_server_url",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "LDAP Server Url",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "organizational_unit",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Organizational Unit",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "base_dn",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Base Distinguished Name (DN)",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "password",
"fieldtype": "Password",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Password for Base DN",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 1,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2016-09-22 04:31:42.998441",
"modified_by": "Administrator",
"module": "Integrations",
"name": "LDAP Settings",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 1,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
}

+ 168
- 0
frappe/integrations/doctype/ldap_settings/ldap_settings.py 查看文件

@@ -0,0 +1,168 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cstr, cint
from frappe.integration_broker.doctype.integration_service.integration_service import IntegrationService

class LDAPSettings(IntegrationService):
def on_update(self):
pass
def validate(self):
if not self.flags.ignore_mandatory:
self.validate_ldap_credentails()
def enable(self):
if not self.flags.ignore_mandatory:
self.validate_ldap_credentails()

def validate_ldap_credentails(self):
try:
import ldap
conn = ldap.initialize(self.ldap_server_url)
conn.simple_bind_s(self.base_dn, self.get_password(raise_exception=False))
raise ImportError
except ImportError:
msg = """
<div>
Seems ldap is not installed on system.<br>
Guidelines to install ldap dependancies and python package,
<a href="https://discuss.erpnext.com/t/frappe-v-7-1-beta-ldap-dependancies/15841" target="_blank">Click here</a>,
</div>
"""
frappe.throw(msg, title="LDAP Not Installed")

except ldap.LDAPError:
conn.unbind_s()
frappe.throw("Incorrect UserId or Password")

@frappe.whitelist()
def get_service_details():
return """
<div>
<p> Steps to configure Service
<ol>
<li> Setup credentials on LDAP settings doctype
Click on
<button class="btn btn-default btn-xs disabled"> LDAP Settings </button>
top right corner
<br>
To setup LDAP you need,
<ul>
<li> Server URL & Port : ldap://ldap.forumsys.com:389</li>
<li> Base Distinguished Name : cn=read-only-admin,dc=example,dc=com</li>
<li> Organisational Unit : ou=mathematicians,dc=example,dc=com</li>
<li> Password : Base DN password </li>
</ul>
</li>
<br>
<li>
After saving settings,
<label>
<span class="input-area">
<input type="checkbox" class="input-with-feedback" checked disabled>
</span>
<span class="label-area small">Enable</span>
</label>
LDAP Integration Service and Save a document.
</li>
</ol>
</div>
"""

def get_ldap_settings():
try:
settings = frappe.get_doc("LDAP Settings")

settings.update({
"enabled": cint(frappe.db.get_value("Integration Service", "LDAP", "enabled")),
"method": "frappe.integrations.doctype.ldap_settings.ldap_settings.login"
})
return settings
except Exception:
# this will return blank settings
return frappe._dict()
@frappe.whitelist(allow_guest=True)
def login():
#### LDAP LOGIN LOGIC #####
args = frappe.form_dict
user = authenticate_ldap_user(args.usr, args.pwd)

frappe.local.login_manager.user = user.name
frappe.local.login_manager.post_login()

# because of a GET request!
frappe.db.commit()

def authenticate_ldap_user(user=None, password=None):
dn = None
params = {}
settings = get_ldap_settings()
try:
import ldap
except:
msg = """
<div>
{{_("Seems ldap is not installed on system")}}.<br>
<a href"https://discuss.erpnext.com/t/frappe-v-7-1-beta-ldap-dependancies/15841">Click here</a>,
{{_("Guidelines to install ldap dependancies and python")}}
</div>
"""
frappe.throw(msg, title="LDAP Not Installed")
conn = ldap.initialize(settings.ldap_server_url)

try:
# simple_bind_s is synchronous binding to server, it takes two param DN and password
conn.simple_bind_s(settings.base_dn, settings.get_password(raise_exception=False))

#search for surnames beginning with a
#available options for how deep a search you want.
#LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL,LDAP_SCOPE_SUBTREE,
result = conn.search_s(settings.organizational_unit, ldap.SCOPE_SUBTREE,
"uid=*{0}".format(user))
print result
for dn, r in result:
dn = cstr(dn)
params["email"] = cstr(r['mail'][0])
params["username"] = cstr(r['uid'][0])
params["first_name"] = cstr(r['cn'][0])
if dn:
conn.simple_bind_s(dn, password)
return create_user(params)
else:
frappe.throw(_("Not a valid LDAP user"))

except ldap.LDAPError:
conn.unbind_s()
frappe.throw(_("Incorrect UserId or Password"))

def create_user(params):
if frappe.db.exists("User", params["email"]):
return frappe.get_doc("User", params["email"])
else:
params.update({
"doctype": "User",
"send_welcome_email": 0,
"language": "",
"user_type": "System User",
"user_roles": [{
"role": _("Blogger")
}]
})

user = frappe.get_doc(params).insert(ignore_permissions=True)
frappe.db.commit()
return user

+ 0
- 0
frappe/integrations/doctype/paypal_settings/__init__.py 查看文件


+ 31
- 0
frappe/integrations/doctype/paypal_settings/paypal_settings.js 查看文件

@@ -0,0 +1,31 @@
// Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.provide("frappe.integration_service")

frappe.ui.form.on('PayPal Settings', {
refresh: function(frm) {

}
});

frappe.integration_service.paypal_settings = Class.extend({
init: function(frm) {
},
get_scheduler_job_info: function() {
return {}
},
get_service_info: function(frm) {
frappe.call({
method: "frappe.integrations.doctype.paypal_settings.paypal_settings.get_service_details",
callback: function(r){
var integration_service_help = frm.fields_dict.integration_service_help.wrapper;
$(integration_service_help).empty();
$(integration_service_help).append(r.message);
}
})
}
})

+ 190
- 0
frappe/integrations/doctype/paypal_settings/paypal_settings.json 查看文件

@@ -0,0 +1,190 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2016-09-21 08:03:01.009852",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "System",
"editable_grid": 1,
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "api_username",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "API Username",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "api_password",
"fieldtype": "Password",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "API Password",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "signature",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Signature",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "Check this if you are testing your payment using the Sandbox API",
"fieldname": "paypal_sandbox",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Use Sandbox",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "Mention transaction completion page URL",
"fieldname": "redirect_to",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Redirect To",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 1,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2016-09-26 02:00:45.145155",
"modified_by": "Administrator",
"module": "Integrations",
"name": "PayPal Settings",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 1,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
}

frappe/integrations/paypal.py → frappe/integrations/doctype/paypal_settings/paypal_settings.py 查看文件

@@ -1,6 +1,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
# Copyright (c) 2015, Frappe Technologies and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
import frappe
import json
from frappe import _
from frappe.utils import get_url, call_hook_method
from urllib import urlencode
from frappe.integration_broker.doctype.integration_service.integration_service import IntegrationService
import urllib


""" """
# Integrating PayPal # Integrating PayPal
@@ -11,7 +20,7 @@ Example:


from frappe.integration_broker.doctype.integration_service.integration_service import get_integration_controller from frappe.integration_broker.doctype.integration_service.integration_service import get_integration_controller


controller = get_integration_controller("PayPal", setup=False)
controller = get_integration_controller("PayPal")
controller().validate_transaction_currency(currency) controller().validate_transaction_currency(currency)


### 2. Redirect for payment ### 2. Redirect for payment
@@ -48,79 +57,49 @@ Example:
payment_status - payment gateway will put payment status on callback. payment_status - payment gateway will put payment status on callback.
For paypal payment status parameter is one from: [Completed, Cancelled, Failed] For paypal payment status parameter is one from: [Completed, Cancelled, Failed]


"""


from __future__ import unicode_literals
import frappe
import json
from frappe import _
from urllib import urlencode
from frappe.utils import get_url, call_hook_method
from frappe.integration_broker.integration_controller import IntegrationController

class Controller(IntegrationController):
service_name = 'PayPal'
parameters_template = [
{
"label": "API Username",
'fieldname': 'api_username',
'fieldtype': 'Data',
'reqd': 1
},
{
"label": "API Password",
'fieldname': 'api_password',
'fieldtype': "Password",
'reqd': 1
},
{
"label": "Signature",
"fieldname": "signature",
'fieldtype': "Data",
"reqd": 1
}
]
More Details:
<div class="small">For details on how to get your API credentials, follow this link: <a href="https://developer.paypal.com/docs/classic/api/apiCredentials/" target="_blank">https://developer.paypal.com/docs/classic/api/apiCredentials/</a></div>


js = "assets/frappe/js/integrations/paypal.js"
"""


class PayPalSettings(IntegrationService):
service_name = "PayPal"
supported_currencies = ["AUD", "BRL", "CAD", "CZK", "DKK", "EUR", "HKD", "HUF", "ILS", "JPY", "MYR", "MXN", supported_currencies = ["AUD", "BRL", "CAD", "CZK", "DKK", "EUR", "HKD", "HUF", "ILS", "JPY", "MYR", "MXN",
"TWD", "NZD", "NOK", "PHP", "PLN", "GBP", "RUB", "SGD", "SEK", "CHF", "THB", "TRY", "USD"] "TWD", "NZD", "NOK", "PHP", "PLN", "GBP", "RUB", "SGD", "SEK", "CHF", "THB", "TRY", "USD"]

def enable(self, parameters, use_test_account=0):
def validate(self):
if not self.flags.ignore_mandatory:
self.validate_paypal_credentails()
def on_update(self):
pass
def enable(self):
call_hook_method('payment_gateway_enabled', gateway=self.service_name) call_hook_method('payment_gateway_enabled', gateway=self.service_name)
self.parameters = parameters
self.validate_paypal_credentails(use_test_account)

def get_settings(self):
if not hasattr(self, "parameters"):
parameters = frappe.db.get_value("Integration Service", self.service_name,
["custom_settings_json"])
self.parameters = json.loads(parameters)
if not self.flags.ignore_mandatory:
self.validate_paypal_credentails()
return frappe._dict(self.parameters)

def validate_transaction_currency(self, currency): def validate_transaction_currency(self, currency):
if currency not in self.supported_currencies: if currency not in self.supported_currencies:
frappe.throw(_("Please select another payment method. {0} does not support transactions in currency '{1}'").format(self.service_name, currency)) frappe.throw(_("Please select another payment method. {0} does not support transactions in currency '{1}'").format(self.service_name, currency))

def get_paypal_params_and_url(self, use_test_account=None):
use_test_account = frappe.db.get_value("Integration Service", self.service_name, ["use_test_account"])
paypal_settings = frappe._dict(self.get_settings())

def get_paypal_params_and_url(self):
params = { params = {
"USER": paypal_settings.api_username,
"PWD": paypal_settings.api_password,
"SIGNATURE": paypal_settings.signature,
"USER": self.api_username,
"PWD": self.get_password(fieldname="api_password", raise_exception=False),
"SIGNATURE": self.signature,
"VERSION": "98", "VERSION": "98",
"METHOD": "GetPalDetails" "METHOD": "GetPalDetails"
} }


api_url = "https://api-3t.sandbox.paypal.com/nvp" if use_test_account else "https://api-3t.paypal.com/nvp"
api_url = "https://api-3t.sandbox.paypal.com/nvp" if self.paypal_sandbox else "https://api-3t.paypal.com/nvp"


return params, api_url return params, api_url


def validate_paypal_credentails(self, use_test_account):
params, url = self.get_paypal_params_and_url(use_test_account)
def validate_paypal_credentails(self):
params, url = self.get_paypal_params_and_url()
params = urlencode(params) params = urlencode(params)


try: try:
@@ -131,12 +110,11 @@ class Controller(IntegrationController):


except Exception: except Exception:
frappe.throw(_("Invalid payment gateway credentials")) frappe.throw(_("Invalid payment gateway credentials"))
def get_payment_url(self, **kwargs): def get_payment_url(self, **kwargs):
use_test_account = frappe.db.get_value("Integration Service", self.service_name, ["use_test_account"])
response = self.execute_set_express_checkout(kwargs["amount"], kwargs["currency"]) response = self.execute_set_express_checkout(kwargs["amount"], kwargs["currency"])


if use_test_account:
if self.paypal_sandbox:
return_url = "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}" return_url = "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}"
else: else:
return_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}" return_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}"
@@ -169,15 +147,53 @@ class Controller(IntegrationController):


return response return response


@frappe.whitelist()
def get_service_details():
return """
<div>
<p> Steps to configure Service
<ol>
<li> Get PayPal api credentials from link:
<a href="https://developer.paypal.com/docs/classic/api/apiCredentials/" target="_blank">
https://developer.paypal.com/docs/classic/api/apiCredentials/
</a>
</li>
<br>
<li> Setup credentials on PayPal settings doctype.
Click on
<button class="btn btn-default btn-xs disabled"> PayPal Settings </button>
top right corner
</li>
<br>
<li>
After saving settings,
<label>
<span class="input-area">
<input type="checkbox" class="input-with-feedback" checked disabled>
</span>
<span class="label-area small">Enabled</span>
</label>
PayPal Integration Service and Save a document.
</li>
<br>
<li>
To view PayPal payment logs,
<button class="btn btn-default btn-xs disabled"> Show Log </button>
</li>
</ol>
</div>
"""

@frappe.whitelist(allow_guest=True, xss_safe=True) @frappe.whitelist(allow_guest=True, xss_safe=True)
def get_express_checkout_details(token): def get_express_checkout_details(token):
params, url = Controller().get_paypal_params_and_url()
doc = frappe.get_doc("PayPal Settings")
params, url = doc.get_paypal_params_and_url()
params.update({ params.update({
"METHOD": "GetExpressCheckoutDetails", "METHOD": "GetExpressCheckoutDetails",
"TOKEN": token "TOKEN": token
}) })


response = Controller().post_request(url, data=params)
response = doc.post_request(url, data=params)


if response.get("ACK")[0] != "Success": if response.get("ACK")[0] != "Success":
frappe.respond_as_web_page(_("Something went wrong"), frappe.respond_as_web_page(_("Something went wrong"),
@@ -200,10 +216,14 @@ def get_express_checkout_details(token):
def confirm_payment(token): def confirm_payment(token):
redirect = True redirect = True
status_changed_to, redirect_to = None, None status_changed_to, redirect_to = None, None
doc = frappe.get_doc("PayPal Settings")
integration_request = frappe.get_doc("Integration Request", token) integration_request = frappe.get_doc("Integration Request", token)
data = json.loads(integration_request.data) data = json.loads(integration_request.data)

params, url = Controller().get_paypal_params_and_url()
redirect_to = data.get('redirect_to') or None
redirect_message = data.get('redirect_message') or None
params, url = doc.get_paypal_params_and_url()
params.update({ params.update({
"METHOD": "DoExpressCheckoutPayment", "METHOD": "DoExpressCheckoutPayment",
"PAYERID": data.get("payerid"), "PAYERID": data.get("payerid"),
@@ -213,7 +233,7 @@ def confirm_payment(token):
"PAYMENTREQUEST_0_CURRENCYCODE": data.get("currency").upper() "PAYMENTREQUEST_0_CURRENCYCODE": data.get("currency").upper()
}) })


response = Controller().post_request(url, data=params)
response = doc.post_request(url, data=params)


if response.get("ACK")[0] == "Success": if response.get("ACK")[0] == "Success":
update_integration_request_status(token, { update_integration_request_status(token, {
@@ -222,21 +242,22 @@ def confirm_payment(token):
}, "Completed") }, "Completed")


if data.get("reference_doctype") and data.get("reference_docname"): if data.get("reference_doctype") and data.get("reference_docname"):
redirect_to = frappe.get_doc(data.get("reference_doctype"), data.get("reference_docname")).run_method("on_payment_authorized", "Completed")

if not redirect_to:
if data.get('redirect_to'):
redirect_to = data.get('redirect_to')

redirect_to = redirect_to or get_url("/integrations/payment-success")
redirect_url = frappe.get_doc(data.get("reference_doctype"), data.get("reference_docname")).run_method("on_payment_authorized", "Completed")


if not redirect_url:
redirect_url = '/integrations/payment-success'
else: else:
redirect_to = get_url("/integrations/payment-failed")
redirect_url = "/integrations/payment-failed"

if redirect_to:
redirect_url += '?' + urllib.urlencode({'redirect_to': redirect_to})
if redirect_message:
redirect_url += '&' + urllib.urlencode({'redirect_message': redirect_message})


# this is done so that functions called via hooks can update flags.redirect_to # this is done so that functions called via hooks can update flags.redirect_to
if redirect: if redirect:
frappe.local.response["type"] = "redirect" frappe.local.response["type"] = "redirect"
frappe.local.response["location"] = redirect_to
frappe.local.response["location"] = get_url(redirect_to)


def update_integration_request_status(token, data, status, error=False): def update_integration_request_status(token, data, status, error=False):
frappe.get_doc("Integration Request", token).update_status(data, status) frappe.get_doc("Integration Request", token).update_status(data, status)
@@ -244,7 +265,8 @@ def update_integration_request_status(token, data, status, error=False):
@frappe.whitelist(allow_guest=True, xss_safe=True) @frappe.whitelist(allow_guest=True, xss_safe=True)
def get_checkout_url(**kwargs): def get_checkout_url(**kwargs):
try: try:
return Controller().get_payment_url(**kwargs)
doc = frappe.get_doc("PayPal Settings")
return doc.get_payment_url(**kwargs)
except Exception: except Exception:
frappe.respond_as_web_page(_("Something went wrong"), frappe.respond_as_web_page(_("Something went wrong"),
_("Looks like something is wrong with this site's Paypal configuration. Don't worry! No payment has been made from your Paypal account."), _("Looks like something is wrong with this site's Paypal configuration. Don't worry! No payment has been made from your Paypal account."),

+ 0
- 0
frappe/integrations/doctype/razorpay_settings/__init__.py 查看文件


+ 33
- 0
frappe/integrations/doctype/razorpay_settings/razorpay_settings.js 查看文件

@@ -0,0 +1,33 @@
// Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.provide("frappe.integration_service")

frappe.ui.form.on('Razorpay Settings', {
refresh: function(frm) {
}
});

frappe.integration_service.razorpay_settings = Class.extend({
init: function(frm) {
},
get_scheduler_job_info: function() {
return {
"Execute on every few minits of interval": " Captures all authorised payments"
}
},
get_service_info: function(frm) {
frappe.call({
method: "frappe.integrations.doctype.razorpay_settings.razorpay_settings.get_service_details",
callback: function(r){
var integration_service_help = frm.fields_dict.integration_service_help.wrapper;
$(integration_service_help).empty();
$(integration_service_help).append(r.message);
}
})
}
})

+ 137
- 0
frappe/integrations/doctype/razorpay_settings/razorpay_settings.json 查看文件

@@ -0,0 +1,137 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2016-09-20 03:44:03.799402",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "System",
"editable_grid": 1,
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "api_key",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "API Key",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "api_secret",
"fieldtype": "Password",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "API Secret",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "Mention transaction completion page URL",
"fieldname": "redirect_to",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Redirect To",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 1,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2016-09-26 02:00:03.604912",
"modified_by": "Administrator",
"module": "Integrations",
"name": "Razorpay Settings",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 1,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
}

frappe/integrations/razorpay.py → frappe/integrations/doctype/razorpay_settings/razorpay_settings.py 查看文件

@@ -1,6 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
# Copyright (c) 2015, Frappe Technologies and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
import frappe
from frappe.utils import get_url, call_hook_method
from frappe import _
import urllib, json
from frappe.integration_broker.doctype.integration_service.integration_service import IntegrationService


""" """
# Integrating RazorPay # Integrating RazorPay
@@ -50,31 +57,11 @@ payment_status - payment gateway will put payment status on callback.
For razorpay payment status is Authorized For razorpay payment status is Authorized


""" """
from __future__ import unicode_literals
import frappe
from frappe import _
import urllib, json
from frappe.utils import get_url, call_hook_method
from frappe.integration_broker.integration_controller import IntegrationController


class Controller(IntegrationController):
service_name = 'Razorpay'
parameters_template = [
{
"label": "API Key",
'fieldname': 'api_key',
'fieldtype': "Data",
'reqd': 1
},
{
"label": "API Secret",
'fieldname': 'api_secret',
'fieldtype': "Password",
'reqd': 1
}
]

# do also changes in razorpay.js scheduler job helper
class RazorpaySettings(IntegrationService):
service_name = "Razorpay"
supported_currencies = ["INR"]
scheduled_jobs = [ scheduled_jobs = [
{ {
"all": [ "all": [
@@ -82,48 +69,41 @@ class Controller(IntegrationController):
] ]
} }
] ]

js = "assets/frappe/js/integrations/razorpay.js"

supported_currencies = ["INR"]

def enable(self, parameters, use_test_account=0):
def validate(self):
if not self.flags.ignore_mandatory:
self.validate_razorpay_credentails()
def on_update(self):
pass
def enable(self):
call_hook_method('payment_gateway_enabled', gateway='Razorpay') call_hook_method('payment_gateway_enabled', gateway='Razorpay')
self.parameters = parameters
self.validate_razorpay_credentails()


if not self.flags.ignore_mandatory:
self.validate_razorpay_credentails()
def validate_razorpay_credentails(self): def validate_razorpay_credentails(self):
razorpay_settings = self.get_settings()

if razorpay_settings.get("api_key"):
if self.api_key and self.api_secret:
try: try:
self.get_request(url="https://api.razorpay.com/v1/payments", self.get_request(url="https://api.razorpay.com/v1/payments",
auth=(razorpay_settings.api_key, razorpay_settings.api_secret))
auth=(self.api_key, self.get_password(fieldname="api_secret", raise_exception=False)))
except Exception: except Exception:
frappe.throw(_("Seems API Key or API Secret is wrong !!!")) frappe.throw(_("Seems API Key or API Secret is wrong !!!"))
def validate_transaction_currency(self, currency): def validate_transaction_currency(self, currency):
if currency not in self.supported_currencies: if currency not in self.supported_currencies:
frappe.throw(_("Please select another payment method. {0} does not support transactions in currency '{1}'").format(self.service_name, currency)) frappe.throw(_("Please select another payment method. {0} does not support transactions in currency '{1}'").format(self.service_name, currency))


def get_payment_url(self, **kwargs): def get_payment_url(self, **kwargs):
return get_url("./integrations/razorpay_checkout?{0}".format(urllib.urlencode(kwargs))) return get_url("./integrations/razorpay_checkout?{0}".format(urllib.urlencode(kwargs)))

def get_settings(self):
if hasattr(self, "parameters"):
return frappe._dict(self.parameters)

custom_settings_json = frappe.db.get_value("Integration Service", "Razorpay", "custom_settings_json")

if custom_settings_json:
return frappe._dict(json.loads(custom_settings_json))

def create_request(self, data): def create_request(self, data):
self.data = frappe._dict(data) self.data = frappe._dict(data)


try: try:
self.integration_request = super(Controller, self).create_request(self.data, "Host", \
self.service_name)
self.integration_request = super(RazorpaySettings, self).create_request(self.data, "Host", \
"Razorpay")
return self.authorize_payment() return self.authorize_payment()


except Exception: except Exception:
@@ -139,7 +119,6 @@ class Controller(IntegrationController):
The money is deducted from the customer’s account, but will not be transferred to the merchant’s account The money is deducted from the customer’s account, but will not be transferred to the merchant’s account
until it is explicitly captured by merchant. until it is explicitly captured by merchant.
""" """

settings = self.get_settings() settings = self.get_settings()
data = json.loads(self.integration_request.data) data = json.loads(self.integration_request.data)
redirect_to = data.get('notes', {}).get('redirect_to') or None redirect_to = data.get('notes', {}).get('redirect_to') or None
@@ -198,8 +177,8 @@ def capture_payment(is_sandbox=False, sanbox_response=None):


Note: Attempting to capture a payment whose status is not authorized will produce an error. Note: Attempting to capture a payment whose status is not authorized will produce an error.
""" """
controller = frappe.get_doc("Integration Service", "Razorpay")
settings = controller.get_parameters()
controller = frappe.get_doc("Razorpay Settings")
for doc in frappe.get_all("Integration Request", filters={"status": "Authorized", for doc in frappe.get_all("Integration Request", filters={"status": "Authorized",
"integration_request_service": "Razorpay"}, fields=["name", "data"]): "integration_request_service": "Razorpay"}, fields=["name", "data"]):
try: try:
@@ -208,7 +187,7 @@ def capture_payment(is_sandbox=False, sanbox_response=None):
else: else:
data = json.loads(doc.data) data = json.loads(doc.data)
resp = controller.post_request("https://api.razorpay.com/v1/payments/{0}/capture".format(data.get("razorpay_payment_id")), resp = controller.post_request("https://api.razorpay.com/v1/payments/{0}/capture".format(data.get("razorpay_payment_id")),
auth=(settings["api_key"], settings["api_secret"]), data={"amount": data.get("amount")})
auth=(controller.api_key, controller.get_password("api_secret")), data={"amount": data.get("amount")})


if resp.get("status") == "captured": if resp.get("status") == "captured":
frappe.db.set_value("Integration Request", doc.name, "status", "Completed") frappe.db.set_value("Integration Request", doc.name, "status", "Completed")
@@ -221,9 +200,47 @@ def capture_payment(is_sandbox=False, sanbox_response=None):
@frappe.whitelist(allow_guest=True, xss_safe=True) @frappe.whitelist(allow_guest=True, xss_safe=True)
def get_checkout_url(**kwargs): def get_checkout_url(**kwargs):
try: try:
return Controller().get_payment_url(**kwargs)
return frappe.get_doc("Razorpay Settings").get_payment_url(**kwargs)
except Exception: except Exception:
frappe.respond_as_web_page(_("Something went wrong"), frappe.respond_as_web_page(_("Something went wrong"),
_("Looks like something is wrong with this site's Razorpay configuration. Don't worry! No payment has been made."), _("Looks like something is wrong with this site's Razorpay configuration. Don't worry! No payment has been made."),
success=False, success=False,
http_status_code=frappe.ValidationError.http_status_code) http_status_code=frappe.ValidationError.http_status_code)

@frappe.whitelist()
def get_service_details():
return """
<div>
<p> Steps to configure Service
<ol>
<li> Get Razorpay api credentials by login to:
<a href="https://razorpay.com/" target="_blank">
https://razorpay.com/
</a>
</li>
<br>
<li> Setup credentials on Razorpay Settings doctype.
Click on
<button class="btn btn-default btn-xs disabled"> Razorpay Settings </button>
top right corner
</li>
<br>
<li>
After saving settings,
<label>
<span class="input-area">
<input type="checkbox" class="input-with-feedback" checked disabled>
</span>
<span class="label-area small">Enable</span>
</label>
Razorpay Integration Service and Save a document.
</li>
<br>
<li>
To view Razorpays payment logs,
<button class="btn btn-default btn-xs disabled"> Show Log </button>
</li>
</ol>
</div>
"""

+ 0
- 139
frappe/integrations/ldap_auth.py 查看文件

@@ -1,139 +0,0 @@
import frappe
import ldap, json
from frappe.integration_broker.integration_controller import IntegrationController
from frappe import _
from frappe.utils import cstr, cint

class Controller(IntegrationController):
service_name = 'LDAP Auth'
parameters_template = [
{
"label": "LDAP Server Url",
"fieldname": "ldap_server_url",
"reqd": 1,
"fieldtype": "Data"
},
{
"label": "Organizational Unit",
"fieldname": "organizational_unit",
"reqd": 1,
"fieldtype": "Data"
},
{
"label": "Base Distinguished Name (DN)",
"fieldname": "base_dn",
"reqd": 1,
"fieldtype": "Data"
},
{
"label": "Password for Base DN",
"fieldname": "password",
"reqd": 1,
"fieldtype": "Password"
},
{
"label": "Sync frequency from ldap to frappe",
"fieldname": "sync_frequency",
"reqd": 1,
"fieldtype": "Select",
"options": "\nDaily\nWeekly",
}
]
js = "assets/frappe/js/integrations/ldap_auth.js"
def enable(self, parameters, use_test_account=0):
self.parameters = parameters
self.validate_ldap_credentails()

def validate_ldap_credentails(self):
ldap_settings = self.get_settings()
try:
conn = ldap.initialize(ldap_settings.get('ldap_server_url'))
conn.simple_bind_s(ldap_settings.get("base_dn"), ldap_settings.get("password"))
except ldap.LDAPError:
conn.unbind_s()
frappe.throw("Incorrect UserId or Password")

def get_settings(self):
return frappe._dict(self.parameters)

def get_ldap_settings():
try:
doc = frappe.get_doc("Integration Service", "LDAP Auth")
settings = json.loads(doc.custom_settings_json)
settings.update({
"enabled": cint(doc.enabled),
"method": "frappe.integrations.ldap_auth.login"
})
return settings
except Exception:
# this will return blank settings
return frappe._dict()
@frappe.whitelist(allow_guest=True)
def login():
#### LDAP LOGIN LOGIC #####
args = frappe.form_dict
user = authenticate_ldap_user(args.usr, args.pwd)

frappe.local.login_manager.user = user.name
frappe.local.login_manager.post_login()

# because of a GET request!
frappe.db.commit()

def authenticate_ldap_user(user=None, password=None):
dn = None
params = {}
settings = get_ldap_settings()
conn = ldap.initialize(settings.get('ldap_server_url'))
print settings
try:
# simple_bind_s is synchronous binding to server, it takes two param DN and password
conn.simple_bind_s(settings.get("base_dn"), settings.get("password"))
print "here"
#search for surnames beginning with a
#available options for how deep a search you want.
#LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL,LDAP_SCOPE_SUBTREE,
result = conn.search_s(settings.get("organizational_unit"), ldap.SCOPE_SUBTREE,
"uid=*{0}".format(user))
print result
for dn, r in result:
dn = cstr(dn)
params["email"] = cstr(r['mail'][0])
params["username"] = cstr(r['uid'][0])
params["first_name"] = cstr(r['cn'][0])
if dn:
conn.simple_bind_s(dn, password)
return create_user(params)
else:
frappe.throw(_("Not a valid LDAP user"))

except ldap.LDAPError:
conn.unbind_s()
frappe.throw(_("Incorrect UserId or Password"))

def create_user(params):
if frappe.db.exists("User", params["email"]):
return frappe.get_doc("User", params["email"])
else:
params.update({
"doctype": "User",
"send_welcome_email": 0,
"language": "",
"user_type": "System User",
"user_roles": [{
"role": _("Blogger")
}]
})

user = frappe.get_doc(params).insert(ignore_permissions=True)
frappe.db.commit()
return user

+ 1
- 0
frappe/patches.txt 查看文件

@@ -143,3 +143,4 @@ execute:frappe.core.doctype.language.language.update_language_names()
execute:frappe.db.set_value("Print Settings", "Print Settings", "add_draft_heading", 1) execute:frappe.db.set_value("Print Settings", "Print Settings", "add_draft_heading", 1)
frappe.patches.v7_0.cleanup_list_settings frappe.patches.v7_0.cleanup_list_settings
execute:frappe.db.set_default('language', '') execute:frappe.db.set_default('language', '')
frappe.patches.v7_1.refactor_integration_broker

+ 52
- 0
frappe/patches/v7_1/refactor_integration_broker.py 查看文件

@@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt

from __future__ import unicode_literals
import frappe
import json

def execute():
for doctype_name in ["Razorpay Log", "Razorpay Payment", "Razorpay Settings"]:
delete_doc("DocType", doctype_name)
reload_doctypes()
setup_services()

def delete_doc(doctype, doctype_name):
frappe.delete_doc(doctype, doctype_name)

def reload_doctypes():
for doctype in ("razorpay_settings", "paypal_settings", "dropbox_settings", "ldap_settings"):
frappe.reload_doc("integrations", "doctype", doctype)

def setup_services():
for service in [{"old_name": "Razorpay", "new_name": "Razorpay"},
{"old_name": "PayPal", "new_name": "PayPal"},
{"old_name": "Dropbox Integration", "new_name": "Dropbox"},
{"old_name": "LDAP Auth", "new_name": "LDAP"}]:

try:
service_doc = frappe.get_doc("Integration Service", service["old_name"])
settings = json.loads(service_doc.custom_settings_json)

service_settings = frappe.new_doc("{0} Settings".format(service["new_name"]))
service_settings.update(settings)
service_settings.flags.ignore_mandatory = True
service_settings.save(ignore_permissions=True)

if service["old_name"] in ["Dropbox Integration", "LDAP Auth"]:
delete_doc("Integration Service", service["old_name"])
new_service_doc = frappe.get_doc({
"doctype": "Integration Service",
"service": service["new_name"],
"enabled": 1
})
new_service_doc.flags.ignore_mandatory = True
new_service_doc.save(ignore_permissions=True)

except Exception:
pass

+ 0
- 48
frappe/public/js/integrations/dropbox_integration.js 查看文件

@@ -1,48 +0,0 @@
frappe.provide("frappe.integration_service")

frappe.integration_service.dropbox_integration = {
load: function(frm) {
new frappe.integration_service.DropboxIntegration(frm)
},
scheduler_job_helper: function(){
return {
"Daily": "Take backup of database and files to dropbox on daily basis",
"Weekly": "Take backup of database and files to dropbox on weekly basis"
}
}
}

frappe.integration_service.DropboxIntegration = Class.extend({
init: function(frm) {
this.frm = frm;
this.frm.toggle_display("use_test_account", false);
if(this.frm.doc.service == "Dropbox Integration" && this.frm.doc.enabled && !this.frm.doc.__islocal){
this.allow_dropbox_acess(frm);
this.take_backup(frm);
}
},

allow_dropbox_acess: function(frm) {
this.frm.add_custom_button(__("Allow Dropbox Access"), function(frm){
frappe.call({
method: "frappe.integrations.dropbox_integration.get_dropbox_authorize_url",
freeze: true,
callback: function(r) {
if(!r.exc) {
window.open(r.message.url);
}
}
})
}).addClass("btn-primary")
},

take_backup: function(frm) {
var me = this;
this.frm.add_custom_button(__("Take Backup Now"), function(frm){
frappe.call({
method: "frappe.integrations.dropbox_integration.take_backup",
freeze: true
})
}).addClass("btn-primary")
}
})

+ 0
- 15
frappe/public/js/integrations/ldap_auth.js 查看文件

@@ -1,15 +0,0 @@
frappe.provide("frappe.integration_service")

frappe.integration_service.ldap_auth = {
load: function(frm) {
new frappe.integration_service.ldapAuth(frm)
}
}

frappe.integration_service.ldapAuth = Class.extend({
init:function(frm){
this.frm = frm;
this.frm.toggle_display("use_test_account", false);
}
})

+ 0
- 21
frappe/public/js/integrations/paypal.js 查看文件

@@ -1,21 +0,0 @@
frappe.provide("frappe.integration_service")

frappe.integration_service.paypal = {
load: function(frm) {
new frappe.integration_service.PayPal(frm)
}
}

frappe.integration_service.PayPal = Class.extend({
init:function(frm){
this.frm = frm;
this.show_logs();
},
show_logs: function(){
this.frm.add_custom_button(__("Show Log"), function(frm){
frappe.route_options = {"integration_request_service": "PayPal"};
frappe.set_route("List", "Integration Request");
}).addClass("btn-primary")
}
})

+ 4
- 4
frappe/templates/pages/integrations/razorpay_checkout.py 查看文件

@@ -6,8 +6,6 @@ from frappe import _
from frappe.utils import flt from frappe.utils import flt
import json import json


from frappe.integrations.razorpay import Controller

no_cache = 1 no_cache = 1
no_sitemap = 1 no_sitemap = 1


@@ -16,7 +14,7 @@ expected_keys = ('amount', 'title', 'description', 'reference_doctype', 'referen


def get_context(context): def get_context(context):
context.no_cache = 1 context.no_cache = 1
context.api_key = Controller().get_settings().api_key
context.api_key = frappe.db.get_value("Razorpay Settings", None, "api_key")


# all these keys exist in form_dict # all these keys exist in form_dict
if not (set(expected_keys) - set(frappe.form_dict.keys())): if not (set(expected_keys) - set(frappe.form_dict.keys())):
@@ -43,4 +41,6 @@ def make_payment(razorpay_payment_id, options, reference_doctype, reference_docn
"reference_doctype": reference_doctype "reference_doctype": reference_doctype
}) })


return Controller().create_request(data)
data = frappe.get_doc("Razorpay Settings").create_request(data)
frappe.db.commit()
return data

+ 1
- 1
frappe/www/login.py 查看文件

@@ -8,7 +8,7 @@ from frappe.utils.oauth import get_oauth2_authorize_url, get_oauth_keys, login_v
import json import json
from frappe import _ from frappe import _
from frappe.auth import LoginManager from frappe.auth import LoginManager
from frappe.integrations.ldap_auth import get_ldap_settings
from frappe.integrations.doctype.ldap_settings.ldap_settings import get_ldap_settings


no_cache = True no_cache = True




+ 0
- 1
requirements.txt 查看文件

@@ -38,4 +38,3 @@ zxcvbn
psutil psutil
unittest-xml-reporting unittest-xml-reporting
xlwt xlwt
python-ldap

Loading…
取消
儲存