refactor: sign up flow changes (#31205)
* fix: logout to site login page if the site is on Frappe Cloud * fix: check if the site user is logged in before rendering trial banner * fix: show dropdown even if the site is not on trial plan * refactor: don't expose communication secret in boot * feat: show install app button for fc sites * fix: remove auth from desk we can simplify it and let user do auth in fc * fix: install app button condition * refactor: use `is_fc_site` method * fix: return boolean value for `is_fc_site` function * fix: add install app button in /apps page * fix: don't generate otp for login to fc * fix: remove install app option from desk * fix: design changes for trial banner * fix: add more details to the `current_site_info` endpoint also don't render trial banner if trial end date is passed * fix: don't route user to welcome page always put them on the site's dashboard * fix: override base_url when needed also remove misleading class * fix: show banner to normal user to contact system admin for plan upgrade * refactor: redirect from /login instead of every /logout code * fix: rename login to fc to manage billing also move it above the divider * refactor: separate out site-login url from login.py
This commit is contained in:
parent
2022ddf407
commit
5886234b53
5 changed files with 71 additions and 141 deletions
|
|
@ -15,6 +15,7 @@ from frappe.desk.doctype.form_tour.form_tour import get_onboarding_ui_tours
|
|||
from frappe.desk.doctype.route_history.route_history import frequently_visited_links
|
||||
from frappe.desk.form.load import get_meta_bundle
|
||||
from frappe.email.inbox import get_email_accounts
|
||||
from frappe.integrations.frappe_providers.frappecloud_billing import is_fc_site
|
||||
from frappe.model.base_document import get_controller
|
||||
from frappe.permissions import has_permission
|
||||
from frappe.query_builder import DocType
|
||||
|
|
@ -111,6 +112,7 @@ def get_bootinfo():
|
|||
bootinfo.translated_doctypes = get_translated_doctypes()
|
||||
bootinfo.subscription_conf = add_subscription_conf()
|
||||
bootinfo.marketplace_apps = get_marketplace_apps()
|
||||
bootinfo.is_fc_site = is_fc_site()
|
||||
bootinfo.changelog_feed = get_changelog_feed_items()
|
||||
bootinfo.enable_address_autocompletion = frappe.db.get_single_value(
|
||||
"Geolocation Settings", "enable_address_autocompletion"
|
||||
|
|
@ -139,7 +141,7 @@ def load_conf_settings(bootinfo):
|
|||
from frappe.core.api.file import get_max_file_size
|
||||
|
||||
bootinfo.max_file_size = get_max_file_size()
|
||||
for key in ("developer_mode", "socketio_port", "file_watcher_port", "fc_communication_secret"):
|
||||
for key in ("developer_mode", "socketio_port", "file_watcher_port"):
|
||||
if key in frappe.conf:
|
||||
bootinfo[key] = frappe.conf.get(key)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,15 @@ from frappe import _
|
|||
|
||||
def get_base_url():
|
||||
url = "https://frappecloud.com"
|
||||
if frappe.conf.developer_mode and frappe.conf.get("saas_billing_base_url"):
|
||||
url = frappe.conf.get("saas_billing_base_url")
|
||||
if frappe.conf.developer_mode and frappe.conf.get("fc_base_url"):
|
||||
url = frappe.conf.get("fc_base_url")
|
||||
return url
|
||||
|
||||
|
||||
def get_site_login_url():
|
||||
return f"{get_base_url()}/dashboard/site-login"
|
||||
|
||||
|
||||
def get_site_name():
|
||||
site_name = frappe.local.site
|
||||
if frappe.conf.developer_mode and frappe.conf.get("saas_billing_site_name"):
|
||||
|
|
@ -29,15 +33,28 @@ def get_headers():
|
|||
|
||||
return {
|
||||
"X-Site-Token": frappe.conf.get("fc_communication_secret"),
|
||||
"X-Site-User": frappe.session.user,
|
||||
"X-Site": get_site_name(),
|
||||
}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def current_site_info():
|
||||
from frappe.utils import cint
|
||||
|
||||
request = requests.post(f"{get_base_url()}/api/method/press.saas.api.site.info", headers=get_headers())
|
||||
if request.status_code == 200:
|
||||
return request.json().get("message")
|
||||
res = request.json().get("message")
|
||||
if not res:
|
||||
return None
|
||||
|
||||
return {
|
||||
**res,
|
||||
"site_name": get_site_name(),
|
||||
"base_url": get_base_url(),
|
||||
"setup_complete": cint(frappe.get_system_settings("setup_complete")),
|
||||
}
|
||||
|
||||
else:
|
||||
frappe.throw(_("Failed to get site info"))
|
||||
|
||||
|
|
@ -58,19 +75,19 @@ def api(method, data=None):
|
|||
|
||||
|
||||
@frappe.whitelist()
|
||||
def is_fc_site():
|
||||
def is_fc_site() -> bool:
|
||||
is_system_manager = frappe.get_roles(frappe.session.user).count("System Manager")
|
||||
setup_completed = frappe.get_system_settings("setup_complete")
|
||||
return is_system_manager and setup_completed and frappe.conf.get("fc_communication_secret")
|
||||
return bool(is_system_manager and setup_completed and frappe.conf.get("fc_communication_secret"))
|
||||
|
||||
|
||||
# login to frappe cloud dashboard
|
||||
@frappe.whitelist()
|
||||
def send_verification_code(route: str):
|
||||
def send_verification_code():
|
||||
request = requests.post(
|
||||
f"{get_base_url()}/api/method/press.api.developer.saas.send_verification_code",
|
||||
headers=get_headers(),
|
||||
json={"domain": get_site_name(), "route": route},
|
||||
json={"domain": get_site_name()},
|
||||
)
|
||||
if request.status_code == 200:
|
||||
return request.json().get("message")
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
const frappeCloudBaseEndpoint = "https://frappecloud.com";
|
||||
let frappeCloudBaseEndpoint = "https://frappecloud.com";
|
||||
let isFCUser = false;
|
||||
|
||||
$(document).ready(function () {
|
||||
if (
|
||||
frappe.boot.fc_communication_secret &&
|
||||
frappe.boot.is_fc_site &&
|
||||
frappe.boot.setup_complete === 1 &&
|
||||
!frappe.is_mobile() &&
|
||||
frappe.user.has_role("System Manager")
|
||||
|
|
@ -10,147 +11,40 @@ $(document).ready(function () {
|
|||
frappe.call({
|
||||
method: "frappe.integrations.frappe_providers.frappecloud_billing.current_site_info",
|
||||
callback: (r) => {
|
||||
if (!r?.message) return;
|
||||
|
||||
const response = r.message;
|
||||
if (response.trial_end_date) {
|
||||
const trial_end_date = new Date(response.trial_end_date);
|
||||
frappeCloudBaseEndpoint = response.base_url;
|
||||
isFCUser = response.is_fc_user;
|
||||
|
||||
if (response.trial_end_date && trial_end_date > new Date()) {
|
||||
$(".layout-main-section").before(
|
||||
generateTrialSubscriptionBanner(response.trial_end_date)
|
||||
);
|
||||
|
||||
addLoginToFCDropdownItem();
|
||||
|
||||
$(".login-to-fc").on("click", function () {
|
||||
window.route = "dashboard";
|
||||
initiateRequestForLoginToFrappeCloud();
|
||||
});
|
||||
|
||||
$(".upgrade-plan-button").on("click", function () {
|
||||
window.route = "site-dashboard";
|
||||
initiateRequestForLoginToFrappeCloud();
|
||||
});
|
||||
}
|
||||
addManageBillingDropdown();
|
||||
|
||||
$(".login-to-fc, .upgrade-plan-button").on("click", function () {
|
||||
openFrappeCloudDashboard();
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function initiateRequestForLoginToFrappeCloud() {
|
||||
frappe.confirm(__("Are you sure you want to login to Frappe Cloud dashboard?"), () => {
|
||||
requestLoginToFC();
|
||||
});
|
||||
}
|
||||
|
||||
function requestLoginToFC(freezing_msg = "Initiating login to Frappe Cloud...") {
|
||||
frappe.call({
|
||||
method: "frappe.integrations.frappe_providers.frappecloud_billing.send_verification_code",
|
||||
args: {
|
||||
route: window.route,
|
||||
},
|
||||
freeze: true,
|
||||
freeze_message: __(freezing_msg),
|
||||
callback: function (r) {
|
||||
if (r.message.is_user_logged_in) {
|
||||
window.open(`${frappeCloudBaseEndpoint}${r.message.redirect_to}`, "_blank");
|
||||
return;
|
||||
} else {
|
||||
showFCLoginDialog(r.message.email);
|
||||
setErrorMessage("");
|
||||
}
|
||||
},
|
||||
error: function (r) {
|
||||
frappe.throw(__("Failed to login to Frappe Cloud. Please try again"));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function setErrorMessage(message) {
|
||||
$("#fc-login-error").text(message);
|
||||
}
|
||||
|
||||
function showFCLoginDialog(email) {
|
||||
if (!window.fc_login_dialog) {
|
||||
var d = new frappe.ui.Dialog({
|
||||
title: __("Login to Frappe Cloud"),
|
||||
primary_action_label: __("Verify", null, "Submit verification code"),
|
||||
primary_action: verifyCode,
|
||||
});
|
||||
|
||||
$(d.body).html(
|
||||
repl(
|
||||
`<div>
|
||||
<p>We have sent the verification code to your email id <strong>${email}</strong></p>
|
||||
<div class="form-group mt-2">
|
||||
<div class="clearfix">
|
||||
<label class="control-label" style="padding-right: 0px;">Verification Code</label>
|
||||
</div>
|
||||
<div class="control-input-wrapper">
|
||||
<div class="control-input"><input type="text" class="input-with-feedback form-control" id="fc-login-verification-code"></div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-danger" id="fc-login-error"></p>
|
||||
</div>`,
|
||||
frappe.app
|
||||
)
|
||||
);
|
||||
|
||||
d.add_custom_action("Didn't receive code? Resend", () => {
|
||||
d.hide();
|
||||
requestLoginToFC("Resending Verification Code...");
|
||||
});
|
||||
|
||||
window.fc_login_dialog = d;
|
||||
}
|
||||
|
||||
function verifyCode() {
|
||||
let otp = $("#fc-login-verification-code").val();
|
||||
if (!otp) {
|
||||
return;
|
||||
}
|
||||
frappe.call({
|
||||
method: "frappe.integrations.frappe_providers.frappecloud_billing.verify_verification_code",
|
||||
args: {
|
||||
verification_code: otp,
|
||||
route: window.route,
|
||||
},
|
||||
freeze: true,
|
||||
freeze_message: __("Verifying verification code..."),
|
||||
callback: function (r) {
|
||||
const message = r.message;
|
||||
if (message.login_token) {
|
||||
window.fc_login_dialog.hide();
|
||||
window.open(
|
||||
`${frappeCloudBaseEndpoint}/api/method/press.api.developer.saas.login_to_fc?token=${message.login_token}`,
|
||||
"_blank"
|
||||
);
|
||||
frappe.msgprint({
|
||||
title: __("Frappe Cloud Login Successful"),
|
||||
indicator: "green",
|
||||
message: `<p>${__(
|
||||
"You will be redirected to Frappe Cloud soon."
|
||||
)}</p><p>${__(
|
||||
"If you haven't been redirected,"
|
||||
)} <a href="${frappeCloudBaseEndpoint}/api/method/press.api.developer.saas.login_to_fc?token=${
|
||||
message.login_token
|
||||
}" target="_blank">${__("Click here to login")}</a></p>`,
|
||||
});
|
||||
} else {
|
||||
setErrorMessage("Login failed. Please try again");
|
||||
}
|
||||
},
|
||||
error: function (r) {
|
||||
if (r.exc) {
|
||||
setErrorMessage(JSON.parse(JSON.parse(r._server_messages)[0])["message"]);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
window.fc_login_dialog.show();
|
||||
function addManageBillingDropdown() {
|
||||
$(".dropdown-navbar-user .dropdown-menu .dropdown-divider").before(
|
||||
`<div class="dropdown-item login-to-fc" target="_blank">Manage Billing</div>`
|
||||
);
|
||||
}
|
||||
|
||||
function addLoginToFCDropdownItem() {
|
||||
$(".dropdown-navbar-user .dropdown-menu .dropdown-item:last()").before(
|
||||
`<div class="dropdown-item login-to-fc" target="_blank">Login to Frappe Cloud</div>`
|
||||
);
|
||||
function openFrappeCloudDashboard() {
|
||||
window.open(`${frappeCloudBaseEndpoint}/dashboard/sites/${frappe.boot.sitename}`, "_blank");
|
||||
}
|
||||
|
||||
function generateTrialSubscriptionBanner(trialEndDate) {
|
||||
|
|
@ -169,14 +63,13 @@ function generateTrialSubscriptionBanner(trialEndDate) {
|
|||
align-items: center;
|
||||
background-color: var(--subtle-accent);
|
||||
border-radius: var(--border-radius-md);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
.trial-banner > div {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.trial-banner .info-icon {
|
||||
margin: 4px 0;
|
||||
margin: auto 0;
|
||||
}
|
||||
.trial-banner > div > div {
|
||||
display: flex;
|
||||
|
|
@ -202,7 +95,7 @@ function generateTrialSubscriptionBanner(trialEndDate) {
|
|||
border-color: var(--gray-400);
|
||||
}
|
||||
</style>
|
||||
<div class="trial-banner px-3 py-2 m-2">
|
||||
<div class="trial-banner px-3 py-2 m-2 mt-4">
|
||||
<div>
|
||||
<svg class="info-icon" width="18" height="18" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_3360_13841)">
|
||||
|
|
@ -219,18 +112,26 @@ function generateTrialSubscriptionBanner(trialEndDate) {
|
|||
Your trial ends in ${trial_end_string}.
|
||||
</span>
|
||||
<span class="description">
|
||||
Please upgrade for uninterrupted services
|
||||
${
|
||||
isFCUser
|
||||
? "Please upgrade for uninterrupted services"
|
||||
: "Please contact your system administrator to upgrade your plan."
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button"
|
||||
${
|
||||
isFCUser
|
||||
? `<button type="button"
|
||||
class="upgrade-plan-button px-2 py-1"
|
||||
>
|
||||
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.2641 1C5.5758 1 4.97583 1.46845 4.80889 2.1362L3.57555 7.06953C3.33887 8.01625 4.05491 8.93333 5.03077 8.93333H7.50682L6.72168 14.4293C6.68838 14.6624 6.82229 14.8872 7.04319 14.9689C7.26408 15.0507 7.51204 14.9671 7.63849 14.7684L13.2161 6.00354C13.6398 5.33782 13.1616 4.46667 12.3725 4.46667H9.59038L10.3017 1.62127C10.3391 1.4719 10.3055 1.31365 10.2108 1.19229C10.116 1.07094 9.97063 1 9.81666 1H6.2641ZM5.77903 2.37873C5.83468 2.15615 6.03467 2 6.2641 2H9.17627L8.46492 4.8454C8.42758 4.99477 8.46114 5.15302 8.55589 5.27437C8.65064 5.39573 8.79602 5.46667 8.94999 5.46667H12.3725L8.0395 12.2757L8.5783 8.50404C8.5988 8.36056 8.55602 8.21523 8.46105 8.10573C8.36608 7.99623 8.22827 7.93333 8.08332 7.93333H5.03077C4.70548 7.93333 4.4668 7.62764 4.5457 7.31207L5.77903 2.37873Z" fill="currentColor"/>
|
||||
</svg>
|
||||
${__("Upgrade plan")}
|
||||
</button>
|
||||
</button>`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ def get_home_page_via_hooks():
|
|||
|
||||
|
||||
def get_boot_data():
|
||||
from frappe.integrations.frappe_providers.frappecloud_billing import is_fc_site
|
||||
from frappe.locale import get_date_format, get_first_day_of_the_week, get_number_format, get_time_format
|
||||
|
||||
return {
|
||||
|
|
@ -187,6 +188,7 @@ def get_boot_data():
|
|||
},
|
||||
"assets_json": get_assets_json(),
|
||||
"sitename": frappe.local.site,
|
||||
"is_fc_site": is_fc_site(),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ no_cache = True
|
|||
|
||||
|
||||
def get_context(context):
|
||||
from frappe.integrations.frappe_providers.frappecloud_billing import is_fc_site
|
||||
|
||||
redirect_to = frappe.local.request.args.get("redirect-to")
|
||||
redirect_to = sanitize_redirect(redirect_to)
|
||||
|
||||
|
|
@ -37,6 +39,12 @@ def get_context(context):
|
|||
frappe.local.flags.redirect_location = redirect_to
|
||||
raise frappe.Redirect
|
||||
|
||||
if is_fc_site():
|
||||
from frappe.integrations.frappe_providers.frappecloud_billing import get_site_login_url
|
||||
|
||||
frappe.local.flags.redirect_location = get_site_login_url()
|
||||
raise frappe.Redirect
|
||||
|
||||
context.no_header = True
|
||||
context.for_test = "login.html"
|
||||
context["title"] = "Login"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue