Browse Source

Merge remote-tracking branch 'frappe/develop' into v6-wip

Conflicts:
	frappe/__version__.py
	frappe/core/doctype/communication/communication.json
	frappe/hooks.py
	frappe/model/document.py
	frappe/public/css/form.css
	frappe/public/less/form.less
	requirements.txt
	setup.py
version-14
Anand Doshi 10 years ago
parent
commit
c9782e23e4
44 changed files with 684 additions and 345 deletions
  1. +4
    -1
      frappe/__init__.py
  2. +1
    -1
      frappe/__version__.py
  3. +1
    -1
      frappe/auth.py
  4. +1
    -0
      frappe/change_log/v5/v5_4_0.md
  5. +6
    -0
      frappe/config/desktop.py
  6. +23
    -0
      frappe/config/integrations.py
  7. +0
    -6
      frappe/config/setup.py
  8. +0
    -5
      frappe/config/website.py
  9. +215
    -199
      frappe/core/doctype/communication/communication.json
  10. +3
    -0
      frappe/custom/doctype/customize_form/customize_form.py
  11. +1
    -1
      frappe/desk/form/load.py
  12. +1
    -2
      frappe/desk/notifications.py
  13. +15
    -7
      frappe/email/bulk.py
  14. +30
    -6
      frappe/email/doctype/email_unsubscribe/email_unsubscribe.json
  15. +28
    -2
      frappe/email/doctype/email_unsubscribe/email_unsubscribe.py
  16. +5
    -1
      frappe/email/email_body.py
  17. +2
    -2
      frappe/handler.py
  18. +1
    -1
      frappe/hooks.py
  19. +0
    -0
      frappe/integrations/__init__.py
  20. +0
    -0
      frappe/integrations/doctype/__init__.py
  21. +0
    -0
      frappe/integrations/doctype/social_login_keys/__init__.py
  22. +221
    -0
      frappe/integrations/doctype/social_login_keys/social_login_keys.json
  23. +0
    -0
      frappe/integrations/doctype/social_login_keys/social_login_keys.py
  24. +18
    -10
      frappe/model/db_schema.py
  25. +21
    -7
      frappe/model/delete_doc.py
  26. +2
    -2
      frappe/model/document.py
  27. +1
    -0
      frappe/modules.txt
  28. +12
    -0
      frappe/public/css/form.css
  29. +10
    -0
      frappe/public/js/frappe/form/control.js
  30. +1
    -1
      frappe/public/js/frappe/form/dashboard.js
  31. +17
    -4
      frappe/public/js/frappe/form/footer/timeline_item.html
  32. +8
    -0
      frappe/public/js/frappe/form/grid.js
  33. +1
    -1
      frappe/public/js/frappe/ui/page.html
  34. +15
    -0
      frappe/public/less/form.less
  35. +1
    -0
      frappe/public/less/variables.less
  36. +1
    -1
      frappe/sessions.py
  37. +1
    -1
      frappe/utils/boilerplate.py
  38. +7
    -0
      frappe/utils/redis_wrapper.py
  39. +0
    -80
      frappe/website/doctype/social_login_keys/social_login_keys.json
  40. +3
    -0
      frappe/website/doctype/web_form/web_form.py
  41. +1
    -0
      frappe/website/render.py
  42. +4
    -2
      frappe/website/template.py
  43. +1
    -0
      requirements.txt
  44. +1
    -1
      setup.py

+ 4
- 1
frappe/__init__.py View File

@@ -241,7 +241,7 @@ def msgprint(msg, small=0, raise_exception=0, as_table=False):
msg = '<table border="1px" style="border-collapse: collapse" cellpadding="2px">' + ''.join(['<tr>'+''.join(['<td>%s</td>' % c for c in r])+'</tr>' for r in msg]) + '</table>' msg = '<table border="1px" style="border-collapse: collapse" cellpadding="2px">' + ''.join(['<tr>'+''.join(['<td>%s</td>' % c for c in r])+'</tr>' for r in msg]) + '</table>'


