Browse Source

Remove flags in frappe.call, api, run_method, filter moduleview items by permission

version-14
Anand Doshi 10 years ago
parent
commit
ce9e3ed931
29 changed files with 177 additions and 68 deletions
  1. +8
    -2
      frappe/__init__.py
  2. +6
    -1
      frappe/api.py
  3. +9
    -5
      frappe/boot.py
  4. +3
    -0
      frappe/core/doctype/comment/comment.py
  5. +14
    -9
      frappe/core/doctype/docshare/docshare.py
  6. +12
    -2
      frappe/core/doctype/user/user.py
  7. +6
    -0
      frappe/core/page/desktop/desktop.js
  8. +33
    -0
      frappe/desk/moduleview.py
  9. +3
    -1
      frappe/desk/page/messages/messages.js
  10. +1
    -2
      frappe/desk/page/messages/messages.py
  11. +1
    -1
      frappe/desk/page/messages/messages_row.html
  12. +1
    -1
      frappe/desk/page/messages/messages_sidebar.html
  13. +2
    -0
      frappe/hooks.py
  14. +12
    -4
      frappe/model/delete_doc.py
  15. +4
    -1
      frappe/model/document.py
  16. +0
    -1
      frappe/modules/import_file.py
  17. +4
    -1
      frappe/public/css/desk.css
  18. BIN
      frappe/public/images/ui/into-the-dawn.jpg
  19. +11
    -1
      frappe/public/js/frappe/assets.js
  20. +0
    -5
      frappe/public/js/frappe/desk.js
  21. +3
    -1
      frappe/public/js/frappe/form/footer/timeline.js
  22. +1
    -1
      frappe/public/js/frappe/form/footer/timeline_item.html
  23. +1
    -4
      frappe/public/js/frappe/misc/user.js
  24. +0
    -4
      frappe/public/js/frappe/views/calendar.js
  25. +0
    -4
      frappe/public/js/frappe/views/ganttview.js
  26. +10
    -4
      frappe/public/less/desk.less
  27. +25
    -12
      frappe/share.py
  28. +3
    -0
      frappe/templates/pages/desk.html
  29. +4
    -1
      frappe/templates/pages/desk.py

+ 8
- 2
frappe/__init__.py View File

@@ -446,7 +446,8 @@ def get_meta(doctype, cached=True):
import frappe.model.meta
return frappe.model.meta.get_meta(doctype, cached=cached)

def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False, ignore_permissions=False):
def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False,
ignore_permissions=False, flags=None):
"""Delete a document. Calls `frappe.model.delete_doc.delete_doc`.

:param doctype: DocType of document to be delete.
@@ -456,7 +457,8 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa
:param for_reload: Call `before_reload` trigger before deleting.
:param ignore_permissions: Ignore user permissions."""
import frappe.model.delete_doc
frappe.model.delete_doc.delete_doc(doctype, name, force, ignore_doctypes, for_reload, ignore_permissions)
frappe.model.delete_doc.delete_doc(doctype, name, force, ignore_doctypes, for_reload,
ignore_permissions, flags)

def delete_doc_if_exists(doctype, name):
"""Delete document if exists."""
@@ -682,6 +684,10 @@ def call(fn, *args, **kwargs):
for a in fnargs:
if a in kwargs:
newargs[a] = kwargs.get(a)

if "flags" in newargs:
del newargs["flags"]

return fn(*args, **newargs)

def make_property_setter(args, ignore_validate=False, validate_fields_for_doctype=True):


+ 6
- 1
frappe/api.py View File

@@ -70,10 +70,15 @@ def handle():
if frappe.local.request.method=="PUT":
data = json.loads(frappe.local.form_dict.data)
doc = frappe.get_doc(doctype, name)

if "flags" in data:
del data["flags"]

# Not checking permissions here because it's checked in doc.save
doc.update(data)

frappe.local.response.update({
"data": doc.save().as_dict()
"data": doc.save().as_dict()
})
frappe.db.commit()



+ 9
- 5
frappe/boot.py View File

