@@ -13,7 +13,8 @@ import os, sys, importlib, inspect, json | |||
from .exceptions import * | |||
from .utils.jinja import get_jenv, get_template, render_template | |||
__version__ = "7.0.47" | |||
__version__ = '7.2.0' | |||
__title__ = "Frappe Framework" | |||
local = Local() | |||
@@ -46,7 +47,7 @@ def _(msg, lang=None): | |||
lang = local.lang | |||
# msg should always be unicode | |||
msg = cstr(msg) | |||
msg = cstr(msg).strip() | |||
return get_full_dict(local.lang).get(msg) or msg | |||
@@ -55,8 +56,6 @@ def get_lang_dict(fortype, name=None): | |||
:param fortype: must be one of `doctype`, `page`, `report`, `include`, `jsfile`, `boot` | |||
:param name: name of the document for which assets are to be returned.""" | |||
if local.lang=="en": | |||
return {} | |||
from frappe.translate import get_dict | |||
return get_dict(fortype, name) | |||
@@ -172,7 +171,9 @@ def get_site_config(sites_path=None, site_path=None): | |||
if os.path.exists(site_config): | |||
config.update(get_file_json(site_config)) | |||
elif local.site and not local.flags.new_site: | |||
raise IncorrectSitePath, "{0} does not exist".format(site_config) | |||
print "{0} does not exist".format(local.site) | |||
sys.exit(1) | |||
#raise IncorrectSitePath, "{0} does not exist".format(site_config) | |||
return _dict(config) | |||
@@ -273,7 +274,7 @@ def msgprint(msg, title=None, raise_exception=0, as_table=False, indicator=None, | |||
if as_table and type(msg) in (list, tuple): | |||
out.msg = '<table border="1px" style="border-collapse: collapse" cellpadding="2px">' + ''.join(['<tr>'+''.join(['<td>%s</td>' % c for c in r])+'</tr>' for r in msg]) + '</table>' | |||
if flags.print_messages: | |||
if flags.print_messages and out.msg: | |||
print "Message: " + repr(out.msg).encode("utf-8") | |||
if title: | |||
@@ -488,7 +489,7 @@ def has_permission(doctype=None, ptype="read", doc=None, user=None, verbose=Fals | |||
return out | |||
def has_website_permission(doctype, ptype="read", doc=None, user=None, verbose=False): | |||
def has_website_permission(doc=None, ptype='read', user=None, verbose=False): | |||
"""Raises `frappe.PermissionError` if not permitted. | |||
:param doctype: DocType for which permission is to be check. | |||
@@ -499,11 +500,21 @@ def has_website_permission(doctype, ptype="read", doc=None, user=None, verbose=F | |||
if not user: | |||
user = session.user | |||
hooks = (get_hooks("has_website_permission") or {}).get(doctype, []) | |||
if hooks: | |||
if doc: | |||
if isinstance(doc, basestring): | |||
doc = get_doc(doctype, doc) | |||
doctype = doc.doctype | |||
if doc.flags.ignore_permissions: | |||
return True | |||
# check permission in controller | |||
if hasattr(doc, 'has_website_permission'): | |||
return doc.has_website_permission(ptype, verbose=verbose) | |||
hooks = (get_hooks("has_website_permission") or {}).get(doctype, []) | |||
if hooks: | |||
for method in hooks: | |||
result = call(method, doc=doc, ptype=ptype, user=user, verbose=verbose) | |||
# if even a single permission check is Falsy | |||
@@ -553,7 +564,7 @@ def new_doc(doctype, parent_doc=None, parentfield=None, as_dict=False): | |||
from frappe.model.create_new import get_new_doc | |||
return get_new_doc(doctype, parent_doc, parentfield, as_dict=as_dict) | |||
def set_value(doctype, docname, fieldname, value): | |||
def set_value(doctype, docname, fieldname, value=None): | |||
"""Set document value. Calls `frappe.client.set_value`""" | |||
import frappe.client | |||
return frappe.client.set_value(doctype, docname, fieldname, value) | |||
@@ -1113,7 +1124,7 @@ def as_json(obj, indent=1): | |||
return json.dumps(obj, indent=indent, sort_keys=True, default=json_handler) | |||
def are_emails_muted(): | |||
return flags.mute_emails or conf.get("mute_emails") or False | |||
return flags.mute_emails or int(conf.get("mute_emails") or 0) or False | |||
def get_test_records(doctype): | |||
"""Returns list of objects from `test_records.json` in the given doctype's folder.""" | |||
@@ -1125,13 +1136,21 @@ def get_test_records(doctype): | |||
else: | |||
return [] | |||
def format_value(value, df, doc=None, currency=None): | |||
def format_value(*args, **kwargs): | |||
"""Format value with given field properties. | |||
:param value: Value to be formatted. | |||
:param df: DocField object with properties `fieldtype`, `options` etc.""" | |||
:param df: (Optional) DocField object with properties `fieldtype`, `options` etc.""" | |||
import frappe.utils.formatters | |||
return frappe.utils.formatters.format_value(value, df, doc, currency=currency) | |||
return frappe.utils.formatters.format_value(*args, **kwargs) | |||
def format(*args, **kwargs): | |||
"""Format value with given field properties. | |||
:param value: Value to be formatted. | |||
:param df: (Optional) DocField object with properties `fieldtype`, `options` etc.""" | |||
import frappe.utils.formatters | |||
return frappe.utils.formatters.format_value(*args, **kwargs) | |||
def get_print(doctype=None, name=None, print_format=None, style=None, html=None, as_pdf=False, doc=None): | |||
"""Get Print Format for given document. | |||
@@ -1241,7 +1260,12 @@ log_level = None | |||
def logger(module=None, with_more_info=True): | |||
'''Returns a python logger that uses StreamHandler''' | |||
from frappe.utils.logger import get_logger | |||
return get_logger(module or __name__, with_more_info=with_more_info) | |||
return get_logger(module or 'default', with_more_info=with_more_info) | |||
def log_error(message=None, title=None): | |||
'''Log error to Error Log''' | |||
get_doc(dict(doctype='Error Log', error=str(message or get_traceback()), | |||
method=title)).insert(ignore_permissions=True) | |||
def get_desk_link(doctype, name): | |||
return '<a href="#Form/{0}/{1}" style="font-weight: bold;">{2} {1}</a>'.format(doctype, name, _(doctype)) | |||
@@ -8,6 +8,9 @@ import frappe.handler | |||
import frappe.client | |||
from frappe.utils.response import build_response | |||
from frappe import _ | |||
from urlparse import urlparse | |||
from urllib import urlencode | |||
from frappe.integration_broker.oauth2 import oauth_server | |||
def handle(): | |||
""" | |||
@@ -32,6 +35,27 @@ def handle(): | |||
`/api/resource/{doctype}/{name}?run_method={method}` will run a whitelisted controller method | |||
""" | |||
form_dict = frappe.local.form_dict | |||
authorization_header = frappe.get_request_header("Authorization").split(" ") if frappe.get_request_header("Authorization") else None | |||
if authorization_header and authorization_header[0].lower() == "bearer": | |||
token = authorization_header[1] | |||
r = frappe.request | |||
parsed_url = urlparse(r.url) | |||
access_token = { "access_token": token} | |||
uri = parsed_url.scheme + "://" + parsed_url.netloc + parsed_url.path + "?" + urlencode(access_token) | |||
http_method = r.method | |||
body = r.get_data() | |||
headers = r.headers | |||
required_scopes = frappe.db.get_value("OAuth Bearer Token", token, "scopes").split(";") | |||
valid, oauthlib_request = oauth_server.verify_request(uri, http_method, body, headers, required_scopes) | |||
if valid: | |||
frappe.set_user(frappe.db.get_value("OAuth Bearer Token", token, "user")) | |||
frappe.local.form_dict = form_dict | |||
parts = frappe.request.path[1:].split("/",3) | |||
call = doctype = name = None | |||
@@ -72,7 +72,6 @@ def application(request): | |||
raise NotFound | |||
except HTTPException, e: | |||
frappe.logger().error('Request Error', exc_info=True) | |||
return e | |||
except frappe.SessionStopped, e: | |||
@@ -150,6 +150,13 @@ class LoginManager: | |||
if not resume: | |||
frappe.response["full_name"] = self.full_name | |||
# redirect information | |||
redirect_to = frappe.cache().hget('redirect_after_login', self.user) | |||
if redirect_to: | |||
frappe.local.response["redirect_to"] = redirect_to | |||
frappe.cache().hdel('redirect_after_login', self.user) | |||
frappe.local.cookie_manager.set_cookie("full_name", self.full_name) | |||
frappe.local.cookie_manager.set_cookie("user_id", self.user) | |||
frappe.local.cookie_manager.set_cookie("user_image", self.info.user_image or "") | |||
@@ -103,16 +103,18 @@ def get_allowed_pages(): | |||
return page_info | |||
def load_translations(bootinfo): | |||
if frappe.local.lang != 'en': | |||
messages = frappe.get_lang_dict("boot") | |||
messages = frappe.get_lang_dict("boot") | |||
bootinfo["lang"] = frappe.lang | |||
bootinfo["lang"] = frappe.lang | |||
# load translated report names | |||
for name in bootinfo.user.all_reports: | |||
messages[name] = frappe._(name) | |||
# load translated report names | |||
for name in bootinfo.user.all_reports: | |||
messages[name] = frappe._(name) | |||
bootinfo["__messages"] = messages | |||
# only untranslated | |||
messages = {k:v for k, v in messages.iteritems() if k!=v} | |||
bootinfo["__messages"] = messages | |||
def get_fullnames(): | |||
"""map of user fullnames""" | |||
@@ -165,3 +167,9 @@ def load_print(bootinfo, doclist): | |||
def load_print_css(bootinfo, print_settings): | |||
bootinfo.print_css = frappe.get_attr("frappe.www.print.get_print_style")(print_settings.print_style or "Modern", for_legacy=True) | |||
def get_unseen_notes(): | |||
return frappe.db.sql('''select name, title, content from tabNote where notify_on_login=1 | |||
and expire_notification_on > %s and %s not in | |||
(select user from `tabNote Seen By` nsb | |||
where nsb.parent=tabNote.name)''', (frappe.utils.now(), frappe.session.user), as_dict=True) |
@@ -57,14 +57,19 @@ def make_asset_dirs(make_copy=False): | |||
# symlink app/public > assets/app | |||
for app_name in frappe.get_all_apps(True): | |||
pymodule = frappe.get_module(app_name) | |||
source = os.path.join(os.path.abspath(os.path.dirname(pymodule.__file__)), 'public') | |||
target = os.path.join(assets_path, app_name) | |||
app_base_path = os.path.abspath(os.path.dirname(pymodule.__file__)) | |||
if not os.path.exists(target) and os.path.exists(source): | |||
if make_copy: | |||
shutil.copytree(os.path.abspath(source), target) | |||
else: | |||
os.symlink(os.path.abspath(source), target) | |||
symlinks = [] | |||
symlinks.append([os.path.join(app_base_path, 'public'), os.path.join(assets_path, app_name)]) | |||
symlinks.append([os.path.join(app_base_path, 'docs'), os.path.join(assets_path, app_name + '_docs')]) | |||
for source, target in symlinks: | |||
source = os.path.abspath(source) | |||
if not os.path.exists(target) and os.path.exists(source): | |||
if make_copy: | |||
shutil.copytree(source, target) | |||
else: | |||
os.symlink(source, target) | |||
def build(no_compress=False, verbose=False): | |||
assets_path = os.path.join(frappe.local.sites_path, "assets") | |||
@@ -72,9 +77,6 @@ def build(no_compress=False, verbose=False): | |||
for target, sources in get_build_maps().iteritems(): | |||
pack(os.path.join(assets_path, target), sources, no_compress, verbose) | |||
shutil.copy(os.path.join(os.path.dirname(os.path.abspath(frappe.__file__)), 'data', 'languages.txt'), frappe.local.sites_path) | |||
# reset_app_html() | |||
def get_build_maps(): | |||
"""get all build.jsons with absolute paths""" | |||
# framework js and css files | |||
@@ -0,0 +1,24 @@ | |||
#### Gantt View | |||
- New Gantt view for documents where date range is available | |||
#### In-App Help | |||
- Search for help from within the app. Click on "Help" | |||
#### Web Form | |||
- Add grids (child tables) | |||
- Add page breaks (for long forms) | |||
- Add payment gateway | |||
- Add attachments | |||
#### Auto Email Report | |||
- Email reports automatically on daily / weekly / monthly basis | |||
#### Other Fixes | |||
- Send a popup to all users on login for a new Note by checking on "Notify users with a popup when they log in" | |||
- Portal Users (Customers, Supplier, Students) can now have roles | |||
- Sidebar in portal view will be rendered as per roles and can be configured from Portal Settings | |||
- Restrict the number of backups to be saved in System Settings | |||
- Scheduler log is now error log and as MyISAM | |||
- A better way to export customzations and Email Alert directly from Customize Form | |||
- Option to send email from Data Import Tool where applicable | |||
- Integration Broker |
@@ -47,22 +47,32 @@ def get_value(doctype, fieldname, filters=None, as_dict=True, debug=False): | |||
return frappe.db.get_value(doctype, filters, fieldname, as_dict=as_dict, debug=debug) | |||
@frappe.whitelist() | |||
def set_value(doctype, name, fieldname, value): | |||
def set_value(doctype, name, fieldname, value=None): | |||
'''Set a value using get_doc, group of values | |||
:param doctype: DocType of the document | |||
:param name: name of the document | |||
:param fieldname: fieldname string or JSON / dict with key value pair | |||
:param value: value if fieldname is JSON / dict''' | |||
if fieldname!="idx" and fieldname in frappe.model.default_fields: | |||
frappe.throw(_("Cannot edit standard fields")) | |||
if not value: | |||
values = fieldname | |||
if isinstance(fieldname, basestring): | |||
values = json.loads(fieldname) | |||
else: | |||
values = {fieldname: value} | |||
doc = frappe.db.get_value(doctype, name, ["parenttype", "parent"], as_dict=True) | |||
if doc and doc.parent and doc.parenttype: | |||
doc = frappe.get_doc(doc.parenttype, doc.parent) | |||
child = doc.getone({"doctype": doctype, "name": name}) | |||
child.set(fieldname, value) | |||
child.update(values) | |||
else: | |||
doc = frappe.get_doc(doctype, name) | |||
df = doc.meta.get_field(fieldname) | |||
if df.fieldtype == "Read Only" or df.read_only: | |||
frappe.throw(_("Can not edit Read Only fields")) | |||
else: | |||
doc.set(fieldname, value) | |||
doc.update(values) | |||
doc.save() | |||
@@ -52,7 +52,7 @@ def build_docs(context, app, docs_version="current", target=None, local=False, w | |||
or "docs.py" in source_path): | |||
_build_docs_once(site, app, docs_version, target, local, only_content_updated=True) | |||
apps_path = frappe.get_app_path("frappe", "..", "..") | |||
apps_path = frappe.get_app_path(app, "..", "..") | |||
start_watch(apps_path, handler=trigger_make) | |||
def _build_docs_once(site, app, docs_version, target, local, only_content_updated=False): | |||
@@ -66,7 +66,9 @@ def _new_site(db_name, site, mariadb_root_username=None, mariadb_root_password=N | |||
print "*** Scheduler is", scheduler_status, "***" | |||
finally: | |||
os.remove(installing) | |||
if os.path.exists(installing): | |||
os.remove(installing) | |||
frappe.destroy() | |||
@click.command('restore') | |||
@@ -238,6 +240,20 @@ def reload_doc(context, module, doctype, docname): | |||
finally: | |||
frappe.destroy() | |||
@click.command('reload-doctype') | |||
@click.argument('doctype') | |||
@pass_context | |||
def reload_doctype(context, doctype): | |||
"Reload schema for a DocType" | |||
for site in context.sites: | |||
try: | |||
frappe.init(site=site) | |||
frappe.connect() | |||
frappe.reload_doctype(doctype, force=context.force) | |||
frappe.db.commit() | |||
finally: | |||
frappe.destroy() | |||
@click.command('use') | |||
@click.argument('site') | |||
@@ -455,6 +471,7 @@ commands = [ | |||
new_site, | |||
reinstall, | |||
reload_doc, | |||
reload_doctype, | |||
remove_from_installed_apps, | |||
restore, | |||
run_patch, | |||
@@ -33,7 +33,7 @@ def new_language(context, lang_code, app): | |||
frappe.translate.write_translations_file(app, lang_code) | |||
print "File created at ./apps/{app}/{app}/translations/{lang_code}.csv".format(app=app, lang_code=lang_code) | |||
print "You will need to add the language in frappe/data/languages.txt, if you haven't done it already." | |||
print "You will need to add the language in frappe/geo/languages.json, if you haven't done it already." | |||
@click.command('get-untranslated') | |||
@click.argument('lang') | |||
@@ -171,7 +171,7 @@ def export_json(context, doctype, path, name=None): | |||
@click.argument('path') | |||
@pass_context | |||
def export_csv(context, doctype, path): | |||
"Export data import template for DocType" | |||
"Export data import template with data for DocType" | |||
from frappe.core.page.data_import_tool import data_import_tool | |||
for site in context.sites: | |||
try: | |||
@@ -200,6 +200,13 @@ def export_fixtures(context): | |||
def import_doc(context, path, force=False): | |||
"Import (insert/update) doclist. If the argument is a directory, all files ending with .json are imported" | |||
from frappe.core.page.data_import_tool import data_import_tool | |||
if not os.path.exists(path): | |||
path = os.path.join('..', path) | |||
if not os.path.exists(path): | |||
print 'Invalid path {0}'.format(path) | |||
sys.exit(1) | |||
for site in context.sites: | |||
try: | |||
frappe.init(site=site) | |||
@@ -213,13 +220,21 @@ def import_doc(context, path, force=False): | |||
@click.option('--only-insert', default=False, is_flag=True, help='Do not overwrite existing records') | |||
@click.option('--submit-after-import', default=False, is_flag=True, help='Submit document after importing it') | |||
@click.option('--ignore-encoding-errors', default=False, is_flag=True, help='Ignore encoding errors while coverting to unicode') | |||
@click.option('--no-email', default=True, is_flag=True, help='Send email if applicable') | |||
@pass_context | |||
def import_csv(context, path, only_insert=False, submit_after_import=False, ignore_encoding_errors=False): | |||
def import_csv(context, path, only_insert=False, submit_after_import=False, ignore_encoding_errors=False, no_email=True): | |||
"Import CSV using data import tool" | |||
from frappe.core.page.data_import_tool import importer | |||
from frappe.utils.csvutils import read_csv_content | |||
site = get_site(context) | |||
if not os.path.exists(path): | |||
path = os.path.join('..', path) | |||
if not os.path.exists(path): | |||
print 'Invalid path {0}'.format(path) | |||
sys.exit(1) | |||
with open(path, 'r') as csvfile: | |||
content = read_csv_content(csvfile.read()) | |||
@@ -227,7 +242,7 @@ def import_csv(context, path, only_insert=False, submit_after_import=False, igno | |||
frappe.connect() | |||
try: | |||
importer.upload(content, submit_after_import=submit_after_import, | |||
importer.upload(content, submit_after_import=submit_after_import, no_email=no_email, | |||
ignore_encoding_errors=ignore_encoding_errors, overwrite=not only_insert, | |||
via_console=True) | |||
frappe.db.commit() | |||
@@ -284,8 +299,9 @@ def console(context): | |||
@click.option('--driver', help="For Travis") | |||
@click.option('--module', help="Run tests in a module") | |||
@click.option('--profile', is_flag=True, default=False) | |||
@click.option('--junit-xml-output', help="Destination file path for junit xml report") | |||
@pass_context | |||
def run_tests(context, app=None, module=None, doctype=None, test=(), driver=None, profile=False): | |||
def run_tests(context, app=None, module=None, doctype=None, test=(), driver=None, profile=False, junit_xml_output=False): | |||
"Run tests" | |||
import frappe.test_runner | |||
from frappe.utils import sel | |||
@@ -299,7 +315,7 @@ def run_tests(context, app=None, module=None, doctype=None, test=(), driver=None | |||
try: | |||
ret = frappe.test_runner.main(app, module, doctype, context.verbose, tests=tests, | |||
force=context.force, profile=profile) | |||
force=context.force, profile=profile, junit_xml_output=junit_xml_output) | |||
if len(ret.failures) == 0 and len(ret.errors) == 0: | |||
ret = 0 | |||
finally: | |||
@@ -382,6 +398,47 @@ def get_version(): | |||
if hasattr(module, "__version__"): | |||
print "{0} {1}".format(m, module.__version__) | |||
@click.command('setup-global-help') | |||
@click.option('--mariadb_root_password') | |||
def setup_global_help(mariadb_root_password=None): | |||
'''setup help table in a separate database that will be | |||
shared by the whole bench and set `global_help_setup` as 1 in | |||
common_site_config.json''' | |||
from frappe.installer import update_site_config | |||
frappe.local.flags = frappe._dict() | |||
frappe.local.flags.in_setup_help = True | |||
frappe.local.flags.in_install = True | |||
frappe.local.lang = 'en' | |||
frappe.local.conf = frappe.get_site_config(sites_path='.') | |||
update_site_config('global_help_setup', 1, | |||
site_config_path=os.path.join('.', 'common_site_config.json')) | |||
if mariadb_root_password: | |||
frappe.local.conf.root_password = mariadb_root_password | |||
from frappe.utils.help import sync | |||
sync() | |||
@click.command('setup-help') | |||
@pass_context | |||
def setup_help(context): | |||
'''Setup help table in the current site (called after migrate)''' | |||
from frappe.utils.help import sync | |||
for site in context.sites: | |||
try: | |||
frappe.init(site) | |||
frappe.connect() | |||
sync() | |||
finally: | |||
frappe.destroy() | |||
commands = [ | |||
build, | |||
clear_cache, | |||
@@ -406,4 +463,6 @@ commands = [ | |||
watch, | |||
_bulk_rename, | |||
add_to_email_queue, | |||
setup_global_help, | |||
setup_help | |||
] |
@@ -43,7 +43,7 @@ def get_data(): | |||
"items": [ | |||
{ | |||
"type": "doctype", | |||
"name": "Scheduler Log", | |||
"name": "Error Log", | |||
"description": _("Errors in Background Events"), | |||
}, | |||
{ | |||
@@ -51,6 +51,11 @@ def get_data(): | |||
"name": "Email Queue", | |||
"description": _("Background Email Queue"), | |||
}, | |||
{ | |||
"type": "page", | |||
"label": _("Background Jobs"), | |||
"name": "background_jobs", | |||
}, | |||
{ | |||
"type": "doctype", | |||
"name": "Error Snapshot", | |||
@@ -75,7 +75,7 @@ def get_data(): | |||
}, | |||
{ | |||
"type": "doctype", | |||
"name": "Scheduler Log", | |||
"name": "Error Log", | |||
"description": _("Log of error on automated events (scheduler).") | |||
}, | |||
{ | |||
@@ -156,8 +156,8 @@ def get_data(): | |||
}, | |||
{ | |||
"type": "doctype", | |||
"name": "Email Group Member", | |||
"description": _("Email Group Member List"), | |||
"name": "Auto Email Report", | |||
"description": _("Setup Reports to be emailed at regular intervals"), | |||
}, | |||
] | |||
}, | |||
@@ -222,10 +222,19 @@ def get_data(): | |||
}, | |||
{ | |||
"type": "doctype", | |||
"name": "Dropbox Backup", | |||
"description": _("Manage cloud backups on Dropbox"), | |||
"hide_count": True | |||
} | |||
"name": "Integration Service", | |||
"description": _("Centralize access to Integrations"), | |||
}, | |||
{ | |||
"type": "doctype", | |||
"name": "OAuth Client", | |||
"description": _("Register OAuth Client App"), | |||
}, | |||
{ | |||
"type": "doctype", | |||
"name": "OAuth Provider Settings", | |||
"description": _("Settings for OAuth Provider"), | |||
}, | |||
] | |||
}, | |||
{ | |||
@@ -15,6 +15,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "label_and_type", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -39,6 +40,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 1, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "label", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
@@ -67,6 +69,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 1, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "Data", | |||
"fieldname": "fieldtype", | |||
"fieldtype": "Select", | |||
@@ -95,6 +98,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 1, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "fieldname", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
@@ -121,6 +125,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "reqd", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -149,6 +154,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:in_list([\"Float\", \"Currency\", \"Percent\"], doc.fieldtype)", | |||
"description": "Set non-standard precision for a Float or Currency field", | |||
"fieldname": "precision", | |||
@@ -176,6 +182,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:in_list(['Data', 'Link', 'Dynamic Link', 'Password', 'Select', 'Read Only', 'Attach', 'Attach Image'], doc.fieldtype)", | |||
"fieldname": "length", | |||
"fieldtype": "Int", | |||
@@ -202,6 +209,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "search_index", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -230,6 +238,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "in_list_view", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -256,6 +265,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "bold", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -281,6 +291,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:doc.fieldtype===\"Section Break\"", | |||
"fieldname": "collapsible", | |||
"fieldtype": "Check", | |||
@@ -307,6 +318,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:doc.fieldtype==\"Section Break\"", | |||
"fieldname": "collapsible_depends_on", | |||
"fieldtype": "Code", | |||
@@ -333,6 +345,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_6", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -356,6 +369,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "For Links, enter the DocType as range.\nFor Select, enter list of Options, each on a new line.", | |||
"fieldname": "options", | |||
"fieldtype": "Text", | |||
@@ -383,6 +397,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "default", | |||
"fieldtype": "Small Text", | |||
"hidden": 0, | |||
@@ -409,6 +424,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "permissions", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -433,6 +449,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "depends_on", | |||
"fieldtype": "Code", | |||
"hidden": 0, | |||
@@ -459,6 +476,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "hidden", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -487,6 +505,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "read_only", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -513,6 +532,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "unique", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -538,6 +558,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Do not allow user to change after set the first time", | |||
"fieldname": "set_only_once", | |||
"fieldtype": "Check", | |||
@@ -563,6 +584,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_13", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -586,6 +608,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "0", | |||
"fieldname": "permlevel", | |||
"fieldtype": "Int", | |||
@@ -615,6 +638,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "User permissions should not apply for this Link", | |||
"fieldname": "ignore_user_permissions", | |||
"fieldtype": "Check", | |||
@@ -640,6 +664,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "allow_on_submit", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -668,6 +693,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "report_hide", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -696,6 +722,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Don't HTML Encode HTML tags like <script> or just characters like < or >, as they could be intentionally used in this field", | |||
"fieldname": "ignore_xss_filter", | |||
"fieldtype": "Check", | |||
@@ -722,6 +749,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "display", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -746,6 +774,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "in_filter", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -774,6 +803,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "no_copy", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -802,6 +832,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "print_hide", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -830,6 +861,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:[\"Int\", \"Float\", \"Currency\", \"Percent\"].indexOf(doc.fieldtype)!==-1", | |||
"fieldname": "print_hide_if_no_value", | |||
"fieldtype": "Check", | |||
@@ -856,6 +888,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "print_width", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
@@ -880,6 +913,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "width", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
@@ -908,6 +942,35 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "", | |||
"description": "Number of columns for a field in a List View or a Grid (Total Columns should be less than 11)", | |||
"fieldname": "columns", | |||
"fieldtype": "Int", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Columns", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_22", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -931,6 +994,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "description", | |||
"fieldtype": "Small Text", | |||
"hidden": 0, | |||
@@ -959,6 +1023,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "oldfieldname", | |||
"fieldtype": "Data", | |||
"hidden": 1, | |||
@@ -984,6 +1049,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "oldfieldtype", | |||
"fieldtype": "Data", | |||
"hidden": 1, | |||
@@ -1016,7 +1082,7 @@ | |||
"issingle": 0, | |||
"istable": 1, | |||
"max_attachments": 0, | |||
"modified": "2016-07-11 03:25:57.882851", | |||
"modified": "2016-08-23 11:59:07.036627", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "DocField", | |||
@@ -1026,5 +1092,5 @@ | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"sort_order": "ASC", | |||
"track_seen": 0 | |||
} | |||
"track_seen": 0 | |||
} |
@@ -14,6 +14,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "role_and_level", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -38,6 +39,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "role", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
@@ -67,6 +69,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Filter records based on User Permissions defined for a user", | |||
"fieldname": "apply_user_permissions", | |||
"fieldtype": "Check", | |||
@@ -92,6 +95,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Apply this rule if the User is the Owner", | |||
"fieldname": "if_owner", | |||
"fieldtype": "Check", | |||
@@ -118,6 +122,34 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "0", | |||
"fieldname": "is_custom", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Is Custom", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 1, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_2", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -141,6 +173,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "0", | |||
"fieldname": "permlevel", | |||
"fieldtype": "Int", | |||
@@ -170,6 +203,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "", | |||
"description": "JSON list of DocTypes used to apply User Permissions. If empty, all linked DocTypes will be used to apply User Permissions.", | |||
"fieldname": "user_permission_doctypes", | |||
@@ -196,6 +230,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "section_break_4", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -220,6 +255,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"fieldname": "read", | |||
"fieldtype": "Check", | |||
@@ -249,6 +285,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"fieldname": "write", | |||
"fieldtype": "Check", | |||
@@ -278,6 +315,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"fieldname": "create", | |||
"fieldtype": "Check", | |||
@@ -307,6 +345,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"fieldname": "delete", | |||
"fieldtype": "Check", | |||
@@ -332,6 +371,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_8", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -355,6 +395,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "submit", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -383,6 +424,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "cancel", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -411,6 +453,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "amend", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -439,6 +482,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "additional_permissions", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -463,6 +507,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"fieldname": "report", | |||
"fieldtype": "Check", | |||
@@ -490,6 +535,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"fieldname": "export", | |||
"fieldtype": "Check", | |||
@@ -515,6 +561,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "import", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -539,6 +586,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "This role update User Permissions for a user", | |||
"fieldname": "set_user_permissions", | |||
"fieldtype": "Check", | |||
@@ -564,6 +612,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_19", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -587,6 +636,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"fieldname": "share", | |||
"fieldtype": "Check", | |||
@@ -613,6 +663,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"fieldname": "print", | |||
"fieldtype": "Check", | |||
@@ -638,6 +689,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"fieldname": "email", | |||
"fieldtype": "Check", | |||
@@ -670,7 +722,7 @@ | |||
"issingle": 0, | |||
"istable": 1, | |||
"max_attachments": 0, | |||
"modified": "2016-07-11 03:27:59.695670", | |||
"modified": "2016-09-29 08:07:20.450064", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "DocPerm", | |||
@@ -679,5 +731,6 @@ | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"sort_order": "ASC", | |||
"track_seen": 0 | |||
} |
@@ -19,9 +19,7 @@ class DocShare(Document): | |||
self.get_doc().run_method("validate_share", self) | |||
def cascade_permissions_downwards(self): | |||
if self.share: | |||
self.write = 1 | |||
if self.write: | |||
if self.share or self.write: | |||
self.read = 1 | |||
def get_doc(self): | |||
@@ -34,7 +34,7 @@ class TestDocShare(unittest.TestCase): | |||
self.assertTrue(self.event.has_permission()) | |||
def test_share_permission(self): | |||
frappe.share.add("Event", self.event.name, self.user, share=1) | |||
frappe.share.add("Event", self.event.name, self.user, write=1, share=1) | |||
frappe.set_user(self.user) | |||
self.assertTrue(self.event.has_permission("share")) | |||
@@ -60,14 +60,14 @@ class TestDocShare(unittest.TestCase): | |||
self.assertRaises(frappe.PermissionError, frappe.share.add, "Event", self.event.name, self.user) | |||
frappe.set_user("Administrator") | |||
frappe.share.add("Event", self.event.name, self.user, share=1) | |||
frappe.share.add("Event", self.event.name, self.user, write=1, share=1) | |||
# test not raises | |||
frappe.set_user(self.user) | |||
frappe.share.add("Event", self.event.name, "test1@example.com", share=1) | |||
frappe.share.add("Event", self.event.name, "test1@example.com", write=1, share=1) | |||
def test_remove_share(self): | |||
frappe.share.add("Event", self.event.name, self.user, share=1) | |||
frappe.share.add("Event", self.event.name, self.user, write=1, share=1) | |||
frappe.set_user(self.user) | |||
self.assertTrue(self.event.has_permission("share")) | |||
@@ -11,18 +11,25 @@ | |||
// } | |||
// }) | |||
cur_frm.cscript.refresh = function(doc, cdt, cdn) { | |||
if(doc.__islocal && (user !== "Administrator" || !frappe.boot.developer_mode)) { | |||
cur_frm.set_value("custom", 1); | |||
cur_frm.toggle_enable("custom", 0); | |||
} | |||
frappe.ui.form.on('DocType', { | |||
refresh: function(frm) { | |||
if(frm.doc.__islocal && (user !== "Administrator" || !frappe.boot.developer_mode)) { | |||
frm.set_value("custom", 1); | |||
frm.toggle_enable("custom", 0); | |||
} | |||
if(!frappe.boot.developer_mode && !frm.doc.custom) { | |||
// make the document read-only | |||
frm.set_read_only(); | |||
} | |||
if(!frappe.boot.developer_mode && !doc.custom) { | |||
// make the document read-only | |||
cur_frm.set_read_only(); | |||
if(!frm.doc.__islocal) { | |||
frm.toggle_enable("engine", 0); | |||
} | |||
} | |||
} | |||
}) | |||
// for legacy... :) | |||
cur_frm.cscript.validate = function(doc, cdt, cdn) { | |||
doc.server_code_compiled = null; | |||
} |
@@ -11,11 +11,13 @@ | |||
"doctype": "DocType", | |||
"document_type": "Document", | |||
"editable_grid": 0, | |||
"engine": "InnoDB", | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "sb0", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -41,6 +43,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "module", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
@@ -68,6 +71,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Child Tables are shown as a Grid in other DocTypes.", | |||
"fieldname": "istable", | |||
"fieldtype": "Check", | |||
@@ -95,6 +99,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"depends_on": "istable", | |||
"fieldname": "editable_grid", | |||
@@ -122,6 +127,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Single Types have only one record no tables associated. Values are stored in tabSingles", | |||
"fieldname": "issingle", | |||
"fieldtype": "Check", | |||
@@ -149,6 +155,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "cb01", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -172,6 +179,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "document_type", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
@@ -199,6 +207,36 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "InnoDB", | |||
"depends_on": "eval:!doc.issingle", | |||
"fieldname": "engine", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Database Engine", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "InnoDB\nMyISAM", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "icon", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
@@ -223,6 +261,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "custom", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -247,6 +286,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "beta", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -272,6 +312,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "0", | |||
"depends_on": "eval: doc.image_field", | |||
"fieldname": "image_view", | |||
@@ -299,6 +340,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "app", | |||
"fieldtype": "Data", | |||
"hidden": 1, | |||
@@ -323,6 +365,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "fields_section_break", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -348,6 +391,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "fields", | |||
"fieldtype": "Table", | |||
"hidden": 0, | |||
@@ -375,6 +419,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "sb1", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -399,6 +444,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Naming Options:\n<ol><li><b>field:[fieldname]</b> - By Field</li><li><b>naming_series:</b> - By Naming Series (field called naming_series must be present</li><li><b>Prompt</b> - Prompt user for a name</li><li><b>[series]</b> - Series by prefix (separated by a dot); for example PRE.#####</li></ol>", | |||
"fieldname": "autoname", | |||
"fieldtype": "Data", | |||
@@ -426,6 +472,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "name_case", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
@@ -453,6 +500,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "description", | |||
"fieldtype": "Small Text", | |||
"hidden": 0, | |||
@@ -479,6 +527,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "", | |||
"fieldname": "column_break_15", | |||
"fieldtype": "Column Break", | |||
@@ -503,6 +552,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:!doc.istable", | |||
"description": "Show this field as title", | |||
"fieldname": "title_field", | |||
@@ -529,6 +579,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:!doc.istable", | |||
"fieldname": "search_fields", | |||
"fieldtype": "Data", | |||
@@ -556,6 +607,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Must be of type \"Attach Image\"", | |||
"fieldname": "image_field", | |||
"fieldtype": "Data", | |||
@@ -582,6 +634,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "modified", | |||
"depends_on": "eval:!doc.istable", | |||
"description": "", | |||
@@ -609,6 +662,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "DESC", | |||
"depends_on": "eval:!doc.istable", | |||
"fieldname": "sort_order", | |||
@@ -636,6 +690,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:!doc.istable", | |||
"description": "Comments and Communications will be associated with this linked document", | |||
"fieldname": "timeline_field", | |||
@@ -663,6 +718,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:!doc.istable", | |||
"fieldname": "sb2", | |||
"fieldtype": "Section Break", | |||
@@ -688,6 +744,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "", | |||
"fieldname": "permissions", | |||
"fieldtype": "Table", | |||
@@ -716,6 +773,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:!doc.istable", | |||
"fieldname": "sb3", | |||
"fieldtype": "Section Break", | |||
@@ -740,6 +798,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "cb30", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -764,6 +823,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "in_create", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -790,6 +850,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "read_only", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -816,6 +877,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "is_submittable", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -840,6 +902,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Allow Import via Data Import Tool", | |||
"fieldname": "allow_import", | |||
"fieldtype": "Check", | |||
@@ -865,6 +928,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "allow_rename", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -891,6 +955,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "in_dialog", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -917,6 +982,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "read_only_onload", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -943,6 +1009,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "max_attachments", | |||
"fieldtype": "Int", | |||
"hidden": 0, | |||
@@ -969,6 +1036,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "cb31", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -993,6 +1061,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "hide_heading", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -1019,6 +1088,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "hide_toolbar", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -1045,6 +1115,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "allow_copy", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -1071,6 +1142,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "track_seen", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -1096,6 +1168,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"fieldname": "quick_entry", | |||
"fieldtype": "Check", | |||
@@ -1122,6 +1195,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "default_print_format", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
@@ -1154,7 +1228,7 @@ | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-07-25 12:18:27.724194", | |||
"modified": "2016-10-13 01:13:58.133080", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "DocType", | |||
@@ -1170,6 +1244,7 @@ | |||
"export": 0, | |||
"if_owner": 0, | |||
"import": 0, | |||
"is_custom": 0, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
@@ -1190,6 +1265,7 @@ | |||
"export": 0, | |||
"if_owner": 0, | |||
"import": 0, | |||
"is_custom": 0, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
@@ -46,8 +46,8 @@ class DocType(Document): | |||
elif self.istable: | |||
self.allow_import = 0 | |||
self.validate_series() | |||
self.scrub_field_names() | |||
self.validate_series() | |||
self.validate_document_type() | |||
validate_fields(self) | |||
@@ -120,6 +120,12 @@ class DocType(Document): | |||
if not autoname and self.get("fields", {"fieldname":"naming_series"}): | |||
self.autoname = "naming_series:" | |||
# validate field name if autoname field:fieldname is used | |||
if autoname and autoname.startswith('field:'): | |||
field = autoname.split(":")[1] | |||
if not field or field not in [ df.fieldname for df in self.fields ]: | |||
frappe.throw(_("Invalid fieldname '{0}' in autoname".format(field))) | |||
if autoname and (not autoname.startswith('field:')) \ | |||
and (not autoname.startswith('eval:')) \ | |||
and (not autoname.lower() in ('prompt', 'hash')) \ | |||
@@ -593,8 +599,7 @@ def make_module_and_roles(doc, perm_fieldname="permissions"): | |||
for role in list(set(roles)): | |||
if not frappe.db.exists("Role", role): | |||
r = frappe.get_doc({"doctype": "Role", "role_name": role}) | |||
r.role_name = role | |||
r = frappe.get_doc(dict(doctype= "Role", role_name=role, desk_access=1)) | |||
r.flags.ignore_mandatory = r.flags.ignore_permissions = True | |||
r.insert() | |||
except frappe.DoesNotExistError, e: | |||
@@ -0,0 +1,8 @@ | |||
// Copyright (c) 2016, Frappe Technologies and contributors | |||
// For license information, please see license.txt | |||
frappe.ui.form.on('Error Log', { | |||
refresh: function(frm) { | |||
} | |||
}); |
@@ -2,7 +2,7 @@ | |||
"allow_copy": 0, | |||
"allow_import": 0, | |||
"allow_rename": 0, | |||
"autoname": "SCHLOG.#####", | |||
"autoname": "Error-.#####", | |||
"beta": 0, | |||
"creation": "2013-01-16 13:09:40", | |||
"custom": 0, | |||
@@ -10,11 +10,14 @@ | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "System", | |||
"editable_grid": 0, | |||
"engine": "MyISAM", | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "0", | |||
"fieldname": "seen", | |||
"fieldtype": "Check", | |||
@@ -41,6 +44,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "method", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
@@ -48,7 +52,7 @@ | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"label": "Method", | |||
"label": "Title", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
@@ -65,6 +69,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "error", | |||
"fieldtype": "Code", | |||
"hidden": 0, | |||
@@ -97,10 +102,10 @@ | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-07-03 14:24:13.581374", | |||
"modified": "2016-10-06 03:29:47.810715", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "Scheduler Log", | |||
"name": "Error Log", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
@@ -113,6 +118,7 @@ | |||
"export": 0, | |||
"if_owner": 0, | |||
"import": 0, | |||
"is_custom": 0, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, |
@@ -0,0 +1,21 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe.model.document import Document | |||
class ErrorLog(Document): | |||
def onload(self): | |||
if not self.seen: | |||
self.db_set('seen', 1) | |||
frappe.db.commit() | |||
def set_old_logs_as_seen(): | |||
# set logs as seen | |||
frappe.db.sql("""update `tabError Log` set seen=1 | |||
where seen=0 and datediff(curdate(), creation) > 7""") | |||
# clear old logs | |||
frappe.db.sql("""delete from `tabError Log` where datediff(curdate(), creation) > 30""") |
@@ -1,4 +1,4 @@ | |||
frappe.listview_settings['Scheduler Log'] = { | |||
frappe.listview_settings['Error Log'] = { | |||
add_fields: ["seen"], | |||
get_indicator: function(doc) { | |||
if(cint(doc.seen)) { |
@@ -0,0 +1,12 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies and Contributors | |||
# See license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
import unittest | |||
# test_records = frappe.get_test_records('Error Log') | |||
class TestErrorLog(unittest.TestCase): | |||
pass |
@@ -3,15 +3,18 @@ | |||
"allow_import": 1, | |||
"allow_rename": 0, | |||
"autoname": "", | |||
"beta": 0, | |||
"creation": "2012-12-12 11:19:22", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"editable_grid": 0, | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "file_name", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
@@ -38,6 +41,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:!doc.is_folder", | |||
"fieldname": "is_private", | |||
"fieldtype": "Check", | |||
@@ -53,17 +57,18 @@ | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 1, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 1, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "preview", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -89,6 +94,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "preview_html", | |||
"fieldtype": "HTML", | |||
"hidden": 0, | |||
@@ -114,6 +120,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "section_break_5", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -138,6 +145,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "", | |||
"fieldname": "is_home_folder", | |||
"fieldtype": "Check", | |||
@@ -164,6 +172,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "is_attachments_folder", | |||
"fieldtype": "Check", | |||
"hidden": 1, | |||
@@ -189,6 +198,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "file_size", | |||
"fieldtype": "Int", | |||
"hidden": 0, | |||
@@ -213,6 +223,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_5", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -237,6 +248,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:!doc.is_folder", | |||
"fieldname": "file_url", | |||
"fieldtype": "Code", | |||
@@ -262,6 +274,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "thumbnail_url", | |||
"fieldtype": "Small Text", | |||
"hidden": 0, | |||
@@ -287,6 +300,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "folder", | |||
"fieldtype": "Link", | |||
"hidden": 1, | |||
@@ -313,6 +327,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "is_folder", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -338,6 +353,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:!doc.is_folder", | |||
"fieldname": "section_break_8", | |||
"fieldtype": "Section Break", | |||
@@ -363,6 +379,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "attached_to_doctype", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
@@ -388,6 +405,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_10", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -412,6 +430,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "attached_to_name", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
@@ -436,6 +455,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "content_hash", | |||
"fieldtype": "Data", | |||
"hidden": 1, | |||
@@ -460,6 +480,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "lft", | |||
"fieldtype": "Int", | |||
"hidden": 1, | |||
@@ -485,6 +506,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "rgt", | |||
"fieldtype": "Int", | |||
"hidden": 1, | |||
@@ -510,6 +532,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "old_parent", | |||
"fieldtype": "Data", | |||
"hidden": 1, | |||
@@ -536,6 +559,7 @@ | |||
"hide_toolbar": 0, | |||
"icon": "icon-file", | |||
"idx": 1, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"in_dialog": 0, | |||
"is_submittable": 0, | |||
@@ -543,7 +567,7 @@ | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"menu_index": 0, | |||
"modified": "2016-02-22 09:23:59.892258", | |||
"modified": "2016-09-21 12:23:34.017457", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "File", | |||
@@ -590,7 +614,10 @@ | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"title_field": "file_name" | |||
"sort_order": "ASC", | |||
"title_field": "file_name", | |||
"track_seen": 0 | |||
} |
@@ -12,6 +12,7 @@ import frappe | |||
import json | |||
import urllib | |||
import os | |||
import shutil | |||
import requests | |||
import requests.exceptions | |||
import StringIO | |||
@@ -72,6 +73,23 @@ class File(NestedSet): | |||
self.set_folder_size() | |||
if frappe.db.exists('File', {'name': self.name, 'is_folder': 0}): | |||
if not self.is_folder and (self.is_private != self.db_get('is_private')): | |||
private_files = frappe.get_site_path('private', 'files') | |||
public_files = frappe.get_site_path('public', 'files') | |||
if not self.is_private: | |||
shutil.move(os.path.join(private_files, self.file_name), | |||
os.path.join(public_files, self.file_name)) | |||
self.file_url = "/files/{0}".format(self.file_name) | |||
else: | |||
shutil.move(os.path.join(public_files, self.file_name), | |||
os.path.join(private_files, self.file_name)) | |||
self.file_url = "/private/files/{0}".format(self.file_name) | |||
def set_folder_size(self): | |||
"""Set folder size if folder""" | |||
if self.is_folder and not self.is_new(): | |||
@@ -350,4 +368,3 @@ def check_file_permission(file_url): | |||
return True | |||
raise frappe.PermissionError | |||
@@ -0,0 +1,8 @@ | |||
// Copyright (c) 2016, Frappe Technologies and contributors | |||
// For license information, please see license.txt | |||
frappe.ui.form.on('Language', { | |||
refresh: function(frm) { | |||
} | |||
}); |
@@ -0,0 +1,160 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_import": 0, | |||
"allow_rename": 1, | |||
"autoname": "field:language_code", | |||
"beta": 0, | |||
"creation": "2014-08-22 16:12:17.249590", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "Setup", | |||
"editable_grid": 0, | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "language_code", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"label": "Language Code", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "language_name", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"label": "Language Name", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "flag", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"label": "Flag", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "based_on", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Based On", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Language", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
], | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"icon": "icon-globe", | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"in_dialog": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-08-23 15:06:32.827148", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "Language", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"amend": 0, | |||
"apply_user_permissions": 0, | |||
"cancel": 0, | |||
"create": 1, | |||
"delete": 1, | |||
"email": 0, | |||
"export": 0, | |||
"if_owner": 0, | |||
"import": 0, | |||
"permlevel": 0, | |||
"print": 0, | |||
"read": 1, | |||
"report": 0, | |||
"role": "System Manager", | |||
"set_user_permissions": 0, | |||
"share": 0, | |||
"submit": 0, | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"search_fields": "language_name", | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"title_field": "language_name", | |||
"track_seen": 0 | |||
} |
@@ -0,0 +1,41 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import frappe, json | |||
from frappe.model.document import Document | |||
class Language(Document): | |||
pass | |||
def export_languages_json(): | |||
'''Export list of all languages''' | |||
languages = frappe.db.get_all('Language', fields=['name', 'language_name']) | |||
languages = [{'name': d.language_name, 'code': d.name} for d in languages] | |||
languages.sort(lambda a,b: 1 if a['code'] > b['code'] else -1) | |||
with open(frappe.get_app_path('frappe', 'geo', 'languages.json'), 'w') as f: | |||
f.write(frappe.as_json(languages)) | |||
def sync_languages(): | |||
'''Sync frappe/geo/languages.json with Language''' | |||
with open(frappe.get_app_path('frappe', 'geo', 'languages.json'), 'r') as f: | |||
data = json.loads(f.read()) | |||
for l in data: | |||
if not frappe.db.exists('Language', l['code']): | |||
frappe.get_doc({ | |||
'doctype': 'Language', | |||
'language_code': l['code'], | |||
'language_name': l['name'] | |||
}).insert() | |||
def update_language_names(): | |||
'''Update frappe/geo/languages.json names (for use via patch)''' | |||
with open(frappe.get_app_path('frappe', 'geo', 'languages.json'), 'r') as f: | |||
data = json.loads(f.read()) | |||
for l in data: | |||
frappe.db.set_value('Language', l['code'], 'language_name', l['name']) |
@@ -0,0 +1,12 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies and Contributors | |||
# See license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
import unittest | |||
# test_records = frappe.get_test_records('Language') | |||
class TestLanguage(unittest.TestCase): | |||
pass |
@@ -3,6 +3,7 @@ | |||
from __future__ import unicode_literals | |||
import frappe | |||
import os | |||
from frappe.model.document import Document | |||
from frappe.build import html_to_js_template | |||
from frappe.model.utils import render_include | |||
@@ -49,15 +50,10 @@ class Page(Document): | |||
from frappe.core.doctype.doctype.doctype import make_module_and_roles | |||
make_module_and_roles(self, "roles") | |||
if not frappe.flags.in_import and getattr(conf,'developer_mode', 0) and self.standard=='Yes': | |||
from frappe.modules.export_file import export_to_files | |||
from frappe.modules import get_module_path, scrub | |||
import os | |||
export_to_files(record_list=[['Page', self.name]]) | |||
# write files | |||
path = os.path.join(get_module_path(self.module), 'page', scrub(self.name), scrub(self.name)) | |||
from frappe.modules.utils import export_module_json | |||
path = export_module_json(self, self.standard=='Yes', self.module) | |||
if path: | |||
# js | |||
if not os.path.exists(path + '.js'): | |||
with open(path + '.js', 'w') as f: | |||
@@ -132,6 +128,9 @@ class Page(Document): | |||
template = frappe.render_template(template, context) | |||
self.script = html_to_js_template(fname, template) + self.script | |||
# flag for not caching this page | |||
self._dynamic_page = True | |||
if frappe.lang != 'en': | |||
from frappe.translate import get_lang_js | |||
self.script += get_lang_js("page", self.name) | |||
@@ -3,7 +3,9 @@ | |||
from __future__ import unicode_literals | |||
import frappe | |||
import json | |||
from frappe import _ | |||
import frappe.desk.query_report | |||
from frappe.utils import cint | |||
from frappe.model.document import Document | |||
from frappe.modules.export_file import export_to_files | |||
@@ -48,6 +50,40 @@ class Report(Document): | |||
make_boilerplate("controller.py", self, {"name": self.name}) | |||
make_boilerplate("controller.js", self, {"name": self.name}) | |||
def get_data(self, filters=None, limit=None, user=None): | |||
'''Run the report''' | |||
out = [] | |||
if self.report_type in ('Query Report', 'Script Report'): | |||
# query and script reports | |||
data = frappe.desk.query_report.run(self.name, filters=filters, user=user) | |||
out.append([d.split(':')[0] for d in data.get('columns')]) | |||
out += data.get('result') | |||
else: | |||
# standard report | |||
params = json.loads(self.json) | |||
columns = params.get('columns') | |||
filters = params.get('filters') | |||
def _format(parts): | |||
# sort by is saved as DocType.fieldname, covert it to sql | |||
return '`tab{0}`.`{1}`'.format(*parts) | |||
order_by = _format(params.get('sort_by').split('.')) + ' ' + params.get('sort_order') | |||
if params.get('sort_by_next'): | |||
order_by += ', ' + _format(params.get('sort_by_next').split('.')) + ' ' + params.get('sort_order_next') | |||
result = frappe.get_list(self.ref_doctype, fields = [_format([c[1], c[0]]) for c in columns], | |||
filters=filters, order_by = order_by, as_list=True, limit=limit, user=user) | |||
meta = frappe.get_meta(self.ref_doctype) | |||
out.append([meta.get_label(c[0]) for c in columns]) | |||
out = out + [list(d) for d in result] | |||
return out | |||
@Document.whitelist | |||
def toggle_disable(self, disable): | |||
self.db_set("disabled", cint(disable)) |
@@ -1,10 +1,30 @@ | |||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||
# See license.txt | |||
import frappe | |||
from __future__ import unicode_literals | |||
import frappe, json, os | |||
import unittest | |||
test_records = frappe.get_test_records('Report') | |||
class TestReport(unittest.TestCase): | |||
pass | |||
def test_report_builder(self): | |||
if frappe.db.exists('Report', 'User Activity Report'): | |||
frappe.delete_doc('Report', 'User Activity Report') | |||
with open(os.path.join(os.path.dirname(__file__), 'user_activity_report.json'), 'r') as f: | |||
frappe.get_doc(json.loads(f.read())).insert() | |||
report = frappe.get_doc('Report', 'User Activity Report') | |||
data = report.get_data() | |||
self.assertEquals(data[0][0], 'ID') | |||
self.assertEquals(data[0][1], 'User Type') | |||
self.assertTrue('Administrator' in [d[0] for d in data]) | |||
def test_query_report(self): | |||
report = frappe.get_doc('Report', 'Permitted Documents For User') | |||
data = report.get_data(filters={'user': 'Administrator', 'doctype': 'DocType'}) | |||
self.assertEquals(data[0][0], 'Name') | |||
self.assertEquals(data[0][1], 'Module') | |||
self.assertTrue('User' in [d[0] for d in data]) | |||
@@ -0,0 +1,17 @@ | |||
{ | |||
"add_total_row": 0, | |||
"apply_user_permissions": 1, | |||
"disabled": 0, | |||
"docstatus": 0, | |||
"doctype": "Report", | |||
"is_standard": "No", | |||
"javascript": null, | |||
"json": "{\"filters\":[],\"columns\":[[\"name\",\"User\"],[\"user_type\",\"User\"],[\"first_name\",\"User\"],[\"last_name\",\"User\"],[\"last_active\",\"User\"],[\"role\",\"UserRole\"]],\"sort_by\":\"User.modified\",\"sort_order\":\"desc\",\"sort_by_next\":null,\"sort_order_next\":\"desc\"}", | |||
"modified": "2016-09-01 02:59:07.728890", | |||
"module": "Core", | |||
"name": "User Activity Report", | |||
"query": null, | |||
"ref_doctype": "User", | |||
"report_name": "User Activity Report", | |||
"report_type": "Report Builder" | |||
} |
@@ -14,13 +14,14 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "role_name", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"in_list_view": 0, | |||
"label": "Role Name", | |||
"length": 0, | |||
"no_copy": 0, | |||
@@ -40,6 +41,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "If disabled, this role will be removed from all users.", | |||
"fieldname": "disabled", | |||
"fieldtype": "Check", | |||
@@ -61,6 +63,33 @@ | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"fieldname": "desk_access", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"label": "Desk Access", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
], | |||
"hide_heading": 0, | |||
@@ -74,7 +103,7 @@ | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-07-25 05:24:24.406260", | |||
"modified": "2016-09-23 05:38:14.727541", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "Role", | |||
@@ -1,14 +1,22 @@ | |||
[ | |||
{ | |||
"doctype": "Role", | |||
"role_name": "_Test Role" | |||
}, | |||
"doctype": "Role", | |||
"role_name": "_Test Role", | |||
"desk_access": 1 | |||
}, | |||
{ | |||
"doctype": "Role", | |||
"role_name": "_Test Role 2" | |||
}, | |||
"doctype": "Role", | |||
"role_name": "_Test Role 2", | |||
"desk_access": 1 | |||
}, | |||
{ | |||
"doctype": "Role", | |||
"role_name": "_Test Role 3" | |||
"doctype": "Role", | |||
"role_name": "_Test Role 3", | |||
"desk_access": 1 | |||
}, | |||
{ | |||
"doctype": "Role", | |||
"role_name": "_Test Role 4", | |||
"desk_access": 0 | |||
} | |||
] |
@@ -1 +0,0 @@ | |||
Log exceptions (errors) raised when executing the scheduler. |
@@ -1,3 +0,0 @@ | |||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
@@ -1,8 +0,0 @@ | |||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors | |||
// For license information, please see license.txt | |||
frappe.ui.form.on('Scheduler Log', { | |||
refresh: function(frm) { | |||
} | |||
}); |
@@ -1,19 +0,0 @@ | |||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe.model.document import Document | |||
class SchedulerLog(Document): | |||
def onload(self): | |||
if not self.seen: | |||
self.seen = 1 | |||
self.save() | |||
def set_old_logs_as_seen(): | |||
frappe.db.sql("""update `tabScheduler Log` set seen=1 | |||
where seen=0 and datediff(curdate(), creation) > 7""") |
@@ -1,12 +0,0 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||
# See license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
import unittest | |||
# test_records = frappe.get_test_records('Scheduler Log') | |||
class TestSchedulerLog(unittest.TestCase): | |||
pass |
@@ -1,5 +1,4 @@ | |||
frappe.ui.form.on("System Settings", "refresh", function(frm) { | |||
frappe.setup_language_field(frm); | |||
frappe.call({ | |||
method: "frappe.core.doctype.system_settings.system_settings.load", | |||
callback: function(data) { | |||
@@ -9,6 +9,9 @@ import unittest | |||
from frappe import _ | |||
class TestTranslation(unittest.TestCase): | |||
def setUp(self): | |||
frappe.db.sql('delete from tabTranslation') | |||
def tearDown(self): | |||
frappe.local.lang = 'en' | |||
frappe.local.lang_full_dict=None | |||
@@ -19,21 +22,51 @@ class TestTranslation(unittest.TestCase): | |||
frappe.local.lang = key | |||
frappe.local.lang_full_dict=None | |||
translation = create_translation(key, val) | |||
self.assertEquals(_(translation.source_name), val[1]) | |||
self.assertEquals(_(val[0]), val[1]) | |||
frappe.delete_doc('Translation', translation.name) | |||
frappe.local.lang_full_dict=None | |||
self.assertEquals(_(translation.source_name), val[0]) | |||
self.assertEquals(_(val[0]), val[0]) | |||
def test_parent_language(self): | |||
data = [ | |||
['es', ['Test Data', 'datos de prueba']], | |||
['es', ['Test Spanish', 'prueba de español']], | |||
['es-MX', ['Test Data', 'pruebas de datos']] | |||
] | |||
for key, val in data: | |||
create_translation(key, val) | |||
frappe.local.lang = 'es' | |||
frappe.local.lang_full_dict=None | |||
self.assertTrue(_(data[0][0]), data[0][1]) | |||
frappe.local.lang_full_dict=None | |||
self.assertTrue(_(data[1][0]), data[1][1]) | |||
frappe.local.lang = 'es-MX' | |||
# different translation for es-MX | |||
frappe.local.lang_full_dict=None | |||
self.assertTrue(_(data[2][0]), data[2][1]) | |||
# from spanish (general) | |||
frappe.local.lang_full_dict=None | |||
self.assertTrue(_(data[1][0]), data[1][1]) | |||
def get_translation_data(): | |||
html_source_data = """ <font color="#848484" face="arial, tahoma, verdana, sans-serif"> | |||
<span style="font-size: 11px; line-height: 16.9px;">Test Data</span></font> """ | |||
html_translated_data = """ <font color="#848484" face="arial, tahoma, verdana, sans-serif"> | |||
html_source_data = """<font color="#848484" face="arial, tahoma, verdana, sans-serif"> | |||
<span style="font-size: 11px; line-height: 16.9px;">Test Data</span></font>""" | |||
html_translated_data = """<font color="#848484" face="arial, tahoma, verdana, sans-serif"> | |||
<span style="font-size: 11px; line-height: 16.9px;"> testituloksia </span></font>""" | |||
return {'hr': ['Test data', 'Testdaten'], | |||
'ms': ['Test Data','ujian Data'], | |||
'et': ['Test Data', 'testandmed'], | |||
'es': ['Test Data', 'datos de prueba'], | |||
'en': ['Quotation', 'Tax Invoice'], | |||
'fi': [html_source_data, html_translated_data]} | |||
@@ -3,9 +3,6 @@ | |||
frappe.ui.form.on('Translation', { | |||
before_load: function(frm) { | |||
frappe.setup_language_field(frm); | |||
}, | |||
language: function(frm) { | |||
frm.events.update_language_code(frm); | |||
}, | |||
@@ -3,70 +3,22 @@ | |||
"allow_import": 1, | |||
"allow_rename": 0, | |||
"autoname": "", | |||
"beta": 0, | |||
"creation": "2016-02-17 12:21:16.175465", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "Setup", | |||
"editable_grid": 0, | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"default": "", | |||
"fieldname": "language", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Language", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "column_break_3", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "en", | |||
"fieldname": "language_code", | |||
"fieldtype": "Data", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
@@ -75,6 +27,7 @@ | |||
"label": "Language Code", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Language", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
@@ -90,6 +43,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "section_break_4", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -114,6 +68,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "If your data is in HTML, please copy paste the exact HTML code with the tags.", | |||
"fieldname": "source_name", | |||
"fieldtype": "Code", | |||
@@ -140,6 +95,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_6", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -164,13 +120,14 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "target_name", | |||
"fieldtype": "Code", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"in_list_view": 1, | |||
"label": "Translated", | |||
"length": 0, | |||
"no_copy": 0, | |||
@@ -189,13 +146,14 @@ | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"in_dialog": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-03-04 15:42:07.020950", | |||
"modified": "2016-08-24 03:48:55.525143", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "Translation", | |||
@@ -223,9 +181,11 @@ | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"title_field": "language_code" | |||
"title_field": "source_name", | |||
"track_seen": 0 | |||
} |
@@ -5,10 +5,11 @@ | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe.model.document import Document | |||
from frappe.translate import clear_cache | |||
class Translation(Document): | |||
def on_update(self): | |||
frappe.cache().hdel('lang_user_translations', self.language_code) | |||
clear_cache() | |||
def on_trash(self): | |||
frappe.cache().hdel('lang_user_translations', self.language_code) | |||
clear_cache() |
@@ -8,14 +8,36 @@ import requests | |||
from frappe.model.delete_doc import delete_doc | |||
from frappe.utils.data import today, add_to_date | |||
from frappe import _dict | |||
from frappe.limits import SiteExpiredError, update_limits, clear_limit | |||
from frappe.limits import update_limits, clear_limit | |||
from frappe.utils import get_url | |||
from frappe.installer import update_site_config | |||
from frappe.core.doctype.user.user import MaxUsersReachedError | |||
test_records = frappe.get_test_records('User') | |||
class TestUser(unittest.TestCase): | |||
def test_user_type(self): | |||
new_user = frappe.get_doc(dict(doctype='User', email='test-for-type@example.com', | |||
first_name='Tester')).insert() | |||
self.assertEquals(new_user.user_type, 'Website User') | |||
# role with desk access | |||
new_user.add_roles('_Test Role 2') | |||
new_user.save() | |||
self.assertEquals(new_user.user_type, 'System User') | |||
# clear role | |||
new_user.user_roles = [] | |||
new_user.save() | |||
self.assertEquals(new_user.user_type, 'Website User') | |||
# role without desk access | |||
new_user.add_roles('_Test Role 4') | |||
new_user.save() | |||
self.assertEquals(new_user.user_type, 'Website User') | |||
frappe.delete_doc('User', new_user.name) | |||
def test_delete(self): | |||
frappe.get_doc("User", "test@example.com").add_roles("_Test Role 2") | |||
self.assertRaises(frappe.LinkExistsError, delete_doc, "Role", "_Test Role 2") | |||
@@ -122,6 +144,7 @@ class TestUser(unittest.TestCase): | |||
clear_limit('users') | |||
# def test_deny_multiple_sessions(self): | |||
# from frappe.installer import update_site_config | |||
# clear_limit('users') | |||
# | |||
# # allow one session | |||
@@ -156,13 +179,18 @@ class TestUser(unittest.TestCase): | |||
# test_request(conn1) | |||
def test_site_expiry(self): | |||
user = frappe.get_doc('User', 'test@example.com') | |||
user.enabled = 1 | |||
user.new_password = 'testpassword' | |||
user.save() | |||
update_limits({'expiry': add_to_date(today(), days=-1)}) | |||
frappe.local.conf = _dict(frappe.get_site_config()) | |||
frappe.db.commit() | |||
res = requests.post(get_url(), params={'cmd': 'login', 'usr': 'test@example.com', 'pwd': 'testpassword', | |||
'device': 'desktop'}) | |||
res = requests.post(get_url(), params={'cmd': 'login', 'usr': | |||
'test@example.com', 'pwd': 'testpassword', 'device': 'desktop'}) | |||
# While site is expired status code returned is 417 Failed Expectation | |||
self.assertEqual(res.status_code, 417) | |||
@@ -1,7 +1,5 @@ | |||
frappe.ui.form.on('User', { | |||
before_load: function(frm) { | |||
frappe.setup_language_field(frm); | |||
var update_tz_select = function(user_language) { | |||
frm.set_df_property("time_zone", "options", [""].concat(frappe.all_timezones)); | |||
} | |||
@@ -38,17 +38,22 @@ class User(Document): | |||
[m.module_name for m in frappe.db.get_all('Desktop Icon', | |||
fields=['module_name'], filters={'standard': 1}, order_by="module_name")]) | |||
def before_insert(self): | |||
self.flags.in_insert = True | |||
def after_insert(self): | |||
self.set_default_roles() | |||
def validate(self): | |||
self.check_demo() | |||
self.in_insert = self.get("__islocal") | |||
# clear new password | |||
self.__new_password = self.new_password | |||
self.new_password = "" | |||
if self.name not in STANDARD_USERS: | |||
self.validate_email_type(self.email) | |||
self.validate_email_type(self.name) | |||
self.add_system_manager_role() | |||
self.set_system_user() | |||
self.set_full_name() | |||
@@ -70,6 +75,10 @@ class User(Document): | |||
frappe.clear_cache(user=self.name) | |||
self.send_password_notification(self.__new_password) | |||
def has_website_permission(self, ptype, verbose=False): | |||
"""Returns true if current user is the session user""" | |||
return self.name == frappe.session.user | |||
def check_demo(self): | |||
if frappe.session.user == 'demo@erpnext.com': | |||
frappe.throw('Cannot change user details in demo. Please signup for a new account at https://erpnext.com', title='Not Allowed') | |||
@@ -89,6 +98,33 @@ class User(Document): | |||
if not cint(self.enabled) and getattr(frappe.local, "login_manager", None): | |||
frappe.local.login_manager.logout(user=self.name) | |||
def set_default_roles(self): | |||
"""Set a default role if specified by rules (`default_role`) in hooks or Portal Settings | |||
Hooks for default roles can be set as: | |||
default_roles = [ | |||
{'role': 'Customer', 'doctype':'Contact', 'email_field': 'email_id', | |||
'filters': {'ifnull(customer, "")': ('!=', '')}} | |||
] | |||
""" | |||
role_found = False | |||
for rule in frappe.get_hooks('default_roles'): | |||
filters = {rule.get('email_field'): self.email} | |||
if rule.get('filters'): | |||
filters.update(rule.get('filters')) | |||
match = frappe.get_all(rule.get('doctype'), filters=filters, limit=1) | |||
if match: | |||
role_found = True | |||
self.add_roles(rule.get('role')) | |||
if not role_found: | |||
default_role = frappe.db.get_single_value('Portal Settings', 'default_role') | |||
if default_role: | |||
self.add_roles(default_role) | |||
def add_system_manager_role(self): | |||
# if adding system manager, do nothing | |||
if not cint(self.enabled) or ("System Manager" in [user_role.role for user_role in | |||
@@ -116,7 +152,7 @@ class User(Document): | |||
]) | |||
def email_new_password(self, new_password=None): | |||
if new_password and not self.in_insert: | |||
if new_password and not self.flags.in_insert: | |||
_update_password(self.name, new_password) | |||
if self.send_password_update_notification: | |||
@@ -124,14 +160,26 @@ class User(Document): | |||
frappe.msgprint(_("New password emailed")) | |||
def set_system_user(self): | |||
if self.user_roles or self.name == 'Administrator': | |||
'''Set as System User if any of the given roles has desk_access''' | |||
if self.has_desk_access() or self.name == 'Administrator': | |||
self.user_type = 'System User' | |||
else: | |||
self.user_type = 'Website User' | |||
def has_desk_access(self): | |||
'''Return true if any of the set roles has desk access''' | |||
if not self.user_roles: | |||
return False | |||
return len(frappe.db.sql("""select name | |||
from `tabRole` where desk_access=1 | |||
and name in ({0}) limit 1""".format(', '.join(['%s'] * len(self.user_roles))), | |||
[d.role for d in self.user_roles])) | |||
def share_with_self(self): | |||
if self.user_type=="System User": | |||
frappe.share.add(self.doctype, self.name, self.name, share=1, | |||
frappe.share.add(self.doctype, self.name, self.name, write=1, share=1, | |||
flags={"ignore_share_permission": True}) | |||
else: | |||
frappe.share.remove(self.doctype, self.name, self.name, | |||
@@ -147,7 +195,7 @@ class User(Document): | |||
def send_password_notification(self, new_password): | |||
try: | |||
if self.in_insert: | |||
if self.flags.in_insert: | |||
if self.name not in STANDARD_USERS: | |||
if new_password: | |||
# new password given, no email required | |||
@@ -155,12 +203,15 @@ class User(Document): | |||
if not self.flags.no_welcome_mail and self.send_welcome_email: | |||
self.send_welcome_mail_to_user() | |||
msgprint(_("Welcome email sent")) | |||
self.flags.email_sent = 1 | |||
if frappe.session.user != 'Guest': | |||
msgprint(_("Welcome email sent")) | |||
return | |||
else: | |||
self.email_new_password(new_password) | |||
except frappe.OutgoingEmailError: | |||
print frappe.get_traceback() | |||
pass # email server not set, don't send email | |||
@@ -458,6 +509,13 @@ def update_password(new_password, key=None, old_password=None): | |||
user_doc, redirect_url = reset_user_data(user) | |||
# get redirect url from cache | |||
redirect_to = frappe.cache().hget('redirect_after_login', user) | |||
if redirect_to: | |||
redirect_url = redirect_to | |||
frappe.cache().hdel('redirect_after_login', user) | |||
frappe.local.login_manager.login_as(user) | |||
if user_doc.user_type == "System User": | |||
@@ -517,7 +575,7 @@ def verify_password(password): | |||
frappe.local.login_manager.check_password(frappe.session.user, password) | |||
@frappe.whitelist(allow_guest=True) | |||
def sign_up(email, full_name): | |||
def sign_up(email, full_name, redirect_to): | |||
user = frappe.db.get("User", {"email": email}) | |||
if user: | |||
if user.disabled: | |||
@@ -526,9 +584,12 @@ def sign_up(email, full_name): | |||
return _("Already Registered") | |||
else: | |||
if frappe.db.sql("""select count(*) from tabUser where | |||
HOUR(TIMEDIFF(CURRENT_TIMESTAMP, TIMESTAMP(modified)))=1""")[0][0] > 200: | |||
frappe.msgprint("Login is closed for sometime, please check back again in an hour.") | |||
raise Exception, "Too Many New Users" | |||
HOUR(TIMEDIFF(CURRENT_TIMESTAMP, TIMESTAMP(modified)))=1""")[0][0] > 300: | |||
frappe.respond_as_web_page(_('Temperorily Disabled'), | |||
_('Too many users signed up recently, so the registration is disabled. Please try back in an hour'), | |||
http_status_code=429) | |||
from frappe.utils import random_string | |||
user = frappe.get_doc({ | |||
"doctype":"User", | |||
@@ -540,7 +601,14 @@ def sign_up(email, full_name): | |||
}) | |||
user.flags.ignore_permissions = True | |||
user.insert() | |||
return _("Registration Details Emailed.") | |||
if redirect_to: | |||
frappe.cache().hset('redirect_after_login', user.name, redirect_to) | |||
if user.flags.email_sent: | |||
return _("Please check your email for verification") | |||
else: | |||
return _("Please ask your administrator to verify your sign-up") | |||
@frappe.whitelist(allow_guest=True) | |||
def reset_password(user): | |||
@@ -630,10 +698,10 @@ def has_permission(doc, user): | |||
# dont allow non Administrator user to view / edit Administrator user | |||
return False | |||
def notifify_admin_access_to_system_manager(login_manager=None): | |||
def notify_admin_access_to_system_manager(login_manager=None): | |||
if (login_manager | |||
and login_manager.user == "Administrator" | |||
and frappe.local.conf.notifify_admin_access_to_system_manager): | |||
and frappe.local.conf.notify_admin_access_to_system_manager): | |||
message = """<p> | |||
{dear_system_manager} <br><br> | |||
@@ -7,7 +7,7 @@ import frappe | |||
def get_notification_config(): | |||
return { | |||
"for_doctype": { | |||
"Scheduler Log": {"seen": 0}, | |||
"Error Log": {"seen": 0}, | |||
"Communication": {"status": "Open", "communication_type": "Communication"}, | |||
"ToDo": "frappe.core.notifications.get_things_todo", | |||
"Event": "frappe.core.notifications.get_todays_events", | |||
@@ -0,0 +1,39 @@ | |||
<div class="list-jobs"> | |||
{% if jobs.length %} | |||
<table class="table table-bordered" style="table-layout: fixed;"> | |||
<thead> | |||
<tr> | |||
<th style="width: 20%">Queue / Worker</th> | |||
<th>Job</th> | |||
<th style="width: 15%">Created</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{% for j in jobs %} | |||
<tr> | |||
<td><span class="indicator {{ j.color }}" title="{{ j.status }}">{{ j.queue.split(".").slice(-1)[0] }}</span></td> | |||
<td style="overflow: auto;"> | |||
<div> | |||
{{ frappe.utils.encode_tags(j.job_name) }} | |||
</div> | |||
{% if j.exc_info %} | |||
<div> | |||
<pre>{{ frappe.utils.encode_tags(j.exc_info) }}</pre> | |||
</div> | |||
{% endif %} | |||
</td> | |||
<td class="small">{{ j.creation }}</td> | |||
</tr> | |||
{% endfor %} | |||
</tbody> | |||
</table> | |||
<p> | |||
<span class="indicator green" style="margin-right: 20px;">Started</span> | |||
<span class="indicator orange" style="margin-right: 20px;">Queued</span> | |||
<span class="indicator red">Failed</span> | |||
</p> | |||
{% else %} | |||
<p class="text-muted">No pending or current jobs for this site</p> | |||
{% endif %} | |||
<p class="text-muted" style="margin-top: 30px;">Last refreshed {{ frappe.datetime.now_datetime() }}</p> | |||
</div> |
@@ -0,0 +1,39 @@ | |||
frappe.pages['background_jobs'].on_page_load = function(wrapper) { | |||
var page = frappe.ui.make_app_page({ | |||
parent: wrapper, | |||
title: 'Background Jobs', | |||
single_column: true | |||
}); | |||
$(frappe.render_template('background_jobs_outer')).appendTo(page.body); | |||
page.content = $(page.body).find('.table-area'); | |||
frappe.pages.background_jobs.page = page; | |||
} | |||
frappe.pages['background_jobs'].on_page_show = function(wrapper) { | |||
frappe.pages.background_jobs.refresh_jobs(); | |||
} | |||
frappe.pages.background_jobs.refresh_jobs = function() { | |||
var page = frappe.pages.background_jobs.page; | |||
// don't call if already waiting for a response | |||
if(page.called) return; | |||
page.called = true; | |||
frappe.call({ | |||
method: 'frappe.core.page.background_jobs.background_jobs.get_info', | |||
args: { | |||
show_failed: page.body.find('.show-failed').prop('checked') ? 1 : 0 | |||
}, | |||
callback: function(r) { | |||
page.called = false; | |||
page.body.find('.list-jobs').remove(); | |||
$(frappe.render_template('background_jobs', {jobs:r.message || []})).appendTo(page.content); | |||
if(frappe.get_route()[0]==='background_jobs') { | |||
frappe.background_jobs_timeout = setTimeout(frappe.pages.background_jobs.refresh_jobs, 2000); | |||
} | |||
} | |||
}); | |||
} |
@@ -0,0 +1,22 @@ | |||
{ | |||
"content": null, | |||
"creation": "2016-08-18 16:44:14.322642", | |||
"docstatus": 0, | |||
"doctype": "Page", | |||
"idx": 0, | |||
"modified": "2016-08-18 16:48:11.577611", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "background_jobs", | |||
"owner": "Administrator", | |||
"page_name": "background_jobs", | |||
"roles": [ | |||
{ | |||
"role": "System Manager" | |||
} | |||
], | |||
"script": null, | |||
"standard": "Yes", | |||
"style": null, | |||
"title": "Background Jobs" | |||
} |
@@ -0,0 +1,51 @@ | |||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
from rq import Queue, Worker | |||
from frappe.utils.background_jobs import get_redis_conn | |||
from frappe.utils import format_datetime, cint | |||
colors = { | |||
'queued': 'orange', | |||
'failed': 'red', | |||
'started': 'green' | |||
} | |||
@frappe.whitelist() | |||
def get_info(show_failed=False): | |||
conn = get_redis_conn() | |||
queues = Queue.all(conn) | |||
workers = Worker.all(conn) | |||
jobs = [] | |||
def add_job(j, name): | |||
if j.kwargs.get('site')==frappe.local.site or True: | |||
jobs.append({ | |||
'job_name': j.kwargs.get('kwargs', {}).get('playbook_method') \ | |||
or str(j.kwargs.get('job_name')), | |||
'status': j.status, 'queue': name, | |||
'creation': format_datetime(j.created_at), | |||
'color': colors[j.status] | |||
}) | |||
if j.exc_info: | |||
jobs[-1]['exc_info'] = j.exc_info | |||
for w in workers: | |||
j = w.get_current_job() | |||
if j: | |||
add_job(j, w.name) | |||
for q in queues: | |||
if q.name != 'failed': | |||
for j in q.get_jobs(): add_job(j, q.name) | |||
if cint(show_failed): | |||
for q in queues: | |||
if q.name == 'failed': | |||
for j in q.get_jobs()[:10]: add_job(j, q.name) | |||
return jobs |
@@ -0,0 +1,12 @@ | |||
<div style="padding: 20px;"> | |||
<p> | |||
<div class="checkbox"> | |||
<label> | |||
<input type="checkbox" class="show-failed"> {{ __("Show failed jobs") }} | |||
</label> | |||
</div> | |||
</p> | |||
<div class="table-area"> | |||
</div> | |||
</div> |
@@ -77,6 +77,12 @@ | |||
{%= __("Ignore encoding errors.") %} | |||
</label> | |||
</div> | |||
<div class="checkbox"> | |||
<label> | |||
<input type="checkbox" name="no_email" checked> | |||
{%= __("Do not send Emails.") %} | |||
</label> | |||
</div> | |||
<p> | |||
<button class="btn btn-sm btn-primary btn-import">Import</button> | |||
</p> | |||
@@ -42,11 +42,15 @@ frappe.DataImportTool = Class.extend({ | |||
if(me.doctype) { | |||
// render select columns | |||
var doctype_list = [frappe.get_doc('DocType', me.doctype)]; | |||
var parent_doctype = frappe.get_doc('DocType', me.doctype); | |||
parent_doctype["reqd"] = true; | |||
var doctype_list = [parent_doctype]; | |||
frappe.meta.get_table_fields(me.doctype).forEach(function(df) { | |||
doctype_list.push(frappe.get_doc('DocType', df.options)); | |||
var d = frappe.get_doc('DocType', df.options); | |||
d["reqd"]=df.reqd; | |||
doctype_list.push(d); | |||
}); | |||
$(frappe.render_template("data_import_tool_columns", {doctype_list: doctype_list})) | |||
.appendTo(me.select_columns.empty()); | |||
} | |||
@@ -103,7 +107,8 @@ frappe.DataImportTool = Class.extend({ | |||
return { | |||
submit_after_import: me.page.main.find('[name="submit_after_import"]').prop("checked"), | |||
ignore_encoding_errors: me.page.main.find('[name="ignore_encoding_errors"]').prop("checked"), | |||
overwrite: !me.page.main.find('[name="always_insert"]').prop("checked") | |||
overwrite: !me.page.main.find('[name="always_insert"]').prop("checked"), | |||
no_email: me.page.main.find('[name="no_email"]').prop("checked") | |||
} | |||
}, | |||
args: { | |||
@@ -26,12 +26,12 @@ 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, pre_process=None): | |||
def import_file_by_path(path, ignore_links=False, overwrite=False, submit=False, pre_process=None, no_email=True): | |||
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, | |||
upload(rows = read_csv_content(infile.read()), ignore_links=ignore_links, no_email=no_email, overwrite=overwrite, | |||
submit_after_import=submit, pre_process=pre_process) | |||
def export_csv(doctype, path): | |||
@@ -4,6 +4,7 @@ | |||
<div class="row"> | |||
{% for f in doctype.fields %} | |||
{% if (frappe.model.no_value_type.indexOf(f.fieldtype)===-1) %} | |||
{% doctype.reqd||(f.reqd=0);%} | |||
<div class="col-sm-4"> | |||
<div class="checkbox" style="margin: 5px 0px;"> | |||
<label> | |||
@@ -16,19 +16,24 @@ from frappe.utils import cint, cstr, flt, getdate, get_datetime | |||
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, | |||
def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, no_email=True, overwrite=None, | |||
ignore_links=False, pre_process=None, via_console=False): | |||
"""upload data""" | |||
frappe.flags.mute_emails = True | |||
frappe.flags.in_import = True | |||
# extra input params | |||
params = json.loads(frappe.form_dict.get("params") or '{}') | |||
if params.get("submit_after_import"): | |||
submit_after_import = True | |||
if params.get("ignore_encoding_errors"): | |||
ignore_encoding_errors = True | |||
if not params.get("no_email"): | |||
no_email = False | |||
frappe.flags.mute_emails = no_email | |||
from frappe.utils.csvutils import read_csv_content_from_uploaded_file | |||
@@ -18,8 +18,8 @@ def get_roles_and_doctypes(): | |||
istable=0 and | |||
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 | |||
('Administrator')""")] | |||
"roles": [d[0] for d in frappe.db.sql("""select name from tabRole where | |||
name != 'Administrator' and disabled=0""")] | |||
} | |||
@frappe.whitelist() | |||
@@ -20,7 +20,7 @@ frappe.query_reports["Permitted Documents For User"] = { | |||
return { | |||
"query": "frappe.core.report.permitted_documents_for_user.permitted_documents_for_user.query_doctypes", | |||
"filters": { | |||
"user": frappe.query_report.filters_by_name.user.get_value() | |||
"user": frappe.query_report_filters_by_name.user.get_value() | |||
} | |||
} | |||
} | |||
@@ -0,0 +1,3 @@ | |||
frappe.ready(function() { | |||
// bind events here | |||
}) |
@@ -0,0 +1,86 @@ | |||
{ | |||
"allow_comments": 0, | |||
"allow_delete": 0, | |||
"allow_edit": 1, | |||
"allow_multiple": 0, | |||
"breadcrumbs": "[{\"title\": _(\"My Account\"), \"route\": \"me\"}]", | |||
"creation": "2016-09-19 05:16:59.242754", | |||
"doc_type": "User", | |||
"docstatus": 0, | |||
"doctype": "Web Form", | |||
"idx": 0, | |||
"is_standard": 1, | |||
"login_required": 1, | |||
"modified": "2016-09-24 04:31:41.920694", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "edit-profile", | |||
"owner": "Administrator", | |||
"published": 1, | |||
"route": "update-profile", | |||
"show_sidebar": 1, | |||
"sidebar_items": [], | |||
"success_message": "Profile updated successfully.", | |||
"success_url": "/me", | |||
"title": "Update Profile", | |||
"web_form_fields": [ | |||
{ | |||
"fieldname": "first_name", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"label": "First Name", | |||
"read_only": 0, | |||
"reqd": 1 | |||
}, | |||
{ | |||
"fieldname": "middle_name", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"label": "Middle Name (Optional)", | |||
"read_only": 0, | |||
"reqd": 0 | |||
}, | |||
{ | |||
"fieldname": "last_name", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"label": "Last Name", | |||
"read_only": 0, | |||
"reqd": 0 | |||
}, | |||
{ | |||
"description": "", | |||
"fieldname": "user_image", | |||
"fieldtype": "Attach", | |||
"hidden": 0, | |||
"label": "User Image", | |||
"read_only": 0, | |||
"reqd": 0 | |||
}, | |||
{ | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
"label": "More Information", | |||
"read_only": 0, | |||
"reqd": 0 | |||
}, | |||
{ | |||
"fieldname": "phone", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"label": "Phone", | |||
"read_only": 0, | |||
"reqd": 0 | |||
}, | |||
{ | |||
"description": "", | |||
"fieldname": "language", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
"label": "Language", | |||
"options": "Language", | |||
"read_only": 0, | |||
"reqd": 0 | |||
} | |||
] | |||
} |
@@ -0,0 +1,7 @@ | |||
from __future__ import unicode_literals | |||
import frappe | |||
def get_context(context): | |||
# do your magic here | |||
pass |
@@ -9,12 +9,14 @@ | |||
"description": "Adds a custom script (client or server) to a DocType", | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "Document", | |||
"editable_grid": 0, | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "dt", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
@@ -42,6 +44,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "Client", | |||
"fieldname": "script_type", | |||
"fieldtype": "Select", | |||
@@ -70,6 +73,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "script", | |||
"fieldtype": "Code", | |||
"hidden": 0, | |||
@@ -97,6 +101,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "sample", | |||
"fieldtype": "HTML", | |||
"hidden": 0, | |||
@@ -130,7 +135,7 @@ | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-07-25 05:24:24.245725", | |||
"modified": "2016-09-24 05:47:53.900418", | |||
"modified_by": "Administrator", | |||
"module": "Custom", | |||
"name": "Custom Script", | |||
@@ -177,7 +182,7 @@ | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 1, | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"sort_order": "ASC", | |||
@@ -4,11 +4,15 @@ | |||
frappe.provide("frappe.customize_form"); | |||
frappe.ui.form.on("Customize Form", { | |||
setup: function(frm) { | |||
frm.get_docfield("fields").allow_bulk_edit = 1; | |||
}, | |||
onload: function(frm) { | |||
frappe.customize_form.add_fields_help(frm); | |||
frm.set_query("doc_type", function() { | |||
return { | |||
translate_values: false, | |||
filters: [ | |||
['DocType', 'issingle', '=', 0], | |||
['DocType', 'custom', '=', 0], | |||
@@ -71,6 +75,28 @@ frappe.ui.form.on("Customize Form", { | |||
frm.add_custom_button(__('Reset to defaults'), function() { | |||
frappe.customize_form.confirm(__('Remove all customizations?'), frm); | |||
}, "icon-eraser", "btn-default"); | |||
if(frappe.boot.developer_mode) { | |||
frm.add_custom_button(__('Export Customizations'), function() { | |||
frappe.prompt( | |||
[ | |||
{fieldtype:'Link', fieldname:'module', options:'Module Def', | |||
label: __('Module to Export')}, | |||
{fieldtype:'Check', fieldname:'sync_on_migrate', | |||
label: __('Sync on Migrate'), 'default': 1}, | |||
], | |||
function(data) { | |||
frappe.call({ | |||
method: 'frappe.modules.utils.export_customizations', | |||
args: { | |||
doctype: frm.doc.doc_type, | |||
module: data.module, | |||
sync_on_migrate: data.sync_on_migrate | |||
} | |||
}); | |||
}); | |||
}); | |||
} | |||
} | |||
// sort order select | |||
@@ -15,6 +15,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "doc_type", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
@@ -40,6 +41,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "doc_type", | |||
"fieldname": "properties", | |||
"fieldtype": "Section Break", | |||
@@ -65,6 +67,33 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "label", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Change Label (via Custom Translation)", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "default_print_format", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
@@ -90,6 +119,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "", | |||
"fieldname": "max_attachments", | |||
"fieldtype": "Int", | |||
@@ -115,6 +145,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "allow_copy", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -139,6 +170,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "istable", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -164,6 +196,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "istable", | |||
"fieldname": "editable_grid", | |||
"fieldtype": "Check", | |||
@@ -190,6 +223,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "1", | |||
"fieldname": "quick_entry", | |||
"fieldtype": "Check", | |||
@@ -216,6 +250,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval: doc.image_field", | |||
"fieldname": "image_view", | |||
"fieldtype": "Check", | |||
@@ -242,6 +277,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_5", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -266,6 +302,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Use this fieldname to generate title", | |||
"fieldname": "title_field", | |||
"fieldtype": "Data", | |||
@@ -292,6 +329,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Must be of type \"Attach Image\"", | |||
"fieldname": "image_field", | |||
"fieldtype": "Data", | |||
@@ -318,6 +356,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Fields separated by comma (,) will be included in the \"Search By\" list of Search dialog box", | |||
"fieldname": "search_fields", | |||
"fieldtype": "Data", | |||
@@ -343,6 +382,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "doc_type", | |||
"fieldname": "section_break_8", | |||
"fieldtype": "Section Break", | |||
@@ -368,6 +408,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "sort_field", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
@@ -392,6 +433,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_10", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -416,6 +458,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "sort_order", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
@@ -441,6 +484,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "doc_type", | |||
"description": "Customize Label, Print Hide, Default etc.", | |||
"fieldname": "fields_section_break", | |||
@@ -467,6 +511,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "fields", | |||
"fieldtype": "Table", | |||
"hidden": 0, | |||
@@ -500,7 +545,7 @@ | |||
"issingle": 1, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-07-08 04:40:57.045612", | |||
"modified": "2016-09-16 02:36:09.171273", | |||
"modified_by": "Administrator", | |||
"module": "Custom", | |||
"name": "Customize Form", | |||
@@ -7,6 +7,7 @@ from __future__ import unicode_literals | |||
Thus providing a better UI from user perspective | |||
""" | |||
import frappe | |||
import frappe.translate | |||
from frappe import _ | |||
from frappe.utils import cint | |||
from frappe.model.document import Document | |||
@@ -54,7 +55,8 @@ docfield_properties = { | |||
'default': 'Text', | |||
'precision': 'Select', | |||
'read_only': 'Check', | |||
'length': 'Int' | |||
'length': 'Int', | |||
'columns': 'Int' | |||
} | |||
allowed_fieldtype_change = (('Currency', 'Float', 'Percent'), ('Small Text', 'Data'), | |||
@@ -83,8 +85,36 @@ class CustomizeForm(Document): | |||
new_d[property] = d.get(property) | |||
self.append("fields", new_d) | |||
# load custom translation | |||
translation = self.get_name_translation() | |||
self.label = translation.target_name if translation else '' | |||
# NOTE doc is sent to clientside by run_method | |||
def get_name_translation(self): | |||
'''Get translation object if exists of current doctype name in the default language''' | |||
return frappe.get_value('Translation', | |||
{'source_name': self.doc_type, 'language_code': frappe.local.lang or 'en'}, | |||
['name', 'target_name'], as_dict=True) | |||
def set_name_translation(self): | |||
'''Create, update custom translation for this doctype''' | |||
current = self.get_name_translation() | |||
if current: | |||
if self.label and current!=self.label: | |||
frappe.db.set_value('Translation', current.name, 'target_name', self.label) | |||
frappe.translate.clear_cache() | |||
else: | |||
# clear translation | |||
frappe.delete_doc('Translation', current.name) | |||
else: | |||
if self.label: | |||
frappe.get_doc(dict(doctype='Translation', | |||
source_name=self.doc_type, | |||
target_name=self.label, | |||
language_code=frappe.local.lang or 'en')).insert() | |||
def clear_existing_doc(self): | |||
doc_type = self.doc_type | |||
@@ -101,10 +131,18 @@ class CustomizeForm(Document): | |||
if not self.doc_type: | |||
return | |||
self.flags.update_db = False | |||
self.set_property_setters() | |||
self.update_custom_fields() | |||
self.set_name_translation() | |||
validate_fields_for_doctype(self.doc_type) | |||
if self.flags.update_db: | |||
from frappe.model.db_schema import updatedb | |||
updatedb(self.doc_type) | |||
frappe.msgprint(_("{0} updated").format(_(self.doc_type))) | |||
frappe.clear_cache(doctype=self.doc_type) | |||
self.fetch_to_customize() | |||
@@ -117,7 +155,6 @@ class CustomizeForm(Document): | |||
self.make_property_setter(property=property, value=self.get(property), | |||
property_type=doctype_properties[property]) | |||
update_db = False | |||
for df in self.get("fields"): | |||
if df.get("__islocal"): | |||
continue | |||
@@ -144,10 +181,10 @@ class CustomizeForm(Document): | |||
elif property == "precision" and cint(df.get("precision")) > 6 \ | |||
and cint(df.get("precision")) > cint(meta_df[0].get("precision")): | |||
update_db = True | |||
self.flags.update_db = True | |||
elif property == "unique": | |||
update_db = True | |||
self.flags.update_db = True | |||
elif (property == "read_only" and cint(df.get("read_only"))==0 | |||
and frappe.db.get_value("DocField", {"parent": self.doc_type, "fieldname": df.fieldname}, "read_only")==1): | |||
@@ -158,16 +195,14 @@ class CustomizeForm(Document): | |||
self.make_property_setter(property=property, value=df.get(property), | |||
property_type=docfield_properties[property], fieldname=df.fieldname) | |||
if update_db: | |||
from frappe.model.db_schema import updatedb | |||
updatedb(self.doc_type) | |||
def update_custom_fields(self): | |||
for i, df in enumerate(self.get("fields")): | |||
if df.get("__islocal"): | |||
self.add_custom_field(df, i) | |||
else: | |||
self.update_in_custom_field(df, i) | |||
if df.get("is_custom_field"): | |||
if not frappe.db.exists('Custom Field', {'dt': self.doc_type, 'fieldname': df.fieldname}): | |||
self.add_custom_field(df, i) | |||
self.flags.update_db = True | |||
else: | |||
self.update_in_custom_field(df, i) | |||
self.delete_custom_fields() | |||
@@ -179,7 +214,8 @@ class CustomizeForm(Document): | |||
for property in docfield_properties: | |||
d.set(property, df.get(property)) | |||
d.insert_after = self.fields[i-1].fieldname | |||
if i!=0: | |||
d.insert_after = self.fields[i-1].fieldname | |||
d.idx = i | |||
d.insert() | |||
@@ -189,6 +225,7 @@ class CustomizeForm(Document): | |||
meta = frappe.get_meta(self.doc_type) | |||
meta_df = meta.get("fields", {"fieldname": df.fieldname}) | |||
if not (meta_df and meta_df[0].get("is_custom_field")): | |||
# not a custom field | |||
return | |||
custom_field = frappe.get_doc("Custom Field", meta_df[0].name) | |||
@@ -202,15 +239,17 @@ class CustomizeForm(Document): | |||
changed = True | |||
# check and update `insert_after` property | |||
insert_after = self.fields[i-1].fieldname | |||
if custom_field.insert_after != insert_after: | |||
custom_field.insert_after = insert_after | |||
custom_field.idx = i | |||
changed = True | |||
if i!=0: | |||
insert_after = self.fields[i-1].fieldname | |||
if custom_field.insert_after != insert_after: | |||
custom_field.insert_after = insert_after | |||
custom_field.idx = i | |||
changed = True | |||
if changed: | |||
custom_field.flags.ignore_validate = True | |||
custom_field.save() | |||
custom_field.db_update() | |||
self.flags.update_db = True | |||
#custom_field.save() | |||
def delete_custom_fields(self): | |||
meta = frappe.get_meta(self.doc_type) | |||
@@ -109,7 +109,7 @@ class TestCustomizeForm(unittest.TestCase): | |||
d.append("fields", { | |||
"label": "Test Add Custom Field Via Customize Form", | |||
"fieldtype": "Data", | |||
"__islocal": 1 | |||
"is_custom_field": 1 | |||
}) | |||
d.run_method("save_customization") | |||
self.assertEquals(frappe.db.get_value("Custom Field", | |||
@@ -15,6 +15,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "label_and_type", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -40,6 +41,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "label", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
@@ -66,6 +68,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "Data", | |||
"fieldname": "fieldtype", | |||
"fieldtype": "Select", | |||
@@ -94,6 +97,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "fieldname", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
@@ -120,6 +124,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "reqd", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -148,6 +153,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "unique", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -173,6 +179,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "in_list_view", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -197,6 +204,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_7", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -221,6 +229,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:in_list([\"Float\", \"Currency\", \"Percent\"], doc.fieldtype)", | |||
"description": "Set non-standard precision for a Float or Currency field", | |||
"fieldname": "precision", | |||
@@ -249,6 +258,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:in_list(['Data', 'Link', 'Dynamic Link', 'Password', 'Select', 'Read Only', 'Attach', 'Attach Image'], doc.fieldtype)", | |||
"fieldname": "length", | |||
"fieldtype": "Int", | |||
@@ -275,6 +285,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "For Links, enter the DocType as range.\nFor Select, enter list of Options, each on a new line.", | |||
"fieldname": "options", | |||
"fieldtype": "Text", | |||
@@ -302,6 +313,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "permissions", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -327,6 +339,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 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": "Code", | |||
@@ -354,6 +367,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "0", | |||
"fieldname": "permlevel", | |||
"fieldtype": "Int", | |||
@@ -381,6 +395,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "hidden", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -409,6 +424,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "read_only", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -434,6 +450,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:doc.fieldtype==\"Section Break\"", | |||
"fieldname": "collapsible", | |||
"fieldtype": "Check", | |||
@@ -460,6 +477,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:doc.fieldtype==\"Section Break\"", | |||
"fieldname": "collapsible_depends_on", | |||
"fieldtype": "Code", | |||
@@ -486,6 +504,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_14", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -510,6 +529,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "ignore_user_permissions", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -534,6 +554,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "allow_on_submit", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -560,6 +581,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "report_hide", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -586,6 +608,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "display", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
@@ -611,6 +634,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "default", | |||
"fieldtype": "Text", | |||
"hidden": 0, | |||
@@ -637,6 +661,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "in_filter", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -665,6 +690,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "column_break_21", | |||
"fieldtype": "Column Break", | |||
"hidden": 0, | |||
@@ -689,6 +715,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "description", | |||
"fieldtype": "Text", | |||
"hidden": 0, | |||
@@ -717,6 +744,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "print_hide", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -743,6 +771,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:[\"Int\", \"Float\", \"Currency\", \"Percent\"].indexOf(doc.fieldtype)!==-1", | |||
"fieldname": "print_hide_if_no_value", | |||
"fieldtype": "Check", | |||
@@ -769,6 +798,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Print Width of the field, if the field is a column in a table", | |||
"fieldname": "print_width", | |||
"fieldtype": "Data", | |||
@@ -796,6 +826,35 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:cur_frm.doc.istable", | |||
"description": "Number of columns for a field in a Grid (Total Columns in a grid should be less than 11)", | |||
"fieldname": "columns", | |||
"fieldtype": "Int", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Columns", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "width", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
@@ -824,6 +883,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "is_custom_field", | |||
"fieldtype": "Check", | |||
"hidden": 1, | |||
@@ -856,7 +916,7 @@ | |||
"issingle": 0, | |||
"istable": 1, | |||
"max_attachments": 0, | |||
"modified": "2016-07-11 03:27:58.928043", | |||
"modified": "2016-08-23 12:03:07.126339", | |||
"modified_by": "Administrator", | |||
"module": "Custom", | |||
"name": "Customize Form Field", | |||
@@ -865,5 +925,6 @@ | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"sort_order": "ASC", | |||
"track_seen": 0 | |||
} |
@@ -42,6 +42,7 @@ CREATE TABLE `tabDocField` ( | |||
`ignore_user_permissions` int(1) NOT NULL DEFAULT 0, | |||
`width` varchar(255) DEFAULT NULL, | |||
`print_width` varchar(255) DEFAULT NULL, | |||
`columns` int(11) NOT NULL DEFAULT 0, | |||
`default` text, | |||
`description` text, | |||
`in_filter` int(1) NOT NULL DEFAULT 0, | |||
@@ -76,6 +77,7 @@ CREATE TABLE `tabDocPerm` ( | |||
`permlevel` int(11) DEFAULT '0', | |||
`role` varchar(255) DEFAULT NULL, | |||
`match` varchar(255) DEFAULT NULL, | |||
`is_custom` int(1) NOT NULL DEFAULT 0, | |||
`read` int(1) NOT NULL DEFAULT 1, | |||
`write` int(1) NOT NULL DEFAULT 1, | |||
`create` int(1) NOT NULL DEFAULT 1, | |||
@@ -144,6 +146,7 @@ CREATE TABLE `tabDocType` ( | |||
`tag_fields` varchar(255) DEFAULT NULL, | |||
`subject` varchar(255) DEFAULT NULL, | |||
`_last_update` varchar(32) DEFAULT NULL, | |||
`engine` varchar(20) DEFAULT 'InnoDB', | |||
`default_print_format` varchar(255) DEFAULT NULL, | |||
`is_submittable` int(1) NOT NULL DEFAULT 0, | |||
`_user_tags` varchar(255) DEFAULT NULL, | |||
@@ -1,57 +0,0 @@ | |||
ar العربية | |||
bg bǎlgarski | |||
bn বাংলা | |||
bo ལྷ་སའི་སྐད་ | |||
bs bosanski | |||
ca català | |||
cs česky | |||
da dansk | |||
da-DK dansk (Danmark) | |||
de deutsch | |||
el ελληνικά | |||
en english | |||
es español | |||
es-PE Español (Perú) | |||
et eesti | |||
fa پارسی | |||
fi suomalainen | |||
fr français | |||
gu ગુજરાતી | |||
he עברית | |||
hi हिंदी | |||
hr hrvatski | |||
hu magyar | |||
id Indonesia | |||
is íslenska | |||
it italiano | |||
ja 日本語 | |||
km ភាសាខ្មែរ | |||
kn ಕನ್ನಡ | |||
ko 한국의 | |||
lv latviešu valoda | |||
mk македонски | |||
ml മലയാളം | |||
mr मराठी | |||
ms Melayu | |||
my မြန်မာ | |||
nl nederlands | |||
no norsk | |||
pl polski | |||
pt português | |||
pt-BR português brasileiro | |||
ro român | |||
ru русский | |||
sk slovenčina (Slovak) | |||
sl slovenščina (Slovene) | |||
sv svenska | |||
sq shqiptar | |||
sr српски | |||
ta தமிழ் | |||
te తెలుగు | |||
th ไทย | |||
tr Türk | |||
uk українська | |||
ur اردو | |||
vi việt | |||
zh-cn 簡體中文 | |||
zh-tw 正體中文 |
@@ -108,7 +108,8 @@ def set_default(key, value, parent, parenttype="__default"): | |||
:param parent: Usually, **User** to whom the default belongs. | |||
:param parenttype: [optional] default is `__default`.""" | |||
frappe.db.sql("""delete from `tabDefaultValue` where defkey=%s and parent=%s""", (key, parent)) | |||
add_default(key, value, parent) | |||
if value != None: | |||
add_default(key, value, parent) | |||
def add_default(key, value, parent, parenttype=None): | |||
d = frappe.get_doc({ | |||
@@ -13,7 +13,11 @@ def get(name): | |||
page = frappe.get_doc('Page', name) | |||
if page.is_permitted(): | |||
page.load_assets() | |||
return page | |||
docs = frappe._dict(page.as_dict()) | |||
if getattr(page, '_dynamic_page', None): | |||
docs['_dynamic_page'] = 1 | |||
return docs | |||
else: | |||
frappe.response['403'] = 1 | |||
raise frappe.PermissionError, 'No read permission for Page %s' % \ | |||
@@ -14,6 +14,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "document_type", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
@@ -31,7 +32,7 @@ | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
@@ -40,6 +41,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "field", | |||
"fieldtype": "Select", | |||
"hidden": 0, | |||
@@ -56,7 +58,7 @@ | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
@@ -65,6 +67,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "update_value", | |||
"fieldtype": "Small Text", | |||
"hidden": 0, | |||
@@ -81,15 +84,16 @@ | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"bold": 1, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "SQL Conditions. Example: status=\"Open\"", | |||
"fieldname": "condition", | |||
"fieldtype": "Small Text", | |||
@@ -114,8 +118,9 @@ | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"bold": 1, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"default": "500", | |||
"description": "Max 500 records at a time", | |||
"fieldname": "limit", | |||
@@ -150,7 +155,7 @@ | |||
"issingle": 1, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-07-15 06:24:42.575613", | |||
"modified": "2016-09-23 05:10:19.377701", | |||
"modified_by": "Administrator", | |||
"module": "Desk", | |||
"name": "Bulk Update", | |||
@@ -178,7 +183,7 @@ | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 0, | |||
"quick_entry": 1, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"sort_field": "modified", | |||
@@ -29,7 +29,12 @@ def update(doctype, field, value, condition='', limit=500): | |||
for i, d in enumerate(items): | |||
doc = frappe.get_doc(doctype, d) | |||
doc.set(field, value) | |||
doc.save() | |||
try: | |||
doc.save() | |||
except Exception, e: | |||
frappe.msgprint(_("Validation failed for {0}").format(frappe.bold(doc.name))) | |||
raise e | |||
frappe.publish_progress(float(i)*100/n, | |||
title = _('Updating Records'), doctype='Bulk Update', docname='Bulk Update') | |||
@@ -5,6 +5,7 @@ | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe import _ | |||
import json | |||
import random | |||
from frappe.model.document import Document | |||
@@ -81,6 +82,10 @@ def get_desktop_icons(user=None): | |||
# sort by idx | |||
user_icons.sort(lambda a, b: 1 if a.idx > b.idx else -1) | |||
# translate | |||
for d in user_icons: | |||
if d.label: d.label = _(d.label) | |||
frappe.cache().hset('desktop_icons', user, user_icons) | |||
return user_icons | |||
@@ -4,7 +4,8 @@ | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe.utils import getdate, cint, add_months, date_diff, add_days, nowdate, get_datetime_str, cstr | |||
from frappe.utils import (getdate, cint, add_months, date_diff, add_days, | |||
nowdate, get_datetime_str, cstr, get_datetime) | |||
from frappe.model.document import Document | |||
from frappe.utils.user import get_enabled_system_users | |||
@@ -12,15 +13,14 @@ weekdays = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", | |||
class Event(Document): | |||
def validate(self): | |||
if self.starts_on and self.ends_on and self.starts_on > self.ends_on: | |||
if self.starts_on and self.ends_on and get_datetime(self.starts_on) > get_datetime(self.ends_on): | |||
frappe.msgprint(frappe._("Event end must be after start"), raise_exception=True) | |||
if self.starts_on == self.ends_on: | |||
# this scenario doesn't make sense i.e. it starts and ends at the same second! | |||
self.ends_on = None | |||
if self.starts_on and self.ends_on and int(date_diff(self.ends_on.split(" ")[0], self.starts_on.split(" ")[0])) > 0 \ | |||
and self.repeat_on == "Every Day": | |||
if getdate(self.starts_on) == getdate(self.ends_on) and self.repeat_on == "Every Day": | |||
frappe.msgprint(frappe._("Every day events should finish on the same day."), raise_exception=True) | |||
def get_permission_query_conditions(user): | |||
@@ -0,0 +1,3 @@ | |||
frappe.listview_settings['Event'] = { | |||
add_fields: ["starts_on", "ends_on"] | |||
} |
@@ -26,11 +26,9 @@ frappe.ui.form.on("Note", { | |||
// hide all other fields | |||
$.each(frm.fields_dict, function(fieldname, field) { | |||
if(fieldname !== "content" | |||
&& !in_list(["Section Break", "Column Break"], field.df.fieldtype)) { | |||
frm.set_df_property(fieldname, "hidden", editable ? 0: 1); | |||
} | |||
if(fieldname !== "content") { | |||
frm.set_df_property(fieldname, "hidden", editable ? 0: 1); | |||
} | |||
}) | |||
// no label, description for content either | |||
@@ -5,7 +5,7 @@ | |||
"beta": 0, | |||
"creation": "2013-05-24 13:41:00", | |||
"custom": 0, | |||
"description": "Note is a free page where users can share documents / notes", | |||
"description": "", | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "Document", | |||
@@ -15,6 +15,7 @@ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "title", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
@@ -39,7 +40,8 @@ | |||
"allow_on_submit": 0, | |||
"bold": 1, | |||
"collapsible": 0, | |||
"description": "Everyone can read", | |||
"columns": 0, | |||
"description": "", | |||
"fieldname": "public", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
@@ -64,6 +66,61 @@ | |||
"allow_on_submit": 0, | |||
"bold": 1, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "public", | |||
"fieldname": "notify_on_login", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Notify users with a popup when they log in", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"depends_on": "eval:doc.notify_on_login && doc.public", | |||
"fieldname": "expire_notification_on", | |||
"fieldtype": "Date", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Expire Notification On", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 1, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 1, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Help: To link to another record in the system, use \"#Form/Note/[Note Name]\" as the Link URL. (don't use \"http://\")", | |||
"fieldname": "content", | |||
"fieldtype": "Text Editor", | |||
@@ -84,6 +141,59 @@ | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 1, | |||
"columns": 0, | |||
"fieldname": "seen_by_section", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Seen By", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "seen_by", | |||
"fieldtype": "Table", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Seen By Table", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Note Seen By", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
], | |||
"hide_heading": 0, | |||
@@ -97,7 +207,7 @@ | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-07-25 05:24:24.137761", | |||
"modified": "2016-08-30 00:28:57.094889", | |||
"modified_by": "Administrator", | |||
"module": "Desk", | |||
"name": "Note", | |||
@@ -11,10 +11,23 @@ class Note(Document): | |||
import re | |||
self.name = re.sub("[%'\"#*?`]", "", self.title.strip()) | |||
def validate(self): | |||
if self.notify_on_login and not self.expire_notification_on: | |||
# expire this notification in a week (default) | |||
self.expire_notification_on = frappe.utils.add_days(self.creation, 7) | |||
def before_print(self): | |||
self.print_heading = self.name | |||
self.sub_heading = "" | |||
@frappe.whitelist() | |||
def mark_as_seen(note): | |||
note = frappe.get_doc('Note', note) | |||
if frappe.session.user not in [d.user for d in note.seen_by]: | |||
note.append('seen_by', {'user': frappe.session.user}) | |||
note.save() | |||
def get_permission_query_conditions(user): | |||
if not user: user = frappe.session.user | |||
@@ -0,0 +1,64 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_import": 0, | |||
"allow_rename": 0, | |||
"beta": 0, | |||
"creation": "2016-08-29 05:29:16.726172", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "", | |||
"editable_grid": 1, | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "user", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"label": "User", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "User", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
], | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"in_dialog": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 1, | |||
"max_attachments": 0, | |||
"modified": "2016-08-29 06:02:41.531341", | |||
"modified_by": "Administrator", | |||
"module": "Desk", | |||
"name": "Note Seen By", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
"permissions": [], | |||
"quick_entry": 1, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_seen": 0 | |||
} |
@@ -0,0 +1,10 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe.model.document import Document | |||
class NoteSeenBy(Document): | |||
pass |
@@ -79,7 +79,8 @@ class FormMeta(Meta): | |||
def _add_code(self, path, fieldname): | |||
js = get_js(path) | |||
if js: | |||
self.set(fieldname, (self.get(fieldname) or "") + "\n\n" + js) | |||
self.set(fieldname, (self.get(fieldname) or "") | |||
+ "\n\n/* Adding {0} */\n\n".format(path) + js) | |||
def add_html_templates(self, path): | |||
if self.custom: | |||
@@ -103,7 +104,7 @@ class FormMeta(Meta): | |||
custom = frappe.db.get_value("Custom Script", {"dt": self.name, | |||
"script_type": "Client"}, "script") or "" | |||
self.set("__js", (self.get('__js') or '') + "\n\n" + custom) | |||
self.set("__js", (self.get('__js') or '') + "\n\n/* Appending Custom Script */\n\n" + custom) | |||
def add_search_fields(self): | |||
"""add search fields found in the doctypes indicated by link fields' options""" | |||
@@ -5,6 +5,10 @@ frappe.pages['backups'].on_page_load = function(wrapper) { | |||
single_column: true | |||
}); | |||
page.add_inner_button(__("Set Number of Backups"), function() { | |||
frappe.set_route('Form', 'System Settings'); | |||
}); | |||
frappe.breadcrumbs.add("Setup"); | |||
$(frappe.render_template("backups")).appendTo(page.body.addClass("no-border")); | |||
@@ -1,5 +1,6 @@ | |||
import os | |||
from frappe.utils import get_site_path | |||
import frappe | |||
from frappe.utils import get_site_path, cint | |||
from frappe.utils.data import convert_utc_to_user_timezone | |||
import datetime | |||
@@ -17,9 +18,41 @@ def get_context(context): | |||
path = get_site_path('private', 'backups') | |||
files = [x for x in os.listdir(path) if os.path.isfile(os.path.join(path, x))] | |||
backup_limit = get_scheduled_backup_limit() | |||
if len(files) > backup_limit: | |||
cleanup_old_backups(path, files, backup_limit) | |||
files = [('/backups/' + _file, | |||
get_time(os.path.join(path, _file)), | |||
get_size(os.path.join(path, _file))) for _file in files] | |||
files.sort(key=lambda x: x[1], reverse=True) | |||
return {"files": files} | |||
def get_scheduled_backup_limit(): | |||
backup_limit = frappe.db.get_singles_value('System Settings', 'backup_limit') | |||
return cint(backup_limit) | |||
def cleanup_old_backups(site_path, files, limit): | |||
backup_paths = [] | |||
for f in files: | |||
_path = os.path.abspath(os.path.join(site_path, f)) | |||
backup_paths.append(_path) | |||
backup_paths = sorted(backup_paths, key=os.path.getctime) | |||
files_to_delete = len(backup_paths) - limit | |||
for idx in range(0, files_to_delete): | |||
f = os.path.basename(backup_paths[idx]) | |||
files.remove(f) | |||
os.remove(backup_paths[idx]) | |||
def delete_downloadable_backups(): | |||
path = get_site_path('private', 'backups') | |||
files = [x for x in os.listdir(path) if os.path.isfile(os.path.join(path, x))] | |||
backup_limit = get_scheduled_backup_limit() | |||
if len(files) > backup_limit: | |||
cleanup_old_backups(path, files, backup_limit) |