if flags.print_messages: 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 '')) message_log.append((small and '__small:' or '')+cstr(msg or ''))
_raise_exception() _raise_exception()
@@ -430,6 +430,9 @@ def has_website_permission(doctype, ptype="read", doc=None, user=None, verbose=F


hooks = (get_hooks("has_website_permission") or {}).get(doctype, []) hooks = (get_hooks("has_website_permission") or {}).get(doctype, [])
if hooks: if hooks:
if isinstance(doc, basestring):
doc = get_doc(doctype, doc)

for method in hooks: for method in hooks:
result = call(get_attr(method), doc=doc, ptype=ptype, user=user, verbose=verbose) result = call(get_attr(method), doc=doc, ptype=ptype, user=user, verbose=verbose)
# if even a single permission check is Falsy # if even a single permission check is Falsy


+ 1
- 1
frappe/__version__.py View File

@@ -1,2 +1,2 @@
from __future__ import unicode_literals from __future__ import unicode_literals
__version__ = "6.0.0-wip"
__version__ = "6.0.0"

+ 1
- 1
frappe/auth.py View File

@@ -23,7 +23,7 @@ class HTTPRequest:
self.domain = self.domain[4:] self.domain = self.domain[4:]


if frappe.get_request_header('X-Forwarded-For'): if frappe.get_request_header('X-Forwarded-For'):
frappe.local.request_ip = frappe.get_request_header('X-Forwarded-For')
frappe.local.request_ip = (frappe.get_request_header('X-Forwarded-For').split(",")[0]).strip()


elif frappe.get_request_header('REMOTE_ADDR'): elif frappe.get_request_header('REMOTE_ADDR'):
frappe.local.request_ip = frappe.get_request_header('REMOTE_ADDR') frappe.local.request_ip = frappe.get_request_header('REMOTE_ADDR')


+ 1
- 0
frappe/change_log/v5/v5_4_0.md View File

@@ -0,0 +1 @@
- Moved Backup Manager and Social Login Keys to the new **Integrations** module

+ 6
- 0
frappe/config/desktop.py View File

@@ -72,4 +72,10 @@ def get_data():
"type": "module", "type": "module",
"system_manager": 1 "system_manager": 1
}, },
"Integrations": {
"color": "#36414C",
"icon": "octicon octicon-plug",
"type": "module",
"system_manager": 1
}
} }

+ 23
- 0
frappe/config/integrations.py View File

@@ -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
}
]
}
]

+ 0
- 6
frappe/config/setup.py View File

@@ -208,12 +208,6 @@ def get_data():
"description": _("Install Applications."), "description": _("Install Applications."),
"icon": "icon-download" "icon": "icon-download"
}, },
{
"type": "doctype",
"name": "Backup Manager",
"description": _("Manage cloud backups on Dropbox"),
"hide_count": True
},
{ {
"type": "doctype", "type": "doctype",
"name": "Scheduler Log", "name": "Scheduler Log",


+ 0
- 5
frappe/config/website.py View File

@@ -77,11 +77,6 @@ def get_data():
"type": "doctype", "type": "doctype",
"name": "Website Theme", "name": "Website Theme",
"description": _("List of themes for Website."), "description": _("List of themes for Website."),
},
{
"type": "doctype",
"name": "Social Login Keys",
"description": _("Enter keys to enable login via Facebook, Google, GitHub."),
} }
] ]
}, },


+ 215
- 199
frappe/core/doctype/communication/communication.json View File

@@ -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": "Setup",
"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": "Setup",
"fields": [ "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 "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 "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": "" "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 "reqd": 1
},
},
{ {
"fieldname": "column_break_5",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "column_break_5",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": "" "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": "" "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": "" "precision": ""
},
},
{ {
"fieldname": "section_break_8",
"fieldtype": "Section Break",
"permlevel": 0,
"fieldname": "section_break_8",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": "" "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" "width": "400"
},
},
{ {
"fieldname": "additional_info",
"fieldtype": "Section Break",
"label": "Additional Info",
"fieldname": "additional_info",
"fieldtype": "Section Break",
"label": "Additional Info",
"permlevel": 0 "permlevel": 0
},
},
{ {
"fieldname": "recipients",
"fieldtype": "Data",
"label": "Recipients",
"fieldname": "recipients",
"fieldtype": "Data",
"label": "Recipients",
"permlevel": 0 "permlevel": 0
},
},
{ {
"fieldname": "sender",
"fieldtype": "Data",
"label": "Sender",
"fieldname": "phone_no",
"fieldtype": "Data",
"label": "Phone No.",
"permlevel": 0 "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": "" "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 "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 "permlevel": 0
},
},
{ {
"fieldname": "column_break4",
"fieldtype": "Column Break",
"label": "By",
"fieldname": "column_break4",
"fieldtype": "Column Break",
"label": "By",
"permlevel": 0 "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": "" "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 "read_only": 1
},
},
{ {
"fieldname": "column_break5",
"fieldtype": "Column Break",
"label": "On",
"fieldname": "column_break5",
"fieldtype": "Column Break",
"label": "On",
"permlevel": 0 "permlevel": 0
},
},
{ {
"default": "Today",
"fieldname": "communication_date",
"fieldtype": "Datetime",
"label": "Date",
"default": "Today",
"fieldname": "communication_date",
"fieldtype": "Datetime",
"label": "Date",
"permlevel": 0 "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 "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 "read_only": 1
} }
],
"icon": "icon-comment",
"idx": 1,
"in_dialog": 0,
"issingle": 0,
"modified": "2015-07-28 16:18:11.664740",
"modified_by": "Administrator",
"module": "Core",
"name": "Communication",
"owner": "Administrator",
],
"icon": "icon-comment",
"idx": 1,
"in_dialog": 0,
"issingle": 0,
"modified": "2015-07-28 17:18:11.664740",
"modified_by": "Administrator",
"module": "Core",
"name": "Communication",
"owner": "Administrator",
"permissions": [ "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 "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 "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 "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 "write": 1
} }
],
"search_fields": "subject",
],
"search_fields": "subject",
"title_field": "subject" "title_field": "subject"
}
}

+ 3
- 0
frappe/custom/doctype/customize_form/customize_form.py View File

@@ -135,6 +135,9 @@ class CustomizeForm(Document):
and cint(df.get("precision")) > cint(meta_df[0].get("precision")): and cint(df.get("precision")) > cint(meta_df[0].get("precision")):
update_db = True update_db = True


elif property == "unique":
update_db = True

self.make_property_setter(property=property, value=df.get(property), self.make_property_setter(property=property, value=df.get(property),
property_type=self.docfield_properties[property], fieldname=df.fieldname) property_type=self.docfield_properties[property], fieldname=df.fieldname)




+ 1
- 1
frappe/desk/form/load.py View File

@@ -113,7 +113,7 @@ def get_comments(dt, dn, limit=100):


communications = frappe.db.sql("""select name, communications = frappe.db.sql("""select name,
content as comment, sender as comment_by, creation, 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 "Communication" as doctype
from tabCommunication from tabCommunication
where reference_doctype=%s and reference_name=%s where reference_doctype=%s and reference_name=%s


+ 1
- 2
frappe/desk/notifications.py View File

@@ -95,8 +95,7 @@ def clear_notifications(user="*"):
frappe.cache().delete_keys("notification_count:") frappe.cache().delete_keys("notification_count:")
else: else:
# delete count for user # delete count for user
for key in frappe.cache().get_keys("notification_count:"):
frappe.cache().hdel(key, user)
frappe.cache().hdel_keys("notification_count:", user)


def delete_notification_count_for(doctype): def delete_notification_count_for(doctype):
frappe.cache().delete_key("notification_count:" + doctype) frappe.cache().delete_key("notification_count:" + doctype)


+ 15
- 7
frappe/email/bulk.py View File

@@ -60,6 +60,9 @@ def send(recipients=None, sender=None, subject=None, message=None, reference_doc
if reference_doctype and reference_name: if reference_doctype and reference_name:
unsubscribed = [d.email for d in frappe.db.get_all("Email Unsubscribe", "email", unsubscribed = [d.email for d in frappe.db.get_all("Email Unsubscribe", "email",
{"reference_doctype": reference_doctype, "reference_name": reference_name})] {"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: else:
unsubscribed = [] unsubscribed = []


@@ -159,14 +162,19 @@ def unsubscribe(doctype, name, email):
if not verify_request(): if not verify_request():
return 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) return_unsubscribed_page(email, doctype, name)




+ 30
- 6
frappe/email/doctype/email_unsubscribe/email_unsubscribe.json View File

@@ -25,7 +25,8 @@
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0
"set_only_once": 0,
"unique": 0
}, },
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
@@ -43,9 +44,10 @@
"print_hide": 0, "print_hide": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0
"set_only_once": 0,
"unique": 0
}, },
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
@@ -63,9 +65,30 @@
"print_hide": 0, "print_hide": 0,
"read_only": 0, "read_only": 0,
"report_hide": 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, "search_index": 0,
"set_only_once": 0
"set_only_once": 0,
"unique": 0
} }
], ],
"hide_heading": 0, "hide_heading": 0,
@@ -75,7 +98,7 @@
"is_submittable": 0, "is_submittable": 0,
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"modified": "2015-03-18 09:41:20.216319",
"modified": "2015-08-05 06:02:12.805282",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Email", "module": "Email",
"name": "Email Unsubscribe", "name": "Email Unsubscribe",
@@ -90,6 +113,7 @@
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0, "import": 0,
"permlevel": 0, "permlevel": 0,
"print": 1, "print": 1,


