[inbox] js clean ups, other minor fixes in imap

This commit is contained in:
mbauskar 2017-03-01 11:23:13 +05:30
parent 1d272da47f
commit 0ab2af1715
9 changed files with 457 additions and 423 deletions

View file

@ -633,64 +633,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "uid",
"fieldtype": "Int",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "UID",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "fingerprint",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Fingerprint",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -1315,6 +1257,64 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "uid",
"fieldtype": "Int",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "UID",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "fingerprint",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Fingerprint",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "feedback_section",
"fieldtype": "Section Break",
"hidden": 0,
@ -1486,5 +1486,5 @@
"sort_order": "DESC",
"title_field": "subject",
"track_changes": 1,
"track_seen": 1
"track_seen": 0
}

View file

@ -280,7 +280,7 @@ class EmailAccount(Document):
#notify if user is linked to account
if len(incoming_mails)>0 and not frappe.local.flags.in_test:
frappe.publish_realtime('new_email', {"account":self.email_account_name,"number":len(incoming_mails)})
frappe.publish_realtime('new_email', {"account":self.email_account_name, "number":len(incoming_mails)})
if exceptions:
raise Exception, frappe.as_json(exceptions)
@ -306,14 +306,15 @@ class EmailAccount(Document):
frappe.db.commit()
def insert_communication(self, msg, args={}):
if isinstance(msg,list):
if isinstance(msg, list):
raw, uid, seen = msg
else:
raw = msg
seen = uid = None
uid = -1
seen = 0
if args.get("uid", None): uid = args.get("uid", None)
if args.get("seen", None): seen = args.get("seen", None)
if args.get("uid", -1): uid = args.get("uid", -1)
if args.get("seen", 0): seen = args.get("seen", 0)
email = Email(raw)
@ -345,11 +346,11 @@ class EmailAccount(Document):
"cc": email.mail.get("CC"),
"email_account": self.name,
"communication_medium": "Email",
"uid": uid,
"uid": int(uid or -1),
"message_id": email.message_id,
"communication_date": email.date,
"has_attachment": 1 if email.attachments else 0,
"seen": seen,
"seen": seen or 0,
"fingerprint": args.get("fingerprint", None)
})
@ -565,12 +566,13 @@ class EmailAccount(Document):
if self.email_sync_option == "ALL":
max_uid = get_max_email_uid(self.name)
last_uid = max_uid + int(self.initial_sync_count or 100) if max_uid == 1 else "*"
print "UID {}:{}".format(max_uid, last_uid)
return "UID {}:{}".format(max_uid, last_uid)
else:
return self.email_sync_option
def mark_emails_as_seen(self):
""" mark Email Flag Queue of self.email_account mails as seen"""
def mark_emails_as_read(self):
""" mark Email Flag Queue of self.email_account mails as read"""
if not self.use_imap:
return
@ -581,10 +583,33 @@ class EmailAccount(Document):
uid_list = list(set([ flag.get("uid") for flag in flags ]))
if flags and uid_list:
email_server = self.get_incoming_server()
marked_as_seen = email_server.mark_as_seen(uid_list=uid_list)
email_server.update_flag(uid_list=uid_list)
docnames = ",".join([ "'%s'"%uid for uid in uid_list ])
frappe.db.sql(""" update `tabCommunication` set seen=1 where name in ({docnames})""".format(docnames=docnames))
docnames = ",".join([ "'%s'"%flag.get("name") for flag in flags ])
frappe.db.sql(""" update `tabCommunication` set seen=1
where name in ({docnames})""".format(docnames=docnames))
def mark_emails_as_unread(self):
""" mark Email Flag Queue of self.email_account mails as unread"""
if not self.use_imap:
return
flags = frappe.db.sql("""select name, communication, uid from `tabEmail Flag Queue`
where action = "Unread" and is_completed=0 """.format(email_account=self.name), as_dict=True)
uid_list = list(set([ flag.get("uid") for flag in flags ]))
if flags and uid_list:
email_server = self.get_incoming_server()
email_server.update_flag(uid_list=uid_list, operation="Unread")
docnames = ",".join([ "'%s'"%flag.get("communication") for flag in flags ])
frappe.db.sql(""" update `tabCommunication` set seen=0
where name in ({docnames})""".format(docnames=docnames))
docnames = ",".join([ "'%s'"%flag.get("name") for flag in flags ])
frappe.db.sql(""" update `tabEmail Flag Queue` set is_completed=1
where name in ({docnames})""".format(docnames=docnames))
@frappe.whitelist()
def get_append_to(doctype=None, txt=None, searchfield=None, start=None, page_len=None, filters=None):
@ -661,7 +686,8 @@ def pull_from_email_account(email_account):
email_account.receive()
# mark Email Flag Queue mail as read
email_account.mark_emails_as_seen()
email_account.mark_emails_as_read()
email_account.mark_emails_as_unread()
def get_max_email_uid(email_account):
# get maximum uid of emails

View file

@ -1,5 +1,5 @@
{
"allow_copy": 0,
"allow_copy": 1,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@ -15,21 +15,23 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "email_account",
"fieldtype": "Data",
"fieldname": "is_completed",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Email Account",
"label": "Is Completed",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@ -43,10 +45,12 @@
"collapsible": 0,
"columns": 0,
"fieldname": "communication",
"fieldtype": "Data",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Communication",
@ -70,45 +74,19 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "uid",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "UID",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "+FLAGS",
"fieldname": "action",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Action",
"length": 0,
"no_copy": 0,
"options": "+FLAGS\n-FLAGS",
"options": "Read\nUnread",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -126,18 +104,18 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Seen",
"fieldname": "flag",
"fieldtype": "Select",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Flag",
"length": 0,
"no_copy": 0,
"options": "Seen\nUnseen",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -155,13 +133,13 @@
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_create": 1,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-02-13 07:58:35.414784",
"modified": "2017-03-01 05:24:47.756892",
"modified_by": "Administrator",
"module": "Email",
"name": "Email Flag Queue",
@ -190,8 +168,9 @@
}
],
"quick_entry": 0,
"read_only": 0,
"read_only": 1,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,

View file

@ -8,71 +8,41 @@ import json
from frappe.model.document import Document
from frappe.desk.form.load import get_attachments
@frappe.whitelist()
def get_list(email_account,start,page_length):
inbox_list = []
communications = frappe.db.sql("""select name, sender, sender_full_name, actualdate, recipients, communication_medium as comment_type, subject, status ,reference_doctype,reference_name,timeline_doctype,timeline_name,timeline_label,sent_or_received,uid,message_id, seen,nomatch,has_attachment
from tabCommunication
where email_account = %(email_account)s and deleted = 0
ORDER BY actualdate DESC
LIMIT %(page_length)s OFFSET %(start)s""",{"email_account":email_account,"start":int(start),"page_length":int(page_length)},as_dict=1)
for c in communications:
comm = {}
comm["name"] = c.get('name')
comm["reference_doctype"] = c.get('reference_doctype')
comm["reference_name"] = c.get('reference_name')
if c.get('recipients') != None:
comm["recipients"] = c.get('recipients').replace('"',"").strip("<>")
comm["sender"] = c.get('sender')
comm["sender_full_name"] = c.get('sender_full_name')
comm["actualdate"] = c.get('actualdate')
comm["subject"] = c.get('subject')
comm["status"] = c.get('status')
comm["content"] = c.get('content')
comm["timeline_doctype"] = c.get('timeline_doctype')
comm["timeline_name"] = c.get('timeline_name')
comm["timeline_label"] = c.get('timeline_label')
comm["sent_or_received"] = c.get('sent_or_received')
comm["uid"]= c.get('uid')
comm["message_id"]=c.get("message_id")
comm["seen"] = c.get('seen')
comm["nomatch"] =c.get('nomatch')
comm["has_attachment"]=c.get('has_attachment')
inbox_list.append(comm)
return inbox_list
@frappe.whitelist()
def get_email_content(name):
docinfo = frappe.desk.form.load.get_attachments("Communication",name)
content = frappe.db.get_value("Communication", name,"content")
docinfo = frappe.desk.form.load.get_attachments("Communication", name)
content = frappe.db.get_value("Communication", name, "content")
return docinfo, content
@frappe.whitelist()
def create_flag_queue(names,action,flag,field):
def create_flag_queue(names, action, flag):
names = json.loads(names)
class Found(Exception):
pass
for item in names:
if item["uid"]:
state = frappe.db.get_value("Communication", item["name"], field)
if (action =='+FLAGS' and state ==0) or (action =='-FLAGS' and state ==1): #check states are correct
if item.get("uid"):
state = frappe.db.get_value("Communication", item.get("name"), "seen")
frappe.errprint(state)
# check states are correct
if (action =='Read' and state == 0) or (action =='Unread' and state == 1):
try:
queue = frappe.db.sql("""select name,action,flag from `tabEmail Flag Queue`
where comm_name = %(name)s""",{"name":item["name"]},as_dict=1)
queue = frappe.db.sql("""select name, action, flag from `tabEmail Flag Queue`
where communication = %(name)s""", {"name":item.get("name")}, as_dict=True)
for q in queue:
if q.flag==flag:#is same email with same flag
if q.action!=action:#to prevent flag local and server states being out of sync
# is same email with same flag
if q.flag == flag:
# to prevent flag local and server states being out of sync
if q.action != action:
frappe.delete_doc("Email Flag Queue", q.name)
raise Found
flag_queue = frappe.get_doc({
"doctype": "Email Flag Queue",
"comm_name": str(item["name"]),
"action":action,
"flag":flag
"communication": item.get("name"),
"action": action,
"flag": flag
})
flag_queue.save(ignore_permissions=True);
except Found:
@ -80,40 +50,35 @@ def create_flag_queue(names,action,flag,field):
@frappe.whitelist()
def setnomatch(name):
frappe.db.set_value("Communication", str(name), "nomatch", 1, update_modified=False)
frappe.db.set_value("Communication", name, "nomatch", 1, update_modified=False)
@frappe.whitelist()
def update_local_flags(names,field,val):
def update_local_flags(names, field, val):
names = json.loads(names)
for d in names:
frappe.db.set_value("Communication", str(d["name"]), field, val,update_modified=False)
@frappe.whitelist()
def get_length(email_account):
try:
return frappe.db.sql("""select count(name)
from tabCommunication
where deleted = 0 and email_account= %(email_account)s""",{"email_account":email_account})
except:
return 0
frappe.db.set_value("Communication", d.get("name"), field, val, update_modified=False)
@frappe.whitelist()
def get_accounts(user):
try:
return frappe.db.sql("""select email_account,email_id
from `tabUser Email`
where parent = %(user)s
order by idx""",{"user":user},as_dict=1)
except:
return
email_accounts = []
# for the selection/deletion of multiple items
def set_multiple_status(names, status):
names = json.loads(names)
for name in names:
set_status(name, status)
accounts = frappe.get_all("User Email", filters={ "parent": user },
fields=["email_account as account", "email_id as title"],
distinct=True, order_by="idx")
def set_status(name, status):
st = frappe.get_doc("Issue", name)
st.status = status
st.save()
if not accounts:
return None
all_accounts = ",".join([ account.get("account") for account in accounts ])
if len(accounts) > 1:
email_accounts.append({
"account": all_accounts,
"title": "All Accounts"
})
email_accounts.extend(accounts)
return {
"email_accounts": email_accounts,
"all_accounts": all_accounts
}

