Merge branch 'develop' of http://github.com/frappe/frappe into develop

This commit is contained in:
mbauskar 2016-01-11 19:06:34 +05:30
commit 007b8fb6b9
220 changed files with 11474 additions and 9668 deletions

View file

@ -1052,7 +1052,9 @@ def publish_realtime(*args, **kwargs):
:param room: Room in which to publish update (default entire site)
:param user: Transmit to user
:param doctype: Transmit to doctype, docname
:param docname: Transmit to doctype, docname"""
:param docname: Transmit to doctype, docname
:param after_commit: (default False) will emit after current transaction is committed
"""
import frappe.async
return frappe.async.publish_realtime(*args, **kwargs)

View file

@ -1,2 +1,2 @@
from __future__ import unicode_literals
__version__ = "6.16.4"
__version__ = "6.17.6"

View file

@ -97,7 +97,7 @@ def is_file_old(file_path):
return ((time.time() - os.stat(file_path).st_mtime) > TASK_LOG_MAX_AGE)
def publish_realtime(event=None, message=None, room=None, user=None, doctype=None, docname=None, now=False):
def publish_realtime(event=None, message=None, room=None, user=None, doctype=None, docname=None, after_commit=False):
"""Publish real-time updates
:param event: Event name, like `task_progress` etc. that will be handled by the client (default is `task_progress` if within task or `global`)
@ -105,23 +105,24 @@ def publish_realtime(event=None, message=None, room=None, user=None, doctype=Non
:param room: Room in which to publish update (default entire site)
:param user: Transmit to user
:param doctype: Transmit to doctype, docname
:param docname: Transmit to doctype, docname"""
:param docname: Transmit to doctype, docname
:param after_commit: (default False) will emit after current transaction is committed"""
if message is None:
message = {}
if event is None:
if frappe.local.task_id:
if getattr(frappe.local, "task_id", None):
event = "task_progress"
else:
event = "global"
if not room:
if frappe.local.task_id:
if getattr(frappe.local, "task_id", None):
room = get_task_progress_room()
if not "task_id" in message:
message["task_id"] = frappe.local.task_id
now = True
after_commit = False
elif user:
room = get_user_room(user)
elif doctype and docname:
@ -129,10 +130,10 @@ def publish_realtime(event=None, message=None, room=None, user=None, doctype=Non
else:
room = get_site_room()
if now:
emit_via_redis(event, message, room)
else:
if after_commit:
frappe.local.realtime_log.append([event, message, room])
else:
emit_via_redis(event, message, room)
def emit_via_redis(event, message, room):
"""Publish real-time updates via redis
@ -159,7 +160,7 @@ def put_log(line_no, line, task_id=None):
"lines": {line_no: line}
},
"task_id": task_id
}, room=task_progress_room, now=True)
}, room=task_progress_room)
r.hset(task_log_key, line_no, line)
r.expire(task_log_key, 3600)

View file

@ -0,0 +1,4 @@
- Ability to **Like** a document, comment or communication
- See notifications about likes that you received
- View it on Activity feed
- *Stars* have been converted to Likes

View file

@ -218,6 +218,7 @@ def migrate(context, rebuild_website=False):
clear_notifications()
finally:
frappe.publish_realtime("version-update")
frappe.destroy()
if rebuild_website:
@ -225,6 +226,7 @@ def migrate(context, rebuild_website=False):
else:
call_command(sync_www, context)
def prepare_for_update():
from frappe.sessions import clear_global_cache
clear_global_cache()

View file

@ -1,338 +1,338 @@
{
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "hash",
"creation": "2012-08-08 10:40:11",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "hash",
"creation": "2012-08-08 10:40:11",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "comment",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Comment",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment",
"oldfieldtype": "Text",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "comment",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Comment",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment",
"oldfieldtype": "Text",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_type",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Comment Type",
"length": 0,
"no_copy": 0,
"options": "Email\nChat\nPhone\nSMS\nCreated\nSubmitted\nCancelled\nAssigned\nAssignment Completed\nComment\nWorkflow\nLabel\nAttachment\nAttachment Removed",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_type",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Comment Type",
"length": 0,
"no_copy": 0,
"options": "Email\nChat\nPhone\nSMS\nCreated\nSubmitted\nCancelled\nAssigned\nAssignment Completed\nComment\nWorkflow\nLabel\nAttachment\nAttachment Removed\nLike",
"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,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_by",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Comment By",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment_by",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_by",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Comment By",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment_by",
"oldfieldtype": "Data",
"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,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_by_fullname",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Comment By Fullname",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment_by_fullname",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_by_fullname",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Comment By Fullname",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment_by_fullname",
"oldfieldtype": "Data",
"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,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Comment Date",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment_date",
"oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Comment Date",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment_date",
"oldfieldtype": "Date",
"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,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_time",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Comment Time",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment_time",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_time",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Comment Time",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment_time",
"oldfieldtype": "Data",
"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,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_doctype",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Comment Doctype",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment_doctype",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_doctype",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Comment Doctype",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment_doctype",
"oldfieldtype": "Data",
"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,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_docname",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Comment Docname",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment_docname",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "comment_docname",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Comment Docname",
"length": 0,
"no_copy": 0,
"oldfieldname": "comment_docname",
"oldfieldtype": "Data",
"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,
"bold": 0,
"collapsible": 0,
"fieldname": "post_topic",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Post Topic",
"length": 0,
"no_copy": 0,
"oldfieldname": "post_topic",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "post_topic",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Post Topic",
"length": 0,
"no_copy": 0,
"oldfieldname": "post_topic",
"oldfieldtype": "Data",
"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,
"bold": 0,
"collapsible": 0,
"fieldname": "unsubscribed",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Unsubscribed",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "unsubscribed",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Unsubscribed",
"length": 0,
"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,
"bold": 0,
"collapsible": 0,
"fieldname": "reference_doctype",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference DocType",
"length": 0,
"no_copy": 0,
"options": "DocType",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "reference_doctype",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference DocType",
"length": 0,
"no_copy": 0,
"options": "DocType",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "Reference DocType and Reference Name are used to render a comment as a link (href) to a Doc.",
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference Name",
"length": 0,
"no_copy": 0,
"options": "reference_doctype",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "Reference DocType and Reference Name are used to render a comment as a link (href) to a Doc.",
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference Name",
"length": 0,
"no_copy": 0,
"options": "reference_doctype",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "icon-comments",
"idx": 1,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2015-11-16 06:29:43.314568",
"modified_by": "Administrator",
"module": "Core",
"name": "Comment",
"owner": "Administrator",
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "icon-comments",
"idx": 1,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2015-12-26 06:29:43.314568",
"modified_by": "Administrator",
"module": "Core",
"name": "Comment",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"read_only": 0,
"read_only_onload": 0,
],
"read_only": 0,
"read_only_onload": 0,
"title_field": "comment"
}
}

View file

@ -23,8 +23,8 @@ class Comment(Document):
if self.comment_type in ("Created", "Submitted", "Cancelled", "Label"):
comment_type = "Label"
elif self.comment_type == "Comment":
comment_type = "Comment"
elif self.comment_type in ("Comment", "Like"):
comment_type = self.comment_type
else:
comment_type = "Info"
@ -32,7 +32,9 @@ class Comment(Document):
"subject": self.comment,
"doctype": self.comment_doctype,
"name": self.comment_docname,
"feed_type": comment_type
"feed_type": comment_type,
"reference_doctype": self.reference_doctype,
"reference_name": self.reference_name
}
def after_insert(self):
@ -44,13 +46,15 @@ class Comment(Document):
if self.comment_docname == frappe.session.user:
message = self.as_dict()
message['broadcast'] = True
frappe.publish_realtime('new_message', message)
frappe.publish_realtime('new_message', message, after_commit=True)
else:
# comment_docname contains the user who is addressed in the messages' page comment
frappe.publish_realtime('new_message', self.as_dict(), user=self.comment_docname)
frappe.publish_realtime('new_message', self.as_dict(),
user=self.comment_docname, after_commit=True)
else:
frappe.publish_realtime('new_comment', self.as_dict(), doctype= self.comment_doctype,
docname = self.comment_docname)
frappe.publish_realtime('new_comment', self.as_dict(),
doctype= self.comment_doctype, docname = self.comment_docname,
after_commit=True)
self.notify_mentions()
@ -182,3 +186,6 @@ def on_doctype_update():
frappe.db.commit()
frappe.db.sql("""alter table `tabComment`
add index comment_doctype_docname_index(comment_doctype, comment_docname)""")
if "_liked_by" not in frappe.db.get_table_columns("Comment"):
add_column("Comment", "_liked_by", "Text")

View file

