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(['%s | ' % c for c in r])+'
' for r in msg]) + '
'
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