Merge branch 'develop' into custom-perms-1

This commit is contained in:
Nabin Hait 2017-01-18 16:00:22 +05:30 committed by GitHub
commit 61e60efdcb
24 changed files with 137 additions and 144 deletions

View file

@ -13,7 +13,7 @@ import os, sys, importlib, inspect, json
from .exceptions import *
from .utils.jinja import get_jenv, get_template, render_template
__version__ = '7.2.9'
__version__ = '7.2.11'
__title__ = "Frappe Framework"
local = Local()

View file

@ -255,7 +255,7 @@ class LoginManager:
self.run_trigger('on_logout')
if user == frappe.session.user:
delete_session(frappe.session.sid)
delete_session(frappe.session.sid, user=user, reason="User Manually Logged Out")
self.clear_cookies()
else:
clear_sessions(user)

View file

@ -52,15 +52,16 @@ def clear_website_cache(context):
frappe.destroy()
@click.command('destroy-all-sessions')
@click.option('--reason')
@pass_context
def destroy_all_sessions(context):
def destroy_all_sessions(context, reason=None):
"Clear sessions of all users (logs them out)"
import frappe.sessions
for site in context.sites:
try:
frappe.init(site=site)
frappe.connect()
frappe.sessions.clear_all_sessions()
frappe.sessions.clear_all_sessions(reason)
frappe.db.commit()
finally:
frappe.destroy()

View file

@ -334,12 +334,13 @@ def add_attachments(name, attachments):
# loop through attachments
for a in attachments:
attach = frappe.db.get_value("File", {"name":a},
["file_name", "file_url", "is_private"], as_dict=1)
if isinstance(a, basestring):
attach = frappe.db.get_value("File", {"name":a},
["file_name", "file_url", "is_private"], as_dict=1)
# save attachments to new doc
save_url(attach.file_url, attach.file_name, "Communication", name,
"Home/Attachments", attach.is_private)
# save attachments to new doc
save_url(attach.file_url, attach.file_name, "Communication", name,
"Home/Attachments", attach.is_private)
def filter_email_list(doc, email_list, exclude, is_cc=False):
# temp variables

View file

@ -58,6 +58,15 @@ def login_feed(login_manager):
"full_name": get_fullname(login_manager.user)
})
def logout_feed(user, reason):
if not user:
return
add_info_comment(**{
"subject": _("{0} logged out: <b>{1}</b>").format(get_fullname(user), reason),
"full_name": get_fullname(user),
})
def get_feed_match_conditions(user=None, force=True):
if not user: user = frappe.session.user

View file

