Merge pull request #7662 from deepeshgarg007/remove_user_limit
BREAKING CHANGE: Remove limits from frappe
This commit is contained in:
commit
dfa16a77f4
21 changed files with 7 additions and 802 deletions
|
|
@ -5,7 +5,6 @@ import frappe
|
|||
from frappe import _
|
||||
from frappe.commands import pass_context, get_site
|
||||
from frappe.commands.scheduler import _is_scheduler_enabled
|
||||
from frappe.limits import update_limits, get_limits
|
||||
from frappe.installer import update_site_config
|
||||
from frappe.utils import touch_file, get_site_path
|
||||
from six import text_type
|
||||
|
|
@ -443,79 +442,6 @@ def set_admin_password(context, admin_password, logout_all_sessions=False):
|
|||
finally:
|
||||
frappe.destroy()
|
||||
|
||||
@click.command('set-limit')
|
||||
@click.option('--site', help='site name')
|
||||
@click.argument('limit')
|
||||
@click.argument('value')
|
||||
@pass_context
|
||||
def set_limit(context, site, limit, value):
|
||||
"""Sets user / space / email limit for a site"""
|
||||
_set_limits(context, site, ((limit, value),))
|
||||
|
||||
@click.command('set-limits')
|
||||
@click.option('--site', help='site name')
|
||||
@click.option('--limit', 'limits', type=(text_type, text_type), multiple=True)
|
||||
@pass_context
|
||||
def set_limits(context, site, limits):
|
||||
_set_limits(context, site, limits)
|
||||
|
||||
def _set_limits(context, site, limits):
|
||||
import datetime
|
||||
|
||||
if not limits:
|
||||
return
|
||||
|
||||
if not site:
|
||||
site = get_site(context)
|
||||
|
||||
with frappe.init_site(site):
|
||||
frappe.connect()
|
||||
new_limits = {}
|
||||
for limit, value in limits:
|
||||
if limit not in ('daily_emails', 'emails', 'space', 'users', 'email_group', 'currency',
|
||||
'expiry', 'support_email', 'support_chat', 'upgrade_url', 'subscription_id',
|
||||
'subscription_type', 'current_plan', 'subscription_base_price', 'upgrade_plan',
|
||||
'upgrade_base_price', 'cancellation_url'):
|
||||
frappe.throw(_('Invalid limit {0}').format(limit))
|
||||
|
||||
if limit=='expiry' and value:
|
||||
try:
|
||||
datetime.datetime.strptime(value, '%Y-%m-%d')
|
||||
except ValueError:
|
||||
raise ValueError("Incorrect data format, should be YYYY-MM-DD")
|
||||
|
||||
elif limit in ('space', 'subscription_base_price', 'upgrade_base_price'):
|
||||
value = float(value)
|
||||
|
||||
elif limit in ('users', 'emails', 'email_group', 'daily_emails'):
|
||||
value = int(value)
|
||||
|
||||
new_limits[limit] = value
|
||||
|
||||
update_limits(new_limits)
|
||||
|
||||
@click.command('clear-limits')
|
||||
@click.option('--site', help='site name')
|
||||
@click.argument('limits', nargs=-1, type=click.Choice(['emails', 'space', 'users', 'email_group',
|
||||
'expiry', 'support_email', 'support_chat', 'upgrade_url', 'daily_emails', 'cancellation_url']))
|
||||
@pass_context
|
||||
def clear_limits(context, site, limits):
|
||||
"""Clears given limit from the site config, and removes limit from site config if its empty"""
|
||||
from frappe.limits import clear_limit as _clear_limit
|
||||
if not limits:
|
||||
return
|
||||
|
||||
if not site:
|
||||
site = get_site(context)
|
||||
|
||||
with frappe.init_site(site):
|
||||
_clear_limit(limits)
|
||||
|
||||
# Remove limits from the site_config, if it's empty
|
||||
limits = get_limits()
|
||||
if not limits:
|
||||
update_site_config('limits', 'None', validate=False)
|
||||
|
||||
@click.command('set-last-active-for-user')
|
||||
@click.option('--user', help="Setup last active date for user")
|
||||
@pass_context
|
||||
|
|
@ -613,9 +539,6 @@ commands = [
|
|||
run_patch,
|
||||
set_admin_password,
|
||||
uninstall,
|
||||
set_limit,
|
||||
set_limits,
|
||||
clear_limits,
|
||||
disable_user,
|
||||
_use,
|
||||
set_last_active_for_user,
|
||||
|
|
|
|||
|
|
@ -273,34 +273,3 @@ class TestFile(unittest.TestCase):
|
|||
self.assertRaises(frappe.ValidationError, folder.delete)
|
||||
|
||||
|
||||
def test_file_upload_limit(self):
|
||||
from frappe.core.doctype.file.file import MaxFileSizeReachedError
|
||||
from frappe.limits import update_limits, clear_limit
|
||||
from frappe import _dict
|
||||
|
||||
update_limits({
|
||||
'space': 1,
|
||||
'space_usage': {
|
||||
'files_size': (1024 ** 2),
|
||||
'database_size': 0,
|
||||
'backup_size': 0,
|
||||
'total': (1024 ** 2)
|
||||
}
|
||||
})
|
||||
|
||||
# Rebuild the frappe.local.conf to take up the changes from site_config
|
||||
frappe.local.conf = _dict(frappe.get_site_config())
|
||||
|
||||
_file = frappe.get_doc({
|
||||
"doctype": "File",
|
||||
"file_name": "_test_max_space.txt",
|
||||
"attached_to_name": "",
|
||||
"attached_to_doctype": "",
|
||||
"folder": self.get_folder("Test Folder 2", "Home").name,
|
||||
"content": "This file tests for max space usage"})
|
||||
self.assertRaises(MaxFileSizeReachedError,
|
||||
_file.save)
|
||||
|
||||
# Scrub the site_config and rebuild frappe.local.conf
|
||||
clear_limit("space")
|
||||
frappe.local.conf = _dict(frappe.get_site_config())
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ 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 update_limits, clear_limit
|
||||
from frappe.utils import get_url
|
||||
from frappe.core.doctype.user.user import get_total_users
|
||||
from frappe.core.doctype.user.user import MaxUsersReachedError, test_password_strength
|
||||
|
|
@ -116,44 +115,6 @@ class TestUser(unittest.TestCase):
|
|||
|
||||
self.assertTrue("System Manager" in [d.role for d in me.get("roles")])
|
||||
|
||||
def test_user_limit_for_site(self):
|
||||
update_limits({'users': get_total_users()})
|
||||
|
||||
# reload site config
|
||||
from frappe import _dict
|
||||
frappe.local.conf = _dict(frappe.get_site_config())
|
||||
|
||||
# Create a new user
|
||||
user = frappe.new_doc('User')
|
||||
user.email = 'test_max_users@example.com'
|
||||
user.first_name = 'Test_max_user'
|
||||
|
||||
self.assertRaises(MaxUsersReachedError, user.add_roles, 'System Manager')
|
||||
|
||||
if frappe.db.exists('User', 'test_max_users@example.com'):
|
||||
delete_contact('test_max_users@example.com')
|
||||
frappe.delete_doc('User', 'test_max_users@example.com')
|
||||
|
||||
# Clear the user limit
|
||||
clear_limit('users')
|
||||
|
||||
def test_user_limit_for_site_with_simultaneous_sessions(self):
|
||||
clear_limit('users')
|
||||
|
||||
# make sure this user counts
|
||||
user = frappe.get_doc('User', 'test@example.com')
|
||||
user.add_roles('Website Manager')
|
||||
user.save()
|
||||
|
||||
update_limits({'users': get_total_users()})
|
||||
|
||||
user.simultaneous_sessions = user.simultaneous_sessions + 1
|
||||
|
||||
self.assertRaises(MaxUsersReachedError, user.save)
|
||||
|
||||
# Clear the user limit
|
||||
clear_limit('users')
|
||||
|
||||
# def test_deny_multiple_sessions(self):
|
||||
# from frappe.installer import update_site_config
|
||||
# clear_limit('users')
|
||||
|
|
@ -184,25 +145,6 @@ class TestUser(unittest.TestCase):
|
|||
# # first connection should fail
|
||||
# test_request(conn1)
|
||||
|
||||
def test_site_expiry(self):
|
||||
user = frappe.get_doc('User', 'test@example.com')
|
||||
user.enabled = 1
|
||||
user.new_password = 'Eastern_43A1W'
|
||||
user.save()
|
||||
|
||||
update_limits({'expiry': add_to_date(today(), days=-1), 'support_email': 'support@example.com'})
|
||||
frappe.local.conf = _dict(frappe.get_site_config())
|
||||
|
||||
frappe.db.commit()
|
||||
|
||||
res = requests.post(get_url(), params={'cmd': 'login', 'usr':
|
||||
'test@example.com', 'pwd': 'Eastern_43A1W', 'device': 'desktop'})
|
||||
|
||||
# While site is expired status code returned is 417 Failed Expectation
|
||||
self.assertEqual(res.status_code, 417)
|
||||
|
||||
clear_limit("expiry")
|
||||
frappe.local.conf = _dict(frappe.get_site_config())
|
||||
|
||||
def test_delete_user(self):
|
||||
new_user = frappe.get_doc(dict(doctype='User', email='test-for-delete@example.com',
|
||||
|
|
@ -227,26 +169,6 @@ class TestUser(unittest.TestCase):
|
|||
frappe.delete_doc('User', new_user.name)
|
||||
self.assertFalse(frappe.db.exists('User', new_user.name))
|
||||
|
||||
def test_deactivate_additional_users(self):
|
||||
update_limits({'users': get_total_users()+1})
|
||||
|
||||
if not frappe.db.exists("User", "test_deactivate_additional_users@example.com"):
|
||||
user = frappe.new_doc('User')
|
||||
user.email = 'test_deactivate_additional_users@example.com'
|
||||
user.first_name = 'Test Deactivate Additional Users'
|
||||
user.add_roles("System Manager")
|
||||
|
||||
#update limits
|
||||
update_limits({"users": get_total_users()-1})
|
||||
self.assertEqual(frappe.db.get_value("User", "test_deactivate_additional_users@example.com", "enabled"), 0)
|
||||
|
||||
if frappe.db.exists("User", "test_deactivate_additional_users@example.com"):
|
||||
delete_contact('test_deactivate_additional_users@example.com')
|
||||
frappe.delete_doc('User', 'test_deactivate_additional_users@example.com')
|
||||
|
||||
# Clear the user limit
|
||||
clear_limit('users')
|
||||
|
||||
def test_password_strength(self):
|
||||
# Test Password without Password Strenth Policy
|
||||
frappe.db.set_value("System Settings", "System Settings", "enable_password_policy", 0)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import frappe.share
|
|||
import re
|
||||
import json
|
||||
|
||||
from frappe.limits import get_limits
|
||||
from frappe.website.utils import is_signup_enabled
|
||||
from frappe.utils.background_jobs import enqueue
|
||||
|
||||
|
|
@ -91,7 +90,6 @@ class User(Document):
|
|||
|
||||
def on_update(self):
|
||||
# clear new password
|
||||
self.validate_user_limit()
|
||||
self.share_with_self()
|
||||
clear_notifications(user=self.name)
|
||||
frappe.clear_cache(user=self.name)
|
||||
|
|
@ -474,34 +472,6 @@ 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)
|
||||
|
||||
def validate_user_email_inbox(self):
|
||||
""" check if same email account added in User Emails twice """
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
#page-usage-info .indicator-right::after {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
<div>
|
||||
{% if limits.upgrade_url %}
|
||||
<div class="upgrade-message padding" style="border-bottom: 1px solid #d0d8dc;">
|
||||
{% if limits.expiry %}
|
||||
<h4>{{ __("You have {0} days left in your subscription", [days_to_expiry]) }}</h4>
|
||||
{% else %}
|
||||
<h4>{{ __("You have subscribed for one user free plan") }}</h4>
|
||||
{% endif %}
|
||||
|
||||
<p>Upgrade to a premium plan with more users, storage and priority support.</p>
|
||||
<button class="btn btn-primary btn-sm primary-action">Upgrade</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if limits.users %}
|
||||
{% var users_percent = ((enabled_users / limits.users) * 100); %}
|
||||
<div class="usage-info-section" style="margin: 30px;">
|
||||
<h4>{{ __("Users") }}</h4>
|
||||
|
||||
<div class="progress" style="margin-bottom: 0;">
|
||||
<div class="progress-bar progress-bar-{%= (users_percent < 75 ? "success" : "warning") %}" style="width: {{ users_percent }}%">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>{%= enabled_users %} out of {%= limits.users %} enabled</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if limits.emails %}
|
||||
<div class="usage-info-section" style="margin: 30px;">
|
||||
<h4>{{ __("Emails") }}</h4>
|
||||
|
||||
{% var email_percent = (( emails_sent / limits.emails ) * 100); %}
|
||||
{% var emails_remaining = (limits.emails - emails_sent) %}
|
||||
|
||||
<div class="progress" style="margin-bottom: 0;">
|
||||
<div class="progress-bar progress-bar-{%= (email_percent < 75 ? "success" : "warning") %}" style="width: {{ email_percent }}%">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>{%= emails_sent %} out of {%= limits.emails %} sent this month</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if limits.space %}
|
||||
<div class="usage-info-section" style="margin: 30px;">
|
||||
<h4>{{ __("Space") }}</h4>
|
||||
|
||||
<div class="progress" style="margin-bottom: 0;">
|
||||
<div class="progress-bar" style="width: {%= database_percent %}%; background-color: #5e64ff"></div>
|
||||
<div class="progress-bar" style="width: {%= files_percent %}%; background-color: #743ee2"></div>
|
||||
<div class="progress-bar" style="width: {%= backup_percent %}%; background-color: #7CD6FD"></div>
|
||||
</div>
|
||||
|
||||
<span class="indicator blue" style="margin-right: 20px;">
|
||||
{{ __("Database Size:") }} {%= limits.space_usage.database_size %} MB
|
||||
</span>
|
||||
<span class="indicator purple" style="margin-right: 20px;">
|
||||
{{ __("Files Size:") }} {%= limits.space_usage.files_size %} MB
|
||||
</span>
|
||||
<span class="indicator lightblue" style="margin-right: 20px;">
|
||||
{{ __("Backup Size:") }} {%= limits.space_usage.backup_size %} MB
|
||||
</span>
|
||||
|
||||
<p>{{ usage_message }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
frappe.pages['usage-info'].on_page_load = function(wrapper) {
|
||||
var page = frappe.ui.make_app_page({
|
||||
parent: wrapper,
|
||||
title: 'Usage Info',
|
||||
single_column: true
|
||||
});
|
||||
|
||||
frappe.call({
|
||||
method: "frappe.limits.get_usage_info",
|
||||
callback: function(r) {
|
||||
var usage_info = r.message;
|
||||
if (!usage_info) {
|
||||
// nothing to show
|
||||
// TODO improve this
|
||||
return;
|
||||
}
|
||||
|
||||
let limits = usage_info.limits;
|
||||
let database_percent = (limits.space_usage.database_size / limits.space) * 100;
|
||||
let files_percent = (limits.space_usage.files_size / limits.space) * 100;
|
||||
let backup_percent = (limits.space_usage.backup_size / limits.space) * 100;
|
||||
|
||||
let total_consumed = database_percent + files_percent + backup_percent;
|
||||
|
||||
let last_part = backup_percent;
|
||||
if (total_consumed > 100) {
|
||||
last_part = backup_percent - (total_consumed - 100);
|
||||
}
|
||||
backup_percent = last_part;
|
||||
|
||||
let usage_message = '';
|
||||
if (limits.space_usage.total > limits.space) {
|
||||
usage_message = __('You have used up all of the space allotted to you. Please buy more space in your subscription.');
|
||||
} else {
|
||||
let available = flt(limits.space - limits.space_usage.total, 2);
|
||||
usage_message = __('{0} available out of {1}', [(available + ' MB').bold(), (limits.space + ' MB').bold()]);
|
||||
}
|
||||
|
||||
$(frappe.render_template("usage_info", Object.assign(usage_info, {
|
||||
database_percent,
|
||||
files_percent,
|
||||
backup_percent,
|
||||
usage_message
|
||||
}))).appendTo(page.main);
|
||||
|
||||
var btn_text = usage_info.limits.users == 1 ? __("Upgrade") : __("Renew / Upgrade");
|
||||
$(page.main).find('.btn-primary').html(btn_text).on('click', () => {
|
||||
window.open(usage_info.upgrade_url);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"content": null,
|
||||
"creation": "2016-06-02 18:14:53.475842",
|
||||
"docstatus": 0,
|
||||
"doctype": "Page",
|
||||
"idx": 0,
|
||||
"modified": "2016-06-02 18:14:53.475842",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "usage-info",
|
||||
"owner": "Administrator",
|
||||
"page_name": "usage-info",
|
||||
"roles": [
|
||||
{
|
||||
"role": "System Manager"
|
||||
}
|
||||
],
|
||||
"script": null,
|
||||
"standard": "Yes",
|
||||
"style": null,
|
||||
"title": "Usage Info"
|
||||
}
|
||||
|
|
@ -13,13 +13,13 @@ class EmailGroup(Document):
|
|||
def onload(self):
|
||||
singles = [d.name for d in frappe.db.get_all("DocType", "name", {"issingle": 1})]
|
||||
self.get("__onload").import_types = [{"value": d.parent, "label": "{0} ({1})".format(d.parent, d.label)} \
|
||||
for d in frappe.db.get_all("DocField", ("parent", "label"), {"options": "Email"})
|
||||
for d in frappe.db.get_all("DocField", ("parent", "label"), {"options": "Email"})
|
||||
if d.parent not in singles]
|
||||
|
||||
def import_from(self, doctype):
|
||||
"""Extract Email Addresses from given doctype and add them to the current list"""
|
||||
meta = frappe.get_meta(doctype)
|
||||
email_field = [d.fieldname for d in meta.fields
|
||||
email_field = [d.fieldname for d in meta.fields
|
||||
if d.fieldtype in ("Data", "Small Text", "Text", "Code") and d.options=="Email"][0]
|
||||
unsubscribed_field = "unsubscribed" if meta.get_field("unsubscribed") else None
|
||||
added = 0
|
||||
|
|
@ -90,13 +90,3 @@ def add_subscribers(name, email_list):
|
|||
|
||||
return frappe.get_doc("Email Group", name).update_total_subscribers()
|
||||
|
||||
def restrict_email_group(doc, method):
|
||||
from frappe.limits import get_limits
|
||||
|
||||
email_group_limit = get_limits().get('email_group')
|
||||
if not email_group_limit:
|
||||
return
|
||||
|
||||
email_group = frappe.get_doc("Email Group", doc.email_group)
|
||||
if email_group.get_total_subscribers() >= email_group_limit:
|
||||
frappe.throw(_("Please Upgrade to add more than {0} subscribers").format(email_group_limit))
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import frappe
|
|||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.email.queue import send_one
|
||||
from frappe.limits import get_limits
|
||||
from frappe.utils import now_datetime
|
||||
|
||||
|
||||
|
|
@ -17,13 +16,6 @@ class EmailQueue(Document):
|
|||
for r in recipients:
|
||||
self.append("recipients", {"recipient":r, "status":"Not Sent"})
|
||||
|
||||
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'))
|
||||
|
||||
def get_duplicate(self, recipients):
|
||||
values = self.as_dict()
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ app_include_js = [
|
|||
"assets/js/form.min.js",
|
||||
"assets/js/control.min.js",
|
||||
"assets/js/report.min.js",
|
||||
"assets/frappe/js/frappe/toolbar.js"
|
||||
]
|
||||
app_include_css = [
|
||||
"assets/css/desk.min.css",
|
||||
|
|
@ -76,7 +75,6 @@ calendars = ["Event"]
|
|||
on_session_creation = [
|
||||
"frappe.core.doctype.activity_log.feed.login_feed",
|
||||
"frappe.core.doctype.user.user.notify_admin_access_to_system_manager",
|
||||
"frappe.limits.check_if_expired",
|
||||
"frappe.utils.scheduler.reset_enabled_scheduler_events",
|
||||
]
|
||||
|
||||
|
|
@ -138,9 +136,6 @@ doc_events = {
|
|||
"on_change": [
|
||||
"frappe.social.doctype.energy_point_rule.energy_point_rule.process_energy_points"
|
||||
],
|
||||
},
|
||||
"Email Group Member": {
|
||||
"validate": "frappe.email.doctype.email_group.email_group.restrict_email_group"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -161,8 +156,7 @@ scheduler_events = {
|
|||
'frappe.model.utils.user_settings.sync_user_settings',
|
||||
"frappe.utils.error.collect_error_snapshots",
|
||||
"frappe.desk.page.backups.backups.delete_downloadable_backups",
|
||||
"frappe.limits.update_space_usage",
|
||||
"frappe.limits.update_site_usage",
|
||||
"frappe.desk.doctype.auto_repeat.auto_repeat.make_auto_repeat_entry",
|
||||
"frappe.deferred_insert.save_to_db",
|
||||
"frappe.desk.form.document_follow.send_hourly_updates",
|
||||
],
|
||||
|
|
@ -174,7 +168,6 @@ scheduler_events = {
|
|||
"frappe.sessions.clear_expired_sessions",
|
||||
"frappe.email.doctype.notification.notification.trigger_daily_alerts",
|
||||
"frappe.realtime.remove_old_task_logs",
|
||||
"frappe.utils.scheduler.disable_scheduler_on_expiry",
|
||||
"frappe.utils.scheduler.restrict_scheduler_events_if_dormant",
|
||||
"frappe.email.doctype.auto_email_report.auto_email_report.send_daily",
|
||||
"frappe.core.doctype.activity_log.activity_log.clear_authentication_logs",
|
||||
|
|
@ -236,7 +229,6 @@ bot_parsers = [
|
|||
]
|
||||
|
||||
setup_wizard_exception = "frappe.desk.page.setup_wizard.setup_wizard.email_setup_wizard_exception"
|
||||
before_write_file = "frappe.limits.validate_space_limit"
|
||||
|
||||
before_migrate = ['frappe.patches.v11_0.sync_user_permission_doctype_before_migrate.execute']
|
||||
after_migrate = ['frappe.website.doctype.website_theme.website_theme.generate_theme_files_if_not_exist']
|
||||
|
|
|
|||
233
frappe/limits.py
233
frappe/limits.py
|
|
@ -1,233 +0,0 @@
|
|||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
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.utils.user import get_enabled_system_users, disable_users
|
||||
from frappe.utils.__init__ import get_site_info
|
||||
import os, subprocess, json
|
||||
from six.moves.urllib.parse import parse_qsl, urlsplit, urlunsplit, urlencode
|
||||
from six import string_types
|
||||
|
||||
class SiteExpiredError(frappe.ValidationError):
|
||||
http_status_code = 417
|
||||
|
||||
EXPIRY_WARNING_DAYS = 10
|
||||
|
||||
def check_if_expired():
|
||||
"""check if account is expired. If expired, do not allow login"""
|
||||
if not has_expired():
|
||||
return
|
||||
|
||||
limits = get_limits()
|
||||
expiry = limits.get("expiry")
|
||||
|
||||
if not expiry:
|
||||
return
|
||||
|
||||
expires_on = formatdate(limits.get("expiry"))
|
||||
support_email = limits.get("support_email")
|
||||
|
||||
if limits.upgrade_url:
|
||||
message = _("""Your subscription expired on {0}. To renew, {1}.""").format(expires_on, get_upgrade_link(limits.upgrade_url))
|
||||
|
||||
elif support_email:
|
||||
message = _("""Your subscription expired on {0}. To renew, please send an email to {1}.""").format(expires_on, support_email)
|
||||
|
||||
else:
|
||||
# no recourse just quit
|
||||
return
|
||||
|
||||
frappe.throw(message, SiteExpiredError)
|
||||
|
||||
def has_expired():
|
||||
if frappe.session.user=="Administrator":
|
||||
return False
|
||||
|
||||
expires_on = get_limits().expiry
|
||||
if not expires_on:
|
||||
return False
|
||||
|
||||
if now_datetime().date() <= getdate(expires_on):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_expiry_message():
|
||||
if "System Manager" not in frappe.get_roles():
|
||||
return ""
|
||||
|
||||
limits = get_limits()
|
||||
if not limits.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 {0}.").format(formatdate(expires_on))
|
||||
|
||||
if message and limits.upgrade_url:
|
||||
upgrade_link = get_upgrade_link(limits.upgrade_url)
|
||||
message += ' ' + _('To renew, {0}.').format(upgrade_link)
|
||||
|
||||
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 or 0) * 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': len(get_enabled_system_users()),
|
||||
'emails_sent': get_emails_sent_this_month(),
|
||||
'space_usage': limits.space_usage['total'],
|
||||
})
|
||||
|
||||
if limits.expiry:
|
||||
usage_info['expires_on'] = formatdate(limits.expiry)
|
||||
usage_info['days_to_expiry'] = (getdate(limits.expiry) - getdate()).days
|
||||
|
||||
if limits.upgrade_url:
|
||||
usage_info['upgrade_url'] = get_upgrade_url(limits.upgrade_url)
|
||||
|
||||
return usage_info
|
||||
|
||||
def get_upgrade_url(upgrade_url):
|
||||
parts = urlsplit(upgrade_url)
|
||||
params = dict(parse_qsl(parts.query))
|
||||
params.update({
|
||||
'site': frappe.local.site,
|
||||
'email': frappe.session.user,
|
||||
'full_name': get_fullname(),
|
||||
'country': frappe.db.get_value("System Settings", "System Settings", 'country')
|
||||
})
|
||||
|
||||
query = urlencode(params, doseq=True)
|
||||
url = urlunsplit((parts.scheme, parts.netloc, parts.path, query, parts.fragment))
|
||||
return url
|
||||
|
||||
def get_upgrade_link(upgrade_url, label=None):
|
||||
upgrade_url = get_upgrade_url(upgrade_url)
|
||||
upgrade_link = '<a href="{upgrade_url}" target="_blank">{click_here}</a>'.format(upgrade_url=upgrade_url, click_here=label or _('click here'))
|
||||
return upgrade_link
|
||||
|
||||
def get_limits():
|
||||
'''
|
||||
"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(limits_dict):
|
||||
'''Add/Update limit in site_config'''
|
||||
limits = get_limits()
|
||||
limits.update(limits_dict)
|
||||
update_site_config("limits", limits, validate=False)
|
||||
disable_users(limits)
|
||||
frappe.local.conf.limits = limits
|
||||
|
||||
def clear_limit(key):
|
||||
'''Remove a limit option from site_config'''
|
||||
limits = get_limits()
|
||||
to_clear = [key] if isinstance(key, string_types) else key
|
||||
for key in to_clear:
|
||||
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.core.doctype.file.file 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(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 = frappe.db.get_database_size()
|
||||
|
||||
usage = {
|
||||
'files_size': flt(files_size, 2),
|
||||
'backup_size': flt(backup_size, 2),
|
||||
'database_size': flt(database_size, 2),
|
||||
'total': flt(flt(files_size) + flt(backup_size) + flt(database_size), 2)
|
||||
}
|
||||
|
||||
update_limits({ 'space_usage': usage })
|
||||
|
||||
return usage
|
||||
|
||||
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], 2)
|
||||
|
||||
def update_site_usage():
|
||||
data = get_site_info()
|
||||
with open(os.path.join(frappe.get_site_path(), 'site_data.json'), 'w') as outfile:
|
||||
json.dump(data, outfile)
|
||||
outfile.close()
|
||||
|
|
@ -156,7 +156,6 @@ frappe.patches.v7_0.update_send_after_in_bulk_email
|
|||
execute:frappe.db.sql('''delete from `tabSingles` where doctype="Email Settings"''') # 2016-06-13
|
||||
execute:frappe.db.sql("delete from `tabWeb Page` where ifnull(template_path, '')!=''")
|
||||
frappe.patches.v7_0.rename_newsletter_list_to_email_group
|
||||
frappe.patches.v7_0.replace_upgrade_link_limit
|
||||
frappe.patches.v7_0.set_email_group
|
||||
frappe.patches.v7_1.setup_integration_services #2016-10-27
|
||||
frappe.patches.v7_1.rename_chinese_language_codes
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.limits import get_limits, clear_limit, update_limits
|
||||
|
||||
def execute():
|
||||
limits = get_limits()
|
||||
if limits and limits.upgrade_link:
|
||||
upgrade_url = limits.upgrade_link
|
||||
clear_limit('upgrade_link')
|
||||
update_limits({'upgrade_url': upgrade_url})
|
||||
|
|
@ -32,11 +32,9 @@ frappe.views.ListSidebar = class ListSidebar {
|
|||
this.setup_keyboard_shortcuts();
|
||||
this.setup_list_group_by();
|
||||
|
||||
let limits = frappe.boot.limits;
|
||||
|
||||
if (limits.upgrade_url && limits.expiry && !frappe.flags.upgrade_dismissed) {
|
||||
this.setup_upgrade_box();
|
||||
}
|
||||
// do not remove
|
||||
// used to trigger custom scripts
|
||||
$(document).trigger('list_sidebar_setup');
|
||||
|
||||
if (this.list_view.list_view_settings && this.list_view.list_view_settings.disable_sidebar_stats) {
|
||||
this.sidebar.find('.sidebar-stat').remove();
|
||||
|
|
@ -274,35 +272,6 @@ frappe.views.ListSidebar = class ListSidebar {
|
|||
});
|
||||
}
|
||||
|
||||
setup_upgrade_box() {
|
||||
let upgrade_list = $(`<ul class="list-unstyled sidebar-menu"></ul>`).appendTo(this.sidebar);
|
||||
|
||||
// Show Renew/Upgrade button,
|
||||
// if account is holding one user free plan or
|
||||
// if account's expiry date within range of 30 days from today's date
|
||||
|
||||
let upgrade_date = frappe.datetime.add_days(frappe.datetime.get_today(), 30);
|
||||
if (frappe.boot.limits.users === 1 || upgrade_date >= frappe.boot.limits.expiry) {
|
||||
let upgrade_box = $(`<div class="border" style="
|
||||
padding: 0px 10px;
|
||||
border-radius: 3px;
|
||||
">
|
||||
<a><i class="octicon octicon-x pull-right close" style="margin-top: 10px;"></i></a>
|
||||
<h5>Go Premium</h5>
|
||||
<p>Upgrade to a premium plan with more users, storage and priority support.</p>
|
||||
<button class="btn btn-xs btn-default btn-upgrade" style="margin-bottom: 10px;"> Renew / Upgrade </button>
|
||||
</div>`).appendTo(upgrade_list);
|
||||
|
||||
upgrade_box.find('.btn-upgrade').on('click', () => {
|
||||
frappe.set_route('usage-info');
|
||||
});
|
||||
|
||||
upgrade_box.find('.close').on('click', () => {
|
||||
upgrade_list.remove();
|
||||
frappe.flags.upgrade_dismissed = 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get_cat_tags() {
|
||||
return this.cat_tags;
|
||||
|
|
|
|||
|
|
@ -1,54 +0,0 @@
|
|||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd.
|
||||
// For license information, please see license.txt
|
||||
|
||||
$(document).on("toolbar_setup", function() {
|
||||
var help_links = [];
|
||||
var limits = frappe.boot.limits;
|
||||
|
||||
if(frappe.boot.expiry_message) {
|
||||
var expiry_message_shown = localStorage.expiry_message_shown;
|
||||
|
||||
// if message is more than a day old, show message again
|
||||
if (!(expiry_message_shown
|
||||
&& (new Date() - new Date(expiry_message_shown) < 86400000))) {
|
||||
|
||||
localStorage.expiry_message_shown = new Date();
|
||||
frappe.msgprint(frappe.boot.expiry_message);
|
||||
}
|
||||
}
|
||||
|
||||
$(help_links.join("\n")).insertBefore($("#toolbar-user").find(".divider:last"));
|
||||
|
||||
if(limits.space || limits.users || limits.expiry || limits.emails) {
|
||||
help_links = [];
|
||||
help_links.push('<li class="usage-info-link"><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 limits = frappe.boot.limits;
|
||||
var usage = limits.space_usage;
|
||||
if (!usage) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if(!usage.sidebar_usage_html) {
|
||||
if (limits.space) {
|
||||
usage.total_used_percent = cint(usage.total / 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 }}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 usage.sidebar_usage_html;
|
||||
}
|
||||
|
|
@ -116,7 +116,6 @@ def get():
|
|||
from frappe.desk.notifications import \
|
||||
get_notification_info_for_boot, get_notifications
|
||||
from frappe.boot import get_bootinfo, get_unseen_notes
|
||||
from frappe.limits import get_limits, get_expiry_message
|
||||
|
||||
bootinfo = None
|
||||
if not getattr(frappe.conf,'disable_session_cache', None):
|
||||
|
|
@ -160,9 +159,6 @@ def get():
|
|||
|
||||
bootinfo["setup_complete"] = cint(frappe.db.get_single_value('System Settings', 'setup_complete'))
|
||||
|
||||
# limits
|
||||
bootinfo.limits = get_limits()
|
||||
bootinfo.expiry_message = get_expiry_message()
|
||||
|
||||
return bootinfo
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@ from __future__ import unicode_literals
|
|||
from unittest import TestCase
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from frappe.utils.scheduler import (enqueue_applicable_events, restrict_scheduler_events_if_dormant,
|
||||
get_enabled_scheduler_events, disable_scheduler_on_expiry)
|
||||
get_enabled_scheduler_events)
|
||||
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 update_limits, clear_limit
|
||||
|
||||
import frappe
|
||||
import time
|
||||
|
|
@ -68,42 +67,7 @@ class TestScheduler(TestCase):
|
|||
frappe.flags.enabled_events = None
|
||||
|
||||
|
||||
def test_restrict_scheduler_events(self):
|
||||
frappe.set_user("Administrator")
|
||||
dormant_date = add_days(today(), -5)
|
||||
frappe.db.sql('UPDATE `tabUser` SET `last_active`=%s', dormant_date)
|
||||
|
||||
restrict_scheduler_events_if_dormant()
|
||||
frappe.local.conf = _dict(frappe.get_site_config())
|
||||
|
||||
self.assertFalse("all" in get_enabled_scheduler_events())
|
||||
self.assertTrue(frappe.conf.get('dormant', False))
|
||||
|
||||
clear_limit("expiry")
|
||||
frappe.local.conf = _dict(frappe.get_site_config())
|
||||
|
||||
|
||||
def test_disable_scheduler_on_expiry(self):
|
||||
update_limits({'expiry': add_to_date(today(), days=-1)})
|
||||
frappe.local.conf = _dict(frappe.get_site_config())
|
||||
|
||||
if not frappe.db.exists('User', 'test_scheduler@example.com'):
|
||||
user = frappe.new_doc('User')
|
||||
user.email = 'test_scheduler@example.com'
|
||||
user.first_name = 'Test_scheduler'
|
||||
user.save()
|
||||
user.add_roles('System Manager')
|
||||
|
||||
frappe.db.commit()
|
||||
frappe.set_user("test_scheduler@example.com")
|
||||
|
||||
disable_scheduler_on_expiry()
|
||||
|
||||
ss = frappe.get_doc("System Settings")
|
||||
self.assertFalse(ss.enable_scheduler)
|
||||
|
||||
clear_limit("expiry")
|
||||
frappe.local.conf = _dict(frappe.get_site_config())
|
||||
|
||||
|
||||
def test_job_timeout(self):
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import os
|
|||
from frappe.utils import get_sites
|
||||
from datetime import datetime
|
||||
from frappe.utils.background_jobs import enqueue, get_jobs, queue_timeout
|
||||
from frappe.limits import has_expired
|
||||
from frappe.utils.data import get_datetime, now_datetime
|
||||
from frappe.core.doctype.user.user import STANDARD_USERS
|
||||
from frappe.installer import update_site_config
|
||||
|
|
@ -304,9 +303,6 @@ def reset_enabled_scheduler_events(login_manager):
|
|||
if is_dormant:
|
||||
update_site_config('dormant', 'None')
|
||||
|
||||
def disable_scheduler_on_expiry():
|
||||
if has_expired():
|
||||
disable_scheduler()
|
||||
|
||||
def restrict_scheduler_events_if_dormant():
|
||||
if is_dormant():
|
||||
|
|
|
|||
|
|
@ -306,40 +306,6 @@ def set_last_active_to_now(user):
|
|||
from frappe.utils import now_datetime
|
||||
frappe.db.set_value("User", user, "last_active", now_datetime())
|
||||
|
||||
def disable_users(limits=None):
|
||||
if not limits:
|
||||
return
|
||||
|
||||
if limits.get('users'):
|
||||
system_manager = get_system_managers(only_name=True)
|
||||
user_list = ['Administrator', 'Guest']
|
||||
if system_manager:
|
||||
user_list.append(system_manager[-1])
|
||||
#exclude system manager from active user list
|
||||
# active_users = frappe.db.sql_list("""select name from tabUser
|
||||
# where name not in ('Administrator', 'Guest', %s) and user_type = 'System User' and enabled=1
|
||||
# order by creation desc""", system_manager)
|
||||
|
||||
active_users = frappe.get_all("User", filters={"user_type":"System User", "enabled":1, "name": ["not in", user_list]}, fields=["name"])
|
||||
|
||||
user_limit = cint(limits.get('users')) - 1
|
||||
|
||||
if len(active_users) > user_limit:
|
||||
|
||||
# if allowed user limit 1 then deactivate all additional users
|
||||
# else extract additional user from active user list and deactivate them
|
||||
if cint(limits.get('users')) != 1:
|
||||
active_users = active_users[:-1 * user_limit]
|
||||
|
||||
for user in active_users:
|
||||
frappe.db.set_value("User", user, 'enabled', 0)
|
||||
|
||||
from frappe.core.doctype.user.user import get_total_users
|
||||
|
||||
if get_total_users() > cint(limits.get('users')):
|
||||
reset_simultaneous_sessions(cint(limits.get('users')))
|
||||
|
||||
frappe.db.commit()
|
||||
|
||||
def reset_simultaneous_sessions(user_limit):
|
||||
for user in frappe.db.sql("""select name, simultaneous_sessions from tabUser
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue