Merge pull request #1794 from vjFaLk/frappe-limits
Added Miscellenous Frappe Subscription features
This commit is contained in:
commit
acc4595fc7
12 changed files with 314 additions and 41 deletions
2
frappe/commands/site.py
Normal file → Executable file
2
frappe/commands/site.py
Normal file → Executable file
|
|
@ -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"
|
||||
|
|
|
|||
73
frappe/desk/page/setup_wizard/setup_wizard.py
Normal file → Executable file
73
frappe/desk/page/setup_wizard/setup_wizard.py
Normal file → Executable file
|
|
@ -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()})
|
||||
|
|
|
|||
5
frappe/email/bulk.py
Normal file → Executable file
5
frappe/email/bulk.py
Normal file → Executable file
|
|
@ -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
frappe/public/build.json
Normal file → Executable file
0
frappe/public/build.json
Normal file → Executable file
18
frappe/public/js/frappe/setup_wizard.js
Executable file
18
frappe/public/js/frappe/setup_wizard.js
Executable file
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
55
frappe/public/js/frappe/toolbar.js
Executable file
55
frappe/public/js/frappe/toolbar.js
Executable file
|
|
@ -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;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue