Added Miscellenous Frappe Subscription featuresversion-14
@@ -353,7 +353,7 @@ def set_limit(context, site, limit, value): | |||
else: | |||
limit += '_limit' | |||
# Space can be float, while other should be integers | |||
val = float(value) if limit == 'space_limit' else int(value) | |||
value = float(value) if limit == 'space_limit' else int(value) | |||
set_limits({limit : value}) | |||
@@ -360,9 +360,6 @@ def validate_space_limit(file_size): | |||
frappe_limits = get_limits() | |||
if not frappe_limits: | |||
return | |||
if not frappe_limits.has_key('space_limit'): | |||
return | |||
@@ -1,6 +1,10 @@ | |||
<div class="padding" style="max-width: 500px;"> | |||
<h3>Users</h3> | |||
<div class="padding" style="max-width: 800px;"> | |||
{% if user_limit %} | |||
{% var users_percent = ((users / user_limit) * 100); %} | |||
<h3>Users</h3> | |||
<div class="progress"> | |||
<div class="progress-bar progress-bar-{%= (users_percent < 75 ? "success" : "warning") %}" style="width: {{ users_percent }}%"> | |||
</div> | |||
@@ -23,6 +27,70 @@ | |||
</tbody> | |||
</table> | |||
<br> | |||
{% endif %} | |||
{% if expiry %} | |||
<h3>Expiration</h3> | |||
{% var days_remaining = total_days - used_days %} | |||
{% var date_percent = (( used_days / total_days) * 100); %} | |||
<div class="progress"> | |||
<div class="progress-bar progress-bar-{%= (date_percent < 75 ? "success" : "warning") %}" style="width: {{ date_percent }}%"> | |||
</div> | |||
</div> | |||
<table class="table table-bordered"> | |||
<thead> | |||
<tr> | |||
<th style="width: 33%">Creation Date</th> | |||
<th style="width: 33%">Expiry Date</th> | |||
<th style="width: 33%">Days Remaining</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>{%= creation %}</td> | |||
<td>{%= expiry %}</td> | |||
<td class="{%= (days_remaining < 10) ? "text-success" : "text-warning" %}">{%= days_remaining %}</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
<br> | |||
{% endif %} | |||
{% if email_limit %} | |||
<h3>Emails</h3> | |||
{% var email_percent = (( bulk_count / email_limit ) * 100); %} | |||
{% var emails_remaining = (email_limit - bulk_count) %} | |||
<div class="progress"> | |||
<div class="progress-bar progress-bar-{%= (email_percent < 75 ? "success" : "warning") %}" style="width: {{ email_percent }}%"> | |||
</div> | |||
</div> | |||
<table class="table table-bordered"> | |||
<thead> | |||
<tr> | |||
<th style="width: 33%">Emails Used</th> | |||
<th style="width: 33%">Total Emails</th> | |||
<th style="width: 33%">Emails Left</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>{%= bulk_count %}</td> | |||
<td>{%= email_limit %}</td> | |||
<td class="{%= (emails_remaining < 100) ? "text-success" : "text-warning" %}">{%= emails_remaining %}</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
<br> | |||
{% endif %} | |||
<h3>Disk Space</h3> | |||
{% var database_percent = ((database_size / max) * 100); %} | |||
@@ -61,11 +129,15 @@ | |||
<td><b>Total</b></td> | |||
<td><b>{%= total %} MB</b></td> | |||
</tr> | |||
{% if max %} | |||
<tr> | |||
<td><b>Available</b></td> | |||
<td class="{%= ((max - total) > 50) ? "" : "text-warning" %}"> | |||
<b>{%= flt(max - total, 2) %} MB</b></td> | |||
</tr> | |||
{% endif %} | |||
</tbody> | |||
</table> | |||
</div> |
@@ -6,18 +6,29 @@ frappe.pages['usage-info'].on_page_load = function(wrapper) { | |||
}); | |||
frappe.call({ | |||
method: "frappe.limits.get_limits", | |||
callback: function(doc) { | |||
doc = doc.message; | |||
if(!doc.database_size) doc.database_size = 26; | |||
if(!doc.files_size) doc.files_size = 1; | |||
if(!doc.backup_size) doc.backup_size = 1; | |||
method: "frappe.limits.get_limits", | |||
callback: function(r) { | |||
var doc = r.message; | |||
if(!doc.database_size) doc.database_size = 26; | |||
if(!doc.files_size) doc.files_size = 1; | |||
if(!doc.backup_size) doc.backup_size = 1; | |||
doc.max = flt(doc.space_limit * 1024); | |||
doc.total = (doc.database_size + doc.files_size + doc.backup_size); | |||
doc.users = keys(frappe.boot.user_info).length - 2; | |||
doc.max = flt(doc.space_limit * 1024); | |||
doc.total = (doc.database_size + doc.files_size + doc.backup_size); | |||
doc.users = keys(frappe.boot.user_info).length - 2; | |||
doc.today = frappe.datetime.get_today() | |||
doc.total_days = frappe.datetime.get_day_diff(doc.expiry, doc.creation) | |||
doc.used_days = frappe.datetime.get_day_diff(doc.today, doc.creation) | |||
$(frappe.render_template("usage_info", doc)).appendTo(page.main); | |||
$(frappe.render_template("usage_info", doc)).appendTo(page.main); | |||
var btn_text = doc.user_limit == 1 ? __("Upgrade") : __("Renew / Upgrade"); | |||
if(doc.limits_upgrade_link) { | |||
page.set_primary_action(btn_text, function() { | |||
frappe.set_route("upgrade"); | |||
}); | |||
} | |||
} | |||
}); | |||
@@ -1,15 +1,15 @@ | |||
{ | |||
"content": null, | |||
"creation": "2013-10-04 13:49:33", | |||
"docstatus": 0, | |||
"doctype": "Page", | |||
"idx": 1, | |||
"modified": "2016-06-10 12:05:31.701566", | |||
"modified_by": "Administrator", | |||
"module": "Desk", | |||
"name": "setup-wizard", | |||
"owner": "Administrator", | |||
"page_name": "setup-wizard", | |||
"content": null, | |||
"creation": "2013-10-04 13:49:33", | |||
"docstatus": 0, | |||
"doctype": "Page", | |||
"idx": 1, | |||
"modified": "2016-06-15 13:07:32.651564", | |||
"modified_by": "Administrator", | |||
"module": "Desk", | |||
"name": "setup-wizard", | |||
"owner": "Administrator", | |||
"page_name": "setup-wizard", | |||
"roles": [ | |||
{ | |||
"role": "Administrator" | |||
@@ -10,6 +10,7 @@ from frappe.translate import (set_default_language, get_dict, | |||
from frappe.geo.country_info import get_country_info | |||
from frappe.utils.file_manager import save_file | |||
from frappe.utils.password import update_password | |||
from werkzeug.useragents import UserAgent | |||
@frappe.whitelist() | |||
def setup_complete(args): | |||
@@ -146,3 +147,75 @@ def load_languages(): | |||
"default_language": get_language_from_code(frappe.local.lang), | |||
"languages": sorted(get_lang_dict().keys()) | |||
} | |||
def prettify_args(args): | |||
# remove attachments | |||
for key, val in args.items(): | |||
if isinstance(val, basestring) and "data:image" in val: | |||
filename = val.split("data:image", 1)[0].strip(", ") | |||
size = round((len(val) * 3 / 4) / 1048576.0, 2) | |||
args[key] = "Image Attached: '{0}' of size {1} MB".format(filename, size) | |||
pretty_args = [] | |||
for key in sorted(args): | |||
pretty_args.append("{} = {}".format(key, args[key])) | |||
return pretty_args | |||
def email_setup_wizard_exception(traceback, args): | |||
from frappe.limits import get_limits | |||
frappe_limits = get_limits() | |||
if not frappe_limits.get('setup_wizard_exception_email'): | |||
return | |||
pretty_args = prettify_args(args) | |||
if frappe.local.request: | |||
user_agent = UserAgent(frappe.local.request.headers.get('User-Agent', '')) | |||
else: | |||
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 | |||
<pre>{traceback}</pre> | |||
--- | |||
#### Setup Wizard Arguments | |||
<pre>{args}</pre> | |||
--- | |||
#### Request Headers | |||
<pre>{headers}</pre>""".format( | |||
site=frappe.local.site, | |||
traceback=traceback, | |||
args="\n".join(pretty_args), | |||
user=frappe.session.user, | |||
user_agent=user_agent, | |||
headers=frappe.local.request.headers, | |||
accept_languages=", ".join(frappe.local.request.accept_languages.values())) | |||
frappe.sendmail(recipients=frappe_limits.get('setup_wizard_exception_email'), | |||
sender=frappe.session.user, | |||
subject="Exception in Setup Wizard - {}".format(frappe.local.site), | |||
message=message) | |||
def set_setup_complete(*args): | |||
from frappe.limits import set_limits | |||
set_limits({'setup_complete' : 1 , 'creation': frappe.utils.today()}) |
@@ -334,3 +334,8 @@ def clear_outbox(): | |||
"""Remove mails older than 31 days in Outbox. Called daily via scheduler.""" | |||
frappe.db.sql("""delete from `tabBulk Email` where | |||
datediff(now(), creation) > 31""") | |||
def prevent_bulk_email_delete(doc, method): | |||
from frappe.limits import get_limits | |||
if frappe.session.user != 'Administrator' and get_limits().get('block_bulk_email_delete'): | |||
frappe.throw(_('Only Administrator can delete Bulk Email')) |
@@ -14,6 +14,11 @@ app_email = "info@frappe.io" | |||
before_install = "frappe.utils.install.before_install" | |||
after_install = "frappe.utils.install.after_install" | |||
extend_bootinfo = "frappe.limits.load_limits" | |||
page_js = { | |||
"setup-wizard": "public/js/frappe/setup_wizard.js" | |||
} | |||
# website | |||
app_include_js = [ | |||
@@ -23,7 +28,8 @@ app_include_js = [ | |||
"assets/js/list.min.js", | |||
"assets/js/form.min.js", | |||
"assets/js/report.min.js", | |||
"assets/js/d3.min.js" | |||
"assets/js/d3.min.js", | |||
"assets/frappe/js/frappe/toolbar.js" | |||
] | |||
app_include_css = [ | |||
"assets/css/desk.min.css", | |||
@@ -64,7 +70,7 @@ calendars = ["Event"] | |||
on_session_creation = [ | |||
"frappe.core.doctype.communication.feed.login_feed", | |||
"frappe.core.doctype.user.user.notifify_admin_access_to_system_manager", | |||
"frappe.limits.check_if_expired", #Unsure of where to move | |||
"frappe.limits.check_if_expired", | |||
"frappe.utils.scheduler.reset_enabled_scheduler_events", | |||
] | |||
@@ -93,6 +99,9 @@ doc_events = { | |||
"User": { | |||
"validate": "frappe.utils.user.validate_user_limit" | |||
}, | |||
"Bulk Email": { | |||
"on_trash": "frappe.email.bulk.prevent_bulk_email_delete" | |||
}, | |||
"*": { | |||
"after_insert": "frappe.email.doctype.email_alert.email_alert.trigger_email_alerts", | |||
"validate": "frappe.email.doctype.email_alert.email_alert.trigger_email_alerts", | |||
@@ -170,4 +179,6 @@ bot_parsers = [ | |||
'frappe.utils.bot.CountBot' | |||
] | |||
setup_wizard_exception = "frappe.desk.page.setup_wizard.setup_wizard.email_setup_wizard_exception" | |||
setup_wizard_success = "frappe.desk.page.setup_wizard.setup_wizard.set_setup_complete" | |||
before_write_file = "frappe.core.doctype.file.file.validate_space_limit" |
@@ -1,25 +1,24 @@ | |||
from __future__ import unicode_literals | |||
import frappe | |||
import subprocess, os | |||
from frappe.model.document import Document | |||
from frappe.core.doctype.user.user import get_total_users | |||
from frappe.utils import flt, cint, now_datetime, getdate, get_site_path | |||
from frappe.utils import now_datetime, getdate | |||
from frappe.installer import update_site_config | |||
from frappe.utils.file_manager import MaxFileSizeReachedError | |||
from frappe.utils.data import formatdate | |||
from frappe import _ | |||
class SiteExpiredError(frappe.ValidationError): | |||
pass | |||
EXPIRY_WARNING_DAYS = 10 | |||
def load_limits(bootinfo): | |||
bootinfo["frappe_limits"] = get_limits() | |||
bootinfo["expiry_message"] = get_expiry_message() | |||
def has_expired(): | |||
if frappe.session.user=="Administrator": | |||
return False | |||
if not get_limits(): | |||
return False | |||
expires_on = get_limits().get("expiry") | |||
if not expires_on: | |||
return False | |||
@@ -35,14 +34,46 @@ def check_if_expired(): | |||
return | |||
# if expired, stop user from logging in | |||
expires_on = formatdate(get_limits().get("expiry")) | |||
support_email = get_limits().get("support_email") or _("your provider") | |||
frappe.throw("""Your subscription expired on <b>{}</b>. | |||
To extend please drop a mail at <b>support@erpnext.com</b>""".format(expires_on), | |||
frappe.throw(_("""Your subscription expired on {0}. | |||
To extend please send an email to {1}""").format(expires_on, support_email), | |||
SiteExpiredError) | |||
def get_expiry_message(): | |||
if "System Manager" not in frappe.get_roles(): | |||
return "" | |||
if not get_limits().get("expiry"): | |||
return "" | |||
expires_on = getdate(get_limits().get("expiry")) | |||
today = now_datetime().date() | |||
message = "" | |||
if today > expires_on: | |||
message = _("Your subscription has expired") | |||
else: | |||
days_to_expiry = (expires_on - today).days | |||
if days_to_expiry == 0: | |||
message = _("Your subscription will expire today") | |||
elif days_to_expiry == 1: | |||
message = _("Your subscription will expire tomorrow") | |||
elif days_to_expiry <= EXPIRY_WARNING_DAYS: | |||
message = _("Your subscription will expire on") + " " + formatdate(expires_on) | |||
return message | |||
@frappe.whitelist() | |||
def get_limits(): | |||
return frappe.get_conf().get("limits") | |||
limits = frappe.get_conf().get("limits") or {} | |||
day = frappe.utils.add_months(frappe.utils.today(), -1) | |||
limits["bulk_count"] = frappe.db.count("Bulk Email", filters={'creation': ['>', day]}) | |||
return limits | |||
def set_limits(limits): | |||
@@ -55,7 +86,7 @@ def set_limits(limits): | |||
def clear_limit(limit): | |||
frappe_limits = get_limits() or {} | |||
frappe_limits = get_limits() | |||
if limit in frappe_limits: | |||
del frappe_limits[limit] | |||
@@ -0,0 +1,18 @@ | |||
frappe.wiz.on("after_load", function() { | |||
if (frappe.boot.frappe_limits.user_limit===1) { | |||
// remove users slide | |||
var users_slide; | |||
for (var i in frappe.wiz.wizard.slides) { | |||
var slide = frappe.wiz.wizard.slides[i]; | |||
if (slide.title === frappe.wiz.user.title) { | |||
users_slide = i; | |||
break; | |||
} | |||
} | |||
if (users_slide >= 0) { | |||
frappe.wiz.wizard.slides.splice(users_slide, 1); | |||
} | |||
} | |||
}); |
@@ -0,0 +1,55 @@ | |||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. | |||
// For license information, please see license.txt | |||
$(document).on("toolbar_setup", function() { | |||
var help_links = []; | |||
var support_link = "#upgrade"; | |||
var chat_link = "#upgrade"; | |||
frappe_limits = frappe.boot.frappe_limits | |||
if(frappe.boot.expiry_message) { | |||
frappe.msgprint(frappe.boot.expiry_message) | |||
} | |||
if(frappe_limits.support_email || frappe_limits.support_chat) { | |||
help_links.push('<li class="divider"></li>'); | |||
} | |||
if(frappe_limits.support_email) { | |||
support_link = 'mailto:'+frappe.boot.frappe_limits.support_email; | |||
help_links.push('<li><a href="'+support_link+'">' + frappe._('Email Support') + '</a></li>'); | |||
} | |||
if(frappe_limits.support_chat) { | |||
chat_link = frappe_limits.support_chat; | |||
help_links.push('<li><a href="'+chat_link+'" target="_blank">' + frappe._('Chat Support') + '</a></li>'); | |||
} | |||
$(help_links.join("\n")).insertBefore($("#toolbar-user").find(".divider:last")); | |||
if(frappe_limits.space_limit || frappe_limits.user_limit || frappe_limits.expiry || frappe_limits.email_limit) | |||
{ | |||
help_links = []; | |||
help_links.push('<li><a href="#usage-info">' + frappe._('Usage Info') + '</a></li>'); | |||
help_links.push('<li class="divider"></li>'); | |||
} | |||
$(help_links.join("\n")).insertBefore($("#toolbar-user").find("li:first")); | |||
}); | |||
frappe.get_form_sidebar_extension = function() { | |||
var fs = frappe.boot.frappe_limits; | |||
if(!fs.sidebar_usage_html) { | |||
fs.total_used = flt(fs.database_size + fs.backup_size + fs.files_size); | |||
fs.total_used_percent = cint(fs.total_used / flt(fs.max_space * 1024) * 100); | |||
var template = '<ul class="list-unstyled sidebar-menu">\ | |||
<li class="usage-stats">\ | |||
<a href="#usage-info" class="text-muted">{{ fs.total_used }}MB ({{ fs.total_used_percent }}%) used</a></li>\ | |||
</ul>'; | |||
fs.sidebar_usage_html = frappe.render(template, {fs:fs}, "form_sidebar_usage"); | |||
} | |||
return fs.sidebar_usage_html; | |||
} |