seitime-frappe/frappe/desk/form/document_follow.py
2020-12-03 14:04:24 +05:30

293 lines
7.5 KiB
Python

# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
import frappe
import frappe.utils
from frappe.utils import get_url_to_form
from frappe.model import log_types
from frappe import _
from itertools import groupby
@frappe.whitelist()
def update_follow(doctype, doc_name, following):
if following:
return follow_document(doctype, doc_name, frappe.session.user)
else:
return unfollow_document(doctype, doc_name, frappe.session.user)
@frappe.whitelist()
def follow_document(doctype, doc_name, user):
'''
param:
Doctype name
doc name
user email
condition:
avoided for some doctype
follow only if track changes are set to 1
'''
if (doctype in ("Communication", "ToDo", "Email Unsubscribe", "File", "Comment", "Email Account", "Email Domain")
or doctype in log_types):
return
if ((not frappe.get_meta(doctype).track_changes)
or user == "Administrator"):
return
if not frappe.db.get_value("User", user, "document_follow_notify", ignore=True, cache=True):
return
if not is_document_followed(doctype, doc_name, user):
doc = frappe.new_doc("Document Follow")
doc.update({
"ref_doctype": doctype,
"ref_docname": doc_name,
"user": user
})
doc.save()
return doc
@frappe.whitelist()
def unfollow_document(doctype, doc_name, user):
doc = frappe.get_all(
"Document Follow",
filters={
"ref_doctype": doctype,
"ref_docname": doc_name,
"user": user
},
fields=["name"],
limit=1
)
if doc:
frappe.delete_doc("Document Follow", doc[0].name)
return 1
return 0
def get_message(doc_name, doctype, frequency, user):
activity_list = get_version(doctype, doc_name, frequency, user) + get_comments(doctype, doc_name, frequency, user)
return sorted(activity_list, key=lambda k: k["time"], reverse=True)
def send_email_alert(receiver, docinfo, timeline):
if receiver:
frappe.sendmail(
subject=_("Document Follow Notification"),
recipients=[receiver],
template="document_follow",
args={
"docinfo": docinfo,
"timeline": timeline,
}
)
def send_document_follow_mails(frequency):
'''
param:
frequency for sanding mails
task:
set receiver according to frequency
group document list according to user
get changes, activity, comments on doctype
call method to send mail
'''
users = frappe.get_list("Document Follow",
fields=["*"])
sorted_users = sorted(users, key=lambda k: k['user'])
grouped_by_user = {}
for k, v in groupby(sorted_users, key=lambda k: k['user']):
grouped_by_user[k] = list(v)
for user in grouped_by_user:
user_frequency = frappe.db.get_value("User", user, "document_follow_frequency")
message = []
valid_document_follows = []
if user_frequency == frequency:
for d in grouped_by_user[user]:
content = get_message(d.ref_docname, d.ref_doctype, frequency, user)
if content:
message = message + content
valid_document_follows.append({
"reference_docname": d.ref_docname,
"reference_doctype": d.ref_doctype,
"reference_url": get_url_to_form(d.ref_doctype, d.ref_docname)
})
if message and frappe.db.get_value("User", user, "document_follow_notify", ignore=True):
send_email_alert(user, valid_document_follows, message)
def get_version(doctype, doc_name, frequency, user):
timeline = []
filters = get_filters("docname", doc_name, frequency, user)
version = frappe.get_all("Version",
filters=filters,
fields=["ref_doctype", "data", "modified", "modified", "modified_by"]
)
if version:
for v in version:
change = frappe.parse_json(v.data)
time = frappe.utils.format_datetime(v.modified, "hh:mm a")
timeline_items = []
if change.changed:
timeline_items = get_field_changed(change.changed, time, doctype, doc_name, v)
if change.row_changed:
timeline_items = get_row_changed(change.row_changed, time, doctype, doc_name, v)
if change.added:
timeline_items = get_added_row(change.added, time, doctype, doc_name, v)
timeline = timeline + timeline_items
return timeline
def get_comments(doctype, doc_name, frequency, user):
timeline = []
filters = get_filters("reference_name", doc_name, frequency, user)
comments = frappe.get_all("Comment",
filters=filters,
fields=["content", "modified", "modified_by", "comment_type"]
)
for comment in comments:
if comment.comment_type == "Like":
by = ''' By : <b>{0}<b>'''.format(comment.modified_by)
elif comment.comment_type == "Comment":
by = '''Commented by : <b>{0}<b>'''.format(comment.modified_by)
else:
by = ''
time = frappe.utils.format_datetime(comment.modified, "hh:mm a")
timeline.append({
"time": comment.modified,
"data": {
"time": time,
"comment": frappe.utils.html2text(str(comment.content)),
"by": by
},
"doctype": doctype,
"doc_name": doc_name,
"type": "comment"
})
return timeline
def is_document_followed(doctype, doc_name, user):
return frappe.db.exists(
"Document Follow",
{
"ref_doctype": doctype,
"ref_docname": doc_name,
"user": user
}
)
@frappe.whitelist()
def get_follow_users(doctype, doc_name):
return frappe.get_all(
"Document Follow",
filters={
"ref_doctype": doctype,
"ref_docname":doc_name
},
fields=["user"]
)
def get_row_changed(row_changed, time, doctype, doc_name, v):
items = []
for d in row_changed:
d[2] = d[2] if d[2] else ' '
d[0] = d[0] if d[0] else ' '
d[3][0][1] = d[3][0][1] if d[3][0][1] else ' '
items.append({
"time": v.modified,
"data": {
"time": time,
"table_field": d[0],
"row": str(d[1]),
"field": d[3][0][0],
"from": frappe.utils.html2text(str(d[3][0][1])),
"to": frappe.utils.html2text(str(d[3][0][2]))
},
"doctype": doctype,
"doc_name": doc_name,
"type": "row changed",
"by": v.modified_by
})
return items
def get_added_row(added, time, doctype, doc_name, v):
items = []
for d in added:
items.append({
"time": v.modified,
"data": {
"to": d[0],
"time": time
},
"doctype": doctype,
"doc_name": doc_name,
"type": "row added",
"by": v.modified_by
})
return items
def get_field_changed(changed, time, doctype, doc_name, v):
items = []
for d in changed:
d[1] = d[1] if d[1] else ' '
d[2] = d[2] if d[2] else ' '
d[0] = d[0] if d[0] else ' '
items.append({
"time": v.modified,
"data": {
"time": time,
"field": d[0],
"from": frappe.utils.html2text(str(d[1])),
"to": frappe.utils.html2text(str(d[2]))
},
"doctype": doctype,
"doc_name": doc_name,
"type": "field changed",
"by": v.modified_by
})
return items
def send_hourly_updates():
send_document_follow_mails("Hourly")
def send_daily_updates():
send_document_follow_mails("Daily")
def send_weekly_updates():
send_document_follow_mails("Weekly")
def get_filters(search_by, name, frequency, user):
filters = []
if frequency == "Weekly":
filters = [
[search_by, "=", name],
["modified", ">", frappe.utils.add_days(frappe.utils.nowdate(),-7)],
["modified", "<", frappe.utils.nowdate()],
["modified_by", "!=", user]
]
elif frequency == "Daily":
filters = [
[search_by, "=", name],
["modified", ">", frappe.utils.add_days(frappe.utils.nowdate(),-1)],
["modified", "<", frappe.utils.nowdate()],
["modified_by", "!=", user]
]
elif frequency == "Hourly":
filters = [
[search_by, "=", name],
["modified", ">", frappe.utils.add_to_date(frappe.utils.now_datetime(), hours=-1)],
["modified", "<", frappe.utils.now_datetime()],
["modified_by", "!=", user]
]
return filters