@@ -5,7 +5,7 @@ | |||
"es6": true | |||
}, | |||
"parserOptions": { | |||
"ecmaVersion": 8, | |||
"ecmaVersion": 9, | |||
"sourceType": "module" | |||
}, | |||
"extends": "eslint:recommended", | |||
@@ -1,16 +0,0 @@ | |||
name: Backport | |||
on: | |||
pull_request: | |||
types: | |||
- closed | |||
- labeled | |||
jobs: | |||
backport: | |||
runs-on: ubuntu-18.04 | |||
name: Backport | |||
steps: | |||
- name: Backport | |||
uses: tibdex/backport@v1 | |||
with: | |||
github_token: ${{ secrets.GITHUB_TOKEN }} |
@@ -3,15 +3,16 @@ | |||
# These owners will be the default owners for everything in | |||
# the repo. Unless a later match takes precedence, | |||
* @surajshetty3416, @netchampfaris | |||
* @frappe/frappe-review-team | |||
website/ @scmmishra | |||
web_form/ @scmmishra | |||
templates/ @scmmishra | |||
www/ @scmmishra | |||
integrations/ @Mangesh-Khairnar | |||
patches/ @surajshetty3416 @sahil28297 | |||
patches/ @sahil28297 | |||
dashboard/ @prssanna | |||
email/ @Thunderbottom | |||
event_streaming/ @ruchamahabal | |||
data_import* @netchampfaris | |||
core/ @surajshetty3416 | |||
requirements.txt @gavindsouza | |||
requirements.txt @gavindsouza |
@@ -1,22 +1,24 @@ | |||
{ | |||
"cards": [ | |||
{ | |||
"icon": "octicon octicon-briefcase", | |||
"links": "[\n {\n \"description\": \"Documents assigned to you and by you.\",\n \"label\": \"To Do\",\n \"name\": \"ToDo\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Event and other calendars.\",\n \"label\": \"Calendar\",\n \"link\": \"List/Event/Calendar\",\n \"name\": \"Event\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Private and public Notes.\",\n \"label\": \"Note\",\n \"name\": \"Note\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Files\",\n \"name\": \"File\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Activity log of all users.\",\n \"label\": \"Activity\",\n \"name\": \"activity\",\n \"type\": \"page\"\n }\n]", | |||
"title": "Tools" | |||
"hidden": 0, | |||
"label": "Tools", | |||
"links": "[\n {\n \"description\": \"Documents assigned to you and by you.\",\n \"label\": \"To Do\",\n \"name\": \"ToDo\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Event and other calendars.\",\n \"label\": \"Calendar\",\n \"link\": \"List/Event/Calendar\",\n \"name\": \"Event\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Private and public Notes.\",\n \"label\": \"Note\",\n \"name\": \"Note\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Files\",\n \"name\": \"File\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Activity log of all users.\",\n \"label\": \"Activity\",\n \"name\": \"activity\",\n \"type\": \"page\"\n }\n]" | |||
}, | |||
{ | |||
"links": "[\n {\n \"description\": \"Newsletters to contacts, leads.\",\n \"label\": \"Newsletter\",\n \"name\": \"Newsletter\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Email Group List\",\n \"label\": \"Email Group\",\n \"name\": \"Email Group\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Email" | |||
"hidden": 0, | |||
"label": "Email", | |||
"links": "[\n {\n \"description\": \"Newsletters to contacts, leads.\",\n \"label\": \"Newsletter\",\n \"name\": \"Newsletter\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Email Group List\",\n \"label\": \"Email Group\",\n \"name\": \"Email Group\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"icon": "fa fa-cog", | |||
"links": "[\n {\n \"type\": \"doctype\",\n \"name\": \"Assignment Rule\",\n \"description\": \"Set up rules for user assignments.\",\n \"label\": \"Assignment Rule\"\n },\n {\n \"type\": \"doctype\",\n \"name\": \"Milestone\",\n \"description\": \"Tracks milestones on the lifecycle of a document if it undergoes multiple stages.\",\n \"label\": \"Milestone\"\n },\n {\n \"type\": \"doctype\",\n \"name\": \"Auto Repeat\",\n \"description\": \"Automatically generates recurring documents.\",\n \"label\": \"Auto Repeat\"\n }\n]", | |||
"title": "Automation" | |||
"hidden": 0, | |||
"label": "Automation", | |||
"links": "[\n {\n \"type\": \"doctype\",\n \"name\": \"Assignment Rule\",\n \"description\": \"Set up rules for user assignments.\",\n \"label\": \"Assignment Rule\"\n },\n {\n \"type\": \"doctype\",\n \"name\": \"Milestone\",\n \"description\": \"Tracks milestones on the lifecycle of a document if it undergoes multiple stages.\",\n \"label\": \"Milestone\"\n },\n {\n \"type\": \"doctype\",\n \"name\": \"Auto Repeat\",\n \"description\": \"Automatically generates recurring documents.\",\n \"label\": \"Auto Repeat\"\n }\n]" | |||
}, | |||
{ | |||
"links": "[\n {\n \"type\": \"doctype\",\n \"name\": \"Event Producer\",\n \"description\": \"The site you want to subscribe to for consuming events.\",\n \"label\": \"Event Producer\"\n },\n {\n \"type\": \"doctype\",\n \"name\": \"Event Consumer\",\n \"description\": \"The site which is consuming your events.\",\n \"label\": \"Event Consumer\"\n },\n {\n \"type\": \"doctype\",\n \"name\": \"Event Update Log\",\n \"description\": \"Maintains a Log of all inserts, updates and deletions on Event Producer site for documents that have consumers.\",\n \"label\": \"Event Update Log\"\n },\n {\n \"type\": \"doctype\",\n \"name\": \"Event Sync Log\",\n \"description\": \"Maintains a log of every event consumed along with the status of the sync and a Resync button in case sync fails.\",\n \"label\": \"Event Sync Log\"\n },\n {\n \"type\": \"doctype\",\n \"name\": \"Document Type Mapping\",\n \"description\": \"The mapping configuration between two doctypes.\",\n \"label\": \"Document Type Mapping\"\n }\n]", | |||
"title": "Event Streaming" | |||
"hidden": 0, | |||
"label": "Event Streaming", | |||
"links": "[\n {\n \"type\": \"doctype\",\n \"name\": \"Event Producer\",\n \"description\": \"The site you want to subscribe to for consuming events.\",\n \"label\": \"Event Producer\"\n },\n {\n \"type\": \"doctype\",\n \"name\": \"Event Consumer\",\n \"description\": \"The site which is consuming your events.\",\n \"label\": \"Event Consumer\"\n },\n {\n \"type\": \"doctype\",\n \"name\": \"Event Update Log\",\n \"description\": \"Maintains a Log of all inserts, updates and deletions on Event Producer site for documents that have consumers.\",\n \"label\": \"Event Update Log\"\n },\n {\n \"type\": \"doctype\",\n \"name\": \"Event Sync Log\",\n \"description\": \"Maintains a log of every event consumed along with the status of the sync and a Resync button in case sync fails.\",\n \"label\": \"Event Sync Log\"\n },\n {\n \"type\": \"doctype\",\n \"name\": \"Document Type Mapping\",\n \"description\": \"The mapping configuration between two doctypes.\",\n \"label\": \"Document Type Mapping\"\n }\n]" | |||
} | |||
], | |||
"category": "Administration", | |||
@@ -30,7 +32,7 @@ | |||
"idx": 0, | |||
"is_standard": 1, | |||
"label": "Tools", | |||
"modified": "2020-03-12 16:30:41.841895", | |||
"modified": "2020-04-01 11:24:40.804346", | |||
"modified_by": "Administrator", | |||
"module": "Automation", | |||
"name": "Tools", | |||
@@ -39,27 +41,27 @@ | |||
"pin_to_top": 0, | |||
"shortcuts": [ | |||
{ | |||
"is_query_report": 0, | |||
"label": "ToDo", | |||
"link_to": "ToDo", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"is_query_report": 0, | |||
"label": "Note", | |||
"link_to": "Note", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"is_query_report": 0, | |||
"label": "File", | |||
"link_to": "File", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"is_query_report": 0, | |||
"label": "Assignment Rule", | |||
"link_to": "Assignment Rule", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"is_query_report": 0, | |||
"label": "Auto Repeat", | |||
"link_to": "Auto Repeat", | |||
"type": "DocType" | |||
} | |||
@@ -1,4 +1,5 @@ | |||
{ | |||
"actions": [], | |||
"allow_events_in_timeline": 1, | |||
"allow_import": 1, | |||
"allow_rename": 1, | |||
@@ -115,6 +116,7 @@ | |||
"label": "Phone", | |||
"oldfieldname": "contact_no", | |||
"oldfieldtype": "Data", | |||
"options": "Phone", | |||
"read_only": 1 | |||
}, | |||
{ | |||
@@ -200,6 +202,7 @@ | |||
"fieldname": "mobile_no", | |||
"fieldtype": "Data", | |||
"label": "Mobile No", | |||
"options": "Phone", | |||
"read_only": 1 | |||
}, | |||
{ | |||
@@ -245,7 +248,8 @@ | |||
"icon": "fa fa-user", | |||
"idx": 1, | |||
"image_field": "image", | |||
"modified": "2019-10-10 22:04:41.070479", | |||
"links": [], | |||
"modified": "2020-04-06 18:25:28.223693", | |||
"modified_by": "Administrator", | |||
"module": "Contacts", | |||
"name": "Contact", | |||
@@ -1,4 +1,5 @@ | |||
{ | |||
"actions": [], | |||
"creation": "2019-08-02 13:10:37.890214", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
@@ -14,6 +15,7 @@ | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Number", | |||
"options": "Phone", | |||
"reqd": 1 | |||
}, | |||
{ | |||
@@ -34,7 +36,8 @@ | |||
} | |||
], | |||
"istable": 1, | |||
"modified": "2019-09-24 17:47:50.375326", | |||
"links": [], | |||
"modified": "2020-04-06 18:28:10.486220", | |||
"modified_by": "Administrator", | |||
"module": "Contacts", | |||
"name": "Contact Phone", | |||
@@ -1,37 +1,37 @@ | |||
{ | |||
"cards": [ | |||
{ | |||
"icon": "fa fa-th", | |||
"links": "[\n {\n \"description\": \"Import Data from CSV / Excel files.\",\n \"icon\": \"octicon octicon-cloud-upload\",\n \"label\": \"Import Data\",\n \"name\": \"Data Import\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Export Data in CSV / Excel format.\",\n \"icon\": \"octicon octicon-cloud-upload\",\n \"label\": \"Export Data\",\n \"name\": \"Data Export\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Update many values at one time.\",\n \"hide_count\": true,\n \"label\": \"Bulk Update\",\n \"name\": \"Bulk Update\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"List of backups available for download\",\n \"icon\": \"fa fa-download\",\n \"label\": \"Download Backups\",\n \"name\": \"backups\",\n \"type\": \"page\"\n },\n {\n \"description\": \"Restore or permanently delete a document.\",\n \"label\": \"Deleted Documents\",\n \"name\": \"Deleted Document\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Data" | |||
"hidden": 0, | |||
"label": "Data", | |||
"links": "[\n {\n \"description\": \"Import Data from CSV / Excel files.\",\n \"icon\": \"octicon octicon-cloud-upload\",\n \"label\": \"Import Data\",\n \"name\": \"Data Import\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Export Data in CSV / Excel format.\",\n \"icon\": \"octicon octicon-cloud-upload\",\n \"label\": \"Export Data\",\n \"name\": \"Data Export\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Update many values at one time.\",\n \"hide_count\": true,\n \"label\": \"Bulk Update\",\n \"name\": \"Bulk Update\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"List of backups available for download\",\n \"icon\": \"fa fa-download\",\n \"label\": \"Download Backups\",\n \"name\": \"backups\",\n \"type\": \"page\"\n },\n {\n \"description\": \"Restore or permanently delete a document.\",\n \"label\": \"Deleted Documents\",\n \"name\": \"Deleted Document\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"icon": "fa fa-envelope", | |||
"links": "[\n {\n \"description\": \"Add / Manage Email Accounts.\",\n \"label\": \"Email Account\",\n \"name\": \"Email Account\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Add / Manage Email Domains.\",\n \"label\": \"Email Domain\",\n \"name\": \"Email Domain\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Setup Notifications based on various criteria.\",\n \"label\": \"Notification\",\n \"name\": \"Notification\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Email Templates for common queries.\",\n \"label\": \"Email Template\",\n \"name\": \"Email Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Setup Reports to be emailed at regular intervals\",\n \"label\": \"Auto Email Report\",\n \"name\": \"Auto Email Report\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Create and manage newsletter\",\n \"label\": \"Newsletter\",\n \"name\": \"Newsletter\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Configure notifications for mentions, assignments, energy points and more.\",\n \"label\": \"Notification Settings\",\n \"name\": \"Notification Settings\",\n \"route\": \"Form/Notification Settings/Administrator\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Email / Notifications" | |||
"hidden": 0, | |||
"label": "Email / Notifications", | |||
"links": "[\n {\n \"description\": \"Add / Manage Email Accounts.\",\n \"label\": \"Email Account\",\n \"name\": \"Email Account\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Add / Manage Email Domains.\",\n \"label\": \"Email Domain\",\n \"name\": \"Email Domain\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Setup Notifications based on various criteria.\",\n \"label\": \"Notification\",\n \"name\": \"Notification\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Email Templates for common queries.\",\n \"label\": \"Email Template\",\n \"name\": \"Email Template\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Setup Reports to be emailed at regular intervals\",\n \"label\": \"Auto Email Report\",\n \"name\": \"Auto Email Report\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Create and manage newsletter\",\n \"label\": \"Newsletter\",\n \"name\": \"Newsletter\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Configure notifications for mentions, assignments, energy points and more.\",\n \"label\": \"Notification Settings\",\n \"name\": \"Notification Settings\",\n \"route\": \"Form/Notification Settings/Administrator\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"icon": "fa fa-globe", | |||
"links": "[\n {\n \"description\": \"Setup of top navigation bar, footer and logo.\",\n \"label\": \"Website Settings\",\n \"name\": \"Website Settings\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"List of themes for Website.\",\n \"label\": \"Website Theme\",\n \"name\": \"Website Theme\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Javascript to append to the head section of the page.\",\n \"label\": \"Website Script\",\n \"name\": \"Website Script\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Settings for About Us Page.\",\n \"label\": \"About Us Settings\",\n \"name\": \"About Us Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Settings for Contact Us Page.\",\n \"label\": \"Contact Us Settings\",\n \"name\": \"Contact Us Settings\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Website" | |||
"hidden": 0, | |||
"label": "Website", | |||
"links": "[\n {\n \"description\": \"Setup of top navigation bar, footer and logo.\",\n \"label\": \"Website Settings\",\n \"name\": \"Website Settings\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"List of themes for Website.\",\n \"label\": \"Website Theme\",\n \"name\": \"Website Theme\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Javascript to append to the head section of the page.\",\n \"label\": \"Website Script\",\n \"name\": \"Website Script\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Settings for About Us Page.\",\n \"label\": \"About Us Settings\",\n \"name\": \"About Us Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Settings for Contact Us Page.\",\n \"label\": \"Contact Us Settings\",\n \"name\": \"Contact Us Settings\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"icon": "fa fa-wrench", | |||
"links": "[\n {\n \"description\": \"Language, Date and Time settings\",\n \"hide_count\": true,\n \"label\": \"System Settings\",\n \"name\": \"System Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Log of error on automated events (scheduler).\",\n \"label\": \"Error Log\",\n \"name\": \"Error Log\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Log of error during requests.\",\n \"label\": \"Error Snapshot\",\n \"name\": \"Error Snapshot\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Enable / Disable Domains\",\n \"hide_count\": true,\n \"label\": \"Domain Settings\",\n \"name\": \"Domain Settings\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Core" | |||
"hidden": 0, | |||
"label": "Core", | |||
"links": "[\n {\n \"description\": \"Language, Date and Time settings\",\n \"hide_count\": true,\n \"label\": \"System Settings\",\n \"name\": \"System Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Log of error on automated events (scheduler).\",\n \"label\": \"Error Log\",\n \"name\": \"Error Log\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Log of error during requests.\",\n \"label\": \"Error Snapshot\",\n \"name\": \"Error Snapshot\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Enable / Disable Domains\",\n \"hide_count\": true,\n \"label\": \"Domain Settings\",\n \"name\": \"Domain Settings\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"icon": "fa fa-print", | |||
"links": "[\n {\n \"description\": \"Drag and Drop tool to build and customize Print Formats.\",\n \"label\": \"Print Format Builder\",\n \"name\": \"print-format-builder\",\n \"type\": \"page\"\n },\n {\n \"description\": \"Set default format, page size, print style etc.\",\n \"label\": \"Print Settings\",\n \"name\": \"Print Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Customized HTML Templates for printing transactions.\",\n \"label\": \"Print Format\",\n \"name\": \"Print Format\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Stylesheets for Print Formats\",\n \"label\": \"Print Style\",\n \"name\": \"Print Style\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Printing" | |||
"hidden": 0, | |||
"label": "Printing", | |||
"links": "[\n {\n \"description\": \"Drag and Drop tool to build and customize Print Formats.\",\n \"label\": \"Print Format Builder\",\n \"name\": \"print-format-builder\",\n \"type\": \"page\"\n },\n {\n \"description\": \"Set default format, page size, print style etc.\",\n \"label\": \"Print Settings\",\n \"name\": \"Print Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Customized HTML Templates for printing transactions.\",\n \"label\": \"Print Format\",\n \"name\": \"Print Format\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Stylesheets for Print Formats\",\n \"label\": \"Print Style\",\n \"name\": \"Print Style\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"icon": "fa fa-random", | |||
"links": "[\n {\n \"description\": \"Define workflows for forms.\",\n \"label\": \"Workflow\",\n \"name\": \"Workflow\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"States for workflow (e.g. Draft, Approved, Cancelled).\",\n \"label\": \"Workflow State\",\n \"name\": \"Workflow State\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Actions for workflow (e.g. Approve, Cancel).\",\n \"label\": \"Workflow Action\",\n \"name\": \"Workflow Action\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Workflow" | |||
"hidden": 0, | |||
"label": "Workflow", | |||
"links": "[\n {\n \"description\": \"Define workflows for forms.\",\n \"label\": \"Workflow\",\n \"name\": \"Workflow\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"States for workflow (e.g. Draft, Approved, Cancelled).\",\n \"label\": \"Workflow State\",\n \"name\": \"Workflow State\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Actions for workflow (e.g. Approve, Cancel).\",\n \"label\": \"Workflow Action\",\n \"name\": \"Workflow Action\",\n \"type\": \"doctype\"\n }\n]" | |||
} | |||
], | |||
"category": "Administration", | |||
"category": "Modules", | |||
"charts": [], | |||
"creation": "2020-03-02 15:09:40.527211", | |||
"developer_mode_only": 0, | |||
@@ -42,29 +42,29 @@ | |||
"idx": 0, | |||
"is_standard": 1, | |||
"label": "Settings", | |||
"modified": "2020-03-12 16:30:43.510434", | |||
"modified": "2020-04-01 11:24:40.636747", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "Settings", | |||
"owner": "Administrator", | |||
"pin_to_bottom": 0, | |||
"pin_to_top": 1, | |||
"pin_to_bottom": 1, | |||
"pin_to_top": 0, | |||
"shortcuts": [ | |||
{ | |||
"icon": "octicon octicon-settings", | |||
"is_query_report": 0, | |||
"label": "System Settings", | |||
"link_to": "System Settings", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"icon": "fa fa-print", | |||
"is_query_report": 0, | |||
"label": "Print Settings", | |||
"link_to": "Print Settings", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"icon": "fa fa-globe", | |||
"is_query_report": 0, | |||
"label": "Website Settings", | |||
"link_to": "Website Settings", | |||
"type": "DocType" | |||
} | |||
@@ -1,19 +1,19 @@ | |||
{ | |||
"cards": [ | |||
{ | |||
"icon": "fa fa-group", | |||
"links": "[\n {\n \"description\": \"System and Website Users\",\n \"label\": \"User\",\n \"name\": \"User\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"User Roles\",\n \"label\": \"Role\",\n \"name\": \"Role\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Role Profile\",\n \"label\": \"Role Profile\",\n \"name\": \"Role Profile\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Users" | |||
"hidden": 0, | |||
"label": "Users", | |||
"links": "[\n {\n \"description\": \"System and Website Users\",\n \"label\": \"User\",\n \"name\": \"User\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"User Roles\",\n \"label\": \"Role\",\n \"name\": \"Role\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Role Profile\",\n \"label\": \"Role Profile\",\n \"name\": \"Role Profile\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"icon": "fa fa-group", | |||
"links": "[\n {\n \"description\": \"Activity Log by \",\n \"label\": \"Activity Log\",\n \"name\": \"Activity Log\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"View Log of all print, download and export events\",\n \"label\": \"Access Log\",\n \"name\": \"Access Log\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Logs" | |||
"hidden": 0, | |||
"label": "Logs", | |||
"links": "[\n {\n \"description\": \"Activity Log by \",\n \"label\": \"Activity Log\",\n \"name\": \"Activity Log\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"View Log of all print, download and export events\",\n \"label\": \"Access Log\",\n \"name\": \"Access Log\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"icon": "fa fa-lock", | |||
"links": "[\n {\n \"description\": \"Set Permissions on Document Types and Roles\",\n \"icon\": \"fa fa-lock\",\n \"label\": \"Role Permissions Manager\",\n \"name\": \"permission-manager\",\n \"type\": \"page\"\n },\n {\n \"description\": \"Restrict user for specific document\",\n \"icon\": \"fa fa-lock\",\n \"label\": \"User Permissions\",\n \"name\": \"User Permission\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Set custom roles for page and report\",\n \"label\": \"Role Permission for Page and Report\",\n \"name\": \"Role Permission for Page and Report\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"User\"\n ],\n \"description\": \"Check which Documents are readable by a User\",\n \"doctype\": \"User\",\n \"icon\": \"fa fa-eye-open\",\n \"is_query_report\": true,\n \"label\": \"Permitted Documents For User\",\n \"name\": \"Permitted Documents For User\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"DocShare\"\n ],\n \"description\": \"Report of all document shares\",\n \"doctype\": \"DocShare\",\n \"icon\": \"fa fa-share\",\n \"label\": \"Document Share Report\",\n \"name\": \"Document Share Report\",\n \"type\": \"report\"\n }\n]", | |||
"title": "Permissions" | |||
"hidden": 0, | |||
"label": "Permissions", | |||
"links": "[\n {\n \"description\": \"Set Permissions on Document Types and Roles\",\n \"icon\": \"fa fa-lock\",\n \"label\": \"Role Permissions Manager\",\n \"name\": \"permission-manager\",\n \"type\": \"page\"\n },\n {\n \"description\": \"Restrict user for specific document\",\n \"icon\": \"fa fa-lock\",\n \"label\": \"User Permissions\",\n \"name\": \"User Permission\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Set custom roles for page and report\",\n \"label\": \"Role Permission for Page and Report\",\n \"name\": \"Role Permission for Page and Report\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"User\"\n ],\n \"description\": \"Check which Documents are readable by a User\",\n \"doctype\": \"User\",\n \"icon\": \"fa fa-eye-open\",\n \"is_query_report\": true,\n \"label\": \"Permitted Documents For User\",\n \"name\": \"Permitted Documents For User\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"DocShare\"\n ],\n \"description\": \"Report of all document shares\",\n \"doctype\": \"DocShare\",\n \"icon\": \"fa fa-share\",\n \"label\": \"Document Share Report\",\n \"name\": \"Document Share Report\",\n \"type\": \"report\"\n }\n]" | |||
} | |||
], | |||
"category": "Administration", | |||
@@ -27,7 +27,7 @@ | |||
"idx": 0, | |||
"is_standard": 1, | |||
"label": "Users", | |||
"modified": "2020-03-12 16:30:42.483376", | |||
"modified": "2020-04-01 11:24:40.767676", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "Users", | |||
@@ -36,22 +36,22 @@ | |||
"pin_to_top": 0, | |||
"shortcuts": [ | |||
{ | |||
"is_query_report": 0, | |||
"label": "User", | |||
"link_to": "User", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"is_query_report": 0, | |||
"label": "Role", | |||
"link_to": "Role", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"is_query_report": 0, | |||
"label": "permission-manager", | |||
"link_to": "permission-manager", | |||
"type": "Page" | |||
}, | |||
{ | |||
"is_query_report": 0, | |||
"label": "user-profile", | |||
"link_to": "user-profile", | |||
"type": "Page" | |||
} | |||
@@ -238,12 +238,14 @@ | |||
{ | |||
"fieldname": "phone", | |||
"fieldtype": "Data", | |||
"label": "Phone" | |||
"label": "Phone", | |||
"options": "Phone" | |||
}, | |||
{ | |||
"fieldname": "mobile_no", | |||
"fieldtype": "Data", | |||
"label": "Mobile No", | |||
"options": "Phone", | |||
"unique": 1 | |||
}, | |||
{ | |||
@@ -588,7 +590,7 @@ | |||
"image_field": "user_image", | |||
"links": [], | |||
"max_attachments": 5, | |||
"modified": "2020-03-23 22:59:26.154985", | |||
"modified": "2020-04-08 12:27:36.716490", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "User", | |||
@@ -205,7 +205,7 @@ class User(Document): | |||
_update_password(user=self.name, pwd=new_password, | |||
logout_all_sessions=self.logout_all_sessions) | |||
if not self.flags.no_welcome_mail and self.send_welcome_email: | |||
if not self.flags.no_welcome_mail and cint(self.send_welcome_email): | |||
self.send_welcome_mail_to_user() | |||
self.flags.email_sent = 1 | |||
if frappe.session.user != 'Guest': | |||
@@ -577,7 +577,7 @@ def update_password(new_password, logout_all_sessions=0, key=None, old_password= | |||
return redirect_url if redirect_url else "/" | |||
@frappe.whitelist(allow_guest=True) | |||
def test_password_strength(new_password, key=None, old_password=None, user_data=[]): | |||
def test_password_strength(new_password, key=None, old_password=None, user_data=None): | |||
from frappe.utils.password_strength import test_password_strength as _test_password_strength | |||
password_policy = frappe.db.get_value("System Settings", None, | |||
@@ -1,201 +1,63 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_guest_to_view": 0, | |||
"allow_import": 0, | |||
"allow_rename": 0, | |||
"beta": 0, | |||
"creation": "2016-03-30 10:04:25.828742", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "", | |||
"editable_grid": 1, | |||
"actions": [], | |||
"creation": "2016-03-30 10:04:25.828742", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"email_account", | |||
"email_id", | |||
"column_break_3", | |||
"awaiting_password", | |||
"enable_outgoing" | |||
], | |||
"fields": [ | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "email_account", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 0, | |||
"label": "Email Account", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Email Account", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "email_account", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"label": "Email Account", | |||
"options": "Email Account", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fetch_from": "email_account.email_id", | |||
"fieldname": "email_id", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Email ID", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 1, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "email_id", | |||
"fieldtype": "Data", | |||
"label": "Email ID", | |||
"options": "Email", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_3", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "column_break_3", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fetch_from": "email_account.awaiting_password", | |||
"fieldname": "awaiting_password", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 0, | |||
"label": "Awaiting Password", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 1, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"default": "0", | |||
"fetch_from": "email_account.awaiting_password", | |||
"fieldname": "awaiting_password", | |||
"fieldtype": "Check", | |||
"in_list_view": 1, | |||
"label": "Awaiting Password", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fetch_from": "email_account.enable_outgoing", | |||
"fieldname": "enable_outgoing", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Enable Outgoing", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 1, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
"default": "0", | |||
"fetch_from": "email_account.enable_outgoing", | |||
"fieldname": "enable_outgoing", | |||
"fieldtype": "Check", | |||
"label": "Enable Outgoing", | |||
"read_only": 1 | |||
} | |||
], | |||
"has_web_view": 0, | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 1, | |||
"max_attachments": 0, | |||
"modified": "2018-05-25 22:43:34.045787", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "User Email", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
"permissions": [], | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"show_name_in_global_search": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 0, | |||
"track_seen": 0 | |||
], | |||
"istable": 1, | |||
"links": [], | |||
"modified": "2020-04-06 19:19:12.130246", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "User Email", | |||
"owner": "Administrator", | |||
"permissions": [], | |||
"sort_field": "modified", | |||
"sort_order": "DESC" | |||
} |
@@ -97,7 +97,13 @@ class Dashboard { | |||
container: this.container, | |||
type: "chart", | |||
columns: 2, | |||
allow_sorting: false, | |||
options: { | |||
allow_sorting: false, | |||
allow_create: false, | |||
allow_delete: false, | |||
allow_hiding: false, | |||
allow_edit: false, | |||
}, | |||
widgets: this.charts, | |||
}); | |||
}) | |||
@@ -1,17 +1,19 @@ | |||
{ | |||
"cards": [ | |||
{ | |||
"links": "[\n {\n \"label\": \"Dashboard\",\n \"name\": \"Dashboard\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Dashboard Chart\",\n \"name\": \"Dashboard Chart\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Dashboard Chart Source\",\n \"name\": \"Dashboard Chart Source\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Dashboards" | |||
"hidden": 0, | |||
"label": "Dashboards", | |||
"links": "[\n {\n \"label\": \"Dashboard\",\n \"name\": \"Dashboard\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Dashboard Chart\",\n \"name\": \"Dashboard Chart\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Dashboard Chart Source\",\n \"name\": \"Dashboard Chart Source\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"icon": "fa fa-glass", | |||
"links": "[\n {\n \"description\": \"Change field properties (hide, readonly, permission etc.)\",\n \"label\": \"Customize Form\",\n \"name\": \"Customize Form\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Add fields to forms.\",\n \"label\": \"Custom Field\",\n \"name\": \"Custom Field\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Add custom javascript to forms.\",\n \"label\": \"Custom Script\",\n \"name\": \"Custom Script\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Add custom forms.\",\n \"label\": \"DocType\",\n \"name\": \"DocType\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Form Customization" | |||
"hidden": 0, | |||
"label": "Form Customization", | |||
"links": "[\n {\n \"description\": \"Change field properties (hide, readonly, permission etc.)\",\n \"label\": \"Customize Form\",\n \"name\": \"Customize Form\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Add fields to forms.\",\n \"label\": \"Custom Field\",\n \"name\": \"Custom Field\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Add custom javascript to forms.\",\n \"label\": \"Custom Script\",\n \"name\": \"Custom Script\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Add custom forms.\",\n \"label\": \"DocType\",\n \"name\": \"DocType\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"links": "[\n {\n \"description\": \"Add your own translations\",\n \"label\": \"Custom Translations\",\n \"name\": \"Translation\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Other" | |||
"hidden": 0, | |||
"label": "Other", | |||
"links": "[\n {\n \"description\": \"Add your own translations\",\n \"label\": \"Custom Translations\",\n \"name\": \"Translation\",\n \"type\": \"doctype\"\n }\n]" | |||
} | |||
], | |||
"category": "Administration", | |||
@@ -25,7 +27,7 @@ | |||
"idx": 0, | |||
"is_standard": 1, | |||
"label": "Customization", | |||
"modified": "2020-03-12 16:30:42.155206", | |||
"modified": "2020-04-01 11:24:40.787109", | |||
"modified_by": "Administrator", | |||
"module": "Custom", | |||
"name": "Customization", | |||
@@ -34,17 +36,17 @@ | |||
"pin_to_top": 0, | |||
"shortcuts": [ | |||
{ | |||
"is_query_report": 0, | |||
"label": "Customize Form", | |||
"link_to": "Customize Form", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"is_query_report": 0, | |||
"label": "Custom Role", | |||
"link_to": "Custom Role", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"is_query_report": 0, | |||
"label": "Custom Script", | |||
"link_to": "Custom Script", | |||
"type": "DocType" | |||
} | |||
@@ -358,7 +358,7 @@ | |||
"default": "0", | |||
"fieldname": "allow_in_quick_entry", | |||
"fieldtype": "Check", | |||
"label": " Allow in Quick Entry " | |||
"label": "Allow in Quick Entry" | |||
}, | |||
{ | |||
"fieldname": "property_depends_on_section", | |||
@@ -385,7 +385,7 @@ | |||
"idx": 1, | |||
"istable": 1, | |||
"links": [], | |||
"modified": "2020-03-16 14:53:40.619043", | |||
"modified": "2020-04-07 14:53:40.619043", | |||
"modified_by": "Administrator", | |||
"module": "Custom", | |||
"name": "Customize Form Field", | |||
@@ -4,24 +4,34 @@ | |||
from __future__ import unicode_literals | |||
import frappe | |||
import json | |||
from frappe import _, DoesNotExistError | |||
from json import loads, dumps | |||
from frappe import _, DoesNotExistError, ValidationError, _dict | |||
from frappe.boot import get_allowed_pages, get_allowed_reports | |||
from six import string_types | |||
from frappe.cache_manager import build_domain_restriced_doctype_cache, build_domain_restriced_page_cache, build_table_count_cache | |||
from frappe.cache_manager import ( | |||
build_domain_restriced_doctype_cache, | |||
build_domain_restriced_page_cache, | |||
build_table_count_cache | |||
) | |||
class Workspace: | |||
def __init__(self, page_name): | |||
self.page_name = page_name | |||
def build_cache(self): | |||
self.doc = frappe.get_doc("Desk Page", self.page_name) | |||
self.get_pages_to_extend() | |||
self.extended_cards = [] | |||
self.extended_charts = [] | |||
self.extended_shortcuts = [] | |||
user = frappe.get_user() | |||
user.build_permissions() | |||
self.user = user | |||
user_doc = frappe.get_doc('User', frappe.session.user) | |||
self.blocked_modules = user_doc.get_blocked_modules() | |||
self.doc = self.get_page_for_user() | |||
if self.doc.module in self.blocked_modules: | |||
raise frappe.PermissionError | |||
self.user = user | |||
self.allowed_pages = get_allowed_pages() | |||
self.allowed_reports = get_allowed_reports() | |||
@@ -29,16 +39,27 @@ class Workspace: | |||
self.restricted_doctypes = build_domain_restriced_doctype_cache() | |||
self.restricted_pages = build_domain_restriced_page_cache() | |||
def get_page_for_user(self): | |||
filters = { | |||
'extends': self.page_name, | |||
'for_user': frappe.session.user | |||
} | |||
pages = frappe.get_list("Desk Page", filters=filters) | |||
if pages: | |||
return frappe.get_doc("Desk Page", pages[0]) | |||
self.get_pages_to_extend() | |||
return frappe.get_doc("Desk Page", self.page_name) | |||
def get_pages_to_extend(self): | |||
pages = frappe.get_all("Desk Page", filters={ | |||
"extends": self.page_name, | |||
'restrict_to_domain': ['in', frappe.get_active_domains()] | |||
'restrict_to_domain': ['in', frappe.get_active_domains()], | |||
'for_user': '', | |||
'module': ['not in', self.blocked_modules] | |||
}) | |||
pages = [frappe.get_doc("Desk Page", page['name']) for page in pages] | |||
self.extended_cards = [] | |||
self.extended_charts = [] | |||
self.extended_shortcuts = [] | |||
for page in pages: | |||
self.extended_cards = self.extended_cards + page.cards | |||
@@ -61,17 +82,17 @@ class Workspace: | |||
def build_workspace(self): | |||
self.cards = { | |||
'label': self.doc.cards_label, | |||
'label': _(self.doc.cards_label), | |||
'items': self.get_cards() | |||
} | |||
self.charts = { | |||
'label': self.doc.charts_label, | |||
'label': _(self.doc.charts_label), | |||
'items': self.get_charts() | |||
} | |||
self.shortcuts = { | |||
'label': self.doc.shortcuts_label, | |||
'label': _(self.doc.shortcuts_label), | |||
'items': self.get_shortcuts() | |||
} | |||
@@ -105,18 +126,21 @@ class Workspace: | |||
item["count"] = count | |||
# Translate label | |||
item["label"] = _(item.label) if item.label else _(item.name) | |||
return item | |||
new_data = [] | |||
for section in cards: | |||
new_items = [] | |||
if isinstance(section.links, string_types): | |||
links = json.loads(section.links) | |||
links = loads(section.links) | |||
else: | |||
links = section.links | |||
for item in links: | |||
item = frappe._dict(item) | |||
item = _dict(item) | |||
# Condition: based on country | |||
if item.country and item.country != default_country: | |||
@@ -125,15 +149,15 @@ class Workspace: | |||
# Check if user is allowed to view | |||
if self.is_item_allowed(item.name, item.type): | |||
prepared_item = _prepare_item(item) | |||
new_items.append(item) | |||
new_items.append(prepared_item) | |||
if new_items: | |||
if isinstance(section, frappe._dict): | |||
if isinstance(section, _dict): | |||
new_section = section.copy() | |||
else: | |||
new_section = section.as_dict().copy() | |||
new_section["links"] = new_items | |||
new_section["label"] = section.title | |||
new_section["label"] = _(new_section["label"]) | |||
new_data.append(new_section) | |||
return new_data | |||
@@ -147,7 +171,8 @@ class Workspace: | |||
for chart in charts: | |||
if frappe.has_permission('Dashboard Chart', doc=chart.chart_name): | |||
chart.label = chart.label if chart.label else chart.chart_name | |||
# Translate label | |||
chart.label = _(chart.label) if chart.label else _(chart.chart_name) | |||
all_charts.append(chart) | |||
return all_charts | |||
@@ -167,21 +192,23 @@ class Workspace: | |||
for item in shortcuts: | |||
new_item = item.as_dict().copy() | |||
new_item['name'] = _(item.link_to) | |||
if self.is_item_allowed(item.link_to, item.type) and _in_active_domains(item): | |||
if item.type == "Page": | |||
page = self.allowed_pages[item.link_to] | |||
new_item['label'] = _(page.get("title", frappe.unscrub(item.link_to))) | |||
if item.type == "Report": | |||
report = self.allowed_reports.get(item.link_to, {}) | |||
if report.get("report_type") in ["Query Report", "Script Report"]: | |||
new_item['is_query_report'] = 1 | |||
else: | |||
new_item['ref_doctype'] = report.get('ref_doctype') | |||
# Translate label | |||
new_item["label"] = _(item.label) if item.label else _(item.link_to) | |||
items.append(new_item) | |||
return items | |||
@frappe.whitelist() | |||
@frappe.read_only() | |||
def get_desktop_page(page): | |||
"""Applies permissions, customizations and returns the configruration for a page | |||
on desk. | |||
@@ -192,9 +219,8 @@ def get_desktop_page(page): | |||
Returns: | |||
dict: dictionary of cards, charts and shortcuts to be displayed on website | |||
""" | |||
wspace = Workspace(page) | |||
try: | |||
wspace.build_cache() | |||
wspace = Workspace(page) | |||
wspace.build_workspace() | |||
return { | |||
'charts': wspace.charts, | |||
@@ -213,9 +239,14 @@ def get_desk_sidebar_items(): | |||
"""Get list of sidebar items for desk | |||
""" | |||
# don't get domain restricted pages | |||
blocked_modules = frappe.get_doc('User', frappe.session.user).get_blocked_modules() | |||
filters = { | |||
'restrict_to_domain': ['in', frappe.get_active_domains()], | |||
'extends_another_page': False | |||
'extends_another_page': 0, | |||
'is_standard': 1, | |||
'for_user': '', | |||
'module': ['not in', blocked_modules] | |||
} | |||
if not frappe.local.conf.developer_mode: | |||
@@ -228,8 +259,10 @@ def get_desk_sidebar_items(): | |||
from collections import defaultdict | |||
sidebar_items = defaultdict(list) | |||
# The order will be maintained while categorizing | |||
for page in pages: | |||
# The order will be maintained while categorizing | |||
# Translate label | |||
page['label'] = _(page.get('name')) | |||
sidebar_items[page["category"]].append(page) | |||
return sidebar_items | |||
@@ -242,8 +275,8 @@ def get_table_with_counts(): | |||
def get_custom_reports_and_doctypes(module): | |||
return [ | |||
frappe._dict({ | |||
"title": "Custom", | |||
_dict({ | |||
"label": "Custom", | |||
"links": get_custom_doctype_list(module) + get_custom_report_list(module) | |||
}) | |||
] | |||
@@ -280,104 +313,111 @@ def get_custom_report_list(module): | |||
return out | |||
def make_them_pages(): | |||
"""Helper function to make pages | |||
""" | |||
pages = [ | |||
('Desk', 'frappe', 'octicon octicon-calendar'), | |||
('Settings', 'frappe', 'octicon octicon-settings'), | |||
('Users and Permissions', 'frappe', 'octicon octicon-settings'), | |||
('Customization', 'frappe', 'octicon octicon-settings'), | |||
('Integrations', 'frappe', 'octicon octicon-globe'), | |||
('Core', 'frappe', 'octicon octicon-circuit-board'), | |||
('Website', 'frappe', 'octicon octicon-globe'), | |||
('Getting Started', 'erpnext', 'fa fa-check-square-o'), | |||
('Accounts', 'erpnext', 'octicon octicon-repo'), | |||
('Selling', 'erpnext', 'octicon octicon-tag'), | |||
('Buying', 'erpnext', 'octicon octicon-briefcase'), | |||
('Stock', 'erpnext', 'octicon octicon-package'), | |||
('Assets', 'erpnext', 'octicon octicon-database'), | |||
('Projects', 'erpnext', 'octicon octicon-rocket'), | |||
('CRM', 'erpnext', 'octicon octicon-broadcast'), | |||
('Support', 'erpnext', 'fa fa-check-square-o'), | |||
('HR', 'erpnext', 'octicon octicon-organization'), | |||
('Quality Management', 'erpnext', 'fa fa-check-square-o'), | |||
('Manufacturing', 'erpnext', 'octicon octicon-tools'), | |||
('Retail', 'erpnext', 'octicon octicon-credit-card'), | |||
('Education', 'erpnext', 'octicon octicon-mortar-board'), | |||
('Healthcare', 'erpnext', 'fa fa-heartbeat'), | |||
('Agriculture', 'erpnext', 'octicon octicon-globe'), | |||
('Non Profit', 'erpnext', 'octicon octicon-heart'), | |||
('Help', 'erpnext', 'octicon octicon-device-camera-video') | |||
] | |||
def get_custom_workspace_for_user(page): | |||
"""Get custom page from desk_page if exists or create one | |||
for page in pages: | |||
print("Processing Page: {0}".format(page[0])) | |||
make_them_cards(page[0], page[2]) | |||
Args: | |||
page (stirng): Page name | |||
Returns: | |||
Object: Document object | |||
""" | |||
filters = { | |||
'extends': page, | |||
'for_user': frappe.session.user | |||
} | |||
pages = frappe.get_list("Desk Page", filters=filters) | |||
if pages: | |||
return frappe.get_doc("Desk Page", pages[0]) | |||
doc = frappe.new_doc("Desk Page") | |||
doc.extends = page | |||
doc.for_user = frappe.session.user | |||
return doc | |||
def make_them_cards(page_name, from_module=None, to_module=None, icon=None): | |||
from frappe.desk.moduleview import get | |||
@frappe.whitelist() | |||
def save_customization(page, config): | |||
"""Save customizations as a separate doctype in Desk page per user | |||
if not from_module: | |||
from_module = page_name | |||
Args: | |||
page (string): Name of the page to be edited | |||
config (dict): Dictionary config of al widgets | |||
if not to_module: | |||
to_module = page_name | |||
Returns: | |||
Boolean: Customization saving status | |||
""" | |||
original_page = frappe.get_doc("Desk Page", page) | |||
page_doc = get_custom_workspace_for_user(page) | |||
# Update field values | |||
page_doc.update({ | |||
"charts_label": original_page.charts_label, | |||
"cards_label": original_page.cards_label, | |||
"shortcuts_label": original_page.shortcuts_label, | |||
"icon": original_page.icon, | |||
"module": original_page.module, | |||
"developer_mode_only": original_page.developer_mode_only, | |||
"category": original_page.category | |||
}) | |||
config = _dict(loads(config)) | |||
page_doc.charts = prepare_widget(config.charts, "Desk Chart", "charts") | |||
page_doc.shortcuts = prepare_widget(config.shortcuts, "Desk Shortcut", "shortcuts") | |||
page_doc.cards = prepare_widget(config.cards, "Desk Card", "cards") | |||
# Set label | |||
page_doc.label = page + '-' + frappe.session.user | |||
try: | |||
modules = get(from_module)['data'] | |||
except: | |||
return | |||
# Find or make page doc | |||
if frappe.db.exists("Desk Page", page_name): | |||
page = frappe.get_doc("Desk Page", page_name) | |||
print("--- Got Page: {0}".format(page.name)) | |||
else: | |||
page = frappe.new_doc("Desk Page") | |||
page.label = page_name | |||
page.cards = [] | |||
page.icon = icon | |||
print("--- New Page: {0}".format(page.name)) | |||
# Guess Which Module | |||
if not to_module and frappe.db.exists("Module Def", page_name): | |||
page.module = page_name | |||
if to_module: | |||
page.module = to_module | |||
elif frappe.db.exists("Module Def", page_name): | |||
page.module = page_name | |||
for data in modules: | |||
# Create a New Card Child Doc | |||
card = frappe.new_doc("Desk Card") | |||
# Data clean up | |||
for item in data['items']: | |||
try: | |||
del item['count'] | |||
del item['incomplete_dependencies'] | |||
except KeyError: | |||
pass | |||
# Set Child doc values | |||
card.title = data['label'] | |||
card.icon = data.get('icon') | |||
# Pretty dump JSON | |||
card.links = json.dumps(data['items'], indent=4, sort_keys=True) | |||
# Set Parent attributes | |||
card.parent = page.name | |||
card.parenttype = page.doctype | |||
card.parentfield = "cards" | |||
# Add cards to page doc | |||
print("------- Adding Card: {0}".format(card.title)) | |||
page.cards.append(card) | |||
# End it all | |||
page.save() | |||
frappe.db.commit() | |||
return | |||
if page_doc.is_new(): | |||
page_doc.insert(ignore_permissions=True) | |||
else: | |||
page_doc.save(ignore_permissions=True) | |||
except (ValidationError, TypeError) as e: | |||
# Create a json string to log | |||
json_config = dumps(config, sort_keys=True, indent=4) | |||
# Error log body | |||
log = \ | |||
""" | |||
page: {0} | |||
config: {1} | |||
exception: {2} | |||
""".format(page, json_config, e) | |||
frappe.log_error(log, _("Could not save customization")) | |||
return False | |||
return True | |||
def prepare_widget(config, doctype, parentfield): | |||
"""Create widget child table entries with parent details | |||
Args: | |||
config (dict): Dictionary containing widget config | |||
doctype (string): Doctype name of the child table | |||
parentfield (string): Parent field for the child table | |||
Returns: | |||
TYPE: List of Document objects | |||
""" | |||
order = config.get('order') | |||
widgets = config.get('widgets') | |||
prepare_widget_list = [] | |||
for idx, name in enumerate(order): | |||
wid_config = widgets[name].copy() | |||
# Some cleanup | |||
wid_config.pop("name", None) | |||
# New Doc | |||
doc = frappe.new_doc(doctype) | |||
doc.update(wid_config) | |||
# Manually Set IDX | |||
doc.idx = idx + 1 | |||
# Set Parent Field | |||
doc.parentfield = parentfield | |||
prepare_widget_list.append(doc) | |||
return prepare_widget_list |
@@ -49,7 +49,8 @@ | |||
"fieldname": "chart_type", | |||
"fieldtype": "Select", | |||
"label": "Chart Type", | |||
"options": "Count\nSum\nAverage\nGroup By\nCustom\nReport" | |||
"options": "Count\nSum\nAverage\nGroup By\nCustom\nReport", | |||
"set_only_once": 1 | |||
}, | |||
{ | |||
"depends_on": "eval:doc.chart_type === 'Custom'", | |||
@@ -215,7 +216,7 @@ | |||
} | |||
], | |||
"links": [], | |||
"modified": "2020-03-31 16:00:01.987059", | |||
"modified": "2020-04-08 18:54:36.739183", | |||
"modified_by": "Administrator", | |||
"module": "Desk", | |||
"name": "Dashboard Chart", | |||
@@ -2,11 +2,12 @@ | |||
"actions": [], | |||
"creation": "2020-01-29 14:45:54.383089", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"title", | |||
"label", | |||
"column_break_2", | |||
"icon", | |||
"hidden", | |||
"section_break_3", | |||
"links" | |||
], | |||
@@ -18,13 +19,6 @@ | |||
"options": "JSON", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "title", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Title", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "section_break_3", | |||
"fieldtype": "Section Break" | |||
@@ -34,14 +28,23 @@ | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"fieldname": "icon", | |||
"default": "0", | |||
"fieldname": "hidden", | |||
"fieldtype": "Check", | |||
"in_list_view": 1, | |||
"label": "Hidden" | |||
}, | |||
{ | |||
"fieldname": "label", | |||
"fieldtype": "Data", | |||
"label": "Icon" | |||
"in_list_view": 1, | |||
"label": "Label", | |||
"reqd": 1 | |||
} | |||
], | |||
"istable": 1, | |||
"links": [], | |||
"modified": "2020-02-03 12:40:42.595122", | |||
"modified": "2020-03-31 14:38:06.303847", | |||
"modified_by": "Administrator", | |||
"module": "Desk", | |||
"name": "Desk Card", | |||
@@ -26,7 +26,7 @@ | |||
], | |||
"istable": 1, | |||
"links": [], | |||
"modified": "2020-03-20 10:04:13.992228", | |||
"modified": "2020-03-31 13:33:13.128804", | |||
"modified_by": "Administrator", | |||
"module": "Desk", | |||
"name": "Desk Chart", | |||
@@ -2,17 +2,21 @@ | |||
// For license information, please see license.txt | |||
frappe.ui.form.on('Desk Page', { | |||
refresh: function(frm) { | |||
setup: function(frm) { | |||
frm.get_field("is_standard").toggle(frappe.boot.developer_mode); | |||
frm.get_field("extends_another_page").toggle(frappe.boot.developer_mode); | |||
if (!frappe.boot.developer_mode) { | |||
frm.set_read_only(); | |||
frm.fields | |||
.filter(field => field.has_input) | |||
.forEach(field => { | |||
frm.set_df_property(field.df.fieldname, "read_only", "1"); | |||
}); | |||
frm.disable_save(); | |||
if (!frappe.boot.developer_mode || frm.doc.for_user) { | |||
frm.trigger('disable_form'); | |||
} | |||
}, | |||
disable_form: function(frm) { | |||
frm.set_read_only(); | |||
frm.fields | |||
.filter(field => field.has_input) | |||
.forEach(field => { | |||
frm.set_df_property(field.df.fieldname, "read_only", "1"); | |||
}); | |||
frm.disable_save(); | |||
} | |||
}); | |||
}); |
@@ -9,6 +9,7 @@ | |||
"field_order": [ | |||
"label", | |||
"extends", | |||
"for_user", | |||
"module", | |||
"category", | |||
"restrict_to_domain", | |||
@@ -36,7 +37,6 @@ | |||
"fieldname": "label", | |||
"fieldtype": "Data", | |||
"label": "Name", | |||
"length": 22, | |||
"unique": 1 | |||
}, | |||
{ | |||
@@ -52,6 +52,7 @@ | |||
"options": "Desk Chart" | |||
}, | |||
{ | |||
"depends_on": "eval:!doc.extends_another_page || !doc.is_standard", | |||
"fieldname": "shortcuts", | |||
"fieldtype": "Table", | |||
"label": "Shortcuts", | |||
@@ -136,16 +137,19 @@ | |||
"search_index": 1 | |||
}, | |||
{ | |||
"depends_on": "eval:!doc.extends_another_page || !doc.is_standard", | |||
"fieldname": "charts_label", | |||
"fieldtype": "Data", | |||
"label": "Label" | |||
}, | |||
{ | |||
"depends_on": "eval:!doc.extends_another_page || !doc.is_standard", | |||
"fieldname": "shortcuts_label", | |||
"fieldtype": "Data", | |||
"label": "Label" | |||
}, | |||
{ | |||
"depends_on": "eval:!doc.extends_another_page || !doc.is_standard", | |||
"fieldname": "cards_label", | |||
"fieldtype": "Data", | |||
"label": "Label" | |||
@@ -166,24 +170,36 @@ | |||
"default": "0", | |||
"fieldname": "is_standard", | |||
"fieldtype": "Check", | |||
"label": "Is Standard" | |||
"in_list_view": 1, | |||
"in_standard_filter": 1, | |||
"label": "Is Standard", | |||
"search_index": 1 | |||
}, | |||
{ | |||
"default": "0", | |||
"fieldname": "extends_another_page", | |||
"fieldtype": "Check", | |||
"label": "Extends Another Page" | |||
"label": "Extends Another Page", | |||
"search_index": 1 | |||
}, | |||
{ | |||
"depends_on": "eval:doc.extends_another_page == 1", | |||
"fieldname": "extends", | |||
"fieldtype": "Link", | |||
"in_standard_filter": 1, | |||
"label": "Extends", | |||
"options": "Desk Page" | |||
"options": "Desk Page", | |||
"search_index": 1 | |||
}, | |||
{ | |||
"fieldname": "for_user", | |||
"fieldtype": "Data", | |||
"label": "For User", | |||
"read_only": 1 | |||
} | |||
], | |||
"links": [], | |||
"modified": "2020-03-12 16:38:16.206732", | |||
"modified": "2020-03-26 12:35:41.981432", | |||
"modified_by": "Administrator", | |||
"module": "Desk", | |||
"name": "Desk Page", | |||
@@ -6,11 +6,11 @@ | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"type", | |||
"icon", | |||
"label", | |||
"column_break_4", | |||
"link_to", | |||
"icon", | |||
"restrict_to_domain", | |||
"is_query_report", | |||
"section_break_5", | |||
"stats_filter", | |||
"column_break_3", | |||
@@ -51,6 +51,7 @@ | |||
"label": "Format" | |||
}, | |||
{ | |||
"depends_on": "eval:doc.type == \"DocType\" && frappe.boot.developer_mode", | |||
"fieldname": "section_break_5", | |||
"fieldtype": "Section Break", | |||
"label": "Count Filter" | |||
@@ -61,13 +62,7 @@ | |||
"label": "Color" | |||
}, | |||
{ | |||
"default": "0", | |||
"depends_on": "eval:doc.type === \"Report\"", | |||
"fieldname": "is_query_report", | |||
"fieldtype": "Check", | |||
"label": "Is Query Report" | |||
}, | |||
{ | |||
"depends_on": "eval:frappe.boot.developer_mode", | |||
"fieldname": "icon", | |||
"fieldtype": "Data", | |||
"label": "Icon" | |||
@@ -77,15 +72,22 @@ | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"depends_on": "eval:frappe.boot.developer_mode", | |||
"fieldname": "restrict_to_domain", | |||
"fieldtype": "Link", | |||
"label": "Restrict to Domain", | |||
"options": "Domain" | |||
}, | |||
{ | |||
"fieldname": "label", | |||
"fieldtype": "Data", | |||
"label": "Label", | |||
"reqd": 1 | |||
} | |||
], | |||
"istable": 1, | |||
"links": [], | |||
"modified": "2020-03-11 13:09:00.180528", | |||
"modified": "2020-04-07 19:04:23.645198", | |||
"modified_by": "Administrator", | |||
"module": "Desk", | |||
"name": "Desk Shortcut", | |||
@@ -8,5 +8,14 @@ frappe.ui.form.on('Notification Settings', { | |||
route: '#modules/Settings', | |||
type: 'Custom' | |||
}); | |||
}, | |||
refresh: (frm) => { | |||
if (frappe.user.has_role('System Manager')) { | |||
frm.add_custom_button('Go to Notification Settings List', () => { | |||
frappe.set_route('List', 'Notification Settings'); | |||
}); | |||
} | |||
} | |||
}); |
@@ -62,7 +62,14 @@ def get_subscribed_documents(): | |||
def get_permission_query_conditions(user): | |||
if not user: user = frappe.session.user | |||
return '''(`tabNotification Settings`.user = '{user}')'''.format(user=user) | |||
if user == 'Administrator': | |||
return | |||
roles = frappe.get_roles(user) | |||
if "System Manager" in roles: | |||
return '''(`tabNotification Settings`.name != 'Administrator')''' | |||
return '''(`tabNotification Settings`.name = '{user}')'''.format(user=user) | |||
@frappe.whitelist() | |||
def set_seen_value(value, user): |
@@ -0,0 +1,31 @@ | |||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||
// License: GNU General Public License v3. See license.txt | |||
frappe.views.calendar["ToDo"] = { | |||
field_map: { | |||
"start": "date", | |||
"end": "date", | |||
"id": "name", | |||
"title": "description", | |||
"allDay": "allDay", | |||
"progress": "progress" | |||
}, | |||
gantt: true, | |||
filters: [ | |||
{ | |||
"fieldtype": "Link", | |||
"fieldname": "reference_type", | |||
"options": "Task", | |||
"label": __("Task") | |||
}, | |||
{ | |||
"fieldtype": "Dynamic Link", | |||
"fieldname": "reference_name", | |||
"options": "reference_type", | |||
"label": __("Task") | |||
} | |||
], | |||
get_events_method: "frappe.desk.calendar.get_events" | |||
}; | |||
@@ -8,16 +8,22 @@ from frappe import _ | |||
from frappe.desk.doctype.global_search_settings.global_search_settings import update_global_search_doctypes | |||
def install(): | |||
update_genders_and_salutations() | |||
update_genders() | |||
update_salutations() | |||
update_global_search_doctypes() | |||
setup_email_linking() | |||
@frappe.whitelist() | |||
def update_genders_and_salutations(): | |||
default_genders = [_("Male"), _("Female"), _("Other")] | |||
default_salutations = [_("Mr"), _("Ms"), _('Mx'), _("Dr"), _("Mrs"), _("Madam"), _("Miss"), _("Master"), _("Prof")] | |||
def update_genders(): | |||
default_genders = [_("Male"), _("Female"), _("Other"),_("Transgender"), _("Genderqueer"), _("Non-Conforming"),_("Prefer not to say")] | |||
records = [{'doctype': 'Gender', 'gender': d} for d in default_genders] | |||
records += [{'doctype': 'Salutation', 'salutation': d} for d in default_salutations] | |||
for record in records: | |||
frappe.get_doc(record).insert(ignore_permissions=True, ignore_if_duplicate=True) | |||
@frappe.whitelist() | |||
def update_salutations(): | |||
default_salutations = [_("Mr"), _("Ms"), _('Mx'), _("Dr"), _("Mrs"), _("Madam"), _("Miss"), _("Master"), _("Prof")] | |||
records = [{'doctype': 'Salutation', 'salutation': d} for d in default_salutations] | |||
for record in records: | |||
doc = frappe.new_doc(record.get("doctype")) | |||
doc.update(record) | |||
@@ -66,6 +66,7 @@ | |||
"fieldtype": "Data", | |||
"in_global_search": 1, | |||
"label": "Email Address", | |||
"options": "Email", | |||
"reqd": 1 | |||
}, | |||
{ | |||
@@ -410,7 +411,7 @@ | |||
], | |||
"icon": "fa fa-inbox", | |||
"links": [], | |||
"modified": "2019-12-18 15:56:39.744520", | |||
"modified": "2020-04-06 19:20:50.491146", | |||
"modified_by": "Administrator", | |||
"module": "Email", | |||
"name": "Email Account", | |||
@@ -68,8 +68,7 @@ def add_subscribers(name, email_list): | |||
email_list = email_list.replace(",", "\n").split("\n") | |||
template = frappe.db.get_value('Email Group', name, 'welcome_email_template') | |||
if template: | |||
welcome_email = frappe.get_doc("Email Template", template) | |||
welcome_email = frappe.get_doc("Email Template", template) if template else None | |||
count = 0 | |||
for email in email_list: | |||
@@ -108,4 +107,4 @@ def send_welcome_email(welcome_email, email, email_group): | |||
) | |||
message = frappe.render_template(welcome_email.response, args) | |||
frappe.sendmail(email, subject=welcome_email.subject, message=message) | |||
frappe.sendmail(email, subject=welcome_email.subject, message=message) |
@@ -51,9 +51,6 @@ class Newsletter(WebsiteGenerator): | |||
frappe.msgprint(_("Scheduled to send to {0} recipients").format(len(self.recipients))) | |||
frappe.db.set(self, "email_sent", 1) | |||
frappe.db.set(self, "schedule_send", now_datetime()) | |||
frappe.db.set(self, 'scheduled_to_send', len(self.recipients)) | |||
else: | |||
frappe.msgprint(_("Newsletter should have atleast one recipient")) | |||
@@ -71,8 +68,8 @@ class Newsletter(WebsiteGenerator): | |||
attachments = [] | |||
if self.send_attachements: | |||
files = frappe.get_all("File", fields = ["name"], filters = {"attached_to_doctype": "Newsletter", | |||
"attached_to_name":self.name}, order_by="creation desc") | |||
files = frappe.get_all("File", fields=["name"], filters={"attached_to_doctype": "Newsletter", | |||
"attached_to_name": self.name}, order_by="creation desc") | |||
for file in files: | |||
try: | |||
@@ -82,17 +79,21 @@ class Newsletter(WebsiteGenerator): | |||
except IOError: | |||
frappe.throw(_("Unable to find attachment {0}").format(file.name)) | |||
send(recipients = self.recipients, sender = sender, | |||
subject = self.subject, message = self.message, | |||
reference_doctype = self.doctype, reference_name = self.name, | |||
add_unsubscribe_link = self.send_unsubscribe_link, attachments=attachments, | |||
unsubscribe_method = "/unsubscribe", | |||
unsubscribe_params = {"name": self.name}, | |||
send_priority = 0, queue_separately=True) | |||
send(recipients=self.recipients, sender=sender, | |||
subject=self.subject, message=self.message, | |||
reference_doctype=self.doctype, reference_name=self.name, | |||
add_unsubscribe_link=self.send_unsubscribe_link, attachments=attachments, | |||
unsubscribe_method="/unsubscribe", | |||
unsubscribe_params={"name": self.name}, | |||
send_priority=0, queue_separately=True) | |||
if not frappe.flags.in_test: | |||
frappe.db.auto_commit_on_many_writes = False | |||
self.db_set("email_sent", 1) | |||
self.db_set("schedule_send", now_datetime()) | |||
self.db_set("scheduled_to_send", len(self.recipients)) | |||
def get_recipients(self): | |||
"""Get recipients from Email Group""" | |||
recipients_list = [] | |||
@@ -268,6 +269,6 @@ def send_scheduled_email(): | |||
scheduled_newsletter = frappe.get_all('Newsletter', filters = { | |||
'schedule_send': ('<=', now_datetime()), | |||
'email_sent': 0 | |||
}, fields = ['name']) | |||
}, fields = ['name'], ignore_ifnull=True) | |||
for newsletter in scheduled_newsletter: | |||
send_newsletter(newsletter.name) | |||
send_newsletter(newsletter.name) |
@@ -1,25 +1,29 @@ | |||
{ | |||
"cards": [ | |||
{ | |||
"links": "[\n {\n \"description\": \"Dropbox backup settings\",\n \"label\": \"Dropbox Settings\",\n \"name\": \"Dropbox Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"S3 Backup Settings\",\n \"label\": \"S3 Backup Settings\",\n \"name\": \"S3 Backup Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Google Drive Backup.\",\n \"label\": \"Google Drive\",\n \"name\": \"Google Drive\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Backup" | |||
"hidden": 0, | |||
"label": "Backup", | |||
"links": "[\n {\n \"description\": \"Dropbox backup settings\",\n \"label\": \"Dropbox Settings\",\n \"name\": \"Dropbox Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"S3 Backup Settings\",\n \"label\": \"S3 Backup Settings\",\n \"name\": \"S3 Backup Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Google Drive Backup.\",\n \"label\": \"Google Drive\",\n \"name\": \"Google Drive\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"links": "[\n {\n \"description\": \"Google API Settings.\",\n \"label\": \"Google Settings\",\n \"name\": \"Google Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Google Contacts Integration.\",\n \"label\": \"Google Contacts\",\n \"name\": \"Google Contacts\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Google Calendar Integration.\",\n \"label\": \"Google Calendar\",\n \"name\": \"Google Calendar\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Google Drive Integration.\",\n \"label\": \"Google Drive\",\n \"name\": \"Google Drive\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Google Services" | |||
"hidden": 0, | |||
"label": "Google Services", | |||
"links": "[\n {\n \"description\": \"Google API Settings.\",\n \"label\": \"Google Settings\",\n \"name\": \"Google Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Google Contacts Integration.\",\n \"label\": \"Google Contacts\",\n \"name\": \"Google Contacts\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Google Calendar Integration.\",\n \"label\": \"Google Calendar\",\n \"name\": \"Google Calendar\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Google Drive Integration.\",\n \"label\": \"Google Drive\",\n \"name\": \"Google Drive\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"links": "[\n {\n \"description\": \"Webhooks calling API requests into web apps\",\n \"label\": \"Webhook\",\n \"name\": \"Webhook\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Slack Webhooks for internal integration\",\n \"label\": \"Slack Webhook URL\",\n \"name\": \"Slack Webhook URL\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Webhook" | |||
"hidden": 0, | |||
"label": "Webhook", | |||
"links": "[\n {\n \"description\": \"Webhooks calling API requests into web apps\",\n \"label\": \"Webhook\",\n \"name\": \"Webhook\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Slack Webhooks for internal integration\",\n \"label\": \"Slack Webhook URL\",\n \"name\": \"Slack Webhook URL\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"links": "[\n {\n \"description\": \"Enter keys to enable login via Facebook, Google, GitHub.\",\n \"label\": \"Social Login Key\",\n \"name\": \"Social Login Key\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Ldap settings\",\n \"label\": \"LDAP Settings\",\n \"name\": \"LDAP Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Register OAuth Client App\",\n \"label\": \"OAuth Client\",\n \"name\": \"OAuth Client\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Settings for OAuth Provider\",\n \"label\": \"OAuth Provider Settings\",\n \"name\": \"OAuth Provider Settings\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Authentication" | |||
"hidden": 0, | |||
"label": "Authentication", | |||
"links": "[\n {\n \"description\": \"Enter keys to enable login via Facebook, Google, GitHub.\",\n \"label\": \"Social Login Key\",\n \"name\": \"Social Login Key\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Ldap settings\",\n \"label\": \"LDAP Settings\",\n \"name\": \"LDAP Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Register OAuth Client App\",\n \"label\": \"OAuth Client\",\n \"name\": \"OAuth Client\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Settings for OAuth Provider\",\n \"label\": \"OAuth Provider Settings\",\n \"name\": \"OAuth Provider Settings\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"icon": "fa fa-star", | |||
"links": "[\n {\n \"description\": \"Braintree payment gateway settings\",\n \"label\": \"Braintree Settings\",\n \"name\": \"Braintree Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"PayPal payment gateway settings\",\n \"label\": \"PayPal Settings\",\n \"name\": \"PayPal Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Razorpay Payment gateway settings\",\n \"label\": \"Razorpay Settings\",\n \"name\": \"Razorpay Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Stripe payment gateway settings\",\n \"label\": \"Stripe Settings\",\n \"name\": \"Stripe Settings\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Payments" | |||
"hidden": 0, | |||
"label": "Payments", | |||
"links": "[\n {\n \"description\": \"Braintree payment gateway settings\",\n \"label\": \"Braintree Settings\",\n \"name\": \"Braintree Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"PayPal payment gateway settings\",\n \"label\": \"PayPal Settings\",\n \"name\": \"PayPal Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Razorpay Payment gateway settings\",\n \"label\": \"Razorpay Settings\",\n \"name\": \"Razorpay Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Stripe payment gateway settings\",\n \"label\": \"Stripe Settings\",\n \"name\": \"Stripe Settings\",\n \"type\": \"doctype\"\n }\n]" | |||
} | |||
], | |||
"category": "Administration", | |||
@@ -34,7 +38,7 @@ | |||
"idx": 0, | |||
"is_standard": 1, | |||
"label": "Integrations", | |||
"modified": "2020-03-12 16:30:42.823316", | |||
"modified": "2020-04-01 11:24:40.751651", | |||
"modified_by": "Administrator", | |||
"module": "Integrations", | |||
"name": "Integrations", | |||
@@ -1,487 +1,129 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_events_in_timeline": 0, | |||
"allow_guest_to_view": 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, | |||
"creation": "2016-09-21 10:12:57.399174", | |||
"doctype": "DocType", | |||
"document_type": "System", | |||
"editable_grid": 1, | |||
"field_order": [ | |||
"enabled", | |||
"send_notifications_to", | |||
"send_email_for_successful_backup", | |||
"backup_frequency", | |||
"limit_no_of_backups", | |||
"no_of_backups", | |||
"file_backup", | |||
"app_access_key", | |||
"app_secret_key", | |||
"allow_dropbox_access", | |||
"dropbox_access_key", | |||
"dropbox_access_secret", | |||
"dropbox_access_token" | |||
], | |||
"fields": [ | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "enabled", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Enabled", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"default": "0", | |||
"fieldname": "enabled", | |||
"fieldtype": "Check", | |||
"label": "Enabled" | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"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_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 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, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "send_notifications_to", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Send Notifications To", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"description": "Note: By default emails for failed backups are sent.", | |||
"fieldname": "send_email_for_successful_backup", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Send Email for Successful Backup", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"default": "1", | |||
"description": "Note: By default emails for failed backups are sent.", | |||
"fieldname": "send_email_for_successful_backup", | |||
"fieldtype": "Check", | |||
"label": "Send Email for Successful Backup" | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 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_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 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, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "backup_frequency", | |||
"fieldtype": "Select", | |||
"in_list_view": 1, | |||
"label": "Backup Frequency", | |||
"options": "\nDaily\nWeekly", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "limit_no_of_backups", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Limit Number of DB Backups", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"default": "0", | |||
"fieldname": "limit_no_of_backups", | |||
"fieldtype": "Check", | |||
"label": "Limit Number of DB Backups" | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "5", | |||
"depends_on": "eval:doc.limit_no_of_backups", | |||
"fieldname": "no_of_backups", | |||
"fieldtype": "Int", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Number of DB Backups", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"default": "5", | |||
"depends_on": "eval:doc.limit_no_of_backups", | |||
"fieldname": "no_of_backups", | |||
"fieldtype": "Int", | |||
"label": "Number of DB Backups" | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"fieldname": "file_backup", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "File Backup", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"default": "1", | |||
"fieldname": "file_backup", | |||
"fieldtype": "Check", | |||
"label": "File Backup" | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "", | |||
"fieldname": "app_access_key", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 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, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "app_access_key", | |||
"fieldtype": "Data", | |||
"label": "App Access Key" | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "", | |||
"fieldname": "app_secret_key", | |||
"fieldtype": "Password", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 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, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "app_secret_key", | |||
"fieldtype": "Password", | |||
"label": "App Secret Key" | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 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_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 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, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "allow_dropbox_access", | |||
"fieldtype": "Button", | |||
"label": "Allow Dropbox Access" | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 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_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 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, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "dropbox_access_key", | |||
"fieldtype": "Password", | |||
"hidden": 1, | |||
"label": "Dropbox Access Key", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 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_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 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, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "dropbox_access_secret", | |||
"fieldtype": "Password", | |||
"hidden": 1, | |||
"label": "Dropbox Access Secret", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "dropbox_access_token", | |||
"fieldtype": "Password", | |||
"hidden": 1, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Dropbox Access Token", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
"fieldname": "dropbox_access_token", | |||
"fieldtype": "Password", | |||
"hidden": 1, | |||
"label": "Dropbox Access Token" | |||
} | |||
], | |||
"has_web_view": 0, | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 1, | |||
"is_submittable": 0, | |||
"issingle": 1, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2019-01-03 05:44:40.520943", | |||
"modified_by": "Administrator", | |||
"module": "Integrations", | |||
"name": "Dropbox Settings", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
], | |||
"in_create": 1, | |||
"issingle": 1, | |||
"modified": "2019-08-22 16:26:44.468391", | |||
"modified_by": "Administrator", | |||
"module": "Integrations", | |||
"name": "Dropbox Settings", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"amend": 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, | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"print": 1, | |||
"read": 1, | |||
"role": "System Manager", | |||
"share": 1, | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 0, | |||
"read_only": 1, | |||
"read_only_onload": 0, | |||
"show_name_in_global_search": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 1, | |||
"track_seen": 0, | |||
"track_views": 0 | |||
} | |||
], | |||
"read_only": 1, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 1 | |||
} |
@@ -3,22 +3,25 @@ | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import dropbox | |||
import json | |||
import frappe | |||
import os | |||
from frappe import _ | |||
from frappe.model.document import Document | |||
import dropbox, json | |||
from frappe.integrations.offsite_backup_utils import get_latest_backup_file, send_email, validate_file_size | |||
from frappe.integrations.utils import make_post_request | |||
from frappe.utils import (cint, get_request_site_address, | |||
get_files_path, get_backups_path, get_url, encode) | |||
from frappe.utils.backups import new_backup | |||
from frappe.utils.background_jobs import enqueue | |||
from six.moves.urllib.parse import urlparse, parse_qs | |||
from frappe.integrations.utils import make_post_request | |||
from rq.timeouts import JobTimeoutException | |||
from frappe.utils import (cint, split_emails, get_request_site_address, | |||
get_files_path, get_backups_path, get_url, encode) | |||
from six import text_type | |||
ignore_list = [".DS_Store"] | |||
class DropboxSettings(Document): | |||
def onload(self): | |||
if not self.app_access_key and frappe.conf.dropbox_access_key: | |||
@@ -48,10 +51,12 @@ def take_backup_to_dropbox(retry_count=0, upload_db_backup=True): | |||
did_not_upload, error_log = [], [] | |||
try: | |||
if cint(frappe.db.get_value("Dropbox Settings", None, "enabled")): | |||
validate_file_size() | |||
did_not_upload, error_log = backup_to_dropbox(upload_db_backup) | |||
if did_not_upload: raise Exception | |||
send_email(True, "Dropbox") | |||
send_email(True, "Dropbox", "Dropbox Settings", "send_notifications_to") | |||
except JobTimeoutException: | |||
if retry_count < 2: | |||
args = { | |||
@@ -66,34 +71,8 @@ def take_backup_to_dropbox(retry_count=0, upload_db_backup=True): | |||
else: | |||
file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log)] | |||
error_message = ("\n".join(file_and_error) + "\n" + frappe.get_traceback()) | |||
frappe.errprint(error_message) | |||
send_email(False, "Dropbox", error_message) | |||
def send_email(success, service_name, error_status=None): | |||
if success: | |||
if frappe.db.get_value("Dropbox Settings", None, "send_email_for_successful_backup") == '0': | |||
return | |||
subject = "Backup Upload Successful" | |||
message ="""<h3>Backup Uploaded Successfully</h3><p>Hi there, this is just to inform you | |||
that your backup was successfully uploaded to your %s account. So relax!</p> | |||
""" % service_name | |||
else: | |||
subject = "[Warning] Backup Upload Failed" | |||
message ="""<h3>Backup Upload Failed</h3><p>Oops, your automated backup to %s | |||
failed.</p> | |||
<p>Error message: <br> | |||
<pre><code>%s</code></pre> | |||
</p> | |||
<p>Please contact your system manager for more information.</p> | |||
""" % (service_name, error_status) | |||
if not frappe.db: | |||
frappe.connect() | |||
recipients = split_emails(frappe.db.get_value("Dropbox Settings", None, "send_notifications_to")) | |||
frappe.sendmail(recipients=recipients, subject=subject, message=message) | |||
send_email(False, "Dropbox", "Dropbox Settings", "send_notifications_to", error_message) | |||
def backup_to_dropbox(upload_db_backup=True): | |||
if not frappe.db: | |||
@@ -114,8 +93,12 @@ def backup_to_dropbox(upload_db_backup=True): | |||
dropbox_client = dropbox.Dropbox(dropbox_settings['access_token']) | |||
if upload_db_backup: | |||
backup = new_backup(ignore_files=True) | |||
filename = os.path.join(get_backups_path(), os.path.basename(backup.backup_path_db)) | |||
if frappe.flags.create_new_backup: | |||
backup = new_backup(ignore_files=True) | |||
filename = os.path.join(get_backups_path(), os.path.basename(backup.backup_path_db)) | |||
else: | |||
filename = get_latest_backup_file() | |||
upload_file_to_dropbox(filename, "/database", dropbox_client) | |||
# delete older databases | |||
@@ -0,0 +1,10 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2019, Frappe Technologies and Contributors | |||
# See license.txt | |||
from __future__ import unicode_literals | |||
# import frappe | |||
import unittest | |||
class TestDropboxSettings(unittest.TestCase): | |||
pass |
@@ -19,6 +19,7 @@ from apiclient.http import MediaFileUpload | |||
from frappe.utils import get_backups_path, get_bench_path | |||
from frappe.utils.backups import new_backup | |||
from frappe.integrations.doctype.google_settings.google_settings import get_auth_url | |||
from frappe.integrations.offsite_backup_utils import get_latest_backup_file, send_email, validate_file_size | |||
SCOPES = "https://www.googleapis.com/auth/drive" | |||
@@ -183,13 +184,16 @@ def upload_system_backup_to_google_drive(): | |||
check_for_folder_in_google_drive() | |||
account.load_from_db() | |||
progress(1, "Backing up Data.") | |||
backup = new_backup() | |||
fileurl_backup = os.path.basename(backup.backup_path_db) | |||
fileurl_public_files = os.path.basename(backup.backup_path_files) | |||
fileurl_private_files = os.path.basename(backup.backup_path_private_files) | |||
validate_file_size() | |||
if frappe.flags.create_new_backup: | |||
set_progress(1, "Backing up Data.") | |||
backup = new_backup() | |||
fileurl_backup = os.path.basename(backup.backup_path_db) | |||
fileurl_public_files = os.path.basename(backup.backup_path_files) | |||
fileurl_private_files = os.path.basename(backup.backup_path_private_files) | |||
else: | |||
fileurl_backup, fileurl_public_files, fileurl_private_files = get_latest_backup_file(with_files=True) | |||
for fileurl in [fileurl_backup, fileurl_public_files, fileurl_private_files]: | |||
file_metadata = { | |||
@@ -203,15 +207,14 @@ def upload_system_backup_to_google_drive(): | |||
frappe.throw(_("Google Drive - Could not locate locate - {0}").format(e)) | |||
try: | |||
progress(2, "Uploading backup to Google Drive.") | |||
set_progress(2, "Uploading backup to Google Drive.") | |||
google_drive.files().create(body=file_metadata, media_body=media, fields="id").execute() | |||
except HttpError as e: | |||
send_email(success=False, error=e) | |||
frappe.msgprint(_("Google Drive - Could not upload backup - Error {0}").format(e)) | |||
send_email(False, "Google Drive", "Google Drive", "email", error_status=e) | |||
progress(3, "Uploading successful.") | |||
set_progress(3, "Uploading successful.") | |||
frappe.db.set_value("Google Drive", None, "last_backup_on", frappe.utils.now_datetime()) | |||
send_email(success=True) | |||
send_email(True, "Google Drive", "Google Drive", "email") | |||
return _("Google Drive Backup Successful.") | |||
def daily_backup(): | |||
@@ -226,30 +229,5 @@ def get_absolute_path(filename): | |||
file_path = os.path.join(get_backups_path()[2:], filename) | |||
return "{0}/sites/{1}".format(get_bench_path(), file_path) | |||
def progress(progress, message): | |||
def set_progress(progress, message): | |||
frappe.publish_realtime("upload_to_google_drive", dict(progress=progress, total=3, message=message), user=frappe.session.user) | |||
def send_email(success, error=None): | |||
if success: | |||
if not frappe.db.get_single_value("Google Drive", "send_email_for_successful_backup"): | |||
return | |||
subject = "Backup Upload Successful" | |||
message = """<h3>Backup Uploaded Successfully</h3><p>Hi there, this is just to inform you | |||
that your backup was successfully uploaded to Google Drive.</p> | |||
""" | |||
else: | |||
subject = "[Warning] Backup Upload Failed" | |||
message = """<h3>Backup Upload Failed</h3><p>Oops, your automated backup to Google Drive | |||
failed.</p> | |||
<p>Error message: <br> | |||
<pre><code>{0}</code></pre> | |||
</p> | |||
<p>Please contact your system manager for more information.</p> | |||
""".format(error) | |||
frappe.sendmail( | |||
recipients=frappe.db.get_single_value("Google Drive", "email"), | |||
subject=subject, | |||
message=message | |||
) |
@@ -1,517 +1,517 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_guest_to_view": 0, | |||
"allow_import": 0, | |||
"allow_rename": 0, | |||
"autoname": "", | |||
"beta": 0, | |||
"creation": "2016-08-24 14:07:21.955052", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "Document", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"allow_copy": 0, | |||
"allow_guest_to_view": 0, | |||
"allow_import": 0, | |||
"allow_rename": 0, | |||
"autoname": "", | |||
"beta": 0, | |||
"creation": "2016-08-24 14:07:21.955052", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "Document", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"fields": [ | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "", | |||
"fieldname": "client_id", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "App Client ID", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 1, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "", | |||
"fieldname": "client_id", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "App Client ID", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 1, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "app_name", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "App Name", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "app_name", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "App Name", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "user", | |||
"fieldtype": "Link", | |||
"hidden": 1, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "User", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "User", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "user", | |||
"fieldtype": "Link", | |||
"hidden": 1, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "User", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "User", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "cb_1", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "cb_1", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "client_secret", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "App Client Secret", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 1, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "client_secret", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "App Client Secret", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 1, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "If checked, users will not see the Confirm Access dialog.", | |||
"fieldname": "skip_authorization", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Skip Authorization", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "If checked, users will not see the Confirm Access dialog.", | |||
"fieldname": "skip_authorization", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Skip Authorization", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "", | |||
"fieldname": "sb_1", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "", | |||
"fieldname": "sb_1", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "all openid", | |||
"description": "A list of resources which the Client App will have access to after the user allows it.<br> e.g. project", | |||
"fieldname": "scopes", | |||
"fieldtype": "Text", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Scopes", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "all openid", | |||
"description": "A list of resources which the Client App will have access to after the user allows it.<br> e.g. project", | |||
"fieldname": "scopes", | |||
"fieldtype": "Text", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Scopes", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "cb_3", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "cb_3", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "URIs for receiving authorization code once the user allows access, as well as failure responses. Typically a REST endpoint exposed by the Client App.\n<br>e.g. http://hostname//api/method/frappe.www.login.login_via_facebook", | |||
"fieldname": "redirect_uris", | |||
"fieldtype": "Text", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Redirect URIs", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "URIs for receiving authorization code once the user allows access, as well as failure responses. Typically a REST endpoint exposed by the Client App.\n<br>e.g. http://hostname//api/method/frappe.www.login.login_via_facebook", | |||
"fieldname": "redirect_uris", | |||
"fieldtype": "Text", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Redirect URIs", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "default_redirect_uri", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Default Redirect URI", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "default_redirect_uri", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Default Redirect URI", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 1, | |||
"collapsible_depends_on": "1", | |||
"columns": 0, | |||
"fieldname": "sb_advanced", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": " Advanced Settings", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 1, | |||
"collapsible_depends_on": "1", | |||
"columns": 0, | |||
"fieldname": "sb_advanced", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Advanced Settings", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "grant_type", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 1, | |||
"label": "Grant Type", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Authorization Code\nImplicit", | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "grant_type", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 1, | |||
"label": "Grant Type", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Authorization Code\nImplicit", | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "cb_2", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "cb_2", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "Code", | |||
"fieldname": "response_type", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 1, | |||
"label": "Response Type", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Code\nToken", | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "Code", | |||
"fieldname": "response_type", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 1, | |||
"label": "Response Type", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Code\nToken", | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
], | |||
"has_web_view": 0, | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2017-10-05 21:07:39.476360", | |||
"modified_by": "Administrator", | |||
"module": "Integrations", | |||
"name": "OAuth Client", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
], | |||
"has_web_view": 0, | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2020-04-07 21:07:39.476360", | |||
"modified_by": "Administrator", | |||
"module": "Integrations", | |||
"name": "OAuth Client", | |||
"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": 1, | |||
"role": "System Manager", | |||
"set_user_permissions": 0, | |||
"share": 1, | |||
"submit": 0, | |||
"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": 1, | |||
"role": "System Manager", | |||
"set_user_permissions": 0, | |||
"share": 1, | |||
"submit": 0, | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"show_name_in_global_search": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"title_field": "app_name", | |||
"track_changes": 1, | |||
], | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"show_name_in_global_search": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"title_field": "app_name", | |||
"track_changes": 1, | |||
"track_seen": 0 | |||
} |
@@ -1,397 +1,110 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_events_in_timeline": 0, | |||
"allow_guest_to_view": 0, | |||
"allow_import": 0, | |||
"allow_rename": 0, | |||
"beta": 0, | |||
"creation": "2017-09-04 20:57:20.129205", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"creation": "2017-09-04 20:57:20.129205", | |||
"doctype": "DocType", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"enabled", | |||
"notify_email", | |||
"send_email_for_successful_backup", | |||
"frequency", | |||
"access_key_id", | |||
"secret_access_key", | |||
"region", | |||
"endpoint_url", | |||
"bucket", | |||
"backup_limit" | |||
], | |||
"fields": [ | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fetch_if_empty": 0, | |||
"fieldname": "enabled", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Enable Automatic Backup", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"default": "0", | |||
"fieldname": "enabled", | |||
"fieldtype": "Check", | |||
"label": "Enable Automatic Backup" | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fetch_if_empty": 0, | |||
"fieldname": "notify_email", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 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, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "notify_email", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Send Notifications To", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"description": "Note: By default emails for failed backups are sent.", | |||
"fetch_if_empty": 0, | |||
"fieldname": "send_email_for_successful_backup", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Send Email for Successful Backup", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"default": "1", | |||
"description": "Note: By default emails for failed backups are sent.", | |||
"fieldname": "send_email_for_successful_backup", | |||
"fieldtype": "Check", | |||
"label": "Send Email for Successful Backup" | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fetch_if_empty": 0, | |||
"fieldname": "frequency", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 0, | |||
"label": "Backup Frequency", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Daily\nWeekly\nMonthly\nNone", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "frequency", | |||
"fieldtype": "Select", | |||
"in_list_view": 1, | |||
"label": "Backup Frequency", | |||
"options": "Daily\nWeekly\nMonthly\nNone", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fetch_if_empty": 0, | |||
"fieldname": "access_key_id", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 0, | |||
"label": "Access Key ID", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "access_key_id", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Access Key ID", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fetch_if_empty": 0, | |||
"fieldname": "secret_access_key", | |||
"fieldtype": "Password", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 0, | |||
"label": "Secret Access Key", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "secret_access_key", | |||
"fieldtype": "Password", | |||
"in_list_view": 1, | |||
"label": "Secret Access Key", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "us-east-1", | |||
"description": "See https://docs.aws.amazon.com/de_de/general/latest/gr/rande.html#s3_region for details.", | |||
"fetch_if_empty": 0, | |||
"fieldname": "region", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Region", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "us-east-1\nus-east-2\nus-west-1\nus-west-2\nap-south-1\nap-southeast-1\nap-southeast-2\nap-northeast-1\nap-northeast-2\nap-northeast-3\nca-central-1\ncn-north-1\ncn-northwest-1\neu-central-1\neu-west-1\neu-west-2\neu-west-3\neu-north-1\nsa-east-1", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"default": "us-east-1", | |||
"description": "See https://docs.aws.amazon.com/de_de/general/latest/gr/rande.html#s3_region for details.", | |||
"fieldname": "region", | |||
"fieldtype": "Select", | |||
"label": "Region", | |||
"options": "us-east-1\nus-east-2\nus-west-1\nus-west-2\nap-south-1\nap-southeast-1\nap-southeast-2\nap-northeast-1\nap-northeast-2\nap-northeast-3\nca-central-1\ncn-north-1\ncn-northwest-1\neu-central-1\neu-west-1\neu-west-2\neu-west-3\neu-north-1\nsa-east-1" | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fetch_if_empty": 0, | |||
"fieldname": "endpoint_url", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Endpoint URL", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "endpoint_url", | |||
"fieldtype": "Data", | |||
"label": "Endpoint URL" | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fetch_if_empty": 0, | |||
"fieldname": "bucket", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Bucket", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
}, | |||
"fieldname": "bucket", | |||
"fieldtype": "Data", | |||
"label": "Bucket", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_in_quick_entry": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fetch_if_empty": 0, | |||
"fieldname": "backup_limit", | |||
"fieldtype": "Int", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Backup Limit", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"translatable": 0, | |||
"unique": 0 | |||
"fieldname": "backup_limit", | |||
"fieldtype": "Int", | |||
"label": "Backup Limit", | |||
"reqd": 1 | |||
} | |||
], | |||
"has_web_view": 0, | |||
"hide_toolbar": 1, | |||
"idx": 0, | |||
"in_create": 0, | |||
"is_submittable": 0, | |||
"issingle": 1, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"menu_index": 0, | |||
"modified": "2019-04-10 03:56:55.632017", | |||
"modified_by": "Administrator", | |||
"module": "Integrations", | |||
"name": "S3 Backup Settings", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
], | |||
"hide_toolbar": 1, | |||
"issingle": 1, | |||
"modified": "2019-08-22 16:26:04.774571", | |||
"modified_by": "Administrator", | |||
"module": "Integrations", | |||
"name": "S3 Backup Settings", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"amend": 0, | |||
"cancel": 0, | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 0, | |||
"if_owner": 0, | |||
"import": 0, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
"report": 0, | |||
"role": "System Manager", | |||
"set_user_permissions": 0, | |||
"share": 1, | |||
"submit": 0, | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"print": 1, | |||
"read": 1, | |||
"role": "System Manager", | |||
"share": 1, | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 1, | |||
"read_only": 0, | |||
"show_name_in_global_search": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 1, | |||
"track_seen": 0, | |||
"track_views": 0 | |||
], | |||
"quick_entry": 1, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 1 | |||
} |
@@ -8,12 +8,14 @@ import os.path | |||
import frappe | |||
import boto3 | |||
from frappe import _ | |||
from frappe.integrations.offsite_backup_utils import get_latest_backup_file, send_email, validate_file_size | |||
from frappe.model.document import Document | |||
from frappe.utils import cint, split_emails | |||
from frappe.utils import cint | |||
from frappe.utils.background_jobs import enqueue | |||
from rq.timeouts import JobTimeoutException | |||
from botocore.exceptions import ClientError | |||
class S3BackupSettings(Document): | |||
def validate(self): | |||
@@ -49,7 +51,7 @@ class S3BackupSettings(Document): | |||
@frappe.whitelist() | |||
def take_backup(): | |||
"Enqueue longjob for taking backup to s3" | |||
"""Enqueue longjob for taking backup to s3""" | |||
enqueue("frappe.integrations.doctype.s3_backup_settings.s3_backup_settings.take_backups_s3", queue='long', timeout=1500) | |||
frappe.msgprint(_("Queued for backup. It may take a few minutes to an hour.")) | |||
@@ -65,22 +67,21 @@ def take_backups_weekly(): | |||
def take_backups_monthly(): | |||
take_backups_if("Monthly") | |||
def take_backups_if(freq): | |||
if cint(frappe.db.get_value("S3 Backup Settings", None, "enabled")): | |||
if frappe.db.get_value("S3 Backup Settings", None, "frequency") == freq: | |||
take_backups_s3() | |||
@frappe.whitelist() | |||
def take_backups_s3(retry_count=0): | |||
try: | |||
validate_file_size() | |||
backup_to_s3() | |||
send_email(True, "S3 Backup Settings") | |||
send_email(True, "Amazon S3", "S3 Backup Settings", "notify_email") | |||
except JobTimeoutException: | |||
if retry_count < 2: | |||
args = { | |||
"retry_count" :retry_count + 1 | |||
"retry_count": retry_count + 1 | |||
} | |||
enqueue("frappe.integrations.doctype.s3_backup_settings.s3_backup_settings.take_backups_s3", | |||
queue='long', timeout=1500, **args) | |||
@@ -89,31 +90,10 @@ def take_backups_s3(retry_count=0): | |||
except Exception: | |||
notify() | |||
def notify(): | |||
error_message = frappe.get_traceback() | |||
frappe.errprint(error_message) | |||
send_email(False, "S3 Backup Settings", error_message) | |||
def send_email(success, service_name, error_status=None): | |||
if success: | |||
if frappe.db.get_value("S3 Backup Settings", None, "send_email_for_successful_backup") == '0': | |||
return | |||
subject = "Backup Upload Successful" | |||
message = """<h3>Backup Uploaded Successfully! </h3><p>Hi there, this is just to inform you | |||
that your backup was successfully uploaded to your Amazon S3 bucket. So relax!</p> """ | |||
else: | |||
subject = "[Warning] Backup Upload Failed" | |||
message = """<h3>Backup Upload Failed! </h3><p>Oops, your automated backup to Amazon S3 failed. | |||
</p> <p>Error message: %s</p> <p>Please contact your system manager | |||
for more information.</p>""" % error_status | |||
if not frappe.db: | |||
frappe.connect() | |||
recipients = split_emails(frappe.db.get_value("S3 Backup Settings", None, "notify_email")) | |||
frappe.sendmail(recipients=recipients, subject=subject, message=message) | |||
send_email(False, 'Amazon S3', "S3 Backup Settings", "notify_email", error_message) | |||
def backup_to_s3(): | |||
@@ -130,11 +110,15 @@ def backup_to_s3(): | |||
endpoint_url=doc.endpoint_url or 'https://s3.amazonaws.com' | |||
) | |||
backup = new_backup(ignore_files=False, backup_path_db=None, | |||
if frappe.flags.create_new_backup: | |||
backup = new_backup(ignore_files=False, backup_path_db=None, | |||
backup_path_files=None, backup_path_private_files=None, force=True) | |||
db_filename = os.path.join(get_backups_path(), os.path.basename(backup.backup_path_db)) | |||
files_filename = os.path.join(get_backups_path(), os.path.basename(backup.backup_path_files)) | |||
private_files = os.path.join(get_backups_path(), os.path.basename(backup.backup_path_private_files)) | |||
db_filename = os.path.join(get_backups_path(), os.path.basename(backup.backup_path_db)) | |||
files_filename = os.path.join(get_backups_path(), os.path.basename(backup.backup_path_files)) | |||
private_files = os.path.join(get_backups_path(), os.path.basename(backup.backup_path_private_files)) | |||
else: | |||
db_filename, files_filename, private_files = get_latest_backup_file(with_files=True) | |||
folder = os.path.basename(db_filename)[:15] + '/' | |||
# for adding datetime to folder name | |||
@@ -143,8 +127,8 @@ def backup_to_s3(): | |||
upload_file_to_s3(files_filename, folder, conn, bucket) | |||
delete_old_backups(doc.backup_limit, bucket) | |||
def upload_file_to_s3(filename, folder, conn, bucket): | |||
def upload_file_to_s3(filename, folder, conn, bucket): | |||
destpath = os.path.join(folder, os.path.basename(filename)) | |||
try: | |||
print("Uploading file:", filename) | |||
@@ -156,7 +140,7 @@ def upload_file_to_s3(filename, folder, conn, bucket): | |||
def delete_old_backups(limit, bucket): | |||
all_backups = list() | |||
all_backups = [] | |||
doc = frappe.get_single("S3 Backup Settings") | |||
backup_limit = int(limit) | |||
@@ -0,0 +1,83 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2019, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
import glob | |||
import os | |||
from frappe.utils import split_emails, get_backups_path | |||
def send_email(success, service_name, doctype, email_field, error_status=None): | |||
recipients = get_recipients(service_name, email_field) | |||
if not recipients: | |||
frappe.log_error("No Email Recipient found for {0}".format(service_name), | |||
"{0}: Failed to send backup status email".format(service_name)) | |||
return | |||
if success: | |||
if not frappe.db.get_value(doctype, None, "send_email_for_successful_backup"): | |||
return | |||
subject = "Backup Upload Successful" | |||
message = """ | |||
<h3>Backup Uploaded Successfully!</h3> | |||
<p>Hi there, this is just to inform you that your backup was successfully uploaded to your {0} bucket. So relax!</p>""".format(service_name) | |||
else: | |||
subject = "[Warning] Backup Upload Failed" | |||
message = """ | |||
<h3>Backup Upload Failed!</h3> | |||
<p>Oops, your automated backup to {0} failed.</p> | |||
<p>Error message: {1}</p> | |||
<p>Please contact your system manager for more information.</p>""".format(service_name, error_status) | |||
frappe.sendmail(recipients=recipients, subject=subject, message=message) | |||
def get_recipients(service_name, email_field): | |||
if not frappe.db: | |||
frappe.connect() | |||
return split_emails(frappe.db.get_value(service_name, None, email_field)) | |||
def get_latest_backup_file(with_files=False): | |||
def get_latest(file_ext): | |||
file_list = glob.glob(os.path.join(get_backups_path(), file_ext)) | |||
return max(file_list, key=os.path.getctime) | |||
latest_file = get_latest('*.sql.gz') | |||
if with_files: | |||
latest_public_file_bak = get_latest('*-files.tar') | |||
latest_private_file_bak = get_latest('*-private-files.tar') | |||
return latest_file, latest_public_file_bak, latest_private_file_bak | |||
return latest_file | |||
def get_file_size(file_path, unit): | |||
if not unit: | |||
unit = 'MB' | |||
file_size = os.path.getsize(file_path) | |||
memory_size_unit_mapper = {'KB': 1, 'MB': 2, 'GB': 3, 'TB': 4} | |||
i = 0 | |||
while i < memory_size_unit_mapper[unit]: | |||
file_size = file_size / 1000.0 | |||
i += 1 | |||
return file_size | |||
def validate_file_size(): | |||
frappe.flags.create_new_backup = True | |||
latest_file = get_latest_backup_file() | |||
file_size = get_file_size(latest_file, unit='GB') | |||
if file_size > 1: | |||
frappe.flags.create_new_backup = False |
@@ -1,5 +1,5 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies and contributors | |||
# Copyright (c) 2019, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
@@ -110,7 +110,11 @@ def make_autoname(key="", doctype="", doc=""): | |||
if "#" not in key: | |||
key = key + ".#####" | |||
elif "." not in key: | |||
frappe.throw(_("Invalid naming series (. missing)") + (_(" for {0}").format(doctype) if doctype else "")) | |||
error_message = _("Invalid naming series (. missing)") | |||
if doctype: | |||
error_message = _("Invalid naming series (. missing) for {0}").format(doctype) | |||
frappe.throw(error_message) | |||
parts = key.split('.') | |||
n = parse_naming_series(parts, doctype, doc) | |||
@@ -271,3 +271,4 @@ execute:frappe.delete_doc_if_exists('DocType', 'GSuite Templates') | |||
execute:frappe.delete_doc_if_exists('DocType', 'GCalendar Account') | |||
execute:frappe.delete_doc_if_exists('DocType', 'GCalendar Settings') | |||
frappe.patches.v12_0.remove_parent_and_parenttype_from_print_formats | |||
execute:from frappe.desk.page.setup_wizard.install_fixtures import update_genders;update_genders() |
@@ -2,7 +2,7 @@ | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe.desk.page.setup_wizard.install_fixtures import update_genders_and_salutations | |||
from frappe.desk.page.setup_wizard.install_fixtures import update_genders, update_salutations | |||
def execute(): | |||
frappe.db.set_value("DocType", "Contact", "module", "Contacts") | |||
@@ -11,4 +11,5 @@ def execute(): | |||
frappe.reload_doc('contacts', 'doctype', 'gender') | |||
frappe.reload_doc('contacts', 'doctype', 'salutation') | |||
update_genders_and_salutations() | |||
update_genders() | |||
update_salutations() |
@@ -550,6 +550,7 @@ export default class GridRow { | |||
hide_form() { | |||
frappe.dom.unfreeze(); | |||
this.row.toggle(true); | |||
frappe.utils.scroll_to(this.row, true, 15); | |||
this.refresh(); | |||
if(cur_frm) cur_frm.cur_grid = null; | |||
this.wrapper.removeClass("grid-row-open"); | |||
@@ -9,6 +9,7 @@ export default class GridRowForm { | |||
var me = this; | |||
this.make_form(); | |||
this.form_area.empty(); | |||
frappe.utils.scroll_to(0, false, 0, this.wrapper.find('.grid-form-body')); | |||
this.layout = new frappe.ui.form.Layout({ | |||
fields: this.row.docfields, | |||
@@ -29,20 +29,18 @@ frappe.ui.form.States = Class.extend({ | |||
}); | |||
frappe.workflow.get_transitions(me.frm.doc).then((transitions) => { | |||
var next_html = $.map(transitions, | |||
function(d) { | |||
return d.action.bold() + __(" by Role ") + d.allowed; | |||
}).join(", ") || __("None: End of Workflow").bold(); | |||
$(d.body).html("<p>"+__("Current status")+": " + state.bold() + "</p>" | |||
+ "<p>"+__("Document is only editable by users of role")+": " | |||
+ frappe.workflow.get_document_state(me.frm.doctype, | |||
state).allow_edit.bold() + "</p>" | |||
+ "<p>"+__("Next actions")+": "+ next_html +"</p>" | |||
+ (me.frm.doc.__islocal ? ("<div class='alert alert-info'>" | |||
+__("Workflow will start after saving.")+"</div>") : "") | |||
+ "<p class='help'>"+__("Note: Other permission rules may also apply")+"</p>" | |||
).css({padding: '15px'}); | |||
const next_actions = $.map(transitions, d => `${d.action.bold()} ${__("by Role")} ${d.allowed}`) | |||
.join(", ") || __("None: End of Workflow").bold(); | |||
const document_editable_by = frappe.workflow.get_document_state(me.frm.doctype, state).allow_edit.bold(); | |||
$(d.body).html(` | |||
<p>${__("Current status")}: ${state.bold()}</p> | |||
<p>${__("Document is only editable by users with role")}: ${document_editable_by}</p> | |||
<p>${__("Next actions")}: ${next_actions}</p> | |||
<p>${__("{0}: Other permission rules may also apply", [__('Note').bold()])}</p> | |||
`).css({padding: '15px'}); | |||
d.show(); | |||
}); | |||
}, true); | |||
@@ -115,7 +113,7 @@ frappe.ui.form.States = Class.extend({ | |||
} else { | |||
this.setup_btn(added); | |||
} | |||
}); | |||
}, | |||
@@ -53,15 +53,18 @@ frappe.views.ListGroupBy = class ListGroupBy { | |||
render_group_by_items() { | |||
let get_item_html = (fieldname) => { | |||
let label; | |||
let fieldtype; | |||
let label, fieldtype; | |||
if (fieldname === 'assigned_to') { | |||
label = __('Assigned To'); | |||
} else if (fieldname === 'owner') { | |||
label = __('Created By'); | |||
} else { | |||
label = frappe.meta.get_label(this.doctype, fieldname); | |||
fieldtype = frappe.meta.get_docfield(this.doctype, fieldname).fieldtype; | |||
let docfield = frappe.meta.get_docfield(this.doctype, fieldname); | |||
if (!docfield) { | |||
return; | |||
} | |||
fieldtype = docfield.fieldtype; | |||
} | |||
return `<li class="group-by-field list-link"> | |||
@@ -125,11 +125,14 @@ frappe.ui.FieldGroup = frappe.ui.form.Layout.extend({ | |||
return this.set_value(key, val); | |||
}, | |||
set_values: function(dict) { | |||
let promises = []; | |||
for(var key in dict) { | |||
if(this.fields_dict[key]) { | |||
this.set_value(key, dict[key]); | |||
promises.push(this.set_value(key, dict[key])); | |||
} | |||
} | |||
return Promise.all(promises); | |||
}, | |||
clear: function() { | |||
for(var key in this.fields_dict) { | |||
@@ -203,6 +203,7 @@ $.extend(frappe.ui.toolbar, { | |||
fullwidth = !fullwidth; | |||
localStorage.container_fullwidth = fullwidth; | |||
frappe.ui.toolbar.set_fullwidth_if_enabled(); | |||
$(document.body).trigger('toggleFullWidth'); | |||
}, | |||
set_fullwidth_if_enabled() { | |||
let fullwidth = JSON.parse(localStorage.container_fullwidth || 'false'); | |||
@@ -122,9 +122,11 @@ Object.assign(frappe.utils, { | |||
</a></p>'); | |||
return content.html(); | |||
}, | |||
scroll_to: function(element, animate, additional_offset) { | |||
scroll_to: function(element, animate, additional_offset, element_to_be_scrolled) { | |||
element_to_be_scrolled = element_to_be_scrolled || $("html, body"); | |||
var y = 0; | |||
if(element && typeof element==='number') { | |||
if (element && typeof element==="number") { | |||
y = element; | |||
} else if(element) { | |||
var header_offset = $(".navbar").height() + $(".page-head").height(); | |||
@@ -136,14 +138,14 @@ Object.assign(frappe.utils, { | |||
} | |||
// already there | |||
if(y==$('html, body').scrollTop()) { | |||
if (y == element_to_be_scrolled.scrollTop()) { | |||
return; | |||
} | |||
if (animate!==false) { | |||
$("html, body").animate({ scrollTop: y }); | |||
if (animate !== false) { | |||
element_to_be_scrolled.animate({ scrollTop: y }); | |||
} else { | |||
$(window).scrollTop(y); | |||
element_to_be_scrolled.scrollTop(y); | |||
} | |||
}, | |||
@@ -1,7 +1,6 @@ | |||
export default class Desktop { | |||
constructor({ wrapper }) { | |||
this.wrapper = wrapper; | |||
window.desk = this; | |||
this.pages = {}; | |||
this.sidebar_items = {}; | |||
this.sidebar_categories = [ | |||
@@ -45,12 +44,12 @@ export default class Desktop { | |||
this.desktop_settings = response.message; | |||
} else { | |||
frappe.throw({ | |||
title: "Couldn't Load Desk", | |||
title: __("Couldn't Load Desk"), | |||
message: | |||
"Something went wrong while loading Desk. <b>Please relaod the page</b>. If the problem persists, contact the Administrator", | |||
__("Something went wrong while loading Desk. <b>Please relaod the page</b>. If the problem persists, contact the Administrator"), | |||
indicator: "red", | |||
primary_action: { | |||
label: "Reload", | |||
label: __("Reload"), | |||
action: () => location.reload() | |||
} | |||
}); | |||
@@ -64,7 +63,7 @@ export default class Desktop { | |||
item.name}" class="sidebar-item ${ | |||
item.selected ? "selected" : "" | |||
}"> | |||
<span>${item.name}</span> | |||
<span>${item.label || item.name}</span> | |||
</div>`); | |||
}; | |||
@@ -79,8 +78,10 @@ export default class Desktop { | |||
}; | |||
const make_category_title = name => { | |||
// DO NOT REMOVE: Comment to load translation | |||
// __("Modules") __("Domains") __("Places") __("Administration") | |||
let $title = $( | |||
`<div class="sidebar-group-title h6 uppercase">${name}</div>` | |||
`<div class="sidebar-group-title h6 uppercase">${__(name)}</div>` | |||
); | |||
$title.appendTo(this.sidebar); | |||
}; | |||
@@ -106,8 +107,6 @@ export default class Desktop { | |||
} | |||
this.current_page = page; | |||
localStorage.current_desk_page = page; | |||
frappe.set_route("workspace", page); | |||
this.pages[page] ? this.pages[page].show() : this.make_page(page); | |||
} | |||
@@ -131,20 +130,20 @@ export default class Desktop { | |||
this.pages[page] = $page; | |||
return $page; | |||
} | |||
setup_events() {} | |||
} | |||
class DesktopPage { | |||
constructor({ container, page_name }) { | |||
frappe.desk_page = this; | |||
this.container = container; | |||
this.page_name = page_name; | |||
this.sections = {}; | |||
this.allow_customization = false; | |||
this.make(); | |||
this.reload(); | |||
} | |||
show() { | |||
frappe.desk_page = this; | |||
this.page.show(); | |||
} | |||
@@ -152,8 +151,34 @@ class DesktopPage { | |||
this.page.hide(); | |||
} | |||
reload() { | |||
this.in_customize_mode = false; | |||
this.page && this.page.remove(); | |||
this.make(); | |||
this.setup_events(); | |||
} | |||
make_customization_link() { | |||
this.customize_link = $(`<div class="small customize-options" style="cursor: pointer;">${__('Customize Workspace')}</div>`); | |||
this.customize_link.appendTo(this.page); | |||
this.customize_link.on('click', () => { | |||
this.customize(); | |||
}); | |||
this.save_or_discard_link = $(`<div class="small customize-options small-bounce"> | |||
<span class="save-customization">${__('Save')}</span> / <span class="discard-customization">${__('Discard')}</span> | |||
</div>`).hide(); | |||
this.save_or_discard_link.appendTo(this.page); | |||
this.save_or_discard_link.find(".save-customization").on("click", () => this.save_customization()); | |||
this.save_or_discard_link.find(".discard-customization").on("click", () => this.reload()); | |||
this.page.addClass('allow-customization'); | |||
} | |||
make() { | |||
this.make_page(); | |||
this.page = $(`<div class="desk-page" data-page-name=${this.page_name}></div>`); | |||
this.page.appendTo(this.container); | |||
this.get_data().then(res => { | |||
this.data = res.message; | |||
// this.make_onboarding(); | |||
@@ -163,28 +188,32 @@ class DesktopPage { | |||
return; | |||
} | |||
this.allow_customization = this.data.allow_customization || false; | |||
this.refresh(); | |||
}); | |||
} | |||
let create_shortcuts_and_cards = () => { | |||
this.data.shortcuts.items.length && this.make_shortcuts(); | |||
this.data.cards.items.length && this.make_cards(); | |||
}; | |||
refresh() { | |||
this.page.empty(); | |||
this.allow_customization = this.data.allow_customization || false; | |||
this.allow_customization && this.make_customization_link(); | |||
if (!this.sections["onboarding"] && this.data.charts.items.length) { | |||
this.make_charts().then(() => { | |||
create_shortcuts_and_cards(); | |||
}); | |||
} else { | |||
create_shortcuts_and_cards(); | |||
let create_shortcuts_and_cards = () => { | |||
this.data.shortcuts.items.length && this.make_shortcuts(); | |||
this.data.cards.items.length && this.make_cards(); | |||
if (this.allow_customization) { | |||
// Move the widget group up to align with labels if customization is allowed | |||
$('.desk-page .widget-group:visible:first').css('margin-top', '-25px'); | |||
} | |||
}); | |||
} | |||
}; | |||
make_page() { | |||
this.page = $( | |||
`<div class="desk-page" data-page-name=${this.page_name}></div>` | |||
); | |||
this.page.appendTo(this.container); | |||
if (!this.sections["onboarding"] && this.data.charts.items.length) { | |||
this.make_charts().then(() => { | |||
create_shortcuts_and_cards(); | |||
}); | |||
} else { | |||
create_shortcuts_and_cards(); | |||
} | |||
} | |||
get_data() { | |||
@@ -193,40 +222,50 @@ class DesktopPage { | |||
}); | |||
} | |||
make_onboarding() { | |||
this.sections["onboarding"] = new frappe.widget.WidgetGroup({ | |||
title: `Getting Started`, | |||
container: this.page, | |||
type: "onboarding", | |||
columns: 1, | |||
widgets: [ | |||
{ | |||
label: "Unlock Great Customer Experience", | |||
subtitle: "Just a few steps, and you’re good to go.", | |||
steps: [ | |||
{ | |||
label: "Configure Lead Sources", | |||
completed: true | |||
}, | |||
{ | |||
label: "Add Your Leads", | |||
completed: false | |||
}, | |||
{ | |||
label: "Create Your First Opportunity", | |||
completed: false | |||
}, | |||
{ | |||
label: "Onboard your Sales Team", | |||
completed: false | |||
}, | |||
{ | |||
label: "Assign Territories", | |||
completed: false | |||
} | |||
] | |||
} | |||
] | |||
setup_events() { | |||
$(document.body).on('toggleFullWidth', () => this.refresh()); | |||
} | |||
customize() { | |||
if (this.in_customize_mode) { | |||
return; | |||
} | |||
// It may be possible the chart area is hidden since it has no widgets | |||
// So the margin-top: -25px would be applied to the shortcut group | |||
// We need to remove this as the chart group will be visible during customization | |||
$('.desk-page .widget-group:visible:first').css('margin-top', '0px'); | |||
this.customize_link.hide(); | |||
this.save_or_discard_link.show(); | |||
Object.keys(this.sections).forEach(section => { | |||
this.sections[section].customize(); | |||
}); | |||
this.in_customize_mode = true; | |||
// Move the widget group up to align with labels if customization is allowed | |||
$('.desk-page .widget-group:visible:first').css('margin-top', '-25px'); | |||
} | |||
save_customization() { | |||
const config = {}; | |||
if (this.sections.charts) config.charts = this.sections.charts.get_widget_config(); | |||
if (this.sections.shortcuts) config.shortcuts = this.sections.shortcuts.get_widget_config(); | |||
if (this.sections.cards) config.cards = this.sections.cards.get_widget_config(); | |||
frappe.call('frappe.desk.desktop.save_customization', { | |||
page: this.page_name, | |||
config: config | |||
}).then(res => { | |||
if (res.message) { | |||
frappe.msgprint({ message: __("Customizations Saved Successfully"), title: __("Success")}); | |||
this.reload(); | |||
} else { | |||
frappe.throw({message: __("Something went wrong while saving customizations"), title: __("Failed")}); | |||
this.reload(); | |||
} | |||
}); | |||
} | |||
@@ -240,11 +279,18 @@ class DesktopPage { | |||
} | |||
this.sections["charts"] = new frappe.widget.WidgetGroup({ | |||
title: this.data.charts.label || `${this.page_name} Dashboard`, | |||
title: this.data.charts.label || __('{} Dashboard', [__(this.page_name)]), | |||
container: this.page, | |||
type: "chart", | |||
columns: 1, | |||
allow_sorting: false, | |||
options: { | |||
allow_sorting: this.allow_customization && !frappe.is_mobile(), | |||
allow_create: this.allow_customization, | |||
allow_delete: this.allow_customization, | |||
allow_hiding: false, | |||
allow_edit: true, | |||
max_widget_count: 2, | |||
}, | |||
widgets: this.data.charts.items | |||
}); | |||
}); | |||
@@ -252,22 +298,34 @@ class DesktopPage { | |||
make_shortcuts() { | |||
this.sections["shortcuts"] = new frappe.widget.WidgetGroup({ | |||
title: this.data.shortcuts.label || `Your Shortcuts`, | |||
title: this.data.shortcuts.label || __(`Your Shortcuts`), | |||
container: this.page, | |||
type: "bookmark", | |||
type: "shortcut", | |||
columns: 3, | |||
allow_sorting: this.allow_customization && frappe.is_mobile(), | |||
options: { | |||
allow_sorting: this.allow_customization && !frappe.is_mobile(), | |||
allow_create: this.allow_customization, | |||
allow_delete: this.allow_customization, | |||
allow_hiding: false, | |||
allow_edit: true, | |||
}, | |||
widgets: this.data.shortcuts.items | |||
}); | |||
} | |||
make_cards() { | |||
let cards = new frappe.widget.WidgetGroup({ | |||
title: this.data.cards.label || `Reports & Masters`, | |||
title: this.data.cards.label || __(`Reports & Masters`), | |||
container: this.page, | |||
type: "links", | |||
columns: 3, | |||
allow_sorting: this.allow_customization && frappe.is_mobile(), | |||
options: { | |||
allow_sorting: this.allow_customization && !frappe.is_mobile(), | |||
allow_create: false, | |||
allow_delete: false, | |||
allow_hiding: this.allow_customization, | |||
allow_edit: false, | |||
}, | |||
widgets: this.data.cards.items | |||
}); | |||
@@ -1,3 +1,5 @@ | |||
import get_dialog_constructor from './widget_dialog.js'; | |||
export default class Widget { | |||
constructor(opts) { | |||
Object.assign(this, opts); | |||
@@ -8,22 +10,71 @@ export default class Widget { | |||
this.set_title(); | |||
this.set_actions(); | |||
this.set_body(); | |||
this.setup_events(); | |||
} | |||
get_config() { | |||
return { | |||
name: this.name, | |||
label: this.label | |||
}; | |||
} | |||
customize() { | |||
customize(options) { | |||
this.in_customize_mode = true; | |||
this.action_area.empty(); | |||
options.allow_delete && | |||
this.add_custom_button( | |||
'<i class="fa fa-trash" aria-hidden="true"></i>', | |||
() => this.delete() | |||
); | |||
options.allow_sorting && | |||
this.add_custom_button( | |||
'<i class="fa fa-arrows" aria-hidden="true"></i>', | |||
null, | |||
"drag-handle" | |||
); | |||
if (options.allow_hiding) { | |||
if (this.hidden) { | |||
this.widget.removeClass("hidden"); | |||
this.body.css("opacity", 0.5); | |||
this.title_field.css("opacity", 0.5); | |||
this.footer.css("opacity", 0.5); | |||
} | |||
const classname = this.hidden ? 'fa fa-eye' : 'fa fa-eye-slash'; | |||
this.add_custom_button( | |||
`<i class="${classname}" aria-hidden="true"></i>`, | |||
() => this.hide_or_show(), | |||
"show-or-hide-button" | |||
); | |||
this.show_or_hide_button = this.action_area.find( | |||
".show-or-hide-button" | |||
); | |||
} | |||
options.allow_edit && | |||
this.add_custom_button( | |||
'<i class="fa fa-pencil" aria-hidden="true"></i>', | |||
() => this.edit() | |||
); | |||
} | |||
make() { | |||
this.make_widget(); | |||
this.widget.appendTo(this.container); | |||
this.setup_events(); | |||
} | |||
make_widget() { | |||
this.widget = $(`<div class="widget"> | |||
this.widget = $(`<div class="widget ${ | |||
this.hidden ? "hidden" : "" | |||
}" data-widget-name=${this.name ? this.name : ''}> | |||
<div class="widget-head"> | |||
<div class="widget-title"></div> | |||
<div class="widget-title ellipsis"></div> | |||
<div class="widget-control"></div> | |||
</div> | |||
<div class="widget-body"> | |||
@@ -37,24 +88,81 @@ export default class Widget { | |||
this.action_area = this.widget.find(".widget-control"); | |||
this.head = this.widget.find(".widget-head"); | |||
this.footer = this.widget.find(".widget-footer"); | |||
this.set_title(); | |||
this.set_actions(); | |||
this.set_body(); | |||
this.refresh(); | |||
} | |||
set_title() { | |||
this.title_field[0].innerHTML = this.label || this.name; | |||
this.title_field[0].innerHTML = this.label; | |||
} | |||
set_actions() { | |||
add_custom_button(html, action, class_name = "") { | |||
let button = $( | |||
`<button class="btn btn-default btn-xs ${class_name}">${html}</button>` | |||
); | |||
button.click(event => { | |||
event.stopPropagation(); | |||
action && action(); | |||
}); | |||
button.appendTo(this.action_area); | |||
} | |||
delete() { | |||
this.widget.addClass("zoomOutDelete"); | |||
// wait for animation | |||
setTimeout(() => { | |||
this.widget.remove(); | |||
this.options.on_delete && this.options.on_delete(this.name); | |||
}, 300); | |||
} | |||
edit() { | |||
const dialog_class = get_dialog_constructor(this.widget_type); | |||
this.edit_dialog = new dialog_class({ | |||
label: this.label, | |||
type: this.widget_type, | |||
values: this.get_config(), | |||
primary_action: (data) => { | |||
Object.assign(this, data); | |||
data.name = this.name; | |||
this.refresh(); | |||
}, | |||
primary_action_label: __("Save") | |||
}); | |||
this.edit_dialog.make(); | |||
} | |||
hide_or_show() { | |||
if (!this.hidden) { | |||
this.body.css("opacity", 0.5); | |||
this.title_field.css("opacity", 0.5); | |||
this.footer.css("opacity", 0.5); | |||
this.hidden = true; | |||
} else { | |||
this.body.css("opacity", 1); | |||
this.title_field.css("opacity", 1); | |||
this.footer.css("opacity", 1); | |||
this.hidden = false; | |||
} | |||
this.show_or_hide_button.empty(); | |||
const classname = this.hidden ? 'fa fa-eye' : 'fa fa-eye-slash'; | |||
$(`<i class="${classname}" aria-hidden="true"></i>`).appendTo( | |||
this.show_or_hide_button | |||
); | |||
} | |||
setup_events() { | |||
// | |||
} | |||
set_body() { | |||
set_actions() { | |||
// | |||
} | |||
setup_events() { | |||
set_body() { | |||
// | |||
} | |||
} | |||
} |
@@ -9,12 +9,19 @@ export default class ChartWidget extends Widget { | |||
this.height = 240; | |||
} | |||
refresh() { | |||
this.make_chart(); | |||
get_config() { | |||
return { | |||
name: this.name, | |||
chart_name: this.chart_name, | |||
label: this.label, | |||
}; | |||
} | |||
customize() { | |||
this.setup_customize_actions(); | |||
refresh() { | |||
delete this.dashboard_chart; | |||
this.set_title(); | |||
this.set_body(); | |||
this.make_chart(); | |||
} | |||
set_body() { | |||
@@ -67,28 +74,22 @@ export default class ChartWidget extends Widget { | |||
} | |||
this.setup_container(); | |||
this.prepare_chart_object(); | |||
this.action_area.empty(); | |||
this.prepare_chart_actions(); | |||
this.setup_filter_button(); | |||
if ( | |||
this.chart_doc.timeseries && | |||
this.chart_doc.chart_type !== "Custom" | |||
) { | |||
this.render_time_series_filters(); | |||
if (!this.in_customize_mode) { | |||
this.action_area.empty(); | |||
this.prepare_chart_actions(); | |||
this.setup_filter_button(); | |||
if ( | |||
this.chart_doc.timeseries && | |||
this.chart_doc.chart_type !== "Custom" | |||
) { | |||
this.render_time_series_filters(); | |||
} | |||
} | |||
this.fetch_and_update_chart(); | |||
}); | |||
} | |||
setup_customize_actions() { | |||
this.action_area.empty(); | |||
const buttons = $(`<button type="button" class="btn btn-xs btn-secondary btn-default selected">Resize</button> | |||
<button class="btn btn-secondary btn-light btn-danger btn-xs"><i class="fa fa-trash" aria-hidden="true"></i></button>`); | |||
buttons.appendTo(this.action_area); | |||
} | |||
render_time_series_filters() { | |||
let filters = [ | |||
{ | |||
@@ -428,9 +429,7 @@ export default class ChartWidget extends Widget { | |||
} | |||
fetch(filters, refresh = false, args) { | |||
let method = this.settings | |||
? this.settings.method | |||
: "frappe.desk.doctype.dashboard_chart.dashboard_chart.get"; | |||
let method = this.settings.method; | |||
if (this.chart_doc.chart_type == "Report") { | |||
args = { | |||
@@ -558,6 +557,9 @@ export default class ChartWidget extends Widget { | |||
}; | |||
return Promise.resolve(); | |||
} else { | |||
this.settings = { | |||
method: "frappe.desk.doctype.dashboard_chart.dashboard_chart.get" | |||
}; | |||
return Promise.resolve(); | |||
} | |||
}); | |||
@@ -6,8 +6,13 @@ export default class LinksWidget extends Widget { | |||
super(opts); | |||
} | |||
refresh() { | |||
// | |||
get_config() { | |||
return { | |||
name: this.name, | |||
links: JSON.stringify(this.links), | |||
label: this.label, | |||
hidden: this.hidden, | |||
}; | |||
} | |||
set_body() { | |||
@@ -75,21 +80,22 @@ export default class LinksWidget extends Widget { | |||
const popover = link.find(".module-link-popover"); | |||
link_label.mouseover(() => { | |||
if (this.in_customize_mode) return; | |||
popover.show(); | |||
}); | |||
link_label.mouseout(() => popover.hide()); | |||
} else { | |||
if (link_label.hasClass("help-video-link")) { | |||
link_label.click(event => { | |||
link_label.click(event => { | |||
if (this.in_customize_mode) return; | |||
if (link_label.hasClass("help-video-link")) { | |||
let yt_id = event.target.dataset.youtubeid; | |||
frappe.help.show_video(yt_id); | |||
}); | |||
} else { | |||
link_label.click(event => { | |||
} else { | |||
let route = event.target.dataset.route; | |||
frappe.set_route(route); | |||
}); | |||
} | |||
} | |||
}); | |||
} | |||
}); | |||
} |
@@ -0,0 +1,52 @@ | |||
import get_dialog_constructor from "./widget_dialog.js"; | |||
export default class NewWidget { | |||
constructor(opts) { | |||
Object.assign(this, opts); | |||
this.make(); | |||
} | |||
customize() { | |||
return; | |||
} | |||
make() { | |||
this.make_widget(); | |||
this.widget.appendTo(this.container); | |||
this.setup_events(); | |||
} | |||
get_title() { | |||
// DO NOT REMOVE: Comment to load translation | |||
// __("New Chart") __("New Shortcut") | |||
return __(`New ${frappe.utils.to_title_case(this.type)}`); | |||
} | |||
make_widget() { | |||
this.widget = $(`<div class="widget new-widget"> | |||
+ ${this.get_title()} | |||
</div>`); | |||
this.body = this.widget; | |||
} | |||
setup_events() { | |||
this.widget.on("click", () => this.open_dialog()); | |||
} | |||
open_dialog() { | |||
const dialog_class = get_dialog_constructor(this.type); | |||
this.dialog = new dialog_class({ | |||
label: this.label, | |||
type: this.type, | |||
values: false, | |||
primary_action: this.on_create, | |||
}); | |||
this.dialog.make(); | |||
} | |||
delete() { | |||
this.widget.remove(); | |||
} | |||
} |
@@ -3,7 +3,6 @@ import Widget from "./base_widget.js"; | |||
export default class OnboardingWidget extends Widget { | |||
constructor(opts) { | |||
super(opts); | |||
window.onb = this; | |||
} | |||
refresh() { } | |||
@@ -1,48 +1,62 @@ | |||
import Widget from "./base_widget.js"; | |||
import { generate_route } from "./utils"; | |||
// import { get_luminosity, shadeColor } from "./utils"; | |||
String.prototype.format = function () { | |||
var i = 0, args = arguments; | |||
return this.replace(/{}/g, function () { | |||
return typeof args[i] != 'undefined' ? args[i++] : ''; | |||
}); | |||
}; | |||
export default class ShortcutWidget extends Widget { | |||
constructor(opts) { | |||
super(opts); | |||
} | |||
refresh() { | |||
// | |||
get_config() { | |||
return { | |||
name: this.name, | |||
icon: this.icon, | |||
label: this.label, | |||
format: this.format, | |||
link_to: this.link_to, | |||
color: this.color, | |||
restrict_to_domain: this.restrict_to_domain, | |||
stats_filter: this.stats_filter, | |||
type: this.type, | |||
}; | |||
} | |||
setup_events() { | |||
this.widget.click(() => { | |||
let route = generate_route(this) | |||
frappe.set_route(route) | |||
}) | |||
if (this.in_customize_mode) return; | |||
let route = generate_route({ | |||
route: this.route, | |||
name: this.link_to, | |||
type: this.type, | |||
is_query_report: this.is_query_report, | |||
doctype: this.ref_doctype | |||
}); | |||
frappe.set_route(route); | |||
}); | |||
} | |||
set_actions() { | |||
this.widget.addClass('shortcut-widget-box'); | |||
const get_filter = new Function(`return ${this.stats_filter}`) | |||
if (this.in_customize_mode) return; | |||
this.widget.addClass("shortcut-widget-box"); | |||
const get_filter = new Function(`return ${this.stats_filter}`); | |||
if (this.type == "DocType" && this.stats_filter) { | |||
frappe.db.count(this.link_to, { | |||
filters: get_filter() | |||
}).then(count => this.set_count(count)) | |||
frappe.db | |||
.count(this.link_to, { | |||
filters: get_filter(), | |||
}) | |||
.then((count) => this.set_count(count)); | |||
} | |||
} | |||
set_title() { | |||
if (this.icon) { | |||
this.title_field[0].innerHTML = `<div> | |||
<i class="${this.icon}" style="color: rgb(141, 153, 166); font-size: 18px; margin-right: 6px;"></i> | |||
<i class="${this.icon}" style=""></i> | |||
${this.label || this.name} | |||
</div>` | |||
} | |||
else { | |||
</div>`; | |||
} else { | |||
super.set_title(); | |||
} | |||
} | |||
@@ -50,19 +64,22 @@ export default class ShortcutWidget extends Widget { | |||
set_count(count) { | |||
const get_label = () => { | |||
if (this.format) { | |||
return this.format.format(count); | |||
return this.format.replace(/{}/g, count); | |||
} | |||
return count | |||
} | |||
return count; | |||
}; | |||
this.action_area.empty(); | |||
const label = get_label(); | |||
const buttons = $(`<div class="small pill">${label}</div>`); | |||
if(this.color) { | |||
buttons.css('background-color', this.color); | |||
buttons.css('color', frappe.ui.color.get_contrast_color(this.color)) | |||
if (this.color) { | |||
buttons.css("background-color", this.color); | |||
buttons.css( | |||
"color", | |||
frappe.ui.color.get_contrast_color(this.color) | |||
); | |||
} | |||
buttons.appendTo(this.action_area); | |||
} | |||
} | |||
} |
@@ -0,0 +1,266 @@ | |||
class WidgetDialog { | |||
constructor(opts) { | |||
Object.assign(this, opts); | |||
this.editing = Boolean(this.values && Object.keys(this.values).length); | |||
} | |||
make() { | |||
this.make_dialog(); | |||
this.setup_dialog_events(); | |||
this.dialog.show(); | |||
this.editing && this.set_default_values(); | |||
} | |||
make_dialog() { | |||
this.dialog = new frappe.ui.Dialog({ | |||
title: this.get_title(), | |||
fields: this.get_fields(), | |||
primary_action: (data) => { | |||
data = this.process_data(data); | |||
if (!this.editing) { | |||
data.name = `${this.type}-${this.label}-${frappe.utils.get_random(20)}`; | |||
} | |||
this.dialog.hide(); | |||
this.primary_action(data); | |||
}, | |||
primary_action_label: this.primary_action_label || __("Add"), | |||
}); | |||
} | |||
get_title() { | |||
// DO NOT REMOVE: Comment to load translation | |||
// __("New Chart") __("New Shortcut") __("Edit Chart") __("Edit Shortcut") | |||
let action = this.editing ? "Edit" : "Add"; | |||
return __(`${action} ${frappe.utils.to_title_case(this.type)}`); | |||
} | |||
get_fields() { | |||
// | |||
} | |||
set_default_values() { | |||
return this.dialog.set_values(this.values); | |||
} | |||
process_data(data) { | |||
return data; | |||
} | |||
setup_dialog_events() { | |||
// | |||
} | |||
hide_field(fieldname) { | |||
this.dialog.set_df_property(fieldname, "hidden", true); | |||
} | |||
show_field(fieldname) { | |||
this.dialog.set_df_property(fieldname, "hidden", false); | |||
} | |||
} | |||
class ChartDialog extends WidgetDialog { | |||
constructor(opts) { | |||
super(opts); | |||
} | |||
get_fields() { | |||
return [ | |||
{ | |||
fieldtype: "Link", | |||
fieldname: "chart_name", | |||
label: "Chart Name", | |||
options: "Dashboard Chart", | |||
reqd: 1, | |||
}, | |||
{ | |||
fieldtype: "Data", | |||
fieldname: "label", | |||
label: "Label", | |||
}, | |||
]; | |||
} | |||
process_data(data) { | |||
data.label = data.label ? data.label : data.chart_name; | |||
return data; | |||
} | |||
} | |||
class ShortcutDialog extends WidgetDialog { | |||
constructor(opts) { | |||
super(opts); | |||
} | |||
hide_filters() { | |||
this.hide_field("count_section_break"); | |||
this.hide_field("filters_section_break"); | |||
} | |||
show_filters() { | |||
this.show_field("count_section_break"); | |||
this.show_field("filters_section_break"); | |||
} | |||
get_fields() { | |||
return [ | |||
{ | |||
fieldtype: "Select", | |||
fieldname: "type", | |||
label: "Type", | |||
reqd: 1, | |||
options: "DocType\nReport\nPage", | |||
onchange: () => { | |||
if (this.dialog.get_value("type") == "DocType") { | |||
this.dialog.fields_dict.link_to.get_query = () => { | |||
return { filters: { istable: false } }; | |||
}; | |||
} else { | |||
this.dialog.fields_dict.link_to.get_query = null; | |||
} | |||
}, | |||
}, | |||
{ | |||
fieldtype: "Data", | |||
fieldname: "label", | |||
label: "Label", | |||
}, | |||
{ | |||
fieldtype: "Column Break", | |||
fieldname: "column_break_4", | |||
}, | |||
{ | |||
fieldtype: "Dynamic Link", | |||
fieldname: "link_to", | |||
label: "Link To", | |||
reqd: 1, | |||
options: "type", | |||
onchange: () => { | |||
if (this.dialog.get_value("type") == "DocType") { | |||
let doctype = this.dialog.get_value("link_to"); | |||
doctype && | |||
frappe.db | |||
.get_value("DocType", doctype, "issingle") | |||
.then((res) => { | |||
if (res.message && res.message.issingle) { | |||
this.hide_filters(); | |||
} else { | |||
this.setup_filter(doctype); | |||
this.show_filters(); | |||
} | |||
}); | |||
} else { | |||
this.hide_filters(); | |||
} | |||
}, | |||
}, | |||
{ | |||
fieldtype: "Section Break", | |||
fieldname: "filters_section_break", | |||
label: "Count Filter", | |||
hidden: 1, | |||
}, | |||
{ | |||
fieldtype: "HTML", | |||
fieldname: "filter_area_loading", | |||
}, | |||
{ | |||
fieldtype: "HTML", | |||
fieldname: "filter_area", | |||
hidden: 1, | |||
}, | |||
{ | |||
fieldtype: "Section Break", | |||
fieldname: "count_section_break", | |||
label: "Count Customizations", | |||
hidden: 1, | |||
}, | |||
{ | |||
fieldtype: "Color", | |||
fieldname: "color", | |||
label: "Color", | |||
}, | |||
{ | |||
fieldtype: "Column Break", | |||
fieldname: "column_break_3", | |||
}, | |||
{ | |||
fieldtype: "Data", | |||
fieldname: "format", | |||
label: "Format", | |||
description: "For Example: {} Open", | |||
}, | |||
]; | |||
} | |||
set_default_values() { | |||
super.set_default_values().then(() => { | |||
this.dialog.fields_dict.link_to.df.onchange(); | |||
}); | |||
} | |||
process_data(data) { | |||
let stats_filter = {}; | |||
if (this.dialog.get_value("type") == "DocType" && this.filter_group) { | |||
let filters = this.filter_group.get_filters(); | |||
filters.forEach((arr) => { | |||
stats_filter[arr[1]] = [arr[2], arr[3]]; | |||
}); | |||
data.stats_filter = JSON.stringify(stats_filter); | |||
} | |||
data.label = data.label | |||
? data.label | |||
: frappe.model.unscrub(data.link_to); | |||
return data; | |||
} | |||
setup_filter(doctype) { | |||
if (this.filter_group) { | |||
this.filter_group.wrapper.empty(); | |||
delete this.filter_group; | |||
} | |||
let $loading = this.dialog.get_field("filter_area_loading").$wrapper; | |||
$(`<span class="text-muted">Loading Filters...</span>`).appendTo($loading); | |||
this.filters = []; | |||
if (this.values && this.values.stats_filter) { | |||
const filters_json = JSON.parse(this.values.stats_filter); | |||
this.filters = Object.keys(filters_json).map((filter) => { | |||
let val = filters_json[filter]; | |||
return [this.values.link_to, filter, val[0], val[1], false]; | |||
}); | |||
} | |||
this.filter_group = new frappe.ui.FilterGroup({ | |||
parent: this.dialog.get_field("filter_area").$wrapper, | |||
doctype: doctype, | |||
on_change: () => {}, | |||
}); | |||
frappe.model.with_doctype(doctype, () => { | |||
this.filter_group.add_filters_to_filter_group(this.filters); | |||
this.hide_field("filter_area_loading"); | |||
this.show_field("filter_area"); | |||
}); | |||
} | |||
} | |||
export default function get_dialog_constructor(type) { | |||
const widget_map = { | |||
chart: ChartDialog, | |||
shortcut: ShortcutDialog, | |||
}; | |||
return widget_map[type] || WidgetDialog; | |||
} |
@@ -3,46 +3,31 @@ import BaseWidget from "../widgets/base_widget"; | |||
import ShortcutWidget from "../widgets/shortcut_widget"; | |||
import LinksWidget from "../widgets/links_widget"; | |||
import OnboardingWidget from "../widgets/onboarding_widget"; | |||
import NewWidget from "../widgets/new_widget"; | |||
frappe.provide('frappe.widget') | |||
frappe.provide("frappe.widget"); | |||
const widget_factory = { | |||
chart: ChartWidget, | |||
base: BaseWidget, | |||
bookmark: ShortcutWidget, | |||
shortcut: ShortcutWidget, | |||
links: LinksWidget, | |||
onboarding: OnboardingWidget | |||
onboarding: OnboardingWidget, | |||
}; | |||
export default class WidgetGroup { | |||
constructor(opts) { | |||
Object.assign(this, opts); | |||
// opts = { | |||
// title: "CRM Dashboard", | |||
// container: $(''), | |||
// widgets: [ | |||
// {type: "dashboard", width: "Full", options: {}}. | |||
// {type: "dashboard", width: "Full", options: {}} | |||
// ], | |||
// allow_delete: true, | |||
// allow_create: true, | |||
// allow_rearrange: true, | |||
// hide_edit_option: false, | |||
// collapsible: false | |||
// } | |||
window.wid_area = this; | |||
this.widgets_list = []; | |||
this.widgets_dict = {}; | |||
this.widget_order = []; | |||
this.make(); | |||
} | |||
make() { | |||
this.make_container(); | |||
this.refresh(); | |||
} | |||
refresh() { | |||
this.title && this.set_title(this.title); | |||
this.title && this.set_title(); | |||
this.widgets && this.make_widgets(); | |||
this.allow_sorting && this.setup_sortable(); | |||
} | |||
make_container() { | |||
@@ -58,22 +43,94 @@ export default class WidgetGroup { | |||
this.title_area = widget_area.find(".widget-group-title"); | |||
this.control_area = widget_area.find(".widget-group-control"); | |||
this.body = widget_area.find(".widget-group-body"); | |||
!this.widgets.length && this.widget_area.hide(); | |||
widget_area.appendTo(this.container); | |||
} | |||
set_title(title) { | |||
set_title() { | |||
this.title_area[0].innerText = this.title; | |||
} | |||
make_widgets() { | |||
this.body.empty() | |||
this.body.empty(); | |||
this.widgets.forEach((widget) => { | |||
this.add_widget(widget); | |||
}); | |||
} | |||
add_widget(widget) { | |||
const widget_class = widget_factory[this.type]; | |||
this.widgets.forEach(widget => { | |||
new widget_class({ | |||
...widget, | |||
container: this.body | |||
}) | |||
let widget_object = new widget_class({ | |||
...widget, | |||
widget_type: this.type, | |||
container: this.body, | |||
options: { | |||
...this.options, | |||
on_delete: (name) => this.on_delete(name), | |||
}, | |||
}); | |||
this.widgets_list.push(widget_object); | |||
this.widgets_dict[widget.name] = widget_object; | |||
return widget_object; | |||
} | |||
customize() { | |||
this.widget_area.show(); | |||
this.widgets_list.forEach((wid) => { | |||
wid.customize(this.options); | |||
}); | |||
this.options.allow_create && this.setup_new_widget(); | |||
this.options.allow_sorting && this.setup_sortable(); | |||
} | |||
setup_new_widget() { | |||
const max = this.options | |||
? this.options.max_widget_count || Number.POSITIVE_INFINITY | |||
: Number.POSITIVE_INFINITY; | |||
if (this.widgets_list.length < max) { | |||
this.new_widget = new NewWidget({ | |||
container: this.body, | |||
type: this.type, | |||
on_create: (config) => { | |||
// Remove new widget | |||
this.new_widget.delete(); | |||
delete this.new_widget; | |||
config.in_customize_mode = 1; | |||
// Add new widget and customize it | |||
let wid = this.add_widget(config); | |||
wid.customize(this.options); | |||
// Put back the new widget if required | |||
if (this.widgets_list.length < max) { | |||
this.setup_new_widget(); | |||
} | |||
}, | |||
}); | |||
} | |||
} | |||
on_delete(name) { | |||
this.widgets_list = this.widgets_list.filter((wid) => name != wid.name); | |||
delete this.widgets_dict[name]; | |||
this.update_widget_order(); | |||
if (!this.new_widget) this.setup_new_widget(); | |||
} | |||
update_widget_order() { | |||
this.widget_order = []; | |||
this.body.children().each((index, element) => { | |||
let name = element.dataset.widgetName; | |||
if (name) { | |||
this.widget_order.push(name); | |||
} | |||
}); | |||
} | |||
@@ -81,13 +138,26 @@ export default class WidgetGroup { | |||
const container = this.body[0]; | |||
this.sortable = new Sortable(container, { | |||
animation: 150, | |||
onEnd: () => { | |||
console.log("Sorting") | |||
}, | |||
// onChoose: (evt) => this.sortable_config.on_choose(evt, container), | |||
// onStart: (evt) => this.sortable_config.on_start(evt, container) | |||
handle: ".drag-handle", | |||
onEnd: () => this.update_widget_order(), | |||
}); | |||
} | |||
get_widget_config() { | |||
this.update_widget_order(); | |||
let prepared_dict = {}; | |||
this.widgets_list.forEach((wid) => { | |||
let config = wid.get_config(); | |||
let name = config.docname ? config.docname : config.name; | |||
prepared_dict[name] = config; | |||
}); | |||
return { | |||
order: this.widget_order, | |||
widgets: prepared_dict, | |||
}; | |||
} | |||
} | |||
frappe.widget.WidgetGroup = WidgetGroup; | |||
frappe.widget.WidgetGroup = WidgetGroup; |
@@ -76,6 +76,24 @@ | |||
position: relative; | |||
min-height: 1px; | |||
padding-right: 15px; | |||
.desk-page.allow-customization { | |||
.customize-options { | |||
text-align: right; | |||
margin-top: 7px; | |||
color: @text-muted; | |||
z-index: 99; | |||
.save-customization { | |||
cursor: pointer; | |||
color: @text-color; | |||
} | |||
.discard-customization { | |||
cursor: pointer; | |||
} | |||
} | |||
} | |||
} | |||
@media (max-width: 768px) { | |||
@@ -90,6 +108,9 @@ | |||
.widget-group { | |||
margin-bottom: 25px; | |||
// -webkit-animation-name: slideInUp; | |||
// animation-name: slideInUp; | |||
// animation-duration: 0.4s; | |||
.widget-group-head { | |||
display: flex; | |||
@@ -201,6 +222,17 @@ | |||
margin-left: 5px; | |||
} | |||
.drag-handle { | |||
cursor: all-scroll; | |||
cursor: -webkit-grabbing; | |||
&:active { | |||
cursor: grabbing; | |||
cursor: -moz-grabbing; | |||
cursor: -webkit-grabbing; | |||
} | |||
} | |||
.dashboard-date-field { | |||
.clearfix, | |||
.help-box { | |||
@@ -220,6 +252,16 @@ | |||
border-color: @disabled-background | |||
} | |||
&.new-widget { | |||
min-height: 65px; | |||
background-color: @disabled-background; | |||
color: @text-muted; | |||
display: flex; | |||
align-content: center; | |||
justify-content: center; | |||
cursor: pointer; | |||
} | |||
// Overrides for each widgets | |||
&.dashboard-widget-box { | |||
padding: 10px 15px !important; | |||
@@ -300,6 +342,14 @@ | |||
.widget-head { | |||
margin-top: 5px; | |||
margin-bottom: 5px; | |||
.widget-title { | |||
i { | |||
color: @text-muted; | |||
font-size: 18px; | |||
margin-right: 6px; | |||
} | |||
} | |||
} | |||
} | |||
@@ -357,23 +407,153 @@ | |||
border-radius: 10px; | |||
} | |||
.pill-green { | |||
background: #71b92c; | |||
// color: #000; | |||
@-webkit-keyframes smallBounce { | |||
from, | |||
20%, | |||
53%, | |||
80%, | |||
to { | |||
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); | |||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); | |||
-webkit-transform: translate3d(0, 0, 0); | |||
transform: translate3d(0, 0, 0); | |||
} | |||
40%, | |||
43% { | |||
-webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); | |||
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); | |||
-webkit-transform: translate3d(0, -12px, 0); | |||
transform: translate3d(0, -12px, 0); | |||
} | |||
70% { | |||
-webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); | |||
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); | |||
-webkit-transform: translate3d(0, -6px, 0); | |||
transform: translate3d(0, -6px, 0); | |||
} | |||
90% { | |||
-webkit-transform: translate3d(0, -4px, 0); | |||
transform: translate3d(0, -4px, 0); | |||
} | |||
} | |||
@keyframes smallBounce { | |||
from, | |||
20%, | |||
53%, | |||
80%, | |||
to { | |||
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); | |||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); | |||
-webkit-transform: translate3d(0, 0, 0); | |||
transform: translate3d(0, 0, 0); | |||
} | |||
40%, | |||
43% { | |||
-webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); | |||
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); | |||
-webkit-transform: translate3d(0, -12px, 0); | |||
transform: translate3d(0, -12px, 0); | |||
} | |||
70% { | |||
-webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); | |||
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); | |||
-webkit-transform: translate3d(0, -6px, 0); | |||
transform: translate3d(0, -6px, 0); | |||
} | |||
90% { | |||
-webkit-transform: translate3d(0, -4px, 0); | |||
transform: translate3d(0, -4px, 0); | |||
} | |||
} | |||
.small-bounce { | |||
-webkit-animation-name: smallBounce; | |||
animation-name: smallBounce; | |||
-webkit-transform-origin: center bottom; | |||
transform-origin: center bottom; | |||
animation-duration: 1s; | |||
} | |||
@-webkit-keyframes slideInUp { | |||
from { | |||
-webkit-transform: translate3d(0, 100%, 0); | |||
transform: translate3d(0, 100%, 0); | |||
visibility: visible; | |||
} | |||
to { | |||
-webkit-transform: translate3d(0, 0, 0); | |||
transform: translate3d(0, 0, 0); | |||
} | |||
} | |||
@keyframes slideInUp { | |||
from { | |||
-webkit-transform: translate3d(0, 100%, 0); | |||
transform: translate3d(0, 100%, 0); | |||
visibility: visible; | |||
} | |||
to { | |||
-webkit-transform: translate3d(0, 0, 0); | |||
transform: translate3d(0, 0, 0); | |||
} | |||
} | |||
.pill-red { | |||
background: @red; | |||
.slide-in-up { | |||
-webkit-animation-name: slideInUp; | |||
animation-name: slideInUp; | |||
animation-duration: 1s; | |||
} | |||
.pill-blue { | |||
background: @blue; | |||
@-webkit-keyframes pulse { | |||
from { | |||
-webkit-transform: scale3d(1, 1, 1); | |||
transform: scale3d(1, 1, 1); | |||
} | |||
50% { | |||
-webkit-transform: scale3d(1.05, 1.05, 1.05); | |||
transform: scale3d(1.05, 1.05, 1.05); | |||
} | |||
to { | |||
-webkit-transform: scale3d(1, 1, 1); | |||
transform: scale3d(1, 1, 1); | |||
} | |||
} | |||
.pill-yellow { | |||
background: @yellow; | |||
@keyframes pulse { | |||
from { | |||
-webkit-transform: scale3d(1, 1, 1); | |||
transform: scale3d(1, 1, 1); | |||
} | |||
50% { | |||
-webkit-transform: scale3d(1.05, 1.05, 1.05); | |||
transform: scale3d(1.05, 1.05, 1.05); | |||
} | |||
to { | |||
-webkit-transform: scale3d(1, 1, 1); | |||
transform: scale3d(1, 1, 1); | |||
} | |||
} | |||
.pill-orange { | |||
background: @orange; | |||
.zoomOutDelete { | |||
// -webkit-animation-name: zoomOut; | |||
// animation-name: zoomOut; | |||
// animation-duration: 1s; | |||
transition: opacity 0.2s, visibility 0.2s, transform 0.2s; | |||
transform: scale3d(0.5, 0.5, 0.5); | |||
opacity: 0; | |||
visibility: hidden; | |||
} |
@@ -262,6 +262,11 @@ | |||
border-bottom: 1px solid @border-color; | |||
} | |||
.grid-form-body { | |||
max-height: 75vh; | |||
overflow-y: auto; | |||
} | |||
.grid-header-toolbar { | |||
display: flow-root; | |||
} | |||
@@ -37,6 +37,7 @@ | |||
padding-bottom: 5px; | |||
max-width: 330px; | |||
min-width: 200px; | |||
overflow-wrap: break-word; | |||
.preview-field { | |||
padding-bottom: 10px; | |||
@@ -7,5 +7,6 @@ | |||
<a href="{{ link }}" rel="nofollow" class="btn btn-primary btn-sm primary-action" style="padding: 8px 20px;">{{ _("Confirm Request") }}</a> | |||
</p> | |||
<p style="font-size: 85%;"> | |||
{{_("You can also copy-paste this ")}} <a href="{{ link }}">{{_("Verification Link")}}</a>{{_(" to your browser")}} | |||
{% set verification_link = '<a href="{{ link }}">{{ _("Verification Link") }}</a>' %} | |||
{{_("You can also copy-paste this {0} to your browser").format(verification_link) }} | |||
</p> |
@@ -4,9 +4,10 @@ | |||
<ol class="breadcrumb" itemscope itemtype="http://schema.org/BreadcrumbList"> | |||
{%- set parents = parents[-3:] %} | |||
{% for parent in parents %} | |||
<li class="breadcrumb-item"> | |||
<a href="{{ url_prefix }}{{ parent.route | abs_url }}" itemprop="url"> | |||
{{ parent.title or parent.label or parent.name or "" }} | |||
<li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem" class="breadcrumb-item"> | |||
<a itemprop="item" href="{{ url_prefix }}{{ parent.route | abs_url }}" itemprop="url"> | |||
<span itemprop="name">{{ parent.title or parent.label or parent.name or "" }}</span> | |||
<meta itemprop="position" content="{{ loop.index }}" /> | |||
</a> | |||
</li> | |||
{% endfor %} | |||
@@ -137,3 +137,29 @@ p { | |||
position: absolute; | |||
z-index: 2; | |||
} | |||
.invalid-login { | |||
-webkit-animation: wiggle 0.5s linear; | |||
} | |||
@-webkit-keyframes wiggle { | |||
8%, | |||
41% { | |||
-webkit-transform: translateX(-10px); | |||
} | |||
25%, | |||
58% { | |||
-webkit-transform: translateX(10px); | |||
} | |||
75% { | |||
-webkit-transform: translateX(-5px); | |||
} | |||
92% { | |||
-webkit-transform: translateX(5px); | |||
} | |||
0%, | |||
100% { | |||
-webkit-transform: translateX(0); | |||
} | |||
} | |||
@@ -141,6 +141,14 @@ login.set_indicator = function(message, color) { | |||
.removeClass().addClass('indicator').addClass(color).text(message) | |||
} | |||
login.set_invalid = function(message) { | |||
$(".login-content.page-card").addClass('invalid-login'); | |||
setTimeout(() => { | |||
$(".login-content.page-card").removeClass('invalid-login'); | |||
}, 500) | |||
login.set_indicator(message, 'red'); | |||
} | |||
login.login_handlers = (function() { | |||
var get_error_handler = function(default_message) { | |||
return function(xhr, data) { | |||
@@ -161,7 +169,7 @@ login.login_handlers = (function() { | |||
} | |||
if(message===default_message) { | |||
login.set_indicator(message, 'red'); | |||
login.set_invalid(message); | |||
} else { | |||
login.reset_sections(false); | |||
} | |||
@@ -181,7 +181,7 @@ class TestDocument(unittest.TestCase): | |||
# css attributes | |||
xss = '<div style="something: doesn\'t work; color: red;">Test</div>' | |||
escaped_xss = '<div style="color: red;">Test</div>' | |||
escaped_xss = '<div style="">Test</div>' | |||
d.subject += xss | |||
d.save() | |||
d.reload() | |||
@@ -54,8 +54,8 @@ def get_datetime(datetime_str=None): | |||
elif isinstance(datetime_str, datetime.date): | |||
return datetime.datetime.combine(datetime_str, datetime.time()) | |||
# dateutil parser does not agree with dates like 0001-01-01 | |||
if not datetime_str or (datetime_str or "").startswith("0001-01-01"): | |||
# dateutil parser does not agree with dates like "0001-01-01" or "0000-00-00" | |||
if not datetime_str or (datetime_str or "").startswith(("0001-01-01", "0000-00-00")): | |||
return None | |||
try: | |||
@@ -1,26 +1,29 @@ | |||
{ | |||
"cards": [ | |||
{ | |||
"icon": "fa fa-cog", | |||
"links": "[\n {\n \"description\": \"Setup of top navigation bar, footer and logo.\",\n \"label\": \"Website Settings\",\n \"name\": \"Website Settings\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"List of themes for Website.\",\n \"label\": \"Website Theme\",\n \"name\": \"Website Theme\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Javascript to append to the head section of the page.\",\n \"label\": \"Website Script\",\n \"name\": \"Website Script\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Settings for About Us Page.\",\n \"label\": \"About Us Settings\",\n \"name\": \"About Us Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Settings for Contact Us Page.\",\n \"label\": \"Contact Us Settings\",\n \"name\": \"Contact Us Settings\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Setup" | |||
"hidden": 0, | |||
"label": "Setup", | |||
"links": "[\n {\n \"description\": \"Setup of top navigation bar, footer and logo.\",\n \"label\": \"Website Settings\",\n \"name\": \"Website Settings\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"List of themes for Website.\",\n \"label\": \"Website Theme\",\n \"name\": \"Website Theme\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Javascript to append to the head section of the page.\",\n \"label\": \"Website Script\",\n \"name\": \"Website Script\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Settings for About Us Page.\",\n \"label\": \"About Us Settings\",\n \"name\": \"About Us Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Settings for Contact Us Page.\",\n \"label\": \"Contact Us Settings\",\n \"name\": \"Contact Us Settings\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"links": "[\n {\n \"description\": \"Single Post (article).\",\n \"label\": \"Blog Post\",\n \"name\": \"Blog Post\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"A user who posts blogs.\",\n \"label\": \"Blogger\",\n \"name\": \"Blogger\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Categorize blog posts.\",\n \"label\": \"Blog Category\",\n \"name\": \"Blog Category\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Blog" | |||
"hidden": 0, | |||
"label": "Blog", | |||
"links": "[\n {\n \"description\": \"Single Post (article).\",\n \"label\": \"Blog Post\",\n \"name\": \"Blog Post\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"A user who posts blogs.\",\n \"label\": \"Blogger\",\n \"name\": \"Blogger\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Categorize blog posts.\",\n \"label\": \"Blog Category\",\n \"name\": \"Blog Category\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"icon": "fa fa-star", | |||
"links": "[\n {\n \"description\": \"Content web page.\",\n \"label\": \"Web Page\",\n \"name\": \"Web Page\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"User editable form on Website.\",\n \"label\": \"Web Form\",\n \"name\": \"Web Form\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Website Sidebar\",\n \"name\": \"Website Sidebar\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Embed image slideshows in website pages.\",\n \"label\": \"Website Slideshow\",\n \"name\": \"Website Slideshow\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Add meta tags to your web pages\",\n \"label\": \"Website Route Meta\",\n \"name\": \"Website Route Meta\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Web Site" | |||
"hidden": 0, | |||
"label": "Web Site", | |||
"links": "[\n {\n \"description\": \"Content web page.\",\n \"label\": \"Web Page\",\n \"name\": \"Web Page\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"User editable form on Website.\",\n \"label\": \"Web Form\",\n \"name\": \"Web Form\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Website Sidebar\",\n \"name\": \"Website Sidebar\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Embed image slideshows in website pages.\",\n \"label\": \"Website Slideshow\",\n \"name\": \"Website Slideshow\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Add meta tags to your web pages\",\n \"label\": \"Website Route Meta\",\n \"name\": \"Website Route Meta\",\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"links": "[\n {\n \"label\": \"Portal Settings\",\n \"name\": \"Portal Settings\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Portal" | |||
"hidden": 0, | |||
"label": "Portal", | |||
"links": "[\n {\n \"label\": \"Portal Settings\",\n \"name\": \"Portal Settings\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]" | |||
}, | |||
{ | |||
"links": "[\n {\n \"label\": \"Help Category\",\n \"name\": \"Help Category\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Help Article\",\n \"name\": \"Help Article\",\n \"type\": \"doctype\"\n }\n]", | |||
"title": "Knowledge Base" | |||
"hidden": 0, | |||
"label": "Knowledge Base", | |||
"links": "[\n {\n \"label\": \"Help Category\",\n \"name\": \"Help Category\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Help Article\",\n \"name\": \"Help Article\",\n \"type\": \"doctype\"\n }\n]" | |||
} | |||
], | |||
"category": "Modules", | |||
@@ -34,7 +37,7 @@ | |||
"idx": 0, | |||
"is_standard": 1, | |||
"label": "Website", | |||
"modified": "2020-03-12 16:30:43.092622", | |||
"modified": "2020-04-01 11:24:40.726934", | |||
"modified_by": "Administrator", | |||
"module": "Website", | |||
"name": "Website", | |||
@@ -45,30 +48,30 @@ | |||
{ | |||
"color": "", | |||
"format": "{} Published", | |||
"is_query_report": 0, | |||
"label": "Blog Post", | |||
"link_to": "Blog Post", | |||
"stats_filter": "{\"published\":\"1\"}", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"format": "{} Active", | |||
"is_query_report": 0, | |||
"label": "Blogger", | |||
"link_to": "Blogger", | |||
"stats_filter": "{\"disabled\": 0}", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"is_query_report": 0, | |||
"label": "Web Page", | |||
"link_to": "Web Page", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"is_query_report": 0, | |||
"label": "Web Form", | |||
"link_to": "Web Form", | |||
"type": "DocType" | |||
}, | |||
{ | |||
"is_query_report": 0, | |||
"label": "Website Settings", | |||
"link_to": "Website Settings", | |||
"type": "DocType" | |||
} | |||
@@ -1,559 +1,142 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_guest_to_view": 0, | |||
"allow_import": 0, | |||
"allow_rename": 0, | |||
"beta": 0, | |||
"creation": "2013-02-21 20:12:42", | |||
"custom": 0, | |||
"description": "Settings for Contact Us Page", | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"editable_grid": 0, | |||
"actions": [], | |||
"creation": "2013-02-21 20:12:42", | |||
"description": "Settings for Contact Us Page", | |||
"doctype": "DocType", | |||
"engine": "InnoDB", | |||
"field_order": [ | |||
"introduction_section", | |||
"forward_to_email", | |||
"heading", | |||
"introduction", | |||
"query_options", | |||
"address", | |||
"address_title", | |||
"address_line1", | |||
"address_line2", | |||
"city", | |||
"state", | |||
"pincode", | |||
"country", | |||
"column_break_14", | |||
"phone", | |||
"email_id", | |||
"skype" | |||
], | |||
"fields": [ | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "introduction_section", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Introduction", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Send enquiries to this email address", | |||
"fieldname": "forward_to_email", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Forward To Email Address", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Default: \"Contact Us\"", | |||
"fieldname": "heading", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Heading", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Introductory information for the Contact Us Page", | |||
"fieldname": "introduction", | |||
"fieldtype": "Text Editor", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Introduction", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Contact options, like \"Sales Query, Support Query\" etc each on a new line or separated by commas.", | |||
"fieldname": "query_options", | |||
"fieldtype": "Small Text", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Query Options", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "address", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Address", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 1, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "address_title", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Address Title", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "address_line1", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Address Line 1", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "address_line2", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Address Line 2", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "city", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "City", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "state", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "State", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "pincode", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Pincode", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "country", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Country", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_14", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "phone", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Phone", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "email_id", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Email Id", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "skype", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Skype", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
"fieldname": "introduction_section", | |||
"fieldtype": "Section Break", | |||
"label": "Introduction" | |||
}, | |||
{ | |||
"description": "Send enquiries to this email address", | |||
"fieldname": "forward_to_email", | |||
"fieldtype": "Data", | |||
"label": "Forward To Email Address", | |||
"options": "Email" | |||
}, | |||
{ | |||
"description": "Default: \"Contact Us\"", | |||
"fieldname": "heading", | |||
"fieldtype": "Data", | |||
"label": "Heading" | |||
}, | |||
{ | |||
"description": "Introductory information for the Contact Us Page", | |||
"fieldname": "introduction", | |||
"fieldtype": "Text Editor", | |||
"label": "Introduction" | |||
}, | |||
{ | |||
"description": "Contact options, like \"Sales Query, Support Query\" etc each on a new line or separated by commas.", | |||
"fieldname": "query_options", | |||
"fieldtype": "Small Text", | |||
"label": "Query Options" | |||
}, | |||
{ | |||
"fieldname": "address", | |||
"fieldtype": "Section Break", | |||
"label": "Address" | |||
}, | |||
{ | |||
"bold": 1, | |||
"fieldname": "address_title", | |||
"fieldtype": "Data", | |||
"label": "Address Title" | |||
}, | |||
{ | |||
"fieldname": "address_line1", | |||
"fieldtype": "Data", | |||
"label": "Address Line 1" | |||
}, | |||
{ | |||
"fieldname": "address_line2", | |||
"fieldtype": "Data", | |||
"label": "Address Line 2" | |||
}, | |||
{ | |||
"fieldname": "city", | |||
"fieldtype": "Data", | |||
"label": "City" | |||
}, | |||
{ | |||
"fieldname": "state", | |||
"fieldtype": "Data", | |||
"label": "State" | |||
}, | |||
{ | |||
"fieldname": "pincode", | |||
"fieldtype": "Data", | |||
"label": "Pincode" | |||
}, | |||
{ | |||
"fieldname": "country", | |||
"fieldtype": "Data", | |||
"label": "Country" | |||
}, | |||
{ | |||
"fieldname": "column_break_14", | |||
"fieldtype": "Column Break" | |||
}, | |||
{ | |||
"fieldname": "phone", | |||
"fieldtype": "Data", | |||
"label": "Phone", | |||
"options": "Phone" | |||
}, | |||
{ | |||
"fieldname": "email_id", | |||
"fieldtype": "Data", | |||
"label": "Email Id", | |||
"options": "Email" | |||
}, | |||
{ | |||
"fieldname": "skype", | |||
"fieldtype": "Data", | |||
"label": "Skype" | |||
} | |||
], | |||
"has_web_view": 0, | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"icon": "fa fa-cog", | |||
"idx": 1, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"is_submittable": 0, | |||
"issingle": 1, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2017-09-04 21:41:55.580325", | |||
"modified_by": "Administrator", | |||
"module": "Website", | |||
"name": "Contact Us Settings", | |||
"owner": "Administrator", | |||
], | |||
"icon": "fa fa-cog", | |||
"idx": 1, | |||
"issingle": 1, | |||
"links": [], | |||
"modified": "2020-04-06 19:17:46.083764", | |||
"modified_by": "Administrator", | |||
"module": "Website", | |||
"name": "Contact Us Settings", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"amend": 0, | |||
"apply_user_permissions": 0, | |||
"cancel": 0, | |||
"create": 1, | |||
"delete": 0, | |||
"email": 1, | |||
"export": 0, | |||
"if_owner": 0, | |||
"import": 0, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
"report": 0, | |||
"role": "Website Manager", | |||
"set_user_permissions": 0, | |||
"share": 1, | |||
"submit": 0, | |||
"create": 1, | |||
"email": 1, | |||
"print": 1, | |||
"read": 1, | |||
"role": "Website Manager", | |||
"share": 1, | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"show_name_in_global_search": 0, | |||
"track_changes": 1, | |||
"track_seen": 0 | |||
], | |||
"sort_field": "modified", | |||
"sort_order": "DESC" | |||
} |
@@ -1,7 +1,7 @@ | |||
Babel==2.6.0 | |||
beautifulsoup4==4.8.2 | |||
bleach-whitelist==0.0.10 | |||
bleach==3.1.2 | |||
bleach==3.1.4 | |||
boto3==1.10.18 | |||
braintree==3.57.1 | |||
chardet==3.0.4 | |||