diff --git a/core/doctype/custom_script/custom_script.js b/core/doctype/custom_script/custom_script.js
deleted file mode 100644
index 8e4fc8d6e5..0000000000
--- a/core/doctype/custom_script/custom_script.js
+++ /dev/null
@@ -1,10 +0,0 @@
-cur_frm.cscript.refresh = function(doc, dt, dn) {
- if (doc.script_type == 'Server' && user!="Administrator") {
- cur_frm.set_df_property('script', 'read_only', 1);
- cur_frm.set_df_property('dt', 'read_only', 1);
- }
-
- if(user=="Administrator") {
- cur_frm.set_df_property('script_type', 'read_only', 0);
- }
-}
\ No newline at end of file
diff --git a/core/doctype/custom_script/custom_script.py b/core/doctype/custom_script/custom_script.py
index 0a5cff3670..da44d8918a 100644
--- a/core/doctype/custom_script/custom_script.py
+++ b/core/doctype/custom_script/custom_script.py
@@ -61,8 +61,8 @@ class CustomDocType(DocType):
f.write(custom_script)
def get_custom_server_script_path(doctype, plugin=None):
- from webnotes.modules import scrub
- from webnotes.utils import get_site_base_path, get_site_path
+ from webnotes.modules import scrub, get_plugin_path
+ from webnotes.utils import get_site_base_path
import os
# check if doctype exists
@@ -75,7 +75,7 @@ def get_custom_server_script_path(doctype, plugin=None):
plugin = doctype_plugin or os.path.basename(get_site_base_path())
# site_abs_path/plugin_name/module_name/doctype/doctype_name/doctype_name.py
- path = get_site_path(webnotes.conf.get("plugins_path"), scrub(plugin),
- scrub(module), "doctype", scrub(doctype), scrub(doctype) + ".py")
+ path = os.path.join(get_plugin_path(scrub(plugin)), scrub(module),
+ "doctype", scrub(doctype), scrub(doctype) + ".py")
return path
diff --git a/core/doctype/custom_script/custom_script.txt b/core/doctype/custom_script/custom_script.txt
index deacf0d9ad..5fc50d474e 100644
--- a/core/doctype/custom_script/custom_script.txt
+++ b/core/doctype/custom_script/custom_script.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-01-10 16:34:01",
"docstatus": 0,
- "modified": "2013-10-14 15:50:29",
+ "modified": "2013-10-16 16:56:41",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -23,14 +23,18 @@
"permlevel": 0
},
{
+ "cancel": 1,
+ "create": 1,
"doctype": "DocPerm",
"name": "__common__",
"parent": "Custom Script",
"parentfield": "permissions",
"parenttype": "DocType",
+ "permlevel": 0,
"read": 1,
"report": 1,
- "submit": 0
+ "submit": 0,
+ "write": 1
},
{
"doctype": "DocType",
@@ -50,6 +54,7 @@
"doctype": "DocField",
"fieldname": "script_type",
"fieldtype": "Select",
+ "hidden": 1,
"label": "Script Type",
"oldfieldname": "script_type",
"oldfieldtype": "Select",
@@ -66,19 +71,11 @@
"options": "Script"
},
{
- "cancel": 1,
- "create": 1,
"doctype": "DocPerm",
- "permlevel": 0,
- "role": "System Manager",
- "write": 1
+ "role": "System Manager"
},
{
- "cancel": 1,
- "create": 1,
"doctype": "DocPerm",
- "permlevel": 0,
- "role": "Administrator",
- "write": 1
+ "role": "Administrator"
}
]
\ No newline at end of file
diff --git a/core/doctype/file_data/file_data.py b/core/doctype/file_data/file_data.py
index 92e1991f30..37ada879e2 100644
--- a/core/doctype/file_data/file_data.py
+++ b/core/doctype/file_data/file_data.py
@@ -15,6 +15,9 @@ class DocType():
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
+ def before_insert(self):
+ webnotes.local.rollback_observers.append(self)
+
def on_update(self):
# check duplicate assignement
n_records = webnotes.conn.sql("""select count(*) from `tabFile Data`
@@ -27,12 +30,6 @@ class DocType():
raise webnotes.DuplicateEntryError
def on_trash(self):
- if self.doc.file_name and webnotes.conn.sql("""select count(*) from `tabFile Data`
- where file_name=%s""", self.doc.file_name)[0][0]==1:
- path = webnotes.utils.get_site_path(conf.files_path, self.doc.file_name)
- if os.path.exists(path):
- os.remove(path)
-
if self.doc.attached_to_name:
# check persmission
try:
@@ -41,4 +38,14 @@ class DocType():
webnotes.msgprint(webnotes._("No permission to write / remove."),
raise_exception=True)
except webnotes.DoesNotExistError:
- pass
\ No newline at end of file
+ pass
+
+ # if file not attached to any other record, delete it
+ if self.doc.file_name and webnotes.conn.sql("""select count(*) from `tabFile Data`
+ where file_name=%s and name!=%s""", (self.doc.file_name, self.doc.name)):
+ path = webnotes.utils.get_site_path(conf.files_path, self.doc.file_name)
+ if os.path.exists(path):
+ os.remove(path)
+
+ def on_rollback(self):
+ self.on_trash()
\ No newline at end of file
diff --git a/core/doctype/profile/profile.py b/core/doctype/profile/profile.py
index 27c982ec46..b2360b0acf 100644
--- a/core/doctype/profile/profile.py
+++ b/core/doctype/profile/profile.py
@@ -28,7 +28,6 @@ class DocType:
self.add_system_manager_role()
self.check_enable_disable()
if self.in_insert:
- self.autoname()
if self.doc.name not in ("Guest", "Administrator"):
self.send_welcome_mail()
webnotes.msgprint(_("Welcome Email Sent"))
@@ -392,3 +391,22 @@ def profile_query(doctype, txt, searchfield, start, page_len, filters):
name asc
limit %(start)s, %(page_len)s""" % {'key': searchfield, 'txt': "%%%s%%" % txt,
'mcond':get_match_cond(doctype, searchfield), 'start': start, 'page_len': page_len})
+
+def get_total_users():
+ total_users = webnotes.conn.sql("""select count(*) from `tabProfile`
+ where ifnull(enabled, 0) = 1
+ and docstatus < 2
+ and name not in ('Administrator', 'Guest')""")
+ if total_users:
+ return total_users[0][0]
+ return 0
+
+def get_active_users():
+ active_users = webnotes.conn.sql("""select count(*) from `tabProfile`
+ where ifnull(enabled, 0) = 1
+ and docstatus < 2
+ and name not in ('Administrator', 'Guest')
+ and hour(timediff(now(), last_login)) < 72""")
+ if active_users:
+ return active_users[0][0]
+ return 0
diff --git a/public/build.json b/public/build.json
index b76fc47555..36c2d44888 100644
--- a/public/build.json
+++ b/public/build.json
@@ -13,10 +13,18 @@
"lib/public/js/lib/bootstrap.min.js",
"lib/public/js/wn/misc/number_format.js",
"lib/public/js/lib/nprogress.js",
- "lib/public/js/wn/class.js",
"lib/website/js/website.js"
]
},
+
+ {
+ "public/js/editor.min.js": [
+ "lib/public/js/lib/jquery/jquery.hotkeys.js",
+ "lib/public/js/wn/class.js",
+ "lib/public/js/lib/beautify-html.js",
+ "lib/public/js/wn/ui/editor.js",
+ ]
+ },
{
"public/css/all-app.css": [
@@ -43,6 +51,7 @@
"lib/public/js/lib/center_image.js",
"lib/public/js/lib/bootstrap.min.js",
"lib/public/js/lib/nprogress.js",
+ "lib/public/js/lib/beautify-html.js",
"lib/public/js/wn/provide.js",
"lib/public/js/wn/class.js",
@@ -115,6 +124,7 @@
"lib/public/js/wn/ui/toolbar/recent.js",
"lib/public/js/wn/ui/toolbar/bookmarks.js",
"lib/public/js/wn/ui/toolbar/toolbar.js",
+ "lib/public/js/wn/ui/editor.js",
"lib/public/js/legacy/form.js",
"lib/public/js/legacy/print_format.js",
diff --git a/public/css/common.css b/public/css/common.css
index a0c49d1e3c..03112a9f5c 100644
--- a/public/css/common.css
+++ b/public/css/common.css
@@ -395,26 +395,11 @@ div#freeze {
font-size: 32px;
color: #888;
}
+/* form */
-.wysiwyg-editor {
- height: 400px;
- background-color: white;
- border-collapse: separate;
- border: 1px solid rgb(204, 204, 204);
- padding: 4px;
- box-sizing: content-box;
- -webkit-box-shadow: rgba(0, 0, 0, 0.0745098) 0px 1px 1px 0px inset;
- box-shadow: rgba(0, 0, 0, 0.0745098) 0px 1px 1px 0px inset;
- border-top-right-radius: 3px; border-bottom-right-radius: 3px;
- border-bottom-left-radius: 3px; border-top-left-radius: 3px;
- overflow: scroll;
- outline: none;
-}
-
-.wysiwyg-editor img {
+.wn-editor img {
max-width: 100%;
}
-/* form */
textarea[data-fieldtype="Small Text"] {
height: 60px;
diff --git a/public/js/lib/bootstrap-wysiwyg.js b/public/js/lib/bootstrap-wysiwyg.js
deleted file mode 100644
index 5bc4134155..0000000000
--- a/public/js/lib/bootstrap-wysiwyg.js
+++ /dev/null
@@ -1,193 +0,0 @@
-/* http://github.com/mindmup/bootstrap-wysiwyg */
-/*global jQuery, $, FileReader*/
-/*jslint browser:true*/
-jQuery(function ($) {
- 'use strict';
- var readFileIntoDataUrl = function (fileInfo) {
- var loader = $.Deferred(),
- fReader = new FileReader();
-
- wn.upload.upload_file(fileInfo, {
- from_form: 1,
- doctype: cur_frm.doctype,
- docname: cur_frm.docname
- }, function(fileid, filename, r) {
- if(!r.exc) {
- if(fileid)
- cur_frm.attachments.update_attachment(fileid, filename);
- loader.resolve(filename);
- }
- });
- return loader.promise();
- };
- $.fn.cleanHtml = function () {
- var html = $(this).html();
- html = html && html.replace(/(
|\s|
<\/div>| )*$/, '');
-
- // remove custom typography (use CSS!)
- html = html && html.replace(/(font-family|font-size|line-height):[^;]*;/g, '');
- html = html && html.replace(/<[^>]*(font=['"][^'"]*['"])>/g, function(a,b) { return a.replace(b, ''); });
- html = html && html.replace(/\s*style\s*=\s*["']\s*["']/g, '');
- return html;
- };
- $.fn.wysiwyg = function (userOptions) {
- var editor = this,
- selectedRange,
- defaultOptions = {
- hotKeys: {
- 'ctrl+b meta+b': 'bold',
- 'ctrl+i meta+i': 'italic',
- 'ctrl+u meta+u': 'underline',
- 'ctrl+z meta+z': 'undo',
- 'ctrl+y meta+y meta+shift+z': 'redo',
- 'ctrl+l meta+l': 'justifyleft',
- 'ctrl+e meta+e': 'justifycenter',
- 'ctrl+j meta+j': 'justifyfull',
- 'shift+tab': 'outdent',
- 'tab': 'indent'
- },
- toolbarSelector: '[data-role=editor-toolbar]',
- commandRole: 'edit',
- activeToolbarClass: 'btn-info',
- selectionMarker: 'edit-focus-marker',
- selectionColor: 'darkgrey'
- },
- options,
- updateToolbar = function () {
- if (options.activeToolbarClass) {
- $(options.toolbarSelector).find('.btn[data-' + options.commandRole + ']').each(function () {
- var command = $(this).data(options.commandRole);
- if (document.queryCommandState(command)) {
- $(this).addClass(options.activeToolbarClass);
- } else {
- $(this).removeClass(options.activeToolbarClass);
- }
- });
- }
- },
- execCommand = function (commandWithArgs, valueArg) {
- var commandArr = commandWithArgs.split(' '),
- command = commandArr.shift(),
- args = commandArr.join(' ') + (valueArg || '');
- document.execCommand(command, 0, args);
- updateToolbar();
- },
- bindHotkeys = function (hotKeys) {
- $.each(hotKeys, function (hotkey, command) {
- editor.keydown(hotkey, function (e) {
- if (editor.attr('contenteditable') && editor.is(':visible')) {
- e.preventDefault();
- e.stopPropagation();
- execCommand(command);
- }
- }).keyup(hotkey, function (e) {
- if (editor.attr('contenteditable') && editor.is(':visible')) {
- e.preventDefault();
- e.stopPropagation();
- }
- });
- });
- },
- getCurrentRange = function () {
- var sel = window.getSelection();
- if (sel.getRangeAt && sel.rangeCount) {
- return sel.getRangeAt(0);
- }
- },
- saveSelection = function () {
- selectedRange = getCurrentRange();
- },
- restoreSelection = function () {
- var selection = window.getSelection();
- if (selectedRange) {
- selection.removeAllRanges();
- selection.addRange(selectedRange);
- }
- },
- insertFiles = function (files) {
- editor.focus();
- $.each(files, function (idx, fileInfo) {
- if (/^image\//.test(fileInfo.type)) {
- $.when(readFileIntoDataUrl(fileInfo)).done(function (dataUrl) {
- execCommand('insertimage', dataUrl);
- });
- }
- });
- },
- markSelection = function (input, color) {
- restoreSelection();
- document.execCommand('hiliteColor', 0, color || 'transparent');
- saveSelection();
- input.data(options.selectionMarker, color);
- },
- bindToolbar = function (toolbar, options) {
- toolbar.find('a[data-' + options.commandRole + ']').click(function () {
- restoreSelection();
- editor.focus();
- execCommand($(this).data(options.commandRole));
- saveSelection();
- });
- toolbar.find('[data-toggle=dropdown]').click(restoreSelection);
-
- toolbar.find('input[type=text][data-' + options.commandRole + ']').on('webkitspeechchange change', function () {
- var newValue = this.value; /* ugly but prevents fake double-calls due to selection restoration */
- this.value = '';
- restoreSelection();
- if (newValue) {
- editor.focus();
- execCommand($(this).data(options.commandRole), newValue);
- }
- saveSelection();
- }).on('focus', function () {
- var input = $(this);
- if (!input.data(options.selectionMarker)) {
- markSelection(input, options.selectionColor);
- input.focus();
- }
- }).on('blur', function () {
- var input = $(this);
- if (input.data(options.selectionMarker)) {
- markSelection(input, false);
- }
- });
- toolbar.find('input[type=file][data-' + options.commandRole + ']').change(function () {
- restoreSelection();
- if (this.type === 'file' && this.files && this.files.length > 0) {
- insertFiles(this.files);
- }
- saveSelection();
- this.value = '';
- });
- },
- initFileDrops = function () {
- editor.on('dragenter dragover', false)
- .on('drop', function (e) {
- var dataTransfer = e.originalEvent.dataTransfer;
- e.stopPropagation();
- e.preventDefault();
- if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
- insertFiles(dataTransfer.files);
- }
- });
- };
- options = $.extend({}, defaultOptions, userOptions);
- bindHotkeys(options.hotKeys);
- initFileDrops();
- bindToolbar($(options.toolbarSelector), options);
- editor.attr('contenteditable', true)
- .on('mouseup keyup mouseout', function () {
- saveSelection();
- updateToolbar();
- });
- $(window).bind('touchend', function (e) {
- var isInside = (editor.is(e.target) || editor.has(e.target).length > 0),
- currentRange = getCurrentRange(),
- clear = currentRange && (currentRange.startContainer === currentRange.endContainer && currentRange.startOffset === currentRange.endOffset);
- if (!clear || isInside) {
- saveSelection();
- updateToolbar();
- }
- });
- return this;
- };
-});
diff --git a/public/js/wn/class.js b/public/js/wn/class.js
index 94a73b2d83..afe20613f1 100644
--- a/public/js/wn/class.js
+++ b/public/js/wn/class.js
@@ -64,9 +64,9 @@ To subclass, use:
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
+ this._type = "instance";
if ( !initializing && this.init )
this.init.apply(this, arguments);
- this._type = "instance";
}
// Populate our constructed prototype object
diff --git a/public/js/wn/dom.js b/public/js/wn/dom.js
index 6f0c6f1b44..479c75082a 100644
--- a/public/js/wn/dom.js
+++ b/public/js/wn/dom.js
@@ -105,6 +105,24 @@ wn.dom = {
}
}
+wn.get_modal = function(title, body_html) {
+ var modal = $('
\
+
\
+
\
+ \
+
'+body_html+'\
+
\
+
\
+
\
+
').appendTo(document.body);
+
+ return modal;
+};
+
var pending_req = 0
wn.set_loading = function() {
pending_req++;
diff --git a/public/js/wn/form/control.js b/public/js/wn/form/control.js
index 5991af24e5..9cdac3fc2e 100644
--- a/public/js/wn/form/control.js
+++ b/public/js/wn/form/control.js
@@ -853,11 +853,11 @@ wn.ui.form.ControlLink = wn.ui.form.ControlData.extend({
});
wn.ui.form.ControlCode = wn.ui.form.ControlInput.extend({
- editor_name: "ACE",
+ editor_name: "wn.editors.ACE",
make_input: function() {
$(this.input_area).css({"min-height":"360px"});
var me = this;
- this.editor = new wn.editors[this.editor_name]({
+ this.editor = new (wn.provide(this.editor_name))({
parent: this.input_area,
change: function(value) {
me.parse_validate_and_set_in_model(value);
@@ -865,12 +865,6 @@ wn.ui.form.ControlCode = wn.ui.form.ControlInput.extend({
field: this
});
this.has_input = true;
-
- if(this.editor.$editor) {
- this.editor.$editor.keypress("ctrl+s meta+s", function() {
- me.frm.save_or_update();
- });
- }
},
get_value: function() {
return this.editor.get_value();
@@ -882,7 +876,13 @@ wn.ui.form.ControlCode = wn.ui.form.ControlInput.extend({
});
wn.ui.form.ControlTextEditor = wn.ui.form.ControlCode.extend({
- editor_name: "BootstrapWYSIWYG"
+ editor_name: "bsEditor",
+ make_input: function() {
+ this._super();
+ this.editor.editor.keypress("ctrl+s meta+s", function() {
+ me.frm.save_or_update();
+ });
+ },
});
wn.ui.form.ControlTable = wn.ui.form.Control.extend({
diff --git a/public/js/wn/form/editors.js b/public/js/wn/form/editors.js
index d46813f9f3..ee4396bb07 100644
--- a/public/js/wn/form/editors.js
+++ b/public/js/wn/form/editors.js
@@ -12,187 +12,6 @@
wn.provide("wn.editors");
-wn.editors.BootstrapWYSIWYG = Class.extend({
- init: function(opts) {
- wn.require("lib/js/lib/bootstrap-wysiwyg.js");
- this.opts = opts;
- this.make_body();
- this.make_bindings();
- },
- make_body: function() {
- var me = this;
- this.myid = "editor-" + wn.dom.set_unique_id();
- $('
\
-
\
- \
-
\
-
').appendTo(this.opts.parent);
- this.$parent = $(this.opts.parent);
- this.$editor = $("#" + this.myid);
- this.$parent.find(".btn-add-link").click(function() {
- me.show_link_dialog();
- return false;
- })
- this.$editor.on("keyup", function() { me.save_selection() });
- this.$editor.on("mouseup", function() { me.save_selection() });
- this.$textarea = this.$parent.find(".html-editor");
- this.input = this.$editor.get(0);
- },
- set_focus: function() {
- this.$editor.focus();
- },
- save_selection: function() {
- this.saved_selection = wn.dom.save_selection();
- },
- show_link_dialog: function() {
- var me = this;
- var d = new wn.ui.Dialog({
- title: "Add Link",
- fields: [
- {fieldtype: "Data", label:"Link", fieldname: "link", reqd: 1,
- description:"example: http://example.com"},
- {fieldtype: "Button", label:"Add", fieldname: "add"},
- ]
- });
- d.show();
- d.fields_dict.link.set_input("http://");
- $(d.fields_dict.add.input).click(function() {
- var values = d.get_values();
- if(values) {
- d.hide();
- wn.dom.restore_selection(me.saved_selection);
- document.execCommand("CreateLink", false, values.link);
- }
- });
- d.onhide = function() {
- wn.dom.restore_selection(me.saved_selection);
- }
- },
- make_bindings: function() {
- var me = this;
- var fonts = ['Serif', 'Sans', 'Arial', 'Arial Black', 'Courier',
- 'Courier New', 'Comic Sans MS', 'Helvetica', 'Impact', 'Lucida Grande',
- 'Lucida Sans', 'Tahoma', 'Times', 'Times New Roman', 'Verdana'],
- fontTarget = this.$parent.find('[title=Font]').siblings('.dropdown-menu');
-
- $.each(fonts, function (idx, fontName) {
- fontTarget.append($('
'+
- fontName + ''));
- });
-
- // magic-overlay
- this.$parent.find('[data-role=magic-overlay]').each(function () {
- var overlay = $(this), target = $(overlay.data('target'));
- overlay.css('opacity', 0).css('position', 'absolute')
- //.offset(target.offset())
- .css("left", 157) // use this because in dialogs, can't find the offset
- .width(38).height(33);
- });
-
- this.$editor
- .wysiwyg()
- .on("mouseup keyup mouseout", function() {
- var value = $(this).html();
- if(value==null) value="";
- me.opts.change(value);
- })
- this.$textarea
- .on("change", function() {
- var value = $(this).val();
- if(value==null) value="";
- me.opts.change(value);
- });
-
- this.current_editor = this.$editor;
- this.$parent.find(".btn-html").click(function() {
- if($(this).prop("disabled")==true) return;
- wn.require("lib/js/lib/beautify-html.js");
- me.$textarea.val(html_beautify(me.$editor.cleanHtml()));
- me.$parent.find(".for-rich-text").toggle(false);
- me.$parent.find(".for-html").toggle(true);
- me.$parent.find(".btn-html").attr("disabled", "disabled");
- me.$parent.find(".btn-rich-text").attr("disabled", false);
- me.current_editor = me.$textarea;
- });
-
- this.$parent.find(".btn-rich-text").click(function() {
- if($(this).prop("disabled")==true) return;
- me.$editor.html(me.$textarea.val());
- me.$parent.find(".for-rich-text").toggle(true);
- me.$parent.find(".for-html").toggle(false);
-
- me.$parent.find(".btn-rich-text").attr("disabled", "disabled");
- me.$parent.find(".btn-html").attr("disabled", false);
- me.current_editor = me.$editor;
- });
-
- },
- set_input: function(value) {
- if(this.opts.field.inside_change_event)
- return;
-
- if(this.value!=value) {
- this.value = value==null ? "" : value;
- this.$editor.html(this.value);
- this.$textarea.val(this.value);
- }
- },
- get_value: function() {
- if(this.current_editor==this.$editor)
- return this.$editor.cleanHtml();
- else
- return this.$textarea.val();
- }
-})
-
-
wn.editors.ACE = Class.extend({
init: function(opts) {
this.opts = opts;
@@ -258,7 +77,4 @@ wn.editors.ACE = Class.extend({
});
}
},
- set_focus: function() {
- this.$editor.focus();
- },
})
\ No newline at end of file
diff --git a/public/js/wn/misc/tools.js b/public/js/wn/misc/tools.js
index 75bd3e969a..7e542efd38 100644
--- a/public/js/wn/misc/tools.js
+++ b/public/js/wn/misc/tools.js
@@ -15,7 +15,7 @@ wn.tools.downloadify = function(data, roles, me) {
// save file > abt 200 kb using server call
if((_get_data().length > 200000) || flash_disabled) {
- open_url_post("server.py?cmd=webnotes.utils.datautils.send_csv_to_client",
+ open_url_post("/?cmd=webnotes.utils.datautils.send_csv_to_client",
{args: {data: data, filename: me.title}}, true);
} else {
wn.require("lib/js/lib/downloadify/downloadify.min.js");
diff --git a/public/js/wn/request.js b/public/js/wn/request.js
index 54710290b0..198dd49c09 100644
--- a/public/js/wn/request.js
+++ b/public/js/wn/request.js
@@ -4,7 +4,7 @@
// My HTTP Request
wn.provide('wn.request');
-wn.request.url = 'server.py';
+wn.request.url = '/';
// generic server call (call page, object)
wn.call = function(opts) {
diff --git a/public/js/wn/ui/dialog.js b/public/js/wn/ui/dialog.js
index bae73db818..ca12a51472 100644
--- a/public/js/wn/ui/dialog.js
+++ b/public/js/wn/ui/dialog.js
@@ -28,21 +28,7 @@ wn.ui.Dialog = wn.ui.FieldGroup.extend({
this.make();
},
make: function() {
- // ui-front class is used as appendTo by jquery.autocomplete
- this.$wrapper = $('
')
- .appendTo(document.body);
+ this.$wrapper = wn.get_modal("", "");
this.wrapper = this.$wrapper.find('.modal-dialog').get(0);
this.make_head();
this.body = this.$wrapper.find(".modal-body").get(0);
diff --git a/public/js/wn/ui/editor.js b/public/js/wn/ui/editor.js
index 17b8f44d58..869e1c52e9 100644
--- a/public/js/wn/ui/editor.js
+++ b/public/js/wn/ui/editor.js
@@ -4,52 +4,68 @@
/* Inspired from: http://github.com/mindmup/bootstrap-wysiwyg */
// todo
-// html editing
-// image
-// links
-// onsave, oncancel
+// make it inline friendly
-wn.provide("wn.ui");
-wn.ui.Editor = Class.extend({
- init: function(editor, options) {
+bsEditor = Class.extend({
+ init: function(options) {
+ this.options = $.extend(options || {}, this.default_options);
+ if(this.options.editor) {
+ this.setup_editor(this.options.editor);
+ this.setup_fixed_toolbar();
+ } else if(this.options.parent) {
+ this.wrapper = $("
").appendTo(this.options.parent);
+ this.setup_editor($("
").appendTo(this.wrapper));
+ this.setup_inline_toolbar();
+ this.editor.css(this.options.inline_editor_style);
+ this.set_editing();
+ }
+ },
+ setup_editor: function(editor) {
var me = this;
this.editor = $(editor);
- this.options = $.extend(options || {}, this.default_options);
- this.files = [];
-
this.editor.on("click", function() {
- if(!this.editing) {
- me.make();
- me.editor.attr('contenteditable', true);
- me.original_html = me.editor.html();
- wn._editor_toolbar.show();
- wn._current_editor = me.editor.focus();
- me.editing = true;
+ if(!me.editing) {
+ me.set_editing();
}
}).on("mouseup keyup mouseout", function() {
if(me.editing) {
- wn._editor_toolbar.saveSelection();
- wn._editor_toolbar.update();
+ me.toolbar.save_selection();
+ me.toolbar.update();
+ me.options.change && me.options.change(me.clean_html());
}
- }).on("blur", function() {
- if(wn._editor_toolbar.clicked.parents(".wn-editor-toolbar").length)
- return;
- wn._editor_toolbar.toolbar.find("[data-action='Save']").trigger("click");
}).data("object", this);
this.bind_hotkeys();
this.init_file_drops();
+
},
- make: function() {
- if(!wn._editor_toolbar) {
- wn._editor_toolbar = new wn.ui.EditorToolbar(this.options)
+
+ set_editing: function() {
+ this.editor.attr('contenteditable', true);
+ this.original_html = this.editor.html();
+ this.toolbar.show();
+ this.toolbar.editor = this.editor.focus();
+ this.editing = true;
+ },
+
+ setup_fixed_toolbar: function() {
+ if(!window.bs_editor_toolbar) {
+ window.bs_editor_toolbar = new bsEditorToolbar(this.options)
}
+ this.toolbar = window.bs_editor_toolbar;
+ },
+ setup_inline_toolbar: function() {
+ this.toolbar = new bsEditorToolbar(this.options, this.wrapper);
},
onhide: function(action) {
this.editing = false;
if(action==="Cancel") {
this.editor.html(this.original_html);
- }
+ this.options.oncancel && this.options.oncancel(this);
+ } else {
+ this.options.onsave && this.options.onsave(this);
+ this.options.change && this.options.change(this.get_value());
+ }
},
default_options: {
hotKeys: {
@@ -64,17 +80,28 @@ wn.ui.Editor = Class.extend({
'shift+tab': 'outdent',
'tab': 'indent'
},
- toolbarSelector: '[data-role=editor-toolbar]',
- commandRole: 'edit',
- activeToolbarClass: 'btn-info',
- selectionMarker: 'edit-focus-marker',
- selectionColor: 'darkgrey',
+ inline_editor_style: {
+ "height": "400px",
+ "background-color": "white",
+ "border-collapse": "separate",
+ "border": "1px solid rgb(204, 204, 204)",
+ "padding": "4px",
+ "box-sizing": "content-box",
+ "-webkit-box-shadow": "rgba(0, 0, 0, 0.0745098) 0px 1px 1px 0px inset",
+ "box-shadow": "rgba(0, 0, 0, 0.0745098) 0px 1px 1px 0px inset",
+ "border-radius": "3px",
+ "overflow": "scroll",
+ "outline": "none"
+ },
+ toolbar_selector: '[data-role=editor-toolbar]',
+ command_role: 'edit',
+ active_toolbar_class: 'btn-info',
+ selection_marker: 'edit-focus-marker',
+ selection_color: 'darkgrey',
remove_typography: true,
+ max_file_size: 1,
},
- show: function() {
- },
-
bind_hotkeys: function () {
var me = this;
$.each(this.options.hotKeys, function (hotkey, command) {
@@ -82,7 +109,7 @@ wn.ui.Editor = Class.extend({
if (me.editor.attr('contenteditable') && me.editor.is(':visible')) {
e.preventDefault();
e.stopPropagation();
- wn._editor_toolbar.execCommand(command);
+ me.toolbar.execCommand(command);
}
}).keyup(hotkey, function (e) {
if (me.editor.attr('contenteditable') && me.editor.is(':visible')) {
@@ -125,7 +152,7 @@ wn.ui.Editor = Class.extend({
$.each(files, function (i, file) {
if (/^image\//.test(file.type)) {
me.get_image(file, function(image_url) {
- wn._editor_toolbar.execCommand('insertimage', image_url);
+ me.toolbar.execCommand('insertimage', image_url);
})
}
});
@@ -137,52 +164,73 @@ wn.ui.Editor = Class.extend({
freader.onload = function() {
var dataurl = freader.result;
- me.files.push(dataurl);
+ // add filename to dataurl
+ var parts = dataurl.split(",");
+ parts[0] += ";filename=" + fileobj.name;
+ dataurl = parts[0] + ',' + parts[1];
+ if(me.options.max_file_size) {
+ if(dataurl.length > (me.options.max_file_size * 1024 * 1024 * 1.4)) {
+ bs_get_modal("Upload Error", "Max file size (" + me.options.max_file_size + "M) exceeded.").modal("show");
+ throw "file size exceeded";
+ }
+ }
callback(dataurl);
}
freader.readAsDataURL(fileobj);
+ },
+
+ get_value: function() {
+ return this.clean_html()
+ },
+
+ set_input: function(value) {
+ if(this.options.field && this.options.field.inside_change_event)
+ return;
+ this.editor.html(value==null ? "" : value);
}
})
-wn.ui.EditorToolbar = Class.extend({
- init: function(options) {
+bsEditorToolbar = Class.extend({
+ init: function(options, parent) {
this.options = options;
- this.options.toolbar_style = $.extend(this.options.toolbar_style || {}, this.style);
- this.make();
- this.toolbar = $(".wn-editor-toolbar").css(this.options.toolbar_style);
- this.overlay_image_button();
+ this.inline = !!parent;
+ this.options.toolbar_style = $.extend((this.inline ? this.inline_style : this.fixed_style),
+ this.options.toolbar_style || {});
+ this.make(parent);
+ this.toolbar.css(this.options.toolbar_style);
+ this.setup_image_button();
this.bind_events();
- this.bind_touch();
-
- var me = this;
- $(document).mousedown(function(e) {
- me.clicked = $(e.target);
- });
+ //this.bind_touch();
},
- style: {
+ fixed_style: {
position: "fixed",
top: "0px",
padding: "5px",
width: "100%",
height: "45px",
- "background-color": "#ddd",
- "z-index": "1001" // more than navbar
+ "background-color": "black",
+ display: "none"
},
- make: function() {
- if(!$(".wn-editor-toolbar").length) {
- $('
\
+ inline_style: {
+ padding: "5px",
+ },
+ make: function(parent) {
+ if(!parent)
+ parent = $("body");
+ if(!parent.find(".wn-editor-toolbar").length) {
+ this.toolbar = $('
').prependTo(parent);
+
+ if(this.inline) {
+ this.toolbar.find("[data-action]").remove();
+ } else {
+ this.toolbar.find(".btn-toolbar").addClass("container");
+ }
}
},
- overlay_image_button: function() {
+ setup_image_button: function() {
// magic-overlay
- this.toolbar.find('[data-role=magic-overlay]').each(function () {
- var overlay = $(this), target=overlay.prev();
- overlay.css('opacity', 0).css('position', 'absolute')
- .css("left", 155)
- .width(38).height(33);
- });
+ var me = this;
+ this.file_input = this.toolbar.find('input[type="file"]')
+ .css({
+ 'opacity':0,
+ 'position':'absolute',
+ 'left':0,
+ 'width':0,
+ 'height':0
+ });
+ this.toolbar.find(".btn-insert-img").on("click", function() {
+ me.file_input.trigger("click");
+ })
},
show: function() {
- $("body").animate({"padding-top": this.toolbar.outerHeight() });
+ var me = this;
this.toolbar.toggle(true);
+ if(!this.inline) {
+ $("body").animate({"padding-top": this.toolbar.outerHeight() }, {
+ complete: function() { me.toolbar.css("z-index", 1001); }
+ });
+ }
},
hide: function(action) {
- $("body").animate({"padding-top": 0 });
- this.toolbar.toggle(false);
- wn._current_editor.attr('contenteditable', false).data("object").onhide(action);
- wn._current_editor = null;
+ if(!this.editor)
+ return;
+ var me = this;
+ this.toolbar.css("z-index", 0);
+ if(!this.inline) {
+ $("body").animate({"padding-top": 0 }, {complete: function() {
+ me.toolbar.toggle(false);
+ }});
+ }
+
+ this.editor && this.editor.attr('contenteditable', false).data("object").onhide(action);
+ this.editor = null;
},
bind_events: function () {
var me = this;
// standard button events
- this.toolbar.find('a[data-' + me.options.commandRole + ']').click(function () {
- me.restoreSelection();
- wn._current_editor.focus();
- me.execCommand($(this).data(me.options.commandRole));
- me.saveSelection();
+ this.toolbar.find('a[data-' + me.options.command_role + ']').click(function () {
+ me.restore_selection();
+ me.editor.focus();
+ me.execCommand($(this).data(me.options.command_role));
+ me.save_selection();
+ // close dropdown
+ me.toolbar.find('[data-toggle=dropdown]').dropdown("hide");
return false;
});
- this.toolbar.find('[data-toggle=dropdown]').click(function() { me.restoreSelection() });
+ this.toolbar.find('[data-toggle=dropdown]').click(function() { me.restore_selection() });
// link
- this.toolbar.find('input[type=text][data-' + this.options.commandRole + ']')
- .on('webkitspeechchange change', function () {
- var newValue = this.value; /* ugly but prevents fake double-calls due to selection restoration */
- this.value = '';
- me.restoreSelection();
- if (newValue) {
- wn._current_editor.focus();
- me.execCommand($(this).data(me.options.commandRole), newValue);
+ this.toolbar.find(".btn-add-link").on("click", function() {
+ if(!window.bs_link_editor) {
+ window.bs_link_editor = new bsLinkEditor(me);
}
- me.saveSelection();
- return false;
- }).on('focus', function () {
- var input = $(this);
- if (!input.data(me.options.selectionMarker)) {
- me.markSelection(input, me.options.selectionColor);
- input.focus();
- }
- }).on('blur', function () {
- var input = $(this);
- if (input.data(me.options.selectionMarker)) {
- me.markSelection(input, false);
- }
- });
+ window.bs_link_editor.show();
+ })
// file event
- this.toolbar.find('input[type=file][data-' + me.options.commandRole + ']').change(function () {
- me.restoreSelection();
+ this.toolbar.find('input[type=file][data-' + me.options.command_role + ']').change(function () {
+ me.restore_selection();
if (this.type === 'file' && this.files && this.files.length > 0) {
- wn._current_editor.data("object").insert_files(this.files);
+ me.editor.data("object").insert_files(this.files);
}
- me.saveSelection();
+ me.save_selection();
this.value = '';
return false;
});
- // cancel
+ // save
this.toolbar.find("[data-action='Save']").on("click", function() {
me.hide("Save");
})
+ // cancel
this.toolbar.find("[data-action='Cancel']").on("click", function() {
me.hide("Cancel");
})
+
+ // edit html
+ this.toolbar.find(".btn-html").on("click", function() {
+ if(!window.bs_html_editor)
+ window.bs_html_editor = new bsHTMLEditor();
+
+ window.bs_html_editor.show(me.editor);
+ })
},
update: function () {
var me = this;
- if (this.options.activeToolbarClass) {
- $(this.options.toolbarSelector).find('.btn[data-' + this.options.commandRole + ']').each(function () {
- var command = $(this).data(me.options.commandRole);
+ if (this.toolbar) {
+ $(this.toolbar).find('.btn[data-' + this.options.command_role + ']').each(function () {
+ var command = $(this).data(me.options.command_role);
if (document.queryCommandState(command)) {
- $(this).addClass(me.options.activeToolbarClass);
+ $(this).addClass(me.options.active_toolbar_class);
} else {
- $(this).removeClass(me.options.activeToolbarClass);
+ $(this).removeClass(me.options.active_toolbar_class);
}
});
}
@@ -331,42 +394,114 @@ wn.ui.EditorToolbar = Class.extend({
this.update();
},
- getCurrentRange: function () {
+ get_current_range: function () {
var sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
return sel.getRangeAt(0);
}
},
- saveSelection: function () {
- this.selectedRange = this.getCurrentRange();
+ save_selection: function () {
+ this.selected_range = this.get_current_range();
},
-
- restoreSelection: function () {
+
+ restore_selection: function () {
var selection = window.getSelection();
- if (this.selectedRange) {
+ if (this.selected_range) {
selection.removeAllRanges();
- selection.addRange(this.selectedRange);
+ selection.addRange(this.selected_range);
}
},
- markSelection: function (input, color) {
- this.restoreSelection();
+ mark_selection: function (input, color) {
+ this.restore_selection();
document.execCommand('hiliteColor', 0, color || 'transparent');
- this.saveSelection();
- input.data(this.options.selectionMarker, color);
+ this.save_selection();
+ input.data(this.options.selection_marker, color);
},
- bind_touch: function() {
+ // bind_touch: function() {
+ // var me = this;
+ // $(window).bind('touchend', function (e) {
+ // var isInside = (me.editor.is(e.target) || me.editor.has(e.target).length > 0),
+ // current_range = me.get_current_range(),
+ // clear = current_range && (current_range.startContainer === current_range.endContainer && current_range.startOffset === current_range.endOffset);
+ // if (!clear || isInside) {
+ // me.save_selection();
+ // me.update();
+ // }
+ // });
+ // }
+});
+
+bsHTMLEditor = Class.extend({
+ init: function() {
var me = this;
- $(window).bind('touchend', function (e) {
- var isInside = (wn._current_editor.is(e.target) || wn._current_editor.has(e.target).length > 0),
- currentRange = me.getCurrentRange(),
- clear = currentRange && (currentRange.startContainer === currentRange.endContainer && currentRange.startOffset === currentRange.endOffset);
- if (!clear || isInside) {
- me.saveSelection();
- me.update();
- }
+ this.modal = bs_get_modal("
Edit HTML", '
\
+
');
+ this.modal.addClass("wn-ignore-click");
+ this.modal.find(".btn-primary").on("click", function() {
+ var html = me.modal.find("textarea").val();
+ $.each(me.dataurls, function(key, val) {
+ html = html.replace(key, val);
+ })
+ me.editor.html();
+ me.modal.modal("hide");
});
- }
-})
\ No newline at end of file
+ },
+ show: function(editor) {
+ var me = this;
+ this.editor = editor;
+ this.modal.modal("show")
+ var html = me.editor.html();
+ // pack dataurls so that html display is faster
+ this.dataurls = {}
+ html = html.replace(/

Insert Link", '
\
+ \
+
\
+
\
+ \
+
\
+
');
+
+ this.modal.addClass("wn-ignore-click");
+ this.modal.find(".btn-primary").on("click", function() {
+ me.toolbar.restore_selection();
+ var url = me.modal.find("input[type=text]").val();
+ var selection = me.toolbar.selected_range.toString();
+ if(url) {
+ if(me.modal.find("input[type=checkbox]:checked").length) {
+ var html = "
" + selection + "";
+ document.execCommand("insertHTML", false, html);
+ } else {
+ document.execCommand("CreateLink", false, url);
+ }
+ }
+ me.modal.modal("hide");
+ return false;
+ });
+ },
+ show: function() {
+ this.modal.find("input[type=text]").val("");
+ this.modal.modal("show");
+ }
+});
+
+bs_get_modal = wn.get_modal;
diff --git a/public/js/wn/views/communication.js b/public/js/wn/views/communication.js
index c59304973e..b320017512 100644
--- a/public/js/wn/views/communication.js
+++ b/public/js/wn/views/communication.js
@@ -136,7 +136,6 @@ wn.views.CommunicationComposer = Class.extend({
make: function() {
var me = this;
this.dialog = new wn.ui.Dialog({
- width: 640,
title: wn._("Add Reply") + ": " + (this.subject || ""),
no_submit_on_enter: true,
fields: [
@@ -166,6 +165,9 @@ wn.views.CommunicationComposer = Class.extend({
fieldname:"select_attachments"}
]
});
+
+ this.dialog.$wrapper.find("[data-edit='outdent']").remove();
+
$(document).on("upload_complete", function(event, filename, fileurl) {
if(me.dialog.display) {
var wrapper = $(me.dialog.fields_dict.select_attachments.wrapper);
diff --git a/public/js/wn/website/editable.js b/public/js/wn/website/editable.js
new file mode 100644
index 0000000000..b2e23a2a18
--- /dev/null
+++ b/public/js/wn/website/editable.js
@@ -0,0 +1,23 @@
+wn.make_editable = function(editor, doctype, name, fieldname) {
+ wn.require("js/editor.min.js");
+ bseditor = new bsEditor({
+ editor: editor,
+ onsave: function(bseditor) {
+ wn.call({
+ type: "POST",
+ method: "webnotes.client.set_value",
+ args: {
+ doctype: doctype,
+ name: name,
+ fieldname: fieldname,
+ value: editor.html()
+ },
+ callback: function(r) {
+ wn.msgprint(r.exc ? "Error" : "Saved");
+ if(!r.exc)
+ editor.html(r.message[0][fieldname]);
+ }
+ });
+ }
+ });
+}
diff --git a/public/js/wn/website/web_page_editable.js b/public/js/wn/website/web_page_editable.js
deleted file mode 100644
index af9132e0a6..0000000000
--- a/public/js/wn/website/web_page_editable.js
+++ /dev/null
@@ -1,33 +0,0 @@
-$(function() {
- $('
').appendTo($("footer.container"))
- $(".editable-button").click(function() {
- if(window.editable) {
- $(".web-page-content").attr("contentEditable", false).removeClass("web-page-editable");
- window.editable = false;
- $(this).html("Edit");
- var html = $(".web-page-content").html() || "";
- html = html.replace(/(font-family|font-size|line-height):[^;]*;/g, '');
- html = html.replace(/<[^>]*(font=['"][^'"]*['"])>/g, function(a,b) { return a.replace(b, ''); });
- html = html.replace(/\s*style\s*=\s*["']\s*["']/g, '');
- $(".web-page-content").html(html);
-
- wn.call({
- type: "POST",
- method: "webnotes.client.set_value",
- args: {
- doctype:"Web Page",
- name: window.name,
- fieldname: "main_section",
- value: html
- },
- callback: function(r) {
- wn.msgprint(r.exc ? "Error" : "Saved");
- }
- });
- } else {
- $(".web-page-content").attr("contentEditable", true).addClass("web-page-editable").focus();
- $(this).html("Save");
- window.editable = true;
- }
- });
-})
diff --git a/webnotes/__init__.py b/webnotes/__init__.py
index 0f408f54f7..03d71940ee 100644
--- a/webnotes/__init__.py
+++ b/webnotes/__init__.py
@@ -89,6 +89,7 @@ def init(site=None):
local.conf = get_conf(site)
local.initialised = True
local.flags = _dict({})
+ local.rollback_observers = []
def destroy():
"""closes connection and releases werkzeug local"""
diff --git a/webnotes/auth.py b/webnotes/auth.py
index 906ad82124..3252de09b8 100644
--- a/webnotes/auth.py
+++ b/webnotes/auth.py
@@ -103,14 +103,17 @@ class LoginManager:
self.post_login()
info = webnotes.conn.get_value("Profile", self.user, ["user_type", "first_name", "last_name"], as_dict=1)
if info.user_type=="Website User":
+ webnotes._response.set_cookie("system_user", "no")
webnotes.response["message"] = "No App"
else:
+ webnotes._response.set_cookie("system_user", "yes")
webnotes.response['message'] = 'Logged In'
full_name = " ".join(filter(None, [info.first_name, info.last_name]))
webnotes.response["full_name"] = full_name
webnotes._response.set_cookie("full_name", full_name)
webnotes._response.set_cookie("user_id", self.user)
+
def post_login(self):
self.run_trigger()
diff --git a/webnotes/db.py b/webnotes/db.py
index 7792445267..b826746419 100644
--- a/webnotes/db.py
+++ b/webnotes/db.py
@@ -48,6 +48,7 @@ class Database:
use_unicode=True, charset='utf8')
self._conn.converter[246]=float
self._cursor = self._conn.cursor()
+ webnotes.local.rollback_observers = []
def use(self, db_name):
"""
@@ -152,7 +153,7 @@ class Database:
if self.transaction_writes and query and query.strip().split()[0].lower() in ['start', 'alter', 'drop', 'create', "begin"]:
raise Exception, 'This statement can cause implicit commit'
- if query and query.strip().lower()=='commit':
+ if query and query.strip().lower() in ('commit', 'rollback'):
self.transaction_writes = 0
if query[:6].lower() in ['update', 'insert']:
@@ -439,10 +440,14 @@ class Database:
def commit(self):
self.sql("commit")
+ webnotes.local.rollback_observers = []
def rollback(self):
- self.sql("ROLLBACK")
- self.transaction_writes = 0
+ self.sql("rollback")
+ for obj in webnotes.local.rollback_observers:
+ if hasattr(obj, "on_rollback"):
+ obj.on_rollback()
+ webnotes.local.rollback_observers = []
def field_exists(self, dt, fn):
return self.sql("select name from tabDocField where fieldname=%s and parent=%s", (dt, fn))
diff --git a/webnotes/model/bean.py b/webnotes/model/bean.py
index b4b6d58490..1b1cd4e5dc 100644
--- a/webnotes/model/bean.py
+++ b/webnotes/model/bean.py
@@ -40,7 +40,7 @@ class Bean:
elif isinstance(dt, dict):
self.set_doclist([dt])
- def load_from_db(self, dt=None, dn=None, prefix='tab'):
+ def load_from_db(self, dt=None, dn=None):
"""
Load doclist from dt
"""
@@ -49,7 +49,7 @@ class Bean:
if not dt: dt = self.doc.doctype
if not dn: dn = self.doc.name
- doc = Document(dt, dn, prefix=prefix)
+ doc = Document(dt, dn)
# get all children types
tablefields = webnotes.model.meta.get_table_fields(dt)
@@ -57,7 +57,7 @@ class Bean:
# load chilren
doclist = webnotes.doclist([doc,])
for t in tablefields:
- doclist += getchildren(doc.name, t[0], t[1], dt, prefix=prefix)
+ doclist += getchildren(doc.name, t[0], t[1], dt)
self.set_doclist(doclist)
@@ -191,6 +191,7 @@ class Bean:
self.check_if_latest(method)
if method != "cancel":
+ self.extract_images_from_text_editor()
self.check_links()
self.update_timestamps_and_docstatus()
@@ -238,45 +239,6 @@ class Bean:
self.make_controller()
return getattr(self.controller, method, None)
- def save_main(self):
- try:
- self.doc.save(check_links = False, ignore_fields = self.ignore_fields)
- except NameError, e:
- webnotes.msgprint('%s "%s" already exists' % (self.doc.doctype, self.doc.name))
-
- # prompt if cancelled
- if webnotes.conn.get_value(self.doc.doctype, self.doc.name, 'docstatus')==2:
- webnotes.msgprint('[%s "%s" has been cancelled]' % (self.doc.doctype, self.doc.name))
- webnotes.errprint(webnotes.utils.getTraceback())
- raise e
-
- def save_children(self):
- child_map = {}
- for d in self.doclist[1:]:
- if d.fields.get("parent") or d.fields.get("parentfield"):
- d.parent = self.doc.name # rename if reqd
- d.parenttype = self.doc.doctype
-
- d.save(check_links=False, ignore_fields = self.ignore_fields)
-
- child_map.setdefault(d.doctype, []).append(d.name)
-
- # delete all children in database that are not in the child_map
-
- # get all children types
- tablefields = webnotes.model.meta.get_table_fields(self.doc.doctype)
-
- for dt in tablefields:
- if dt[0] not in self.ignore_children_type:
- cnames = child_map.get(dt[0]) or []
- if cnames:
- webnotes.conn.sql("""delete from `tab%s` where parent=%s and parenttype=%s and
- name not in (%s)""" % (dt[0], '%s', '%s', ','.join(['%s'] * len(cnames))),
- tuple([self.doc.name, self.doc.doctype] + cnames))
- else:
- webnotes.conn.sql("""delete from `tab%s` where parent=%s and parenttype=%s""" \
- % (dt[0], '%s', '%s'), (self.doc.name, self.doc.doctype))
-
def insert(self):
self.doc.fields["__islocal"] = 1
@@ -324,6 +286,11 @@ class Bean:
if self.ignore_permissions or webnotes.has_permission(self.doc.doctype, perm_to_check, self.doc):
self.to_docstatus = 0
self.prepare_for_save("save")
+ if self.doc.fields.get("__islocal"):
+ # set name before validate
+ self.doc.set_new_name()
+ self.run_method('before_insert')
+
if not self.ignore_validate:
self.run_method('validate')
if not self.ignore_mandatory:
@@ -379,6 +346,45 @@ class Bean:
self.no_permission_to(_("Update"))
return self
+
+ def save_main(self):
+ try:
+ self.doc.save(check_links = False, ignore_fields = self.ignore_fields)
+ except NameError, e:
+ webnotes.msgprint('%s "%s" already exists' % (self.doc.doctype, self.doc.name))
+
+ # prompt if cancelled
+ if webnotes.conn.get_value(self.doc.doctype, self.doc.name, 'docstatus')==2:
+ webnotes.msgprint('[%s "%s" has been cancelled]' % (self.doc.doctype, self.doc.name))
+ webnotes.errprint(webnotes.utils.getTraceback())
+ raise e
+
+ def save_children(self):
+ child_map = {}
+ for d in self.doclist[1:]:
+ if d.fields.get("parent") or d.fields.get("parentfield"):
+ d.parent = self.doc.name # rename if reqd
+ d.parenttype = self.doc.doctype
+
+ d.save(check_links=False, ignore_fields = self.ignore_fields)
+
+ child_map.setdefault(d.doctype, []).append(d.name)
+
+ # delete all children in database that are not in the child_map
+
+ # get all children types
+ tablefields = webnotes.model.meta.get_table_fields(self.doc.doctype)
+
+ for dt in tablefields:
+ if dt[0] not in self.ignore_children_type:
+ cnames = child_map.get(dt[0]) or []
+ if cnames:
+ webnotes.conn.sql("""delete from `tab%s` where parent=%s and parenttype=%s and
+ name not in (%s)""" % (dt[0], '%s', '%s', ','.join(['%s'] * len(cnames))),
+ tuple([self.doc.name, self.doc.doctype] + cnames))
+ else:
+ webnotes.conn.sql("""delete from `tab%s` where parent=%s and parenttype=%s""" \
+ % (dt[0], '%s', '%s'), (self.doc.name, self.doc.doctype))
def delete(self):
webnotes.delete_doc(self.doc.doctype, self.doc.name)
@@ -426,6 +432,12 @@ class Bean:
doc.fields[df.fieldname] = flt(doc.fields.get(df.fieldname))
doc.docstatus = cint(doc.docstatus)
+
+ def extract_images_from_text_editor(self):
+ from webnotes.utils.file_manager import extract_images_from_html
+ if self.doc.doctype != "DocType":
+ for df in self.meta.get({"doctype": "DocField", "parent": self.doc.doctype, "fieldtype":"Text Editor"}):
+ extract_images_from_html(self.doc, df.fieldname)
def clone(source_wrapper):
""" make a clone of a document"""
diff --git a/webnotes/model/code.py b/webnotes/model/code.py
index d60d94791b..fd82fede7b 100644
--- a/webnotes/model/code.py
+++ b/webnotes/model/code.py
@@ -76,8 +76,12 @@ def load_doctype_module(doctype, module, prefix=""):
return None
def get_obj(dt = None, dn = None, doc=None, doclist=[], with_children = 0):
+ import webnotes.model.doc
if dt:
- import webnotes.model.doc
+ if isinstance(dt, list):
+ return get_server_obj(dt[0], dt)
+ if isinstance(dt, webnotes.model.doc.Document):
+ return get_server_obj(dt, [dt])
if not dn:
dn = dt
if with_children:
diff --git a/webnotes/model/doc.py b/webnotes/model/doc.py
index 02ddf4eaa5..15b9d59597 100755
--- a/webnotes/model/doc.py
+++ b/webnotes/model/doc.py
@@ -50,11 +50,12 @@ class Document:
* `idx` : Index (sequence) of the child record
"""
- def __init__(self, doctype = None, name = None, fielddata = None, prefix='tab'):
+ def __init__(self, doctype = None, name = None, fielddata = None):
self._roles = []
self._perms = []
self._user_defaults = {}
- self._prefix = prefix
+ self._new_name_set = False
+ self._meta = None
if isinstance(doctype, dict):
fielddata = doctype
@@ -130,7 +131,7 @@ class Document:
self._loadsingle()
else:
try:
- dataset = webnotes.conn.sql('select * from `%s%s` where name="%s"' % (self._prefix, self.doctype, self.name.replace('"', '\"')))
+ dataset = webnotes.conn.sql('select * from `tab%s` where name="%s"' % (self.doctype, self.name.replace('"', '\"')))
except MySQLdb.ProgrammingError, e:
if e.args[0]==1146:
dataset = None
@@ -179,6 +180,46 @@ class Document:
def get(self, name, value=None):
return self.fields.get(name, value)
+
+ def insert(self):
+ self.fields['__islocal'] = 1
+ self.save()
+ return self
+
+ def save(self, new=0, check_links=1, ignore_fields=0, make_autoname=1,
+ keep_timestamps=False):
+
+ self.get_meta()
+
+ if new:
+ self.fields["__islocal"] = 1
+
+ # add missing parentinfo (if reqd)
+ if self.parent and not (self.parenttype and self.parentfield):
+ self.update_parentinfo()
+
+ if self.parent and not self.idx:
+ self.set_idx()
+
+ # if required, make new
+ if not self._meta.issingle:
+ if self.fields.get('__islocal'):
+ r = self._insert(make_autoname=make_autoname, keep_timestamps = keep_timestamps)
+ if r:
+ return r
+ else:
+ if not webnotes.conn.exists(self.doctype, self.name):
+ print self.fields
+ webnotes.msgprint(webnotes._("Cannot update a non-exiting record, try inserting.") + ": " + self.doctype + " / " + self.name,
+ raise_exception=1)
+
+
+ # save the values
+ self._update_values(self._meta.issingle,
+ check_links and self.make_link_list() or {}, ignore_fields=ignore_fields,
+ keep_timestamps=keep_timestamps)
+ self._clear_temp_fields()
+
def _get_amended_name(self):
am_id = 1
@@ -189,23 +230,35 @@ class Document:
self.name = am_prefix + '-' + str(am_id)
- def _set_name(self, autoname, istable):
+ def set_new_name(self, controller=None):
+ if self._new_name_set:
+ # already set by bean
+ return
+
+ self._new_name_set = True
+
+ self.get_meta()
+ autoname = self._meta.autoname
+
+
self.localname = self.name
- # get my object
- import webnotes.model.code
- so = webnotes.model.code.get_server_obj(self, [])
# amendments
if self.amended_from:
self._get_amended_name()
+
# by method
- elif so and hasattr(so, 'autoname'):
- r = webnotes.model.code.run_server_obj(so, 'autoname')
- if r: return r
+ else:
+ # get my object
+ if not controller:
+ controller = webnotes.get_obj([self])
+
+ if hasattr(controller, 'autoname'):
+ return controller.autoname()
# based on a field
- elif autoname and autoname.startswith('field:'):
+ if autoname and autoname.startswith('field:'):
n = self.fields[autoname[6:]]
if not n:
raise Exception, 'Name is required'
@@ -231,13 +284,13 @@ class Document:
self.name = self.fields['__newname']
# default name for table
- elif istable:
+ elif self._meta.istable:
self.name = make_autoname('#########', self.doctype)
- # unable to determine a name, use a serial number!
+ # unable to determine a name, use global series
if not self.name:
self.name = make_autoname('#########', self.doctype)
-
+
def set_naming_series(self):
if not self.naming_series:
# pick default naming series
@@ -247,13 +300,13 @@ class Document:
self.naming_series = self.naming_series.split("\n")
self.naming_series = self.naming_series[0] or self.naming_series[1]
- def _insert(self, autoname, istable, case='', make_autoname=1, keep_timestamps=False):
+ def _insert(self, make_autoname=True, keep_timestamps=False):
# set name
if make_autoname:
- self._set_name(autoname, istable)
+ self.set_new_name()
# validate name
- self.name = validate_name(self.doctype, self.name, case)
+ self.name = validate_name(self.doctype, self.name, self._meta.name_case)
# insert!
if not keep_timestamps:
@@ -370,10 +423,12 @@ class Document:
if getattr(webnotes.local, "valid_fields_map", None) is None:
webnotes.local.valid_fields_map = {}
+ self.get_meta()
+
valid_fields_map = webnotes.local.valid_fields_map
if not valid_fields_map.get(self.doctype):
- if cint(webnotes.conn.get_value("DocType", self.doctype, "issingle")):
+ if cint( self._meta.issingle):
doctypelist = webnotes.model.doctype.get(self.doctype)
valid_fields_map[self.doctype] = doctypelist.get_fieldnames({
"fieldtype": ["not in", webnotes.model.no_value_fields]})
@@ -382,47 +437,13 @@ class Document:
webnotes.conn.get_table_columns(self.doctype)
return valid_fields_map.get(self.doctype)
-
- def save(self, new=0, check_links=1, ignore_fields=0, make_autoname=1,
- keep_timestamps=False):
- res = webnotes.model.meta.get_dt_values(self.doctype,
- 'autoname, issingle, istable, name_case', as_dict=1)
- res = res and res[0] or {}
-
- if new:
- self.fields["__islocal"] = 1
- # add missing parentinfo (if reqd)
- if self.parent and not (self.parenttype and self.parentfield):
- self.update_parentinfo()
+ def get_meta(self):
+ if not self._meta:
+ self._meta = webnotes.conn.get_value("DocType", self.doctype, ["autoname", "issingle",
+ "istable", "name_case"], as_dict=True) or webnotes._dict()
+ return self._meta
- if self.parent and not self.idx:
- self.set_idx()
-
- # if required, make new
- if not res.get('issingle'):
- if self.fields.get('__islocal'):
- r = self._insert(res.get('autoname'), res.get('istable'), res.get('name_case'),
- make_autoname, keep_timestamps = keep_timestamps)
- if r:
- return r
- else:
- if not webnotes.conn.exists(self.doctype, self.name):
- print self.fields
- webnotes.msgprint(webnotes._("Cannot update a non-exiting record, try inserting.") + ": " + self.doctype + " / " + self.name,
- raise_exception=1)
-
-
- # save the values
- self._update_values(res.get('issingle'),
- check_links and self.make_link_list() or {}, ignore_fields=ignore_fields,
- keep_timestamps=keep_timestamps)
- self._clear_temp_fields()
-
- def insert(self):
- self.fields['__islocal'] = 1
- self.save()
- return self
def update_parentinfo(self):
"""update parent type and parent field, if not explicitly specified"""
@@ -574,22 +595,18 @@ def make_autoname(key, doctype=''):
def getseries(key, digits, doctype=''):
# series created ?
- if webnotes.conn.sql("select name from tabSeries where name='%s'" % key):
-
+ current = cint(webnotes.conn.get_value("Series", key, "current"))
+ if current:
# yes, update it
- webnotes.conn.sql("update tabSeries set current = current+1 where name='%s'" % key)
-
- # find the series counter
- r = webnotes.conn.sql("select current from tabSeries where name='%s'" % key)
- n = r[0][0]
+ webnotes.conn.sql("update tabSeries set current = current+1 where name=%s", key)
+ current = current + 1
else:
-
# no, create it
webnotes.conn.sql("insert into tabSeries (name, current) values ('%s', 1)" % key)
- n = 1
- return ('%0'+str(digits)+'d') % n
+ current = 1
+ return ('%0'+str(digits)+'d') % current
-def getchildren(name, childtype, field='', parenttype='', from_doctype=0, prefix='tab'):
+def getchildren(name, childtype, field='', parenttype='', from_doctype=0):
import webnotes
from webnotes.model.doclist import DocList
@@ -603,8 +620,8 @@ def getchildren(name, childtype, field='', parenttype='', from_doctype=0, prefix
condition += ' and parenttype=%s '
values.append(parenttype)
- dataset = webnotes.conn.sql("""select * from `%s%s` where parent=%s %s order by idx""" \
- % (prefix, childtype, "%s", condition), tuple([name]+values))
+ dataset = webnotes.conn.sql("""select * from `tab%s` where parent=%s %s order by idx""" \
+ % (childtype, "%s", condition), tuple([name]+values))
desc = webnotes.conn.get_description()
l = DocList()
@@ -627,7 +644,7 @@ def check_page_perm(doc):
webnotes.response['403'] = 1
raise webnotes.PermissionError, '[WNF] No read permission for %s %s' % ('Page', doc.name)
-def get(dt, dn='', with_children = 1, from_controller = 0, prefix = 'tab'):
+def get(dt, dn='', with_children = 1, from_controller = 0):
"""
Returns a doclist containing the main record and all child records
"""
@@ -638,7 +655,7 @@ def get(dt, dn='', with_children = 1, from_controller = 0, prefix = 'tab'):
dn = dn or dt
# load the main doc
- doc = Document(dt, dn, prefix=prefix)
+ doc = Document(dt, dn)
if dt=='Page' and webnotes.session['user'] == 'Guest':
check_page_perm(doc)
@@ -653,7 +670,7 @@ def get(dt, dn='', with_children = 1, from_controller = 0, prefix = 'tab'):
# load chilren
doclist = DocList([doc,])
for t in tablefields:
- doclist += getchildren(doc.name, t[0], t[1], dt, prefix=prefix)
+ doclist += getchildren(doc.name, t[0], t[1], dt)
return doclist
diff --git a/webnotes/modules/__init__.py b/webnotes/modules/__init__.py
index b0d97a9408..73cbefa103 100644
--- a/webnotes/modules/__init__.py
+++ b/webnotes/modules/__init__.py
@@ -32,6 +32,10 @@ def get_module_path(module):
return os.path.join(app_path, 'lib', m)
else:
return os.path.join(app_path, 'app', m)
+
+def get_plugin_path(plugin):
+ from webnotes.utils import get_site_path
+ return get_site_path(webnotes.conf.get("plugins_path"), scrub(plugin))
def get_doc_path(module, doctype, name):
dt, dn = scrub_dt_dn(doctype, name)
@@ -41,13 +45,13 @@ def reload_doc(module, dt=None, dn=None, force=True):
from webnotes.modules.import_file import import_files
return import_files(module, dt, dn, force)
-def export_doc(doctype, name, module=None):
+def export_doc(doctype, name, module=None, plugin=None):
"""write out a doc"""
from webnotes.modules.export_file import write_document_file
import webnotes.model.doc
if not module: module = webnotes.conn.get_value(doctype, name, 'module')
- write_document_file(webnotes.model.doc.get(doctype, name), module)
+ write_document_file(webnotes.model.doc.get(doctype, name), module, plugin=plugin)
def get_doctype_module(doctype):
return webnotes.conn.get_value('DocType', doctype, 'module')
diff --git a/webnotes/modules/export_file.py b/webnotes/modules/export_file.py
index 76e19f86b9..90f0ae41a3 100644
--- a/webnotes/modules/export_file.py
+++ b/webnotes/modules/export_file.py
@@ -5,25 +5,25 @@ from __future__ import unicode_literals
import webnotes, os
import webnotes.model.doc
-from webnotes.modules import scrub, get_module_path, lower_case_files_for, scrub_dt_dn
+from webnotes.modules import scrub, get_module_path, lower_case_files_for, scrub_dt_dn, get_plugin_path
def export_doc(doc):
export_to_files([[doc.doctype, doc.name]])
-def export_to_files(record_list=[], record_module=None, verbose=0):
+def export_to_files(record_list=None, record_module=None, verbose=0, plugin=None):
"""
Export record_list to files. record_list is a list of lists ([doctype],[docname] ) ,
"""
if webnotes.flags.in_import:
return
-
+
module_doclist =[]
if record_list:
for record in record_list:
write_document_file(webnotes.model.doc.get(record[0], record[1]),
- record_module)
+ record_module, plugin=plugin)
-def write_document_file(doclist, record_module=None):
+def write_document_file(doclist, record_module=None, plugin=None):
from webnotes.modules.utils import pprint_doclist
doclist = [filter_fields(d.fields) for d in doclist]
@@ -32,7 +32,7 @@ def write_document_file(doclist, record_module=None):
code_type = doclist[0]['doctype'] in lower_case_files_for
# create folder
- folder = create_folder(module, doclist[0]['doctype'], doclist[0]['name'], code_type)
+ folder = create_folder(module, doclist[0]['doctype'], doclist[0]['name'], code_type, plugin=plugin)
# write the data file
fname = (code_type and scrub(doclist[0]['name'])) or doclist[0]['name']
@@ -71,9 +71,11 @@ def get_module_name(doclist):
return module
-def create_folder(module, dt, dn, code_type):
- # get module path by importing the module
- module_path = get_module_path(module)
+def create_folder(module, dt, dn, code_type, plugin=None):
+ if plugin:
+ module_path = os.path.join(get_plugin_path(plugin), scrub(module))
+ else:
+ module_path = get_module_path(module)
dt, dn = scrub_dt_dn(dt, dn)
diff --git a/webnotes/tests/test_hash.py b/webnotes/tests/test_hash.py
new file mode 100644
index 0000000000..35698ad176
--- /dev/null
+++ b/webnotes/tests/test_hash.py
@@ -0,0 +1,30 @@
+from webnotes import HashAuthenticatedCommand, whitelist
+
+class HashCommand(HashAuthenticatedCommand):
+
+ def __call__(self, *args, **kwargs):
+ signature = kwargs.pop('signature')
+ if self.verify_signature(kwargs, signature):
+ return self.command(*args, **kwargs)
+ else:
+ raise Exception
+
+ def command(self, *args, **kwargs):
+ return "Hello World"
+
+ def get_nonce(self):
+ return "5"
+
+hash_cmd = (HashCommand())
+
+# @whitelist(allow_guest=True)
+# def get_hash():
+# return hash_cmd.get_signature({})
+#
+# def get_nonce(self):
+# return "5"
+
+@whitelist(allow_guest=True)
+@HashAuthenticatedCommand(nonce_function=get_nonce)
+def hash_cmd(*args, **kwargs):
+ return "Hello World"
diff --git a/webnotes/utils/email_lib/bulk.py b/webnotes/utils/email_lib/bulk.py
index 8987296b41..58ce068fca 100644
--- a/webnotes/utils/email_lib/bulk.py
+++ b/webnotes/utils/email_lib/bulk.py
@@ -35,7 +35,7 @@ def send(recipients=None, sender=None, doctype='Profile', email_field='email',
import urllib
updated = message + """
""" % (get_url(),
urllib.urlencode({
"cmd": "webnotes.utils.email_lib.bulk.unsubscribe",
diff --git a/webnotes/utils/file_manager.py b/webnotes/utils/file_manager.py
index d4b9caa181..87d28ee626 100644
--- a/webnotes/utils/file_manager.py
+++ b/webnotes/utils/file_manager.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import webnotes
-import os, base64
+import os, base64, re
from webnotes.utils import cstr, cint, get_site_path
from webnotes import _
from webnotes import conf
@@ -61,6 +61,25 @@ def get_uploaded_content():
webnotes.msgprint('No File')
return None, None
+def extract_images_from_html(doc, fieldname):
+ content = doc.get(fieldname)
+ webnotes.flags.has_dataurl = False
+
+ def _save_file(match):
+ data = match.group(1)
+ headers, content = data.split(",")
+ filename = headers.split("filename=")[-1]
+ filename = save_file(filename, content, doc.doctype, doc.name, decode=True).get("file_name")
+ if not webnotes.flags.has_dataurl:
+ webnotes.flags.has_dataurl = True
+
+ return '

{{ updated }}
- {{ content_html }}
+ {{ content }}
{% if blogger_info %}
@@ -21,5 +21,13 @@
Comments
{% include 'lib/website/templates/includes/comments.html' %}
+
{% include 'lib/website/doctype/blog_post/templates/includes/blog_footer.html' %}
{% endblock %}
\ No newline at end of file
diff --git a/website/doctype/blog_post/templates/includes/blog.js b/website/doctype/blog_post/templates/includes/blog.js
index d514a38f08..ee54bf5c5a 100644
--- a/website/doctype/blog_post/templates/includes/blog.js
+++ b/website/doctype/blog_post/templates/includes/blog.js
@@ -26,7 +26,7 @@ var blog = {
get_list: function() {
$.ajax({
method: "GET",
- url: "server.py",
+ url: "/",
data: {
cmd: "website.doctype.blog_post.blog_post.get_blog_list",
start: blog.start,
@@ -42,6 +42,7 @@ var blog = {
});
},
render: function(data) {
+ if(!data) data = [];
var $wrap = $("#blog-list");
$.each(data, function(i, b) {
// comments
diff --git a/website/doctype/web_page/templates/generators/web_page.html b/website/doctype/web_page/templates/generators/web_page.html
index 540c3290ea..0d1accc99f 100644
--- a/website/doctype/web_page/templates/generators/web_page.html
+++ b/website/doctype/web_page/templates/generators/web_page.html
@@ -1,10 +1,5 @@
{% extends base_template %}
-{% block head %}
-
-{% endblock %}
-
{% block content %}
{% include "lib/website/doctype/website_slideshow/templates/includes/slideshow.html" %}
@@ -14,9 +9,9 @@
diff --git a/website/js/website.js b/website/js/website.js
index 2f85e6ffde..343f95fda9 100644
--- a/website/js/website.js
+++ b/website/js/website.js
@@ -22,6 +22,18 @@ $.extend(wn, {
}
return parent;
},
+ require: function(url) {
+ $.ajax({
+ url: url + "?q=" + Math.floor(Math.random() * 1000),
+ async: false,
+ dataType: "text",
+ success: function(data) {
+ var el = document.createElement('script');
+ el.appendChild(document.createTextNode(data));
+ document.getElementsByTagName('head')[0].appendChild(el);
+ }
+ });
+ },
hide_message: function(text) {
$('.message-overlay').remove();
},
@@ -29,7 +41,7 @@ $.extend(wn, {
wn.prepare_call(opts);
$.ajax({
type: "POST",
- url: "server.py",
+ url: "/",
data: opts.args,
dataType: "json",
success: function(data) {
diff --git a/website/templates/includes/login.js b/website/templates/includes/login.js
index df7f8f30de..acc55d2a5c 100644
--- a/website/templates/includes/login.js
+++ b/website/templates/includes/login.js
@@ -59,7 +59,7 @@ login.do_login = function(){
$.ajax({
type: "POST",
- url: "server.py",
+ url: "/",
data: args,
dataType: "json",
success: function(data) {
diff --git a/wnf.py b/wnf.py
index 5d70e6108c..9e46f4f15f 100755
--- a/wnf.py
+++ b/wnf.py
@@ -41,7 +41,7 @@ def run(fn, args):
out = globals().get(fn)(*args.get(fn), **args)
else:
out = globals().get(fn)(**args)
- webnotes.destroy()
+
return out
def get_function(args):
@@ -135,6 +135,7 @@ def setup_utilities(parser):
help="Set administrator password")
parser.add_argument("--mysql", action="store_true", help="get mysql shell for a site")
parser.add_argument("--serve", action="store_true", help="Run development server")
+ parser.add_argument("--get_site_details", action="store_true", help="Get site details")
parser.add_argument("--port", default=8000, type=int, help="port for development server")
# clear
@@ -205,6 +206,7 @@ def install(db_name, source_sql=None, site=None, verbose=True, force=False, root
from webnotes.install_lib.install import Installer
inst = Installer('root', db_name=db_name, site=site, root_password=root_password, site_config=site_config)
inst.install(db_name, source_sql=source_sql, verbose=verbose, force=force, admin_password=admin_password)
+ webnotes.destroy()
@cmd
def reinstall(site=None, verbose=True):
@@ -220,6 +222,7 @@ def install_fixtures(site=None):
webnotes.init(site=site)
from webnotes.install_lib.install import install_fixtures
install_fixtures()
+ webnotes.destroy()
@cmd
def add_system_manager(email, first_name=None, last_name=None, site=None):
@@ -233,12 +236,14 @@ def make_demo(site=None):
import utilities.demo.make_demo
webnotes.init(site=site)
utilities.demo.make_demo.make()
+ webnotes.destroy()
@cmd
def make_demo_fresh(site=None):
import utilities.demo.make_demo
webnotes.init(site=site)
utilities.demo.make_demo.make(reset=True)
+ webnotes.destroy()
# utilities
@@ -270,12 +275,15 @@ def latest(site=None, verbose=True):
except webnotes.modules.patch_handler.PatchError, e:
print "\n".join(webnotes.local.patch_log_list)
raise e
+ finally:
+ webnotes.destroy()
@cmd
def sync_all(site=None, force=False):
import webnotes.model.sync
webnotes.connect(site=site)
webnotes.model.sync.sync_all(force=force)
+ webnotes.destroy()
@cmd
def patch(patch_module, site=None, force=False):
@@ -284,6 +292,7 @@ def patch(patch_module, site=None, force=False):
webnotes.local.patch_log_list = []
webnotes.modules.patch_handler.run_single(patch_module, force=force)
print "\n".join(webnotes.local.patch_log_list)
+ webnotes.destroy()
@cmd
def update_all_sites(remote=None, branch=None, verbose=True):
@@ -296,6 +305,7 @@ def update_all_sites(remote=None, branch=None, verbose=True):
def reload_doc(module, doctype, docname, site=None, force=False):
webnotes.connect(site=site)
webnotes.reload_doc(module, doctype, docname, force=force)
+ webnotes.destroy()
@cmd
def build():
@@ -355,6 +365,7 @@ def domain(host_url=None, site=None):
webnotes.conn.commit()
else:
print webnotes.conn.get_value("Website Settings", None, "subdomain")
+ webnotes.destroy()
@cmd
def make_conf(db_name=None, db_password=None, site=None, site_config=None):
@@ -366,6 +377,7 @@ def make_custom_server_script(doctype, site=None):
from core.doctype.custom_script.custom_script import make_custom_server_script_file
webnotes.connect(site=site)
make_custom_server_script_file(doctype)
+ webnotes.destroy()
# clear
@cmd
@@ -373,12 +385,14 @@ def clear_cache(site=None):
import webnotes.sessions
webnotes.connect(site=site)
webnotes.sessions.clear_cache()
+ webnotes.destroy()
@cmd
def clear_web(site=None):
import webnotes.webutils
webnotes.connect(site=site)
webnotes.webutils.clear_cache()
+ webnotes.destroy()
@cmd
def reset_perms(site=None):
@@ -387,6 +401,7 @@ def reset_perms(site=None):
where ifnull(istable, 0)=0 and ifnull(custom, 0)=0"""):
webnotes.clear_cache(doctype=d)
webnotes.reset_perms(d)
+ webnotes.destroy()
# scheduler
@cmd
@@ -394,12 +409,14 @@ def run_scheduler(site=None):
import webnotes.utils.scheduler
webnotes.connect(site=site)
print webnotes.utils.scheduler.execute()
+ webnotes.destroy()
@cmd
def run_scheduler_event(event, site=None):
import webnotes.utils.scheduler
webnotes.connect(site=site)
print webnotes.utils.scheduler.trigger("execute_" + event)
+ webnotes.destroy()
# replace
@cmd
@@ -413,24 +430,28 @@ def export_doc(doctype, docname, site=None):
import webnotes.modules
webnotes.connect(site=site)
webnotes.modules.export_doc(doctype, docname)
+ webnotes.destroy()
@cmd
def export_doclist(doctype, name, path, site=None):
from core.page.data_import_tool import data_import_tool
webnotes.connect(site=site)
data_import_tool.export_json(doctype, name, path)
+ webnotes.destroy()
@cmd
def export_csv(doctype, path, site=None):
from core.page.data_import_tool import data_import_tool
webnotes.connect(site=site)
data_import_tool.export_csv(doctype, path)
+ webnotes.destroy()
@cmd
def import_doclist(path, site=None):
from core.page.data_import_tool import data_import_tool
webnotes.connect(site=site)
data_import_tool.import_doclist(path)
+ webnotes.destroy()
# translation
@cmd
@@ -438,30 +459,35 @@ def build_message_files(site=None):
import webnotes.translate
webnotes.connect(site=site)
webnotes.translate.build_message_files()
+ webnotes.destroy()
@cmd
def export_messages(lang, outfile, site=None):
import webnotes.translate
webnotes.connect(site=site)
webnotes.translate.export_messages(lang, outfile)
+ webnotes.destroy()
@cmd
def import_messages(lang, infile, site=None):
import webnotes.translate
webnotes.connect(site=site)
webnotes.translate.import_messages(lang, infile)
+ webnotes.destroy()
@cmd
def google_translate(lang, infile, outfile, site=None):
import webnotes.translate
webnotes.connect(site=site)
webnotes.translate.google_translate(lang, infile, outfile)
+ webnotes.destroy()
@cmd
def translate(lang, site=None):
import webnotes.translate
webnotes.connect(site=site)
webnotes.translate.translate(lang)
+ webnotes.destroy()
# git
@cmd
@@ -522,6 +548,7 @@ def mysql(site=None):
msq = commands.getoutput('which mysql')
webnotes.init(site=site)
os.execv(msq, [msq, '-u', webnotes.conf.db_name, '-p'+webnotes.conf.db_password, webnotes.conf.db_name])
+ webnotes.destroy()
@cmd
def serve(port=8000):
@@ -573,6 +600,24 @@ def search_replace_with_prompt(fpath, txt1, txt2, force=False):
with open(fpath, 'w') as f:
f.write(''.join(tmp))
print colored('Updated', 'green')
+
+@cmd
+def get_site_details(site=None, verbose=False):
+ import webnotes
+ from webnotes.profile import get_system_managers
+ from core.doctype.profile.profile import get_total_users, get_active_users
+ import json
+ webnotes.connect(site=site)
+ ret = {
+ 'last_backup_on': webnotes.local.conf.last_backup_on,
+ 'active_users': get_active_users(),
+ 'total_users': get_total_users(),
+ 'system_managers': get_system_managers()
+ }
+ webnotes.destroy()
+ if verbose:
+ print json.dumps(ret, indent=4)
+ return ret
if __name__=="__main__":
main()