From c079e27d3fca28ac564866acec38cbdd51284697 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 5 Aug 2015 18:44:59 +0530 Subject: [PATCH] Moved Backup Manager and Social Login keys to the new Integrations Module, prepared frappe for Mandrill Integration --- frappe/__init__.py | 2 +- frappe/change_log/current/integrations.md | 1 + frappe/config/desktop.py | 6 + frappe/config/integrations.py | 23 + frappe/config/setup.py | 6 - frappe/config/website.py | 5 - .../doctype/communication/communication.json | 414 +++++++++--------- frappe/desk/form/load.py | 2 +- frappe/email/bulk.py | 22 +- .../email_unsubscribe/email_unsubscribe.json | 36 +- .../email_unsubscribe/email_unsubscribe.py | 30 +- frappe/email/email_body.py | 6 +- frappe/handler.py | 4 +- .../__init__.py | 0 frappe/integrations/doctype/__init__.py | 0 .../doctype/social_login_keys/__init__.py | 0 .../social_login_keys/social_login_keys.json | 221 ++++++++++ .../social_login_keys/social_login_keys.py | 0 frappe/model/document.py | 2 +- frappe/modules.txt | 1 + frappe/public/css/form.css | 12 + frappe/public/js/frappe/form/dashboard.js | 2 +- .../js/frappe/form/footer/timeline_item.html | 21 +- frappe/public/less/form.less | 15 + frappe/public/less/variables.less | 1 + frappe/utils/boilerplate.py | 2 +- .../social_login_keys/social_login_keys.json | 80 ---- requirements.txt | 2 + 28 files changed, 599 insertions(+), 317 deletions(-) create mode 100644 frappe/change_log/current/integrations.md create mode 100644 frappe/config/integrations.py rename frappe/{website/doctype/social_login_keys => integrations}/__init__.py (100%) create mode 100644 frappe/integrations/doctype/__init__.py create mode 100644 frappe/integrations/doctype/social_login_keys/__init__.py create mode 100644 frappe/integrations/doctype/social_login_keys/social_login_keys.json rename frappe/{website => integrations}/doctype/social_login_keys/social_login_keys.py (100%) delete mode 100644 frappe/website/doctype/social_login_keys/social_login_keys.json diff --git a/frappe/__init__.py b/frappe/__init__.py index f5b5c29b64..0d813b38c5 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -239,7 +239,7 @@ def msgprint(msg, small=0, raise_exception=0, as_table=False): msg = '' + ''.join([''+''.join(['' % c for c in r])+'' for r in msg]) + '
%s
' if flags.print_messages: - print "Message: " + repr(msg) + print "Message: " + repr(msg).encode("utf-8") message_log.append((small and '__small:' or '')+cstr(msg or '')) _raise_exception() diff --git a/frappe/change_log/current/integrations.md b/frappe/change_log/current/integrations.md new file mode 100644 index 0000000000..5bf04bb82d --- /dev/null +++ b/frappe/change_log/current/integrations.md @@ -0,0 +1 @@ +- Moved Backup Manager and Social Login Keys to the new **Integrations** module diff --git a/frappe/config/desktop.py b/frappe/config/desktop.py index 70b73ffb7e..c5ac49f4d9 100644 --- a/frappe/config/desktop.py +++ b/frappe/config/desktop.py @@ -72,4 +72,10 @@ def get_data(): "type": "module", "system_manager": 1 }, + "Integrations": { + "color": "#36414C", + "icon": "octicon octicon-plug", + "type": "module", + "system_manager": 1 + } } diff --git a/frappe/config/integrations.py b/frappe/config/integrations.py new file mode 100644 index 0000000000..99ee288f5c --- /dev/null +++ b/frappe/config/integrations.py @@ -0,0 +1,23 @@ +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return [ + { + "label": _("Documents"), + "icon": "icon-star", + "items": [ + { + "type": "doctype", + "name": "Social Login Keys", + "description": _("Enter keys to enable login via Facebook, Google, GitHub."), + }, + { + "type": "doctype", + "name": "Backup Manager", + "description": _("Manage cloud backups on Dropbox"), + "hide_count": True + } + ] + } + ] diff --git a/frappe/config/setup.py b/frappe/config/setup.py index 0e5fe02046..eed59e885b 100644 --- a/frappe/config/setup.py +++ b/frappe/config/setup.py @@ -208,12 +208,6 @@ def get_data(): "description": _("Install Applications."), "icon": "icon-download" }, - { - "type": "doctype", - "name": "Backup Manager", - "description": _("Manage cloud backups on Dropbox"), - "hide_count": True - }, { "type": "doctype", "name": "Scheduler Log", diff --git a/frappe/config/website.py b/frappe/config/website.py index f118e0f589..8d5f44f6ac 100644 --- a/frappe/config/website.py +++ b/frappe/config/website.py @@ -77,11 +77,6 @@ def get_data(): "type": "doctype", "name": "Website Theme", "description": _("List of themes for Website."), - }, - { - "type": "doctype", - "name": "Social Login Keys", - "description": _("Enter keys to enable login via Facebook, Google, GitHub."), } ] }, diff --git a/frappe/core/doctype/communication/communication.json b/frappe/core/doctype/communication/communication.json index 24283f4728..dc2139a510 100644 --- a/frappe/core/doctype/communication/communication.json +++ b/frappe/core/doctype/communication/communication.json @@ -1,251 +1,267 @@ { - "allow_import": 1, - "autoname": "naming_series:", - "creation": "2013-01-29 10:47:14", - "description": "Keep a track of all communications", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Master", + "allow_import": 1, + "autoname": "naming_series:", + "creation": "2013-01-29 10:47:14", + "description": "Keep a track of all communications", + "docstatus": 0, + "doctype": "DocType", + "document_type": "Master", "fields": [ { - "default": "COMM-", - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 1, - "label": "Series", - "options": "COMM-", + "default": "COMM-", + "fieldname": "naming_series", + "fieldtype": "Select", + "hidden": 1, + "label": "Series", + "options": "COMM-", "permlevel": 0 - }, - { - "fieldname": "sent_or_received", - "fieldtype": "Select", - "in_list_view": 1, - "label": "Sent or Received", - "options": "Sent\nReceived", - "permlevel": 0, + }, + { + "fieldname": "sent_or_received", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Sent or Received", + "options": "Sent\nReceived", + "permlevel": 0, "reqd": 1 - }, + }, + { + "fieldname": "status", + "fieldtype": "Select", + "label": "Status", + "options": "Open\nReplied\nArchived", + "permlevel": 0, + "precision": "" + }, { - "fieldname": "status", - "fieldtype": "Select", - "label": "Status", - "options": "Open\nReplied\nArchived", - "permlevel": 0, + "description": "Integrations can use this field to set email delivery status", + "fieldname": "delivery_status", + "fieldtype": "Select", + "hidden": 1, + "label": "Delivery Status", + "options": "\nSent\nBounced\nOpened\nMarked As Spam\nRejected\nDelayed\nSoft-Bounced\nClicked\nRecipient Unsubscribed", + "permlevel": 0, "precision": "" - }, + }, { - "fieldname": "subject", - "fieldtype": "Data", - "in_list_view": 0, - "label": "Subject", - "permlevel": 0, + "fieldname": "subject", + "fieldtype": "Data", + "in_list_view": 0, + "label": "Subject", + "permlevel": 0, "reqd": 1 - }, + }, { - "fieldname": "column_break_5", - "fieldtype": "Column Break", - "permlevel": 0, + "fieldname": "column_break_5", + "fieldtype": "Column Break", + "permlevel": 0, "precision": "" - }, + }, { - "fieldname": "reference_doctype", - "fieldtype": "Link", - "label": "Reference DocType", - "options": "DocType", - "permlevel": 0, + "fieldname": "reference_doctype", + "fieldtype": "Link", + "label": "Reference DocType", + "options": "DocType", + "permlevel": 0, "precision": "" - }, + }, { - "fieldname": "reference_name", - "fieldtype": "Dynamic Link", - "label": "Reference Name", - "options": "reference_doctype", - "permlevel": 0, + "fieldname": "reference_name", + "fieldtype": "Dynamic Link", + "label": "Reference Name", + "options": "reference_doctype", + "permlevel": 0, "precision": "" - }, + }, { - "fieldname": "section_break_8", - "fieldtype": "Section Break", - "permlevel": 0, + "fieldname": "section_break_8", + "fieldtype": "Section Break", + "permlevel": 0, "precision": "" - }, + }, { - "fieldname": "content", - "fieldtype": "Text Editor", - "label": "Content", - "permlevel": 0, - "reqd": 0, + "fieldname": "content", + "fieldtype": "Text Editor", + "label": "Content", + "permlevel": 0, + "reqd": 0, "width": "400" - }, + }, { - "fieldname": "additional_info", - "fieldtype": "Section Break", - "label": "Additional Info", + "fieldname": "additional_info", + "fieldtype": "Section Break", + "label": "Additional Info", "permlevel": 0 - }, + }, { - "fieldname": "recipients", - "fieldtype": "Data", - "label": "Recipients", + "fieldname": "recipients", + "fieldtype": "Data", + "label": "Recipients", "permlevel": 0 - }, + }, { - "fieldname": "sender", - "fieldtype": "Data", - "label": "Sender", + "fieldname": "phone_no", + "fieldtype": "Data", + "label": "Phone No.", "permlevel": 0 - }, + }, { - "fieldname": "sender_full_name", - "fieldtype": "Data", - "label": "Sender Full Name", - "permlevel": 0, + "fieldname": "communication_medium", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Communication Medium", + "options": "\nChat\nPhone\nEmail\nSMS\nVisit\nOther", + "permlevel": 0 + }, + { + "fieldname": "column_break_14", + "fieldtype": "Column Break", + "permlevel": 0, "precision": "" - }, + }, { - "fieldname": "communication_medium", - "fieldtype": "Select", - "in_list_view": 1, - "label": "Communication Medium", - "options": "\nChat\nPhone\nEmail\nSMS\nVisit\nOther", + "fieldname": "sender", + "fieldtype": "Data", + "label": "Sender", "permlevel": 0 - }, + }, { - "fieldname": "phone_no", - "fieldtype": "Data", - "label": "Phone No.", - "permlevel": 0 - }, + "fieldname": "sender_full_name", + "fieldtype": "Data", + "label": "Sender Full Name", + "permlevel": 0, + "precision": "" + }, { - "fieldname": "section_break2", - "fieldtype": "Section Break", - "options": "simple", + "fieldname": "section_break2", + "fieldtype": "Section Break", + "options": "simple", "permlevel": 0 - }, + }, { - "fieldname": "column_break4", - "fieldtype": "Column Break", - "label": "By", + "fieldname": "column_break4", + "fieldtype": "Column Break", + "label": "By", "permlevel": 0 - }, + }, { - "fieldname": "email_account", - "fieldtype": "Link", - "label": "Email Account", - "options": "Email Account", - "permlevel": 0, + "fieldname": "email_account", + "fieldtype": "Link", + "label": "Email Account", + "options": "Email Account", + "permlevel": 0, "precision": "" - }, - { - "default": "__user", - "fieldname": "user", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "label": "User", - "options": "User", - "permlevel": 0, + }, + { + "default": "__user", + "fieldname": "user", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "User", + "options": "User", + "permlevel": 0, "read_only": 1 - }, + }, { - "fieldname": "column_break5", - "fieldtype": "Column Break", - "label": "On", + "fieldname": "column_break5", + "fieldtype": "Column Break", + "label": "On", "permlevel": 0 - }, + }, { - "default": "Today", - "fieldname": "communication_date", - "fieldtype": "Datetime", - "label": "Date", + "default": "Today", + "fieldname": "communication_date", + "fieldtype": "Datetime", + "label": "Date", "permlevel": 0 - }, - { - "fieldname": "_user_tags", - "fieldtype": "Data", - "hidden": 1, - "label": "User Tags", - "no_copy": 1, - "permlevel": 0, + }, + { + "fieldname": "_user_tags", + "fieldtype": "Data", + "hidden": 1, + "label": "User Tags", + "no_copy": 1, + "permlevel": 0, "print_hide": 1 - }, - { - "default": "0", - "fieldname": "unread_notification_sent", - "fieldtype": "Check", - "label": "Unread Notification Sent", - "permlevel": 0, - "precision": "", + }, + { + "default": "0", + "fieldname": "unread_notification_sent", + "fieldtype": "Check", + "label": "Unread Notification Sent", + "permlevel": 0, + "precision": "", "read_only": 1 } - ], - "icon": "icon-comment", - "idx": 1, - "in_dialog": 0, - "issingle": 0, - "modified": "2015-03-23 02:33:55.289739", - "modified_by": "Administrator", - "module": "Core", - "name": "Communication", - "owner": "Administrator", + ], + "icon": "icon-comment", + "idx": 1, + "in_dialog": 0, + "issingle": 0, + "modified": "2015-07-28 07:28:11.457131", + "modified_by": "Administrator", + "module": "Core", + "name": "Communication", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 1, - "create": 1, - "delete": 1, - "email": 1, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Support Team", - "share": 1, - "submit": 0, + "amend": 0, + "apply_user_permissions": 1, + "create": 1, + "delete": 1, + "email": 1, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Support Team", + "share": 1, + "submit": 0, "write": 1 - }, - { - "amend": 0, - "create": 1, - "delete": 1, - "email": 1, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Sales Manager", - "share": 1, - "submit": 0, + }, + { + "amend": 0, + "create": 1, + "delete": 1, + "email": 1, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Sales Manager", + "share": 1, + "submit": 0, "write": 1 - }, - { - "amend": 0, - "apply_user_permissions": 1, - "create": 1, - "delete": 1, - "email": 1, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Sales User", - "share": 1, - "submit": 0, + }, + { + "amend": 0, + "apply_user_permissions": 1, + "create": 1, + "delete": 1, + "email": 1, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Sales User", + "share": 1, + "submit": 0, "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "submit": 0, + }, + { + "create": 1, + "delete": 1, + "email": 1, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "submit": 0, "write": 1 } - ], - "search_fields": "subject", + ], + "search_fields": "subject", "title_field": "subject" -} \ No newline at end of file +} diff --git a/frappe/desk/form/load.py b/frappe/desk/form/load.py index 1cab39bed2..82cc238068 100644 --- a/frappe/desk/form/load.py +++ b/frappe/desk/form/load.py @@ -113,7 +113,7 @@ def get_comments(dt, dn, limit=100): communications = frappe.db.sql("""select name, content as comment, sender as comment_by, creation, - communication_medium as comment_type, subject, + communication_medium as comment_type, subject, delivery_status, "Communication" as doctype from tabCommunication where reference_doctype=%s and reference_name=%s diff --git a/frappe/email/bulk.py b/frappe/email/bulk.py index d3c1a1aaf7..5b88bd23e9 100644 --- a/frappe/email/bulk.py +++ b/frappe/email/bulk.py @@ -60,6 +60,9 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc if reference_doctype and reference_name: unsubscribed = [d.email for d in frappe.db.get_all("Email Unsubscribe", "email", {"reference_doctype": reference_doctype, "reference_name": reference_name})] + + unsubscribed += [d.email for d in frappe.db.get_all("Email Unsubscribe", "email", + {"global_unsubscribe": 1})] else: unsubscribed = [] @@ -159,14 +162,19 @@ def unsubscribe(doctype, name, email): if not verify_request(): return - frappe.get_doc({ - "doctype": "Email Unsubscribe", - "email": email, - "reference_doctype": doctype, - "reference_name": name - }).insert(ignore_permissions=True) + try: + frappe.get_doc({ + "doctype": "Email Unsubscribe", + "email": email, + "reference_doctype": doctype, + "reference_name": name + }).insert(ignore_permissions=True) + + except frappe.DuplicateEntryError: + frappe.db.rollback() - frappe.db.commit() + else: + frappe.db.commit() return_unsubscribed_page(email, doctype, name) diff --git a/frappe/email/doctype/email_unsubscribe/email_unsubscribe.json b/frappe/email/doctype/email_unsubscribe/email_unsubscribe.json index a70c363034..8014a44fb9 100644 --- a/frappe/email/doctype/email_unsubscribe/email_unsubscribe.json +++ b/frappe/email/doctype/email_unsubscribe/email_unsubscribe.json @@ -25,7 +25,8 @@ "report_hide": 0, "reqd": 1, "search_index": 0, - "set_only_once": 0 + "set_only_once": 0, + "unique": 0 }, { "allow_on_submit": 0, @@ -43,9 +44,10 @@ "print_hide": 0, "read_only": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, - "set_only_once": 0 + "set_only_once": 0, + "unique": 0 }, { "allow_on_submit": 0, @@ -63,9 +65,30 @@ "print_hide": 0, "read_only": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "global_unsubscribe", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Global Unsubscribe", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, "search_index": 0, - "set_only_once": 0 + "set_only_once": 0, + "unique": 0 } ], "hide_heading": 0, @@ -75,7 +98,7 @@ "is_submittable": 0, "issingle": 0, "istable": 0, - "modified": "2015-03-18 09:41:20.216319", + "modified": "2015-08-05 06:02:12.805282", "modified_by": "Administrator", "module": "Email", "name": "Email Unsubscribe", @@ -90,6 +113,7 @@ "delete": 1, "email": 1, "export": 1, + "if_owner": 0, "import": 0, "permlevel": 0, "print": 1, diff --git a/frappe/email/doctype/email_unsubscribe/email_unsubscribe.py b/frappe/email/doctype/email_unsubscribe/email_unsubscribe.py index 02d3569988..2f879f98ee 100644 --- a/frappe/email/doctype/email_unsubscribe/email_unsubscribe.py +++ b/frappe/email/doctype/email_unsubscribe/email_unsubscribe.py @@ -8,6 +8,32 @@ from frappe.model.document import Document from frappe import _ class EmailUnsubscribe(Document): + def validate(self): + if not self.global_unsubscribe and not (self.reference_doctype and self.reference_name): + frappe.throw(_("Reference DocType and Reference Name are required"), frappe.MandatoryError) + + if not self.global_unsubscribe and frappe.db.get_value(self.doctype, self.name, "global_unsubscribe"): + frappe.throw(_("Delete this record to allow sending to this email address")) + + if self.global_unsubscribe: + if frappe.get_all("Email Unsubscribe", + filters={"email": self.email, "global_unsubscribe": 1, "name": ["!=", self.name]}): + frappe.throw(_("{0} already unsubscribed").format(self.email), frappe.DuplicateEntryError) + + else: + if frappe.get_all("Email Unsubscribe", + filters={ + "email": self.email, + "reference_doctype": self.reference_doctype, + "reference_name": self.reference_name, + "name": ["!=", self.name] + }): + frappe.throw(_("{0} already unsubscribed for {1} {2}").format( + self.email, self.reference_doctype, self.reference_name), + frappe.DuplicateEntryError) + def on_update(self): - doc = frappe.get_doc(self.reference_doctype, self.reference_name) - doc.add_comment("Label", _("Left this conversation"), comment_by=self.email) + if self.reference_doctype and self.reference_name: + doc = frappe.get_doc(self.reference_doctype, self.reference_name) + doc.add_comment("Label", _("Left this conversation"), comment_by=self.email) + diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py index c178cc21ff..48cfdd87c3 100644 --- a/frappe/email/email_body.py +++ b/frappe/email/email_body.py @@ -192,7 +192,7 @@ class EMail: "Date": email.utils.formatdate(), "Reply-To": self.reply_to.encode("utf-8") if self.reply_to else None, "CC": ', '.join(self.cc).encode("utf-8") if self.cc else None, - b'X-Frappe-Site': get_url().encode('utf-8') + b'X-Frappe-Site': get_url().encode('utf-8'), } # reset headers as values may be changed. @@ -201,6 +201,10 @@ class EMail: del self.msg_root[key] self.msg_root[key] = val + # call hook to enable apps to modify msg_root before sending + for hook in frappe.get_hooks("make_email_body_message"): + frappe.get_attr(hook)(self) + def as_string(self): """validate, build message and convert to string""" self.validate() diff --git a/frappe/handler.py b/frappe/handler.py index 25e28a063d..177f21abc3 100755 --- a/frappe/handler.py +++ b/frappe/handler.py @@ -83,11 +83,11 @@ def execute_cmd(cmd): if frappe.session['user'] == 'Guest': if (method not in frappe.guest_methods): frappe.msgprint(_("Not permitted")) - raise frappe.PermissionError('Not Allowed, %s' % str(method)) + raise frappe.PermissionError('Not Allowed, {0}'.format(method)) else: if not method in frappe.whitelisted: frappe.msgprint(_("Not permitted")) - raise frappe.PermissionError('Not Allowed, %s' % str(method)) + raise frappe.PermissionError('Not Allowed, {0}'.format(method)) ret = frappe.call(method, **frappe.form_dict) diff --git a/frappe/website/doctype/social_login_keys/__init__.py b/frappe/integrations/__init__.py similarity index 100% rename from frappe/website/doctype/social_login_keys/__init__.py rename to frappe/integrations/__init__.py diff --git a/frappe/integrations/doctype/__init__.py b/frappe/integrations/doctype/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/integrations/doctype/social_login_keys/__init__.py b/frappe/integrations/doctype/social_login_keys/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/integrations/doctype/social_login_keys/social_login_keys.json b/frappe/integrations/doctype/social_login_keys/social_login_keys.json new file mode 100644 index 0000000000..08a028491a --- /dev/null +++ b/frappe/integrations/doctype/social_login_keys/social_login_keys.json @@ -0,0 +1,221 @@ +{ + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 0, + "creation": "2014-03-04 08:29:52", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "System", + "fields": [ + { + "allow_on_submit": 0, + "fieldname": "facebook", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Facebook", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "facebook_client_id", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Facebook Client ID", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "facebook_client_secret", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Facebook Client Secret", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "google", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Google", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "google_client_id", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Google Client ID", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "google_client_secret", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Google Client Secret", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "github", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "GitHub", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "github_client_id", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "GitHub Client ID", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "github_client_secret", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "GitHub Client Secret", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "hide_heading": 0, + "hide_toolbar": 0, + "icon": "icon-signin", + "idx": 1, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, + "issingle": 1, + "istable": 0, + "modified": "2015-08-05 08:14:52.667728", + "modified_by": "Administrator", + "module": "Integrations", + "name": "Social Login Keys", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 0, + "email": 0, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 0, + "read": 1, + "report": 0, + "role": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "read_only": 0, + "read_only_onload": 0 +} \ No newline at end of file diff --git a/frappe/website/doctype/social_login_keys/social_login_keys.py b/frappe/integrations/doctype/social_login_keys/social_login_keys.py similarity index 100% rename from frappe/website/doctype/social_login_keys/social_login_keys.py rename to frappe/integrations/doctype/social_login_keys/social_login_keys.py diff --git a/frappe/model/document.py b/frappe/model/document.py index 547bdc6932..4b7808ae5b 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -457,7 +457,7 @@ class Document(BaseDocument): msgprint(msg) if frappe.flags.print_messages: - print self.as_dict() + print self.as_json().encode("utf-8") raise frappe.MandatoryError(", ".join((each[0] for each in missing))) diff --git a/frappe/modules.txt b/frappe/modules.txt index e435b0231c..1b8d17eb40 100644 --- a/frappe/modules.txt +++ b/frappe/modules.txt @@ -6,3 +6,4 @@ Custom Geo Desk Print +Integrations \ No newline at end of file diff --git a/frappe/public/css/form.css b/frappe/public/css/form.css index a85f9ae799..2970b68aca 100644 --- a/frappe/public/css/form.css +++ b/frappe/public/css/form.css @@ -157,3 +157,15 @@ select.form-control { -moz-appearance: none; appearance: none; } +.form-headline .alert { + font-size: 12px; + border-color: #d1d8dd; + margin-bottom: 0px; +} +.delivery-status-indicator { + display: inline-block; + margin-top: -3px; + margin-left: 1px; + font-weight: 500; + color: #8d99a6; +} diff --git a/frappe/public/js/frappe/form/dashboard.js b/frappe/public/js/frappe/form/dashboard.js index c20c436f18..ecebda28aa 100644 --- a/frappe/public/js/frappe/form/dashboard.js +++ b/frappe/public/js/frappe/form/dashboard.js @@ -24,7 +24,7 @@ frappe.ui.form.Dashboard = Class.extend({ }, set_headline_alert: function(text, alert_class, icon) { this.set_headline(repl('
%(icon)s%(text)s
', { - "alert_class": alert_class || "alert-info", + "alert_class": alert_class || "", "icon": icon ? ' ' : "", "text": text })); diff --git a/frappe/public/js/frappe/form/footer/timeline_item.html b/frappe/public/js/frappe/form/footer/timeline_item.html index b14d3b8856..e557b3d01c 100644 --- a/frappe/public/js/frappe/form/footer/timeline_item.html +++ b/frappe/public/js/frappe/form/footer/timeline_item.html @@ -10,15 +10,28 @@ {% if(data.doctype=="Communication" || data.comment_type=="Comment") { %} -
+
{%= data.fullname %} – {%= data.comment_on %} {% if(data.doctype=="Communication") { %} - - {%= __("Details") %} + + + {% if (data.delivery_status) { + if (in_list(["Sent", "Opened", "Clicked"], data.delivery_status)) { + var indicator_class = "green"; + } else { + var indicator_class = "red"; + } + %} + + {%= data.delivery_status %} + + {% } else { %} {%= __("Details") %} {% } %} + {%= __("Reply") %} {% } %} diff --git a/frappe/public/less/form.less b/frappe/public/less/form.less index a60dcf3c4a..37eda7e045 100644 --- a/frappe/public/less/form.less +++ b/frappe/public/less/form.less @@ -204,3 +204,18 @@ select.form-control { -moz-appearance: none; appearance: none; } + +.form-headline .alert { + font-size: @text-medium; + border-color: @border-color; + // background-color: @light-bg; + margin-bottom: 0px; +} + +.delivery-status-indicator { + display: inline-block; + margin-top: -3px; + margin-left: 1px; + font-weight: 500; + color: @text-muted; +} diff --git a/frappe/public/less/variables.less b/frappe/public/less/variables.less index ac3bfc58e1..5cda4f81ad 100644 --- a/frappe/public/less/variables.less +++ b/frappe/public/less/variables.less @@ -10,6 +10,7 @@ @modal-backdrop-bg: #334143; @light-yellow: #fffce7; @text-extra-muted: @border-color; +@text-regular: 14px; @text-medium: 12px; @text-small: 10px; diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index 1dbe5d0787..a3112eb481 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -82,7 +82,7 @@ def make_boilerplate(dest, app_name): with open(os.path.join(dest, hooks.app_name, hooks.app_name, "config", "desktop.py"), "w") as f: f.write(encode(desktop_template.format(**hooks))) - + print "'{app}' created at {path}".format(app=app_name, path=os.path.join(dest, app_name)) manifest_template = """include MANIFEST.in diff --git a/frappe/website/doctype/social_login_keys/social_login_keys.json b/frappe/website/doctype/social_login_keys/social_login_keys.json deleted file mode 100644 index e032acf7a2..0000000000 --- a/frappe/website/doctype/social_login_keys/social_login_keys.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "creation": "2014-03-04 08:29:52", - "docstatus": 0, - "doctype": "DocType", - "document_type": "System", - "fields": [ - { - "fieldname": "facebook", - "fieldtype": "Section Break", - "label": "Facebook", - "permlevel": 0 - }, - { - "fieldname": "facebook_client_id", - "fieldtype": "Data", - "label": "Facebook Client ID", - "permlevel": 0 - }, - { - "fieldname": "facebook_client_secret", - "fieldtype": "Data", - "label": "Facebook Client Secret", - "permlevel": 0 - }, - { - "fieldname": "google", - "fieldtype": "Section Break", - "label": "Google", - "permlevel": 0 - }, - { - "fieldname": "google_client_id", - "fieldtype": "Data", - "label": "Google Client ID", - "permlevel": 0 - }, - { - "fieldname": "google_client_secret", - "fieldtype": "Data", - "label": "Google Client Secret", - "permlevel": 0 - }, - { - "fieldname": "github", - "fieldtype": "Section Break", - "label": "GitHub", - "permlevel": 0 - }, - { - "fieldname": "github_client_id", - "fieldtype": "Data", - "label": "GitHub Client ID", - "permlevel": 0 - }, - { - "fieldname": "github_client_secret", - "fieldtype": "Data", - "label": "GitHub Client Secret", - "permlevel": 0 - } - ], - "icon": "icon-signin", - "idx": 1, - "issingle": 1, - "modified": "2015-02-05 05:11:46.875246", - "modified_by": "Administrator", - "module": "Website", - "name": "Social Login Keys", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "permlevel": 0, - "read": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ] -} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index ba31f3ce9d..b963e830b3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,3 +28,5 @@ html2text email_reply_parser click num2words +watchdog +pyopenssl