@ -88,8 +88,8 @@ frappe.ui.form.on('User', {
}
}
if (frappe.route_titles["unsaved"]===1){
delete frappe.route_titles["unsaved"];
if (frappe.route_flags.unsaved===1){
delete frappe.route_flags.unsaved;
for ( var i=0;i<frm.doc.user_emails.length;i++){
frm.doc.user_emails[i].idx=frm.doc.user_emails[i].idx+1;
}
@ -122,16 +122,15 @@ frappe.ui.form.on('User', {
frappe.route_options = {
"email_id": cur_frm.doc.email,
"awaiting_password":1,
"enable_incoming":1,
"append_to":"Communication"
"enable_incoming":1
};
frappe.model.with_doctype("Email Account", function (doc) {
var doc = frappe.model.get_new_doc("Email Account");
frappe.route_titles["create user account"]=cur_frm.doc.name;
frappe.route_flags.create_user_account=cur_frm.doc.name;
frappe.set_route("Form", "Email Account", doc.name);
})
}else{
frappe.route_titles["create user account"]=cur_frm.doc.name;
frappe.route_flags.create_user_account=cur_frm.doc.name;
frappe.set_route("Form", "Email Account", r["message"][0]["name"]);
}
}

View file

@ -41,14 +41,11 @@ class User(Document):
def before_insert(self):
self.flags.in_insert = True
def after_insert(self):
self.set_default_roles()
def force_user_email_update(self):
for user_email in self.user_emails:
if not user_email.email_id:
user_email.email_id = frappe.db.get_value("Email Account", {"name": user_email.email_account},
"email_id")
user_email.email_id = frappe.db.get_value("Email Account",
{"name": user_email.email_account}, "email_id")
def user_emails_to_permissions(self):
if frappe.session.user == "Administrator" or "System Manager" in frappe.get_roles():
@ -127,33 +124,6 @@ class User(Document):
if not cint(self.enabled) and getattr(frappe.local, "login_manager", None):
frappe.local.login_manager.logout(user=self.name)
def set_default_roles(self):
"""Set a default role if specified by rules (`default_role`) in hooks or Portal Settings
Hooks for default roles can be set as:
default_roles = [
{'role': 'Customer', 'doctype':'Contact', 'email_field': 'email_id',
'filters': {'ifnull(customer, "")': ('!=', '')}}
]
"""
role_found = False
for rule in frappe.get_hooks('default_roles'):
filters = {rule.get('email_field'): self.email}
if rule.get('filters'):
filters.update(rule.get('filters'))
match = frappe.get_all(rule.get('doctype'), filters=filters, limit=1)
if match:
role_found = True
self.add_roles(rule.get('role'))
if not role_found:
default_role = frappe.db.get_single_value('Portal Settings', 'default_role')
if default_role:
self.add_roles(default_role)
def add_system_manager_role(self):
# if adding system manager, do nothing
if not cint(self.enabled) or ("System Manager" in [user_role.role for user_role in
@ -586,18 +556,16 @@ def get_email_awaiting(user):
@frappe.whitelist(allow_guest=False)
def set_email_password(email_account, user, password):
account = frappe.get_doc("Email Account",
email_account)
account = frappe.get_doc("Email Account", email_account)
if account.awaiting_password:
account.set("awaiting_password",0)
account.set("password",password)
try:
validate = account.validate()
save= account.save(ignore_permissions=True)
account.save(ignore_permissions=True)
frappe.db.sql("""update `tabUser Email` set awaiting_password = 0
where email_account = %(account)s""",{"account": email_account})
ask_pass_update()
except Exception, e:
except Exception:
frappe.db.rollback()
return False
return True

View file

@ -8,7 +8,7 @@ def sendmail_to_system_managers(subject, content):
frappe.sendmail(recipients=get_system_managers(), subject=subject, content=content)
@frappe.whitelist()
def get_contact_list(doctype, fieldname, txt):
def get_contact_list(txt):
"""Returns contacts (from autosuggest)"""
txt = txt.replace('%', '')
@ -16,9 +16,14 @@ def get_contact_list(doctype, fieldname, txt):
return filter(None, frappe.db.sql_list('select email from tabUser where email like %s',
('%' + txt + '%')))
try:
out = filter(None, frappe.db.sql_list('select `{0}` from `tab{1}` where `{0}` like %s'.format(fieldname, doctype),
'%' + txt + '%'))
if out:
out = filter(None, frappe.db.sql_list("""select email_id from `tabContact`
where `email_id` like %(txt)s order by
if (locate( %(_txt)s, email_id), locate( %(_txt)s, email_id), 99999)""",
{'txt': "%%%s%%" % frappe.db.escape(txt),
'_txt': txt.replace("%", "")
})
)
if not out:
out = get_users()
except Exception, e:
if e.args[0]==1146:

View file

@ -7,11 +7,11 @@ frappe.ui.form.on("Contact", {
refresh: function(frm) {
if(frm.doc.__islocal) {
var last_route = frappe.route_history.slice(-2, -1)[0];
if(frappe.contact_link && frappe.contact_link.doc
&& frappe.contact_link.doc.name==last_route[2]) {
if(frappe.dynamic_link && frappe.dynamic_link.doc
&& frappe.dynamic_link.doc.name==last_route[2]) {
frm.add_child('links', {
link_doctype: frappe.contact_link.doctype,
link_name: frappe.contact_link.doc[frappe.contact_link.fieldname]
link_doctype: frappe.dynamic_link.doctype,
link_name: frappe.dynamic_link.doc[frappe.dynamic_link.fieldname]
});
}
}

View file

@ -31,6 +31,14 @@ class Contact(Document):
frappe.db.sql("""update `tabIssue` set contact='' where contact=%s""",
self.name)
def get_link_for(self, link_doctype):
'''Return the link name, if exists for the given link DocType'''
for link in self.links:
if link.link_doctype==link_doctype:
return link.link_name
return None
def has_common_link(self, doc):
reference_links = [(link.link_doctype, link.link_name) for link in doc.links]
for link in self.links:
@ -40,20 +48,20 @@ class Contact(Document):
def get_default_contact(doctype, name):
'''Returns default contact for the given doctype, name'''
out = frappe.db.sql('''select contact.name
out = frappe.db.sql('''select parent,
(select is_primary_contact from tabContact c where c.name = dl.parent)
as is_primary_contact
from
tabContact contact, `tabDynamic Link` dl
`tabDynamic Link` dl
where
dl.parent = contact.name and
dl.link_doctype=%s and
dl.link_name=%s and
dl.parenttype = "Contact"
order by
contact.is_primary_contact desc, name
limit 1''', (doctype, name), debug=1)
dl.parenttype = "Contact"''', (doctype, name))
print out
return out and out[0][0] or None
if out:
return sorted(out, lambda x,y: cmp(y[1], x[1]))[0][0]
else:
return None
@frappe.whitelist()
def invite_user(contact):

View file

@ -1,9 +1,7 @@
[
{
"customer": "_Test Customer",
"customer_name": "_Test Customer",
"doctype": "Contact",
"email_id": "test_contact_customer@example.com",
"email_id": "test_conctact@example.com",
"first_name": "_Test Contact For _Test Customer",
"is_primary_contact": 1,
"phone": "+91 0000000000",
@ -11,12 +9,10 @@
},
{
"doctype": "Contact",
"email_id": "test_contact_supplier@example.com",
"email_id": "test_contact@example.com",
"first_name": "_Test Contact For _Test Supplier",
"is_primary_contact": 1,
"phone": "+91 0000000000",
"status": "Open",
"supplier": "_Test Supplier",
"supplier_name": "_Test Supplier"
"status": "Open"
}
]

View file

@ -108,9 +108,9 @@ frappe.ui.form.on("Email Account", {
frm.events.notify_if_unreplied(frm);
frm.events.show_gmail_message_for_less_secure_apps(frm);
if (frm.doc.__islocal != 1) {
if (frappe.route_titles["create user account"]) {
var user =frappe.route_titles["create user account"];
delete frappe.route_titles["create user account"];
if (frappe.route_flags.create_user_account) {
var user = frappe.route_flags.create_user_account;
delete frappe.route_flags.create_user_account;
var userdoc = frappe.get_doc("User",user);
frappe.model.with_doc("User", user, function (doc) {
var new_row = frappe.model.add_child(userdoc, "User Email", "user_emails");
@ -118,7 +118,7 @@ frappe.ui.form.on("Email Account", {
new_row.awaiting_password = cur_frm.doc.awaiting_password;
new_row.email_id = cur_frm.doc.email_id;
new_row.idx = 0;
frappe.route_titles["unsaved"] = 1;
frappe.route_flags.unsaved = 1;
frappe.set_route("Form", "User",user);
});
}
@ -145,32 +145,31 @@ frappe.ui.form.on("Email Account", {
"email_id": cur_frm.doc.email_id
},
callback: function (frm) {
try {
if (cur_frm.doc.domain !=frm["message"][0]["name"]) {
if (frm.message) {
if (cur_frm.doc.domain != frm["message"][0]["name"]) {
cur_frm.doc.domain = frm["message"][0]["name"]
cur_frm.doc.email_server= frm["message"][0]["email_server"];
cur_frm.doc.use_imap= frm["message"][0]["use_imap"];
cur_frm.doc.smtp_server= frm["message"][0]["smtp_server"];
cur_frm.doc.use_ssl= frm["message"][0]["use_ssl"];
cur_frm.doc.use_tls= frm["message"][0]["use_tls"];
cur_frm.doc.email_server = frm["message"][0]["email_server"];
cur_frm.doc.use_imap = frm["message"][0]["use_imap"];
cur_frm.doc.smtp_server = frm["message"][0]["smtp_server"];
cur_frm.doc.use_ssl = frm["message"][0]["use_ssl"];
cur_frm.doc.use_tls = frm["message"][0]["use_tls"];
cur_frm.doc.smtp_port = frm["message"][0]["smtp_port"];
if (!norefresh) {
cur_frm.refresh();
}
}
}
catch (Exception) {
}else{
frappe.confirm(
'Email Domain not configured for this account\nCreate one?',
function () {
frappe.model.with_doctype("Email Domain", function() {
frappe.route_options = {email_id: cur_frm.doc.email_id};
frappe.route_titles["return to email_account"] = 1
var doc = frappe.model.get_new_doc("Email Domain");
frappe.set_route("Form", "Email Domain", doc.name);
})
}
)
__('Email Domain not configured for this account, Create one?'),
function () {
frappe.model.with_doctype("Email Domain", function() {
frappe.route_options = {email_id: cur_frm.doc.email_id};
frappe.route_flags.return_to_email_account = 1
var doc = frappe.model.get_new_doc("Email Domain");
frappe.set_route("Form", "Email Domain", doc.name);
})
}
)
}
}
});

View file

@ -7,8 +7,8 @@ frappe.ui.form.on("Email Domain", {
if (frm.doc.email_id){frm.set_value("domain_name",frm.doc.email_id.split("@")[1])}
if (frm.doc.__islocal != 1) {
route = frappe.get_prev_route()
if (frappe.route_titles["return to email_account"]){
delete frappe.route_titles["return to email_account"];
if (frappe.route_flags.return_to_email_account){
delete frappe.route_flags.return_to_email_account;
frappe.set_route(route);
}
}

View file

@ -84,8 +84,8 @@ frappe.Inbox = frappe.ui.Listing.extend({
}
},
refresh:function(){
delete frappe.route_titles["create_contact"];
delete frappe.route_titles["update_contact"];
delete frappe.route_flags.create_contact;
delete frappe.route_flags.update_contact;
this.run();
},
render_headers: function(){
@ -279,8 +279,8 @@ frappe.Inbox = frappe.ui.Listing.extend({
});
d.get_input("newcontact").on("click", function (frm) {
d.hide();
delete frappe.route_titles["update_contact"];
frappe.route_titles["create_contact"] = 1;
delete frappe.route_flags.update_contact;
frappe.route_flags.create_contact = 1;
var name_split = row.sender_full_name?row.sender_full_name.split(' '):["",""];
row.nomatch = 1;

View file

@ -5,7 +5,7 @@
"doctype": "Page",
"icon": "fa fa-inbox",
"idx": 0,
"modified": "2016-12-22 17:19:55.284608",
"modified": "2017-01-16 22:46:18.276855",
"modified_by": "Administrator",
"module": "Email",
"name": "email_inbox",
@ -13,7 +13,7 @@
"page_name": "email_inbox",
"roles": [
{
"role": "Email User"
"role": "All"
}
],
"script": null,

View file

@ -5,11 +5,11 @@ frappe.ui.form.on("Address", {
refresh: function(frm) {
if(frm.doc.__islocal) {
var last_route = frappe.route_history.slice(-2, -1)[0];
if(frappe.contact_link && frappe.contact_link.doc
&& frappe.contact_link.doc.name==last_route[2]) {
if(frappe.dynamic_link && frappe.dynamic_link.doc
&& frappe.dynamic_link.doc.name==last_route[2]) {
frm.add_child('links', {
link_doctype: frappe.contact_link.doctype,
link_name: frappe.contact_link.doc[frappe.contact_link.fieldname]
link_doctype: frappe.dynamic_link.doctype,
link_name: frappe.dynamic_link.doc[frappe.dynamic_link.fieldname]
});
}
}

View file

@ -71,18 +71,21 @@ class Address(Document):
def get_default_address(doctype, name, sort_key='is_primary_address'):
'''Returns default Address name for the given doctype, name'''
out = frappe.db.sql('''select address.name
out = frappe.db.sql('''select
parent,
(select `{0}` from tabAddress a where a.name=dl.parent) as `{0}`
from
tabAddress address, `tabDynamic Link` dl
`tabDynamic Link` dl
where
dl.link_doctype=%s and
dl.link_name=%s and
dl.parent = address.name and
dl.parenttype = "Address"
order by
address.`{0}` desc, name
limit 1'''.format(sort_key), (doctype, name))
return out and out[0][0] or None
link_doctype=%s and
link_name=%s and
parenttype = "Address"
'''.format(sort_key), (doctype, name))
if out:
return sorted(out, lambda x,y: cmp(y[1], x[1]))[0][0]
else:
return None
@frappe.whitelist()
@ -173,7 +176,7 @@ def get_shipping_address(company):
name, address_template = get_address_templates(address_as_dict)
return address_as_dict.get("name"), frappe.render_template(address_template, address_as_dict)
def contact_query(doctype, txt, searchfield, start, page_len, filters):
def address_query(doctype, txt, searchfield, start, page_len, filters):
from frappe.desk.reportview import get_match_cond
return frappe.db.sql("""select

View file

@ -1,15 +1,13 @@
[
{
"address_line1": "_Test Address Line 1",
"address_title": "_Test Address",
"address_type": "Office",
"address_line1": "_Test Address Line 1",
"address_title": "_Test Address",
"address_type": "Office",
"city": "_Test City",
"state": "Test State",
"country": "India",
"customer": "_Test Customer",
"customer_name": "_Test Customer",
"doctype": "Address",
"is_primary_address": 1,
"country": "India",
"doctype": "Address",
"is_primary_address": 1,
"phone": "+91 0000000000"
}
]

View file

@ -154,3 +154,4 @@ frappe.patches.v7_2.set_doctype_engine
frappe.patches.v7_2.merge_knowledge_base
frappe.patches.v7_0.update_report_builder_json
frappe.patches.v7_2.set_in_standard_filter_property #1
execute:frappe.db.sql("update tabCommunication set communication_date = creation where time(communication_date) = 0")

View file

@ -6,6 +6,7 @@
// re-route map (for rename)
frappe.re_route = {"#login": ""};
frappe.route_titles = {};
frappe.route_flags = {};
frappe.route_history = [];
frappe.view_factory = {};
frappe.view_factories = [];

View file

@ -552,7 +552,7 @@ frappe.views.CommunicationComposer = Class.extend({
+ "<br><!-- original-reply --><br>"
+ '<blockquote>' +
'<p>' + __("On {0}, {1} wrote:",
[frappe.datetime.global_date_format(last_email.creation) , last_email.sender]) + '</p>' +
[frappe.datetime.global_date_format(last_email.communication_date) , last_email.sender]) + '</p>' +
last_email_content +
'<blockquote>');
} else {
@ -598,8 +598,6 @@ frappe.views.CommunicationComposer = Class.extend({
frappe.call({
method:'frappe.email.get_contact_list',
args: {
'fieldname': "email_id",
'doctype': "Contact",
'txt': extractLast(term) || '%'
},
quiet: true,

View file

@ -574,7 +574,7 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
var me = this;
this.page.add_inner_button(__('Show Totals'), function() {
me.add_totals_row = 1 - me.add_totals_row;
me.add_totals_row = 1 - (me.add_totals_row ? me.add_totals_row : 0);
me.render_list();
});
},

View file

@ -147,7 +147,7 @@ _f.Frm.prototype.setup_drag_drop = function() {
callback: function(attachment, r) {
me.attachments.attachment_uploaded(attachment, r);
},
confirm_is_private: true
});
});
@ -348,7 +348,7 @@ _f.Frm.prototype.refresh_header = function(is_a_different_doc) {
this.dashboard.refresh();
if(this.meta.is_submittable &&
frappe.perm.get_perm(this.docname, this.doc).submit &&
this.perm[0] && this.perm[0].submit &&
! this.is_dirty() &&
! this.is_new() &&
this.doc.docstatus===0) {

View file

@ -61,7 +61,7 @@ def clear_sessions(user=None, keep_current=False, device=None):
:param device: delete sessions of this device (default: desktop)
'''
for sid in get_sessions_to_clear(user, keep_current, device):
delete_session(sid)
delete_session(sid, reason="Logged In From Another Session")
def get_sessions_to_clear(user=None, keep_current=False, device=None):
'''Returns sessions of the current user. Called at login / logout
@ -85,23 +85,30 @@ def get_sessions_to_clear(user=None, keep_current=False, device=None):
if keep_current:
condition = ' and sid != "{0}"'.format(frappe.db.escape(frappe.session.sid))
return frappe.db.sql_list("""select sid from tabSessions
where user=%s and device=%s {condition}
order by lastupdate desc limit {limit}, 100""".format(condition=condition, limit=limit),
(user, device))
def delete_session(sid=None, user=None):
def delete_session(sid=None, user=None, reason="Session Expired"):
from frappe.core.doctype.communication.feed import logout_feed
frappe.cache().hdel("session", sid)
frappe.cache().hdel("last_db_session_update", sid)
if sid and not user:
user_details = frappe.db.sql("""select user from tabSessions where sid=%s""", sid, as_dict=True)
if user_details: user = user_details[0].get("user")
logout_feed(user, reason)
frappe.db.sql("""delete from tabSessions where sid=%s""", sid)
frappe.db.commit()
def clear_all_sessions():
def clear_all_sessions(reason=None):
"""This effectively logs out all users"""
frappe.only_for("Administrator")
if not reason: reason = "Deleted All Active Session"
for sid in frappe.db.sql_list("select sid from `tabSessions`"):
delete_session(sid)
delete_session(sid, reason=reason)
def get_expired_sessions():
'''Returns list of expired sessions'''
@ -113,11 +120,10 @@ def get_expired_sessions():
return expired
def clear_expired_sessions():
"""This function is meant to be called from scheduler"""
for sid in get_expired_sessions():
delete_session(sid)
delete_session(sid, reason="Session Expired")
def get():
"""get session boot info"""
@ -335,7 +341,7 @@ class Session:
return (cint(parts[0]) * 3600) + (cint(parts[1]) * 60) + cint(parts[2])
def delete_session(self):
delete_session(self.sid)
delete_session(self.sid, reason="Session Expired")
def start_as_guest(self):
"""all guests share the same 'Guest' session"""