Merge branch 'develop'

This commit is contained in:
Nabin Hait 2015-07-27 15:56:33 +05:30
commit dec7c6a348
60 changed files with 1915 additions and 1605 deletions

View file

@ -1,2 +1,2 @@
from __future__ import unicode_literals
__version__ = "5.1.3"
__version__ = "5.1.4"

View file

@ -4,7 +4,6 @@
from __future__ import unicode_literals, absolute_import
import sys
import os
import subprocess
import json
import click
import hashlib
@ -140,7 +139,7 @@ def reinstall(context):
frappe.clear_cache()
installed = frappe.get_installed_apps()
frappe.clear_cache()
except Exception, e:
except Exception:
installed = []
finally:
if frappe.db:
@ -191,8 +190,6 @@ def migrate(context, rebuild_website=False):
import frappe.translate
from frappe.desk.notifications import clear_notifications
verbose = context.verbose
for site in context.sites:
print 'Migrating', site
frappe.init(site=site)
@ -312,15 +309,16 @@ def destroy_all_sessions(context):
frappe.destroy()
@click.command('sync-www')
@click.option('--force', help='Rebuild all pages', is_flag=True, default=False)
@pass_context
def sync_www(context):
def sync_www(context, force=False):
"Sync files from static pages from www directory to Web Pages"
from frappe.website import statics
for site in context.sites:
try:
frappe.init(site=site)
frappe.connect()
statics.sync_statics(rebuild=context.force)
statics.sync_statics(rebuild=force)
frappe.db.commit()
finally:
frappe.destroy()
@ -341,32 +339,17 @@ def build_website(context):
frappe.destroy()
@click.command('setup-docs')
@click.argument('app')
@click.argument('docs-app')
@click.argument('path')
@pass_context
def setup_docs(context,app, docs_app, path):
def setup_docs(context):
"Setup docs in target folder of target app"
from frappe.utils.setup_docs import setup_docs
from frappe.website import statics
for site in context.sites:
try:
frappe.init(site=site)
frappe.connect()
setup_docs(app, docs_app, path)
finally:
frappe.destroy()
@click.command('build-docs')
@click.argument('app')
@pass_context
def build_docs(context, app):
"Build docs from /src to /www folder in app"
from frappe.utils.autodoc import build
frappe.destroy()
for site in context.sites:
try:
frappe.init(site=site)
build(app)
setup_docs()
statics.sync_statics(rebuild=True)
finally:
frappe.destroy()
@ -826,7 +809,6 @@ commands = [
sync_www,
build_website,
setup_docs,
build_docs,
reset_perms,
execute,
celery,

View file

@ -11,7 +11,6 @@ from frappe.utils import get_fullname
class Comment(Document):
"""Comments are added to Documents via forms or views like blogs etc."""
__doclink__ = "https://frappe.io/docs/models/core/comment"
no_feed_on_delete = True
def get_feed(self):
@ -134,4 +133,3 @@ def on_doctype_update():
frappe.db.commit()
frappe.db.sql("""alter table `tabComment`
add index comment_doctype_docname_index(comment_doctype, comment_docname)""")

View file

@ -6,5 +6,4 @@ from __future__ import unicode_literals
from frappe.model.document import Document
class DocField(Document):
__doclink__ = "https://frappe.io/docs/models/core/docfield"
pass

View file

@ -33,6 +33,14 @@
"label": "Apply User Permissions",
"permlevel": 0
},
{
"description": "Apply this rule if the User is the Owner",
"fieldname": "if_owner",
"fieldtype": "Check",
"label": "If user is the owner",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "column_break_2",
"fieldtype": "Column Break",
@ -232,7 +240,7 @@
"idx": 1,
"issingle": 0,
"istable": 1,
"modified": "2015-03-18 06:09:58.928014",
"modified": "2015-07-22 07:39:40.471092",
"modified_by": "Administrator",
"module": "Core",
"name": "DocPerm",

View file

@ -7,5 +7,4 @@ import frappe
from frappe.model.document import Document
class DocPerm(Document):
__doclink__ = "https://frappe.io/docs/models/v5.x/core/docperm"
pass

View file

@ -18,7 +18,6 @@ form_grid_templates = {
}
class DocType(Document):
__doclink__ = "https://frappe.io/docs/models/core/doctype"
def get_feed(self):
return self.name
@ -363,14 +362,21 @@ def validate_permissions(doctype, for_remove=False):
def check_double(d):
has_similar = False
similar_because_of = ""
for p in permissions:
if (p.role==d.role and p.permlevel==d.permlevel
and p.apply_user_permissions==d.apply_user_permissions and p!=d):
has_similar = True
break
if p.role==d.role and p.permlevel==d.permlevel and p!=d:
if p.apply_user_permissions==d.apply_user_permissions:
has_similar = True
similar_because_of = _("Apply User Permissions")
break
elif p.if_owner==d.if_owner:
similar_because_of = _("If Owner")
has_similar = True
break
if has_similar:
frappe.throw(_("{0}: Only one rule allowed with the same Role, Level and Apply User Permissions").format(get_txt(d)))
frappe.throw(_("{0}: Only one rule allowed with the same Role, Level and {1}")\
.format(get_txt(d), similar_because_of))
def check_level_zero_is_set(d):
if cint(d.permlevel) > 0 and d.role != 'All':
@ -467,4 +473,3 @@ def init_list(doctype):
doc = frappe.get_meta(doctype)
make_boilerplate("controller_list.js", doc)
make_boilerplate("controller_list.html", doc)

View file

@ -7,7 +7,6 @@ import frappe, os
from frappe.model.document import Document
class ModuleDef(Document):
__doclink__ = "https://frappe.io/docs/models/core/module_def"
def on_update(self):
"""If in `developer_mode`, create folder for module and
add in `modules.txt` of app if missing."""
@ -39,7 +38,3 @@ class ModuleDef(Document):
frappe.clear_cache()
frappe.setup_module_map()

View file

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe.build import html_to_js_template
from frappe import conf
class Page(Document):
def autoname(self):
@ -36,7 +37,6 @@ class Page(Document):
Writes the .txt for this page and if write_content is checked,
it will write out a .html file
"""
from frappe import conf
from frappe.core.doctype.doctype.doctype import make_module_and_roles
make_module_and_roles(self, "roles")

View file

@ -1,519 +1,519 @@
{
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 1,
"creation": "2014-03-11 14:55:00",
"description": "Represents a User in the system.",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Master",
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 1,
"creation": "2014-03-11 14:55:00",
"description": "Represents a User in the system.",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Master",
"fields": [
{
"fieldname": "sb0_5",
"fieldtype": "Section Break",
"label": "",
"fieldname": "sb0_5",
"fieldtype": "Section Break",
"label": "",
"permlevel": 0
},
},
{
"default": "1",
"fieldname": "enabled",
"fieldtype": "Check",
"in_list_view": 0,
"label": "Enabled",
"no_copy": 0,
"oldfieldname": "enabled",
"oldfieldtype": "Check",
"permlevel": 0,
"default": "1",
"fieldname": "enabled",
"fieldtype": "Check",
"in_list_view": 0,
"label": "Enabled",
"no_copy": 0,
"oldfieldname": "enabled",
"oldfieldtype": "Check",
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "section_break_3",
"fieldtype": "Section Break",
"permlevel": 0,
"fieldname": "section_break_3",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "email",
"fieldtype": "Data",
"hidden": 0,
"label": "Email",
"no_copy": 1,
"oldfieldname": "email",
"oldfieldtype": "Data",
"options": "Email",
"permlevel": 0,
"reqd": 1,
"fieldname": "email",
"fieldtype": "Data",
"hidden": 0,
"label": "Email",
"no_copy": 1,
"oldfieldname": "email",
"oldfieldtype": "Data",
"options": "Email",
"permlevel": 0,
"reqd": 1,
"search_index": 0
},
},
{
"fieldname": "first_name",
"fieldtype": "Data",
"in_list_view": 0,
"label": "First Name",
"no_copy": 0,
"oldfieldname": "first_name",
"oldfieldtype": "Data",
"permlevel": 0,
"fieldname": "first_name",
"fieldtype": "Data",
"in_list_view": 0,
"label": "First Name",
"no_copy": 0,
"oldfieldname": "first_name",
"oldfieldtype": "Data",
"permlevel": 0,
"reqd": 1
},
},
{
"fieldname": "middle_name",
"fieldtype": "Data",
"label": "Middle Name (Optional)",
"no_copy": 0,
"oldfieldname": "middle_name",
"oldfieldtype": "Data",
"fieldname": "middle_name",
"fieldtype": "Data",
"label": "Middle Name (Optional)",
"no_copy": 0,
"oldfieldname": "middle_name",
"oldfieldtype": "Data",
"permlevel": 0
},
},
{
"fieldname": "last_name",
"fieldtype": "Data",
"in_list_view": 0,
"label": "Last Name",
"oldfieldname": "last_name",
"oldfieldtype": "Data",
"fieldname": "last_name",
"fieldtype": "Data",
"in_list_view": 0,
"label": "Last Name",
"oldfieldname": "last_name",
"oldfieldtype": "Data",
"permlevel": 0
},
},
{
"default": "1",
"depends_on": "eval:doc.__islocal",
"fieldname": "send_welcome_email",
"fieldtype": "Check",
"label": "Send Welcome Email",
"permlevel": 0,
"default": "1",
"depends_on": "eval:doc.__islocal",
"fieldname": "send_welcome_email",
"fieldtype": "Check",
"label": "Send Welcome Email",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "unsubscribed",
"fieldtype": "Check",
"hidden": 1,
"label": "Unsubscribed",
"no_copy": 1,
"fieldname": "unsubscribed",
"fieldtype": "Check",
"hidden": 1,
"label": "Unsubscribed",
"no_copy": 1,
"permlevel": 0
},
},
{
"fieldname": "column_break0",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
"permlevel": 0,
"print_width": "50%",
"fieldname": "column_break0",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
"permlevel": 0,
"print_width": "50%",
"width": "50%"
},
},
{
"description": "",
"fieldname": "language",
"fieldtype": "Select",
"label": "Language",
"options": "Loading...",
"description": "",
"fieldname": "language",
"fieldtype": "Select",
"label": "Language",
"options": "Loading...",
"permlevel": 0
},
},
{
"description": "",
"fieldname": "time_zone",
"fieldtype": "Select",
"label": "Timezone",
"description": "",
"fieldname": "time_zone",
"fieldtype": "Select",
"label": "Timezone",
"permlevel": 0
},
},
{
"depends_on": "eval:!doc.__islocal",
"fieldname": "change_password",
"fieldtype": "Section Break",
"label": "",
"depends_on": "eval:!doc.__islocal",
"fieldname": "change_password",
"fieldtype": "Section Break",
"label": "",
"permlevel": 0
},
},
{
"fieldname": "new_password",
"fieldtype": "Password",
"label": "Set New Password",
"no_copy": 1,
"fieldname": "new_password",
"fieldtype": "Password",
"label": "Set New Password",
"no_copy": 1,
"permlevel": 0
},
},
{
"depends_on": "",
"fieldname": "send_password_update_notification",
"fieldtype": "Check",
"label": "Send Password Update Notification",
"permlevel": 0,
"depends_on": "",
"fieldname": "send_password_update_notification",
"fieldtype": "Check",
"label": "Send Password Update Notification",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "reset_password_key",
"fieldtype": "Data",
"hidden": 1,
"label": "Reset Password Key",
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"fieldname": "reset_password_key",
"fieldtype": "Data",
"hidden": 1,
"label": "Reset Password Key",
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
},
{
"depends_on": "eval:!doc.__islocal",
"fieldname": "display_settings",
"fieldtype": "Section Break",
"label": "",
"depends_on": "eval:!doc.__islocal",
"fieldname": "display_settings",
"fieldtype": "Section Break",
"label": "",
"permlevel": 0
},
},
{
"description": "Get your globally recognized avatar from <a href=\"https://gravatar.com/\">Gravatar.com</a>",
"fieldname": "user_image",
"fieldtype": "Attach",
"hidden": 0,
"label": "User Image",
"no_copy": 1,
"description": "Get your globally recognized avatar from Gravatar.com",
"fieldname": "user_image",
"fieldtype": "Attach",
"hidden": 0,
"label": "User Image",
"no_copy": 1,
"permlevel": 0
},
},
{
"fieldname": "cb21",
"fieldtype": "Column Break",
"fieldname": "cb21",
"fieldtype": "Column Break",
"permlevel": 0
},
},
{
"fieldname": "user_image_show",
"fieldtype": "Image",
"label": "user_image_show",
"options": "user_image",
"fieldname": "user_image_show",
"fieldtype": "Image",
"label": "user_image_show",
"options": "user_image",
"permlevel": 0
},
},
{
"fieldname": "email_settings",
"fieldtype": "Section Break",
"label": "Email Settings",
"permlevel": 0,
"fieldname": "email_settings",
"fieldtype": "Section Break",
"label": "Email Settings",
"permlevel": 0,
"precision": ""
},
},
{
"default": "1",
"fieldname": "thread_notify",
"fieldtype": "Check",
"label": "Send Notifications for Transactions I Follow",
"permlevel": 0,
"default": "1",
"fieldname": "thread_notify",
"fieldtype": "Check",
"label": "Send Notifications for Transactions I Follow",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "email_signature",
"fieldtype": "Small Text",
"label": "Email Signature",
"no_copy": 1,
"fieldname": "email_signature",
"fieldtype": "Small Text",
"label": "Email Signature",
"no_copy": 1,
"permlevel": 0
},
},
{
"fieldname": "background",
"fieldtype": "Section Break",
"label": "",
"permlevel": 0,
"fieldname": "background",
"fieldtype": "Section Break",
"label": "",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "background_image",
"fieldtype": "Attach",
"label": "Background Image",
"permlevel": 0,
"fieldname": "background_image",
"fieldtype": "Attach",
"label": "Background Image",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "background_style",
"fieldtype": "Select",
"label": "Background Style",
"options": "Fill Screen\nTile",
"permlevel": 0,
"fieldname": "background_style",
"fieldtype": "Select",
"label": "Background Style",
"options": "Fill Screen\nTile",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "short_bio",
"fieldtype": "Section Break",
"label": "",
"fieldname": "short_bio",
"fieldtype": "Section Break",
"label": "",
"permlevel": 0
},
},
{
"fieldname": "gender",
"fieldtype": "Select",
"label": "Gender",
"oldfieldname": "gender",
"oldfieldtype": "Select",
"options": "\nMale\nFemale\nOther",
"permlevel": 0,
"fieldname": "gender",
"fieldtype": "Select",
"label": "Gender",
"oldfieldname": "gender",
"oldfieldtype": "Select",
"options": "\nMale\nFemale\nOther",
"permlevel": 0,
"search_index": 0
},
},
{
"fieldname": "birth_date",
"fieldtype": "Date",
"label": "Birth Date",
"no_copy": 1,
"oldfieldname": "birth_date",
"oldfieldtype": "Date",
"fieldname": "birth_date",
"fieldtype": "Date",
"label": "Birth Date",
"no_copy": 1,
"oldfieldname": "birth_date",
"oldfieldtype": "Date",
"permlevel": 0
},
},
{
"fieldname": "location",
"fieldtype": "Data",
"label": "Location",
"no_copy": 1,
"fieldname": "location",
"fieldtype": "Data",
"label": "Location",
"no_copy": 1,
"permlevel": 0
},
},
{
"fieldname": "column_break_22",
"fieldtype": "Column Break",
"fieldname": "column_break_22",
"fieldtype": "Column Break",
"permlevel": 0
},
},
{
"fieldname": "bio",
"fieldtype": "Small Text",
"label": "Bio",
"no_copy": 1,
"permlevel": 0,
"fieldname": "bio",
"fieldtype": "Small Text",
"label": "Bio",
"no_copy": 1,
"permlevel": 0,
"set_only_once": 0
},
},
{
"description": "Check / Uncheck roles assigned to the User. Click on the Role to find out what permissions that Role has.",
"fieldname": "sb1",
"fieldtype": "Section Break",
"label": "Roles",
"permlevel": 1,
"description": "Check / Uncheck roles assigned to the User. Click on the Role to find out what permissions that Role has.",
"fieldname": "sb1",
"fieldtype": "Section Break",
"label": "Roles",
"permlevel": 1,
"read_only": 1
},
},
{
"fieldname": "roles_html",
"fieldtype": "HTML",
"label": "Roles HTML",
"permlevel": 0,
"fieldname": "roles_html",
"fieldtype": "HTML",
"label": "Roles HTML",
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "user_roles",
"fieldtype": "Table",
"hidden": 1,
"label": "Roles Assigned",
"options": "UserRole",
"permlevel": 1,
"print_hide": 1,
"fieldname": "user_roles",
"fieldtype": "Table",
"hidden": 1,
"label": "Roles Assigned",
"options": "UserRole",
"permlevel": 1,
"print_hide": 1,
"read_only": 1
},
},
{
"default": "",
"description": "Uncheck modules to hide from user's desktop",
"fieldname": "modules_access",
"fieldtype": "Section Break",
"label": "Modules Access",
"permlevel": 1,
"default": "",
"description": "Uncheck modules to hide from user's desktop",
"fieldname": "modules_access",
"fieldtype": "Section Break",
"label": "Modules Access",
"permlevel": 1,
"precision": ""
},
},
{
"fieldname": "modules_html",
"fieldtype": "HTML",
"label": "Modules HTML",
"permlevel": 1,
"fieldname": "modules_html",
"fieldtype": "HTML",
"label": "Modules HTML",
"permlevel": 1,
"precision": ""
},
},
{
"fieldname": "block_modules",
"fieldtype": "Table",
"hidden": 1,
"label": "Block Modules",
"options": "Block Module",
"permlevel": 1,
"fieldname": "block_modules",
"fieldtype": "Table",
"hidden": 1,
"label": "Block Modules",
"options": "Block Module",
"permlevel": 1,
"precision": ""
},
},
{
"description": "These values will be automatically updated in transactions and also will be useful to restrict permissions for this user on transactions containing these values.",
"fieldname": "sb2",
"fieldtype": "Section Break",
"hidden": 1,
"label": "Defaults",
"oldfieldtype": "Column Break",
"permlevel": 1,
"print_width": "50%",
"read_only": 1,
"description": "These values will be automatically updated in transactions and also will be useful to restrict permissions for this user on transactions containing these values.",
"fieldname": "sb2",
"fieldtype": "Section Break",
"hidden": 1,
"label": "Defaults",
"oldfieldtype": "Column Break",
"permlevel": 1,
"print_width": "50%",
"read_only": 1,
"width": "50%"
},
},
{
"description": "Enter default value fields (keys) and values. If you add multiple values for a field, the first one will be picked. These defaults are also used to set \"match\" permission rules. To see list of fields, go to <a href=\"#Form/Customize Form/Customize Form\">Customize Form</a>.",
"fieldname": "defaults",
"fieldtype": "Table",
"hidden": 1,
"label": "User Defaults",
"no_copy": 1,
"options": "DefaultValue",
"description": "Enter default value fields (keys) and values. If you add multiple values for a field, the first one will be picked. These defaults are also used to set \"match\" permission rules. To see list of fields, go to \"Customize Form\".",
"fieldname": "defaults",
"fieldtype": "Table",
"hidden": 1,
"label": "User Defaults",
"no_copy": 1,
"options": "DefaultValue",
"permlevel": 0
},
},
{
"fieldname": "sb3",
"fieldtype": "Section Break",
"label": "Security Settings",
"oldfieldtype": "Section Break",
"permlevel": 0,
"fieldname": "sb3",
"fieldtype": "Section Break",
"label": "Security Settings",
"oldfieldtype": "Section Break",
"permlevel": 0,
"read_only": 1
},
},
{
"default": "System User",
"description": "User Type \"System User\" can access Desktop. \"Website User\" can only be logged into the website and portal pages. ",
"fieldname": "user_type",
"fieldtype": "Select",
"in_list_view": 1,
"label": "User Type",
"oldfieldname": "user_type",
"oldfieldtype": "Select",
"options": "System User\nWebsite User",
"permlevel": 0,
"read_only": 1,
"default": "System User",
"description": "User Type \"System User\" can access Desktop. \"Website User\" can only be logged into the website and portal pages. ",
"fieldname": "user_type",
"fieldtype": "Select",
"in_list_view": 1,
"label": "User Type",
"oldfieldname": "user_type",
"oldfieldtype": "Select",
"options": "System User\nWebsite User",
"permlevel": 0,
"read_only": 1,
"reqd": 1
},
},
{
"description": "Allow user to login only after this hour (0-24)",
"fieldname": "login_after",
"fieldtype": "Int",
"label": "Login After",
"permlevel": 0,
"description": "Allow user to login only after this hour (0-24)",
"fieldname": "login_after",
"fieldtype": "Int",
"label": "Login After",
"permlevel": 0,
"read_only": 1
},
},
{
"description": "Allow user to login only before this hour (0-24)",
"fieldname": "login_before",
"fieldtype": "Int",
"label": "Login Before",
"permlevel": 0,
"description": "Allow user to login only before this hour (0-24)",
"fieldname": "login_before",
"fieldtype": "Int",
"label": "Login Before",
"permlevel": 0,
"read_only": 1
},
},
{
"description": "Restrict user from this IP address only. Multiple IP addresses can be added by separating with commas. Also accepts partial IP addresses like (111.111.111)",
"fieldname": "restrict_ip",
"fieldtype": "Data",
"label": "Restrict IP",
"permlevel": 0,
"description": "Restrict user from this IP address only. Multiple IP addresses can be added by separating with commas. Also accepts partial IP addresses like (111.111.111)",
"fieldname": "restrict_ip",
"fieldtype": "Data",
"label": "Restrict IP",
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "column_break1",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
"permlevel": 0,
"print_width": "50%",
"fieldname": "column_break1",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
"permlevel": 0,
"print_width": "50%",
"width": "50%"
},
},
{
"fieldname": "last_login",
"fieldtype": "Read Only",
"hidden": 0,
"label": "Last Login",
"no_copy": 1,
"oldfieldname": "last_login",
"oldfieldtype": "Read Only",
"permlevel": 0,
"read_only": 1,
"reqd": 0,
"fieldname": "last_login",
"fieldtype": "Read Only",
"hidden": 0,
"label": "Last Login",
"no_copy": 1,
"oldfieldname": "last_login",
"oldfieldtype": "Read Only",
"permlevel": 0,
"read_only": 1,
"reqd": 0,
"search_index": 0
},
},
{
"fieldname": "last_ip",
"fieldtype": "Read Only",
"label": "Last IP",
"no_copy": 1,
"oldfieldname": "last_ip",
"oldfieldtype": "Read Only",
"permlevel": 0,
"fieldname": "last_ip",
"fieldtype": "Read Only",
"label": "Last IP",
"no_copy": 1,
"oldfieldname": "last_ip",
"oldfieldtype": "Read Only",
"permlevel": 0,
"read_only": 1
},
},
{
"description": "Stores the JSON of last known versions of various installed apps. It is used to show release notes.",
"fieldname": "last_known_versions",
"fieldtype": "Text",
"hidden": 1,
"label": "Last Known Versions",
"permlevel": 0,
"precision": "",
"description": "Stores the JSON of last known versions of various installed apps. It is used to show release notes.",
"fieldname": "last_known_versions",
"fieldtype": "Text",
"hidden": 1,
"label": "Last Known Versions",
"permlevel": 0,
"precision": "",
"read_only": 1
},
},
{
"fieldname": "third_party_authentication",
"fieldtype": "Section Break",
"label": "Third Party Authentication",
"fieldname": "third_party_authentication",
"fieldtype": "Section Break",
"label": "Third Party Authentication",
"permlevel": 1
},
},
{
"fieldname": "fb_username",
"fieldtype": "Data",
"label": "Facebook Username",
"no_copy": 1,
"permlevel": 0,
"fieldname": "fb_username",
"fieldtype": "Data",
"label": "Facebook Username",
"no_copy": 1,
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "fb_userid",
"fieldtype": "Data",
"label": "Facebook User ID",
"no_copy": 1,
"permlevel": 0,
"fieldname": "fb_userid",
"fieldtype": "Data",
"label": "Facebook User ID",
"no_copy": 1,
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "google_userid",
"fieldtype": "Data",
"label": "Google User ID",
"no_copy": 1,
"permlevel": 0,
"fieldname": "google_userid",
"fieldtype": "Data",
"label": "Google User ID",
"no_copy": 1,
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "column_break_49",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "column_break_49",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "github_userid",
"fieldtype": "Data",
"label": "Github User ID",
"no_copy": 1,
"permlevel": 0,
"fieldname": "github_userid",
"fieldtype": "Data",
"label": "Github User ID",
"no_copy": 1,
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "github_username",
"fieldtype": "Data",
"label": "Github Username",
"no_copy": 1,
"permlevel": 0,
"fieldname": "github_username",
"fieldtype": "Data",
"label": "Github Username",
"no_copy": 1,
"permlevel": 0,
"read_only": 1
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "icon-user",
"idx": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 5,
"modified": "2015-06-01 01:00:32.901851",
"modified_by": "Administrator",
"module": "Core",
"name": "User",
"owner": "Administrator",
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "icon-user",
"idx": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 5,
"modified": "2015-07-27 01:00:32.901851",
"modified_by": "Administrator",
"module": "Core",
"name": "User",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"submit": 0,
"create": 1,
"delete": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"submit": 0,
"write": 1
},
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"permlevel": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"submit": 0,
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"permlevel": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"submit": 0,
"write": 1
}
],
"read_only": 0,
],
"read_only": 0,
"search_fields": "first_name, last_name"
}
}

View file

@ -30,12 +30,13 @@ def get_doctype_options():
doctype = frappe.form_dict['doctype']
return [doctype] + [d.options for d in frappe.get_meta(doctype).get_table_fields()]
def import_file_by_path(path, ignore_links=False, overwrite=False, submit=False):
def import_file_by_path(path, ignore_links=False, overwrite=False, submit=False, pre_process=None):
from frappe.utils.csvutils import read_csv_content
from frappe.core.page.data_import_tool.importer import upload
print "Importing " + path
with open(path, "r") as infile:
upload(rows = read_csv_content(infile.read()), ignore_links=ignore_links, overwrite=overwrite, submit_after_import=submit)
upload(rows = read_csv_content(infile.read()), ignore_links=ignore_links, overwrite=overwrite,
submit_after_import=submit, pre_process=pre_process)
def export_csv(doctype, path):
from frappe.core.page.data_import_tool.exporter import get_template
@ -80,7 +81,8 @@ def export_fixture(doctype, app):
export_json(doctype, frappe.get_app_path(app, "fixtures", frappe.scrub(doctype) + ".json"))
def import_doc(path, overwrite=False, ignore_links=False, ignore_insert=False, insert=False, submit=False):
def import_doc(path, overwrite=False, ignore_links=False, ignore_insert=False,
insert=False, submit=False, pre_process=None):
if os.path.isdir(path):
files = [os.path.join(path, f) for f in os.listdir(path)]
else:
@ -89,8 +91,8 @@ def import_doc(path, overwrite=False, ignore_links=False, ignore_insert=False, i
for f in files:
if f.endswith(".json"):
frappe.flags.mute_emails = True
frappe.modules.import_file.import_file_by_path(f, data_import=True, force=True)
frappe.modules.import_file.import_file_by_path(f, data_import=True, force=True, pre_process=pre_process)
frappe.flags.mute_emails = False
elif f.endswith(".csv"):
import_file_by_path(f, ignore_links=ignore_links, overwrite=overwrite, submit=submit)
import_file_by_path(f, ignore_links=ignore_links, overwrite=overwrite, submit=submit, pre_process=pre_process)
frappe.db.commit()

View file

@ -15,7 +15,8 @@ from frappe.utils import cint, cstr, flt
from frappe.core.page.data_import_tool.data_import_tool import get_data_keys
@frappe.whitelist()
def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, overwrite=None, ignore_links=False):
def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, overwrite=None,
ignore_links=False, pre_process=None):
"""upload data"""
frappe.flags.mute_emails = True
# extra input params
@ -200,6 +201,9 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False,
doc = None
doc = get_doc(row_idx)
if pre_process:
pre_process(doc)
try:
frappe.local.message_log = []
if parentfield:

View file

@ -191,6 +191,7 @@ frappe.PermissionEngine = Class.extend({
if (d.permlevel===0) {
me.setup_user_permissions(d, role_cell);
me.setup_if_owner(d, role_cell);
}
var cell = me.add_cell(row, d, "permlevel");
@ -269,6 +270,12 @@ frappe.PermissionEngine = Class.extend({
d.help = "";
},
setup_if_owner: function(d, role_cell) {
var checkbox = this.add_check(role_cell, d, "if_owner")
.removeClass("col-md-4")
.css({"margin-top": "15px"});
},
rights: ["read", "write", "create", "delete", "submit", "cancel", "amend",
"print", "email", "report", "import", "export", "set_user_permissions"],

View file

@ -19,7 +19,7 @@ def get_roles_and_doctypes():
name not in ('DocType') and
exists(select * from `tabDocField` where parent=dt.name)""")],
"roles": [d[0] for d in frappe.db.sql("""select name from tabRole where name not in
('Guest', 'Administrator')""")]
('Administrator')""")]
}
@frappe.whitelist()

View file

@ -52,7 +52,7 @@ cur_frm.cscript.fieldtype = function(doc, dt, dn) {
__('Name of the Document Type (DocType) you want this field to be linked to. e.g. Customer');
} else if(doc.fieldtype == 'Select') {
cur_frm.fields_dict['options_help'].disp_area.innerHTML =
__('Options for select. Each option on a new line. e.g.: <br>Option 1<br>Option 2<br>Option 3<br>');
__('Options for select. Each option on a new line.')+' '+__('e.g.:')+'<br>'+__('Option 1')+'<br>'+__('Option 2')+'<br>'+__('Option 3')+'<br>';
} else if(doc.fieldtype == 'Dynamic Link') {
cur_frm.fields_dict['options_help'].disp_area.innerHTML =
__('Fieldname which will be the DocType for this link field.');

View file

@ -1,136 +1,136 @@
{
"autoname": "DL.####",
"creation": "2013-01-29 17:55:08",
"docstatus": 0,
"doctype": "DocType",
"autoname": "DL.####",
"creation": "2013-01-29 17:55:08",
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"fieldname": "doc_type",
"fieldtype": "Link",
"hidden": 0,
"in_list_view": 1,
"label": "Enter Form Type",
"no_copy": 0,
"options": "DocType",
"permlevel": 0,
"fieldname": "doc_type",
"fieldtype": "Link",
"hidden": 0,
"in_list_view": 1,
"label": "Enter Form Type",
"no_copy": 0,
"options": "DocType",
"permlevel": 0,
"search_index": 0
},
},
{
"depends_on": "doc_type",
"fieldname": "properties",
"fieldtype": "Section Break",
"label": "",
"depends_on": "doc_type",
"fieldname": "properties",
"fieldtype": "Section Break",
"label": "",
"permlevel": 0
},
},
{
"fieldname": "default_print_format",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Default Print Format",
"no_copy": 0,
"options": "Print Format",
"permlevel": 0,
"fieldname": "default_print_format",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Default Print Format",
"no_copy": 0,
"options": "Print Format",
"permlevel": 0,
"search_index": 0
},
},
{
"description": "Fields separated by comma (,) will be included in the<br /><b>Search By</b> list of Search dialog box",
"fieldname": "search_fields",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Search Fields",
"no_copy": 0,
"permlevel": 0,
"description": "Fields separated by comma (,) will be included in the \"Search By\" list of Search dialog box",
"fieldname": "search_fields",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Search Fields",
"no_copy": 0,
"permlevel": 0,
"search_index": 0
},
},
{
"fieldname": "column_break_5",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "column_break_5",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
},
{
"depends_on": "",
"fieldname": "max_attachments",
"fieldtype": "Int",
"label": "Max Attachments",
"no_copy": 0,
"permlevel": 0,
"depends_on": "",
"fieldname": "max_attachments",
"fieldtype": "Int",
"label": "Max Attachments",
"no_copy": 0,
"permlevel": 0,
"search_index": 0
},
},
{
"fieldname": "allow_copy",
"fieldtype": "Check",
"label": "Hide Copy",
"no_copy": 0,
"permlevel": 0,
"fieldname": "allow_copy",
"fieldtype": "Check",
"label": "Hide Copy",
"no_copy": 0,
"permlevel": 0,
"search_index": 0
},
},
{
"depends_on": "doc_type",
"fieldname": "section_break_8",
"fieldtype": "Section Break",
"permlevel": 0,
"depends_on": "doc_type",
"fieldname": "section_break_8",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "sort_field",
"fieldtype": "Select",
"label": "Sort Field",
"fieldname": "sort_field",
"fieldtype": "Select",
"label": "Sort Field",
"permlevel": 0
},
},
{
"fieldname": "column_break_10",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "column_break_10",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "sort_order",
"fieldtype": "Select",
"label": "Sort Order",
"options": "ASC\nDESC",
"fieldname": "sort_order",
"fieldtype": "Select",
"label": "Sort Order",
"options": "ASC\nDESC",
"permlevel": 0
},
},
{
"depends_on": "doc_type",
"description": "Customize Label, Print Hide, Default etc.",
"fieldname": "fields_section_break",
"fieldtype": "Section Break",
"label": "Fields",
"depends_on": "doc_type",
"description": "Customize Label, Print Hide, Default etc.",
"fieldname": "fields_section_break",
"fieldtype": "Section Break",
"label": "Fields",
"permlevel": 0
},
},
{
"fieldname": "fields",
"fieldtype": "Table",
"label": "Fields",
"no_copy": 0,
"options": "Customize Form Field",
"permlevel": 0,
"fieldname": "fields",
"fieldtype": "Table",
"label": "Fields",
"no_copy": 0,
"options": "Customize Form Field",
"permlevel": 0,
"search_index": 0
}
],
"hide_toolbar": 1,
"icon": "icon-glass",
"idx": 1,
"issingle": 1,
"modified": "2015-03-25 06:18:19.010091",
"modified_by": "Administrator",
"module": "Custom",
"name": "Customize Form",
"owner": "Administrator",
],
"hide_toolbar": 1,
"icon": "icon-glass",
"idx": 1,
"issingle": 1,
"modified": "2015-07-27 01:00:32.901851",
"modified_by": "Administrator",
"module": "Custom",
"name": "Customize Form",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "System Manager",
"share": 1,
"submit": 0,
"create": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "System Manager",
"share": 1,
"submit": 0,
"write": 1
}
],
],
"search_fields": "doc_type"
}
}

View file

@ -1,304 +1,304 @@
{
"allow_copy": 0,
"autoname": "hash",
"creation": "2013-02-22 01:27:32",
"docstatus": 0,
"doctype": "DocType",
"allow_copy": 0,
"autoname": "hash",
"creation": "2013-02-22 01:27:32",
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"fieldname": "label_and_type",
"fieldtype": "Section Break",
"label": "Label and Type",
"permlevel": 0,
"fieldname": "label_and_type",
"fieldtype": "Section Break",
"label": "Label and Type",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "label",
"fieldtype": "Data",
"hidden": 0,
"in_list_view": 1,
"label": "Label",
"oldfieldname": "label",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"reqd": 0,
"fieldname": "label",
"fieldtype": "Data",
"hidden": 0,
"in_list_view": 1,
"label": "Label",
"oldfieldname": "label",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"reqd": 0,
"search_index": 1
},
},
{
"default": "Data",
"fieldname": "fieldtype",
"fieldtype": "Select",
"hidden": 0,
"in_list_view": 1,
"label": "Type",
"oldfieldname": "fieldtype",
"oldfieldtype": "Select",
"options": "Attach\nButton\nCheck\nCode\nColumn Break\nCurrency\nData\nDate\nDatetime\nDynamic Link\nFloat\nFold\nHTML\nImage\nInt\nLink\nLong Text\nPassword\nPercent\nRead Only\nSection Break\nSelect\nSmall Text\nTable\nText\nText Editor\nTime",
"permlevel": 0,
"print_hide": 0,
"reqd": 1,
"default": "Data",
"fieldname": "fieldtype",
"fieldtype": "Select",
"hidden": 0,
"in_list_view": 1,
"label": "Type",
"oldfieldname": "fieldtype",
"oldfieldtype": "Select",
"options": "Attach\nButton\nCheck\nCode\nColumn Break\nCurrency\nData\nDate\nDatetime\nDynamic Link\nFloat\nFold\nHTML\nImage\nInt\nLink\nLong Text\nPassword\nPercent\nRead Only\nSection Break\nSelect\nSmall Text\nTable\nText\nText Editor\nTime",
"permlevel": 0,
"print_hide": 0,
"reqd": 1,
"search_index": 1
},
},
{
"fieldname": "fieldname",
"fieldtype": "Data",
"hidden": 0,
"in_list_view": 1,
"label": "Name",
"oldfieldname": "fieldname",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"read_only": 1,
"reqd": 0,
"fieldname": "fieldname",
"fieldtype": "Data",
"hidden": 0,
"in_list_view": 1,
"label": "Name",
"oldfieldname": "fieldname",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"read_only": 1,
"reqd": 0,
"search_index": 1
},
},
{
"fieldname": "reqd",
"fieldtype": "Check",
"hidden": 0,
"label": "Mandatory",
"oldfieldname": "reqd",
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_width": "50px",
"reqd": 0,
"search_index": 0,
"fieldname": "reqd",
"fieldtype": "Check",
"hidden": 0,
"label": "Mandatory",
"oldfieldname": "reqd",
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_width": "50px",
"reqd": 0,
"search_index": 0,
"width": "50px"
},
},
{
"fieldname": "unique",
"fieldtype": "Check",
"label": "Unique",
"permlevel": 0,
"fieldname": "unique",
"fieldtype": "Check",
"label": "Unique",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "in_list_view",
"fieldtype": "Check",
"label": "In List View",
"fieldname": "in_list_view",
"fieldtype": "Check",
"label": "In List View",
"permlevel": 0
},
},
{
"fieldname": "column_break_7",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "column_break_7",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
},
{
"depends_on": "eval:in_list([\"Float\", \"Currency\", \"Percent\"], doc.fieldtype)",
"description": "Set non-standard precision for a Float or Currency field",
"fieldname": "precision",
"fieldtype": "Select",
"label": "Precision",
"options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9",
"permlevel": 0,
"depends_on": "eval:in_list([\"Float\", \"Currency\", \"Percent\"], doc.fieldtype)",
"description": "Set non-standard precision for a Float or Currency field",
"fieldname": "precision",
"fieldtype": "Select",
"label": "Precision",
"options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9",
"permlevel": 0,
"precision": ""
},
},
{
"description": "For Links, enter the DocType as range.\nFor Select, enter list of Options, each on a new line.",
"fieldname": "options",
"fieldtype": "Text",
"hidden": 0,
"in_list_view": 1,
"label": "Options",
"oldfieldname": "options",
"oldfieldtype": "Text",
"permlevel": 0,
"print_hide": 0,
"reqd": 0,
"description": "For Links, enter the DocType as range.\nFor Select, enter list of Options, each on a new line.",
"fieldname": "options",
"fieldtype": "Text",
"hidden": 0,
"in_list_view": 1,
"label": "Options",
"oldfieldname": "options",
"oldfieldtype": "Text",
"permlevel": 0,
"print_hide": 0,
"reqd": 0,
"search_index": 0
},
},
{
"fieldname": "permissions",
"fieldtype": "Section Break",
"label": "Permissions",
"permlevel": 0,
"fieldname": "permissions",
"fieldtype": "Section Break",
"label": "Permissions",
"permlevel": 0,
"precision": ""
},
},
{
"description": "This field will appear only if the fieldname defined here has value OR the rules are true (examples): <br>\nmyfield\neval:doc.myfield=='My Value'<br>\neval:doc.age>18",
"fieldname": "depends_on",
"fieldtype": "Data",
"hidden": 0,
"label": "Depends On",
"oldfieldname": "depends_on",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"description": "This field will appear only if the fieldname defined here has value OR the rules are true (examples): \nmyfield\neval:doc.myfield=='My Value'\neval:doc.age>18",
"fieldname": "depends_on",
"fieldtype": "Data",
"hidden": 0,
"label": "Depends On",
"oldfieldname": "depends_on",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"reqd": 0
},
},
{
"default": "0",
"fieldname": "permlevel",
"fieldtype": "Int",
"hidden": 0,
"in_list_view": 1,
"label": "Perm Level",
"oldfieldname": "permlevel",
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 0,
"reqd": 0,
"default": "0",
"fieldname": "permlevel",
"fieldtype": "Int",
"hidden": 0,
"in_list_view": 1,
"label": "Perm Level",
"oldfieldname": "permlevel",
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 0,
"reqd": 0,
"search_index": 0
},
},
{
"fieldname": "hidden",
"fieldtype": "Check",
"hidden": 0,
"label": "Hidden",
"oldfieldname": "hidden",
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_width": "50px",
"reqd": 0,
"search_index": 0,
"fieldname": "hidden",
"fieldtype": "Check",
"hidden": 0,
"label": "Hidden",
"oldfieldname": "hidden",
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_width": "50px",
"reqd": 0,
"search_index": 0,
"width": "50px"
},
},
{
"fieldname": "column_break_14",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "column_break_14",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "ignore_user_permissions",
"fieldtype": "Check",
"label": "Ignore User Permissions",
"fieldname": "ignore_user_permissions",
"fieldtype": "Check",
"label": "Ignore User Permissions",
"permlevel": 0
},
},
{
"fieldname": "allow_on_submit",
"fieldtype": "Check",
"hidden": 0,
"label": "Allow on Submit",
"oldfieldname": "allow_on_submit",
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"fieldname": "allow_on_submit",
"fieldtype": "Check",
"hidden": 0,
"label": "Allow on Submit",
"oldfieldname": "allow_on_submit",
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"reqd": 0
},
},
{
"fieldname": "report_hide",
"fieldtype": "Check",
"hidden": 0,
"label": "Report Hide",
"oldfieldname": "report_hide",
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"fieldname": "report_hide",
"fieldtype": "Check",
"hidden": 0,
"label": "Report Hide",
"oldfieldname": "report_hide",
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"reqd": 0
},
},
{
"fieldname": "display",
"fieldtype": "Section Break",
"label": "Display",
"permlevel": 0,
"fieldname": "display",
"fieldtype": "Section Break",
"label": "Display",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "default",
"fieldtype": "Text",
"hidden": 0,
"label": "Default",
"oldfieldname": "default",
"oldfieldtype": "Text",
"permlevel": 0,
"print_hide": 0,
"reqd": 0,
"fieldname": "default",
"fieldtype": "Text",
"hidden": 0,
"label": "Default",
"oldfieldname": "default",
"oldfieldtype": "Text",
"permlevel": 0,
"print_hide": 0,
"reqd": 0,
"search_index": 0
},
},
{
"fieldname": "in_filter",
"fieldtype": "Check",
"hidden": 0,
"label": "In Filter",
"oldfieldname": "in_filter",
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_width": "50px",
"reqd": 0,
"fieldname": "in_filter",
"fieldtype": "Check",
"hidden": 0,
"label": "In Filter",
"oldfieldname": "in_filter",
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"print_width": "50px",
"reqd": 0,
"width": "50px"
},
},
{
"fieldname": "column_break_21",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "column_break_21",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "description",
"fieldtype": "Text",
"hidden": 0,
"label": "Description",
"oldfieldname": "description",
"oldfieldtype": "Text",
"permlevel": 0,
"print_hide": 0,
"print_width": "300px",
"reqd": 0,
"fieldname": "description",
"fieldtype": "Text",
"hidden": 0,
"label": "Description",
"oldfieldname": "description",
"oldfieldtype": "Text",
"permlevel": 0,
"print_hide": 0,
"print_width": "300px",
"reqd": 0,
"width": "300px"
},
},
{
"fieldname": "print_hide",
"fieldtype": "Check",
"hidden": 0,
"label": "Print Hide",
"oldfieldname": "print_hide",
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"reqd": 0,
"fieldname": "print_hide",
"fieldtype": "Check",
"hidden": 0,
"label": "Print Hide",
"oldfieldname": "print_hide",
"oldfieldtype": "Check",
"permlevel": 0,
"print_hide": 0,
"reqd": 0,
"search_index": 0
},
},
{
"description": "Print Width of the field, if the field is a column in a table",
"fieldname": "print_width",
"fieldtype": "Data",
"label": "Print Width",
"permlevel": 0,
"print_width": "50px",
"description": "Print Width of the field, if the field is a column in a table",
"fieldname": "print_width",
"fieldtype": "Data",
"label": "Print Width",
"permlevel": 0,
"print_width": "50px",
"width": "50px"
},
},
{
"fieldname": "width",
"fieldtype": "Data",
"hidden": 0,
"in_list_view": 1,
"label": "Width",
"oldfieldname": "width",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_width": "50px",
"reqd": 0,
"search_index": 0,
"fieldname": "width",
"fieldtype": "Data",
"hidden": 0,
"in_list_view": 1,
"label": "Width",
"oldfieldname": "width",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_width": "50px",
"reqd": 0,
"search_index": 0,
"width": "50px"
},
},
{
"fieldname": "is_custom_field",
"fieldtype": "Check",
"hidden": 1,
"label": "Is Custom Field",
"permlevel": 0,
"precision": "",
"fieldname": "is_custom_field",
"fieldtype": "Check",
"hidden": 1,
"label": "Is Custom Field",
"permlevel": 0,
"precision": "",
"read_only": 1
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"issingle": 0,
"istable": 1,
"modified": "2015-04-24 11:37:52.879004",
"modified_by": "Administrator",
"module": "Custom",
"name": "Customize Form Field",
"owner": "Administrator",
"permissions": [],
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"issingle": 0,
"istable": 1,
"modified": "2015-07-27 01:00:32.901851",
"modified_by": "Administrator",
"module": "Custom",
"name": "Customize Form Field",
"owner": "Administrator",
"permissions": [],
"read_only": 0
}
}

View file

@ -11,6 +11,7 @@ from frappe.modules import scrub, get_module_path
from frappe.utils import flt, cint, get_html_format
from frappe.translate import send_translations
import frappe.desk.reportview
from frappe.permissions import get_role_permissions
def get_report_doc(report_name):
doc = frappe.get_doc("Report", report_name)
@ -144,20 +145,35 @@ def get_filtered_data(ref_doctype, columns, data):
linked_doctypes = get_linked_doctypes(columns, data)
match_filters_per_doctype = get_user_match_filters(linked_doctypes, ref_doctype)
shared = frappe.share.get_shared(ref_doctype)
columns_dict = get_columns_dict(columns)
role_permissions = get_role_permissions(frappe.get_meta(ref_doctype))
if_owner = role_permissions.get("if_owner", {}).get("report")
if match_filters_per_doctype:
for row in data:
if shared and row[linked_doctypes[ref_doctype]] in shared:
result.append(row)
elif has_match(row, linked_doctypes, match_filters_per_doctype):
elif has_match(row, linked_doctypes, match_filters_per_doctype, ref_doctype, if_owner, columns_dict):
result.append(row)
else:
result = list(data)
return result
def has_match(row, linked_doctypes, doctype_match_filters):
def has_match(row, linked_doctypes, doctype_match_filters, ref_doctype, if_owner, columns_dict):
"""Returns True if after evaluating permissions for each linked doctype
- There is an owner match for the ref_doctype
- `and` There is a user permission match for all linked doctypes
Returns True if the row is empty
Note:
Each doctype could have multiple conflicting user permission doctypes.
Hence even if one of the sets allows a match, it is true.
This behavior is equivalent to the trickling of user permissions of linked doctypes to the ref doctype.
"""
resultant_match = True
if not row:
@ -167,20 +183,33 @@ def has_match(row, linked_doctypes, doctype_match_filters):
for doctype, filter_list in doctype_match_filters.items():
matched_for_doctype = False
for match_filters in filter_list:
match = True
for dt, idx in linked_doctypes.items():
if dt in match_filters and row[idx] not in match_filters[dt]:
match = False
if doctype==ref_doctype and if_owner:
idx = linked_doctypes.get("User")
if (idx is not None
and row[idx]==frappe.session.user
and columns_dict[idx]==columns_dict.get("owner")):
# owner match is true
matched_for_doctype = True
if not matched_for_doctype:
for match_filters in filter_list:
match = True
for dt, idx in linked_doctypes.items():
# case handled above
if dt=="User" and columns_dict[idx]==columns_dict.get("owner"):
continue
if dt in match_filters and row[idx] not in match_filters[dt]:
match = False
break
# each doctype could have multiple conflicting user permission doctypes, hence using OR
# so that even if one of the sets allows a match, it is true
matched_for_doctype = matched_for_doctype or match
if matched_for_doctype:
break
# each doctype could have multiple conflicting user permission doctypes, hence using OR
# so that even if one of the sets allows a match, it is true
matched_for_doctype = matched_for_doctype or match
if matched_for_doctype:
break
# each doctype's user permissions should match the row! hence using AND
resultant_match = resultant_match and matched_for_doctype
@ -192,16 +221,16 @@ def has_match(row, linked_doctypes, doctype_match_filters):
def get_linked_doctypes(columns, data):
linked_doctypes = {}
for idx, col in enumerate(columns):
if isinstance(col, basestring):
col = col.split(":")
if len(col) > 1 and col[1].startswith("Link"):
link_dt = col[1].split("/")[1]
linked_doctypes[link_dt] = idx
columns_dict = get_columns_dict(columns)
# dict
elif col.get("fieldtype")=="Link" and col.get("options"):
linked_doctypes[col["options"]] = col["fieldname"]
for idx, col in enumerate(columns):
df = columns_dict[idx]
if df.get("fieldtype")=="Link":
if isinstance(col, basestring):
linked_doctypes[df["options"]] = idx
else:
# dict
linked_doctypes[df["options"]] = df["fieldname"]
# remove doctype if column is empty
for doctype, key in linked_doctypes.items():
@ -210,6 +239,35 @@ def get_linked_doctypes(columns, data):
return linked_doctypes
def get_columns_dict(columns):
"""Returns a dict with column docfield values as dict
The keys for the dict are both idx and fieldname,
so either index or fieldname can be used to search for a column's docfield properties
"""
columns_dict = {}
for idx, col in enumerate(columns):
col_dict = {}
# string
if isinstance(col, basestring):
col = col.split(":")
if len(col) > 1:
if "/" in col[1]:
col_dict["fieldtype"], col_dict["options"] = col[1].split("/")
else:
col_dict["fieldtype"] = col[1]
col_dict["fieldname"] = col[0].lower()
# dict
else:
col_dict.update(col)
columns_dict[idx] = col_dict
columns_dict[col_dict["fieldname"]] = col_dict
return columns_dict
def get_user_match_filters(doctypes, ref_doctype):
match_filters = {}

View file

@ -55,7 +55,8 @@ def get_outgoing_email_account(raise_exception_not_set=True, append_to=None):
email_account = get_default_outgoing_email_account(raise_exception_not_set=raise_exception_not_set)
if not email_account and raise_exception_not_set:
frappe.throw(_("Please setup default Email Account from Setup > Email > Email Account"))
frappe.throw(_("Please setup default Email Account from Setup > Email > Email Account"),
frappe.OutgoingEmailError)
frappe.local.outgoing_email_account[append_to or "default"] = email_account

View file

@ -2,12 +2,35 @@ from __future__ import unicode_literals
app_name = "frappe"
app_title = "Frappe Framework"
app_publisher = "Frappe Technologies Pvt. Ltd."
app_description = "Full Stack Web Application Framework in Python"
app_icon = "octicon octicon-circuit-board"
app_version = "5.1.3"
app_color = "orange"
app_description = """## Frappe Framework
app_email = "support@frappe.io"
Frappe is a full stack web application framework written in Python,
Javascript, HTML/CSS with MySQL as the backend. It was built for ERPNext
but is pretty generic and can be used to build database driven apps.
The key differece in Frappe compared to other frameworks is that Frappe
is that meta-data is also treated as data and is used to build front-ends
very easily. Frappe comes with a full blown admin UI called the **Desk**
that handles forms, navigation, lists, menus, permissions, file attachment
and much more out of the box.
Frappe also has a plug-in architecture that can be used to build plugins
to ERPNext.
### Links:
- Project Home: [https://frappe.io](https://frappe.io)
- Tutorial: [https://frappe.io/tutorial](https://frappe.io/tutorial)
- GitHub: [https://github.com/frappe/frappe](https://github.com/frappe/frappe)
- Forum: [https://discuss.erpnext.com](https://discuss.erpnext.com)
"""
app_icon = "octicon octicon-circuit-board"
app_version = "5.1.4"
app_color = "orange"
github_link = "https://github.com/frappe/frappe"
app_email = "info@frappe.io"
before_install = "frappe.utils.install.before_install"
after_install = "frappe.utils.install.after_install"
@ -35,8 +58,7 @@ web_include_js = [
bootstrap = "assets/frappe/css/bootstrap.css"
web_include_css = [
"assets/css/frappe-web.css",
"website_theme.css"
"assets/css/frappe-web.css"
]
website_route_rules = [
{"from_route": "/blog", "to_route": "Blog Post"},

View file

@ -453,7 +453,7 @@ class BaseDocument(object):
return self._precision[cache_key][fieldname]
def get_formatted(self, fieldname, doc=None, currency=None):
def get_formatted(self, fieldname, doc=None, currency=None, absolute_value=False):
from frappe.utils.formatters import format_value
df = self.meta.get_field(fieldname)
@ -461,7 +461,10 @@ class BaseDocument(object):
from frappe.model.meta import get_default_df
df = get_default_df(fieldname)
return format_value(self.get(fieldname), df=df, doc=doc or self, currency=currency)
val = self.get(fieldname)
if absolute_value and isinstance(val, (int, float)):
val = abs(self.get(fieldname))
return format_value(val, df=df, doc=doc or self, currency=currency)
def is_print_hide(self, fieldname, df=None, for_print=True):
"""Returns true if fieldname is to be hidden for print.

View file

@ -294,6 +294,10 @@ class DatabaseQuery(object):
self.add_user_permissions(user_permissions,
user_permission_doctypes=role_permissions.get("user_permission_doctypes").get("read"))
if role_permissions.get("if_owner", {}).get("read"):
self.match_conditions.append("`tab{0}`.owner = '{1}'".format(self.doctype,
frappe.db.escape(frappe.session.user)))
if as_condition:
conditions = ""
if self.match_conditions:

View file

@ -177,7 +177,7 @@ def append_number_if_name_exists(doc):
if frappe.db.exists(doc.doctype, doc.name):
last = frappe.db.sql("""select name from `tab{}`
where name regexp '{}-[[:digit:]]+'
order by name desc limit 1""".format(doc.doctype, doc.name))
order by length(name) desc, name desc limit 1""".format(doc.doctype, doc.name))
if last:
count = str(cint(last[0][0].rsplit("-", 1)[1]) + 1)

View file

@ -7,19 +7,19 @@ import frappe, os, json
from frappe.modules import get_module_path, scrub_dt_dn
from frappe.utils import get_datetime_str
def import_files(module, dt=None, dn=None, force=False):
def import_files(module, dt=None, dn=None, force=False, pre_process=None):
if type(module) is list:
out = []
for m in module:
out.append(import_file(m[0], m[1], m[2], force=force))
out.append(import_file(m[0], m[1], m[2], force=force, pre_process=pre_process))
return out
else:
return import_file(module, dt, dn, force=force)
return import_file(module, dt, dn, force=force, pre_process=pre_process)
def import_file(module, dt, dn, force=False):
def import_file(module, dt, dn, force=False, pre_process=None):
"""Sync a file from txt if modifed, return false if not updated"""
path = get_file_path(module, dt, dn)
ret = import_file_by_path(path, force)
ret = import_file_by_path(path, force, pre_process=pre_process)
return ret
def get_file_path(module, dt, dn):
@ -30,7 +30,7 @@ def get_file_path(module, dt, dn):
return path
def import_file_by_path(path, force=False, data_import=False):
def import_file_by_path(path, force=False, data_import=False, pre_process=None):
frappe.flags.in_import = True
try:
docs = read_doc_from_file(path)
@ -51,7 +51,7 @@ def import_file_by_path(path, force=False, data_import=False):
original_modified = doc.get("modified")
import_doc(doc, force=force, data_import=data_import)
import_doc(doc, force=force, data_import=data_import, pre_process=pre_process)
if original_modified:
# since there is a new timestamp on the file, update timestamp in
@ -87,10 +87,12 @@ ignore_values = {
ignore_doctypes = ["Page Role", "DocPerm"]
def import_doc(docdict, force=False, data_import=False):
def import_doc(docdict, force=False, data_import=False, pre_process=None):
frappe.flags.in_import = True
docdict["__islocal"] = 1
doc = frappe.get_doc(docdict)
if pre_process:
pre_process(doc)
ignore = []

View file

@ -2,7 +2,7 @@ execute:frappe.db.sql("""update `tabPatch Log` set patch=replace(patch, '.4_0.',
frappe.patches.v5_0.convert_to_barracuda_and_utf8mb4
execute:frappe.reload_doc('core', 'doctype', 'doctype', force=True) #2014-01-24
execute:frappe.reload_doc('core', 'doctype', 'docfield', force=True) #2015-05-15
execute:frappe.reload_doc('core', 'doctype', 'docperm') #2014-06-04
execute:frappe.reload_doc('core', 'doctype', 'docperm') #2014-06-24
execute:frappe.reload_doc('core', 'doctype', 'page') #2013-13-26
execute:frappe.reload_doc('core', 'doctype', 'report') #2014-06-03
execute:frappe.reload_doc('core', 'doctype', 'version') #2014-02-21

View file

@ -17,7 +17,11 @@ def check_admin_or_system_manager(user=None):
frappe.throw(_("Not permitted"), frappe.PermissionError)
def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None):
"""check if user has permission"""
"""Returns True if user has permission `ptype` for given `doctype`.
If `doc` is passed, it also checks user, share and owner permissions.
Note: if Table DocType is passed, it always returns True.
"""
if not user: user = frappe.session.user
if frappe.is_table(doctype):
@ -65,6 +69,11 @@ def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None):
if isinstance(doc, basestring):
doc = frappe.get_doc(meta.name, doc)
# if owner match, then return True
if doc.owner == frappe.session.user and role_permissions["if_owner"].get(ptype) and ptype!="create":
return True
# check if user permission
if role_permissions["apply_user_permissions"].get(ptype):
if not user_has_permission(doc, verbose=verbose, user=user,
user_permission_doctypes=role_permissions.get("user_permission_doctypes", {}).get(ptype) or []):
@ -80,6 +89,7 @@ def has_permission(doctype, ptype="read", doc=None, verbose=False, user=None):
return True
def get_doc_permissions(doc, verbose=False, user=None):
"""Returns a dict of evaluated permissions for given `doc` like `{"read":1, "write":1}`"""
if not user: user = frappe.session.user
if frappe.is_table(doc.doctype):
@ -102,23 +112,62 @@ def get_doc_permissions(doc, verbose=False, user=None):
user_permission_doctypes=role_permissions.get("user_permission_doctypes", {}).get(ptype) or []):
role_permissions[ptype] = 0
# update share permissions
role_permissions.update(frappe.db.get_value("DocShare",
{"share_doctype": doc.doctype, "share_name": doc.name, "user": user},
["read", "write", "share"], as_dict=True) or {})
# apply owner permissions on top of existing permissions
if doc.owner == frappe.session.user:
role_permissions.update(role_permissions.if_owner)
update_share_permissions(role_permissions, doc, user)
return role_permissions
def update_share_permissions(role_permissions, doc, user):
"""Updates share permissions on `role_permissions` for given doc, if shared"""
share_ptypes = ("read", "write", "share")
permissions_by_share = frappe.db.get_value("DocShare",
{"share_doctype": doc.doctype, "share_name": doc.name, "user": user},
share_ptypes, as_dict=True)
if permissions_by_share:
for ptype in share_ptypes:
if ptype:
role_permissions[ptype] = 1
def get_role_permissions(meta, user=None, verbose=False):
"""Returns dict of evaluated role permissions like `{"read": True, "write":False}`
If user permissions are applicable, it adds a dict of user permissions like
{
// user permissions will apply on these rights
"apply_user_permissions": {"read": 1, "write": 1},
// doctypes that will be applicable for each right
"user_permission_doctypes": {
"read": [
// AND between "DocType 1" and "DocType 2"
["DocType 1", "DocType 2"],
// OR
["DocType 3"]
]
}
"if_owner": {"read": 1, "write": 1}
}
"""
if not user: user = frappe.session.user
cache_key = (meta.name, user)
if not frappe.local.role_permissions.get(cache_key):
perms = frappe._dict({ "apply_user_permissions": {}, "user_permission_doctypes": {} })
perms = frappe._dict({ "apply_user_permissions": {}, "user_permission_doctypes": {}, "if_owner": {} })
user_roles = frappe.get_roles(user)
for p in meta.permissions:
if cint(p.permlevel)==0 and (p.role in user_roles):
# apply only for level 0
for ptype in rights:
perms[ptype] = perms.get(ptype, 0) or cint(p.get(ptype))
@ -126,6 +175,10 @@ def get_role_permissions(meta, user=None, verbose=False):
perms["apply_user_permissions"][ptype] = (perms["apply_user_permissions"].get(ptype, 1)
and p.get("apply_user_permissions"))
# build if_owner dict if applicable for this right
if p.if_owner and p.get(ptype):
perms["if_owner"][ptype] = 1
if p.apply_user_permissions:
if p.user_permission_doctypes:
# set user_permission_doctypes in perms

View file

@ -32,6 +32,9 @@
margin: 0px;
padding: 15px;
}
.form-section .form-section-heading {
margin: 25px 0px 15px 0px;
}
.empty-section {
display: none !important;
}

View file

@ -285,6 +285,7 @@ body {
}
.avatar-empty {
border: 1px dashed #d1d8dd;
border-radius: 4px;
}
.avatar-small {
margin-right: 5px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 522 B

View file

@ -1,92 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
width="260px"
height="260px"
viewBox="0 0 260 260"
enable-background="new 0 0 260 260"
xml:space="preserve"
inkscape:version="0.91 r13725"
sodipodi:docname="frappe.svg"><metadata
id="metadata73"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs71" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1160"
inkscape:window-height="676"
id="namedview69"
showgrid="false"
inkscape:zoom="1.8230769"
inkscape:cx="130"
inkscape:cy="130"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="text3365"
inkscape:snap-bbox="true"
inkscape:snap-smooth-nodes="true" /><g
id="g3"><g
id="g5"
transform="translate(5.5084746,2.2033898)"><g
id="g7"
transform="matrix(0.6988869,0,0,0.6988869,38.116279,42.59371)"><path
d="m 223.463,82.762 c 27.129,55.638 0.525,91.039 -60.914,120.997 C 101.111,233.715 56.835,232.875 29.705,177.238 2.578,121.601 29.182,86.199 90.62,56.242 152.06,26.284 196.335,27.126 223.463,82.762 Z"
id="path9"
inkscape:connector-curvature="0"
style="fill:#ffdd8c">
</path>
<animateTransform
attributeType="XML"
attributeName="transform"
begin="0s"
dur="10s"
type="rotate"
from="0 125 135"
to="360 125 135"
additive="sum"
repeatCount="indefinite" />
</g></g><g
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#223a4e;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text3365"><path
d="m 4.1839912,112.70592 0,-0.43946 q 0,-0.8789 0.4394531,-1.27441 0.4833985,-0.43945 1.6699219,-0.43945 l 7.0751958,0 0,-4.57032 q 0,-7.250972 3.076171,-10.986324 3.076172,-3.779296 8.833008,-3.779296 4.790039,0 7.119141,2.329101 0.966797,0.966797 0.966797,2.241211 0,0.65918 -0.307617,1.186523 -0.263672,0.527344 -0.57129,0.747071 -0.307617,0.219726 -0.395507,0.175781 -1.054688,-1.230469 -2.944336,-2.06543 -1.889649,-0.834961 -3.867188,-0.834961 -3.911133,0 -5.844726,2.72461 -1.889649,2.724614 -1.889649,8.525394 l 0,4.30664 9.448242,0 q 2.153321,0 2.153321,1.71386 l 0,0.43946 q 0,1.71386 -2.153321,1.71386 l -9.360351,0 0,36.91407 q 0,2.06543 -1.889649,2.06543 l -0.483398,0 q -1.889648,0 -1.889648,-2.06543 l 0,-36.91407 -7.0751958,0 q -1.1865234,0 -1.6699219,-0.3955 -0.4394531,-0.43946 -0.4394531,-1.31836 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:90px;font-family:Omnes;-inkscape-font-specification:Omnes;fill:#223a4e;fill-opacity:1"
id="path3431" /><path
d="m 37.450593,151.33385 0,-40.60547 q 0,-0.0439 0.175781,-0.13184 0.219727,-0.13183 0.571289,-0.21972 0.351563,-0.0879 0.703125,-0.0879 2.8125,0 2.8125,4.30664 l 0,5.31738 q 2.592774,-10.23926 11.777344,-10.23926 2.548828,0 4.21875,1.01074 1.713867,1.01075 1.713867,2.59278 0,0.74707 -0.307617,1.31836 -0.263672,0.52734 -0.571289,0.74707 -0.263672,0.21972 -0.395508,0.17578 -1.845703,-1.71387 -5.097656,-1.71387 -5.581055,0 -8.4375,5.09766 -2.8125,5.05371 -2.8125,13.97461 l 0,18.45703 q 0,2.06543 -1.889649,2.06543 l -0.483398,0 q -1.977539,0 -1.977539,-2.06543 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:90px;font-family:Omnes;-inkscape-font-specification:Omnes;fill:#223a4e;fill-opacity:1"
id="path3433" /><path
d="m 64.125397,142.32506 q 0,-7.16309 7.294922,-10.41504 7.338868,-3.2959 23.466797,-3.51563 l 0.922852,0 0,-2.15332 q 0,-5.97656 -3.47168,-9.27246 -3.427734,-3.33984 -9.580078,-3.33984 -5.273438,0 -8.964844,2.24121 -3.691406,2.19727 -5.537109,5.84473 -0.219727,0 -0.703125,-0.13184 -0.439453,-0.13184 -1.098633,-0.74707 -0.615234,-0.61523 -0.615234,-1.62598 0,-0.70312 0.659179,-1.88964 0.65918,-1.23047 1.757813,-2.24122 5.405273,-5.40527 14.765625,-5.40527 7.954101,0 12.480469,4.39453 4.526369,4.39453 4.526369,12.08496 l 0,26.80664 q 0,0.0439 -0.219729,0.17578 -0.219726,0.0879 -0.615234,0.17579 -0.351563,0.0879 -0.703125,0.0879 -2.680664,0 -2.680664,-4.30664 l 0,-4.43848 q -2.109375,4.21875 -6.635742,6.81152 -4.526368,2.54883 -10.283204,2.54883 -6.811523,0 -10.810546,-3.16406 -3.955079,-3.16406 -3.955079,-8.52539 z m 4.394532,0 q 0,3.77929 2.856445,5.97656 2.900391,2.15332 7.866211,2.15332 6.943359,0 11.733398,-4.1748 4.833985,-4.17481 4.833985,-10.23926 l 0,-4.21875 -1.186524,0 q -13.974609,0.26367 -20.039062,2.68066 -6.064453,2.41699 -6.064453,7.82227 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:90px;font-family:Omnes;-inkscape-font-specification:Omnes;fill:#223a4e;fill-opacity:1"
id="path3435" /><path
d="m 112.15762,168.42857 0,-57.70019 q 0,-0.0439 0.17579,-0.13184 0.21972,-0.13183 0.57128,-0.21972 0.35157,-0.0879 0.70313,-0.0879 2.8125,0 2.8125,4.30664 l 0,4.70214 q 5.71289,-9.62402 16.91894,-9.62402 8.61329,0 14.41407,6.19629 5.80078,6.15234 5.80078,15.86426 0,9.84375 -5.80078,16.08398 -5.75684,6.19629 -14.72168,6.19629 -6.06446,0 -10.41504,-2.76855 -4.35059,-2.76856 -6.1084,-6.76758 l 0,23.95019 q 0,2.06543 -1.88965,2.06543 l -0.4834,0 q -1.97754,0 -1.97754,-2.06543 z m 4.2627,-33.57422 q 0,6.41602 4.70215,10.89844 4.74609,4.48242 11.55761,4.48242 7.42676,0 11.99708,-5.09765 4.57031,-5.1416 4.57031,-13.40332 0,-7.91016 -4.70215,-13.09571 -4.6582,-5.18554 -11.68945,-5.18554 -5.93262,0 -10.15137,3.12011 -4.21875,3.07618 -6.28418,8.48145 l 0,9.7998 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:90px;font-family:Omnes;-inkscape-font-specification:Omnes;fill:#223a4e;fill-opacity:1"
id="path3437" /><path
d="m 163.13419,168.42857 0,-57.70019 q 0,-0.0439 0.17578,-0.13184 0.21972,-0.13183 0.57129,-0.21972 0.35156,-0.0879 0.70312,-0.0879 2.8125,0 2.8125,4.30664 l 0,4.70214 q 5.71289,-9.62402 16.91895,-9.62402 8.61328,0 14.41406,6.19629 5.80078,6.15234 5.80078,15.86426 0,9.84375 -5.80078,16.08398 -5.75684,6.19629 -14.72168,6.19629 -6.06445,0 -10.41504,-2.76855 -4.35059,-2.76856 -6.1084,-6.76758 l 0,23.95019 q 0,2.06543 -1.88965,2.06543 l -0.48339,0 q -1.97754,0 -1.97754,-2.06543 z m 4.26269,-33.57422 q 0,6.41602 4.70215,10.89844 4.74609,4.48242 11.55762,4.48242 7.42676,0 11.99707,-5.09765 4.57031,-5.1416 4.57031,-13.40332 0,-7.91016 -4.70215,-13.09571 -4.6582,-5.18554 -11.68945,-5.18554 -5.93262,0 -10.15137,3.12011 -4.21875,3.07618 -6.28418,8.48145 l 0,9.7998 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:90px;font-family:Omnes;-inkscape-font-specification:Omnes;fill:#223a4e;fill-opacity:1"
id="path3439" /><path
d="m 211.2543,131.99791 q 0,-6.28418 2.72461,-11.38184 2.72461,-5.09765 7.60254,-7.99804 4.87793,-2.94434 10.89844,-2.94434 8.78906,0 14.15039,5.75684 5.40527,5.71289 5.40527,15.02929 l 0,0.43946 q 0,0.92285 -0.43945,1.23047 -0.39551,0.30761 -1.45019,0.30761 l -34.67286,0 q 0.13184,7.91016 4.96582,12.83203 4.87793,4.87793 12.56836,4.87793 10.89844,0 15.24903,-8.52539 0.17578,-0.13183 0.74707,0.0879 0.61523,0.17578 1.18652,0.83496 0.57129,0.65918 0.57129,1.58204 0,0.74707 -0.70313,2.02148 -0.70312,1.27441 -2.02148,2.59277 -2.19727,2.19727 -6.1084,3.73536 -3.91113,1.53808 -8.9209,1.53808 -9.71191,0 -15.73242,-6.15234 -6.02051,-6.19629 -6.02051,-15.86426 z m 4.39453,-3.25195 31.86036,0 q -0.26368,-6.85547 -4.39453,-11.07422 -4.08692,-4.21875 -10.63477,-4.21875 -6.54785,0 -11.20606,4.26269 -4.61425,4.2627 -5.625,11.03028 z m 11.3379,-24.82911 q -0.13184,-0.17578 1.09863,-1.66992 1.23047,-1.49414 3.7793,-3.867185 2.54882,-2.416992 5.40527,-4.570312 2.63672,-1.977539 4.04297,-1.977539 0.83496,0 1.40625,0.527344 0.57129,0.483398 0.57129,1.274414 0,0.878906 -0.74707,1.757812 -0.70313,0.878906 -2.68067,2.373047 -2.94433,2.109375 -6.06445,3.691409 -3.07617,1.58203 -4.83399,2.15332 -1.75781,0.57129 -1.97753,0.30761 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:90px;font-family:Omnes;-inkscape-font-specification:Omnes;fill:#223a4e;fill-opacity:1"
id="path3441" /></g></g></svg>

Before

Width:  |  Height:  |  Size: 9.1 KiB

View file

@ -105,20 +105,6 @@ frappe.ui.form.Layout = Class.extend({
});
},
make_column: function(df) {
this.column = $('<div class="form-column">\
<form>\
</form>\
</div>').appendTo(this.section.body)
.find("form")
.on("submit", function() { return false; })
// distribute all columns equally
var colspan = cint(12 / this.section.find(".form-column").length);
this.section.find(".form-column").removeClass()
.addClass("form-column")
.addClass("col-sm-" + colspan);
},
make_field: function(df, colspan) {
!this.section && this.make_section();
!this.column && this.make_column();
@ -181,7 +167,7 @@ frappe.ui.form.Layout = Class.extend({
section.df = df;
if(df) {
if(df.label) {
$('<div class="col-sm-12 text-muted"><h4>' + __(df.label) + '</h4></div>')
$('<div class="col-sm-12"><h4 class="form-section-heading">' + __(df.label) + '</h4></div>')
.appendTo(this.section);
}
if(df.description) {
@ -198,24 +184,49 @@ frappe.ui.form.Layout = Class.extend({
section.row = {
wrapper: section
};
section.layout = me;
section.refresh = function() {
if(!this.df)
return;
// hide if explictly hidden
var hide = this.df.hidden || this.df.hidden_due_to_dependency;
// hide if no perm
if(!hide && me.frm && !me.frm.get_perm(this.df.permlevel || 0, "read")) {
hide = true;
}
$(this).toggleClass("hide-control", !!hide);
frappe.ui.section_refresh.apply(this);
}
this.column = null;
section.refresh.call(section);
return this.section;
},
make_column: function(df) {
if(!df) df = {};
var column = $('<div class="form-column">\
<form>\
</form>\
</div>').appendTo(this.section.body)
.find("form")
.on("submit", function() { return false; })
if(df.label) {
$('<label class="control-label">'+ __(df.label)
+'</label>').appendTo(column);
}
// distribute all columns equally
var colspan = cint(12 / this.section.find(".form-column").length);
this.section.find(".form-column").removeClass()
.addClass("form-column")
.addClass("col-sm-" + colspan);
column.df = df;
column.layout = this;
//this.fields_dict[df.fieldname] = column;
if(df.fieldname) {
this.fields_list.push(column);
}
column.refresh = function() {
frappe.ui.section_refresh.apply(this);
}
this.column = column;
},
refresh_sections: function() {
var cnt = 0;
this.wrapper.find(".form-section:not(.hide-control)").each(function() {
@ -385,4 +396,19 @@ frappe.ui.form.Layout = Class.extend({
this.refresh_section_count();
}
})
});
frappe.ui.section_refresh = function() {
if(!this.df)
return;
// hide if explictly hidden
var hide = this.df.hidden || this.df.hidden_due_to_dependency;
// hide if no perm
if(!hide && this.layout && this.layout.frm && !this.layout.frm.get_perm(this.df.permlevel || 0, "read")) {
hide = true;
}
$(this).toggleClass("hide-control", !!hide);
}

View file

@ -89,6 +89,9 @@ $.extend(frappe.perm, {
},
build_role_permissions: function(perm, meta) {
// Returns a `dict` of evaluated Role Permissions
// Apply User Permission and its DocTypes are used to display match rules in list view
$.each(meta.permissions || [], function(i, p) {
// if user has this role
if(user_roles.indexOf(p.role)!==-1) {
@ -100,6 +103,7 @@ $.extend(frappe.perm, {
$.each(frappe.perm.rights, function(i, key) {
perm[permlevel][key] = perm[permlevel][key] || (p[key] || 0);
// NOTE: this data is required for displaying match rules in list view
if (permlevel===0) {
var apply_user_permissions = perm[permlevel].apply_user_permissions;
var current_value = (apply_user_permissions[key]===undefined ?
@ -108,6 +112,7 @@ $.extend(frappe.perm, {
}
});
// NOTE: this data is required for displaying match rules in list view
if (permlevel===0 && cint(p.apply_user_permissions) && p.user_permission_doctypes) {
// set user_permission_doctypes in perms
var user_permission_doctypes = JSON.parse(p.user_permission_doctypes);
@ -126,6 +131,10 @@ $.extend(frappe.perm, {
});
}
}
if (permlevel===0 && p["if_owner"]) {
perm[0]["if_owner"] = 1;
}
}
});
@ -177,6 +186,10 @@ $.extend(frappe.perm, {
});
}
if (perm[0].if_owner && perm[0].read) {
match_rules.push({"Owner": user});
}
return match_rules;
},

View file

@ -84,15 +84,15 @@ frappe.search = {
onclick: function() {
var txt = '<table class="table table-bordered">\
<tr><td style="width: 50%">'+__("Make a new record")+'</td><td>'+
__("<b>new</b> <i>type of document</i>")+'</td></tr>\
__("new type of document")+'</td></tr>\
<tr><td>'+__("List a document type")+'</td><td>'+
__("<i>document type...</i>, e.g. <b>customer</b>")+'</td></tr>\
__("document type..., e.g. customer")+'</td></tr>\
<tr><td>'+__("Search in a document type")+'</td><td>'+
__("<i>text</i> <b>in</b> <i>document type</i>")+'</td></tr>\
__("text in document type")+'</td></tr>\
<tr><td>'+__("Open a module or tool")+'</td><td>'+
__("<i>module name...</i>")+'</td></tr>\
__("module name...")+'</td></tr>\
<tr><td>'+__("Calculate")+'</td><td>'+
__("<i>e.g. <strong>(55 + 434) / 4</strong> or <strong>=Math.sin(Math.PI/2)</strong>...</i>")+'</td></tr>\
__("e.g. (55 + 434) / 4 or =Math.sin(Math.PI/2)...")+'</td></tr>\
</table>'
msgprint(txt, "Search Help");
}

View file

@ -187,17 +187,21 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
},
get_order_by: function() {
var order_by = [];
// first
var order_by = this.get_selected_table_and_column(this.sort_by_select)
+ ' ' + this.sort_order_select.val();
var sort_by_select = this.get_selected_table_and_column(this.sort_by_select);
if (sort_by_select) {
order_by.push(sort_by_select + " " + this.sort_order_select.val());
}
// second
if(this.sort_by_next_select.val()) {
order_by += ', ' + this.get_selected_table_and_column(this.sort_by_next_select)
+ ' ' + this.sort_order_next_select.val();
order_by.push(this.get_selected_table_and_column(this.sort_by_next_select)
+ ' ' + this.sort_order_next_select.val());
}
return order_by;
return order_by.join(", ");
},
get_selected_table_and_column: function(select) {

View file

@ -41,6 +41,10 @@
.form-section {
margin: 0px;
padding: 15px;
.form-section-heading {
margin: 25px 0px 15px 0px;
}
}
.empty-section {

View file

@ -55,7 +55,7 @@ def clear_sessions(user=None, keep_current=False):
user = frappe.session.user
for sid in frappe.db.sql("""select sid from tabSessions where user=%s and device=%s""",
(user, frappe.session.device or "desktop")):
(user, frappe.session.data.device or "desktop")):
if keep_current and frappe.session.sid==sid[0]:
continue
else:

View file

@ -0,0 +1,11 @@
<!-- title: {{ app.title }} API -->
{% from "templates/autodoc/macros.html" import github_link, version %}
<p>
{{ version(app.name) }}
{{ github_link(app, app.name, True) }}
</p>
<h3>Contents</h3>
{index}

View file

@ -0,0 +1,55 @@
<!-- title: {{ app.title }} Documentation -->
<!-- no-breadcrumbs -->
{% from "templates/autodoc/macros.html" import github_link, version, discuss_link %}
<p>
{{ version(app.name) }}
{{ github_link(app, app.name, True) }}
</p>
<table class="table table-bordered" style="max-width: 500px;">
<tr>
<td style="width: 40%">
App Name
</td>
<td>
<code>{{ app.name }}</code>
</td>
</tr>
<tr>
<td>
Publisher
</td>
<td>
<code>{{ app.publisher }}</code>
</td>
</tr>
<tr>
<td>
Version
</td>
<td>
<code>{{ app.version }}</code>
</td>
</tr>
</table>
<hr>
{{ app.description }}
<hr>
<h3>Contents</h3>
<ul>
<li>
<a href="{{ '{{ pathname }}' }}/models">Models (DocTypes)</a>
</li>
<li>
<a href="{{ '{{ pathname }}' }}/api">Server-side API</a>
</li>
</ul>
{{ discuss_link() }}
<!-- jinja --><!-- static -->

View file

@ -1,14 +1,21 @@
{% from "templates/autodoc/macros.html" import automodule, version %}
{% macro render_doctype(name) %}
{% set doc = frappe.get_doc("DocType", name) %}
{% set controller = autodoc.get_controller(name) %}
{{ version(name) }}
<!-- title: {{ doctype }} -->
{% from "templates/autodoc/macros.html" import automodule, version,
github_link, doctype_link, discuss_link %}
{% set doc = frappe.get_doc("DocType", doctype) %}
{% set controller = autodoc.get_controller(doctype) %}
<p>
{{ version(doctype) }}
{{ github_link(app, app.name + "/" + scrub(doc.module)
+ "/doctype/" + scrub(doctype), True) }}
</p>
{% if doc.issingle %}<span class="label label-info">Single</span>{% endif %}
{% if doc.istable %}<span class="label label-info">Child Table</span>{% endif %}
{% if not doc.issingle %}
<p><b>Table Name:</b> <code>tab{{ name }}</code></p>
<p><b>Table Name:</b> <code>tab{{ doctype }}</code></p>
{% endif %}
{{ doc.description or "" }}
@ -39,7 +46,7 @@
</td>
<td>{% if df.options and df.fieldtype not in ("HTML") %}
{% if df.fieldtype in ("Table", "Link") %}
<a href="{{ autodoc.get_doclink(df.options) or "#" }}">{{ df.options }}</a>
{{ doctype_link(df.options) }}
{% else %}<pre>{{ df.options }}</pre>{% endif %}
{% endif %}</td>
</tr>
@ -54,26 +61,28 @@
{{ automodule(controller.__module__) }}
{% set parents = frappe.get_list("DocField",
{"options": name, "fieldtype": "Link"}, ["distinct parent"]) %}
filters = {"options": doctype, "fieldtype": "Link"}, fields = ["distinct parent"]) %}
{% if parents %}
<h4>Linked In:</h4>
<ul>
{% for parent in parents %}
<li><a href="{{ autodoc.get_doclink(parent.parent) }}">{{ parent.parent }}</a></li>
<li>{{ doctype_link(parent.parent) }}</li>
{% endfor %}
</ul>
{% endif %}
{% else %}
{% set parents = frappe.get_list("DocField",
{"options": name, "fieldtype": "Table"}, ["parent"]) %}
filters = {"options": doctype, "fieldtype": "Table"}, fields = ["parent"]) %}
{% if parents %}
<h4>Child Table Of</h4>
<ul>
{% for parent in parents %}
<li><a href="{{ autodoc.get_doclink(parent.parent) }}">{{ parent.parent }}</a></li>
<li>{{ doctype_link(parent.parent) }}</li>
{% endfor %}
</ul>
{% endif %}
{% endif %}
{% endmacro %}
<!-- jinja --><!-- static -->
{{ discuss_link() }}

View file

@ -1,6 +1,5 @@
{% macro automodule(name) %}
{% set m = autodoc.automodule(name) %}
{{ version(name) }}
{% for obj in m.members %}
{% if obj.type=="function" %}
{{ render_function(obj, name) }}
@ -10,12 +9,6 @@
{% endfor %}
{% endmacro %}
{% macro version(name) %}
<p>
<span class="label label-default">Version {{ autodoc.get_version(name) }}</span>
</p>
{% endmacro %}
{% macro render_class(obj) %}
<h3 style="font-weight: normal;">Class <b>{{ obj.name }}</b></h3>
{% if obj.bases %}
@ -51,3 +44,26 @@
{{ arg }}{% if default_idx >= 0 %}={{ args[3][default_idx] }}{% endif %}{% if not loop.last %}, {% endif %}
{%- endfor %}
{%- endmacro %}
{% macro version(name) %}
<a class="btn btn-default btn-sm" disabled style="margin-bottom: 10px;">
Version {{ autodoc.get_version(name) }}</a>
{% endmacro %}
{% macro github_link(app, file_path, tree=False) %}
<a class="btn btn-default btn-sm" href="{{ app.github_link }}/{{ "tree" if tree else "blob" }}/v{{ app.version }}/{{ file_path }}"
target="_blank" style="margin-left: 10px; margin-bottom: 10px;"><i class="octicon octicon-mark-github"></i> Source</a>
{% endmacro %}
{% macro discuss_link() %}
<br>
<a href="https://discuss.erpnext.com" target="_blank">Discuss this on the forum</a>
{% endmacro %}
{% macro doctype_link(doctype) %}
{% set module = frappe.db.get_value("DocType", doctype, "module") %}
{% if doctype and module %}
<a href="/{{'{{ pathname.split("/")[0] }}'}}/models/{{
scrub(module) }}/{{ scrub(doctype) }}">{{ doctype }}</a>
{% endif %}
{% endmacro %}

View file

@ -0,0 +1,13 @@
<!-- title: {{ app.title }} Models (DocTypes) -->
{% from "templates/autodoc/macros.html" import github_link, version %}
<p>
{{ version(app.name) }}
{{ github_link(app, app.name, True) }}
</p>
<p>Browse DocTypes by Module</p>
<h3>Contents</h3>
{index}

View file

@ -0,0 +1,11 @@
<!-- title: Module {{ name }} -->
{% from "templates/autodoc/macros.html" import github_link, version %}
<p>
{{ version(app.name) }}
{{ github_link(app, app.name + "/" + scrub(name), True) }}
</p>
<h3>DocTypes for {{ name }}</h3>
{index}

View file

@ -0,0 +1,11 @@
<!-- title: {{ title }} -->
{% from "templates/autodoc/macros.html" import github_link, version %}
<p>
{{ version(app.name) }}
{{ github_link(app, title, True) }}
</p>
<h3>Package Contents</h3>
{index}

View file

@ -0,0 +1,12 @@
<!-- title: {{ name }} -->
{%- from "templates/autodoc/macros.html" import automodule, github_link,
version, discuss_link -%}
<p>
{{ version(app.name) }}
{{ github_link(app, name.replace(".", "/") + ".py") }}
</p>
{{ automodule(name) }}
{{ discuss_link() }}

View file

@ -44,7 +44,7 @@
</script>
{% endif -%}
</head>
<body>
<body data-path="{{ path }}">
<div class="offcanvas-container">
<div class="offcanvas">
<div class="offcanvas-main-section">

View file

@ -19,3 +19,4 @@
</div>
</div>
{%- endif %}
<!-- no-breadcrumbs -->

View file

@ -0,0 +1,229 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
"""Use blog post test to test user permissions logic"""
import frappe
import frappe.defaults
import unittest
import json
import frappe.model.meta
from frappe.core.page.user_permissions.user_permissions import add, remove, get_permissions
from frappe.permissions import clear_user_permissions_for_doctype, get_doc_permissions
test_records = frappe.get_test_records('Blog Post')
test_dependencies = ["User"]
class TestPermissions(unittest.TestCase):
def setUp(self):
frappe.clear_cache(doctype="Blog Post")
user = frappe.get_doc("User", "test1@example.com")
user.add_roles("Website Manager")
user = frappe.get_doc("User", "test2@example.com")
user.add_roles("Blogger")
frappe.set_user("test1@example.com")
def tearDown(self):
frappe.set_user("Administrator")
frappe.db.set_value("Blogger", "_Test Blogger 1", "user", None)
clear_user_permissions_for_doctype("Blog Category")
clear_user_permissions_for_doctype("Blog Post")
clear_user_permissions_for_doctype("Blogger")
frappe.db.sql("""update `tabDocPerm` set user_permission_doctypes=null
where parent='Blog Post' and permlevel=0 and apply_user_permissions=1
and `read`=1""")
frappe.db.sql("""update `tabDocPerm` set if_owner=0
where parent='Blog Post' and permlevel=0 and permlevel=0 and role='Blogger'""")
def test_basic_permission(self):
post = frappe.get_doc("Blog Post", "_test-blog-post")
self.assertTrue(post.has_permission("read"))
def test_user_permissions_in_doc(self):
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1",
"test2@example.com")
frappe.set_user("test2@example.com")
post = frappe.get_doc("Blog Post", "_test-blog-post")
self.assertFalse(post.has_permission("read"))
self.assertFalse(get_doc_permissions(post).get("read"))
post1 = frappe.get_doc("Blog Post", "_test-blog-post-1")
self.assertTrue(post1.has_permission("read"))
self.assertTrue(get_doc_permissions(post1).get("read"))
def test_user_permissions_in_report(self):
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1", "test2@example.com")
frappe.set_user("test2@example.com")
names = [d.name for d in frappe.get_list("Blog Post", fields=["name", "blog_category"])]
self.assertTrue("_test-blog-post-1" in names)
self.assertFalse("_test-blog-post" in names)
def test_default_values(self):
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1", "test2@example.com")
frappe.set_user("test2@example.com")
doc = frappe.new_doc("Blog Post")
self.assertEquals(doc.get("blog_category"), "_Test Blog Category 1")
def test_user_link_match_doc(self):
blogger = frappe.get_doc("Blogger", "_Test Blogger 1")
blogger.user = "test2@example.com"
blogger.save()
frappe.set_user("test2@example.com")
post = frappe.get_doc("Blog Post", "_test-blog-post-2")
self.assertTrue(post.has_permission("read"))
post1 = frappe.get_doc("Blog Post", "_test-blog-post-1")
self.assertFalse(post1.has_permission("read"))
def test_user_link_match_report(self):
blogger = frappe.get_doc("Blogger", "_Test Blogger 1")
blogger.user = "test2@example.com"
blogger.save()
frappe.set_user("test2@example.com")
names = [d.name for d in frappe.get_list("Blog Post", fields=["name", "owner"])]
self.assertTrue("_test-blog-post-2" in names)
self.assertFalse("_test-blog-post-1" in names)
def test_set_user_permissions(self):
frappe.set_user("test1@example.com")
add("test2@example.com", "Blog Post", "_test-blog-post")
def test_not_allowed_to_set_user_permissions(self):
frappe.set_user("test2@example.com")
# this user can't add user permissions
self.assertRaises(frappe.PermissionError, add,
"test2@example.com", "Blog Post", "_test-blog-post")
def test_read_if_explicit_user_permissions_are_set(self):
self.test_set_user_permissions()
frappe.set_user("test2@example.com")
# user can only access permitted blog post
doc = frappe.get_doc("Blog Post", "_test-blog-post")
self.assertTrue(doc.has_permission("read"))
# and not this one
doc = frappe.get_doc("Blog Post", "_test-blog-post-1")
self.assertFalse(doc.has_permission("read"))
def test_not_allowed_to_remove_user_permissions(self):
self.test_set_user_permissions()
defname = get_permissions("test2@example.com", "Blog Post", "_test-blog-post")[0].name
frappe.set_user("test2@example.com")
# user cannot remove their own user permissions
self.assertRaises(frappe.PermissionError, remove,
"test2@example.com", defname, "Blog Post", "_test-blog-post")
def test_user_permissions_based_on_blogger(self):
frappe.set_user("test2@example.com")
doc = frappe.get_doc("Blog Post", "_test-blog-post-1")
self.assertTrue(doc.has_permission("read"))
frappe.set_user("test1@example.com")
add("test2@example.com", "Blog Post", "_test-blog-post")
frappe.set_user("test2@example.com")
doc = frappe.get_doc("Blog Post", "_test-blog-post-1")
self.assertFalse(doc.has_permission("read"))
doc = frappe.get_doc("Blog Post", "_test-blog-post")
self.assertTrue(doc.has_permission("read"))
def test_set_only_once(self):
blog_post = frappe.get_meta("Blog Post")
blog_post.get_field("title").set_only_once = 1
doc = frappe.get_doc("Blog Post", "_test-blog-post-1")
doc.title = "New"
self.assertRaises(frappe.CannotChangeConstantError, doc.save)
blog_post.get_field("title").set_only_once = 0
def test_user_permission_doctypes(self):
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1",
"test2@example.com")
frappe.permissions.add_user_permission("Blogger", "_Test Blogger 1",
"test2@example.com")
frappe.set_user("test2@example.com")
frappe.db.sql("""update `tabDocPerm` set user_permission_doctypes=%s
where parent='Blog Post' and permlevel=0 and apply_user_permissions=1
and `read`=1""", json.dumps(["Blogger"]))
frappe.model.meta.clear_cache("Blog Post")
doc = frappe.get_doc("Blog Post", "_test-blog-post")
self.assertFalse(doc.has_permission("read"))
doc = frappe.get_doc("Blog Post", "_test-blog-post-2")
self.assertTrue(doc.has_permission("read"))
frappe.model.meta.clear_cache("Blog Post")
def if_owner_setup(self):
frappe.db.sql("""update `tabDocPerm` set if_owner=1
where parent='Blog Post' and permlevel=0 and permlevel=0 and role='Blogger'""")
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1",
"test2@example.com")
frappe.permissions.add_user_permission("Blogger", "_Test Blogger 1",
"test2@example.com")
frappe.db.sql("""update `tabDocPerm` set user_permission_doctypes=%s
where parent='Blog Post' and permlevel=0 and apply_user_permissions=1
and `read`=1""", json.dumps(["Blog Category"]))
frappe.model.meta.clear_cache("Blog Post")
def test_insert_if_owner_with_user_permissions(self):
"""If `If Owner` is checked for a Role, check if that document is allowed to be read, updated, submitted, etc. except be created, even if the document is restricted based on User Permissions."""
self.if_owner_setup()
frappe.set_user("test2@example.com")
doc = frappe.get_doc({
"doctype": "Blog Post",
"blog_category": "_Test Blog Category",
"blogger": "_Test Blogger 1",
"title": "_Test Blog Post Title",
"content": "_Test Blog Post Content"
})
self.assertRaises(frappe.PermissionError, doc.insert)
frappe.set_user("Administrator")
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category",
"test2@example.com")
frappe.set_user("test2@example.com")
doc.insert()
frappe.set_user("Administrator")
frappe.permissions.remove_user_permission("Blog Category", "_Test Blog Category",
"test2@example.com")
frappe.set_user("test2@example.com")
doc = frappe.get_doc(doc.doctype, doc.name)
self.assertTrue(doc.has_permission("read"))
self.assertTrue(doc.has_permission("write"))
self.assertFalse(doc.has_permission("create"))

View file

@ -8,50 +8,9 @@ frappe.utils.autodoc
Inspect elements of a given module and return its objects
"""
import inspect, importlib, re, frappe, os, shutil
import inspect, importlib, re, frappe
from frappe.model.document import get_controller
from markdown2 import markdown
def build(app):
app_path = frappe.get_app_path(app)
source = frappe.get_app_path(app, "src")
dest = frappe.get_app_path(app, "www")
for basepath, folders, files in os.walk(source):
destpath = os.path.join(dest, os.path.relpath(basepath, source))
# make target dir if missing
if not os.path.exists(destpath):
os.makedirs(destpath)
# delete removed folders in source from dest
for destfolder in os.listdir(destpath):
if os.path.isdir(os.path.join(destpath, destfolder)):
if destfolder not in folders:
os.path.join(destpath, destfolder)
shutil.rmtree(os.path.join(destpath, destfolder))
for fname in files:
# delete file
if os.path.exists(os.path.join(destpath, fname)):
os.remove(os.path.join(destpath, fname))
print fname
if fname.rsplit(".", 1)[-1] in ("md", "html"):
# render template and build file
with open(os.path.join(destpath, fname.rsplit(".", 1)[0] + ".html"), "w") as destfile:
if fname.endswith(".md"):
# convert markdown to html before rendering
with open(os.path.join(basepath, fname), "r") as template_file:
template = markdown(template_file.read())
html = frappe.render_template(template, {}).encode("utf-8")
destfile.write(html)
else:
template_path = os.path.relpath(os.path.join(basepath, fname), app_path)
html = frappe.render_template(template_path, {}, is_path=True).encode("utf-8")
destfile.write(html)
else:
# not a template, copy
shutil.copyfile(os.path.join(basepath, fname), os.path.join(destpath, fname))
def automodule(name):
"""Returns a list of attributes for given module string.
@ -85,16 +44,22 @@ def automodule(name):
"members": filter(None, attributes),
}
installed = None
def get_version(name):
print name
global installed
if not installed:
installed = frappe.get_installed_apps()
def _for_module(m):
return importlib.import_module(m.split(".")[0]).__version__
if "." in name or name=="frappe":
if "." in name or name in installed:
return _for_module(name)
else:
return _for_module(get_controller(name).__module__)
def get_class_info(class_obj, module_name):
members = []
for attrname in dir(class_obj):
@ -117,15 +82,14 @@ def get_class_info(class_obj, module_name):
}
def get_function_info(value):
docs = getattr(value, "__doc__", "")
if docs:
return {
"name": value.__name__,
"type": "function",
"args": inspect.getargspec(value),
"docs": parse(docs),
"whitelisted": value in frappe.whitelisted
}
docs = getattr(value, "__doc__")
return {
"name": value.__name__,
"type": "function",
"args": inspect.getargspec(value),
"docs": parse(docs) if docs else '<span class="text-muted">No docs</span>',
"whitelisted": value in frappe.whitelisted
}
def parse(docs):
"""Parse __docs__ text into markdown. Will parse directives like `:param name:` etc"""
@ -179,17 +143,3 @@ def strip_leading_tabs(docs):
def automodel(doctype):
"""return doctype template"""
pass
def get_doclink(name):
"""Returns `__doclink__` property of a module or DocType if exists"""
if name=="[Select]": return ""
if "." in name:
obj = frappe.get_attr(name)
else:
obj = get_controller(name)
if hasattr(obj, "__doclink__"):
return obj.__doclink__
else:
return ""