+ 28
- 2
frappe/email/doctype/email_unsubscribe/email_unsubscribe.py View File

@@ -8,6 +8,32 @@ from frappe.model.document import Document
from frappe import _ from frappe import _


class EmailUnsubscribe(Document): 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): 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)


+ 5
- 1
frappe/email/email_body.py View File

@@ -192,7 +192,7 @@ class EMail:
"Date": email.utils.formatdate(), "Date": email.utils.formatdate(),
"Reply-To": self.reply_to.encode("utf-8") if self.reply_to else None, "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, "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. # reset headers as values may be changed.
@@ -201,6 +201,10 @@ class EMail:
del self.msg_root[key] del self.msg_root[key]
self.msg_root[key] = val 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): def as_string(self):
"""validate, build message and convert to string""" """validate, build message and convert to string"""
self.validate() self.validate()


+ 2
- 2
frappe/handler.py View File

@@ -90,11 +90,11 @@ def execute_cmd(cmd, async=False):
if frappe.session['user'] == 'Guest': if frappe.session['user'] == 'Guest':
if (method not in frappe.guest_methods): if (method not in frappe.guest_methods):
frappe.msgprint(_("Not permitted")) frappe.msgprint(_("Not permitted"))
raise frappe.PermissionError('Not Allowed, %s' % str(method))
raise frappe.PermissionError('Not Allowed, {0}'.format(method))
else: else:
if not method in frappe.whitelisted: if not method in frappe.whitelisted:
frappe.msgprint(_("Not permitted")) 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) ret = frappe.call(method, **frappe.form_dict)




+ 1
- 1
frappe/hooks.py View File

@@ -26,7 +26,7 @@ to ERPNext.
""" """


app_icon = "octicon octicon-circuit-board" app_icon = "octicon octicon-circuit-board"
app_version = "6.0.0-wip"
app_version = "6.0.0"
app_color = "orange" app_color = "orange"
github_link = "https://github.com/frappe/frappe" github_link = "https://github.com/frappe/frappe"




frappe/website/doctype/social_login_keys/__init__.py → frappe/integrations/__init__.py View File


+ 0
- 0
frappe/integrations/doctype/__init__.py View File


+ 0
- 0
frappe/integrations/doctype/social_login_keys/__init__.py View File


+ 221
- 0
frappe/integrations/doctype/social_login_keys/social_login_keys.json View File

@@ -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
}

frappe/website/doctype/social_login_keys/social_login_keys.py → frappe/integrations/doctype/social_login_keys/social_login_keys.py View File


+ 18
- 10
frappe/model/db_schema.py View File

@@ -140,6 +140,7 @@ class DbTable:
""" """
fl = frappe.db.sql("SELECT * FROM tabDocField WHERE parent = %s", self.doctype, as_dict = 1) fl = frappe.db.sql("SELECT * FROM tabDocField WHERE parent = %s", self.doctype, as_dict = 1)
precisions = {} precisions = {}
uniques = {}


if not frappe.flags.in_install: if not frappe.flags.in_install:
custom_fl = frappe.db.sql("""\ custom_fl = frappe.db.sql("""\
@@ -152,10 +153,15 @@ class DbTable:
filters={"doc_type": self.doctype, "doctype_or_field": "DocField", "property": "precision"}): filters={"doc_type": self.doctype, "doctype_or_field": "DocField", "property": "precision"}):
precisions[ps.field_name] = ps.value precisions[ps.field_name] = ps.value


# apply unique from property setters
for ps in frappe.get_all("Property Setter", fields=["field_name", "value"],
filters={"doc_type": self.doctype, "doctype_or_field": "DocField", "property": "unique"}):
uniques[ps.field_name] = cint(ps.value)

for f in fl: for f in fl:
self.columns[f['fieldname']] = DbColumn(self, f['fieldname'], self.columns[f['fieldname']] = DbColumn(self, f['fieldname'],
f['fieldtype'], f.get('length'), f.get('default'), f.get('search_index'), f['fieldtype'], f.get('length'), f.get('default'), f.get('search_index'),
f.get('options'), f.get('unique'), precisions.get(f['fieldname']) or f.get('precision'))
f.get('options'), uniques.get(f["fieldname"], f.get('unique')), precisions.get(f['fieldname']) or f.get('precision'))


def get_columns_from_db(self): def get_columns_from_db(self):
self.show_columns = frappe.db.sql("desc `%s`" % self.name) self.show_columns = frappe.db.sql("desc `%s`" % self.name)
@@ -294,18 +300,11 @@ class DbColumn:
return return


# type # type
if (current_def['type'] != column_def) or (self.unique and not current_def['unique'] \
and column_def not in ('text', 'longtext')):
if (current_def['type'] != column_def) or \
((self.unique and not current_def['unique']) and column_def not in ('text', 'longtext')):
self.table.change_type.append(self) self.table.change_type.append(self)


else: else:
# index
if current_def['index'] and not self.set_index and not self.unique:
self.table.drop_index.append(self)
if (not current_def['index'] and self.set_index) and not (column_def in ('text', 'longtext')):
self.table.add_index.append(self)

# default # default
if (self.default_changed(current_def) \ if (self.default_changed(current_def) \
and (self.default not in default_shortcuts) \ and (self.default not in default_shortcuts) \
@@ -313,6 +312,15 @@ class DbColumn:
and not (column_def in ['text','longtext'])): and not (column_def in ['text','longtext'])):
self.table.set_default.append(self) self.table.set_default.append(self)


# index should be applied or dropped irrespective of type change
if ( (current_def['index'] and not self.set_index and not self.unique)
or (current_def['unique'] and not self.unique) ):
# to drop unique you have to drop index
self.table.drop_index.append(self)

elif (not current_def['index'] and self.set_index) and not (column_def in ('text', 'longtext')):
self.table.add_index.append(self)

def default_changed(self, current_def): def default_changed(self, current_def):
if "decimal" in current_def['type']: if "decimal" in current_def['type']:
return self.default_changed_for_decimal(current_def) return self.default_changed_for_decimal(current_def)


+ 21
- 7
frappe/model/delete_doc.py View File

@@ -150,27 +150,41 @@ def check_if_doc_is_linked(doc, method="Delete"):


if item and item.parent != doc.name and ((method=="Delete" and item.docstatus<2) or if item and item.parent != doc.name and ((method=="Delete" and item.docstatus<2) or
(method=="Cancel" and item.docstatus==1)): (method=="Cancel" and item.docstatus==1)):
# raise exception only if
# linked to an non-cancelled doc when deleting
# or linked to a submitted doc when cancelling
frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}").format(doc.doctype, frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}").format(doc.doctype,
doc.name, item.parenttype if item.parent else link_dt, item.parent or item.name), doc.name, item.parenttype if item.parent else link_dt, item.parent or item.name),
frappe.LinkExistsError) frappe.LinkExistsError)


def check_if_doc_is_dynamically_linked(doc):
def check_if_doc_is_dynamically_linked(doc, method="Delete"):
for query in dynamic_link_queries: for query in dynamic_link_queries:
for df in frappe.db.sql(query, as_dict=True): for df in frappe.db.sql(query, as_dict=True):
if frappe.get_meta(df.parent).issingle: if frappe.get_meta(df.parent).issingle:


# dynamic link in single doc # dynamic link in single doc
refdoc = frappe.db.get_singles_dict(df.parent) refdoc = frappe.db.get_singles_dict(df.parent)
if refdoc.get(df.options)==doc.doctype and refdoc.get(df.fieldname)==doc.name:
if (refdoc.get(df.options)==doc.doctype
and refdoc.get(df.fieldname)==doc.name
and ((method=="Delete" and refdoc.docstatus < 2)
or (method=="Cancel" and refdoc.docstatus==1))
):
# raise exception only if
# linked to an non-cancelled doc when deleting
# or linked to a submitted doc when cancelling
frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}").format(doc.doctype, frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}").format(doc.doctype,
doc.name, df.parent, ""), frappe.LinkExistsError) doc.name, df.parent, ""), frappe.LinkExistsError)
else: else:

# dynamic link in table # dynamic link in table
for name in frappe.db.sql_list("""select name from `tab{parent}` where
{options}=%s and {fieldname}=%s""".format(**df), (doc.doctype, doc.name)):
frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}").format(doc.doctype,
doc.name, df.parent, name), frappe.LinkExistsError)
for refdoc in frappe.db.sql("""select name, docstatus from `tab{parent}` where
{options}=%s and {fieldname}=%s""".format(**df), (doc.doctype, doc.name), as_dict=True):

if ((method=="Delete" and refdoc.docstatus < 2) or (method=="Cancel" and refdoc.docstatus==1)):
# raise exception only if
# linked to an non-cancelled doc when deleting
# or linked to a submitted doc when cancelling
frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}")\
.format(doc.doctype, doc.name, df.parent, refdoc.name), frappe.LinkExistsError)


def delete_linked_todos(doc): def delete_linked_todos(doc):
delete_doc("ToDo", frappe.db.sql_list("""select name from `tabToDo` delete_doc("ToDo", frappe.db.sql_list("""select name from `tabToDo`


+ 2
- 2
frappe/model/document.py View File

@@ -457,7 +457,7 @@ class Document(BaseDocument):
msgprint(msg) msgprint(msg)


if frappe.flags.print_messages: 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))) raise frappe.MandatoryError(", ".join((each[0] for each in missing)))


@@ -581,7 +581,7 @@ class Document(BaseDocument):
from frappe.model.delete_doc import check_if_doc_is_linked, check_if_doc_is_dynamically_linked from frappe.model.delete_doc import check_if_doc_is_linked, check_if_doc_is_dynamically_linked
if not self.flags.ignore_links: if not self.flags.ignore_links:
check_if_doc_is_linked(self, method="Cancel") check_if_doc_is_linked(self, method="Cancel")
check_if_doc_is_dynamically_linked(self)
check_if_doc_is_dynamically_linked(self, method="Cancel")


@staticmethod @staticmethod
def whitelist(f): def whitelist(f):


+ 1
- 0
frappe/modules.txt View File

@@ -6,3 +6,4 @@ Custom
Geo Geo
Desk Desk
Print Print
Integrations

+ 12
- 0
frappe/public/css/form.css View File

@@ -161,3 +161,15 @@ select.form-control {
font-weight: bold; font-weight: bold;
background-color: #fffce7; background-color: #fffce7;
} }
.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;
}

+ 10
- 0
frappe/public/js/frappe/form/control.js View File

@@ -119,6 +119,16 @@ frappe.ui.form.ControlHTML = frappe.ui.form.Control.extend({
}, },
html: function(html) { html: function(html) {
this.$wrapper.html(html || this.get_content()); this.$wrapper.html(html || this.get_content());
},
set_value: function(html) {
if(html.appendTo) {
// jquery object
html.appendTo(this.$wrapper.empty());
} else {
// html
this.df.options = html;
this.html(html);
}
} }
}); });




+ 1
- 1
frappe/public/js/frappe/form/dashboard.js View File

@@ -24,7 +24,7 @@ frappe.ui.form.Dashboard = Class.extend({
}, },
set_headline_alert: function(text, alert_class, icon) { set_headline_alert: function(text, alert_class, icon) {
this.set_headline(repl('<div class="alert %(alert_class)s">%(icon)s%(text)s</div>', { this.set_headline(repl('<div class="alert %(alert_class)s">%(icon)s%(text)s</div>', {
"alert_class": alert_class || "alert-info",
"alert_class": alert_class || "",
"icon": icon ? '<i class="'+icon+'" /> ' : "", "icon": icon ? '<i class="'+icon+'" /> ' : "",
"text": text "text": text
})); }));


+ 17
- 4
frappe/public/js/frappe/form/footer/timeline_item.html View File

@@ -10,15 +10,28 @@
</span> </span>
</div> </div>
{% if(data.doctype=="Communication" || data.comment_type=="Comment") { %} {% if(data.doctype=="Communication" || data.comment_type=="Comment") { %}
<h6>
<h6>
<i class="{%= data.icon %} icon-fixed-width"></i> <i class="{%= data.icon %} icon-fixed-width"></i>
<span title="{%= data.comment_by %}">{%= data.fullname %}</span> <span title="{%= data.comment_by %}">{%= data.fullname %}</span>
<span class="text-muted" style="font-weight: normal;"> <span class="text-muted" style="font-weight: normal;">
&ndash; {%= data.comment_on %}</span> &ndash; {%= data.comment_on %}</span>
{% if(data.doctype=="Communication") { %} {% if(data.doctype=="Communication") { %}
<span class="text-muted">&ndash;</span>
<a href="#Form/{%= data.doctype %}/{%= data.name %}"
class="text-muted">{%= __("Details") %}</a>
<span class="text-muted">&ndash;</span>
<a href="#Form/{%= data.doctype %}/{%= data.name %}"
class="text-muted">
{% if (data.delivery_status) {
if (in_list(["Sent", "Opened", "Clicked"], data.delivery_status)) {
var indicator_class = "green";
} else {
var indicator_class = "red";
}
%}
<span class="indicator-right {%= indicator_class %} delivery-status-indicator"
title="{%= data.delivery_status %}">
{%= data.delivery_status %}</span>

{% } else { %} {%= __("Details") %} {% } %}
</a>
<a class="text-muted reply-link pull-right" <a class="text-muted reply-link pull-right"
data-name="{%= data.name %}">{%= __("Reply") %}</a> data-name="{%= data.name %}">{%= __("Reply") %}</a>
{% } %} {% } %}


+ 8
- 0
frappe/public/js/frappe/form/grid.js View File

@@ -53,6 +53,14 @@ frappe.ui.form.Grid = Class.extend({
var me = this, var me = this,
$rows = $(me.parent).find(".rows"), $rows = $(me.parent).find(".rows"),
data = this.get_data(); data = this.get_data();
if (this.frm && this.frm.docname) {
// use doc specific docfield object
this.df = frappe.meta.get_docfield(this.frm.doctype, this.df.fieldname, this.frm.docname);
} else {
// use non-doc specific docfield
this.df = frappe.meta.get_docfield(this.df.options, this.df.fieldname);
}


this.docfields = frappe.meta.get_docfields(this.doctype, this.frm.docname); this.docfields = frappe.meta.get_docfields(this.doctype, this.frm.docname);
this.display_status = frappe.perm.get_field_display_status(this.df, this.frm.doc, this.display_status = frappe.perm.get_field_display_status(this.df, this.frm.doc,


+ 1
- 1
frappe/public/js/frappe/ui/page.html View File

@@ -10,7 +10,7 @@
</div> </div>
<div class="text-right col-sm-5 col-xs-6 page-actions"> <div class="text-right col-sm-5 col-xs-6 page-actions">
<!-- ID and icon buttons --> <!-- ID and icon buttons -->
<h6 class="text-ellipsis sub-heading rtl hide text-muted"></h6>
<h6 class="text-ellipsis sub-heading hide text-muted"></h6>
<span class="page-icon-group hide hidden-xs hidden-sm"></span> <span class="page-icon-group hide hidden-xs hidden-sm"></span>


<!-- buttons --> <!-- buttons -->


+ 15
- 0
frappe/public/less/form.less View File

@@ -209,3 +209,18 @@ select.form-control {
font-weight: bold; font-weight: bold;
background-color: @light-yellow; background-color: @light-yellow;
} }

.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;
}

+ 1
- 0
frappe/public/less/variables.less View File

@@ -10,6 +10,7 @@
@modal-backdrop-bg: #334143; @modal-backdrop-bg: #334143;
@light-yellow: #fffce7; @light-yellow: #fffce7;
@text-extra-muted: @border-color; @text-extra-muted: @border-color;
@text-regular: 14px;
@text-medium: 12px; @text-medium: 12px;
@text-small: 10px; @text-small: 10px;




+ 1
- 1
frappe/sessions.py View File

@@ -32,7 +32,7 @@ def clear_cache(user=None):
cache = frappe.cache() cache = frappe.cache()


groups = ("bootinfo", "user_recent", "user_roles", "user_doc", "lang", groups = ("bootinfo", "user_recent", "user_roles", "user_doc", "lang",
"defaults", "user_permissions", "roles")
"defaults", "user_permissions", "roles", "home_page")


if user: if user:
for name in groups: for name in groups:


+ 1
- 1
frappe/utils/boilerplate.py View File

@@ -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: 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))) 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 manifest_template = """include MANIFEST.in


+ 7
- 0
frappe/utils/redis_wrapper.py View File

@@ -136,8 +136,15 @@ class RedisWrapper(redis.Redis):
except redis.exceptions.ConnectionError: except redis.exceptions.ConnectionError:
pass pass


def hdel_keys(self, name_starts_with, key):
"""Delete hash names with wildcard `*` and key"""
for name in frappe.cache().get_keys(name_starts_with):
name = name.split("|", 1)[1]
self.hdel(name, key)

def hkeys(self, name): def hkeys(self, name):
try: try:
return super(redis.Redis, self).hkeys(self.make_key(name)) return super(redis.Redis, self).hkeys(self.make_key(name))
except redis.exceptions.ConnectionError: except redis.exceptions.ConnectionError:
return [] return []


+ 0
- 80
frappe/website/doctype/social_login_keys/social_login_keys.json View File

@@ -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
}
]
}

+ 3
- 0
frappe/website/doctype/web_form/web_form.py View File

@@ -41,6 +41,9 @@ class WebForm(WebsiteGenerator):
name = frappe.db.get_value(self.doc_type, {"owner": frappe.session.user}, "name") name = frappe.db.get_value(self.doc_type, {"owner": frappe.session.user}, "name")
if name: if name:
frappe.form_dict.name = name frappe.form_dict.name = name
else:
# only a single doc allowed and no existing doc, hence new
frappe.form_dict.new = 1


# always render new form if login is not required or doesn't allow editing existing ones # always render new form if login is not required or doesn't allow editing existing ones
if not self.login_required or not self.allow_edit: if not self.login_required or not self.allow_edit:


+ 1
- 0
frappe/website/render.py View File

@@ -217,6 +217,7 @@ def clear_cache(path=None):
clear_sitemap() clear_sitemap()
frappe.clear_cache("Guest") frappe.clear_cache("Guest")
frappe.cache().delete_value("_website_pages") frappe.cache().delete_value("_website_pages")
frappe.cache().delete_value("home_page")


for method in frappe.get_hooks("website_clear_cache"): for method in frappe.get_hooks("website_clear_cache"):
frappe.get_attr(method)(path) frappe.get_attr(method)(path)

+ 4
- 2
frappe/website/template.py View File

@@ -59,8 +59,10 @@ def set_breadcrumbs(out, context):
"""Build breadcrumbs template (deprecated)""" """Build breadcrumbs template (deprecated)"""
out["no_breadcrumbs"] = context.get("no_breadcrumbs", 0) or ("<!-- no-breadcrumbs -->" in out.get("content", "")) out["no_breadcrumbs"] = context.get("no_breadcrumbs", 0) or ("<!-- no-breadcrumbs -->" in out.get("content", ""))


# breadcrumbs
if not out["no_breadcrumbs"] and "breadcrumbs" not in out:
if out["no_breadcrumbs"]:
out["breadcrumbs"] = ""

elif "breadcrumbs" not in out:
out["breadcrumbs"] = frappe.get_template("templates/includes/breadcrumbs.html").render(context) out["breadcrumbs"] = frappe.get_template("templates/includes/breadcrumbs.html").render(context)


def set_title_and_header(out, context): def set_title_and_header(out, context):


+ 1
- 0
requirements.txt View File

@@ -29,3 +29,4 @@ email_reply_parser
click click
num2words num2words
gevent-socketio gevent-socketio
watchdog==0.8.0

+ 1
- 1
setup.py View File

@@ -1,6 +1,6 @@
from setuptools import setup, find_packages from setuptools import setup, find_packages


version = "6.0.0-wip"
version = "6.0.0"


with open("requirements.txt", "r") as f: with open("requirements.txt", "r") as f:
install_requires = f.readlines() install_requires = f.readlines()


Loading…
Cancel
Save