View file

@ -1,3 +1,5 @@
frappe.provide("frappe.email")
frappe.pages['email_inbox'].on_page_load = function(wrapper) {
frappe.ui.make_app_page({
parent: wrapper,
@ -7,7 +9,7 @@ frappe.pages['email_inbox'].on_page_load = function(wrapper) {
});
frappe.model.with_doctype('Communication', function() {
wrapper.Inbox = new frappe.Inbox({
wrapper.inbox = new frappe.email.EmailInbox({
method: 'frappe.desk.reportview.get',
wrapper: wrapper,
page: wrapper.page,
@ -18,82 +20,79 @@ frappe.pages['email_inbox'].on_page_load = function(wrapper) {
frappe.pages['email_inbox'].refresh = function(wrapper) {
if (wrapper.inbox) {
wrapper.Inbox.refresh()
wrapper.inbox.refresh()
}
};
frappe.Inbox = frappe.ui.Listing.extend({
frappe.email.EmailInbox = frappe.ui.Listing.extend({
init: function(opts) {
$.extend(this, opts);
wrap = this;
this.wrapper = opts.wrapper;
this.filters = {};
this.page_length = 20;
this.start = 0;
this.cur_page = 1;
this.no_result_message = 'No Emails to Display';
this.render_sidemenu();
if (this.account) {
var me = this;
// setup listing
me.make({
doctype: 'Communication',
page: me.page,
method: 'frappe.desk.reportview.get',
get_args: me.get_args,
parent: me.page.main,
start: 0,
show_filters: true
});
this.render_headers();
this.render_footer();
this.run();
this.render_buttons();
this.init_select_all();
var me = this;
frappe.realtime.on("new_email", function(data) {
for(var i =0; i<me.accounts.length; i++) {
if (data.account == me.accounts[i].name) {
frappe.utils.notify(data.account, "you have "+data.number+" new emails", {}, function () {
window.focus();
me.account = data.account;
$(me.page.sidebar).find(".list-row").removeClass("list-row-head").css("font-weight","normal");
$('.inbox-item[data-account="' + data.account + '" ]').closest(".list-row").addClass("list-row-head").css("font-weight","bold");
me.refresh();
});
if(!me.fresh &&(data.account == me.account || me.account == me.allaccounts)) {
me.fresh = true;
me.refresh();
}
}
}
me.fresh = false
});
} else {
frappe.msgprint(__("No Email Account assigned to you. Please contact your System Administrator"));
setTimeout(function() {
if (frappe.session.user==="Administrator") {
frappe.set_route("List", "User");
} else {
frappe.set_route('');
}
}, 3000);
}
this.get_accounts();
},
setup_inbox: function() {
var me = this;
// setup listing
me.make({
doctype: 'Communication',
page: me.page,
method: 'frappe.desk.reportview.get',
get_args: me.get_args,
parent: me.page.main,
start: 0,
show_filters: true
});
this.render_sidebar();
this.render_headers();
this.render_buttons();
this.init_select_all();
this.setup_notifications();
this.refresh();
},
get_accounts: function() {
// get all the configured email account for the user
var me = this;
frappe.call({
method: 'frappe.email.page.email_inbox.get_accounts',
args: {
'user': user
},
callback:function(r){
me.page.sidebar.empty()
if(!r.message) {
frappe.msgprint(__("No Email Account assigned to you. Please contact your System Administrator"));
setTimeout(function() {
if (frappe.session.user==="Administrator")
frappe.set_route("List", "User");
else
frappe.set_route('');
}, 3000);
}
me.accounts = r.message;
me.setup_inbox();
}
});
},
refresh:function(){
delete frappe.route_flags.create_contact;
delete frappe.route_flags.update_contact;
this.run();
},
render_headers: function(){
$(".layout-main-section-wrapper").css("padding-left","0px").css("padding-right","0px");
var data = {"start":this.start,"page_length":this.page_length.toString()};
this.list_header = $(frappe.render_template("inbox_headers", data)).appendTo(this.page.main.find(".list-headers"));
},
render_sidemenu: function () {
render_sidebar: function (data) {
var me = this;
frappe.call({
method: 'frappe.email.page.email_inbox.get_accounts',
@ -148,119 +147,137 @@ frappe.Inbox = frappe.ui.Listing.extend({
}
})
},
toggle_accounts: function() {
$(this.page.main).find(".list-select-all,.list-delete").prop("checked", false);
this.toggle_actions();
this.filter_list.clear_filters();
this.refresh();
},
render_headers: function(){
$(".layout-main-section-wrapper").css("padding-left","0px").css("padding-right","0px");
var data = {
"start":this.start,
"page_length":this.page_length.toString()
};
headers_html = frappe.render_template("inbox_headers", data)
this.list_header = $(headers_html).appendTo(this.page.main.find(".list-headers"));
},
get_args: function(){
var args = {
doctype: this.doctype,
fields:["name", "sender", "sender_full_name", "communication_date", "recipients", "cc","communication_medium",
"subject", "status" ,"reference_doctype", "reference_name", "timeline_doctype", "timeline_name",
"timeline_label", "sent_or_received", "uid", "message_id", "seen"],
filters: this.filter_list.get_filters(),
fields: [
"name", "sender", "sender_full_name", "communication_date", "recipients",
"cc","communication_medium", "subject", "status" ,"reference_doctype",
"reference_name", "timeline_doctype", "timeline_name", "timeline_label",
"sent_or_received", "uid", "message_id", "seen"
],
filters: this.get_email_filters(),
order_by: 'communication_date desc',
save_list_settings: false
};
args.filters = args.filters.concat(this.filter_list.default_filters)
return args;
},
render_list:function(data){
var me = this
$(me.wrapper).find(".result-list").html("");
for (var i = 0; i < data.length; i++)
{
this.prepare_row(data[i]);
$(frappe.render_template("inbox_list", {data: data[i]})).data("data", data[i]).appendTo($(me.wrapper).find(".result-list"))
}
//click action
$(me.wrapper).find(".result-list").find(".list-row").click(function (btn) {
if ($(btn.target).hasClass("noclick")) {
return
}
var row = $(btn.target).closest(".list-row").data("data");
if($(btn.target).hasClass("relink-link")){
me.relink(row);
return
}
if(me.account!="Sent") {
if ($(btn.target).hasClass("company-link")) {
me.company_select(row, true);
return
get_email_filters: function() {
filters = this.filter_list.get_filters()
if(this.account == "Sent") {
this.filter_list.default_filters = [
["Communication", "communication_type", "=", "Communication"],
["Communication", "communication_medium", "=", "Email"],
["Communication", "user", "=", user],
["Communication", "sent_or_received", "=", "Sent"]
]
} else {
this.filter_list.default_filters = [
["Communication", "communication_type", "=", "Communication"],
["Communication", "communication_medium", "=", "Email"],
["Communication", "sent_or_received", "=", "Received"],
["Communication", "email_account", "in", this.account],
]
}
$.extend(filters, this.filter_list.default_filters)
return filters;
},
setup_notifications: function() {
// setup real time email notification using frappe.realtime
var me = this;
frappe.realtime.on("new_email", function(data) {
for(var i =0; i<me.accounts.length; i++) {
if (data.account == me.accounts[i].name) {
frappe.utils.notify(data.account, "you have "+data.number+" new emails", {}, function () {
window.focus();
me.account = data.account;
$(me.page.sidebar).find(".list-row").removeClass("list-row-head").css("font-weight", "normal");
$('.inbox-item[data-account="' + data.account + '" ]').closest(".list-row").addClass("list-row-head").css("font-weight","bold");
me.refresh();
});
if(!me.fresh &&(data.account == me.account || me.account == me.all_accounts)) {
me.fresh = true;
me.refresh();
}
}
me.email_open(row);
});
},
prepare_row:function(row){
row.hascompany =(row.customer || row.supplier) ? true : false;
row.seen = this.account!="Sent" ? row.seen : 1;
},
render_footer:function(){
var me = this;
me.footer = $(me.wrapper).append(frappe.render_template("inbox_footer","")).find(".foot-con");
frappe.require('assets/frappe/js/lib/bootstrap-paginator.min.js',function(){
me.footer.bootstrapPaginator({
currentPage: 1,
totalPages: 10,
bootstrapMajorVersion:3,
onPageClicked: function(e,originalEvent,type,page){
me.cur_page = page;
$('.footer-numbers').html('showing: ' + (me.cur_page - 1) * me.page_length + ' to ' + (
(me.data_length > (me.cur_page * me.page_length))?(me.cur_page * me.page_length):me.data_length) + ' of ' + me.data_length);
me.run(true,true);
}
me.fresh = false
});
});
$(me.wrapper).find('.list-paging-area').addClass('hide');
},
update_footer:function(){
var me = this;
//default filter used for filters
var filters = me.filter_list.get_filters();
if (me.filter_list.default_filters){filters = filters.concat(me.filter_list.default_filters)}
return frappe.call({
method: me.method || 'frappe.desk.query_builder.runquery',
type: "GET",
freeze: (me.freeze != undefined ? me.freeze : true),
args: {
doctype: me.doctype,
fields: ["count(*) as number"],
filters: filters,
save_list_settings: false
},
callback: function (r) {
r.values = me.get_values_from_response(r.message);
me.data_length = r.values[0]["number"]
if (me.data_length != 0) {
me.footer.show();
me.last_page = Math.ceil(me.data_length / me.page_length);
frappe.require('assets/frappe/js/lib/bootstrap-paginator.min.js',function(){
me.footer.bootstrapPaginator({currentPage: 1, totalPages: me.last_page})
});
} else {
me.footer.hide();
render_list: function(data) {
var me = this
$(me.wrapper).find(".result-list").empty();
$.each(data, function(idx, email) {
$(frappe.render_template("inbox_list", {data: email}))
.data("data", email)
.appendTo($(me.wrapper).find(".result-list"))
});
//click action
$(me.wrapper).find(".result-list").find(".list-row").click(function(btn) {
if ($(btn.target).hasClass("noclick"))
return
var row = $(btn.target).closest(".list-row").data("data");
if($(btn.target).hasClass("relink-link")){
me.relink(row);
return
}
if(me.account != "Sent") {
if ($(btn.target).hasClass("company-link")) {
me.company_select(row, true);
return
}
$('.footer-numbers').html('showing: ' + (me.cur_page - 1) * me.page_length + ' to ' + (
(me.data_length > (me.cur_page * me.page_length)) ? (me.cur_page * me.page_length) : me.data_length) + ' of ' + me.data_length);
},
no_spinner: this.no_loading
}
me.email_open(row);
});
},
company_select:function(row,nomatch)
{
company_select: function(row, nomatch) {
var me = this;
var fields = [{
var fields = [
{
"fieldtype": "Heading",
"label": __("Create new Contact to Match Email Address"),
"fieldname": "Option1"
},
{
"fieldtype": "Button",
"label": __("Create/Add new Contact"),
"fieldname":"newcontact",
"description": __('Create new Contact for a Customer, Supplier, User or Organisation to Match "') + row.sender + __('" Against')
}
},
{
"fieldtype": "Button",
"label": __("Create/Add new Contact"),
"fieldname":"newcontact",
"description": __('Create new Contact for a Customer, Supplier, User or Organisation to Match "') + row.sender + __('" Against')
}
];
];
if (!nomatch) {
fields.push({
"fieldtype": "Heading",
@ -273,10 +290,12 @@ frappe.Inbox = frappe.ui.Listing.extend({
"fieldname":"nomatch"
})
}
var d = new frappe.ui.Dialog ({
title: __("Match Emails to a Company"),
fields: fields
});
d.get_input("newcontact").on("click", function (frm) {
d.hide();
delete frappe.route_flags.update_contact;
@ -295,6 +314,7 @@ frappe.Inbox = frappe.ui.Listing.extend({
frappe.set_route("Form", "Contact", doc.name);
})
});
if (!nomatch) {
d.get_input("nomatch").on("click", function (frm) {
d.hide();
@ -312,8 +332,8 @@ frappe.Inbox = frappe.ui.Listing.extend({
}
d.show();
},
email_open:function(row)
{
email_open: function(row) {
var me = this;
me.actions_opened = false;
if(me.open_email == row.name){
@ -363,8 +383,15 @@ frappe.Inbox = frappe.ui.Listing.extend({
//adjust sizing
$(".modal-dialog").addClass("modal-lg");
$(emailitem.$wrapper).find(".modal-title").parent().removeClass("col-xs-7").addClass("col-xs-7 col-sm-8 col-md-9");
$(emailitem.$wrapper).find(".text-right").parent().removeClass("col-xs-5").addClass("col-xs-5 col-sm-4 col-md-3");
$(emailitem.$wrapper).find(".modal-title")
.parent()
.removeClass("col-xs-7")
.addClass("col-xs-7 col-sm-8 col-md-9");
$(emailitem.$wrapper).find(".text-right")
.parent()
.removeClass("col-xs-5")
.addClass("col-xs-5 col-sm-4 col-md-3");
//setup close
emailitem.onhide = function() {
@ -373,9 +400,11 @@ frappe.Inbox = frappe.ui.Listing.extend({
emailitem.show();
},
add_reply_btn_event: function (emailitem, c) {
var me = this;
//reply
//reply
$(emailitem.$wrapper).find(".reply-link").on("click", function () {
var sender = "";
for (var i=0;i<me.accounts.length;i++){
@ -389,14 +418,15 @@ frappe.Inbox = frappe.ui.Listing.extend({
doctype: c.reference_doctype,
name: c.reference_name
},
sender:sender,
sender: sender,
subject: "Re: " + c.subject,
recipients: c.sender,
last_email: c,
attachments:c.attachments
attachments: c.attachments
});
});
//reply-all
//reply-all
$(emailitem.$wrapper).find(".reply-all-link").on("click", function () {
var sender = "";
for (var i=0;i<me.accounts.length;i++){
@ -417,7 +447,8 @@ frappe.Inbox = frappe.ui.Listing.extend({
attachments:c.attachments
});
});
//forward
//forward
$(emailitem.$wrapper).find(".forward-link").on("click", function () {
var sender = "";
for (var i=0;i<me.accounts.length;i++){
@ -441,7 +472,8 @@ frappe.Inbox = frappe.ui.Listing.extend({
$(communication.dialog.fields_dict.select_attachments.wrapper).find("input[type=checkbox]").prop("checked",true)
});
},
relink:function(row){
relink: function(row){
var me = this;
var callback = function(frm){
$(me.wrapper).find(".row-named[data-name="+row.name+"]").find(".reference-document")
@ -453,15 +485,8 @@ frappe.Inbox = frappe.ui.Listing.extend({
}
frappe.timeline.relink_dialog(row.name, row.reference_doctype, row.reference_name, callback);
},
run:function(more,footer) {
var me = this;
me.start = (me.cur_page-1) * me.page_length;
if (!footer) {
this.update_footer()
}
this._super(more)
},
prepare_email:function(c){
prepare_email: function(c){
var me = this;
frappe.call({
method:'frappe.email.page.email_inbox.get_email_content',
@ -473,10 +498,9 @@ frappe.Inbox = frappe.ui.Listing.extend({
callback:function(r){
c.attachments =r["message"][0];
c.content = r["message"][1];
}
}
});
c.doctype ="Communication";
c.doctype = "Communication";
c.comment_on = comment_when(c.communication_date);
@ -505,8 +529,6 @@ frappe.Inbox = frappe.ui.Listing.extend({
c.comment_html = c.comment_html.replace(/&lt;/g,"<").replace(/&gt;/g,">")
}
// bold @mentions
if (c.comment_type === "Comment") {
c.comment_html = c.comment_html.replace(/(^|\W)(@\w+)/g, "$1<b>$2</b>");
@ -514,6 +536,7 @@ frappe.Inbox = frappe.ui.Listing.extend({
return c
},
init_select_all: function () {
var me = this;
@ -540,12 +563,13 @@ frappe.Inbox = frappe.ui.Listing.extend({
// after delete, hide delete button
me.toggle_actions();
},
render_buttons: function(){
var me = this;
me.page.add_action_item("Delete", function(){me.delete_email()});
me.page.add_action_item("Mark as UnRead", function(){me.mark_unread()});
me.page.add_action_item("Mark as Read", function(){me.mark_read()});
me.page.add_action_item("Delete", function(){ me.delete_email() });
me.page.add_action_item("Mark as Unread", function(){ me.mark_unread() });
me.page.add_action_item("Mark as Read", function(){ me.mark_read() });
me.page.set_primary_action("New Email", function(){
var sender = "";
@ -559,8 +583,9 @@ frappe.Inbox = frappe.ui.Listing.extend({
doc: {},
sender: sender
});
},"fa-plus","New Email");
}, "fa-plus", "New Email");
},
toggle_actions: function () {
var me = this;
if (me.page.main.find(".list-row-checkbox:checked").length) {
@ -573,61 +598,68 @@ frappe.Inbox = frappe.ui.Listing.extend({
$(me.page.btn_primary).show()
}
},
delete_email:function(data){
delete_email: function(data){
var me = this;
if (!data) {
var names = $.map(me.action_checked_items('.data("data")'),function(v){return {name:v.name, uid:v.uid}});
var names = $.map(me.action_checked_items('.data("data")'), function(v){
return {name:v.name, uid:v.uid}
});
me.action_checked_items('.remove()')
} else {
var names = [{name:data.name, uid:data.uid}]
}
},
mark_unread:function(){
mark_unread: function(){
var me = this;
var names = $.map(me.action_checked_items('.data("data")'), function(v){return {name:v.name, uid:v.uid}});
me.create_flag_queue(names,"-FLAGS","(\\SEEN)","seen");
var names = $.map(me.action_checked_items('.data("data")'), function(v){
return {name:v.name, uid:v.uid}
});
me.create_flag_queue(names, "Unread", "SEEN");
me.action_checked_items('.css("font-weight", "BOLD")');
me.update_local_flags(names,"seen","0")
me.update_local_flags(names, "seen", "0")
},
mark_read:function(data){
mark_read: function(data){
var me = this;
if (!data) {
var names = $.map(me.action_checked_items('.data("data")'), function(v){return {name:v.name, uid:v.uid}});
me.action_checked_items('.css("font-weight", "normal")')
} else{
var names = [{name:data.name, uid:data.uid}];
$(".row-named").filter("[data-name=" + data.name + "]").css("font-weight", "normal")
} else {
var names = [{name:data.name, uid:data.uid}];
$(".row-named").filter("[data-name=" + data.name + "]").css("font-weight", "normal")
}
me.create_flag_queue(names,"+FLAGS","(\\SEEN)","seen");
me.update_local_flags(names,"seen","1")
me.create_flag_queue(names, "Read", "SEEN");
me.update_local_flags(names, "seen", "1");
},
create_flag_queue:function(names,action,flag,field){
create_flag_queue: function(names, action, flag){
frappe.call({
method: 'frappe.email.page.email_inbox.create_flag_queue',
args:{
names:JSON.stringify(names),
action:action,
flag:flag,
field:field
names: JSON.stringify(names),
action: action,
flag: flag
}
})
},
update_local_flags:function(names,field,val){
frappe.call({
method: 'frappe.email.page.email_inbox.update_local_flags',
args:{
names:JSON.stringify(names),
field:field,
val:val
names: JSON.stringify(names),
field: field,
val: val
}
})
$('.list-row-checkbox:checked').prop( "checked", false );
},
action_checked_items: function(action) {
return $.map(this.page.main.find('.list-row-checkbox:checked'), function(e) {
return eval('$(e).closest(".row-named")'+action);
});
},
});
});

View file

@ -0,0 +1,19 @@
<ul class="list-unstyled sidebar-menu user-actions">
<li class="divider"></li>
</ul>
<ul class="list-unstyled sidebar-menu standard-actions">
<li class="divider"></li>
<li class="list-link" data-view="List">
<a class="email-account" data-account="Sent">{%= __("Sent") %}</a>
</li>
</ul>
<ul class="list-unstyled sidebar-menu standard-actions">
<li class="divider"></li>
<li class="list-link"><h6>Email Accounts</h6></li>
{% for(var i=0, l=data.length; i<l; i++) { %}
<li class="divider"></li>
<li class="list-link" data-view="List">
<a class="email-account {%= i==0?"strong": "" %}" data-account="{%= data[i].account %}">{%= __(data[i].title) %}</a>
</li>
{% } %}
</ul>

View file

@ -14,33 +14,32 @@
<a class="grey" title="{%= data.name %}">{%= data.subject %}</a>
</span>
</div>
<div class="col-sm-2 list-col ellipsis hidden-xs">
<span class="list-value">
<a class="h6 text-muted grey noclick" data-filter="timeline_doctype,=,{%= data.timeline_doctype %}" title="Linked Doctype: {%= data.reference_doctype %}" href="#Form/{%= data.timeline_doctype %}/{%= data.timeline_name %}">{%= data.timeline_label%}</a>
</span>
</div>
<div class="col-sm-2 list-col ellipsis hidden-xs">
<span class="list-value">
<i class="h6 fa fa-link text-muted relink-link pull-right" style="padding: 0px 0px; margin-right: 10px; font-size: 1.1em;"></i>
<a class="text-muted grey noclick reference-document" title="Linked Doctype: {%= data.reference_doctype %}" href="#Form/{%= data.reference_doctype %}/{%= data.reference_name %}">{%= data.reference_name %}</a>
</span>
</div>
<div class="col-sm-1 list-col ellipsis hidden-xs">
<span class="list-value">
<span>
{% if(data.has_attachment){ %}
<i class="fa fa-paperclip fa-large"></i>
{% } %}
</span>
</span>
</div>
<div class="col-sm-1 list-col ellipsis hidden-xs" >
<span class="list-value">
{%= comment_when(data.communication_date,true) %}
</span>
</div>
</div>
</div>
</div>
<div class="col-sm-2 list-col ellipsis hidden-xs">
<span class="list-value">
<a class="h6 text-muted grey noclick" data-filter="timeline_doctype,=,{%= data.timeline_doctype %}" title="Linked Doctype: {%= data.reference_doctype %}" href="#Form/{%= data.timeline_doctype %}/{%= data.timeline_name %}">{%= data.timeline_label%}</a>
</span>
</div>
<div class="col-sm-2 list-col ellipsis hidden-xs">
<span class="list-value">
<i class="h6 fa fa-link text-muted relink-link pull-right" style="padding: 0px 0px; margin-right: 10px; font-size: 1.1em;"></i>
<a class="text-muted grey noclick reference-document" title="Linked Doctype: {%= data.reference_doctype %}" href="#Form/{%= data.reference_doctype %}/{%= data.reference_name %}">{%= data.reference_name %}</a>
</span>
</div>
<div class="col-sm-1 list-col ellipsis hidden-xs">
<span class="list-value">
<span>
{% if(data.has_attachment){ %}
<i class="fa fa-paperclip fa-large"></i>
{% } %}
</span>
</span>
</div>
<div class="col-sm-1 list-col ellipsis hidden-xs" >
<span class="list-value">
{%= comment_when(data.communication_date,true) %}
</span>
</div>
</div>
</div>
</div>
</div>

View file

@ -224,7 +224,7 @@ class EmailServer:
self.validate_message_limits(message_meta)
if cint(self.settings.use_imap):
status, message = self.imap.uid('fetch', message_meta, '(RFC822 BODY.PEEK[HEADER] FLAGS)')
status, message = self.imap.uid('fetch', message_meta, '(BODY.PEEK[] BODY.PEEK[HEADER] FLAGS)')
raw, header, ignore = message
self.get_email_seen_status(message_meta, header[0])
@ -342,7 +342,7 @@ class EmailServer:
return error_msg
def mark_as_seen(self, uid_list=[]):
def update_flag(self, uid_list=[], operation="Read"):
""" set all uids mails the flag as seen """
if not uid_list:
@ -351,10 +351,12 @@ class EmailServer:
if not self.connect():
return
op = "+FLAGS" if operation == "Read" else "-FLAGS"
self.imap.select("Inbox")
for uid in uid_list:
try:
self.imap.uid('STORE', uid, '+FLAGS', '(\\SEEN)')
self.imap.uid('STORE', uid, op, '(\\SEEN)')
except Exception as e:
continue

View file

@ -34,6 +34,18 @@
</ul>
</div>
</li>
{% if(doctype == "Communication") { %}
<li class="hide list-link" data-view="Email Inbox">
<div class="btn-group">
<a class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ __("Email Inbox") }} <span class="caret"></span>
</a>
<ul class="dropdown-menu inbox-dropdown" style="max-height: 300px; overflow-y: auto;">
<li class="new-kanban-board"><a>{{ __("New Kanban Board") }}</a></li>
</ul>
</div>
</li>
{% } %}
<li class="assigned-to-me">
<a>{%= __("Assigned To Me") %}</a>
</li>