View file

@ -32,9 +32,10 @@ def get_allowed_functions_for_jenv():
import frappe
import frappe.utils
import frappe.utils.data
from frappe.utils.autodoc import automodule, get_doclink, get_version
from frappe.utils.autodoc import automodule, get_version
from frappe.model.document import get_controller
from frappe.website.utils import get_shade
from frappe.modules import scrub
datautils = {}
for key, obj in frappe.utils.data.__dict__.items():
@ -76,14 +77,14 @@ def get_allowed_functions_for_jenv():
},
"autodoc": {
"get_version": get_version,
"get_doclink": get_doclink,
"automodule": automodule,
"get_controller": get_controller
},
"get_visible_columns": \
frappe.get_attr("frappe.templates.pages.print.get_visible_columns"),
"_": frappe._,
"get_shade": get_shade
"get_shade": get_shade,
"scrub": scrub
}
def get_jloader():

View file

@ -6,20 +6,50 @@ Call from command line:
"""
import os, json, frappe
import os, json, frappe, markdown2, shutil
class setup_docs(object):
def __init__(self, app, docs_app, path):
"""Generate source templates for models reference and module API.
Must set globals `self.models_base_path`, `self.api_base_path` and `self.app_path`.
def __init__(self):
"""Generate source templates for models reference and module API
and templates at `templates/autodoc`
"""
self.app = app
self.app_path = frappe.get_app_path(app)
if path[0]=="/": path = path[1:]
path = frappe.get_app_path(docs_app, path)
self.app = frappe.get_hooks("autodoc").get("for_app")[0]
docs_app = frappe.get_hooks("autodoc").get("docs_app")[0]
hooks = frappe.get_hooks(app_name = self.app)
self.app_title = hooks.get("app_title")[0]
self.app_path = frappe.get_app_path(self.app)
path = frappe.get_app_path(docs_app, "www", "current")
print "Deleting current..."
shutil.rmtree(path, ignore_errors = True)
os.makedirs(path)
self.app_context = {
"app": {
"name": self.app,
"title": self.app_title,
"description": markdown2.markdown(hooks.get("app_description")[0]),
"version": hooks.get("app_version")[0],
"publisher": hooks.get("app_publisher")[0],
"github_link": hooks.get("github_link")[0],
}
}
# make home page
with open(os.path.join(path, "index.html"), "w") as home:
home.write(frappe.render_template("templates/autodoc/docs_home.html",
self.app_context))
# make folders
self.models_base_path = os.path.join(path, "models")
self.make_folder(self.models_base_path,
template = "templates/autodoc/models_home.html")
self.api_base_path = os.path.join(path, "api")
self.make_folder(self.api_base_path,
template = "templates/autodoc/api_home.html")
for basepath, folders, files in os.walk(self.app_path):
if "doctype" not in basepath:
@ -28,7 +58,9 @@ class setup_docs(object):
module_folder = os.path.join(self.models_base_path, module)
self.make_folder(module_folder)
self.make_folder(module_folder,
template = "templates/autodoc/module_home.html",
context = {"name": module})
self.update_index_txt(module_folder)
if "doctype" in basepath:
@ -70,35 +102,37 @@ class setup_docs(object):
if not os.path.exists(module_doc_path):
print "Writing " + module_doc_path
with open(module_doc_path, "w") as f:
f.write("""<h1>%(name)s</h1>
<!-- title: %(name)s -->
{%%- from "templates/autodoc/macros.html" import automodule -%%}
{{ automodule("%(name)s") }}""" % {"name": self.app + "." + module_name})
context = {"name": self.app + "." + module_name}
context.update(self.app_context)
f.write(frappe.render_template("templates/autodoc/pymodule.html",
context))
self.update_index_txt(module_folder)
def make_folder(self, path):
def make_folder(self, path, template=None, context=None):
if not template:
template = "templates/autodoc/package_index.html"
if not os.path.exists(path):
os.makedirs(path)
index_txt_path = os.path.join(path, "index.txt")
if not os.path.exists(index_txt_path):
index_txt_path = os.path.join(path, "index.txt")
print "Writing " + index_txt_path
with open(index_txt_path, "w") as f:
f.write("")
index_md_path = os.path.join(path, "index.html")
if not os.path.exists(index_md_path):
name = os.path.basename(path)
if name==".":
name = self.app
print "Writing " + index_md_path
with open(index_md_path, "w") as f:
f.write("""<h1>{0}</h1>
<!-- title: {0} -->
{{index}}""".format(name))
index_html_path = os.path.join(path, "index.html")
if not context:
name = os.path.basename(path)
if name==".":
name = self.app
context = {
"title": name
}
context.update(self.app_context)
print "Writing " + index_html_path
with open(index_html_path, "w") as f:
f.write(frappe.render_template(template, context))
def update_index_txt(self, path):
index_txt_path = os.path.join(path, "index.txt")
@ -126,12 +160,7 @@ class setup_docs(object):
print "Writing " + model_path
with open(model_path, "w") as f:
f.write("""<h1>%(doctype)s</h1>
<!-- title: %(doctype)s -->
{%% from "templates/autodoc/doctype.html" import render_doctype %%}
{{ render_doctype("%(doctype)s") }}
<!-- jinja --><!-- static -->
""" % {"doctype": doctype_real_name})
context = {"doctype": doctype_real_name}
context.update(self.app_context)
f.write(frappe.render_template("templates/autodoc/doctype.html",
context).encode("utf-8"))