@ -16,12 +16,12 @@ frappe.ui.form.on("Communication", "refresh", function(frm) {
}
if(frm.doc.status==="Open") {
frm.add_custom_button("Close", function() {
frm.add_custom_button(__("Close"), function() {
frm.set_value("status", "Closed");
frm.save();
});
} else if (frm.doc.status !== "Linked") {
frm.add_custom_button("Reopen", function() {
frm.add_custom_button(__("Reopen"), function() {
frm.set_value("status", "Open");
frm.save();
});
@ -30,7 +30,7 @@ frappe.ui.form.on("Communication", "refresh", function(frm) {
frappe.ui.form.on("Communication", "onload", function(frm) {
if(frm.doc.content) {
frm.doc.content = frappe.utils.remove_script_and_style(frm.doc.content);
frm.doc.content = frappe.dom.remove_script_and_style(frm.doc.content);
}
frm.set_query("reference_doctype", function() {
return {

View file

@ -10,6 +10,7 @@ from frappe.utils.file_manager import get_file
from frappe.email.bulk import check_bulk_limit
import frappe.email.smtp
from frappe import _
from frappe.model.db_schema import add_column
from frappe.model.document import Document
@ -50,7 +51,7 @@ class Communication(Document):
comment["comment_type"] = comment["communication_medium"]
frappe.publish_realtime('new_comment', comment, doctype = self.reference_doctype,
docname = self.reference_name)
docname = self.reference_name, after_commit=True)
def on_update(self):
"""Update parent status as `Open` or `Replied`."""
@ -246,7 +247,6 @@ class Communication(Document):
# if it is a fetched email, add follows to CC
cc.append(self.get_owner_email())
cc += self.get_assignees()
cc += self.get_starrers()
if cc:
# exclude email accounts, unfollows, recipients and unsubscribes
@ -306,10 +306,6 @@ class Communication(Document):
return filtered
def get_starrers(self):
"""Return list of users who have starred this document."""
return [( get_formatted_email(user) or user ) for user in self.get_parent_doc().get_starred_by()]
def get_owner_email(self):
owner = self.get_parent_doc().owner
return get_formatted_email(owner) or owner
@ -337,6 +333,9 @@ def on_doctype_update():
"""Add index in `tabCommunication` for `(reference_doctype, reference_name)`"""
frappe.db.add_index("Communication", ["reference_doctype", "reference_name"])
if "_liked_by" not in frappe.db.get_table_columns("Communication"):
add_column("Communication", "_liked_by", "Text")
@frappe.whitelist()
def make(doctype=None, name=None, content=None, subject=None, sent_or_received = "Sent",
sender=None, recipients=None, communication_medium="Email", send_email=False,

View file

@ -42,8 +42,13 @@ class DocShare(Document):
frappe.throw(_('You need to have "Share" permission'), frappe.PermissionError)
def after_insert(self):
self.get_doc().add_comment("Shared",
_("{0} shared this document with {1}").format(get_fullname(self.owner), get_fullname(self.user)))
doc = self.get_doc()
owner = get_fullname(self.owner)
if self.everyone:
doc.add_comment("Shared", _("{0} shared this document with everyone").format(owner))
else:
doc.add_comment("Shared", _("{0} shared this document with {1}").format(owner, get_fullname(self.user)))
def on_trash(self):
if not self.flags.ignore_share_permission:

View file

@ -26,6 +26,7 @@
"oldfieldtype": "Section Break",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -51,6 +52,7 @@
"options": "Module Def",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
@ -76,6 +78,7 @@
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -101,11 +104,12 @@
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"set_only_once": 1,
"unique": 0
},
{
@ -122,6 +126,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -147,6 +152,7 @@
"options": "\nDocument\nSetup\nSystem\nOther",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -169,6 +175,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -191,6 +198,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -213,6 +221,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -236,6 +245,7 @@
"oldfieldtype": "Section Break",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -261,6 +271,7 @@
"options": "DocField",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -283,6 +294,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -308,6 +320,7 @@
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -333,6 +346,7 @@
"options": "\nTitle Case\nUPPER CASE",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -357,6 +371,7 @@
"oldfieldtype": "Text",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -378,6 +393,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -401,6 +417,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -425,6 +442,7 @@
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -449,6 +467,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -473,6 +492,7 @@
"options": "ASC\nDESC",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -496,6 +516,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -522,6 +543,7 @@
"options": "DocPerm",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -544,6 +566,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -566,6 +589,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -590,6 +614,7 @@
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -614,6 +639,7 @@
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -636,6 +662,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -659,6 +686,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -683,6 +711,7 @@
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -707,6 +736,7 @@
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -731,6 +761,7 @@
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -755,6 +786,7 @@
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -777,6 +809,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -801,6 +834,7 @@
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -825,6 +859,7 @@
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -849,6 +884,7 @@
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -871,6 +907,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -889,7 +926,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2015-11-16 06:29:45.648699",
"modified": "2016-01-11 01:54:58.471041",
"modified_by": "Administrator",
"module": "Core",
"name": "DocType",

View file

@ -50,6 +50,9 @@ class DocType(Document):
self.make_amendable()
if self.istable:
self.allow_import = 0
def check_developer_mode(self):
"""Throw exception if not developer mode or via patch"""
if frappe.flags.in_patch:
@ -274,7 +277,7 @@ def validate_fields(meta):
frappe.throw(_("Max width for type Currency is 100px in row {0}").format(d.idx))
def check_in_list_view(d):
if d.in_list_view and d.fieldtype!="Image" and (d.fieldtype in no_value_fields):
if d.in_list_view and (d.fieldtype in no_value_fields):
frappe.throw(_("'In List View' not allowed for type {0} in row {1}").format(d.fieldtype, d.idx))
def check_dynamic_link_options(d):

View file

@ -1385,7 +1385,7 @@
"istable": 0,
"max_attachments": 5,
"menu_index": 0,
"modified": "2015-12-23 02:45:19.261689",
"modified": "2016-01-08 04:50:48.919694",
"modified_by": "Administrator",
"module": "Core",
"name": "User",
@ -1398,9 +1398,9 @@
"create": 1,
"delete": 1,
"email": 1,
"export": 0,
"export": 1,
"if_owner": 0,
"import": 0,
"import": 1,
"permlevel": 0,
"print": 1,
"read": 1,

View file

@ -14,6 +14,9 @@ def get_notification_config():
"Comment": "frappe.core.notifications.get_unread_messages",
"Error Snapshot": {"seen": 0, "parent_error_snapshot": None},
},
"for_other": {
"Likes": "frappe.core.notifications.get_unseen_likes"
}
}
def get_things_todo():
@ -41,3 +44,12 @@ def get_unread_messages():
AND comment_docname = %s
AND docstatus=0
""", (frappe.session.user,))[0][0]
def get_unseen_likes():
"""Returns count of unseen likes"""
return frappe.db.sql("""select count(*) from `tabFeed`
where
feed_type='Like'
and owner is not null and owner!=%(user)s
and doc_owner=%(user)s
and seen=0""", {"user": frappe.session.user})[0][0]

View file

@ -110,7 +110,8 @@ frappe.DataImportTool = Class.extend({
me.write_messages(r.messages);
}
}
},
is_private: true
});
frappe.realtime.on("data_import_progress", function(data) {

View file

@ -19,11 +19,7 @@ def get_data_keys():
@frappe.whitelist()
def get_doctypes():
if "System Manager" in frappe.get_roles():
return [r[0] for r in frappe.db.sql("""select name from `tabDocType`
where allow_import = 1""")]
else:
return frappe.get_user()._get("can_import")
return frappe.get_user()._get("can_import")
@frappe.whitelist()
def get_doctype_options():

View file

@ -218,7 +218,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False,
# publish task_update
frappe.publish_realtime("data_import_progress", {"progress": [i, total]},
user=frappe.session.user, now=True)
user=frappe.session.user)
try:
doc = get_doc(row_idx)

View file

@ -92,11 +92,9 @@ class CustomField(Document):
# Create new peroperty setter if order changed
if _idx and not existing_property_setter:
field_idx = (_idx.index(self.insert_after) + 1) if (self.insert_after in _idx) else len(_idx)
if field_idx < len(_idx):
_idx[field_idx] = self.fieldname
else:
_idx.append(self.fieldname)
_idx.insert(field_idx, self.fieldname)
frappe.make_property_setter({
"doctype":self.dt,
"doctype_or_field": "DocType",

View file

@ -12,7 +12,6 @@ frappe.ui.form.on("Customize Form", {
filters: [
['DocType', 'issingle', '=', 0],
['DocType', 'custom', '=', 0],
['DocType', 'in_create', '=', 0],
['DocType', 'name', 'not in', 'DocType, DocField, DocPerm, User, Role, UserRole, \
Page, Page Role, Module Def, Print Format, Report, Customize Form, \
Customize Form Field']

View file

@ -19,31 +19,34 @@ def add_user_default(key, value, user=None, parenttype=None):
def get_user_default(key, user=None):
user_defaults = get_defaults(user or frappe.session.user)
d = user_defaults.get(key, None)
if key != frappe.scrub(key):
if is_a_user_permission_key(key):
if d and isinstance(d, (list, tuple)) and len(d)==1:
# Use User Permission value when only when it has a single value
d = d[0]
else:
d = user_defaults.get(frappe.scrub(key), None)
return isinstance(d, (list, tuple)) and d[0] or d
def get_user_default_as_list(key, user=None):
user_defaults = get_defaults(user or frappe.session.user)
d = user_defaults.get(key, None)
if key != frappe.scrub(key):
if is_a_user_permission_key(key):
if d and isinstance(d, (list, tuple)) and len(d)==1:
# Use User Permission value when only when it has a single value
d = [d[0]]
else:
d = user_defaults.get(frappe.scrub(key), None)
return (not isinstance(d, (list, tuple))) and [d] or d
def is_a_user_permission_key(key):
return ":" not in key and key != frappe.scrub(key)
def get_user_permissions(user=None):
if not user:
user = frappe.session.user

View file

@ -1,6 +1,6 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "EV.#####",
"creation": "2013-06-10 13:17:47",
@ -24,6 +24,7 @@
"oldfieldtype": "Section Break",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -46,6 +47,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
@ -71,6 +73,7 @@
"options": "Private\nPublic\nCancel",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
@ -94,6 +97,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -115,6 +119,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -137,6 +142,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
@ -159,6 +165,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -181,6 +188,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -202,6 +210,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -224,6 +233,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -246,6 +256,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -270,6 +281,7 @@
"options": "\nEvery Day\nEvery Week\nEvery Month\nEvery Year",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -294,6 +306,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -315,6 +328,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -338,6 +352,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -361,6 +376,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -384,6 +400,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -407,6 +424,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -430,6 +448,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -453,6 +472,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -476,6 +496,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -497,6 +518,7 @@
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -521,6 +543,7 @@
"oldfieldtype": "Text",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "300px",
"read_only": 0,
"report_hide": 0,
@ -546,6 +569,7 @@
"oldfieldtype": "Section Break",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -569,6 +593,7 @@
"oldfieldtype": "Column Break",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "50%",
"read_only": 0,
"report_hide": 0,
@ -596,6 +621,7 @@
"options": "Event Role",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -621,6 +647,7 @@
"options": "DocType",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
@ -646,6 +673,7 @@
"options": "ref_type",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
@ -664,7 +692,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2015-11-16 06:29:46.775883",
"modified": "2016-01-08 04:50:37.240223",
"modified_by": "Administrator",
"module": "Desk",
"name": "Event",
@ -697,9 +725,9 @@
"create": 1,
"delete": 1,
"email": 1,
"export": 0,
"export": 1,
"if_owner": 0,
"import": 0,
"import": 1,
"permlevel": 0,
"print": 1,
"read": 1,

View file

@ -1,204 +1,309 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "hash",
"creation": "2012-07-03 13:29:42",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "hash",
"creation": "2012-07-03 13:29:42",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "feed_type",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Feed Type",
"length": 0,
"no_copy": 0,
"options": "\nComment\nLogin\nLabel\nInfo",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "feed_type",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Feed Type",
"length": 0,
"no_copy": 0,
"options": "\nComment\nLogin\nLabel\nInfo\nLike",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "doc_type",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Doc Type",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "doc_type",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Doc Type",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "doc_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Doc Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "doc_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Doc Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "subject",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Subject",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "subject",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Subject",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "color",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Color",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "color",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Color",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "full_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Full Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "full_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Full Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "doc_owner",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Doc Owner",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "seen",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Seen",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"description": "Use this to provide alternative link to a feed record",
"fieldname": "reference_doctype",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference DocType",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "reference_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "icon-rss",
"idx": 1,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2015-11-16 06:29:47.123186",
"modified_by": "Administrator",
"module": "Desk",
"name": "Feed",
"owner": "Administrator",
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "icon-rss",
"idx": 1,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2015-12-30 02:48:03.860188",
"modified_by": "Administrator",
"module": "Desk",
"name": "Feed",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
},
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 1,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "All",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"amend": 0,
"apply_user_permissions": 1,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 1,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "All",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
}
],
"read_only": 0,
],
"read_only": 0,
"read_only_onload": 0
}
}

View file

@ -12,7 +12,13 @@ from frappe import _
exclude_from_linked_with = True
class Feed(Document):
pass
no_feed_on_delete = True
def validate(self):
if not (self.reference_doctype and self.reference_name):
# reset both if even one is missing
self.reference_doctype = self.reference_name = None
def on_doctype_update():
if not frappe.db.sql("""show index from `tabFeed`
@ -24,9 +30,12 @@ def on_doctype_update():
def get_permission_query_conditions(user):
if not user: user = frappe.session.user
if not frappe.permissions.apply_user_permissions("Feed", "read", user):
use_user_permissions = frappe.permissions.apply_user_permissions("Feed", "read", user)
if not use_user_permissions:
return ""
conditions = ['`tabFeed`.owner="{user}" or `tabFeed`.doc_owner="{user}"'.format(user=frappe.db.escape(user))]
user_permissions = frappe.defaults.get_user_permissions(user)
can_read = frappe.get_user().get_can_read()
@ -34,19 +43,17 @@ def get_permission_query_conditions(user):
list(set(can_read) - set(user_permissions.keys()))]
if not can_read_doctypes:
return ""
conditions += ["tabFeed.doc_type in ({})".format(", ".join(can_read_doctypes))]
conditions = ["tabFeed.doc_type in ({})".format(", ".join(can_read_doctypes))]
if user_permissions:
can_read_docs = []
for doctype, names in user_permissions.items():
for n in names:
can_read_docs.append('"{}|{}"'.format(doctype, n))
if user_permissions:
can_read_docs = []
for doctype, names in user_permissions.items():
for n in names:
can_read_docs.append('"{}|{}"'.format(doctype, n))
if can_read_docs:
conditions.append("concat_ws('|', tabFeed.doc_type, tabFeed.doc_name) in ({})".format(
", ".join(can_read_docs)))
if can_read_docs:
conditions.append("concat_ws('|', tabFeed.doc_type, tabFeed.doc_name) in ({})".format(
", ".join(can_read_docs)))
return "(" + " or ".join(conditions) + ")"
@ -83,7 +90,10 @@ def update_feed(doc, method=None):
"doc_type": doctype,
"doc_name": name,
"subject": feed.subject,
"full_name": get_fullname(doc.owner)
"full_name": get_fullname(doc.owner),
"doc_owner": frappe.db.get_value(doctype, name, "owner"),
"reference_doctype": feed.reference_doctype,
"reference_name": feed.reference_name
}).insert(ignore_permissions=True)
def login_feed(login_manager):

View file

@ -95,11 +95,11 @@ def get_docinfo(doc=None, doctype=None, name=None):
def get_user_permissions(meta):
out = {}
all_user_permissions = frappe.defaults.get_user_permissions()
for m in meta:
for df in m.get_fields_to_check_permissions(all_user_permissions):
out[df.options] = list(set(all_user_permissions[df.options]))
return out
def get_attachments(dt, dn):
@ -108,7 +108,7 @@ def get_attachments(dt, dn):
def get_comments(dt, dn, limit=100):
comments = frappe.db.sql("""select name, comment, comment_by, creation,
reference_doctype, reference_name, comment_type, "Comment" as doctype
reference_doctype, reference_name, comment_type, "Comment" as doctype, _liked_by
from `tabComment`
where comment_doctype=%s and comment_docname=%s
order by creation desc limit %s""",
@ -116,7 +116,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, delivery_status,
communication_medium as comment_type, subject, delivery_status, _liked_by,
"Communication" as doctype
from tabCommunication
where reference_doctype=%s and reference_name=%s

103
frappe/desk/like.py Normal file
View file

@ -0,0 +1,103 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
"""Allow adding of likes to documents"""
import frappe, json
from frappe.model.db_schema import add_column
from frappe import _
from frappe.utils import get_link_to_form
@frappe.whitelist()
def toggle_like(doctype, name, add=False):
"""Adds / removes the current user in the `__liked_by` property of the given document.
If column does not exist, will add it in the database.
The `_liked_by` property is always set from this function and is ignored if set via
Document API
:param doctype: DocType of the document to like
:param name: Name of the document to like
:param add: `Yes` if like is to be added. If not `Yes` the like will be removed."""
_toggle_like(doctype, name, add)
def _toggle_like(doctype, name, add, user=None):
"""Same as toggle_like but hides param `user` from API"""
if not user:
user = frappe.session.user
try:
liked_by, owner = frappe.db.get_value(doctype, name, ["_liked_by", "owner"])
# CHANGED: Allow someone to like their own documents as it also works as a bookmark
# if owner==frappe.session.user and add=="Yes":
# frappe.throw(_("You cannot like something that you created"))
if liked_by:
liked_by = json.loads(liked_by)
else:
liked_by = []
if add=="Yes":
if user not in liked_by:
liked_by.append(user)
add_comment(doctype, name)
else:
if user in liked_by:
liked_by.remove(user)
remove_like(doctype, name)
frappe.db.set_value(doctype, name, "_liked_by", json.dumps(liked_by), update_modified=False)
except Exception, e:
if isinstance(e.args, (tuple, list)) and e.args and e.args[0]==1054:
add_column(doctype, "_liked_by", "Text")
_toggle_like(doctype, name, add, user)
else:
raise
def remove_like(doctype, name):
"""Remove previous Like"""
# remove Comment
frappe.delete_doc("Comment", [c.name for c in frappe.get_all("Comment",
filters={
"comment_doctype": doctype,
"comment_docname": name,
"comment_by": frappe.session.user,
"comment_type": "Like"
}
)], ignore_permissions=True)
# remove Feed
frappe.delete_doc("Feed", [c.name for c in frappe.get_all("Feed",
filters={
"doc_type": doctype,
"doc_name": name,
"owner": frappe.session.user,
"feed_type": "Like"
}
)], ignore_permissions=True)
def add_comment(doctype, name):
doc = frappe.get_doc(doctype, name)
if doctype=="Comment":
link = get_link_to_form(doc.comment_doctype, doc.comment_docname,
"{0} {1}".format(_(doc.comment_doctype), doc.comment_docname))
doc.add_comment("Like", _("Comment: {0} in {1}").format("<b>" + doc.comment + "</b>", link),
reference_doctype=doc.comment_doctype, reference_name=doc.comment_docname)
elif doctype=="Communication":
link = get_link_to_form(doc.reference_doctype, doc.reference_name,
"{0} {1}".format(_(doc.reference_doctype), doc.reference_name))
doc.add_comment("Like", _("Communication: {0} in {1}").format("<b>" + doc.subject + "</b>", link),
reference_doctype=doc.reference_doctype, reference_name=doc.reference_name)
else:
doc.add_comment("Like", _("Liked"))

View file

@ -24,7 +24,9 @@ def get_notifications():
return {
"open_count_doctype": get_notifications_for_doctypes(config, notification_count),
"open_count_module": get_notifications_for_modules(config, notification_count),
"open_count_other": get_notifications_for_other(config, notification_count),
"new_messages": get_new_messages()
# "likes": get_count_of_new_likes()
}
def get_new_messages():
@ -48,19 +50,27 @@ def get_new_messages():
def get_notifications_for_modules(config, notification_count):
"""Notifications for modules"""
open_count_module = {}
for m in config.for_module:
return get_notifications_for("for_module", config, notification_count)
def get_notifications_for_other(config, notification_count):
"""Notifications for other items"""
return get_notifications_for("for_other", config, notification_count)
def get_notifications_for(notification_type, config, notification_count):
open_count = {}
notification_map = config.get(notification_type) or {}
for m in notification_map:
try:
if m in notification_count:
open_count_module[m] = notification_count[m]
open_count[m] = notification_count[m]
else:
open_count_module[m] = frappe.get_attr(config.for_module[m])()
open_count[m] = frappe.get_attr(notification_map[m])()
frappe.cache().hset("notification_count:" + m, frappe.session.user, open_count_module[m])
frappe.cache().hset("notification_count:" + m, frappe.session.user, open_count[m])
except frappe.PermissionError:
frappe.msgprint("Permission Error in notifications for {0}".format(m))
return open_count_module
return open_count
def get_notifications_for_doctypes(config, notification_count):
"""Notifications for DocTypes"""
@ -143,7 +153,7 @@ def get_notification_config():
config = frappe._dict()
for notification_config in frappe.get_hooks().notification_config:
nc = frappe.get_attr(notification_config)()
for key in ("for_doctype", "for_module", "for_module_doctypes"):
for key in ("for_doctype", "for_module", "for_module_doctypes", "for_other"):
config.setdefault(key, {})
config[key].update(nc.get(key, {}))
return config

View file

@ -62,3 +62,12 @@
width: 97% !important;
margin: auto;
}
#page-activity .list-filters {
display: none !important;
}
#page-activity .octicon-heart {
color: #ff5858;
margin: 0px 5px;
}

View file

@ -18,36 +18,73 @@ frappe.pages['activity'].on_page_load = function(wrapper) {
this.page.set_title(__("Activity"));
this.page.list = new frappe.ui.Listing({
hide_refresh: true,
page: this.page,
method: 'frappe.desk.page.activity.activity.get_feed',
parent: $("<div></div>").appendTo(this.page.main),
render_row: function(row, data) {
new frappe.activity.Feed(row, data);
}
});
frappe.model.with_doctype("Feed", function() {
me.page.list = new frappe.ui.Listing({
hide_refresh: true,
page: me.page,
method: 'frappe.desk.page.activity.activity.get_feed',
parent: $("<div></div>").appendTo(me.page.main),
render_row: function(row, data) {
new frappe.activity.Feed(row, data);
},
show_filters: true,
doctype: "Feed",
get_args: function() {
if (frappe.route_options && frappe.route_options.show_likes) {
delete frappe.route_options.show_likes;
return {
show_likes: true
}
} else {
return {}
}
}
});
this.page.list.run();
me.page.list.run();
me.page.set_primary_action(__("Refresh"), function() {
me.page.list.filter_list.clear_filters();
me.page.list.run();
}, "octicon octicon-sync");
});
frappe.activity.render_plot(this.page);
this.page.main.on("click", ".activity-message", function() {
var doctype = $(this).attr("data-doctype"),
var reference_doctype = $(this).attr("data-reference-doctype"),
reference_name = $(this).attr("data-reference-name"),
doctype = $(this).attr("data-doctype"),
docname = $(this).attr("data-docname");
if (doctype && docname) {
frappe.set_route(["Form", doctype, docname]);
frappe.set_route(["Form", reference_doctype || doctype, reference_name || docname]);
if (reference_doctype && reference_name) {
frappe.route_options = {
scroll_to: { "doctype": doctype, "name": docname }
}
}
}
});
this.page.set_primary_action(__("Refresh"), function() { me.page.list.run(); }, "octicon octicon-sync");
// Build Report Button
if(frappe.boot.user.can_get_report.indexOf("Feed")!=-1) {
this.page.set_secondary_action(__('Build Report'), function() {
this.page.add_menu_item(__('Build Report'), function() {
frappe.set_route('Report', "Feed");
}, 'icon-th');
}, 'icon-th')
}
this.page.add_menu_item(__('Show Likes'), function() {
frappe.route_options = {
show_likes: true
};
me.page.list.run();
}, 'octicon octicon-heart');
};
frappe.pages['activity'].on_page_show = function() {
frappe.breadcrumbs.add("Desk");
}
frappe.activity.last_feed_date = false;
@ -69,7 +106,7 @@ frappe.activity.Feed = Class.extend({
.find("a").addClass("grey");
},
scrub_data: function(data) {
data.by = frappe.user_info(data.owner).fullname;
data.by = frappe.user.full_name(data.owner);
data.imgsrc = frappe.utils.get_file_link(frappe.user_info(data.owner).image);
data.icon = "icon-flag";

View file

@ -3,14 +3,38 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cint
from frappe.desk.doctype.feed.feed import get_permission_query_conditions
@frappe.whitelist()
def get_feed(limit_start, limit_page_length):
def get_feed(limit_start, limit_page_length, show_likes=False):
"""get feed"""
return frappe.get_list("Feed", fields=["name", "feed_type", "doc_type",
"subject", "owner", "modified", "doc_name", "creation"],
limit_start = limit_start, limit_page_length = limit_page_length,
order_by="creation desc")
# directly use the permission query condition function of feed
match_conditions = get_permission_query_conditions(frappe.session.user)
result = frappe.db.sql("""select name, feed_type, doc_type, doc_name, subject,
owner, modified, creation, seen, reference_doctype, reference_name
from `tabFeed`
where
((feed_type='Like' and (owner=%(user)s or doc_owner=%(user)s)) or feed_type!='Like')
{match_conditions}
{show_likes}
order by creation desc
limit %(limit_start)s, %(limit_page_length)s"""
.format(match_conditions="and {0}".format(match_conditions) if match_conditions else "",
show_likes="and feed_type='Like'" if show_likes else ""),
{
"user": frappe.session.user,
"limit_start": cint(limit_start),
"limit_page_length": cint(limit_page_length)
}, as_dict=True)
if show_likes:
# mark likes as seen!
frappe.db.sql("update `tabFeed` set seen=1 where feed_type='Like' and doc_owner=%s", frappe.session.user)
frappe.local.flags.commit = True
return result
@frappe.whitelist()
def get_months_activity():

View file

@ -1,10 +1,15 @@
<div class="row activity-row" data-creation="{%= creation.split(" ")[0] + " 00:00:00" %}">
<div class="col-xs-3 text-right activity-date"><span class="{%= date_class %}">
{%= date_sep || "" %}</span></div>
<div class="col-xs-9 activity-message" data-doctype="{%= doc_type %}" data-docname="{%= doc_name %}"
<div class="col-xs-9 activity-message"
data-doctype="{%= doc_type %}"
data-docname="{%= doc_name %}"
data-reference-doctype="{{ reference_doctype }}"
data-reference-name="{{ reference_name }}"
title="{%= by %} / {%= dateutil.str_to_user(creation) %}">
<span class="avatar avatar-small">
<img src="{%= imgsrc %}">
<div class="avatar-frame" style="background-image: url({{ imgsrc }});"></div>
<!-- <img src="{%= imgsrc %}"> -->
</span>
<span class="small">
{% if (feed_type==="Login") { %}
@ -15,6 +20,13 @@
{%= __("Commented on {0}: {1}", [link, "<strong>" + subject + "</strong>"]) %}
{% } else if (doc_type && !feed_type) { %}
{%= __("Updated {0}: {1}", [link, "<strong>" + subject + "</strong>"]) %}
{% } else if (feed_type==="Like" && doc_type) { %}
{%= by %} <i class="octicon octicon-heart"></i>
{% if (in_list(["Comment", "Communication"], doc_type)) { %}
{%= subject %}
{% } else { %}
{%= link %}
{% } %}
{% } else if (doc_type) { %}
{%= __("{0}: {1}", [link, "<strong>" + subject + "</strong>"]) %}
{% } else { %}

View file

@ -74,12 +74,12 @@ def install_app(name):
frappe.throw(_("You cannot install this app"))
frappe.publish_realtime("install_app_progress", {"status": _("Installing App {0}").format(name)},
user=frappe.session.user, now=True)
user=frappe.session.user)
frappe.installer.install_app(name)
frappe.publish_realtime("install_app_progress", {"status": _("{0} Installed").format(name)},
user=frappe.session.user, now=True)
user=frappe.session.user)
def get_app(name):
"""Get app using git clone and install it in bench environment"""
@ -89,7 +89,7 @@ def get_app(name):
raise frappe.ValidationError
frappe.publish_realtime("install_app_progress", {"status": _("Downloading App {0}").format(name)},
user=frappe.session.user, now=True)
user=frappe.session.user)
args = [find_executable('bench'), 'get-app', name, app_listing[name]['repo_url']]

View file

@ -22,6 +22,8 @@ frappe.pages.messages.on_page_load = function(parent) {
frappe.pages.messages.on_page_show = function() {
// clear title prefix
frappe.utils.set_title_prefix("");
frappe.breadcrumbs.add("Desk");
}
frappe.desk.pages.Messages = Class.extend({

View file

@ -262,9 +262,14 @@ function load_frappe_slides() {
frappe.wiz.welcome.data = r.message;
frappe.wiz.welcome.setup_fields(slide);
slide.get_field("language")
.set_input(frappe.wiz.welcome.data.default_language || "english")
.trigger("change");
var language_field = slide.get_field("language");
language_field.set_input(frappe.wiz.welcome.data.default_language || "english");
if (!frappe.wiz._from_load_messages) {
language_field.$input.trigger("change");
}
delete frappe.wiz._from_load_messages;
moment.locale("en");
}
@ -289,6 +294,7 @@ function load_frappe_slides() {
},
callback: function(r) {
// TODO save values!
frappe.wiz._from_load_messages = true;
// reset all slides so that labels are translated
frappe.wiz.slides = [];

View file

@ -1,53 +0,0 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
"""Allow adding of stars to documents"""
import frappe, json
from frappe.model.db_schema import add_column
@frappe.whitelist()
def toggle_star(doctype, name, add=False):
"""Adds / removes the current user in the `__starred_by` property of the given document.
If column does not exist, will add it in the database.
The `_starred_by` property is always set from this function and is ignored if set via
Document API
:param doctype: DocType of the document to star
:param name: Name of the document to star
:param add: `Yes` if star is to be added. If not `Yes` the star will be removed."""
_toggle_star(doctype, name, add)
def _toggle_star(doctype, name, add=False, user=None):
"""Same as toggle_star but hides param `user` from API"""
if not user:
user = frappe.session.user
try:
starred_by = frappe.db.get_value(doctype, name, "_starred_by")
if starred_by:
starred_by = json.loads(starred_by)
else:
starred_by = []
if add=="Yes":
if user not in starred_by:
starred_by.append(user)
else:
if user in starred_by:
starred_by.remove(user)
frappe.db.sql("""update `tab{0}` set `_starred_by`=%s where name=%s""".format(doctype),
(json.dumps(starred_by), name))
except Exception, e:
if e.args[0]==1054:
add_column(doctype, "_starred_by", "Text")
_toggle_star(doctype, name, add, user)
else:
raise

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

View file

@ -77,6 +77,22 @@
<p class="docs-attr-name">
<a name="frappe.core.notifications.get_unseen_likes" href="#frappe.core.notifications.get_unseen_likes" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.core.notifications.<b>get_unseen_likes</b>
<i class="text-muted">()</i>
</p>
<div class="docs-attr-desc"><p>Returns count of unseen likes</p>
</div>
<br>
<!-- autodoc -->

View file

@ -0,0 +1,96 @@
<!-- title: frappe.desk.like --><div class="dev-header">
<a class="btn btn-default btn-sm" disabled style="margin-bottom: 10px;">
Version 6.x.x</a>
<a class="btn btn-default btn-sm" href="https://github.com/frappe/frappe/blob/develop/frappe/desk/like.py"
target="_blank" style="margin-left: 10px; margin-bottom: 10px;"><i class="octicon octicon-mark-github"></i> Source</a>
</div>
<p class="docs-attr-name">
<a name="frappe.desk.like._toggle_like" href="#frappe.desk.like._toggle_like" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.desk.like.<b>_toggle_like</b>
<i class="text-muted">(doctype, name, add, user=None)</i>
</p>
<div class="docs-attr-desc"><p>Same as toggle_like but hides param <code>user</code> from API</p>
</div>
<br>
<p class="docs-attr-name">
<a name="frappe.desk.like.add_comment" href="#frappe.desk.like.add_comment" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.desk.like.<b>add_comment</b>
<i class="text-muted">(doctype, name)</i>
</p>
<div class="docs-attr-desc"><p><span class="text-muted">No docs</span></p>
</div>
<br>
<p class="docs-attr-name">
<a name="frappe.desk.like.remove_like" href="#frappe.desk.like.remove_like" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.desk.like.<b>remove_like</b>
<i class="text-muted">(doctype, name)</i>
</p>
<div class="docs-attr-desc"><p>Remove previous Like</p>
</div>
<br>
<p><span class="label label-info">Public API</span>
<br><code>/api/method/frappe.desk.like.toggle_like</code>
</p>
<p class="docs-attr-name">
<a name="frappe.desk.like.toggle_like" href="#frappe.desk.like.toggle_like" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.desk.like.<b>toggle_like</b>
<i class="text-muted">(doctype, name, add=False)</i>
</p>
<div class="docs-attr-desc"><p>Adds / removes the current user in the <code>__liked_by</code> property of the given document.
If column does not exist, will add it in the database.</p>
<p>The <code>_liked_by</code> property is always set from this function and is ignored if set via
Document API</p>
<p><strong>Parameters:</strong></p>
<ul>
<li><strong><code>doctype</code></strong> - DocType of the document to like</li>
<li><strong><code>name</code></strong> - Name of the document to like</li>
<li><strong><code>add</code></strong> - <code>Yes</code> if like is to be added. If not <code>Yes</code> the like will be removed.</li>
</ul>
</div>
<br>
<!-- autodoc -->

View file

@ -131,6 +131,22 @@
<p class="docs-attr-name">
<a name="frappe.desk.notifications.get_notifications_for" href="#frappe.desk.notifications.get_notifications_for" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.desk.notifications.<b>get_notifications_for</b>
<i class="text-muted">(notification_type, config, notification_count)</i>
</p>
<div class="docs-attr-desc"><p><span class="text-muted">No docs</span></p>
</div>
<br>
<p class="docs-attr-name">
<a name="frappe.desk.notifications.get_notifications_for_doctypes" href="#frappe.desk.notifications.get_notifications_for_doctypes" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
@ -159,6 +175,22 @@
<p class="docs-attr-name">
<a name="frappe.desk.notifications.get_notifications_for_other" href="#frappe.desk.notifications.get_notifications_for_other" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.desk.notifications.<b>get_notifications_for_other</b>
<i class="text-muted">(config, notification_count)</i>
</p>
<div class="docs-attr-desc"><p>Notifications for other items</p>
</div>
<br>
<!-- autodoc -->

View file

@ -1,64 +0,0 @@
<!-- title: frappe.desk.star --><div class="dev-header">
<a class="btn btn-default btn-sm" disabled style="margin-bottom: 10px;">
Version 6.x.x</a>
<a class="btn btn-default btn-sm" href="https://github.com/frappe/frappe/blob/develop/frappe/desk/star.py"
target="_blank" style="margin-left: 10px; margin-bottom: 10px;"><i class="octicon octicon-mark-github"></i> Source</a>
</div>
<p class="docs-attr-name">
<a name="frappe.desk.star._toggle_star" href="#frappe.desk.star._toggle_star" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.desk.star.<b>_toggle_star</b>
<i class="text-muted">(doctype, name, add=False, user=None)</i>
</p>
<div class="docs-attr-desc"><p>Same as toggle_star but hides param <code>user</code> from API</p>
</div>
<br>
<p><span class="label label-info">Public API</span>
<br><code>/api/method/frappe.desk.star.toggle_star</code>
</p>
<p class="docs-attr-name">
<a name="frappe.desk.star.toggle_star" href="#frappe.desk.star.toggle_star" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.desk.star.<b>toggle_star</b>
<i class="text-muted">(doctype, name, add=False)</i>
</p>
<div class="docs-attr-desc"><p>Adds / removes the current user in the <code>__starred_by</code> property of the given document.
If column does not exist, will add it in the database.</p>
<p>The <code>_starred_by</code> property is always set from this function and is ignored if set via
Document API</p>
<p><strong>Parameters:</strong></p>
<ul>
<li><strong><code>doctype</code></strong> - DocType of the document to star</li>
<li><strong><code>name</code></strong> - Name of the document to star</li>
<li><strong><code>add</code></strong> - <code>Yes</code> if star is to be added. If not <code>Yes</code> the star will be removed.</li>
</ul>
</div>
<br>
<!-- autodoc -->

View file

@ -1,6 +1,7 @@
frappe.desk.calendar
frappe.desk.desk_page
frappe.desk
frappe.desk.like
frappe.desk.moduleview
frappe.desk.notifications
frappe.desk.query_builder
@ -8,5 +9,4 @@ frappe.desk.query_report
frappe.desk.report_dump
frappe.desk.reportview
frappe.desk.search
frappe.desk.star
frappe.desk.tags

View file

@ -284,7 +284,7 @@
<a name="frappe.sessions.clear_sessions" href="#frappe.sessions.clear_sessions" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.sessions.<b>clear_sessions</b>
<i class="text-muted">(user=None, keep_current=False)</i>
<i class="text-muted">(user=None, keep_current=False, device=None)</i>
</p>
<div class="docs-attr-desc"><p><span class="text-muted">No docs</span></p>
</div>

View file

@ -40,6 +40,20 @@
<p class="docs-attr-name">
<a name="add_comment_count" href="#add_comment_count" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
<b>add_comment_count</b>
<i class="text-muted">(self, result)</i>
</p>
<div class="docs-attr-desc"><p><span class="text-muted">No docs</span></p>
</div>
<br>
<p class="docs-attr-name">
<a name="add_limit" href="#add_limit" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
@ -156,7 +170,7 @@
<a name="execute" href="#execute" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
<b>execute</b>
<i class="text-muted">(self, query=None, fields=None, filters=None, or_filters=None, docstatus=None, group_by=None, order_by=None, limit_start=False, limit_page_length=None, as_list=False, with_childnames=False, debug=False, ignore_permissions=False, user=None)</i>
<i class="text-muted">(self, query=None, fields=None, filters=None, or_filters=None, docstatus=None, group_by=None, order_by=None, limit_start=False, limit_page_length=None, as_list=False, with_childnames=False, debug=False, ignore_permissions=False, user=None, with_comment_count=False)</i>
</p>
<div class="docs-attr-desc"><p><span class="text-muted">No docs</span></p>
</div>

View file

@ -110,7 +110,7 @@ all values (including child documents) from the database.</p>
<a name="add_comment" href="#add_comment" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
<b>add_comment</b>
<i class="text-muted">(self, comment_type, text=None, comment_by=None)</i>
<i class="text-muted">(self, comment_type, text=None, comment_by=None, reference_doctype=None, reference_name=None)</i>
</p>
<div class="docs-attr-desc"><p>Add a comment to this document.</p>
@ -280,6 +280,20 @@ timestamps don't match.</p>
<p class="docs-attr-name">
<a name="get_liked_by" href="#get_liked_by" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
<b>get_liked_by</b>
<i class="text-muted">(self)</i>
</p>
<div class="docs-attr-desc"><p><span class="text-muted">No docs</span></p>
</div>
<br>
<p class="docs-attr-name">
<a name="get_permlevel_access" href="#get_permlevel_access" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
@ -308,20 +322,6 @@ timestamps don't match.</p>
<p class="docs-attr-name">
<a name="get_starred_by" href="#get_starred_by" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
<b>get_starred_by</b>
<i class="text-muted">(self)</i>
</p>
<div class="docs-attr-desc"><p><span class="text-muted">No docs</span></p>
</div>
<br>
<p class="docs-attr-name">
<a name="get_url" href="#get_url" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>

View file

@ -21,7 +21,7 @@
<a name="frappe.utils.bench_helper.app_group" href="#frappe.utils.bench_helper.app_group" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.utils.bench_helper.<b>app_group</b>
<i class="text-muted">(ctx, site=False, force=False, verbose=False, profile=False)</i>
<i class="text-muted">()</i>
</p>
<div class="docs-attr-desc"><p><span class="text-muted">No docs</span></p>
</div>

View file

@ -926,6 +926,22 @@ Ported from PrettyDate by John Resig</p>
<p class="docs-attr-name">
<a name="frappe.utils.data.to_markdown" href="#frappe.utils.data.to_markdown" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.utils.data.<b>to_markdown</b>
<i class="text-muted">(html)</i>
</p>
<div class="docs-attr-desc"><p><span class="text-muted">No docs</span></p>
</div>
<br>
<p class="docs-attr-name">
<a name="frappe.utils.data.to_timedelta" href="#frappe.utils.data.to_timedelta" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>

View file

@ -64,22 +64,6 @@
<p class="docs-attr-name">
<a name="frappe.website.render.build_json" href="#frappe.website.render.build_json" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.website.render.<b>build_json</b>
<i class="text-muted">(path)</i>
</p>
<div class="docs-attr-desc"><p><span class="text-muted">No docs</span></p>
</div>
<br>
<p class="docs-attr-name">
<a name="frappe.website.render.build_page" href="#frappe.website.render.build_page" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
@ -144,22 +128,6 @@
<p class="docs-attr-name">
<a name="frappe.website.render.is_ajax" href="#frappe.website.render.is_ajax" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.website.render.<b>is_ajax</b>
<i class="text-muted">()</i>
</p>
<div class="docs-attr-desc"><p><span class="text-muted">No docs</span></p>
</div>
<br>
<p class="docs-attr-name">
<a name="frappe.website.render.render" href="#frappe.website.render.render" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>

View file

@ -1,147 +0,0 @@
<!-- title: frappe.website.template --><div class="dev-header">
<a class="btn btn-default btn-sm" disabled style="margin-bottom: 10px;">
Version 6.x.x</a>
<a class="btn btn-default btn-sm" href="https://github.com/frappe/frappe/blob/develop/frappe/website/template.py"
target="_blank" style="margin-left: 10px; margin-bottom: 10px;"><i class="octicon octicon-mark-github"></i> Source</a>
</div>
<p class="docs-attr-name">
<a name="frappe.website.template.add_hero" href="#frappe.website.template.add_hero" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.website.template.<b>add_hero</b>
<i class="text-muted">(out, context)</i>
</p>
<div class="docs-attr-desc"><p>Add a hero element if specified in content or hooks.
Hero elements get full page width.</p>
</div>
<br>
<p class="docs-attr-name">
<a name="frappe.website.template.add_index" href="#frappe.website.template.add_index" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.website.template.<b>add_index</b>
<i class="text-muted">(out, context)</i>
</p>
<div class="docs-attr-desc"><p>Add index, next button if <code>{index}</code>, <code>{next}</code> is present.</p>
</div>
<br>
<p class="docs-attr-name">
<a name="frappe.website.template.build_template" href="#frappe.website.template.build_template" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.website.template.<b>build_template</b>
<i class="text-muted">(context)</i>
</p>
<div class="docs-attr-desc"><p>Returns a dict of block name and its rendered content</p>
</div>
<br>
<p class="docs-attr-name">
<a name="frappe.website.template.render_blocks" href="#frappe.website.template.render_blocks" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.website.template.<b>render_blocks</b>
<i class="text-muted">(template_path, out, context)</i>
</p>
<div class="docs-attr-desc"><p>Build the template block by block from the main template.</p>
</div>
<br>
<p class="docs-attr-name">
<a name="frappe.website.template.separate_style_and_script" href="#frappe.website.template.separate_style_and_script" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.website.template.<b>separate_style_and_script</b>
<i class="text-muted">(out, context)</i>
</p>
<div class="docs-attr-desc"><p>Extract <code>style</code> and <code>script</code> tags into separate blocks</p>
</div>
<br>
<p class="docs-attr-name">
<a name="frappe.website.template.set_breadcrumbs" href="#frappe.website.template.set_breadcrumbs" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.website.template.<b>set_breadcrumbs</b>
<i class="text-muted">(out, context)</i>
</p>
<div class="docs-attr-desc"><p>Build breadcrumbs template (deprecated)</p>
</div>
<br>
<p class="docs-attr-name">
<a name="frappe.website.template.set_sidebar" href="#frappe.website.template.set_sidebar" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.website.template.<b>set_sidebar</b>
<i class="text-muted">(out, context)</i>
</p>
<div class="docs-attr-desc"><p>Include sidebar (deprecated)</p>
</div>
<br>
<p class="docs-attr-name">
<a name="frappe.website.template.set_title_and_header" href="#frappe.website.template.set_title_and_header" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
frappe.website.template.<b>set_title_and_header</b>
<i class="text-muted">(out, context)</i>
</p>
<div class="docs-attr-desc"><p>Extract and set title and header from content or context.</p>
</div>
<br>
<!-- autodoc -->

View file

@ -3,6 +3,5 @@ frappe.website
frappe.website.render
frappe.website.router
frappe.website.statics
frappe.website.template
frappe.website.utils
frappe.website.website_generator

View file

@ -35,7 +35,7 @@
Version
</td>
<td>
<code>6.16.3</code>
<code>6.17.3</code>
</td>
</tr>
</table>

View file

@ -73,7 +73,8 @@ Comment
Workflow
Label
Attachment
Attachment Removed</pre>
Attachment Removed
Like</pre>
</td>
</tr>

View file

@ -571,20 +571,6 @@ Recipient Unsubscribed</pre>
<p class="docs-attr-name">
<a name="get_starrers" href="#get_starrers" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
<b>get_starrers</b>
<i class="text-muted">(self)</i>
</p>
<div class="docs-attr-desc"><p>Return list of users who have starred this document.</p>
</div>
<br>
<p class="docs-attr-name">
<a name="notify" href="#notify" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>

View file

@ -1068,9 +1068,9 @@ Website User</pre>
<p class="docs-attr-name">
<a name="send_password_notifcation" href="#send_password_notifcation" class="text-muted small">
<a name="send_password_notification" href="#send_password_notification" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
<b>send_password_notifcation</b>
<b>send_password_notification</b>
<i class="text-muted">(self, new_password)</i>
</p>
<div class="docs-attr-desc"><p><span class="text-muted">No docs</span></p>

View file

@ -52,7 +52,8 @@
Comment
Login
Label
Info</pre>
Info
Like</pre>
</td>
</tr>
@ -116,6 +117,55 @@ Info</pre>
<td></td>
</tr>
<tr >
<td>7</td>
<td ><code>doc_owner</code></td>
<td >
Data</td>
<td >
Doc Owner
</td>
<td></td>
</tr>
<tr >
<td>8</td>
<td ><code>seen</code></td>
<td >
Check</td>
<td >
Seen
</td>
<td></td>
</tr>
<tr >
<td>9</td>
<td ><code>reference_doctype</code></td>
<td >
Data</td>
<td >
Reference DocType
<p class="text-muted small">
Use this to provide alternative link to a feed record</p>
</td>
<td></td>
</tr>
<tr >
<td>10</td>
<td ><code>reference_name</code></td>
<td >
Data</td>
<td >
Reference Name
</td>
<td></td>
</tr>
</tbody>
</table>
@ -138,6 +188,20 @@ Info</pre>
</div>
<div style="padding-left: 30px;">
<p class="docs-attr-name">
<a name="validate" href="#validate" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
<b>validate</b>
<i class="text-muted">(self)</i>
</p>
<div class="docs-attr-desc"><p><span class="text-muted">No docs</span></p>
</div>
<br>
</div>
<hr>

View file

@ -423,6 +423,35 @@ Right</pre>
<p class="docs-attr-name">
<a name="add_hero" href="#add_hero" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
<b>add_hero</b>
<i class="text-muted">(self, context)</i>
</p>
<div class="docs-attr-desc"><p>Add a hero element if specified in content or hooks.
Hero elements get full page width.</p>
</div>
<br>
<p class="docs-attr-name">
<a name="add_index" href="#add_index" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
<b>add_index</b>
<i class="text-muted">(self, context)</i>
</p>
<div class="docs-attr-desc"><p>Add index, next button if <code>{index}</code>, <code>{next}</code> is present.</p>
</div>
<br>
<p class="docs-attr-name">
<a name="check_for_redirect" href="#check_for_redirect" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
@ -507,6 +536,20 @@ Right</pre>
<p class="docs-attr-name">
<a name="set_breadcrumbs" href="#set_breadcrumbs" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
<b>set_breadcrumbs</b>
<i class="text-muted">(self, context)</i>
</p>
<div class="docs-attr-desc"><p>Build breadcrumbs template (deprecated)</p>
</div>
<br>
<p class="docs-attr-name">
<a name="set_metatags" href="#set_metatags" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
@ -521,6 +564,20 @@ Right</pre>
<p class="docs-attr-name">
<a name="set_title_and_header" href="#set_title_and_header" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>
<b>set_title_and_header</b>
<i class="text-muted">(self, context)</i>
</p>
<div class="docs-attr-desc"><p>Extract and set title and header from content or context.</p>
</div>
<br>
<p class="docs-attr-name">
<a name="validate" href="#validate" class="text-muted small">
<i class="icon-link small" style="color: #ccc;"></i></a>

View file

@ -1,20 +1,15 @@
Let's say, there is a custom field "VAT Number" in Supplier master, which should be fetched in Purchase Order document.
<br>
<br>Steps:
<br>1. Create a Custom Field <b>"VAT Number"</b> for <b>Supplier</b> document with <b>Field Type</b> as <b>Data</b>.
<br>&nbsp;&nbsp;
<img src="/files/supplier_vat_number.png" height="202" width="607"><br>2. Create another Custom Field <b>"VAT Number"</b> for Purchase Order document. But in this case, enter <b>Field Type</b> as <b>Read Only</b> and <b>Options</b> as <b>supplier.vat_number</b>.
<br>&nbsp; <img src="/files/po_vat_number.png" height="264" width="611"><br>3. Refresh the system using <b>Help -&gt; Clear Cache</b>.
<br>4. Now on selection of Supplier in new Purchase Order form, "VAT Number" will be fetched automatically from Supplier master.
<br>5. The above procedure should be replicated, for all other supplier related transactions.
<br>
<br>Note:
<br>
<blockquote>If field type of "VAT Number" in Purchase Order is other than `Read Only`, then to fetch the value, a small piece of Custom Script need to be written.
<br>i. Go to Setup -&gt; Customize -&gt; Custom Script.
<br>ii. Select DocType as `Purchase Order`.
<br>iii. Add Script `cur_frm.add_fetch('supplier', 'vat_number', 'vat_number')`
<br>iv. Save the Custom Script.
<br>v. Clear cache before testing.
<br>
</blockquote>
# Fetch a Field Value from a Document into a Transaction
Let's say, there is a custom field "VAT Number" in Supplier, which should be fetched in Purchase Order.
#### Steps:
1. Create a Custom Field **VAT Number** for *Supplier* document with *Field Type* as **Data**.
<img class="screenshot" src="{{ docs_base_url }}/assets/img/add-vat-number-in-supplier.png">
1. Create another Custom Field **VAT Number** for *Purchase Order* document, but in this case with *Field Type* as **Read Only** or check **Read Only** checkbox. Set the **Options** as `supplier.vat_number`.
<img class="screenshot" src="{{ docs_base_url }}/assets/img/add-vat-number-in-purchase-order.png">
1. Go to the user menu and click "Reload".
1. Now, on selection of Supplier in a new Purchase Order, **VAT Number** will be fetched automatically from the selected Supplier.
<img class="screenshot" src="{{ docs_base_url }}/assets/img/vat-number-fetched.png">

View file

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils.pdf import get_pdf
from frappe.email.smtp import get_outgoing_email_account
from frappe.utils import get_url, scrub_urls, strip, expand_relative_urls, cint, split_emails
from frappe.utils import get_url, scrub_urls, strip, expand_relative_urls, cint, split_emails, to_markdown
import email.utils
from markdown2 import markdown
@ -89,12 +89,7 @@ class EMail:
def set_html_as_text(self, html):
"""return html2text"""
import HTMLParser
from html2text import html2text
try:
self.set_text(html2text(html))
except HTMLParser.HTMLParseError:
pass
self.set_text(to_markdown(html))
def set_message(self, message, mime_type='text/html', as_attachment=0, filename='attachment.html'):
"""Append the message with MIME content to the root node (as attachment)"""

View file

@ -5,7 +5,7 @@ app_publisher = "Frappe Technologies Pvt. Ltd."
app_description = "Full stack web framework with Python, Javascript, MariaDB, Redis, Node"
app_icon = "octicon octicon-circuit-board"
app_version = "6.16.4"
app_version = "6.17.6"
app_color = "orange"
source_link = "https://github.com/frappe/frappe"
app_license = "MIT"
@ -45,12 +45,6 @@ website_route_rules = [
{"from_route": "/blog/<category>", "to_route": "Blog Post"}
]
website_context = {
"hero": {
"blog": "templates/includes/blog/hero.html"
}
}
write_file_keys = ["file_url", "file_name"]
notification_config = "frappe.core.notifications.get_notification_config"

View file

@ -14,7 +14,7 @@ default_fields = ('doctype','name','owner','creation','modified','modified_by',
integer_docfield_properties = ("reqd", "search_index", "in_list_view", "permlevel",
"hidden", "read_only", "ignore_user_permissions", "allow_on_submit", "report_hide",
"in_filter", "no_copy", "print_hide", "unique")
optional_fields = ("_user_tags", "_comments", "_assign", "_starred_by")
optional_fields = ("_user_tags", "_comments", "_assign", "_liked_by")
def rename(doctype, old, new, debug=False):
import frappe.model.rename_doc

View file

@ -239,7 +239,7 @@ class BaseDocument(object):
if k in default_fields:
del doc[k]
for key in ("_user_tags", "__islocal", "__onload", "_starred_by", "__run_link_triggers"):
for key in ("_user_tags", "__islocal", "__onload", "_liked_by", "__run_link_triggers"):
if self.get(key):
doc[key] = self.get(key)
@ -372,6 +372,12 @@ class BaseDocument(object):
if self.get(df.fieldname) in (None, []) or not strip_html(cstr(self.get(df.fieldname))).strip():
missing.append((df.fieldname, get_msg(df)))
# check for missing parent and parenttype
if self.meta.istable:
for fieldname in ("parent", "parenttype"):
if not self.get(fieldname):
missing.append((fieldname, get_msg(frappe._dict(label=fieldname))))
return missing
def get_invalid_links(self, is_submittable=False):

View file

@ -25,7 +25,7 @@ class DatabaseQuery(object):
def execute(self, query=None, fields=None, filters=None, or_filters=None,
docstatus=None, group_by=None, order_by=None, limit_start=False,
limit_page_length=None, as_list=False, with_childnames=False, debug=False,
ignore_permissions=False, user=None):
ignore_permissions=False, user=None, with_comment_count=False):
if not ignore_permissions and not frappe.has_permission(self.doctype, "read", user=user):
raise frappe.PermissionError, self.doctype
@ -45,9 +45,14 @@ class DatabaseQuery(object):
self.user = user or frappe.session.user
if query:
return self.run_custom_query(query)
result = self.run_custom_query(query)
else:
return self.build_and_run()
result = self.build_and_run()
if with_comment_count and not as_list and self.doctype:
self.add_comment_count(result)
return result
def build_and_run(self):
args = self.prepare_args()
@ -444,3 +449,21 @@ class DatabaseQuery(object):
return 'limit %s, %s' % (self.limit_start, self.limit_page_length)
else:
return ''
def add_comment_count(self, result):
for r in result:
if not r.name:
continue
if "_comments" in r:
comment_count = len(json.loads(r._comments or "[]"))
else:
comment_count = cint(frappe.db.get_value("Comment",
filters={"comment_doctype": self.doctype, "comment_docname": r.name, "comment_type": "Comment"},
fieldname="count(name)"))
communication_count = cint(frappe.db.get_value("Communication",
filters={"reference_doctype": self.doctype, "reference_name": r.name},
fieldname="count(name)"))
r._comment_count = comment_count + communication_count

View file

@ -649,11 +649,11 @@ class Document(BaseDocument):
def notify_update(self):
"""Publish realtime that the current document is modified"""
frappe.publish_realtime("doc_update", {"modified": self.modified, "doctype": self.doctype, "name": self.name},
doctype=self.doctype, docname=self.name)
doctype=self.doctype, docname=self.name, after_commit=True)
if not self.meta.get("read_only") and not self.meta.get("issingle") and \
not self.meta.get("istable"):
frappe.publish_realtime("list_update", {"doctype": self.doctype})
frappe.publish_realtime("list_update", {"doctype": self.doctype}, after_commit=True)
def check_no_back_links_exist(self):
@ -764,7 +764,7 @@ class Document(BaseDocument):
"""Returns Desk URL for this document. `/desk#Form/{doctype}/{name}`"""
return "/desk#Form/{doctype}/{name}".format(doctype=self.doctype, name=self.name)
def add_comment(self, comment_type, text=None, comment_by=None):
def add_comment(self, comment_type, text=None, comment_by=None, reference_doctype=None, reference_name=None):
"""Add a comment to this document.
:param comment_type: e.g. `Comment`. See Comment for more info."""
@ -774,7 +774,9 @@ class Document(BaseDocument):
"comment_type": comment_type,
"comment_doctype": self.doctype,
"comment_docname": self.name,
"comment": text or _(comment_type)
"comment": text or _(comment_type),
"reference_doctype": reference_doctype,
"reference_name": reference_name
}).insert(ignore_permissions=True)
return comment
@ -782,10 +784,10 @@ class Document(BaseDocument):
"""Returns signature (hash) for private URL."""
return hashlib.sha224(get_datetime_str(self.creation)).hexdigest()
def get_starred_by(self):
starred_by = getattr(self, "_starred_by", None)
if starred_by:
return json.loads(starred_by)
def get_liked_by(self):
liked_by = getattr(self, "_liked_by", None)
if liked_by:
return json.loads(liked_by)
else:
return []

View file

@ -119,7 +119,7 @@ def update_property_setters(doctype, old_fieldname, new_fieldname):
where doc_type=%s and field_name=%s""", (new_fieldname, doctype, old_fieldname))
idx_property = frappe.db.sql("""select name, value from `tabProperty Setter`
where doc_type=%s and property = '_idx' and value like '%%%s%%'""",
where doc_type='%s' and property = '_idx' and value like '%%%s%%'""" %
(doctype, old_fieldname), as_dict=1)
if idx_property:

View file

@ -75,6 +75,7 @@ execute:frappe.db.sql("""update tabComment set comment = substr(comment, 6, loca
frappe.patches.v5_0.fix_feed
frappe.patches.v5_0.update_shared
execute:frappe.reload_doc("core", "doctype", "docshare") #2015-07-21
frappe.patches.v6_16.star_to_like
frappe.patches.v5_0.bookmarks_to_stars
frappe.patches.v5_0.style_settings_to_website_theme
frappe.patches.v5_0.rename_ref_type_fieldnames
@ -112,3 +113,5 @@ execute:frappe.create_folder(os.path.join(frappe.local.site_path, 'private', 'fi
frappe.patches.v6_15.remove_property_setter_for_previous_field #2015-12-29
frappe.patches.v6_15.set_username
execute:frappe.permissions.reset_perms("Error Snapshot")
frappe.patches.v6_16.feed_doc_owner

View file

@ -2,7 +2,7 @@ from __future__ import unicode_literals
import json
import frappe
import frappe.defaults
from frappe.desk.star import _toggle_star
from frappe.desk.like import _toggle_like
def execute():
for user in frappe.get_all("User"):
@ -29,4 +29,4 @@ def execute():
or int(frappe.db.get_value("DocType", doctype, "issingle") or 0)
or not frappe.db.table_exists(doctype)):
continue
_toggle_star(doctype, docname, add="Yes", user=username)
_toggle_like(doctype, docname, add="Yes", user=username)

View file

View file

@ -0,0 +1,32 @@
from __future__ import unicode_literals
import frappe
def execute():
frappe.reload_doctype("Feed")
frappe.db.sql("update `tabFeed` set seen=1")
for doctype, name in frappe.db.sql("""select distinct doc_type, doc_name from `tabFeed`
where
(doc_type is not null and doc_type != '')
and (doc_name is not null and doc_name != '')
and doc_type != 'Feed'
for update"""):
owner = frappe.db.get_value(doctype, name, "owner")
if not owner:
continue
frappe.db.sql("""update `tabFeed`
set doc_owner=%(owner)s
where
doc_type=%(doctype)s
and doc_name=%(name)s
and (doc_owner is null or doc_owner = '')""".format(doctype=doctype), {
"doctype": doctype,
"name": name,
"owner": owner
})
frappe.db.commit()

View file

@ -0,0 +1,18 @@
from __future__ import unicode_literals
import frappe
from frappe.model.db_schema import add_column
def execute():
frappe.reload_doctype("Feed")
frappe.db.sql("""update `tabSingles` set field='_liked_by' where field='_starred_by'""")
frappe.db.commit()
for table in frappe.db.get_tables():
columns = [r[0] for r in frappe.db.sql("DESC `{0}`".format(table))]
if "_starred_by" in columns:
frappe.db.sql_ddl("""alter table `{0}` change `_starred_by` `_liked_by` Text """.format(table))
for doctype in ("Comment", "Communication"):
if not frappe.db.has_column(doctype, "_liked_by"):
add_column(doctype, "_liked_by", "Text")

View file

@ -2,20 +2,19 @@
"css/frappe-web.css": [
"public/css/font-awesome.css",
"public/css/octicons/octicons.css",
"public/css/nprogress.css",
"public/css/website.css"
],
"js/frappe-web.min.js": [
"public/js/lib/bootstrap.min.js",
"public/js/frappe/provide.js",
"public/js/frappe/misc/number_format.js",
"public/js/lib/nprogress.js",
"public/js/frappe/translate.js",
"public/js/frappe/misc/pretty_date.js",
"public/js/lib/moment/moment.min.js",
"public/js/lib/highlight.pack.js",
"public/js/frappe/class.js",
"public/js/lib/microtemplate.js",
"public/js/frappe/query_string.js",
"website/js/website.js",
"public/js/lib/socket.io.min.js"
],
@ -25,6 +24,16 @@
"public/js/frappe/ui/editor.html",
"public/js/frappe/ui/editor.js"
],
"js/dialog.min.js": [
"public/js/frappe/dom.js",
"public/js/frappe/ui/modal.html",
"public/js/frappe/form/formatters.js",
"public/js/frappe/form/layout.js",
"public/js/frappe/ui/field_group.js",
"public/js/frappe/form/control.js",
"public/js/frappe/form/link_selector.js",
"public/js/frappe/ui/dialog.js"
],
"css/desk.min.css": [
"public/js/lib/jquery/bootstrap_theme/jquery-ui.selected.css",
"public/css/bootstrap.css",
@ -38,7 +47,6 @@
"public/css/sidebar.css",
"public/css/page.css",
"public/css/tree.css",
"public/css/nprogress.css",
"public/css/desktop.css",
"public/css/form.css",
"public/css/mobile.css"
@ -49,7 +57,6 @@
"public/js/lib/tag-it.min.js",
"public/js/lib/notify.js",
"public/js/lib/bootstrap.min.js",
"public/js/lib/nprogress.js",
"public/js/lib/moment/moment-with-locales.min.js",
"public/js/lib/moment/moment-timezone-with-data.min.js",
"public/js/lib/socket.io.min.js",
@ -84,7 +91,6 @@
"public/js/frappe/form/control.js",
"public/js/frappe/form/link_selector.js",
"public/js/frappe/ui/dialog.js",
"public/js/frappe/ui/button.js",
"public/js/frappe/ui/app_icon.js",
"public/js/frappe/model/model.js",
@ -121,6 +127,7 @@
"public/js/frappe/change_log.html",
"public/js/frappe/desk.js",
"public/js/frappe/query_string.js",
"public/html/error_object.html",
"public/html/error_snapshot.html"
@ -180,7 +187,8 @@
"public/js/frappe/ui/filters/filters.js",
"public/js/frappe/ui/filters/edit_filter.html",
"public/js/frappe/ui/tags.js",
"public/js/frappe/ui/star.js",
"public/js/frappe/ui/like.js",
"public/js/frappe/ui/liked_by.html",
"public/html/print_template.html",
"public/js/frappe/list/doclistview.js",
"public/js/frappe/list/list_sidebar.js",

View file

@ -43,3 +43,12 @@
height: 0;
padding-bottom: 100%;
}
.avatar-frame {
width: 100%;
height: 0;
padding: 50% 0px;
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
border-radius: 4px;
}

View file

@ -108,6 +108,7 @@ a.badge-hover:active .badge {
background-color: #D8DFE5;
}
.msgprint {
margin: 15px 0px;
text-align: center;
}
.msgprint pre {

View file

@ -108,6 +108,7 @@ a.badge-hover:active .badge {
background-color: #D8DFE5;
}
.msgprint {
margin: 15px 0px;
text-align: center;
}
.msgprint pre {
@ -546,3 +547,11 @@ ul.linked-with-list li {
border-bottom: 1px solid #d1d8dd;
border-radius: 0px;
}
.liked-by-popover {
min-width: 200px;
margin-top: -10px;
margin-bottom: -10px;
}
.liked-by-popover li {
margin: 15px 0px;
}

View file

@ -61,8 +61,7 @@
.empty-section {
display: none !important;
}
.shaded-section,
.timeline-item:nth-child(even) {
.shaded-section {
background-color: #fafbfc;
}
.modal .form-layout {
@ -87,37 +86,165 @@
background-color: #e74c3c;
}
.timeline {
border: 1px solid #d1d8dd;
margin: 30px 0px;
}
.timeline .timeline-head .comment-input {
height: auto;
}
.timeline-item {
margin-top: 0px;
padding: 15px 30px 7px;
border-bottom: 1px solid #d1d8dd;
}
.timeline-item .icon-fixed-width {
text-align: center;
}
.timeline-item blockquote {
font-size: inherit;
}
.timeline-item:last-child {
border-bottom: 0px;
.timeline-items {
position: relative;
}
.timeline-item .reply {
margin-top: 5px;
.timeline {
position: relative;
}
.timeline::before {
content: " ";
border-left: 1px solid #d1d8dd;
position: absolute;
top: 0px;
bottom: -124px;
left: 43px;
z-index: -1;
}
@media (max-width: 991px) {
.timeline::before {
bottom: -64px;
}
}
.timeline-item.user-content {
margin: 30px 0px 30px 30px;
}
.timeline-item.user-content .media-body {
border: 1px solid #d1d8dd;
border-radius: 2px;
margin-left: -7px;
position: relative;
overflow: visible;
}
.timeline-item.user-content .comment-header {
background-color: #fafbfc;
padding: 7px 15px;
margin: 0px;
color: #8D99A6;
border-bottom: 1px solid #EBEFF2;
}
.timeline-item.user-content .comment-header .octicon-heart {
color: #ff5858;
cursor: pointer;
}
.timeline-item.user-content .reply {
padding: 10px 15px;
}
.timeline-item.user-content .reply > div > p:first-child {
margin-top: 0px;
}
.timeline-item.user-content .reply > div > p:last-child {
margin-bottom: 0px;
}
.timeline-item.user-content .close-btn-container {
padding: 2px 15px;
}
.timeline-item.user-content .comment-likes {
margin-left: 5px;
}
.timeline-item.user-content .media-body:after,
.timeline-item.user-content .media-body:before {
right: 100%;
top: 15px;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.timeline-item.user-content .media-body:after {
border-color: rgba(136, 183, 213, 0);
border-right-color: #fafbfc;
border-width: 6px;
margin-top: -6px;
}
.timeline-item.user-content .media-body:before {
border-color: rgba(194, 225, 245, 0);
border-right-color: #d1d8dd;
border-width: 7px;
margin-top: -7px;
}
.timeline-item.notification-content {
padding-left: 30px;
margin: 30px 0px;
position: relative;
color: #8D99A6;
}
.timeline-item.notification-content * {
color: #8D99A6;
}
.timeline-item.notification-content .icon-fixed-width {
margin-left: 36px;
}
.timeline-item.notification-content .octicon-heart {
color: #ff5858 !important;
}
.timeline-item.notification-content::before {
content: " ";
width: 7px;
height: 7px;
background-color: #d1d8dd;
position: absolute;
left: 40px;
border-radius: 50%;
top: 5px;
}
.timeline-item .reply-link {
padding: 0px 7px;
}
.timeline-item h6,
.timeline-head h6 {
margin-top: 6px;
padding-left: 7px;
}
.timeline-head {
background-color: white;
border: 1px solid #d1d8dd;
border-radius: 2px;
}
.timeline-head .comment-input-header {
background-color: #fafbfc;
padding: 15px 30px;
border-bottom: 1px solid #d1d8dd;
padding: 7px 15px;
border-bottom: 1px solid #EBEFF2;
}
.timeline-head .comment-input-container {
padding: 15px;
}
.timeline-head .comment-input {
border-color: #EBEFF2;
max-width: 100%;
}
.timeline-head .comment-input:focus {
box-shadow: none;
}
@media (max-width: 767px) {
.timeline-head {
border-left: none;
border-right: none;
border-radius: 0px;
}
}
.timeline-new-email {
margin: 30px 0px;
padding: 0px 65px;
position: relative;
}
.timeline-new-email::before {
content: " ";
width: 7px;
height: 7px;
background-color: #d1d8dd;
position: absolute;
left: 40px;
border-radius: 50%;
top: 5px;
}
.form-footer h5 {
margin: 15px 0px;

View file

@ -48,3 +48,11 @@
.indicator-right.darkgrey::after {
background: #b8c2cc;
}
.indicator.yellow::before,
.indicator-right.yellow::after {
background: #FEEF72;
}
.indicator.light-blue::before,
.indicator-right.light-blue::after {
background: #7CD6FD;
}

View file

@ -98,6 +98,13 @@
.doclist-row {
font-size: 12px;
}
.doclist-row .likes-count {
display: inline-block;
width: 15px;
margin-left: -5px;
color: #8D99A6;
font-size: 12px;
}
.doclist-row .docstatus .octicon {
font-size: 12px;
}
@ -134,14 +141,14 @@
margin: 0px -15px;
padding: 5px 15px;
}
.listview-main-section .icon-star {
.listview-main-section .octicon-heart {
cursor: pointer;
}
.list-row-head .icon-star {
vertical-align: middle;
.list-row-head .octicon-heart {
margin-right: 13px;
}
.star-action.icon-star {
color: #ffdb4c;
.like-action.octicon-heart {
color: #ff5858;
}
.list-id {
font-weight: bold;
@ -163,3 +170,8 @@
display: none;
}
}
.list-comment-count {
display: inline-block;
width: 37px;
text-align: left;
}

View file

@ -330,20 +330,6 @@ body {
border-left-color: transparent !important;
border-right-color: transparent !important;
}
.timeline {
border-left: none !important;
border-right: none !important;
}
.timeline .timeline-head {
padding: 7px 15px;
}
.timeline .timeline-item {
padding: 15px;
border-bottom: 1px dashed #d1d8dd;
}
.timeline .timeline-item:last-child {
border-bottom: none;
}
.list-row {
padding: 13px 15px !important;
}

View file

@ -32,11 +32,13 @@
min-width: 24px;
height: 24px;
border-radius: 4px;
background-color: #ff5858;
color: #fff;
text-align: center;
padding: 2px 5px;
}
.navbar-new-comments-true {
background-color: #ff5858;
}
#navbar-search {
width: 300px;
background-color: rgba(255, 255, 255, 0.9);

View file

@ -1,85 +0,0 @@
/* Make clicks pass-through */
#nprogress {
pointer-events: none;
-webkit-pointer-events: none;
}
/* Make the entire page show a busy cursor */
.nprogress-busy body {
cursor: wait;
}
#nprogress .bar {
background: #36414C;
position: fixed;
z-index: 1050;
top: 0;
left: 0;
width: 100%;
height: 2px;
}
/* Fancy blur effect */
#nprogress .peg {
display: block;
position: absolute;
right: 0px;
width: 100px;
height: 100%;
/*box-shadow: 0 0 10px #2ecc71, 0 0 5px #2ecc71;*/
opacity: 1.0;
-webkit-transform: rotate(3deg) translate(0px, -4px);
-moz-transform: rotate(3deg) translate(0px, -4px);
-ms-transform: rotate(3deg) translate(0px, -4px);
-o-transform: rotate(3deg) translate(0px, -4px);
transform: rotate(3deg) translate(0px, -4px);
}
/* Remove these to get rid of the spinner
#nprogress .spinner {
display: block;
position: fixed;
z-index: 1050;
top: 7px;
right: 15px;
}
#nprogress .spinner-icon {
width: 14px;
height: 14px;
border: solid 2px transparent;
border-top-color: #fff;
border-left-color: #fff;
border-radius: 10px;
-webkit-animation: nprogress-spinner 400ms linear infinite;
-moz-animation: nprogress-spinner 400ms linear infinite;
-ms-animation: nprogress-spinner 400ms linear infinite;
-o-animation: nprogress-spinner 400ms linear infinite;
animation: nprogress-spinner 400ms linear infinite;
}
@-webkit-keyframes nprogress-spinner {
0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); }
}
@-moz-keyframes nprogress-spinner {
0% { -moz-transform: rotate(0deg); transform: rotate(0deg); }
100% { -moz-transform: rotate(360deg); transform: rotate(360deg); }
}
@-o-keyframes nprogress-spinner {
0% { -o-transform: rotate(0deg); transform: rotate(0deg); }
100% { -o-transform: rotate(360deg); transform: rotate(360deg); }
}
@-ms-keyframes nprogress-spinner {
0% { -ms-transform: rotate(0deg); transform: rotate(0deg); }
100% { -ms-transform: rotate(360deg); transform: rotate(360deg); }
}
@keyframes nprogress-spinner {
0% { transform: rotate(0deg); transform: rotate(0deg); }
100% { transform: rotate(360deg); transform: rotate(360deg); }
}*/

View file

@ -161,6 +161,10 @@ body[data-route^="Module"] .main-menu .form-sidebar {
.form-sidebar .form-viewers .shared-with-everyone .octicon {
color: #36414C !important;
}
.form-sidebar .liked-by .octicon-heart {
font-size: 16px;
cursor: pointer;
}
.form-sidebar .form-shared .share-doc-btn:hover,
.form-sidebar .form-shared .share-doc-btn:focus,
.form-sidebar .form-shared .share-doc-btn:active {
@ -174,6 +178,7 @@ body[data-route^="Module"] .main-menu .form-sidebar {
.sidebar-left .form-sidebar .form-tags,
.sidebar-left .form-sidebar .assignment-row,
.sidebar-left .form-sidebar .form-shared,
.sidebar-left .form-sidebar .liked-by,
.sidebar-left .form-sidebar .modified-by,
.sidebar-left .form-sidebar .created-by,
.sidebar-left .form-sidebar .tags-label,

View file

@ -108,6 +108,7 @@ a.badge-hover:active .badge {
background-color: #D8DFE5;
}
.msgprint {
margin: 15px 0px;
text-align: center;
}
.msgprint pre {
@ -264,6 +265,15 @@ a.no-decoration:active {
height: 0;
padding-bottom: 100%;
}
.avatar-frame {
width: 100%;
height: 0;
padding: 50% 0px;
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
border-radius: 4px;
}
.indicator,
.indicator-right {
background: none;
@ -314,6 +324,14 @@ a.no-decoration:active {
.indicator-right.darkgrey::after {
background: #b8c2cc;
}
.indicator.yellow::before,
.indicator-right.yellow::after {
background: #FEEF72;
}
.indicator.light-blue::before,
.indicator-right.light-blue::after {
background: #7CD6FD;
}
.navbar-brand {
max-width: none;
}

View file

@ -5,7 +5,7 @@ frappe.defaults = {
get_user_default: function(key) {
var defaults = frappe.boot.user.defaults;
var d = defaults[key];
if(!d && (key !== frappe.model.scrub(key)))
if(!d && frappe.defaults.is_a_user_permission_key(key))
d = defaults[frappe.model.scrub(key)];
if($.isArray(d)) d = d[0];
return d;
@ -13,8 +13,8 @@ frappe.defaults = {
get_user_defaults: function(key) {
var defaults = frappe.boot.user.defaults;
var d = defaults[key];
if (key !== frappe.model.scrub(key)) {
if (frappe.defaults.is_a_user_permission_key(key)) {
if (d && $.isArray(d) && d.length===1) {
// Use User Permission value when only when it has a single value
d = d[0];
@ -52,14 +52,14 @@ frappe.defaults = {
get_default: function(key) {
var defaults = frappe.boot.user.defaults;
var value = defaults[key];
if (key !== frappe.model.scrub(key)) {
if (frappe.defaults.is_a_user_permission_key(key)) {
if (value && $.isArray(value) && value.length===1) {
value = value[0];
} else {
value = defaults[frappe.model.scrub(key)];
}
}
if(value) {
try {
return JSON.parse(value)
@ -68,6 +68,11 @@ frappe.defaults = {
}
}
},
is_a_user_permission_key: function(key) {
return key.indexOf(":")===-1 && key !== frappe.model.scrub(key);
},
get_user_permissions: function() {
return frappe.defaults.user_permissions;
},

View file

@ -70,6 +70,14 @@ frappe.Application = Class.extend({
frappe.csrf_token = data.csrf_token;
}
});
frappe.realtime.on("version-update", function() {
var dialog = frappe.msgprint(__("The application has been updated to a new version, please refresh this page"));
dialog.set_primary_action("Refresh", function() {
location.reload(true);
});
dialog.get_close_btn().toggle(false);
});
},
load_bootinfo: function() {
@ -80,7 +88,7 @@ frappe.Application = Class.extend({
this.check_metadata_cache_status();
this.set_globals();
this.sync_pages();
moment.locale(frappe.boot.lang);
moment.locale("en");
moment.user_utc_offset = moment().utcOffset();
if(frappe.boot.timezone_info) {
moment.tz.add(frappe.boot.timezone_info);

View file

@ -24,6 +24,18 @@ frappe.dom = {
// execute the script globally
document.getElementsByTagName('head')[0].appendChild(el);
},
remove_script_and_style: function(txt) {
var div = document.createElement('div');
div.innerHTML = txt;
["script", "style", "noscript", "title", "meta", "base", "head"].forEach(function(e, i) {
var elements = div.getElementsByTagName(e);
var i = elements.length;
while (i--) {
elements[i].parentNode.removeChild(elements[i]);
}
});
return div.innerHTML;
},
set_style: function(txt, id) {
if(!txt) return;

View file

@ -102,9 +102,11 @@ frappe.ui.form.Control = Class.extend({
undefined;
},
set_model_value: function(value) {
if(frappe.model.set_value(this.doctype, this.docname, this.df.fieldname,
value, this.df.fieldtype)) {
this.last_value = value;
if(this.doctype) {
if(frappe.model.set_value(this.doctype, this.docname, this.df.fieldname,
value, this.df.fieldtype)) {
this.last_value = value;
}
}
},
});
@ -1153,10 +1155,6 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
select: function(event, ui) {
me.autocomplete_open = false;
if(ui.item.action) {
ui.item.action.apply(me);
}
// prevent selection on tab
var TABKEY = 9;
if(event.keyCode === TABKEY) {
@ -1165,6 +1163,11 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
return false;
}
if(ui.item.action) {
ui.item.value = "";
ui.item.action.apply(me);
}
if(me.frm && me.frm.doc) {
me.selected = true;
me.parse_validate_and_set_in_model(ui.item.value);
@ -1383,7 +1386,7 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({
},
_set_input: function(value) {
if(value == null) value = "";
value = frappe.utils.remove_script_and_style(value);
value = frappe.dom.remove_script_and_style(value);
this.editor.set_input(value);
this.md_editor.val(value);
this.last_value = value;

View file

@ -1,37 +1,21 @@
<div class="timeline">
<div class="timeline-head">
<h6 class="text-muted">{%= __("Add a comment") %}</h6>
<div>
<textarea style="height: 80px" style="margin-top: 10px;"
class="form-control"></textarea>
<div class="comment-input-header">
<span class="small text-muted">{%= __("Add a comment") %}</span>
<button class="btn btn-default btn-comment btn-xs pull-right">
{%= __("Comment") %}
</button>
</div>
<div class="comment-input-container">
<textarea class="form-control comment-input"></textarea>
<input type="data" class="hidden mention-input">
</div>
<div class="media">
<span class="pull-left avatar avatar-medium">
<img class="media-object" src="{%= image %}">
</span>
<div class="media-body">
<div class="row">
<div class="col-xs-4">
<h6>{%= __("You") %}</h6>
</div>
<div class="col-xs-8 text-right" style="margin-top: 2px;">
<button class="btn btn-primary btn-go btn-xs pull-right">
{%= __("Comment") %}
</button>
<div class="checkbox text-muted small pull-right"
style="margin-top: 3px; margin-right: 15px;">
<label>
<input type="checkbox" class="is-email" style="margin-top: 1px;">
{%= __("Email") %}
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="timeline-new-email">
<button class="btn btn-default btn-new-email btn-xs">
{%= __("New Email") %}
</button>
</div>
<div class="timeline-items">
</div>

View file

@ -14,33 +14,31 @@ frappe.ui.form.Comments = Class.extend({
this.list = this.wrapper.find(".timeline-items");
this.input = this.wrapper.find(".form-control");
this.button = this.wrapper.find(".btn-go")
this.comment_button = this.wrapper.find(".btn-comment")
.on("click", function() {
if(me.wrapper.find(".is-email").prop("checked")) {
new frappe.views.CommunicationComposer({
doc: me.frm.doc,
txt: frappe.markdown(me.input.val()),
frm: me.frm,
recipients: me.get_recipient()
})
} else {
me.add_comment(this);
}
me.add_comment(this);
});
this.input.keydown("meta+return ctrl+return", function(e) {
me.button.trigger("click");
me.comment_button.trigger("click");
});
this.email_check = this.wrapper.find(".timeline-head input[type='checkbox']")
.on("change", function() {
me.button.html($(this).prop("checked") ? __("Compose") : __("Comment"));
this.email_button = this.wrapper.find(".btn-new-email")
.on("click", function() {
new frappe.views.CommunicationComposer({
doc: me.frm.doc,
txt: frappe.markdown(me.input.val()),
frm: me.frm,
recipients: me.get_recipient()
})
});
this.list.on("click", ".toggle-blockquote", function() {
$(this).parent().siblings("blockquote").toggleClass("hidden");
});
this.setup_comment_like();
this.setup_mentions();
},
@ -116,7 +114,7 @@ frappe.ui.form.Comments = Class.extend({
prepare_comment: function(c) {
if((c.comment_type || "Comment") === "Comment" && frappe.model.can_delete("Comment")) {
c["delete"] = '<a class="close" href="#">&times;</a>';
c["delete"] = '<a class="close" href="#"><i class="octicon octicon-trashcan"></i></a>';
} else {
c["delete"] = "";
}
@ -130,7 +128,7 @@ frappe.ui.form.Comments = Class.extend({
c.image = frappe.user_info(c.comment_by).image
|| frappe.get_gravatar(c.comment_by);
c.comment_on = comment_when(c.creation);
c.fullname = frappe.user_info(c.comment_by).fullname;
c.fullname = frappe.user.full_name(c.comment_by);
if(c.attachments && typeof c.attachments==="string")
c.attachments = JSON.parse(c.attachments);
@ -150,7 +148,7 @@ frappe.ui.form.Comments = Class.extend({
if(c.comment_type=="Email") {
c.comment = c.comment.split("<!-- original-reply -->")[0];
c.comment = frappe.utils.strip_original_content(c.comment);
c.comment = frappe.utils.remove_script_and_style(c.comment);
c.comment = frappe.dom.remove_script_and_style(c.comment);
c.original_comment = c.comment;
c.comment = frappe.utils.toggle_blockquote(c.comment);
@ -167,6 +165,15 @@ frappe.ui.form.Comments = Class.extend({
if(c.comment_type==="Comment") {
c.comment_html = c.comment_html.replace(/(^|\W)(@\w+)/g, "$1<b>$2</b>");
}
if (in_list(["Comment", "Email"], c.comment_type)) {
c.user_content = true;
if (!$.isArray(c._liked_by)) {
c._liked_by = JSON.parse(c._liked_by || "[]");
}
c.liked_by_user = c._liked_by.indexOf(user)!==-1;
}
}
},
set_icon_and_color: function(c) {
@ -186,7 +193,8 @@ frappe.ui.form.Comments = Class.extend({
"Attachment": "octicon octicon-cloud-upload",
"Attachment Removed": "octicon octicon-trashcan",
"Shared": "octicon octicon-eye",
"Unshared": "octicon octicon-circle-slash"
"Unshared": "octicon octicon-circle-slash",
"Like": "octicon octicon-heart"
}[c.comment_type]
c.color = {
@ -348,10 +356,13 @@ frappe.ui.form.Comments = Class.extend({
this.mention_input = this.wrapper.find(".mention-input");
var source = Object.keys(username_user_map);
source.sort();
this.mention_input.autocomplete({
minLength: 0,
autoFocus: true,
source: Object.keys(username_user_map),
source: source,
select: function(event, ui) {
var value = ui.item.value;
var textarea_value = me.input.val();
@ -467,9 +478,21 @@ frappe.ui.form.Comments = Class.extend({
me.mention_widget.trigger(me.enter);
// prevent default
return false;
}
} else {
if (e.which==me.codes.TAB) {
me.comment_button.focus();
return false;
}
}
});
},
setup_comment_like: function() {
this.wrapper.on("click", ".comment-likes .octicon-heart", frappe.ui.click_toggle_like);
frappe.ui.setup_like_popover(this.wrapper, ".comment-likes");
}
});

View file

@ -1,16 +1,19 @@
<div class="media timeline-item" data-name="{%= data.name %}">
<div class="media timeline-item {% if (data.user_content) { %} user-content {% } else { %} notification-content {% } %}" data-doctype="{{ data.doctype }}" data-name="{%= data.name %}">
{% if (data.user_content) { %}
<span class="pull-left avatar avatar-medium">
<img class="media-object" src="{%= data.image %}">
<div class="avatar-frame" style="background-image: url({%= data.image %})"></div>
</span>
<div class="pull-left media-body" style="max-width: calc(100% - 41px); padding-right: 0px;">
<div>
<div class="pull-right">
{% } %}
<div class="pull-left media-body" style="max-width: calc(100% - 50px); padding-right: 0px;">
<div class="media-content-wrapper">
<div class="pull-right close-btn-container">
<span class="small text-muted">
{%= data.delete %}
</span>
</div>
{% if(data.doctype=="Communication" || data.comment_type=="Comment") { %}
<h6>
<div class="comment-header small">
<i class="{%= data.icon %} icon-fixed-width"></i>
<span title="{%= data.comment_by %}">{%= data.fullname %}</span>
<span class="text-muted" style="font-weight: normal;">
@ -47,14 +50,23 @@
<a class="text-muted reply-link pull-right"
data-name="{%= data.name %}">{%= __("Reply") %}</a>
{% } %}
</h6>
<span class="comment-likes" data-liked-by=\'{{ JSON.stringify(data._liked_by) }}\'>
<i class="octicon octicon-heart like-action
{% if (!data.liked_by_user) { %}
text-extra-muted not-liked
{% } %} "
data-doctype="{%= data.doctype %}"
data-name="{%= data.name %}"></i>
<span class="likes-count text-muted">{{ data._liked_by.length }}</span>
</span>
</div>
<div class="reply">
<div>
{%= data.comment_html %}
</div>
</div>
{% } else if(in_list(["Assignment Completed", "Assigned", "Shared", "Unshared"], data.comment_type)) { %}
<h6>
<div class="small">
<i class="{%= data.icon %} icon-fixed-width"></i>
{% if(data.reference_doctype && data.reference_name) { %}
<a href="#Form/{%= data.reference_doctype %}/{%= data.reference_name %}">
@ -65,14 +77,19 @@
{% } %}
<span class="text-muted" style="font-weight: normal;">
&ndash; {%= data.comment_on %}</span>
</h6>
</div>
{% } else { %}
<h6>
<div class="small">
<i class="{%= data.icon %} icon-fixed-width"></i>
<span title="{%= data.comment_by %}">{%= data.fullname %}</span> {%= data.comment %}
<span class="text-muted" style="font-weight: normal;">
&ndash; {%= data.comment_on %}</span>
</h6>
{% if (data.comment_type == "Like") { %}
<span title="{%= data.comment_by %}">{%= __("Liked by {0}", [data.fullname]) %}</span>
{% } else { %}
<span title="{%= data.comment_by %}">{%= data.fullname %}</span>
{%= data.comment %}
{% } %}
<span class="text-muted" style="font-weight: normal;">
&ndash; {%= data.comment_on %}</span>
</div>
{% } %}
{% if(data.attachments && data.attachments.length) { %}
<div style="margin: 10px 0px">

View file

@ -45,6 +45,12 @@
<li class="form-viewers"></li>
</ul>
<ul class="list-unstyled sidebar-menu text-muted">
<li class="liked-by-parent">
<span class="liked-by">
<i class="octicon octicon-heart like-action text-extra-muted"></i>
<span class="like-count"></span>
</span>
</li>
<li class="modified-by"></li>
<li class="created-by"></li>
</ul>

View file

@ -117,7 +117,7 @@ frappe.form.formatters = {
return frappe.form.formatters.Data(value);
},
StarredBy: function(value) {
LikedBy: function(value) {
var html = "";
$.each(JSON.parse(value || "[]"), function(i, v) {
if(v) html+= '<span class="avatar avatar-small" \
@ -202,7 +202,7 @@ frappe.format = function(value, df, options, doc) {
var formatted = formatter(value, df, options, doc);
if (typeof formatted == "string")
formatted = frappe.utils.remove_script_and_style(formatted);
formatted = frappe.dom.remove_script_and_style(formatted);
return formatted;
}

View file

@ -236,11 +236,12 @@ frappe.ui.form.Layout = Class.extend({
grid_row = null;
prev = null,
fields = me.fields_list,
in_grid = false;
in_grid = false,
focused = false;
// in grid
if(doctype != me.doctype) {
grid_row =me.get_open_grid_row()
grid_row = me.get_open_grid_row();
fields = grid_row.layout.fields_list;
}
@ -254,38 +255,43 @@ frappe.ui.form.Layout = Class.extend({
}
break;
}
if(i==len-1) {
// last field in this group
if(grid_row) {
// in grid
if(grid_row.doc.idx==grid_row.grid.grid_rows.length) {
// last row, close it and find next field
grid_row.toggle_view(false, function() {
me.handle_tab(grid_row.grid.df.parent, grid_row.grid.df.fieldname);
})
} else {
// next row
grid_row.grid.grid_rows[grid_row.doc.idx].toggle_view(true);
}
} else {
$(this.primary_button).focus();
}
} else {
me.focus_on_next_field(i, fields);
if(i < len-1) {
focused = me.focus_on_next_field(i, fields);
}
break;
if (focused) {
break;
}
}
if(fields[i].disp_status==="Write")
if(this.is_visible(fields[i]))
prev = fields[i];
}
if (!focused) {
// last field in this group
if(grid_row) {
// in grid
if(grid_row.doc.idx==grid_row.grid.grid_rows.length) {
// last row, close it and find next field
grid_row.toggle_view(false, function() {
grid_row.grid.frm.layout.handle_tab(grid_row.grid.df.parent, grid_row.grid.df.fieldname);
})
} else {
// next row
grid_row.grid.grid_rows[grid_row.doc.idx].toggle_view(true);
}
} else {
$(this.primary_button).focus();
}
}
return false;
},
focus_on_next_field: function(start_idx, fields) {
// loop to find next eligible fields
for(var i= start_idx + 1, len = fields.length; i < len; i++) {
var field = fields[i];
if(field.disp_status==="Write") {
if(this.is_visible(field)) {
if(field.df.fieldtype==="Table") {
// open table grid
if(!(field.grid.grid_rows && field.grid.grid_rows.length)) {
@ -294,14 +300,18 @@ frappe.ui.form.Layout = Class.extend({
}
// show grid row (if exists)
field.grid.grid_rows[0].show_form();
return true;
} else if(!in_list(frappe.model.no_value_type, field.df.fieldtype)) {
this.set_focus(field);
break;
return true;
}
}
}
},
is_visible: function(field) {
return field.disp_status==="Write" && (field.$wrapper && field.$wrapper.is(":visible"))
},
set_focus: function(field) {
// next is table, show the table
if(field.df.fieldtype=="Table") {

View file

@ -22,6 +22,7 @@ frappe.ui.form.Sidebar = Class.extend({
this.make_shared();
this.make_viewers();
this.make_tags();
this.make_like();
this.bind_events();
@ -37,6 +38,12 @@ frappe.ui.form.Sidebar = Class.extend({
$(".offcanvas").removeClass("active-left active-right");
frappe.ui.scroll(me.frm.footer.wrapper.find(".form-comments"), true);
});
this.like_icon.on("click", function() {
frappe.ui.toggle_like(me.like_icon, me.frm.doctype, me.frm.doc.name, function() {
me.refresh_like();
});
})
},
refresh: function() {
@ -55,6 +62,8 @@ frappe.ui.form.Sidebar = Class.extend({
this.sidebar.find(".created-by").html(__("{0} created this {1}",
["<strong>" + frappe.user.full_name(this.frm.doc.owner) + "</strong>",
"<br>" + comment_when(this.frm.doc.creation)]));
this.refresh_like();
}
},
@ -113,4 +122,26 @@ frappe.ui.form.Sidebar = Class.extend({
this.user_actions.addClass("hide")
this.user_actions.find(".user-action-row").remove();
},
make_like: function() {
this.like_wrapper = this.sidebar.find(".liked-by");
this.like_icon = this.sidebar.find(".liked-by .octicon-heart");
this.like_count = this.sidebar.find(".liked-by .like-count");
frappe.ui.setup_like_popover(this.sidebar.find(".liked-by-parent"), ".liked-by");
},
refresh_like: function() {
if (!this.like_icon) {
return;
}
this.like_wrapper.attr("data-liked-by", this.frm.doc._liked_by);
this.like_icon.toggleClass("text-extra-muted not-liked",
!frappe.ui.is_liked(this.frm.doc))
.attr("data-doctype", this.frm.doctype)
.attr("data-name", this.frm.doc.name);
this.like_count.text(JSON.parse(this.frm.doc._liked_by || "[]").length);
},
});

View file

@ -15,7 +15,6 @@ frappe.ui.form.Toolbar = Class.extend({
this.page.clear_user_actions();
this.show_title_as_dirty();
this.set_primary_action();
this.refresh_star();
if(this.frm.meta.hide_toolbar) {
this.page.hide_menu();
@ -23,26 +22,25 @@ frappe.ui.form.Toolbar = Class.extend({
if(this.frm.doc.__islocal) {
this.page.hide_menu();
this.print_icon && this.print_icon.addClass("hide");
this.star_icon && this.star_icon.addClass("hide");
} else {
this.page.show_menu();
this.print_icon && this.print_icon.removeClass("hide");
this.star_icon && this.star_icon.removeClass("hide");
}
}
},
set_title: function() {
if(this.frm.meta.title_field) {
var title = (this.frm.doc[this.frm.meta.title_field] || "").trim() || __(this.frm.docname);
var title = (this.frm.doc[this.frm.meta.title_field] || "").trim() || this.frm.docname;
if(this.frm.doc.__islocal || title === this.frm.docname || this.frm.meta.autoname==="hash") {
this.page.set_title_sub("");
} else {
this.page.set_title_sub(this.frm.docname);
}
} else {
var title = __(this.frm.docname);
var title = this.frm.docname;
}
var me = this;
title = __(title);
this.page.set_title(title);
if(this.frm.meta.title_field) {
frappe.utils.set_title(title + " - " + this.frm.docname);
@ -97,13 +95,6 @@ frappe.ui.form.Toolbar = Class.extend({
this.page.clear_indicator();
}
},
refresh_star: function() {
this.star_icon &&
this.star_icon.toggleClass("text-extra-muted not-starred",
!frappe.ui.is_starred(this.frm.doc))
.attr("data-doctype", this.frm.doctype)
.attr("data-name", this.frm.doc.name);
},
make_menu: function() {
var me = this;
var p = this.frm.perm[0];
@ -117,13 +108,6 @@ frappe.ui.form.Toolbar = Class.extend({
me.frm.print_doc();});
}
// star
if(!this.frm.meta.issingle) {
this.star_icon = this.page.add_action_icon("icon-star", function() {
frappe.ui.toggle_star(me.star_icon, me.frm.doctype, me.frm.doc.name);
}).removeClass("text-muted").find(".icon-star").addClass("star-action");
}
// email
if(frappe.model.can_email(null, me.frm) && me.frm.doc.docstatus < 2) {
this.page.add_menu_item(__("Email"), function() {

View file

@ -116,7 +116,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
this.setup_filterable();
this.init_filters();
this.init_headers();
this.init_star();
this.init_like();
this.init_select_all();
},
@ -168,9 +168,9 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
}
});
this.$page.find(".result-list").on("click", ".list-row-left", function(e) {
// don't open in case of checkbox, star, filterable
// don't open in case of checkbox, like, filterable
if ((e.target.className || "").indexOf("filterable")!==-1
|| (e.target.className || "").indexOf("icon-star")!==-1
|| (e.target.className || "").indexOf("octicon-heart")!==-1
|| e.target.type==="checkbox") {
return;
}
@ -307,8 +307,8 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
}
}
this.list_header.find(".list-starred-by-me")
.toggleClass("text-extra-muted not-starred", !this.is_star_filtered());
this.list_header.find(".list-liked-by-me")
.toggleClass("text-extra-muted not-liked", !this.is_star_filtered());
this.last_updated_on = new Date();
this.dirty = false;
@ -355,6 +355,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
filters: this.filter_list.get_filters(),
order_by: this.listview.order_by || undefined,
group_by: this.listview.group_by || undefined,
with_comment_count: true
}
// apply default filters, if specified for a listing
@ -368,15 +369,15 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
this.filter_list.add_filter(this.doctype, "_assign", 'like', '%' + user + '%');
this.run();
},
starred_by_me: function() {
this.filter_list.add_filter(this.doctype, "_starred_by", 'like', '%' + user + '%');
liked_by_me: function() {
this.filter_list.add_filter(this.doctype, "_liked_by", 'like', '%' + user + '%');
this.run();
},
remove_starred_by_me: function() {
this.filter_list.get_filter("_starred_by").remove();
remove_liked_by_me: function() {
this.filter_list.get_filter("_liked_by").remove();
},
is_star_filtered: function() {
return this.filter_list.filter_exists(this.doctype, "_starred_by", 'like', '%' + user + '%');
return this.filter_list.filter_exists(this.doctype, "_liked_by", 'like', '%' + user + '%');
},
init_menu: function() {
var me = this;
@ -453,19 +454,20 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
}, true)
},
init_star: function() {
init_like: function() {
var me = this;
this.$page.find(".result-list").on("click", ".star-action", function() {
frappe.ui.toggle_star($(this), me.doctype, $(this).attr("data-name"));
return false;
});
this.list_header.find(".list-starred-by-me").on("click", function() {
this.$page.find(".result-list").on("click", ".like-action", frappe.ui.click_toggle_like);
this.list_header.find(".list-liked-by-me").on("click", function() {
if (me.is_star_filtered()) {
me.remove_starred_by_me();
me.remove_liked_by_me();
} else {
me.starred_by_me();
me.liked_by_me();
}
});
if (!frappe.dom.is_touchscreen()) {
frappe.ui.setup_like_popover(this.$page.find(".result-list"), ".liked-by");
}
},
init_select_all: function() {
@ -576,7 +578,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
return false;
} else {
// second filter set for this field
if(fieldname=='_user_tags' || fieldname=="_starred_by") {
if(fieldname=='_user_tags' || fieldname=="_liked_by") {
// and for tags
this.filter_list.add_filter(this.doctype, fieldname, 'like', '%' + label);
} else {
@ -587,7 +589,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
} else {
// no filter for this item,
// setup one
if(fieldname=='_user_tags' || fieldname=="_starred_by") {
if(fieldname=='_user_tags' || fieldname=="_liked_by") {
this.filter_list.add_filter(this.doctype, fieldname, 'like', '%' + label);
} else {
this.filter_list.add_filter(this.doctype, fieldname, '=', label);

View file

@ -31,7 +31,7 @@
{% } %}
{% } else if(col.fieldtype==="Select") { %}
<span class="filterable indicator {%= frappe.utils.guess_colour(value) %}"
data-filter="{%= col.fieldname %},=,{%= value %}">{%= value %}</span>
data-filter="{%= col.fieldname %},=,{%= value %}">{%= __(value) %}</span>
{% } else if(col.fieldtype==="Link") { %}
<a class="filterable h6 text-muted grey"
data-filter="{%= col.fieldname %},=,{%= value %}">{%= value %}</a>

View file

@ -23,12 +23,12 @@
title="{%= __("Select All") %}">
{% } %}
<i class="icon-fixed-width icon-star text-extra-muted not-starred star-action list-starred-by-me"
title="{%= __("Starred By Me") %}"></i>
<i class="icon-fixed-width octicon octicon-heart text-extra-muted not-liked like-action list-liked-by-me"
title="{%= __("Likes") %}"></i>
{% } %}
<span class="list-value">{%= col.title || col.label || "" %}</span>
<span class="list-value">{%= __(col.title) || __(col.label) || "" %}</span>
</div>
{% } %}
{% } %}

View file

@ -23,9 +23,12 @@
<!-- comment -->
<div class="list-col col-sm-2 col-xs-2
text-right list-row-right">
<div class="visible-xs pull-right list-row-indicator">{%= list.get_indicator_dot(data) %}</div>
<div class="hidden-xs pull-right">
text-right list-row-right" style="padding-left:0px">
<div class="visible-xs list-row-indicator">{%= list.get_indicator_dot(data) %}</div>
<div class="hidden-xs">
<span class="list-row-modified text-muted">
{%= comment_when(data.modified, true) %}
</span>
{% if (data._assign_list.length) { %}
<span class="filterable"
data-filter="_assign,like,%{%= data._assign_list[data._assign_list.length - 1] %}%">
@ -33,14 +36,11 @@
{% } else { %}
<span class="avatar avatar-small avatar-empty"></span>
{% } %}
<span class="h6 {% if(!data._comments_list.length) { %}text-extra-muted{% } %}">
<span class="list-comment-count small
{% if(!data._comment_count) { %} text-extra-muted {% } else { %} text-muted {% } %}">
<i class="octicon octicon-comment-discussion"></i>
{%= data._comments_list.length || 0 %}
{%= (data._comment_count > 99 ? "99+" : data._comment_count) || 0 %}
</span>
</div>
<div class="pull-right list-row-modified">
<span class="text-muted">
{%= comment_when(data.modified, true) %}</span>
</div>
</div>
</div>

View file

@ -2,13 +2,16 @@
<input class="list-delete" type="checkbox"
style="margin: 0 7px 0 0; vertical-align: middle;">
{% } %}
<i class="icon-star
{% if (_starred_by.indexOf(_user)===-1) { %}
text-extra-muted not-starred
{% }%}
icon-fixed-width star-action"
data-name="{{ _name }}" data-doctype="{{ doctype }}">
</i>
<span class="liked-by" data-liked-by=\'{{ JSON.stringify(_liked_by) }}\'>
<i class="octicon octicon-heart
{% if (_liked_by.indexOf(_user)===-1) { %}
text-extra-muted not-liked
{% }%}
icon-fixed-width like-action"
data-name="{{ _name }}" data-doctype="{{ doctype }}">
</i>
<span class="likes-count">{{ (_liked_by.length > 9 ? "9+" : _liked_by.length) || "" }}</span>
</span>
<a class="grey list-id"
style="margin-right: 7px;"
href="#Form/{{ _doctype_encoded }}/{{ _name_encoded }}"

View file

@ -49,7 +49,7 @@ frappe.views.ListView = Class.extend({
}
$.each(['name', 'owner', 'docstatus', '_user_tags', '_comments', 'modified',
'modified_by', '_assign', '_starred_by'],
'modified_by', '_assign', '_liked_by'],
function(i, fieldname) { add_field(fieldname); })
// add title field
@ -266,7 +266,7 @@ frappe.views.ListView = Class.extend({
var indicator = frappe.get_indicator(doc, this.doctype);
if(indicator) {
return '<span class="indicator '+indicator[1]+' filterable" data-filter="'
+indicator[2]+'">'+indicator[0]+'<span>';
+indicator[2]+'">'+__(indicator[0])+'<span>';
} else {
return "";
}
@ -277,15 +277,15 @@ frappe.views.ListView = Class.extend({
if (!indicator) {
return "";
}
return '<span class="indicator '+indicator[1]+'" title="'+indicator[0]+'"></span>';
return '<span class="indicator '+indicator[1]+'" title="'+__(indicator[0])+'"></span>';
},
prepare_data: function(data) {
if(data.modified)
this.prepare_when(data, data.modified);
data._starred_by = data._starred_by ?
JSON.parse(data._starred_by) : [];
data._liked_by = data._liked_by ?
JSON.parse(data._liked_by) : [];
data._checkbox = (frappe.model.can_delete(this.doctype) || this.settings.selectable) && !this.no_delete
@ -311,7 +311,6 @@ frappe.views.ListView = Class.extend({
}
data._user = user;
data._comments_list = data._comments ? JSON.parse(data._comments) : [];
data._tags = $.map((data._user_tags || "").split(","),
function(v) { return v ? v : null; });
data._assign_list = data._assign ? JSON.parse(data._assign) : [];

View file

@ -50,18 +50,6 @@ frappe.utils = {
return txt.toLowerCase().substr(0,7)=='http://'
|| txt.toLowerCase().substr(0,8)=='https://'
},
remove_script_and_style: function(txt) {
var div = document.createElement('div');
div.innerHTML = txt;
["script", "style", "noscript", "title", "meta", "base", "head"].forEach(function(e, i) {
var elements = div.getElementsByTagName(e);
var i = elements.length;
while (i--) {
elements[i].parentNode.removeChild(elements[i]);
}
});
return div.innerHTML;
},
toggle_blockquote: function(txt) {
if (!txt) return txt;

Some files were not shown because too many files have changed in this diff Show more