Merge pull request #799 from hoellen/fix-domain-negative-values-1

don't allow negative values on domain creation/edit
master
mergify[bot] 6 years ago committed by GitHub
commit 99cd1d714b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -75,6 +75,7 @@ v1.6.0 - unreleased
- Enhancement: Contribution documentation ([#700](https://github.com/Mailu/Mailu/issues/700)) - Enhancement: Contribution documentation ([#700](https://github.com/Mailu/Mailu/issues/700))
- Enhancement: Move Mailu Docker network to a fixed subnet ([#727](https://github.com/Mailu/Mailu/issues/727)) - Enhancement: Move Mailu Docker network to a fixed subnet ([#727](https://github.com/Mailu/Mailu/issues/727))
- Enhancement: Added regex validation for alias username ([#764](https://github.com/Mailu/Mailu/issues/764)) - Enhancement: Added regex validation for alias username ([#764](https://github.com/Mailu/Mailu/issues/764))
- Enhancement: Allow to disable aliases or users for a specific domain ([#799](https://github.com/Mailu/Mailu/issues/799))
- Enhancement: Update documentation - Enhancement: Update documentation
- Enhancement: Include favicon package ([#801](https://github.com/Mailu/Mailu/issues/801), ([#802](https://github.com/Mailu/Mailu/issues/802)) - Enhancement: Include favicon package ([#801](https://github.com/Mailu/Mailu/issues/801), ([#802](https://github.com/Mailu/Mailu/issues/802))
- Enhancement: Add logging at critical places in python start.py scripts. Implement LOG_LEVEL to control verbosity ([#588](https://github.com/Mailu/Mailu/issues/588)) - Enhancement: Add logging at critical places in python start.py scripts. Implement LOG_LEVEL to control verbosity ([#588](https://github.com/Mailu/Mailu/issues/588))
@ -111,6 +112,7 @@ v1.6.0 - unreleased
- Bug: Error when trying to log in with an account without domain ([#585](https://github.com/Mailu/Mailu/issues/585)) - Bug: Error when trying to log in with an account without domain ([#585](https://github.com/Mailu/Mailu/issues/585))
- Bug: Fix rainloop permissions ([#637](https://github.com/Mailu/Mailu/issues/637)) - Bug: Fix rainloop permissions ([#637](https://github.com/Mailu/Mailu/issues/637))
- Bug: Fix broken webmail and logo url in admin ([#792](https://github.com/Mailu/Mailu/issues/792)) - Bug: Fix broken webmail and logo url in admin ([#792](https://github.com/Mailu/Mailu/issues/792))
- Bug: Don't allow negative values on domain creation/edit ([#799](https://github.com/Mailu/Mailu/issues/799))
- Bug: Don't recursivly chown on mailboxes ([#776](https://github.com/Mailu/Mailu/issues/776)) - Bug: Don't recursivly chown on mailboxes ([#776](https://github.com/Mailu/Mailu/issues/776))
- Bug: Fix forced password input for user edit ([#745](https://github.com/Mailu/Mailu/issues/745)) - Bug: Fix forced password input for user edit ([#745](https://github.com/Mailu/Mailu/issues/745))
- Bug: Fetched accounts: Password field is of type "text" ([#789](https://github.com/Mailu/Mailu/issues/789)) - Bug: Fetched accounts: Password field is of type "text" ([#789](https://github.com/Mailu/Mailu/issues/789))

@ -91,7 +91,7 @@ def user(localpart, domain_name, password, hash_scheme=None):
@click.option('-a', '--max_aliases') @click.option('-a', '--max_aliases')
@click.option('-q', '--max_quota_bytes') @click.option('-q', '--max_quota_bytes')
@flask_cli.with_appcontext @flask_cli.with_appcontext
def domain(domain_name, max_users=0, max_aliases=0, max_quota_bytes=0): def domain(domain_name, max_users=-1, max_aliases=-1, max_quota_bytes=0):
domain = models.Domain.query.get(domain_name) domain = models.Domain.query.get(domain_name)
if not domain: if not domain:
domain = models.Domain(name=domain_name) domain = models.Domain(name=domain_name)
@ -140,8 +140,8 @@ def config_update(verbose=False, delete_objects=False):
if verbose: if verbose:
print(str(domain_config)) print(str(domain_config))
domain_name = domain_config['name'] domain_name = domain_config['name']
max_users = domain_config.get('max_users', 0) max_users = domain_config.get('max_users', -1)
max_aliases = domain_config.get('max_aliases', 0) max_aliases = domain_config.get('max_aliases', -1)
max_quota_bytes = domain_config.get('max_quota_bytes', 0) max_quota_bytes = domain_config.get('max_quota_bytes', 0)
tracked_domains.add(domain_name) tracked_domains.add(domain_name)
domain = models.Domain.query.get(domain_name) domain = models.Domain.query.get(domain_name)

@ -129,8 +129,8 @@ class Domain(Base):
name = db.Column(IdnaDomain, primary_key=True, nullable=False) name = db.Column(IdnaDomain, primary_key=True, nullable=False)
managers = db.relationship('User', secondary=managers, managers = db.relationship('User', secondary=managers,
backref=db.backref('manager_of'), lazy='dynamic') backref=db.backref('manager_of'), lazy='dynamic')
max_users = db.Column(db.Integer, nullable=False, default=0) max_users = db.Column(db.Integer, nullable=False, default=-1)
max_aliases = db.Column(db.Integer, nullable=False, default=0) max_aliases = db.Column(db.Integer, nullable=False, default=-1)
max_quota_bytes = db.Column(db.Integer(), nullable=False, default=0) max_quota_bytes = db.Column(db.Integer(), nullable=False, default=0)
signup_enabled = db.Column(db.Boolean(), nullable=False, default=False) signup_enabled = db.Column(db.Boolean(), nullable=False, default=False)

@ -53,8 +53,8 @@ class LoginForm(flask_wtf.FlaskForm):
class DomainForm(flask_wtf.FlaskForm): class DomainForm(flask_wtf.FlaskForm):
name = fields.StringField(_('Domain name'), [validators.DataRequired()]) name = fields.StringField(_('Domain name'), [validators.DataRequired()])
max_users = fields_.IntegerField(_('Maximum user count'), default=10) max_users = fields_.IntegerField(_('Maximum user count'), [validators.NumberRange(min=-1)], default=10)
max_aliases = fields_.IntegerField(_('Maximum alias count'), default=10) max_aliases = fields_.IntegerField(_('Maximum alias count'), [validators.NumberRange(min=-1)], default=10)
max_quota_bytes = fields_.IntegerSliderField(_('Maximum user quota'), default=0) max_quota_bytes = fields_.IntegerSliderField(_('Maximum user quota'), default=0)
signup_enabled = fields.BooleanField(_('Enable sign-up'), default=False) signup_enabled = fields.BooleanField(_('Enable sign-up'), default=False)
comment = fields.StringField(_('Comment')) comment = fields.StringField(_('Comment'))

@ -40,8 +40,8 @@
{% endif %} {% endif %}
</td> </td>
<td>{{ domain.name }}</td> <td>{{ domain.name }}</td>
<td>{{ domain.users | count }} / {{ domain.max_users or '∞' }}</td> <td>{{ domain.users | count }} / {{ '∞' if domain.max_users == -1 else domain.max_users }}</td>
<td>{{ domain.aliases | count }} / {{ domain.max_aliases or '∞' }}</td> <td>{{ domain.aliases | count }} / {{ '∞' if domain.max_aliases == -1 else domain.max_aliases }}</td>
<td>{{ domain.comment or '' }}</td> <td>{{ domain.comment or '' }}</td>
<td>{{ domain.created_at }}</td> <td>{{ domain.created_at }}</td>
<td>{{ domain.updated_at or '' }}</td> <td>{{ domain.updated_at or '' }}</td>

@ -18,7 +18,7 @@
{% for domain_name, domain in available_domains.items() %} {% for domain_name, domain in available_domains.items() %}
<tr> <tr>
<td><a href="{{ url_for('.user_signup', domain_name=domain_name) }}">{{ domain_name }}</a></td> <td><a href="{{ url_for('.user_signup', domain_name=domain_name) }}">{{ domain_name }}</a></td>
<td>{{ domain.max_users - (domain.users | count) if domain.max_users else '∞' }}</td> <td>{{ '∞' if domain.max_users == -1 else domain.max_users - (domain.users | count)}}</td>
<td>{{ domain.max_quota_bytes or config['DEFAULT_QUOTA'] | filesizeformat }}</td> <td>{{ domain.max_quota_bytes or config['DEFAULT_QUOTA'] | filesizeformat }}</td>
</tr> </tr>
{% endfor %} {% endfor %}

@ -16,7 +16,7 @@ def alias_list(domain_name):
@access.domain_admin(models.Domain, 'domain_name') @access.domain_admin(models.Domain, 'domain_name')
def alias_create(domain_name): def alias_create(domain_name):
domain = models.Domain.query.get(domain_name) or flask.abort(404) domain = models.Domain.query.get(domain_name) or flask.abort(404)
if domain.max_aliases and len(domain.aliases) >= domain.max_aliases: if not domain.max_aliases == -1 and len(domain.aliases) >= domain.max_aliases:
flask.flash('Too many aliases for domain %s' % domain, 'error') flask.flash('Too many aliases for domain %s' % domain, 'error')
return flask.redirect( return flask.redirect(
flask.url_for('.alias_list', domain_name=domain.name)) flask.url_for('.alias_list', domain_name=domain.name))

@ -18,7 +18,7 @@ def user_list(domain_name):
@access.domain_admin(models.Domain, 'domain_name') @access.domain_admin(models.Domain, 'domain_name')
def user_create(domain_name): def user_create(domain_name):
domain = models.Domain.query.get(domain_name) or flask.abort(404) domain = models.Domain.query.get(domain_name) or flask.abort(404)
if domain.max_users and len(domain.users) >= domain.max_users: if not domain.max_users == -1 and len(domain.users) >= domain.max_users:
flask.flash('Too many users for domain %s' % domain, 'error') flask.flash('Too many users for domain %s' % domain, 'error')
return flask.redirect( return flask.redirect(
flask.url_for('.user_list', domain_name=domain.name)) flask.url_for('.user_list', domain_name=domain.name))
@ -168,7 +168,7 @@ def user_signup(domain_name=None):
available_domains = { available_domains = {
domain.name: domain domain.name: domain
for domain in models.Domain.query.filter_by(signup_enabled=True).all() for domain in models.Domain.query.filter_by(signup_enabled=True).all()
if not domain.max_users or len(domain.users) < domain.max_users if domain.max_users == -1 or len(domain.users) < domain.max_users
} }
if not available_domains: if not available_domains:
flask.flash('No domain available for registration') flask.flash('No domain available for registration')

@ -0,0 +1,65 @@
"""change default unlimited value for max_users and max_aliases to -1
Revision ID: fc099bd15cbe
Revises: cd79ed46d9c2
Create Date: 2019-01-06 13:40:23.372373
"""
# revision identifiers, used by Alembic.
revision = 'fc099bd15cbe'
down_revision = 'cd79ed46d9c2'
from alembic import op
import sqlalchemy as sa
domain_table = sa.Table(
'domain',
sa.MetaData(),
sa.Column('max_users', sa.Integer(), nullable=False),
sa.Column('max_aliases', sa.Integer(), nullable=False),
)
def upgrade():
connection = op.get_bind()
connection.execute(
domain_table.update().where(
domain_table.c.max_users == 0
).values(
max_users=-1
)
)
connection.execute(
domain_table.update().where(
domain_table.c.max_aliases == 0
).values(
max_aliases=-1
)
)
#set new unlimited default to -1
with op.batch_alter_table('domain') as batch:
batch.alter_column('max_users', server_default='-1')
batch.alter_column('max_aliases', server_default='-1')
def downgrade():
connection = op.get_bind()
connection.execute(
domain_table.update().where(
domain_table.c.max_users == -1
).values(
max_users=0
)
)
connection.execute(
domain_table.update().where(
domain_table.c.max_aliases == -1
).values(
max_aliases=0
)
)
#set default to 0
with op.batch_alter_table('domain') as batch:
batch.alter_column('max_users', server_default='0')
batch.alter_column('max_aliases', server_default='0')
Loading…
Cancel
Save