View file

@ -1,177 +1,9 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
"""Use blog post test to test user permissions logic"""
import frappe
import frappe.defaults
import unittest
import json
import frappe.model.meta
from frappe.core.page.user_permissions.user_permissions import add, remove, get_permissions
from frappe.permissions import clear_user_permissions_for_doctype, get_doc_permissions
test_records = frappe.get_test_records('Blog Post')
test_dependencies = ["User"]
class TestBlogPost(unittest.TestCase):
def setUp(self):
frappe.clear_cache(doctype="Blog Post")
pass
user = frappe.get_doc("User", "test1@example.com")
user.add_roles("Website Manager")
user = frappe.get_doc("User", "test2@example.com")
user.add_roles("Blogger")
frappe.set_user("test1@example.com")
def tearDown(self):
frappe.set_user("Administrator")
frappe.db.set_value("Blogger", "_Test Blogger 1", "user", None)
clear_user_permissions_for_doctype("Blog Category")
clear_user_permissions_for_doctype("Blog Post")
clear_user_permissions_for_doctype("Blogger")
frappe.db.sql("""update `tabDocPerm` set user_permission_doctypes=null
where parent='Blog Post' and permlevel=0 and apply_user_permissions=1
and `read`=1""")
def test_basic_permission(self):
post = frappe.get_doc("Blog Post", "_test-blog-post")
self.assertTrue(post.has_permission("read"))
def test_user_permissions_in_doc(self):
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1",
"test2@example.com")
frappe.set_user("test2@example.com")
post = frappe.get_doc("Blog Post", "_test-blog-post")
self.assertFalse(post.has_permission("read"))
self.assertFalse(get_doc_permissions(post).get("read"))
post1 = frappe.get_doc("Blog Post", "_test-blog-post-1")
self.assertTrue(post1.has_permission("read"))
self.assertTrue(get_doc_permissions(post1).get("read"))
def test_user_permissions_in_report(self):
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1", "test2@example.com")
frappe.set_user("test2@example.com")
names = [d.name for d in frappe.get_list("Blog Post", fields=["name", "blog_category"])]
self.assertTrue("_test-blog-post-1" in names)
self.assertFalse("_test-blog-post" in names)
def test_default_values(self):
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1", "test2@example.com")
frappe.set_user("test2@example.com")
doc = frappe.new_doc("Blog Post")
self.assertEquals(doc.get("blog_category"), "_Test Blog Category 1")
def test_user_link_match_doc(self):
blogger = frappe.get_doc("Blogger", "_Test Blogger 1")
blogger.user = "test2@example.com"
blogger.save()
frappe.set_user("test2@example.com")
post = frappe.get_doc("Blog Post", "_test-blog-post-2")
self.assertTrue(post.has_permission("read"))
post1 = frappe.get_doc("Blog Post", "_test-blog-post-1")
self.assertFalse(post1.has_permission("read"))
def test_user_link_match_report(self):
blogger = frappe.get_doc("Blogger", "_Test Blogger 1")
blogger.user = "test2@example.com"
blogger.save()
frappe.set_user("test2@example.com")
names = [d.name for d in frappe.get_list("Blog Post", fields=["name", "owner"])]
self.assertTrue("_test-blog-post-2" in names)
self.assertFalse("_test-blog-post-1" in names)
def test_set_user_permissions(self):
frappe.set_user("test1@example.com")
add("test2@example.com", "Blog Post", "_test-blog-post")
def test_not_allowed_to_set_user_permissions(self):
frappe.set_user("test2@example.com")
# this user can't add user permissions
self.assertRaises(frappe.PermissionError, add,
"test2@example.com", "Blog Post", "_test-blog-post")
def test_read_if_explicit_user_permissions_are_set(self):
self.test_set_user_permissions()
frappe.set_user("test2@example.com")
# user can only access permitted blog post
doc = frappe.get_doc("Blog Post", "_test-blog-post")
self.assertTrue(doc.has_permission("read"))
# and not this one
doc = frappe.get_doc("Blog Post", "_test-blog-post-1")
self.assertFalse(doc.has_permission("read"))
def test_not_allowed_to_remove_user_permissions(self):
self.test_set_user_permissions()
defname = get_permissions("test2@example.com", "Blog Post", "_test-blog-post")[0].name
frappe.set_user("test2@example.com")
# user cannot remove their own user permissions
self.assertRaises(frappe.PermissionError, remove,
"test2@example.com", defname, "Blog Post", "_test-blog-post")
def test_user_permissions_based_on_blogger(self):
frappe.set_user("test2@example.com")
doc = frappe.get_doc("Blog Post", "_test-blog-post-1")
self.assertTrue(doc.has_permission("read"))
frappe.set_user("test1@example.com")
add("test2@example.com", "Blog Post", "_test-blog-post")
frappe.set_user("test2@example.com")
doc = frappe.get_doc("Blog Post", "_test-blog-post-1")
self.assertFalse(doc.has_permission("read"))
doc = frappe.get_doc("Blog Post", "_test-blog-post")
self.assertTrue(doc.has_permission("read"))
def test_set_only_once(self):
blog_post = frappe.get_meta("Blog Post")
blog_post.get_field("title").set_only_once = 1
doc = frappe.get_doc("Blog Post", "_test-blog-post-1")
doc.title = "New"
self.assertRaises(frappe.CannotChangeConstantError, doc.save)
blog_post.get_field("title").set_only_once = 0
def test_user_permission_doctypes(self):
frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1",
"test2@example.com")
frappe.permissions.add_user_permission("Blogger", "_Test Blogger 1",
"test2@example.com")
frappe.set_user("test2@example.com")
frappe.db.sql("""update `tabDocPerm` set user_permission_doctypes=%s
where parent='Blog Post' and permlevel=0 and apply_user_permissions=1
and `read`=1""", json.dumps(["Blogger"]))
frappe.model.meta.clear_cache("Blog Post")
doc = frappe.get_doc("Blog Post", "_test-blog-post")
self.assertFalse(doc.has_permission("read"))
doc = frappe.get_doc("Blog Post", "_test-blog-post-2")
self.assertTrue(doc.has_permission("read"))
frappe.model.meta.clear_cache("Blog Post")

View file

@ -214,7 +214,7 @@
"precision": ""
},
{
"description": "In JSON as <pre>[{\"title\":\"Jobs\", \"name\":\"jobs\"}]</pre>",
"description": "In JSON as [{\"title\":\"Jobs\", \"name\":\"jobs\"}]",
"fieldname": "breadcrumbs",
"fieldtype": "Small Text",
"label": "Breadcrumbs",
@ -262,4 +262,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "title"
}
}

View file

@ -200,22 +200,41 @@
"icon": "icon-file-alt",
"idx": 1,
"max_attachments": 20,
"modified": "2015-07-13 04:46:59.435179",
"modified": "2015-07-22 12:38:08.696692",
"modified_by": "Administrator",
"module": "Website",
"name": "Web Page",
"owner": "Administrator",
"permissions": [
{
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Website Manager",
"share": 1,
"submit": 0,
"write": 0
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Website Manager",
"role": "Guest",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1

View file

@ -231,7 +231,7 @@
"permlevel": 0
},
{
"description": "An icon file with .ico extension. Should be 16 x 16 px. Generated using a favicon generator. [<a href=\"http://favicon-generator.org/\" target=\"_blank\">favicon-generator.org</a>]",
"description": "An icon file with .ico extension. Should be 16 x 16 px. Generated using a favicon generator. [favicon-generator.org]",
"fieldname": "favicon",
"fieldtype": "Attach",
"label": "FavIcon",
@ -296,4 +296,4 @@
"submit": 0
}
]
}
}

