Browse Source

Merge pull request #1794 from vjFaLk/frappe-limits

Added Miscellenous Frappe Subscription features
version-14
Anand Doshi 9 years ago
committed by GitHub
parent
commit
acc4595fc7
12 changed files with 314 additions and 41 deletions
  1. +1
    -1
      frappe/commands/site.py
  2. +0
    -3
      frappe/core/doctype/file/file.py
  3. +74
    -2
      frappe/core/page/usage_info/usage_info.html
  4. +21
    -10
      frappe/core/page/usage_info/usage_info.js
  5. +11
    -11
      frappe/desk/page/setup_wizard/setup_wizard.json
  6. +73
    -0
      frappe/desk/page/setup_wizard/setup_wizard.py
  7. +5
    -0
      frappe/email/bulk.py
  8. +13
    -2
      frappe/hooks.py
  9. +43
    -12
      frappe/limits.py
  10. +0
    -0
      frappe/public/build.json
  11. +18
    -0
      frappe/public/js/frappe/setup_wizard.js
  12. +55
    -0
      frappe/public/js/frappe/toolbar.js

+ 1
- 1
frappe/commands/site.py View 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})



+ 0
- 3
frappe/core/doctype/file/file.py View File

@@ -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



+ 74
- 2
frappe/core/page/usage_info/usage_info.html View File

@@ -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>

+ 21
- 10
frappe/core/page/usage_info/usage_info.js View File

@@ -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");
});
}
}
});



+ 11
- 11
frappe/desk/page/setup_wizard/setup_wizard.json View File

@@ -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
- 0
frappe/desk/page/setup_wizard/setup_wizard.py View 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
- 0
frappe/email/bulk.py View 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'))

+ 13
- 2
frappe/hooks.py View File

@@ -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"

+ 43
- 12
frappe/limits.py View File

@@ -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
frappe/public/build.json View File


+ 18
- 0
frappe/public/js/frappe/setup_wizard.js View 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
- 0
frappe/public/js/frappe/toolbar.js View 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…
Cancel
Save