Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setup stages #4618

Merged
merged 6 commits into from Dec 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
146 changes: 92 additions & 54 deletions frappe/desk/page/setup_wizard/setup_wizard.js
Expand Up @@ -182,39 +182,72 @@ frappe.setup.SetupWizard = class SetupWizard extends frappe.ui.Slides {
}

action_on_complete() {
var me = this;
if (!this.current_slide.set_values()) return;
this.update_values();
this.show_working_state();
this.disable_keyboard_nav();
this.listen_for_setup_stages();

return frappe.call({
method: "frappe.desk.page.setup_wizard.setup_wizard.setup_complete",
args: {args: this.values},
callback: function() {
me.show_setup_complete_state();
if(frappe.setup.welcome_page) {
localStorage.setItem("session_last_route", frappe.setup.welcome_page);
callback: (r) => {
if(r.message.status === 'ok') {
this.post_setup_success();
} else if(r.message.fail !== undefined) {
this.abort_setup(r.message.fail);
}
setTimeout(function() {
// Reload
window.location.href = '';
}, 2000);
setTimeout(()=> {
$('body').removeClass('setup-state');
}, 20000);
},
error: function() {
var d = frappe.msgprint(__("There were errors."));
d.custom_onhide = function() {
$(me.parent).find('.page-card-container').remove();
$('body').removeClass('setup-state');
me.container.show();
frappe.set_route(me.page_name, me.slides.length - 1);
};
}
error: this.abort_setup.bind(this, "Error in setup", true)
});
}

post_setup_success() {
this.set_setup_complete_message(__("Setup Complete"), __("Refreshing..."));
if(frappe.setup.welcome_page) {
localStorage.setItem("session_last_route", frappe.setup.welcome_page);
}
setTimeout(function() {
// Reload
window.location.href = '';
}, 2000);
}

abort_setup(fail_msg, error=false) {
this.$working_state.find('.state-icon-container').html('');
fail_msg = fail_msg ? fail_msg : __("Failed to complete setup");

if(error && !frappe.boot.developer_mode) {
frappe.msgprint(`Don't worry. It's not you, it's us. We've
received the issue details and will get back to you on the solution.
Please feel free to contact us on support@erpnext.com in the meantime.`);
}

this.update_setup_message('Could not start up: ' + fail_msg);

this.$working_state.find('.title').html('Setup failed');

this.$abort_btn.show();
}

listen_for_setup_stages() {
frappe.realtime.on("setup_task", (data) => {
// console.log('data', data);
if(data.stage_status) {
// .html('Process '+ data.progress[0] + ' of ' + data.progress[1] + ': ' + data.stage_status);
this.update_setup_message(data.stage_status);
this.set_setup_load_percent((data.progress[0]+1)/data.progress[1] * 100);
}
if(data.fail_msg) {
this.abort_setup(data.fail_msg);
}
})
}

update_setup_message(message) {
this.$working_state.find('.setup-message').html(message);
}

get_setup_slides_filtered_by_domain() {
var filtered_slides = [];
frappe.setup.slides.forEach(function(slide) {
Expand All @@ -233,51 +266,56 @@ frappe.setup.SetupWizard = class SetupWizard extends frappe.ui.Slides {

show_working_state() {
this.container.hide();
$('body').addClass('setup-state');
frappe.set_route(this.page_name);

this.working_state_message = this.get_message(
__("Setting Up"),
__("Sit tight while your system is being setup. This may take a few moments."),
true
).appendTo(this.parent);
this.$working_state = this.get_message(
__("Setting up your system"),
__("Starting Frappé ...")).appendTo(this.parent);

this.attach_abort_button();

this.current_id = this.slides.length;
this.current_slide = null;
this.completed_state_message = this.get_message(
__("Setup Complete"),
__("Refreshing...")
);
}

show_setup_complete_state() {
this.working_state_message.hide();
this.completed_state_message.appendTo(this.parent);
attach_abort_button() {
this.$abort_btn = $(`<button class='btn btn-default btn-xs text-muted'
style="margin-bottom: 30px;">${__('Retry')}</button>`);
this.$working_state.find('.content').append(this.$abort_btn);

this.$abort_btn.on('click', () => {
$(this.parent).find('.setup-in-progress').remove();
this.container.show();
frappe.set_route(this.page_name, this.slides.length - 1);
});

this.$abort_btn.hide();
}

get_message(title, message="", loading=false) {
const loading_html = loading
? '<div style="width:100%;height:100%" class="lds-rolling state-icon"><div></div></div>'
: `<div style="width:100%;height:100%" class="state-icon">
<i class="fa fa-check-circle text-success"
style="font-size: 64px; margin-top: -8px;"></i>
</div>`;

return $(`<div class="page-card-container" data-state="setup">
<div class="page-card">
<div class="page-card-head">
${loading
? `<span class="indicator orange">${title}</span>`
: `<span class="indicator green">${title}</span>`
}
</div>
<p>${message}</p>
<div class="state-icon-container">
${loading_html}
</div>
get_message(title, message="") {
const loading_html = `<div class="progress-chart" style ="width: 150px;">
<div class="progress" style="margin-top: 70px; margin-bottom: 0px">
<div class="progress-bar" style="width: 2%; background-color: #5e64ff;"></div>
</div>
</div>`;

return $(`<div class="slides-wrapper setup-wizard-slide setup-in-progress">
<div class="content text-center">
<p class="title lead">${title}</p>
<div class="state-icon-container">${loading_html}</div>
<p class="setup-message text-muted" style="margin: 30px 0px;">${message}</p>
</div>
</div>`);
}

set_setup_complete_message(title, message) {
this.$working_state.find('.title').html(title);
this.$working_state.find('.setup-message').html(message);
}

set_setup_load_percent(percent) {
this.$working_state.find('.progress-bar').css({"width": percent + "%"});
}
};

frappe.setup.SetupWizardSlide = class SetupWizardSlide extends frappe.ui.Slide {
Expand Down
149 changes: 108 additions & 41 deletions frappe/desk/page/setup_wizard/setup_wizard.py
Expand Up @@ -13,50 +13,117 @@
from . import install_fixtures
from six import string_types

def get_setup_stages(args):

# App setup stage functions should not include frappe.db.commit
# That is done by frappe after successful completion of all stages
stages = [
{
'status': 'Updating global settings',
'fail_msg': 'Failed to update global settings',
'tasks': [
{
'fn': update_global_settings,
'args': args,
'fail_msg': 'Failed to update global settings'
}
]
}
]

stages += get_stages_hooks(args) + get_setup_complete_hooks(args)

stages.append({
# post executing hooks
'status': 'Wrapping up',
'fail_msg': 'Failed to complete setup',
'tasks': [
{
'fn': run_post_setup_complete,
'args': args,
'fail_msg': 'Failed to complete setup'
}
]
})

return stages

@frappe.whitelist()
def setup_complete(args):
"""Calls hooks for `setup_wizard_complete`, sets home page as `desktop`
and clears cache. If wizard breaks, calls `setup_wizard_exception` hook"""

# Setup complete: do not throw an exception, let the user continue to desk
if cint(frappe.db.get_single_value('System Settings', 'setup_complete')):
# do not throw an exception if setup is already complete
# let the user continue to desk
return
#frappe.throw(_('Setup already complete'))

args = process_args(args)
args = parse_args(args)

try:
if args.language and args.language != "english":
set_default_language(get_language_code(args.language))
stages = get_setup_stages(args)

frappe.clear_cache()

# update system settings
update_system_settings(args)
update_user_name(args)

for method in frappe.get_hooks("setup_wizard_complete"):
frappe.get_attr(method)(args)
try:
current_task = None
for idx, stage in enumerate(stages):
frappe.publish_realtime('setup_task', {"progress": [idx, len(stages)],
"stage_status": stage.get('status')}, user=frappe.session.user)

for task in stage.get('tasks'):
current_task = task
task.get('fn')(task.get('args'))

except Exception:
handle_setup_exception(args)
return {'status': 'fail', 'fail': current_task.get('fail_msg')}
else:
run_setup_success(args)
return {'status': 'ok'}

disable_future_access()
def update_global_settings(args):
if args.language and args.language != "english":
set_default_language(get_language_code(args.lang))
frappe.clear_cache()

frappe.db.commit()
frappe.clear_cache()
except:
frappe.db.rollback()
if args:
traceback = frappe.get_traceback()
for hook in frappe.get_hooks("setup_wizard_exception"):
frappe.get_attr(hook)(traceback, args)
update_system_settings(args)
update_user_name(args)

raise
def run_post_setup_complete(args):
disable_future_access()
frappe.db.commit()
frappe.clear_cache()

else:
for hook in frappe.get_hooks("setup_wizard_success"):
frappe.get_attr(hook)(args)
install_fixtures.install()
def run_setup_success(args):
for hook in frappe.get_hooks("setup_wizard_success"):
frappe.get_attr(hook)(args)
install_fixtures.install()

def get_stages_hooks(args):
stages = []
for method in frappe.get_hooks("setup_wizard_stages"):
stages += frappe.get_attr(method)(args)
return stages

def get_setup_complete_hooks(args):
stages = []
for method in frappe.get_hooks("setup_wizard_complete"):
stages.append({
'status': 'Executing method',
'fail_msg': 'Failed to execute method',
'tasks': [
{
'fn': frappe.get_attr(method),
'args': args,
'fail_msg': 'Failed to execute method'
}
]
})
return stages

def handle_setup_exception(args):
frappe.db.rollback()
if args:
traceback = frappe.get_traceback()
for hook in frappe.get_hooks("setup_wizard_exception"):
frappe.get_attr(hook)(traceback, args)

def update_system_settings(args):
number_format = get_country_info(args.get("country")).get("number_format", "#,###.##")
Expand Down Expand Up @@ -126,7 +193,7 @@ def update_user_name(args):
if args.get('name'):
add_all_roles_to(args.get("name"))

def process_args(args):
def parse_args(args):
if not args:
args = frappe.local.form_dict
if isinstance(args, string_types):
Expand Down Expand Up @@ -234,14 +301,6 @@ def email_setup_wizard_exception(traceback, args):
user_agent = frappe._dict()

message = """
#### Basic Information

- **Site:** {site}
- **User:** {user}
- **Browser:** {user_agent.platform} {user_agent.browser} version: {user_agent.version} language: {user_agent.language}
- **Browser Languages**: `{accept_languages}`

---

#### Traceback

Expand All @@ -257,7 +316,16 @@ def email_setup_wizard_exception(traceback, args):

#### Request Headers

<pre>{headers}</pre>""".format(
<pre>{headers}</pre>

---

#### Basic Information

- **Site:** {site}
- **User:** {user}
- **Browser:** {user_agent.platform} {user_agent.browser} version: {user_agent.version} language: {user_agent.language}
- **Browser Languages**: `{accept_languages}`""".format(
site=frappe.local.site,
traceback=traceback,
args="\n".join(pretty_args),
Expand All @@ -268,14 +336,13 @@ def email_setup_wizard_exception(traceback, args):

frappe.sendmail(recipients=frappe.local.conf.setup_wizard_exception_email,
sender=frappe.session.user,
subject="Exception in Setup Wizard - {}".format(frappe.local.site),
subject="Setup failed: {}".format(frappe.local.site),
message=message,
delayed=False)

def get_language_code(lang):
return frappe.db.get_value('Language', {'language_name':lang})


def enable_twofactor_all_roles():
all_role = frappe.get_doc('Role',{'role_name':'All'})
all_role.two_factor_auth = True
Expand Down