Просмотр исходного кода

[fix] limits variables and how usage is stored within limits + additional fixes

version-14
Anand Doshi 9 лет назад
Родитель
Сommit
3854bcad04
19 измененных файлов: 286 добавлений и 255 удалений
  1. +1
    -1
      frappe/__init__.py
  2. +5
    -0
      frappe/boot.py
  3. +10
    -13
      frappe/commands/site.py
  4. +2
    -63
      frappe/core/doctype/file/file.py
  5. +11
    -4
      frappe/core/doctype/file/test_file.py
  6. +4
    -4
      frappe/core/doctype/user/test_user.py
  7. +32
    -1
      frappe/core/doctype/user/user.py
  8. +12
    -20
      frappe/core/page/usage_info/usage_info.js
  9. +5
    -2
      frappe/desk/page/setup_wizard/setup_wizard.js
  10. +2
    -9
      frappe/desk/page/setup_wizard/setup_wizard.py
  11. +10
    -2
      frappe/email/doctype/email_queue/email_queue.py
  12. +6
    -8
      frappe/email/queue.py
  13. +2
    -10
      frappe/hooks.py
  14. +149
    -35
      frappe/limits.py
  15. +0
    -18
      frappe/public/js/frappe/setup_wizard.js
  16. +31
    -26
      frappe/public/js/frappe/toolbar.js
  17. +3
    -3
      frappe/tests/test_scheduler.py
  18. +0
    -35
      frappe/utils/user.py
  19. +1
    -1
      frappe/website/render.py

+ 1
- 1
frappe/__init__.py Просмотреть файл

@@ -1227,4 +1227,4 @@ def logger(module=None, with_more_info=True):
return get_logger(module or __name__, with_more_info=with_more_info)

def get_desk_link(doctype, name):
return '<a href="#Form/{0}/{1}" style="font-weight: bold;">{2} {1}</a>'.format(doctype, name, _(doctype))
return '<a href="#Form/{0}/{1}" style="font-weight: bold;">{2} {1}</a>'.format(doctype, name, _(doctype))

+ 5
- 0
frappe/boot.py Просмотреть файл

@@ -12,6 +12,7 @@ import frappe.desk.desk_page
from frappe.desk.form.load import get_meta_bundle
from frappe.utils.change_log import get_versions
from frappe.translate import get_lang_dict
from frappe.limits import get_limits, get_expiry_message

def get_bootinfo():
"""build and return boot info"""
@@ -65,6 +66,10 @@ def get_bootinfo():
bootinfo.calendars = sorted(frappe.get_hooks("calendars"))
bootinfo.lang_dict = get_lang_dict()

# limits
bootinfo.limits = get_limits()
bootinfo.expiry_message = get_expiry_message()

return bootinfo

def load_conf_settings(bootinfo):


+ 10
- 13
frappe/commands/site.py Просмотреть файл

@@ -4,8 +4,7 @@ import hashlib, os
import frappe
from frappe.commands import pass_context, get_site
from frappe.commands.scheduler import _is_scheduler_enabled
from frappe.commands import get_site
from frappe.limits import set_limits, get_limits
from frappe.limits import update_limits, get_limits
from frappe.installer import update_site_config

@click.command('new-site')
@@ -345,18 +344,19 @@ def set_limit(context, site, limit, value):
site = get_site(context)

with frappe.init_site(site):
if limit == 'expiry':
if limit=='expiry':
try:
datetime.datetime.strptime(value, '%Y-%m-%d')
except ValueError:
raise ValueError("Incorrect data format, should be YYYY-MM-DD")
else:
limit += '_limit'
# Space can be float, while other should be integers
value = float(value) if limit == 'space_limit' else int(value)

set_limits({limit : value})
elif limit=='space':
value = float(value)

else:
value = int(value)

update_limits({ limit : value })

@click.command('clear-limit')
@click.option('--site', help='site name')
@@ -369,14 +369,11 @@ def clear_limit(context, site, limit):
site = get_site(context)