View file

@ -118,8 +118,6 @@ def get_website_settings():
context.web_include_css = hooks.web_include_css or []
add_website_theme(context)
via_hooks = frappe.get_hooks("website_context")
for key in via_hooks:
context[key] = via_hooks[key]
@ -127,10 +125,12 @@ def get_website_settings():
and isinstance(context[key], (list, tuple)):
context[key] = context[key][0]
add_website_theme(context)
if not context.get("favicon"):
context["favicon"] = "/assets/frappe/images/favicon.png"
if settings.favicon:
if settings.favicon and settings.favicon != "attach_files:":
context["favicon"] = settings.favicon
return context

View file

@ -1,304 +1,304 @@
{
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "field:theme",
"creation": "2015-02-18 12:46:38.168929",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Master",
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "field:theme",
"creation": "2015-02-18 12:46:38.168929",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Master",
"fields": [
{
"allow_on_submit": 0,
"fieldname": "theme",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Theme",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 1,
"allow_on_submit": 0,
"fieldname": "theme",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Theme",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 1,
"set_only_once": 0
},
},
{
"allow_on_submit": 0,
"default": "Website",
"fieldname": "module",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Module",
"no_copy": 0,
"options": "Module Def",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"allow_on_submit": 0,
"default": "Website",
"fieldname": "module",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Module",
"no_copy": 0,
"options": "Module Def",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0
},
},
{
"default": "1",
"description": "This must be checked if the below style settings are applicable",
"fieldname": "apply_style",
"fieldtype": "Check",
"hidden": 0,
"label": "Apply Style",
"permlevel": 0,
"default": "1",
"description": "This must be checked if the below style settings are applicable",
"fieldname": "apply_style",
"fieldtype": "Check",
"hidden": 0,
"label": "Apply Style",
"permlevel": 0,
"precision": ""
},
},
{
"default": "1",
"fieldname": "custom",
"fieldtype": "Check",
"label": "Custom?",
"permlevel": 0,
"default": "1",
"fieldname": "custom",
"fieldtype": "Check",
"label": "Custom?",
"permlevel": 0,
"precision": ""
},
},
{
"allow_on_submit": 0,
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"allow_on_submit": 0,
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
},
{
"description": "Link to your Bootstrap theme",
"fieldname": "bootstrap",
"fieldtype": "Small Text",
"label": "Link to Bootstrap CSS",
"permlevel": 0,
"description": "Link to your Bootstrap theme",
"fieldname": "bootstrap",
"fieldtype": "Small Text",
"label": "Link to Bootstrap CSS",
"permlevel": 0,
"precision": ""
},
},
{
"depends_on": "apply_style",
"fieldname": "section_break_14",
"fieldtype": "Section Break",
"permlevel": 0,
"depends_on": "apply_style",
"fieldname": "section_break_14",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
},
{
"default": "",
"fieldname": "font_size",
"fieldtype": "Select",
"label": "Font Size",
"options": "\n12px\n13px\n14px\n15px\n16px\n17px\n18px",
"permlevel": 0,
"default": "",
"fieldname": "font_size",
"fieldtype": "Select",
"label": "Font Size",
"options": "\n12px\n13px\n14px\n15px\n16px\n17px\n18px",
"permlevel": 0,
"precision": ""
},
},
{
"description": "Add the name of a <a href=\"https://www.google.com/fonts/\" target=\"_blank\">Google Web Font</a> e.g. \"Open Sans\"",
"fieldname": "text_webfont",
"fieldtype": "Data",
"label": "Google Font (Text)",
"permlevel": 0,
"description": "Add the name of a \"Google Web Font\" e.g. \"Open Sans\"",
"fieldname": "text_webfont",
"fieldtype": "Data",
"label": "Google Font (Text)",
"permlevel": 0,
"precision": ""
},
},
{
"description": "Add the name of a <a href=\"https://www.google.com/fonts/\" target=\"_blank\">Google Web Font</a> e.g. \"Open Sans\"",
"fieldname": "heading_webfont",
"fieldtype": "Data",
"label": "Google Font (Heading)",
"permlevel": 0,
"description": "Add the name of a \"Google Web Font\" e.g. \"Open Sans\"",
"fieldname": "heading_webfont",
"fieldtype": "Data",
"label": "Google Font (Heading)",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "column_break_18",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "column_break_18",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "text_color",
"fieldtype": "Data",
"label": "Text Color",
"permlevel": 0,
"fieldname": "text_color",
"fieldtype": "Data",
"label": "Text Color",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "link_color",
"fieldtype": "Data",
"label": "Link Color",
"permlevel": 0,
"fieldname": "link_color",
"fieldtype": "Data",
"label": "Link Color",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "heading_style",
"fieldtype": "Select",
"label": "Heading Style",
"options": "\nUPPERCASE\nTitle Case\nlowercase",
"permlevel": 0,
"fieldname": "heading_style",
"fieldtype": "Select",
"label": "Heading Style",
"options": "\nUPPERCASE\nTitle Case\nlowercase",
"permlevel": 0,
"precision": ""
},
},
{
"depends_on": "apply_style",
"fieldname": "section_break_8",
"fieldtype": "Section Break",
"permlevel": 0,
"depends_on": "apply_style",
"fieldname": "section_break_8",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "top_bar_color",
"fieldtype": "Data",
"label": "Top Bar Color",
"permlevel": 0,
"fieldname": "top_bar_color",
"fieldtype": "Data",
"label": "Top Bar Color",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "top_bar_text_color",
"fieldtype": "Data",
"label": "Top Bar Text Color",
"permlevel": 0,
"fieldname": "top_bar_text_color",
"fieldtype": "Data",
"label": "Top Bar Text Color",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "no_sidebar",
"fieldtype": "Check",
"label": "Hide Sidebar",
"permlevel": 0,
"fieldname": "no_sidebar",
"fieldtype": "Check",
"label": "Hide Sidebar",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "column_break_11",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "column_break_11",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "footer_color",
"fieldtype": "Data",
"label": "Footer Color",
"permlevel": 0,
"fieldname": "footer_color",
"fieldtype": "Data",
"label": "Footer Color",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "footer_text_color",
"fieldtype": "Data",
"label": "Footer Text Color",
"permlevel": 0,
"fieldname": "footer_text_color",
"fieldtype": "Data",
"label": "Footer Text Color",
"permlevel": 0,
"precision": ""
},
},
{
"depends_on": "apply_style",
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"permlevel": 0,
"depends_on": "apply_style",
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "background_color",
"fieldtype": "Data",
"label": "Background Color",
"permlevel": 0,
"fieldname": "background_color",
"fieldtype": "Data",
"label": "Background Color",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "column_break_6",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "column_break_6",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
},
{
"description": "If image is selected, color will be ignored.",
"fieldname": "background_image",
"fieldtype": "Attach Image",
"label": "Background Image",
"permlevel": 0,
"description": "If image is selected, color will be ignored.",
"fieldname": "background_image",
"fieldtype": "Attach Image",
"label": "Background Image",
"permlevel": 0,
"precision": ""
},
},
{
"depends_on": "",
"fieldname": "section_break_21",
"fieldtype": "Section Break",
"permlevel": 0,
"depends_on": "",
"fieldname": "section_break_21",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
},
{
"depends_on": "apply_style",
"description": "",
"fieldname": "css",
"fieldtype": "Code",
"label": "Style using CSS",
"permlevel": 0,
"depends_on": "apply_style",
"description": "",
"fieldname": "css",
"fieldtype": "Code",
"label": "Style using CSS",
"permlevel": 0,
"precision": ""
},
},
{
"fieldname": "js",
"fieldtype": "Code",
"label": "JavaScript",
"permlevel": 0,
"fieldname": "js",
"fieldtype": "Code",
"label": "JavaScript",
"permlevel": 0,
"precision": ""
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"modified": "2015-07-13 04:45:02.429785",
"modified_by": "Administrator",
"module": "Website",
"name": "Website Theme",
"name_case": "",
"owner": "Administrator",
],
"hide_heading": 0,
"hide_toolbar": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"modified": "2015-07-27 01:00:32.901851",
"modified_by": "Administrator",
"module": "Website",
"name": "Website Theme",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"permlevel": 0,
"read": 1,
"role": "Website Manager",
"create": 1,
"delete": 1,
"permlevel": 0,
"read": 1,
"role": "Website Manager",
"write": 1
},
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 0,
"export": 1,
"import": 1,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Administrator",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 0,
"export": 1,
"import": 1,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Administrator",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 1
}
],
"read_only": 0,
"read_only_onload": 0,
"search_fields": "",
"sort_field": "modified",
"sort_order": "DESC",
],
"read_only": 0,
"read_only_onload": 0,
"search_fields": "",
"sort_field": "modified",
"sort_order": "DESC",
"title_field": ""
}
}

View file

@ -63,13 +63,20 @@ def use_theme(theme):
def add_website_theme(context):
bootstrap = frappe.get_hooks("bootstrap")[0]
website_theme = get_active_theme()
context.theme = website_theme and website_theme.as_dict() or frappe._dict()
if website_theme:
if website_theme.bootstrap:
bootstrap = website_theme.bootstrap
web_include_css = context.web_include_css
context.theme = frappe._dict()
context.no_sidebar = website_theme.no_sidebar
if not context.disable_website_theme:
website_theme = get_active_theme()
context.theme = website_theme and website_theme.as_dict() or frappe._dict()
if website_theme:
if website_theme.bootstrap:
bootstrap = website_theme.bootstrap
context.no_sidebar = website_theme.no_sidebar
context.web_include_css = ["website_theme.css"] + context.web_include_css
context.web_include_css = [bootstrap] + context.web_include_css

View file

@ -340,6 +340,9 @@ $.extend(frappe, {
// change id of current page
$(".page-container").attr("id", "page-" + data.path);
// set data-path value in body
$("body").attr("data-path", data.path);
// clear page-header-right
$(".page-header-right").html("");

View file

@ -1,100 +1,100 @@
{
"allow_rename": 1,
"autoname": "field:workflow_name",
"creation": "2012-12-28 10:49:55",
"description": "Defines workflow states and rules for a document.",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Transaction",
"allow_rename": 1,
"autoname": "field:workflow_name",
"creation": "2012-12-28 10:49:55",
"description": "Defines workflow states and rules for a document.",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Transaction",
"fields": [
{
"fieldname": "workflow_name",
"fieldtype": "Data",
"in_list_view": 0,
"label": "Workflow Name",
"permlevel": 0,
"read_only": 0,
"fieldname": "workflow_name",
"fieldtype": "Data",
"in_list_view": 0,
"label": "Workflow Name",
"permlevel": 0,
"read_only": 0,
"reqd": 1
},
},
{
"description": "DocType on which this Workflow is applicable.",
"fieldname": "document_type",
"fieldtype": "Link",
"in_list_view": 0,
"label": "Document Type",
"options": "DocType",
"permlevel": 0,
"description": "DocType on which this Workflow is applicable.",
"fieldname": "document_type",
"fieldtype": "Link",
"in_list_view": 0,
"label": "Document Type",
"options": "DocType",
"permlevel": 0,
"reqd": 1
},
},
{
"description": "If checked, all other workflows become inactive.",
"fieldname": "is_active",
"fieldtype": "Check",
"in_list_view": 0,
"label": "Is Active",
"description": "If checked, all other workflows become inactive.",
"fieldname": "is_active",
"fieldtype": "Check",
"in_list_view": 0,
"label": "Is Active",
"permlevel": 0
},
},
{
"description": "Different \"States\" this document can exist in. Like \"Open\", \"Pending Approval\" etc.",
"fieldname": "states_head",
"fieldtype": "Section Break",
"label": "States",
"description": "Different \"States\" this document can exist in. Like \"Open\", \"Pending Approval\" etc.",
"fieldname": "states_head",
"fieldtype": "Section Break",
"label": "States",
"permlevel": 0
},
},
{
"description": "All possible Workflow States and roles of the workflow. <br>Docstatus Options: 0 is\"Saved\", 1 is \"Submitted\" and 2 is \"Cancelled\"",
"fieldname": "states",
"fieldtype": "Table",
"label": "Document States",
"options": "Workflow Document State",
"permlevel": 0,
"description": "All possible Workflow States and roles of the workflow. \nDocstatus Options: 0 is\"Saved\", 1 is \"Submitted\" and 2 is \"Cancelled\"",
"fieldname": "states",
"fieldtype": "Table",
"label": "Document States",
"options": "Workflow Document State",
"permlevel": 0,
"reqd": 1
},
},
{
"description": "Rules for how states are transitions, like next state and which role is allowed to change state etc.",
"fieldname": "transition_rules",
"fieldtype": "Section Break",
"label": "Transition Rules",
"description": "Rules for how states are transitions, like next state and which role is allowed to change state etc.",
"fieldname": "transition_rules",
"fieldtype": "Section Break",
"label": "Transition Rules",
"permlevel": 0
},
},
{
"description": "Rules defining transition of state in the workflow.",
"fieldname": "transitions",
"fieldtype": "Table",
"label": "Transitions",
"options": "Workflow Transition",
"permlevel": 0,
"description": "Rules defining transition of state in the workflow.",
"fieldname": "transitions",
"fieldtype": "Table",
"label": "Transitions",
"options": "Workflow Transition",
"permlevel": 0,
"reqd": 1
},
},
{
"default": "workflow_state",
"description": "Field that represents the Workflow State of the transaction (if field is not present, a new hidden Custom Field will be created)",
"fieldname": "workflow_state_field",
"fieldtype": "Data",
"label": "Workflow State Field",
"default": "workflow_state",
"description": "Field that represents the Workflow State of the transaction (if field is not present, a new hidden Custom Field will be created)",
"fieldname": "workflow_state_field",
"fieldtype": "Data",
"label": "Workflow State Field",
"permlevel": 0
}
],
"icon": "icon-random",
"idx": 1,
"modified": "2015-02-05 05:11:49.280959",
"modified_by": "Administrator",
"module": "Workflow",
"name": "Workflow",
"owner": "Administrator",
],
"icon": "icon-random",
"idx": 1,
"modified": "2015-07-27 01:00:32.901851",
"modified_by": "Administrator",
"module": "Workflow",
"name": "Workflow",
"owner": "Administrator",
"permissions": [
{
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"role": "System Manager",
"share": 1,
"submit": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"role": "System Manager",
"share": 1,
"submit": 0,
"write": 1
}
]
}
}

View file

@ -1,6 +1,6 @@
from setuptools import setup, find_packages
version = "5.1.3"
version = "5.1.4"
with open("requirements.txt", "r") as f:
install_requires = f.readlines()