From 27e7158fc41fe98b9a8ea3b0a2eb78b509cf51a3 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 18 Nov 2013 13:22:06 +0530 Subject: [PATCH] Added Notification Control for caching notifications probably causing the freezing problem --- core/doctype/doctype/doctype.py | 4 +- core/doctype/notification_count/__init__.py | 0 .../notification_count/notification_count.py | 105 ++++++++++++++++++ .../notification_count/notification_count.txt | 46 ++++++++ core/doctype/profile/profile.py | 4 + .../permission_manager/permission_manager.py | 11 +- core/page/todo/todo.py | 26 +++-- public/js/wn/app.js | 2 +- public/js/wn/views/moduleview.js | 2 +- webnotes/__init__.py | 1 + webnotes/model/bean.py | 35 ++---- webnotes/model/doc.py | 3 +- webnotes/model/doctype.py | 6 +- webnotes/model/utils.py | 9 +- webnotes/plugins.py | 7 +- webnotes/sessions.py | 2 +- webnotes/widgets/notification.py | 62 ----------- 17 files changed, 204 insertions(+), 121 deletions(-) create mode 100644 core/doctype/notification_count/__init__.py create mode 100644 core/doctype/notification_count/notification_count.py create mode 100644 core/doctype/notification_count/notification_count.txt delete mode 100644 webnotes/widgets/notification.py diff --git a/core/doctype/doctype/doctype.py b/core/doctype/doctype/doctype.py index 1e744850f6..94c3de484b 100644 --- a/core/doctype/doctype/doctype.py +++ b/core/doctype/doctype/doctype.py @@ -7,8 +7,6 @@ import webnotes from webnotes import msgprint import os -import MySQLdb - from webnotes.utils import now, cint from webnotes.model import no_value_fields @@ -307,7 +305,7 @@ def make_module_and_roles(doclist, perm_doctype="DocPerm"): r.insert() except webnotes.DoesNotExistError, e: pass - except MySQLdb.ProgrammingError, e: + except webnotes.SQLError, e: if e.args[0]==1146: pass else: diff --git a/core/doctype/notification_count/__init__.py b/core/doctype/notification_count/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/doctype/notification_count/notification_count.py b/core/doctype/notification_count/notification_count.py new file mode 100644 index 0000000000..d87c0bbe7f --- /dev/null +++ b/core/doctype/notification_count/notification_count.py @@ -0,0 +1,105 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# MIT License. See license.txt + +# For license information, please see license.txt + +from __future__ import unicode_literals +import webnotes +try: + from startup.open_count import for_doctype, for_module, for_module_doctypes + all_doctypes = for_doctype.keys() + for_module_doctypes.keys() +except ImportError: + for_doctype = {} + for_module = {} + for_module_doctypes = [] + all_doctypes = [] + +class DocType: + def __init__(self, d, dl): + self.doc, self.doclist = d, dl + +@webnotes.whitelist() +def get(): + can_read = webnotes.user.get_can_read() + open_count_doctype = {} + open_count_module = {} + + notification_count = dict(webnotes.conn.sql("""select for_doctype, open_count + from `tabNotification Count` where owner=%s""", webnotes.session.user)) + + for d in for_doctype: + if d in can_read: + condition = for_doctype[d] + key = condition.keys()[0] + + + if d in notification_count: + open_count_doctype[d] = notification_count[d] + else: + result = webnotes.get_list(d, fields=["count(*)"], + filters=[[d, key, "=", condition[key]]], as_list=True, limit_page_length=1)[0][0] + + webnotes.doc({"doctype":"Notification Count", "for_doctype":d, + "open_count":result}).insert() + + open_count_doctype[d] = result + + for m in for_module: + if m in notification_count: + open_count_module[m] = notification_count[m] + else: + open_count_module[m] = for_module[m]() + webnotes.doc({"doctype":"Notification Count", "for_doctype":m, + "open_count":open_count_module[m]}).insert() + + return { + "open_count_doctype": open_count_doctype, + "open_count_module": open_count_module + } + +def delete_notification_count_for(doctype): + try: + webnotes.conn.sql("""delete from `tabNotification Count` where for_doctype = %s""", doctype) + except webnotes.SQLError: + pass # during install + +def clear_doctype_notifications(controller, method=None): + doctype = controller.doc.doctype + if doctype in all_doctypes: + delete_notification_count_for(for_module_doctypes[doctype] if doctype in \ + for_module_doctypes else doctype) + +def get_notification_info_for_boot(): + out = get() + + can_read = webnotes.user.get_can_read() + conditions = {} + module_doctypes = {} + doctype_info = dict(webnotes.conn.sql("""select name, module from tabDocType""")) + + try: + from startup.open_count import for_doctype + except ImportError: + for_doctype = {} + + for d in list(set(can_read + for_doctype.keys())): + if d in for_doctype: + conditions[d] = for_doctype[d] + + if d in doctype_info: + module_doctypes.setdefault(doctype_info[d], []).append(d) + + out.update({ + "conditions": conditions, + "module_doctypes": module_doctypes, + }) + + return out + +def on_doctype_update(): + if not webnotes.conn.sql("""show index from `tabNotification Count` + where Key_name="notification_count_owner_index" """): + webnotes.conn.commit() + webnotes.conn.sql("""alter table `tabNotification Count` + add index notification_count_owner_index(owner)""") + diff --git a/core/doctype/notification_count/notification_count.txt b/core/doctype/notification_count/notification_count.txt new file mode 100644 index 0000000000..b828e92909 --- /dev/null +++ b/core/doctype/notification_count/notification_count.txt @@ -0,0 +1,46 @@ +[ + { + "creation": "2013-11-18 05:31:03", + "docstatus": 0, + "modified": "2013-11-18 06:26:35", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "DocType", + "document_type": "Other", + "module": "Core", + "name": "__common__" + }, + { + "doctype": "DocField", + "name": "__common__", + "parent": "Notification Count", + "parentfield": "fields", + "parenttype": "DocType", + "permlevel": 0 + }, + { + "doctype": "DocType", + "name": "Notification Count" + }, + { + "doctype": "DocField", + "fieldname": "for_doctype", + "fieldtype": "Data", + "label": "For DocType", + "search_index": 1 + }, + { + "doctype": "DocField", + "fieldname": "count", + "fieldtype": "Int", + "label": "Count" + }, + { + "doctype": "DocField", + "fieldname": "open_count", + "fieldtype": "Int", + "label": "Open Count" + } +] \ No newline at end of file diff --git a/core/doctype/profile/profile.py b/core/doctype/profile/profile.py index 94125eba00..717612d7a6 100644 --- a/core/doctype/profile/profile.py +++ b/core/doctype/profile/profile.py @@ -95,6 +95,7 @@ class DocType: def on_update(self): # owner is always name webnotes.conn.set(self.doc, 'owner', self.doc.name) + webnotes.clear_cache(user=self.doc.name) def reset_password(self): from webnotes.utils import random_string, get_url @@ -207,6 +208,7 @@ Thank you,
raise_exception=True) def on_trash(self): + webnotes.clear_cache(user=self.doc.name) if self.doc.name in ["Administrator", "Guest"]: webnotes.msgprint("""Hey! You cannot delete user: %s""" % (self.name, ), raise_exception=1) @@ -234,8 +236,10 @@ Thank you,
# delete messages webnotes.conn.sql("""delete from `tabComment` where comment_doctype='Message' and (comment_docname=%s or owner=%s)""", (self.doc.name, self.doc.name)) + def on_rename(self,newdn,olddn, merge=False): + webnotes.clear_cache(user=olddn) self.validate_rename(newdn, olddn) tables = webnotes.conn.sql("show tables") diff --git a/core/page/permission_manager/permission_manager.py b/core/page/permission_manager/permission_manager.py index b43c5db96f..1961bd0a49 100644 --- a/core/page/permission_manager/permission_manager.py +++ b/core/page/permission_manager/permission_manager.py @@ -68,14 +68,21 @@ def update_match(name, doctype, match=""): def validate_and_reset(doctype, for_remove=False): from core.doctype.doctype.doctype import validate_permissions_for_doctype validate_permissions_for_doctype(doctype, for_remove) - webnotes.clear_cache(doctype=doctype) + clear_doctype_cache(doctype) @webnotes.whitelist(allow_roles=["System Manager", "Administrator"]) def reset(doctype): webnotes.reset_perms(doctype) - webnotes.clear_cache(doctype=doctype) + clear_doctype_cache(doctype) webnotes.defaults.clear_cache() +def clear_doctype_cache(doctype): + webnotes.clear_cache(doctype=doctype) + for user in webnotes.conn.sql_list("""select distinct tabUserRole.parent from tabUserRole, tabDocPerm + where tabDocPerm.parent = %s + and tabDocPerm.role = tabUserRole.role""", doctype): + webnotes.clear_cache(user=user) + @webnotes.whitelist(allow_roles=["System Manager", "Administrator"]) def get_users_with_role(role): return [p[0] for p in webnotes.conn.sql("""select distinct tabProfile.name diff --git a/core/page/todo/todo.py b/core/page/todo/todo.py index 358ed2efd0..8302129866 100644 --- a/core/page/todo/todo.py +++ b/core/page/todo/todo.py @@ -19,26 +19,28 @@ def edit(arg=None): import markdown2 args = webnotes.local.form_dict - d = Document('ToDo', args.get('name') or None) - d.description = args['description'] - d.date = args['date'] - d.priority = args['priority'] - d.checked = args.get('checked', 0) - if not d.owner: d.owner = webnotes.session['user'] - d.save(not args.get('name') and 1 or 0) - - if args.get('name') and d.checked: + if args.name: + b = webnotes.bean("ToDo", args.name) + else: + b = webnotes.new_bean("ToDo") + + for key in ("description", "date", "priority", "checked"): + b.doc.fields[key] = args.get(key) + + b.insert_or_update() + + if args.name and args.checked: notify_assignment(d) - return d.name + return b.doc.name @webnotes.whitelist() def delete(arg=None): - name = webnotes.form_dict['name'] + name = webnotes.local.form_dict.name d = Document('ToDo', name) if d and d.name and d.owner != webnotes.session['user']: notify_assignment(d) - webnotes.conn.sql("delete from `tabToDo` where name = %s", name) + webnotes.delete_doc("ToDo", d.name, ignore_permissions=True) def notify_assignment(d): doc_type = d.reference_type diff --git a/public/js/wn/app.js b/public/js/wn/app.js index 7e7cd9c068..916d054816 100644 --- a/public/js/wn/app.js +++ b/public/js/wn/app.js @@ -114,7 +114,7 @@ wn.Application = Class.extend({ refresh_notifications: function() { if(wn.session_alive) { return wn.call({ - method: "webnotes.widgets.notification.get", + method: "core.doctype.notification_count.notification_count.get", callback: function(r) { if(r.message) { $.extend(wn.boot.notification_info, r.message); diff --git a/public/js/wn/views/moduleview.js b/public/js/wn/views/moduleview.js index 6cb21081f1..2943e677aa 100644 --- a/public/js/wn/views/moduleview.js +++ b/public/js/wn/views/moduleview.js @@ -248,7 +248,7 @@ wn.views.moduleview.ModuleView = Class.extend({ $(me.wrapper).find(".badge-important").remove(); if(wn.boot.notification_info.open_count_doctype) { $.each(wn.boot.notification_info.open_count_doctype, function(doctype, count) { - if(in_list(me.doctypes, doctype)) { + if(count && in_list(me.doctypes, doctype)) { me.set_top_item_count(doctype, null, count); $('') .css({ diff --git a/webnotes/__init__.py b/webnotes/__init__.py index 3ae0de2533..52ba542e36 100644 --- a/webnotes/__init__.py +++ b/webnotes/__init__.py @@ -9,6 +9,7 @@ from __future__ import unicode_literals from werkzeug.local import Local from werkzeug.exceptions import NotFound +from MySQLdb import ProgrammingError as SQLError import os import json diff --git a/webnotes/model/bean.py b/webnotes/model/bean.py index abe9730266..912254d35b 100644 --- a/webnotes/model/bean.py +++ b/webnotes/model/bean.py @@ -13,6 +13,10 @@ import webnotes from webnotes import _, msgprint from webnotes.utils import cint, cstr, flt from webnotes.model.doc import Document +try: + from startup.bean_handlers import on_method +except ImportError: + on_method = None class DocstatusTransitionError(webnotes.ValidationError): pass class BeanPermissionError(webnotes.ValidationError): pass @@ -236,7 +240,7 @@ class Bean: if hasattr(self.controller, 'custom_' + method): getattr(self.controller, 'custom_' + method)(*args, **kwargs) - notify(self.controller, method) + notify(self, method) self.set_doclist(self.controller.doclist) @@ -256,7 +260,7 @@ class Bean: return self.save() def insert_or_update(self): - if webnotes.conn.exists( self.doc.doctype, self.doc.name): + if self.doc.name and webnotes.conn.exists(self.doc.doctype, self.doc.name): return self.save() else: return self.insert() @@ -461,33 +465,12 @@ def clone(source_wrapper): return new_wrapper - -def notify(controller, caller_method): - try: - from startup.observers import observer_map - except ImportError: - return - - doctype = controller.doc.doctype - - def call_observers(key): - if key in observer_map: - observer_list = observer_map[key] - if isinstance(observer_list, basestring): - observer_list = [observer_list] - for observer_method in observer_list: - webnotes.get_method(observer_method)(controller, caller_method) - - call_observers("*:*") - call_observers(doctype + ":*") - call_observers("*:" + caller_method) - call_observers(doctype + ":" + caller_method) +def notify(bean, method): + if on_method: + on_method(bean, method) # for bc def getlist(doclist, parentfield): - """ - Return child records of a particular type - """ import webnotes.model.utils return webnotes.model.utils.getlist(doclist, parentfield) diff --git a/webnotes/model/doc.py b/webnotes/model/doc.py index 04dd929e38..443319cf6a 100755 --- a/webnotes/model/doc.py +++ b/webnotes/model/doc.py @@ -10,7 +10,6 @@ _toc = ["webnotes.model.doc.Document"] import webnotes import webnotes.model.meta -import MySQLdb from webnotes.utils import * @@ -132,7 +131,7 @@ class Document: else: try: dataset = webnotes.conn.sql('select * from `tab%s` where name="%s"' % (self.doctype, self.name.replace('"', '\"'))) - except MySQLdb.ProgrammingError, e: + except webnotes.SQLError, e: if e.args[0]==1146: dataset = None else: diff --git a/webnotes/model/doctype.py b/webnotes/model/doctype.py index 078d61f8ab..00f9f9cf5a 100644 --- a/webnotes/model/doctype.py +++ b/webnotes/model/doctype.py @@ -244,7 +244,11 @@ def clear_cache(doctype=None): for dt in webnotes.conn.sql("""select parent from tabDocField where fieldtype="Table" and options=%s""", doctype): clear_single(dt[0]) - + + # clear all notifications + from core.doctype.notification_count.notification_count import delete_notification_count_for + delete_notification_count_for(doctype) + else: # clear all for dt in webnotes.conn.sql("""select name from tabDocType"""): diff --git a/webnotes/model/utils.py b/webnotes/model/utils.py index a37ce636be..279ba1de8e 100644 --- a/webnotes/model/utils.py +++ b/webnotes/model/utils.py @@ -179,12 +179,11 @@ def check_permission_and_not_submitted(doctype, name, ignore_permissions=False): def run_on_trash(doctype, name, doclist): # call on_trash if required if doclist: - obj = webnotes.get_obj(doclist=doclist) + bean = webnotes.bean(doclist) else: - obj = webnotes.get_obj(doctype, name) - - if hasattr(obj,'on_trash'): - obj.on_trash() + bean = webnotes.bean(doctype, name) + + bean.run_method("on_trash") class LinkExistsError(webnotes.ValidationError): pass diff --git a/webnotes/plugins.py b/webnotes/plugins.py index 4230c8beb5..e01741dc74 100644 --- a/webnotes/plugins.py +++ b/webnotes/plugins.py @@ -16,13 +16,10 @@ def exec_code(code, namespace=None): return namespace -def get_code(module, doctype, docname, plugin=None): - import MySQLdb - +def get_code(module, doctype, docname, plugin=None): try: code = read_file(module, doctype, docname, plugin, cache=True) - except MySQLdb.OperationalError: - # this happens when syncing + except webnotes.SQLError: return None return code diff --git a/webnotes/sessions.py b/webnotes/sessions.py index c4167a388f..cabcff0e1b 100644 --- a/webnotes/sessions.py +++ b/webnotes/sessions.py @@ -57,7 +57,7 @@ def clear_sessions(user=None, keep_current=False): def get(): """get session boot info""" - from webnotes.widgets.notification import get_notification_info_for_boot + from core.doctype.notification_count.notification_count import get_notification_info_for_boot bootinfo = None if not getattr(conf,'auto_cache_clear',None): diff --git a/webnotes/widgets/notification.py b/webnotes/widgets/notification.py deleted file mode 100644 index 6762169419..0000000000 --- a/webnotes/widgets/notification.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. -# MIT License. See license.txt - -from __future__ import unicode_literals -import webnotes - -@webnotes.whitelist() -def get(): - try: - from startup.open_count import for_doctype, for_module - except ImportError, e: - return {} - - can_read = webnotes.user.get_can_read() - open_count_doctype = {} - open_count_module = {} - - for d in for_doctype: - if d in can_read: - condition = for_doctype[d] - key = condition.keys()[0] - - result = webnotes.get_list(d, fields=["count(*)"], - filters=[[d, key, "=", condition[key]]], as_list=True)[0][0] - if result: - open_count_doctype[d] = result - - for m in for_module: - open_count_module[m] = for_module[m]() - - return { - "open_count_doctype": open_count_doctype, - "open_count_module": open_count_module - } - -def get_notification_info_for_boot(): - out = get() - - can_read = webnotes.user.get_can_read() - conditions = {} - module_doctypes = {} - doctype_info = dict(webnotes.conn.sql("""select name, module from tabDocType""")) - - try: - from startup.open_count import for_doctype - except ImportError: - for_doctype = {} - - for d in list(set(can_read + for_doctype.keys())): - if d in for_doctype: - conditions[d] = for_doctype[d] - - if d in doctype_info: - module_doctypes.setdefault(doctype_info[d], []).append(d) - - out.update({ - "conditions": conditions, - "module_doctypes": module_doctypes, - }) - - return out -