@@ -45,7 +45,7 @@ def get_bootinfo():
tabDocType where ifnull(icon,'')!=''"""))
bootinfo.single_types = frappe.db.sql_list("""select name from tabDocType where ifnull(issingle,0)=1""")
add_home_page(bootinfo, doclist)
add_allowed_pages(bootinfo)
bootinfo.page_info = get_allowed_pages()
load_translations(bootinfo)
add_timezone_info(bootinfo)
load_conf_settings(bootinfo)
@@ -65,6 +65,7 @@ def get_bootinfo():
bootinfo.lang = unicode(bootinfo.lang)

bootinfo.error_report_email = frappe.get_hooks("error_report_email")
bootinfo.default_background_image = "/assets/frappe/images/ui/into-the-dawn.jpg"

return bootinfo

@@ -73,9 +74,10 @@ def load_conf_settings(bootinfo):
for key in ['developer_mode']:
if key in conf: bootinfo[key] = conf.get(key)

def add_allowed_pages(bootinfo):
def get_allowed_pages():
roles = frappe.get_roles()
bootinfo.page_info = {}
page_info = {}

for p in frappe.db.sql("""select distinct
tabPage.name, tabPage.modified, tabPage.title
from `tabPage Role`, `tabPage`
@@ -83,7 +85,7 @@ def add_allowed_pages(bootinfo):
and `tabPage Role`.parent = `tabPage`.name""" % ', '.join(['%s']*len(roles)),
roles, as_dict=True):

bootinfo.page_info[p.name] = {"modified":p.modified, "title":p.title}
page_info[p.name] = {"modified":p.modified, "title":p.title}

# pages where role is not set are also allowed
for p in frappe.db.sql("""select name, modified, title
@@ -91,7 +93,9 @@ def add_allowed_pages(bootinfo):
(select count(*) from `tabPage Role`
where `tabPage Role`.parent=tabPage.name) = 0""", as_dict=1):

bootinfo.page_info[p.name] = {"modified":p.modified, "title":p.title}
page_info[p.name] = {"modified":p.modified, "title":p.title}

return page_info

def load_translations(bootinfo):
if frappe.local.lang != 'en':


+ 3
- 0
frappe/core/doctype/comment/comment.py View File

@@ -105,6 +105,9 @@ class Comment(Document):

def on_trash(self):
"""Removes from `_comments` in parent Document"""
if self.comment_doctype == "Message":
return

if (self.comment_type or "Comment") != "Comment":
frappe.only_for("System Manager")



+ 14
- 9
frappe/core/doctype/docshare/docshare.py View File

@@ -11,8 +11,9 @@ class DocShare(Document):
no_feed_on_delete = True

def validate(self):
self.check_share_permssion()
self.check_share_permission()
self.cascade_permissions_downwards()
self.get_doc().run_method("validate_share", self)

def cascade_permissions_downwards(self):
if self.share:
@@ -25,18 +26,22 @@ class DocShare(Document):
self._doc = frappe.get_doc(self.share_doctype, self.share_name)
return self._doc

def check_share_permssion(self):
if not frappe.has_permission(self.share_doctype, "share", self.get_doc()):
raise frappe.PermissionError
def check_share_permission(self):
if (not self.flags.ignore_share_permission and
not frappe.has_permission(self.share_doctype, "share", self.get_doc())):

frappe.throw(_('You need to have "Share" permission'), frappe.PermissionError)

def after_insert(self):
self.get_doc().add_comment(_("{0} shared this document with {0}").format(get_fullname(self.owner),
get_fullname(self.user)))
self.get_doc().add_comment("Shared",
_("{0} shared this document with {1}").format(get_fullname(self.owner), get_fullname(self.user)))

def on_trash(self):
self.check_share_permssion()
self.get_doc().add_comment(_("{0} un-shared this document with {0}").format(get_fullname(self.owner),
get_fullname(self.user)))
if not self.flags.ignore_share_permission:
self.check_share_permission()

self.get_doc().add_comment("Unshared",
_("{0} un-shared this document with {1}").format(get_fullname(self.owner), get_fullname(self.user)))

def on_doctype_update():
"""Add index in `tabDocShare` for `(user, share_doctype)`"""


+ 12
- 2
frappe/core/doctype/user/user.py View File

@@ -82,9 +82,19 @@ class User(Document):

def share_with_self(self):
if self.user_type=="System User":
frappe.share.add(self.doctype, self.name, self.name, share=1)
frappe.share.add(self.doctype, self.name, self.name, share=1,
flags={"ignore_share_permission": True})
else:
frappe.share.remove(self.doctype, self.name, self.name)
frappe.share.remove(self.doctype, self.name, self.name,
flags={"ignore_share_permission": True})

def validate_share(self, docshare):
if docshare.user == self.name:
if self.user_type=="System User":
if docshare.share != 1:
frappe.throw(_("Sorry! User should have complete access to their own record."))
else:
frappe.throw(_("Sorry! Sharing with Website User is prohibited."))

def clear_new_password(self):
new_password = self.new_password


+ 6
- 0
frappe/core/page/desktop/desktop.js View File

@@ -4,6 +4,7 @@ frappe.pages['desktop'].on_page_load = function(wrapper) {
frappe.assets.views["Module"]();

// load desktop
frappe.desktop.set_background();
frappe.desktop.refresh(wrapper);
};

@@ -130,6 +131,11 @@ $.extend(frappe.desktop, {
});
},

set_background: function() {
frappe.ui.set_user_background(frappe.boot.user.background_image, null,
frappe.boot.user.background_style);
},

all_applications: {
show: function() {
if(!this.dialog) {


+ 33
- 0
frappe/desk/moduleview.py View File

@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.boot import get_allowed_pages

@frappe.whitelist()
def get(module):
@@ -31,6 +32,7 @@ def get_data(module):
get_report_list(module))

data = combine_common_sections(data)
data = apply_permissions(data)

set_last_modified(data)

@@ -115,6 +117,37 @@ def combine_common_sections(data):

return sections

def apply_permissions(data):
default_country = frappe.db.get_default("country")

user = frappe.get_user(frappe.session.user)
user.build_permissions()

allowed_pages = get_allowed_pages()

new_data = []
for section in data:
new_items = []

for item in (section.get("items") or []):
item = frappe._dict(item)

if item.country and item.country!=default_country:
continue

if ((item.type=="doctype" and item.name in user.can_read)
or (item.type=="page" and item.name in allowed_pages)
or (item.type=="report" and item.doctype in user.can_get_report)):

new_items.append(item)

if new_items:
new_section = section.copy()
new_section["items"] = new_items
new_data.append(new_section)

return new_data

def get_config(app, module):
"""Load module info from `[app].config.[module]`."""
config = frappe.get_module("{app}.config.{module}".format(app=app, module=module))


+ 3
- 1
frappe/desk/page/messages/messages.js View File

@@ -7,10 +7,12 @@
frappe.provide('frappe.desk.pages.messages');

frappe.pages.messages.on_page_load = function(parent) {
frappe.assets.views["Form"]();

var page = frappe.ui.make_app_page({
parent: parent,
});
page.set_title(__("Messages"), frappe.get_module("Messages").icon);
page.set_title(__("Messages"));

frappe.desk.pages.messages = new frappe.desk.pages.messages(parent);
}


+ 1
- 2
frappe/desk/page/messages/messages.py View File

@@ -90,8 +90,7 @@ def post(txt, contact, parenttype=None, notify=False, subject=None):

@frappe.whitelist()
def delete(arg=None):
frappe.db.sql("""delete from `tabComment` where name=%s""",
frappe.form_dict['name']);
frappe.get_doc("Comment", frappe.form_dict['name']).delete()

def _notify(contact, txt, subject=None):
from frappe.utils import get_fullname, get_url


+ 1
- 1
frappe/desk/page/messages/messages_row.html View File

@@ -18,7 +18,7 @@
<div class="text-muted">
{%= comment_when(data.modified) %}
</div>
{% if (data.owner==user || data.comment.indexOf("assigned to")!=-1) { %}
{% if (data.owner==user /* && !data.comment_type && data.parenttype!="Assignment" */ ) { %}
<div>
<a class="delete text-extra-muted" data-name="{%= data.name %}"
onclick="frappe.desk.pages.messages.delete(this)">Delete</a>


+ 1
- 1
frappe/desk/page/messages/messages_sidebar.html View File

@@ -1,4 +1,4 @@
<ul class="nav nav-pills nav-stacked" style="margin-right: -15px;">
<ul class="nav nav-pills nav-stacked">
{% for (var i=0, l= data.length; i < l; i++) { var contact = data[i]; %}
<li data-user="{%= contact.name %}" class="h6 module-sidebar-item">
<a class="messages-sidebar-link text-ellipsis">


+ 2
- 0
frappe/hooks.py View File

@@ -94,3 +94,5 @@ scheduler_events = {
"frappe.email.doctype.email_alert.email_alert.trigger_daily_alerts",
]
}

default_background = "/assets/frappe/images/ui/into-the-dawn.jpg"

+ 12
- 4
frappe/model/delete_doc.py View File

@@ -11,7 +11,8 @@ from frappe import _
from rename_doc import dynamic_link_queries
from frappe.model.naming import revert_series_if_last

def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False, ignore_permissions=False):
def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False,
ignore_permissions=False, flags=None):
"""
Deletes a doc(dt, dn) and validates if it is not submitted and not linked in a live record
"""
@@ -58,7 +59,14 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa
doc = frappe.get_doc(doctype, name)

if not for_reload:
check_permission_and_not_submitted(doc, ignore_permissions)
if ignore_permissions:
if not flags: flags = {}
flags["ignore_permissions"] = ignore_permissions

if flags:
doc.flags.update(flags)

check_permission_and_not_submitted(doc)
doc.run_method("on_trash")

delete_linked_todos(doc)
@@ -113,9 +121,9 @@ def delete_from_table(doctype, name, ignore_doctypes, doc):
if t not in ignore_doctypes:
frappe.db.sql("delete from `tab%s` where parenttype=%s and parent = %s" % (t, '%s', '%s'), (doctype, name))

def check_permission_and_not_submitted(doc, ignore_permissions=False):
def check_permission_and_not_submitted(doc):
# permission
if not ignore_permissions and frappe.session.user!="Administrator" and not doc.has_permission("delete"):
if frappe.session.user!="Administrator" and not doc.has_permission("delete"):
frappe.msgprint(_("User not allowed to delete {0}: {1}").format(doc.doctype, doc.name), raise_exception=True)

# check if submitted


+ 4
- 1
frappe/model/document.py View File

@@ -448,6 +448,9 @@ class Document(BaseDocument):

def run_method(self, method, *args, **kwargs):
"""run standard triggers, plus those in hooks"""
if "flags" in kwargs:
del kwargs["flags"]

if hasattr(self, method) and hasattr(getattr(self, method), "__call__"):
fn = lambda self, *args, **kwargs: getattr(self, method)(*args, **kwargs)
else:
@@ -476,7 +479,7 @@ class Document(BaseDocument):

def delete(self):
"""Delete document."""
frappe.delete_doc(self.doctype, self.name)
frappe.delete_doc(self.doctype, self.name, flags=self.flags)

def run_before_save_methods(self):
"""Run standard methods before `INSERT` or `UPDATE`. Standard Methods are:


+ 0
- 1
frappe/modules/import_file.py View File

@@ -117,7 +117,6 @@ def import_doc(docdict, force=False, data_import=False):
doc.flags.ignore_validate = True
doc.flags.ignore_permissions = True
doc.flags.ignore_mandatory = True
doc.flags.ignore_user_permissions = True
doc.insert()

frappe.flags.in_import = False

+ 4
- 1
frappe/public/css/desk.css View File

@@ -306,13 +306,16 @@ kbd {
padding: 10px 15px;
}
.message-row .indicator {
margin-left: -10px;
margin-left: -5px;
margin-right: -20px;
}
.message-box .indicator {
margin-right: 15px;
margin-top: 7px;
}
.message-box .timeline-head {
padding-top: 30px;
}
.page-only-label {
margin-top: 5px;
text-align: center;


BIN
frappe/public/images/ui/into-the-dawn.jpg View File

Before After
Width: 1440  |  Height: 900  |  Size: 540 KiB

+ 11
- 1
frappe/public/js/frappe/assets.js View File

@@ -145,6 +145,16 @@ frappe.assets = {
"Module": function() {
frappe.require("assets/css/module.min.css");
frappe.require("assets/js/module.min.js");
}
},
"Calendar": function() {
frappe.assets.views["Report"]();
frappe.require('assets/frappe/js/lib/fullcalendar/fullcalendar.css');
frappe.require('assets/frappe/js/lib/fullcalendar/fullcalendar.js');
},
"Gantt": function() {
frappe.assets.views["Report"]();
frappe.require('assets/frappe/js/lib/jQuery.Gantt/css/style.css');
frappe.require('assets/frappe/js/lib/jQuery.Gantt/js/jquery.fn.gantt.js');
},
}
};