with frappe.init_site(site):
if not limit == 'expiry':
limit += '_limit'

_clear_limit(limit)

# Remove limits from the site_config, if it's empty
cur_limits = get_limits()
if not cur_limits:
limits = get_limits()
if not limits:
update_site_config('limits', 'None', validate=False)




+ 2
- 63
frappe/core/doctype/file/file.py Просмотреть файл

@@ -11,7 +11,7 @@ naming for same name files: file.gif, file-1.gif, file-2.gif etc
import frappe
import json
import urllib
import os, subprocess
import os
import requests
import requests.exceptions
import StringIO
@@ -20,8 +20,7 @@ import mimetypes, imghdr
from frappe.utils.file_manager import delete_file_data_content, get_content_hash, get_random_filename
from frappe import _
from frappe.utils.nestedset import NestedSet
from frappe.limits import get_limits, set_limits
from frappe.utils import strip, get_url, get_files_path, flt
from frappe.utils import strip, get_files_path
from PIL import Image, ImageOps

class FolderNotEmpty(frappe.ValidationError): pass
@@ -352,63 +351,3 @@ def check_file_permission(file_url):

raise frappe.PermissionError

def validate_space_limit(file_size):
"""Stop from writing file if max space limit is reached"""
from frappe.installer import update_site_config
from frappe.utils import cint
from frappe.utils.file_manager import MaxFileSizeReachedError

frappe_limits = get_limits()

if not frappe_limits.has_key('space_limit'):
return

# In Gigabytes
space_limit = flt(flt(frappe_limits['space_limit']) * 1024, 2)

# in Kilobytes
used_space = flt(frappe_limits['files_size']) + flt(frappe_limits['backup_size']) + flt(frappe_limits['database_size'])
file_size = file_size / (1024.0**2)

# Stop from attaching file
if flt(used_space + file_size, 2) > space_limit:
frappe.throw(_("You have exceeded the max space of {0} for your plan. {1} or {2}.").format(
"<b>{0}MB</b>".format(cint(space_limit)) if (space_limit < 1024) else "<b>{0}GB</b>".format(frappe_limits['space_limit']),
'<a href="#usage-info">{0}</a>'.format(_("Click here to check your usage")),
'<a href="#upgrade">{0}</a>'.format(_("upgrade to a higher plan")),
), MaxFileSizeReachedError)

# update files size in frappe subscription
new_files_size = flt(frappe_limits['files_size']) + file_size
set_limits({'files_size': file_size})

def update_sizes():
from frappe.installer import update_site_config
# public files
files_path = frappe.get_site_path("public", "files")
files_size = flt(subprocess.check_output(['du', '-ms', files_path]).split()[0])

# private files
files_path = frappe.get_site_path("private", "files")
if os.path.exists(files_path):
files_size += flt(subprocess.check_output(['du', '-ms', files_path]).split()[0])

# backups
backup_path = frappe.get_site_path("private", "backups")
backup_size = subprocess.check_output(['du', '-ms', backup_path]).split()[0]

database_size = get_database_size()

set_limits({'files_size': files_size,
'backup_size': backup_size,
'database_size': database_size})

def get_database_size():
db_name = frappe.conf.db_name

# This query will get the database size in MB
db_size = frappe.db.sql('''
SELECT table_schema "database_name", sum( data_length + index_length ) / 1024 / 1024 "database_size"
FROM information_schema.TABLES WHERE table_schema = %s GROUP BY table_schema''', db_name, as_dict=True)

return db_size[0].get('database_size')

+ 11
- 4
frappe/core/doctype/file/test_file.py Просмотреть файл

@@ -98,10 +98,17 @@ class TestFile(unittest.TestCase):

def test_file_upload_limit(self):
from frappe.utils.file_manager import MaxFileSizeReachedError
from frappe.limits import set_limits, clear_limit
from frappe.limits import update_limits, clear_limit
from frappe import _dict

set_limits({'space_limit': 1, 'files_size': (1024 * 1024), 'database_size': 0, 'backup_size': 0})
update_limits({
'space': 1,
'space_usage': {
'files_size': (1024 * 1024),
'database_size': 0,
'backup_size': 0
}
})

# Rebuild the frappe.local.conf to take up the changes from site_config
frappe.local.conf = _dict(frappe.get_site_config())
@@ -110,5 +117,5 @@ class TestFile(unittest.TestCase):
'This files test for max space usage', "", "", self.get_folder("Test Folder 2", "Home").name)

# Scrub the site_config and rebuild frappe.local.conf
clear_limit("space_limit")
frappe.local.conf = _dict(frappe.get_site_config())
clear_limit("space")
frappe.local.conf = _dict(frappe.get_site_config())

+ 4
- 4
frappe/core/doctype/user/test_user.py Просмотреть файл

@@ -8,7 +8,7 @@ import requests
from frappe.model.delete_doc import delete_doc
from frappe.utils.data import today, add_to_date
from frappe import _dict
from frappe.limits import SiteExpiredError, set_limits, clear_limit
from frappe.limits import SiteExpiredError, update_limits, clear_limit
from frappe.utils import get_url
from frappe.installer import update_site_config

@@ -82,7 +82,7 @@ class TestUser(unittest.TestCase):
def test_user_limit_for_site(self):
from frappe.core.doctype.user.user import get_total_users

set_limits({'user_limit': get_total_users()})
update_limits({'users': get_total_users()})

# reload site config
from frappe import _dict
@@ -99,10 +99,10 @@ class TestUser(unittest.TestCase):
frappe.delete_doc('User', 'test_max_users@example.com')

# Clear the user limit
clear_limit('user_limit')
clear_limit('users')

def test_site_expiry(self):
set_limits({'expiry': add_to_date(today(), days=-1)})
update_limits({'expiry': add_to_date(today(), days=-1)})
frappe.local.conf = _dict(frappe.get_site_config())

frappe.db.commit()


+ 32
- 1
frappe/core/doctype/user/user.py Просмотреть файл

@@ -3,6 +3,7 @@

from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe.utils import cint, has_gravatar, format_datetime, now_datetime, get_formatted_email
from frappe import throw, msgprint, _
from frappe.utils.password import update_password as _update_password
@@ -11,10 +12,11 @@ from frappe.utils.user import get_system_managers
import frappe.permissions
import frappe.share
import re
from frappe.limits import get_limits

STANDARD_USERS = ("Guest", "Administrator")

from frappe.model.document import Document
class MaxUsersReachedError(frappe.ValidationError): pass

class User(Document):
__new_password = None
@@ -54,6 +56,7 @@ class User(Document):
self.remove_all_roles_for_guest()
self.validate_username()
self.remove_disabled_roles()
self.validate_user_limit()

if self.language == "Loading...":
self.language = None
@@ -383,6 +386,34 @@ class User(Document):
"""Returns list of modules blocked for that user"""
return [d.module for d in self.block_modules] if self.block_modules else []

def validate_user_limit(self):
'''
Validate if user limit has been reached for System Users
Checked in 'Validate' event as we don't want welcome email sent if max users are exceeded.
'''

if self.user_type == "Website User":
return

if not self.enabled:
# don't validate max users when saving a disabled user
return

limits = get_limits()
if not limits.users:
# no limits defined
return

total_users = get_total_users()
if self.is_new():
# get_total_users gets existing users in database
# a new record isn't inserted yet, so adding 1
total_users += 1

if total_users > limits.users:
frappe.throw(_("Sorry. You have reached the maximum user limit for your subscription. You can either disable an existing user or buy a higher subscription plan."),
MaxUsersReachedError)

@frappe.whitelist()
def get_timezones():
import pytz


+ 12
- 20
frappe/core/page/usage_info/usage_info.js Просмотреть файл

@@ -6,32 +6,24 @@ frappe.pages['usage-info'].on_page_load = function(wrapper) {
});

