mirror of
https://github.com/Mailu/Mailu.git
synced 2025-03-11 14:49:19 +02:00
updated remarks and docs
This commit is contained in:
parent
1e2b5f26ab
commit
10435114ec
@ -337,16 +337,19 @@ def config_import(verbose=0, secrets=False, quiet=False, color=False, update=Fal
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# verbose
|
# verbose
|
||||||
# 0 : show number of changes
|
# 0 : only show number of changes
|
||||||
# 1 : also show changes
|
# 1 : also show detailed changes
|
||||||
# 2 : also show secrets
|
# 2 : also show input data
|
||||||
# 3 : also show input data
|
# 3 : also show sql queries (also needs -s, as sql may contain secrets)
|
||||||
# 4 : also show sql queries
|
# 4 : also show tracebacks (also needs -s, as tracebacks may contain secrets)
|
||||||
# 5 : also show tracebacks
|
|
||||||
|
|
||||||
if quiet:
|
if quiet:
|
||||||
verbose = -1
|
verbose = -1
|
||||||
|
|
||||||
|
if verbose > 2 and not secrets:
|
||||||
|
print('[Warning] Verbosity level capped to 2. Specify --secrets to log sql and tracebacks.')
|
||||||
|
verbose = 2
|
||||||
|
|
||||||
color_cfg = {
|
color_cfg = {
|
||||||
'color': color or sys.stdout.isatty(),
|
'color': color or sys.stdout.isatty(),
|
||||||
'lexer': 'python',
|
'lexer': 'python',
|
||||||
@ -376,7 +379,7 @@ def config_import(verbose=0, secrets=False, quiet=False, color=False, update=Fal
|
|||||||
fmt = f' - {{:<{max([len(loc) for loc, msg in res])}}} : {{}}'
|
fmt = f' - {{:<{max([len(loc) for loc, msg in res])}}} : {{}}'
|
||||||
res = [fmt.format(loc, msg) for loc, msg in res]
|
res = [fmt.format(loc, msg) for loc, msg in res]
|
||||||
num = f'error{["s",""][len(res)==1]}'
|
num = f'error{["s",""][len(res)==1]}'
|
||||||
res.insert(0, f'[ValidationError] {len(res)} {num} occured during input validation')
|
res.insert(0, f'[ValidationError] {len(res)} {num} occurred during input validation')
|
||||||
|
|
||||||
return '\n'.join(res)
|
return '\n'.join(res)
|
||||||
|
|
||||||
@ -484,7 +487,7 @@ def config_import(verbose=0, secrets=False, quiet=False, color=False, update=Fal
|
|||||||
if backref is not None:
|
if backref is not None:
|
||||||
log('Modified', item, '{target!r} {key}: {before!r} -> {after!r}'.format(**backref))
|
log('Modified', item, '{target!r} {key}: {before!r} -> {after!r}'.format(**backref))
|
||||||
return
|
return
|
||||||
# verbose?
|
# show input data?
|
||||||
if not verbose >= 2:
|
if not verbose >= 2:
|
||||||
return
|
return
|
||||||
# hide secrets in data
|
# hide secrets in data
|
||||||
@ -532,7 +535,7 @@ def config_import(verbose=0, secrets=False, quiet=False, color=False, update=Fal
|
|||||||
except ValidationError as exc:
|
except ValidationError as exc:
|
||||||
raise click.ClickException(format_errors(exc.messages)) from exc
|
raise click.ClickException(format_errors(exc.messages)) from exc
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
if verbose >= 5:
|
if verbose >= 3:
|
||||||
raise
|
raise
|
||||||
# (yaml.scanner.ScannerError, UnicodeDecodeError, ...)
|
# (yaml.scanner.ScannerError, UnicodeDecodeError, ...)
|
||||||
raise click.ClickException(
|
raise click.ClickException(
|
||||||
@ -584,7 +587,7 @@ def config_export(full=False, secrets=False, color=False, dns=False, output=None
|
|||||||
if only:
|
if only:
|
||||||
for spec in only:
|
for spec in only:
|
||||||
if spec.split('.', 1)[0] not in MailuSchema.Meta.order:
|
if spec.split('.', 1)[0] not in MailuSchema.Meta.order:
|
||||||
raise click.ClickException(f'[ERROR] Unknown section: {spec}')
|
raise click.ClickException(f'[ValidationError] Unknown section: {spec}')
|
||||||
else:
|
else:
|
||||||
only = MailuSchema.Meta.order
|
only = MailuSchema.Meta.order
|
||||||
|
|
||||||
@ -606,7 +609,7 @@ def config_export(full=False, secrets=False, color=False, dns=False, output=None
|
|||||||
print(colorize(schema.dumps(models.MailuConfig()), **color_cfg), file=output)
|
print(colorize(schema.dumps(models.MailuConfig()), **color_cfg), file=output)
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
if spec := get_fieldspec(exc):
|
if spec := get_fieldspec(exc):
|
||||||
raise click.ClickException(f'[ERROR] Invalid filter: {spec}') from exc
|
raise click.ClickException(f'[ValidationError] Invalid filter: {spec}') from exc
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ class IdnaDomain(db.TypeDecorator):
|
|||||||
""" Stores a Unicode string in it's IDNA representation (ASCII only)
|
""" Stores a Unicode string in it's IDNA representation (ASCII only)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO: String(80) is too small?
|
# TODO: use db.String(255)?
|
||||||
impl = db.String(80)
|
impl = db.String(80)
|
||||||
|
|
||||||
def process_bind_param(self, value, dialect):
|
def process_bind_param(self, value, dialect):
|
||||||
@ -50,7 +50,7 @@ class IdnaEmail(db.TypeDecorator):
|
|||||||
""" Stores a Unicode string in it's IDNA representation (ASCII only)
|
""" Stores a Unicode string in it's IDNA representation (ASCII only)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO: String(255) is too small?
|
# TODO: use db.String(254)?
|
||||||
impl = db.String(255)
|
impl = db.String(255)
|
||||||
|
|
||||||
def process_bind_param(self, value, dialect):
|
def process_bind_param(self, value, dialect):
|
||||||
@ -314,7 +314,7 @@ class Relay(Base):
|
|||||||
__tablename__ = 'relay'
|
__tablename__ = 'relay'
|
||||||
|
|
||||||
name = db.Column(IdnaDomain, primary_key=True, nullable=False)
|
name = db.Column(IdnaDomain, primary_key=True, nullable=False)
|
||||||
# TODO: String(80) is too small?
|
# TODO: use db.String(266)? transport(8):(1)[nexthop(255)](2)
|
||||||
smtp = db.Column(db.String(80), nullable=True)
|
smtp = db.Column(db.String(80), nullable=True)
|
||||||
|
|
||||||
|
|
||||||
@ -322,9 +322,7 @@ class Email(object):
|
|||||||
""" Abstraction for an email address (localpart and domain).
|
""" Abstraction for an email address (localpart and domain).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO: validate max. total length of address (<=254)
|
# TODO: use db.String(64)?
|
||||||
|
|
||||||
# TODO: String(80) is too large (64)?
|
|
||||||
localpart = db.Column(db.String(80), nullable=False)
|
localpart = db.Column(db.String(80), nullable=False)
|
||||||
|
|
||||||
@declarative.declared_attr
|
@declarative.declared_attr
|
||||||
@ -634,7 +632,7 @@ class Token(Base):
|
|||||||
user = db.relationship(User,
|
user = db.relationship(User,
|
||||||
backref=db.backref('tokens', cascade='all, delete-orphan'))
|
backref=db.backref('tokens', cascade='all, delete-orphan'))
|
||||||
password = db.Column(db.String(255), nullable=False)
|
password = db.Column(db.String(255), nullable=False)
|
||||||
# TODO: String(255) is too large? (43 should be sufficient)
|
# TODO: use db.String(32)?
|
||||||
ip = db.Column(db.String(255))
|
ip = db.Column(db.String(255))
|
||||||
|
|
||||||
def check_password(self, password):
|
def check_password(self, password):
|
||||||
|
@ -36,7 +36,7 @@ from . import models, dkim
|
|||||||
|
|
||||||
ma = Marshmallow()
|
ma = Marshmallow()
|
||||||
|
|
||||||
# TODO: how and where to mark keys as "required" while unserializing in api?
|
# TODO: how and where to mark keys as "required" while deserializing in api?
|
||||||
# - when modifying, nothing is required (only the primary key, but this key is in the uri)
|
# - when modifying, nothing is required (only the primary key, but this key is in the uri)
|
||||||
# - the primary key from post data must not differ from the key in the uri
|
# - the primary key from post data must not differ from the key in the uri
|
||||||
# - when creating all fields without default or auto-increment are required
|
# - when creating all fields without default or auto-increment are required
|
||||||
@ -705,6 +705,7 @@ class BaseSchema(ma.SQLAlchemyAutoSchema):
|
|||||||
|
|
||||||
# add attributes required for validation from db
|
# add attributes required for validation from db
|
||||||
# TODO: this will cause validation errors if value from database does not validate
|
# TODO: this will cause validation errors if value from database does not validate
|
||||||
|
# but there should not be an invalid value in the database
|
||||||
for attr_name, field_obj in self.load_fields.items():
|
for attr_name, field_obj in self.load_fields.items():
|
||||||
if field_obj.required and attr_name not in data:
|
if field_obj.required and attr_name not in data:
|
||||||
data[attr_name] = getattr(instance, attr_name)
|
data[attr_name] = getattr(instance, attr_name)
|
||||||
|
45
docs/cli.rst
45
docs/cli.rst
@ -97,7 +97,7 @@ where mail-config.yml looks like:
|
|||||||
without ``--delete-object`` option config-update will only add/update new values but will *not* remove any entries missing in provided YAML input.
|
without ``--delete-object`` option config-update will only add/update new values but will *not* remove any entries missing in provided YAML input.
|
||||||
|
|
||||||
Users
|
Users
|
||||||
-----
|
^^^^^
|
||||||
|
|
||||||
following are additional parameters that could be defined for users:
|
following are additional parameters that could be defined for users:
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ following are additional parameters that could be defined for users:
|
|||||||
* spam_threshold
|
* spam_threshold
|
||||||
|
|
||||||
Alias
|
Alias
|
||||||
-----
|
^^^^^
|
||||||
|
|
||||||
additional fields:
|
additional fields:
|
||||||
|
|
||||||
@ -125,11 +125,11 @@ additional fields:
|
|||||||
config-export
|
config-export
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The purpose of this command is to export domain-, relay-, alias- and user-configuration in YAML or JSON format.
|
The purpose of this command is to export the complete configuration in YAML or JSON format.
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
# docker-compose exec admin flask mailu config-export --help
|
$ docker-compose exec admin flask mailu config-export --help
|
||||||
|
|
||||||
Usage: flask mailu config-export [OPTIONS] [FILTER]...
|
Usage: flask mailu config-export [OPTIONS] [FILTER]...
|
||||||
|
|
||||||
@ -152,18 +152,18 @@ filters to export only some objects or attributes (try: ``user`` or ``domain.nam
|
|||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose exec admin flask mailu config-export -o mail-config.yml
|
$ docker-compose exec admin flask mailu config-export -o mail-config.yml
|
||||||
|
|
||||||
docker-compose exec admin flask mailu config-export --dns domain.dns_mx domain.dns_spf
|
$ docker-compose exec admin flask mailu config-export --dns domain.dns_mx domain.dns_spf
|
||||||
|
|
||||||
config-import
|
config-import
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The purpose of this command is for importing domain-, relay-, alias- and user-configuration in bulk and synchronizing DB entries with an external YAML/JOSN source.
|
This command imports configuration data from an external YAML or JSON source.
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
# docker-compose exec admin flask mailu config-import --help
|
$ docker-compose exec admin flask mailu config-import --help
|
||||||
|
|
||||||
Usage: flask mailu config-import [OPTIONS] [FILENAME|-]
|
Usage: flask mailu config-import [OPTIONS] [FILENAME|-]
|
||||||
|
|
||||||
@ -211,13 +211,28 @@ mail-config.yml contains the configuration and looks like this:
|
|||||||
|
|
||||||
config-update shows the number of created/modified/deleted objects after import.
|
config-update shows the number of created/modified/deleted objects after import.
|
||||||
To suppress all messages except error messages use ``--quiet``.
|
To suppress all messages except error messages use ``--quiet``.
|
||||||
By adding the ``--verbose`` switch (one or more times) the import gets more detailed and shows exactyl what attributes changed.
|
By adding the ``--verbose`` switch (up to two times) the import gets more detailed and shows exactly what attributes changed.
|
||||||
In all messages plain-text secrets (dkim-keys, passwords) are hidden by default. Use ``--secrets`` to show secrets.
|
In all log messages plain-text secrets (dkim-keys, passwords) are hidden by default. Use ``--secrets`` to log secrets.
|
||||||
If you want to test what would be done when importing use ``--dry-run``.
|
If you want to test what would be done when importing without committing any changes, use ``--dry-run``.
|
||||||
By default config-update replaces the whole configuration. You can use ``--update`` to change the existing configuration instead.
|
|
||||||
When updating you can add new and change existing objects.
|
By default config-update replaces the whole configuration. ``--update`` allows to modify the existing configuration instead.
|
||||||
To delete an object use ``-key: value`` (To delete the domain example.com ``-name: example.com`` for example).
|
New elements will be added and existing elements will be modified.
|
||||||
To reset an attribute to default use ``-key: null`` (To reset enable_imap ``-enable_imap: null`` for example).
|
It is possible to delete a single element or prune all elements from lists and associative arrays using a special notation:
|
||||||
|
|
||||||
|
+-----------------------------+------------------+--------------------------+
|
||||||
|
| Delete what? | notation | example |
|
||||||
|
+=============================+==================+==========================+
|
||||||
|
| specific array object | ``- -key: id`` | ``- -name: example.com`` |
|
||||||
|
+-----------------------------+------------------+--------------------------+
|
||||||
|
| specific list item | ``- -id`` | ``- -user1@example.com`` |
|
||||||
|
+-----------------------------+------------------+--------------------------+
|
||||||
|
| all remaining array objects | ``- -key: null`` | ``- -email: null`` |
|
||||||
|
+-----------------------------+------------------+--------------------------+
|
||||||
|
| all remaining list items | ``- -prune-`` | ``- -prune-`` |
|
||||||
|
+-----------------------------+------------------+--------------------------+
|
||||||
|
|
||||||
|
The ``-key: null`` notation can also be used to reset an attribute to its default.
|
||||||
|
To reset *spam_threshold* to it's default *80* use ``-spam_threshold: null``.
|
||||||
|
|
||||||
This is a complete YAML template with all additional parameters that can be defined:
|
This is a complete YAML template with all additional parameters that can be defined:
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user