+ 0
- 5
frappe/public/js/frappe/desk.js View File

@@ -17,7 +17,6 @@ frappe.Application = Class.extend({
},
startup: function() {
this.load_bootinfo();
this.set_user_display_settings();
this.make_nav_bar();
this.set_favicon();
this.setup_keyboard_shortcuts();
@@ -44,10 +43,6 @@ frappe.Application = Class.extend({
$(document).trigger('app_ready');
},

set_user_display_settings: function() {
frappe.ui.set_user_background(frappe.boot.user.background_image, null,
frappe.boot.user.background_style);
},
load_bootinfo: function() {
if(frappe.boot) {
frappe.modules = frappe.boot.modules;


+ 3
- 1
frappe/public/js/frappe/form/footer/timeline.js View File

@@ -145,7 +145,9 @@ frappe.ui.form.Comments = Class.extend({
"Workflow": "octicon octicon-git-branch",
"Label": "octicon octicon-tag",
"Attachment": "octicon octicon-cloud-upload",
"Attachment Removed": "octicon octicon-trashcan"
"Attachment Removed": "octicon octicon-trashcan",
"Shared": "octicon octicon-eye",
"Unshared": "octicon octicon-circle-slash"
}[c.comment_type]

c.color = {


+ 1
- 1
frappe/public/js/frappe/form/footer/timeline_item.html View File

@@ -25,7 +25,7 @@
{%= data.comment_html %}
</div>
</div>
{% } else if(in_list(["Assignment Completed", "Assigned", "Shared"], data.comment_type)) { %}
{% } else if(in_list(["Assignment Completed", "Assigned", "Shared", "Unshared"], data.comment_type)) { %}
<h6>
<i class="{%= data.icon %} icon-fixed-width"></i>
{%= data.comment %}


+ 1
- 4
frappe/public/js/frappe/misc/user.js View File

@@ -36,10 +36,7 @@ frappe.get_gravatar = function(email_id) {
frappe.ui.set_user_background = function(src, selector, style) {
if(!selector) selector = "#page-desktop";
if(!style) style = "Fill Screen";
if(!src) src = "assets/frappe/images/ui/wallpaper-5.jpg";

// hack! load background image asap, before page is rendered
$('<img src="'+src+'" style="height: 1px; width: 1px; margin-bottom: -1px;">').appendTo("body");
if(!src) src = frappe.boot.default_background_image;

frappe.dom.set_style(repl('%(selector)s { \
background: url("%(src)s") center center;\


+ 0
- 4
frappe/public/js/frappe/views/calendar.js View File

@@ -22,10 +22,6 @@ frappe.views.CalendarFactory = frappe.views.Factory.extend({
frappe.views.Calendar = Class.extend({
init: function(options) {
$.extend(this, options);

frappe.require('assets/frappe/js/lib/fullcalendar/fullcalendar.css');
frappe.require('assets/frappe/js/lib/fullcalendar/fullcalendar.js');

this.make_page();
this.setup_options();
this.make();


+ 0
- 4
frappe/public/js/frappe/views/ganttview.js View File

@@ -26,10 +26,6 @@ frappe.views.GanttFactory = frappe.views.Factory.extend({
frappe.views.Gantt = Class.extend({
init: function(opts) {
$.extend(this, opts);

frappe.require('assets/frappe/js/lib/jQuery.Gantt/css/style.css');
frappe.require('assets/frappe/js/lib/jQuery.Gantt/js/jquery.fn.gantt.js');

this.make_page();
frappe.route_options ?
this.set_filters_from_route_options() :


+ 10
- 4
frappe/public/less/desk.less View File

@@ -353,13 +353,19 @@ kbd {
}

.message-row .indicator {
margin-left: -10px;
margin-left: -5px;
margin-right: -20px;
}

.message-box .indicator {
margin-right: 15px;
margin-top: 7px;
.message-box {
.indicator {
margin-right: 15px;
margin-top: 7px;
}

.timeline-head {
padding-top: 30px;
}
}

.page-only-label {


+ 25
- 12
frappe/share.py View File

@@ -3,6 +3,7 @@

from __future__ import unicode_literals
import frappe
from frappe.utils import cint

@frappe.whitelist()
def add(doctype, name, user=None, read=1, write=0, share=0, flags=None):
@@ -14,19 +15,30 @@ def add(doctype, name, user=None, read=1, write=0, share=0, flags=None):
"share_doctype": doctype})

if share_name:
frappe.delete_doc("DocShare", share_name)
doc = frappe.get_doc("DocShare", share_name)
else:
doc = frappe.new_doc("DocShare")
doc.update({
"user": user,
"share_doctype": doctype,
"share_name": name
})

if flags:
doc.flags.update(flags)

doc.update({
# always add read, since you are adding!
"read": 1,
"write": cint(write),
"share": cint(share)
})

doc.save(ignore_permissions=True)

return doc

return frappe.get_doc({
"doctype": "DocShare",
"user": user,
"share_doctype": doctype,
"share_name": name,
"read": read,
"write": write,
"share": share
}).insert(ignore_permissions=True)

def remove(doctype, name, user):
def remove(doctype, name, user, flags=None):
share_name = frappe.db.get_value("DocShare", {"user": user, "share_name": name,
"share_doctype": doctype})

@@ -48,6 +60,7 @@ def set_permission(doctype, name, user, permission_to, value=1):
pass
else:
share = frappe.get_doc("DocShare", share_name)
share.flags.ignore_permissions = True
share.set(permission_to, value)

if not value:


+ 3
- 0
frappe/templates/pages/desk.html View File

@@ -36,6 +36,9 @@
</div>
</div>

<!-- hack! load background image asap, before desktop is rendered -->
<img src="{{ background_image }}" style="height: 1px; width: 1px; margin-bottom: -1px;">

<script type="text/javascript" src="/assets/frappe/js/lib/jquery/jquery.min.js"></script>

<script type="text/javascript">


+ 4
- 1
frappe/templates/pages/desk.py View File

@@ -20,10 +20,13 @@ def get_context(context):
frappe.throw(_("You are not permitted to access this page."), frappe.PermissionError)

hooks = frappe.get_hooks()
boot = frappe.sessions.get()

return {
"build_version": str(os.path.getmtime(os.path.join(frappe.local.sites_path, "assets", "js",
"frappe.min.js"))),
"include_js": hooks["app_include_js"],
"include_css": hooks["app_include_css"],
"boot": json.dumps(frappe.sessions.get(), default=json_handler, indent=1, sort_keys=True)
"boot": json.dumps(boot, default=json_handler, indent=1, sort_keys=True),
"background_image": boot.user.background_image or boot.default_background_image
}

Loading…
Cancel
Save