frappe.call({
method: "frappe.limits.get_usage_data",
method: "frappe.limits.get_usage_info",
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;

if(typeof doc.space_limit !== "undefined")
{
doc.max = flt(doc.space_limit * 1024);
var usage_info = r.message;
if (!usage_info) {
// nothing to show
// TODO improve this
return;
}
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);

var btn_text = doc.user_limit == 1 ? __("Upgrade") : __("Renew / Upgrade");
var btn_text = usage_info.limits.users == 1 ? __("Upgrade") : __("Renew / Upgrade");

if(doc.limits_upgrade_link) {
page.set_primary_action(btn_text, function() {
frappe.set_route("upgrade");
});
}
if(usage_info.upgrade_link) {
page.set_primary_action(btn_text, function() {
window.open(usage_info.upgrade_link);
});
}
}
});



+ 5
- 2
frappe/desk/page/setup_wizard/setup_wizard.js Просмотреть файл

@@ -421,7 +421,7 @@ function load_frappe_slides() {
},


frappe.wiz.user= {
frappe.wiz.user = {
app_name: "frappe",
title: __("The First User: You"),
icon: "icon-user",
@@ -465,5 +465,8 @@ frappe.wiz.on("before_load", function() {
// add welcome slide
frappe.wiz.add_slide(frappe.wiz.welcome);
frappe.wiz.add_slide(frappe.wiz.region);
frappe.wiz.add_slide(frappe.wiz.user);

if (!(frappe.boot.limits && frappe.boot.limits.users===1)) {
frappe.wiz.add_slide(frappe.wiz.user);
}
});

+ 2
- 9
frappe/desk/page/setup_wizard/setup_wizard.py Просмотреть файл

@@ -163,10 +163,7 @@ def prettify_args(args):
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'):
if not frappe.local.conf.setup_wizard_exception_email:
return

pretty_args = prettify_args(args)
@@ -210,12 +207,8 @@ def email_setup_wizard_exception(traceback, args):
headers=frappe.local.request.headers,
accept_languages=", ".join(frappe.local.request.accept_languages.values()))

frappe.sendmail(recipients=frappe_limits.get('setup_wizard_exception_email'),
frappe.sendmail(recipients=frappe.local.conf.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()})

+ 10
- 2
frappe/email/doctype/email_queue/email_queue.py Просмотреть файл

@@ -4,12 +4,20 @@

from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.email.queue import send_one
from frappe.limits import get_limits

class EmailQueue(Document):
pass
def on_trash(self):
self.prevent_email_queue_delete()

def prevent_email_queue_delete(self):
'''If email limit is set, don't allow users to delete Email Queue record'''
if get_limits().emails and frappe.session.user != 'Administrator':
frappe.throw(_('Only Administrator can delete Email Queue'))


@frappe.whitelist()
def retry_sending(name):


+ 6
- 8
frappe/email/queue.py Просмотреть файл

@@ -147,15 +147,18 @@ def check_email_limit(recipients):
or frappe.flags.in_test):

# get count of mails sent this month
this_month = frappe.db.sql("""select count(name) from `tabEmail Queue` where
status='Sent' and MONTH(creation)=MONTH(CURDATE())""")[0][0]
this_month = get_emails_sent_this_month()

monthly_email_limit = frappe.conf.get('monthly_email_limit') or 500
monthly_email_limit = frappe.conf.get('limits', {}).get('emails') or 500

if (this_month + len(recipients)) > monthly_email_limit:
throw(_("Cannot send this email. You have crossed the sending limit of {0} emails for this month.").format(monthly_email_limit),
EmailLimitCrossedError)

def get_emails_sent_this_month():
return frappe.db.sql("""select count(name) from `tabEmail Queue` where
status='Sent' and MONTH(creation)=MONTH(CURDATE())""")[0][0]

def get_unsubscribe_link(reference_doctype, reference_name,
email, recipients, expose_recipients, show_as_cc,
unsubscribe_method, unsubscribe_params, unsubscribe_message):
@@ -334,8 +337,3 @@ def clear_outbox():
"""Remove mails older than 31 days in Outbox. Called daily via scheduler."""
frappe.db.sql("""delete from `tabEmail Queue` where
datediff(now(), creation) > 31""")

def prevent_email_queue_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 Email Queue'))

+ 2
- 10
frappe/hooks.py Просмотреть файл

@@ -14,7 +14,6 @@ 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"
@@ -96,12 +95,6 @@ standard_queries = {
}

doc_events = {
"User": {
"validate": "frappe.utils.user.validate_user_limit"
},
"Email Queue": {
"on_trash": "frappe.email.queue.prevent_email_queue_delete"
},
"*": {
"after_insert": "frappe.email.doctype.email_alert.email_alert.trigger_email_alerts",
"validate": "frappe.email.doctype.email_alert.email_alert.trigger_email_alerts",
@@ -141,7 +134,7 @@ scheduler_events = {
"frappe.async.remove_old_task_logs",
"frappe.utils.scheduler.disable_scheduler_on_expiry",
"frappe.utils.scheduler.restrict_scheduler_events_if_dormant",
"frappe.core.doctype.file.file.update_sizes"
"frappe.limits.update_space_usage"

],
"daily_long": [
@@ -180,5 +173,4 @@ bot_parsers = [
]

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"
before_write_file = "frappe.limits.validate_space_limit"

+ 149
- 35
frappe/limits.py Просмотреть файл

@@ -1,25 +1,34 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import now_datetime, getdate
from frappe import _
from frappe.utils import now_datetime, getdate, flt, cint, get_fullname
from frappe.installer import update_site_config
from frappe.utils.data import formatdate
from frappe import _
from frappe.utils.user import get_enabled_system_users
import os, subprocess, urlparse, urllib

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 check_if_expired():
"""check if account is expired. If expired, do not allow login"""
if not has_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 {0}.
To extend please send an email to {1}""").format(expires_on, support_email),
SiteExpiredError)

def has_expired():
if frappe.session.user=="Administrator":
return False

expires_on = get_limits().get("expiry")
expires_on = get_limits().expiry
if not expires_on:
return False

@@ -28,18 +37,6 @@ def has_expired():

return True

def check_if_expired():
"""check if account is expired. If expired, do not allow login"""
if not has_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 {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 ""
@@ -67,30 +64,147 @@ def get_expiry_message():

return message

@frappe.whitelist()
def get_usage_info():
'''Get data to show for Usage Info'''
# imported here to prevent circular import
from frappe.email.queue import get_emails_sent_this_month

limits = get_limits()
if not (limits and any([limits.users, limits.space, limits.emails, limits.expiry])):
# no limits!
return

limits.space = limits.space * 1024.0 # to MB
if not limits.space_usage:
# hack! to show some progress
limits.space_usage = {
'database_size': 26,
'files_size': 1,
'backup_size': 1,
'total': 28
}

usage_info = frappe._dict({
'limits': limits,
'enabled_users': get_enabled_system_users(),
'emails_sent': get_emails_sent_this_month(),
'space_usage': limits.space_usage['total'],
})

if limits.expiry:
usage_info['days_to_expiry'] = (getdate(limits.expiry) - getdate()).days

if limits.upgrade_link:
usage_info['upgrade_link'] = get_upgrade_link(limits.upgrade_link)

return usage_info

def get_upgrade_link(upgrade_link):
parts = urlparse.urlsplit(upgrade_link)
params = dict(urlparse.parse_qsl(parts.query))
params.update({
'site': frappe.local.site,
'email': frappe.session.user,
'fullname': get_fullname()
})

parts.query = urllib.urlencode(params)
url = urlparse.urlunparse(parts)
return url

def get_limits():
return frappe.get_conf().get("limits") or {}
'''
"limits": {
"users": 1,
"space": 0.5, # in GB
"emails": 1000 # per month
"expiry": "2099-12-31"
}
'''
return frappe._dict(frappe.local.conf.limits or {})

def update_limits(key, value):
'''Add/Update limit in site_config'''
limits = get_limits()
if isinstance(key, dict):
limits.update(key)
else:
limits[key] = value

@frappe.whitelist()
def get_usage_data():
update_site_config("limits", limits, validate=False)
frappe.conf.limits = limits

def clear_limit(key):
'''Remove a limit option from site_config'''
limits = get_limits()
day = frappe.utils.add_months(frappe.utils.today(), -1)
limits["emails_sent"] = frappe.db.count("Email Queue", filters={'creation': ['>', day]})
return limits
if key in limits:
del limits[key]

update_site_config("limits", limits, validate=False)
frappe.conf.limits = limits

def validate_space_limit(file_size):
"""Stop from writing file if max space limit is reached"""
from frappe.utils.file_manager import MaxFileSizeReachedError

limits = get_limits()
if not limits.space:
return

# to MB
space_limit = flt(limits.space * 1024.0, 2)

# in MB
usage = frappe._dict(limits.space_usage or {})
if not usage:
# first time
usage = frappe._dict(update_space_usage())

file_size = file_size / (1024.0 ** 2)

if flt(usage.total + file_size, 2) > space_limit:
# Stop from attaching file
frappe.throw(_("You have exceeded the max space of {0} for your plan. {1}.").format(
"<b>{0}MB</b>".format(cint(space_limit)) if (space_limit < 1024) else "<b>{0}GB</b>".format(limits.space),
'<a href="#usage-info">{0}</a>'.format(_("Click here to check your usage or upgrade to a higher plan"))),
MaxFileSizeReachedError)

# update files size in frappe subscription
usage.files_size = flt(usage.files_size) + file_size
update_limits({ 'space_usage': usage })

def update_space_usage():
# public and private files
files_size = get_folder_size(frappe.get_site_path("public", "files"))
files_size += get_folder_size(frappe.get_site_path("private", "files"))

backup_size = get_folder_size(frappe.get_site_path("private", "backups"))
database_size = get_database_size()

usage = {
'files_size': files_size,
'backup_size': backup_size,
'database_size': database_size,
'total': flt(flt(files_size) + flt(backup_size) + flt(database_size), 2)
}

update_limits({ 'space_usage': usage })

def set_limits(limits):
# Add/Update current config options in site_config
frappe_limits = get_limits() or {}
for key in limits.keys():
frappe_limits[key] = limits[key]
return usage

update_site_config("limits", frappe_limits, validate=False)
def get_folder_size(path):
'''Returns folder size in MB if it exists'''
if os.path.exists(path):
return flt(subprocess.check_output(['du', '-ms', path]).split()[0])

def get_database_size():
'''Returns approximate database size in MB'''
db_name = frappe.conf.db_name

def clear_limit(limit):
frappe_limits = get_limits()
if limit in frappe_limits:
del frappe_limits[limit]
# This query will get the database size in MB
db_size = frappe.db.sql('''
SELECT table_schema "database_name", sum( data_length + index_length ) / 1024 / 1024 "database_size"
FROM information_schema.TABLES WHERE table_schema = %s GROUP BY table_schema''', db_name, as_dict=True)

update_site_config("limits", frappe_limits, validate=False)
return db_size[0].get('database_size')

+ 0
- 18
frappe/public/js/frappe/setup_wizard.js Просмотреть файл

@@ -1,18 +0,0 @@
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);
}

}
});

+ 31
- 26
frappe/public/js/frappe/toolbar.js Просмотреть файл

@@ -5,51 +5,56 @@ $(document).on("toolbar_setup", function() {
var help_links = [];
var support_link = "#upgrade";
var chat_link = "#upgrade";
frappe_limits = frappe.boot.frappe_limits
var limits = frappe.boot.limits;

if(frappe.boot.expiry_message) {
frappe.msgprint(frappe.boot.expiry_message)
}

if(frappe_limits.support_email || frappe_limits.support_chat) {
if(limits.support_email || limits.support_chat) {
help_links.push('<li class="divider"></li>');
}

if(frappe_limits.support_email) {
support_link = 'mailto:'+frappe.boot.frappe_limits.support_email;
if(limits.support_email) {
support_link = 'mailto:'+frappe.boot.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>');
}

if(limits.support_chat) {
help_links.push('<li><a href="'+limits.support_chat+'" 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>');
if(limits.space || limits.users || limits.expiry || limits.emails) {
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"));
}

$(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");
var limits = frappe.boot.limits;
if (!limits.usage) { limits.usage = {}; }
var usage = limits.usage;

if(!usage.sidebar_usage_html) {
if (limits.space) {
usage.total_used = flt(usage.database_size) + flt(usage.backup_size) + flt(usage.files_size);
usage.total_used_percent = cint(usage.total_used / flt(limits.space * 1024) * 100);

var template = '<ul class="list-unstyled sidebar-menu">\
<li class="usage-stats">\
<a href="#usage-info" class="text-muted">{{ usage.total_used }}MB ({{ usage.total_used_percent }}%) used</a></li>\
</ul>';
usage.sidebar_usage_html = frappe.render(template, { 'usage': usage }, "form_sidebar_usage");

} else {
usage.sidebar_usage_html = '';
}
}

return fs.sidebar_usage_html;
return usage.sidebar_usage_html;
}

+ 3
- 3
frappe/tests/test_scheduler.py Просмотреть файл

@@ -7,7 +7,7 @@ from frappe.utils.scheduler import (enqueue_applicable_events, restrict_schedule
from frappe import _dict
from frappe.utils.background_jobs import enqueue
from frappe.utils import now_datetime, today, add_days, add_to_date
from frappe.limits import set_limits, clear_limit
from frappe.limits import update_limits, clear_limit

import frappe
import json, time
@@ -56,7 +56,7 @@ class TestScheduler(TestCase):
def test_restrict_scheduler_events(self):
frappe.set_user("Administrator")
user = frappe.get_doc("User", "Administrator")
dormant_date = add_days(today(), -5)
dormant_date = add_days(today(), -5)
user.last_active = dormant_date
user.save()

@@ -69,7 +69,7 @@ class TestScheduler(TestCase):


def test_disable_scheduler_on_expiry(self):
set_limits({'expiry': add_to_date(today(), days=-1)})
update_limits({'expiry': add_to_date(today(), days=-1)})
frappe.local.conf = _dict(frappe.get_site_config())

user = frappe.new_doc('User')


+ 0
- 35
frappe/utils/user.py Просмотреть файл

@@ -8,8 +8,6 @@ from frappe import _dict
import frappe.share
from frappe import _

class MaxUsersReachedError(frappe.ValidationError): pass

class UserPermissions:
"""
A user permission object can be accessed as `frappe.get_user()`
@@ -307,36 +305,3 @@ def get_users():
})

return users


def validate_user_limit(doc, method):
"""
This is called using validate hook, because welcome email is sent in on_update.
We don't want welcome email sent if max users are exceeded.
"""
from frappe.limits import get_limits
from frappe.core.doctype.user.user import get_total_users
frappe_limits = get_limits()

if doc.user_type == "Website User":
return

if not doc.enabled:
# don't validate max users when saving a disabled user
return

user_limit = frappe_limits.get("user_limit") if frappe_limits else None

if not user_limit:
return

total_users = get_total_users()

if doc.is_new():
# get_total_users gets existing users in database
# a new record isn't inserted yet, so adding 1
total_users += 1

if total_users > user_limit:
frappe.throw(_("Sorry. You have reached the maximum user limit for your subscription. You can either disable an existing user or buy a higher subscription plan."),
MaxUsersReachedError)

+ 1
- 1
frappe/website/render.py Просмотреть файл

@@ -56,7 +56,7 @@ def render(path, http_status_code=None):

except frappe.Redirect, e:
return build_response(path, "", 301, {
"Location": frappe.flags.redirect_location,
"Location": frappe.flags.redirect_location or (frappe.local.response or {}).get('location'),
"Cache-Control": "no-store, no-cache, must-revalidate"
})



Загрузка…
Отмена
Сохранить