class ParametersForm(AdminParametersForm): """Admin parameters form.""" app = "modoboa_pdfcredentials" docstore = SeparatorField(label=_("Documents storage")) storage_dir = forms.CharField( label=_("Directory to save documents into"), initial="/var/lib/modoboa/pdf_credentials", help_text=_("Path to a directory where PDF documents will be saved"), ) security = SeparatorField(label=_("Security options")) delete_first_dl = YesNoField( label=_("Delete documents after the first download"), initial="yes", help_text=_( "Automatically delete a document just after its first download " "from this interface")) generate_at_creation = YesNoField( label=_("Generate documents only at account creation"), initial="yes", help_text=_( "Generate a new document only when a new account is created. " "If set to no, a new document will be created each time a " "password is updated."))
class ParametersForm(AdminParametersForm): app = "webmail" sep3 = SeparatorField(label=_("General")) max_attachment_size = forms.CharField( label=_("Maximum attachment size"), initial="2048", help_text=_( "Maximum attachment size in bytes (or KB, MB, GB if specified)")) sep1 = SeparatorField(label=_("IMAP settings")) imap_server = forms.CharField(label=_("Server address"), initial="127.0.0.1", help_text=_("Address of your IMAP server")) imap_secured = YesNoField( label=_("Use a secured connection"), initial="no", help_text=_("Use a secured connection to access IMAP server")) imap_port = forms.IntegerField( label=_("Server port"), initial=143, help_text=_("Listening port of your IMAP server")) sep2 = SeparatorField(label=_("SMTP settings")) smtp_server = forms.CharField(label=_("Server address"), initial="127.0.0.1", help_text=_("Address of your SMTP server")) smtp_secured_mode = forms.ChoiceField( label=_("Secured connection mode"), choices=[("none", _("None")), ("starttls", "STARTTLS"), ("ssl", "SSL/TLS")], initial="none", help_text=_("Use a secured connection to access SMTP server"), widget=InlineRadioSelect) smtp_port = forms.IntegerField( label=_("Server port"), initial=25, help_text=_("Listening port of your SMTP server")) smtp_authentication = YesNoField( label=_("Authentication required"), initial="no", help_text=_("Server needs authentication"))
class ParametersForm(AdminParametersForm): app = "modoboa_sievefilters" sep1 = SeparatorField(label=_("ManageSieve settings")) server = forms.CharField( label=_("Server address"), initial="127.0.0.1", help_text=_("Address of your MANAGESIEVE server"), widget=forms.TextInput(attrs={"class": "form-control"})) port = forms.IntegerField( label=_("Server port"), initial=4190, help_text=_("Listening port of your MANAGESIEVE server"), widget=forms.TextInput(attrs={"class": "form-control"})) starttls = YesNoField(label=_("Connect using STARTTLS"), initial="no", help_text=_("Use the STARTTLS extension")) authentication_mech = forms.ChoiceField( label=_("Authentication mechanism"), choices=supported_auth_mechs(), initial="auto", help_text=_("Prefered authentication mechanism"), widget=forms.Select(attrs={"class": "form-control"}))
class ParametersForm(AdminParametersForm): app = "radicale" server_settings = SeparatorField(label=ugettext_lazy("Server settings")) server_location = forms.CharField( label=ugettext_lazy("Server URL"), help_text=ugettext_lazy("The URL of your Radicale server. " "It will be used to construct calendar URLs."), widget=forms.TextInput(attrs={"class": "form-control"})) rights_management_sep = SeparatorField( label=ugettext_lazy("Rights management")) rights_file_path = forms.CharField( label=ugettext_lazy("Rights file's path"), initial="/etc/radicale/rights", help_text=ugettext_lazy( "Path to the file that contains rights definition"), widget=forms.TextInput(attrs={"class": "form-control"})) allow_calendars_administration = YesNoField( label=ugettext_lazy("Allow calendars administration"), initial="no", help_text=ugettext_lazy( "Allow domain administrators to manage user calendars " "(read and write)"))
def extra_mailform_fields(form_name, mailbox=None): """Define extra fields to include in mail forms. For now, only the auto-reply state can be modified. :param str form_name: form name (must be 'mailform') :param Mailbox mailbox: mailbox """ if form_name != "mailform": return [] status = False if mailbox is not None and mailbox.armessage_set.count(): status = mailbox.armessage_set.all()[0].enabled return [ ('autoreply', YesNoField( label=ugettext_lazy("Enable auto-reply"), initial="yes" if status else "no", required=False, help_text=ugettext_lazy("Enable or disable Postfix auto-reply"))) ]
class GeneralParametersForm(param_forms.AdminParametersForm): """General parameters.""" app = "core" sep1 = SeparatorField(label=ugettext_lazy("Authentication")) authentication_type = forms.ChoiceField( label=ugettext_lazy("Authentication type"), choices=[('local', ugettext_lazy("Local")), ('ldap', "LDAP")], initial="local", help_text=ugettext_lazy("The backend used for authentication"), widget=InlineRadioSelect) password_scheme = forms.ChoiceField( label=ugettext_lazy("Default password scheme"), choices=[("sha512crypt", "sha512crypt"), ("sha256crypt", "sha256crypt"), ("blfcrypt", "bcrypt"), ("md5crypt", ugettext_lazy("md5crypt (weak)")), ("sha256", ugettext_lazy("sha256 (weak)")), ("md5", ugettext_lazy("md5 (weak)")), ("crypt", ugettext_lazy("crypt (weak)")), ("plain", ugettext_lazy("plain (weak)"))], initial="sha512crypt", help_text=ugettext_lazy("Scheme used to crypt mailbox passwords"), widget=forms.Select(attrs={"class": "form-control"})) rounds_number = forms.IntegerField( label=ugettext_lazy("Rounds"), initial=70000, help_text=ugettext_lazy( "Number of rounds to use (only used by sha256crypt and " "sha512crypt). Must be between 1000 and 999999999, inclusive."), widget=forms.TextInput(attrs={"class": "form-control"})) secret_key = forms.CharField( label=ugettext_lazy("Secret key"), initial=random_key(), help_text=ugettext_lazy("Key used to encrypt/decrypt passwords"), widget=forms.TextInput(attrs={"class": "form-control"})) default_password = forms.CharField( label=ugettext_lazy("Default password"), initial="password", help_text=ugettext_lazy( "Default password for automatically created accounts.")) random_password_length = forms.IntegerField( label=ugettext_lazy("Random password length"), min_value=8, initial=8, help_text=ugettext_lazy("Length of randomly generated passwords.")) # LDAP specific settings ldap_sep = SeparatorField(label=ugettext_lazy("LDAP settings")) ldap_server_address = forms.CharField( label=ugettext_lazy("Server address"), initial="localhost", help_text=ugettext_lazy( "The IP address or the DNS name of the LDAP server"), widget=forms.TextInput(attrs={"class": "form-control"})) ldap_server_port = forms.IntegerField( label=ugettext_lazy("Server port"), initial=389, help_text=ugettext_lazy("The TCP port number used by the LDAP server"), widget=forms.TextInput(attrs={"class": "form-control"})) ldap_secured = YesNoField( label=ugettext_lazy("Use a secured connection"), initial=False, help_text=ugettext_lazy( "Use an SSL/TLS connection to access the LDAP server")) ldap_auth_method = forms.ChoiceField( label=ugettext_lazy("Authentication method"), choices=[('searchbind', ugettext_lazy("Search and bind")), ('directbind', ugettext_lazy("Direct bind"))], initial='searchbind', help_text=ugettext_lazy("Choose the authentication method to use"), widget=forms.Select(attrs={"class": "form-control"})) ldap_bind_dn = forms.CharField( label=ugettext_lazy("Bind DN"), initial='', help_text=ugettext_lazy( "The distinguished name to use when binding to the LDAP server. " "Leave empty for an anonymous bind"), required=False, widget=forms.TextInput(attrs={"class": "form-control"})) ldap_bind_password = forms.CharField( label=ugettext_lazy("Bind password"), initial='', help_text=ugettext_lazy( "The password to use when binding to the LDAP server " "(with 'Bind DN')"), widget=forms.PasswordInput(attrs={"class": "form-control"}, render_value=True), required=False) ldap_search_base = forms.CharField( label=ugettext_lazy("Users search base"), initial="", help_text=ugettext_lazy( "The distinguished name of the search base used to find users"), required=False, widget=forms.TextInput(attrs={"class": "form-control"})) ldap_search_filter = forms.CharField( label=ugettext_lazy("Search filter"), initial="(mail=%(user)s)", help_text=ugettext_lazy( "An optional filter string (e.g. '(objectClass=person)'). " "In order to be valid, it must be enclosed in parentheses."), required=False, widget=forms.TextInput(attrs={"class": "form-control"})) ldap_user_dn_template = forms.CharField( label=ugettext_lazy("User DN template"), initial="", help_text=ugettext_lazy( "The template used to construct a user's DN. It should contain " "one placeholder (ie. %(user)s)"), required=False, widget=forms.TextInput(attrs={"class": "form-control"})) ldap_password_attribute = forms.CharField( label=ugettext_lazy("Password attribute"), initial="userPassword", help_text=ugettext_lazy("The attribute used to store user passwords"), widget=forms.TextInput(attrs={"class": "form-control"})) ldap_is_active_directory = YesNoField( label=ugettext_lazy("Active Directory"), initial=False, help_text=ugettext_lazy( "Tell if the LDAP server is an Active Directory one")) ldap_admin_groups = forms.CharField( label=ugettext_lazy("Administrator groups"), initial="", help_text=ugettext_lazy( "Members of those LDAP Posix groups will be created as domain " "administrators. Use ';' characters to separate groups."), required=False) ldap_group_type = forms.ChoiceField( label=ugettext_lazy("Group type"), initial="posixgroup", choices=constants.LDAP_GROUP_TYPES, help_text=ugettext_lazy( "The LDAP group type to use with your directory.")) ldap_groups_search_base = forms.CharField( label=ugettext_lazy("Groups search base"), initial="", help_text=ugettext_lazy( "The distinguished name of the search base used to find groups"), required=False) dash_sep = SeparatorField(label=ugettext_lazy("Dashboard")) rss_feed_url = forms.URLField( label=ugettext_lazy("Custom RSS feed"), required=False, help_text=ugettext_lazy( "Display custom RSS feed to resellers and domain administrators")) hide_features_widget = YesNoField( label=ugettext_lazy("Hide features widget"), initial=False, help_text=ugettext_lazy( "Hide features widget for resellers and domain administrators")) notif_sep = SeparatorField(label=ugettext_lazy("Notifications")) sender_address = lib_fields.UTF8EmailField( label=_("Sender address"), initial="*****@*****.**", help_text=_("Email address used to send notifications.")) api_sep = SeparatorField(label=ugettext_lazy("Public API")) enable_api_communication = YesNoField( label=ugettext_lazy("Enable communication"), initial=True, help_text=ugettext_lazy( "Enable communication with Modoboa public API")) check_new_versions = YesNoField( label=ugettext_lazy("Check new versions"), initial=True, help_text=ugettext_lazy( "Automatically checks if a newer version is available")) send_statistics = YesNoField(label=ugettext_lazy("Send statistics"), initial=True, help_text=ugettext_lazy( "Send statistics to Modoboa public API " "(counters and used extensions)")) sep3 = SeparatorField(label=ugettext_lazy("Miscellaneous")) inactive_account_threshold = forms.IntegerField( label=_("Inactive account threshold"), initial=30, help_text=_( "An account with a last login date greater than this threshold " "(in days) will be considered as inactive"), widget=forms.TextInput(attrs={"class": "form-control"})) top_notifications_check_interval = forms.IntegerField( label=_("Top notifications check interval"), initial=30, help_text=_( "Interval between two top notification checks (in seconds)"), widget=forms.TextInput(attrs={"class": "form-control"})) log_maximum_age = forms.IntegerField( label=ugettext_lazy("Maximum log record age"), initial=365, help_text=ugettext_lazy("The maximum age in days of a log record"), widget=forms.TextInput(attrs={"class": "form-control"})) items_per_page = forms.IntegerField( label=ugettext_lazy("Items per page"), initial=30, help_text=ugettext_lazy("Number of displayed items per page"), widget=forms.TextInput(attrs={"class": "form-control"})) default_top_redirection = forms.ChoiceField( label=ugettext_lazy("Default top redirection"), choices=[], initial="user", help_text=ugettext_lazy( "The default redirection used when no application is specified"), widget=forms.Select(attrs={"class": "form-control"})) # Visibility rules visibility_rules = { "ldap_sep": "authentication_type=ldap", "ldap_server_address": "authentication_type=ldap", "ldap_server_port": "authentication_type=ldap", "ldap_secured": "authentication_type=ldap", "ldap_auth_method": "authentication_type=ldap", "ldap_bind_dn": "ldap_auth_method=searchbind", "ldap_bind_password": "******", "ldap_search_base": "ldap_auth_method=searchbind", "ldap_search_filter": "ldap_auth_method=searchbind", "ldap_user_dn_template": "ldap_auth_method=directbind", "ldap_password_attribute": "authentication_type=ldap", "ldap_is_active_directory": "authentication_type=ldap", "ldap_admin_groups": "authentication_type=ldap", "ldap_group_type": "authentication_type=ldap", "ldap_groups_search_base": "authentication_type=ldap", "check_new_versions": "enable_api_communication=True", "send_statistics": "enable_api_communication=True", } def __init__(self, *args, **kwargs): super(GeneralParametersForm, self).__init__(*args, **kwargs) self.fields["default_top_redirection"].choices = enabled_applications() def clean_secret_key(self): if len(self.cleaned_data["secret_key"]) not in [16, 24, 32]: raise forms.ValidationError( _("Key must be either 16, 24, or 32 bytes long")) return self.cleaned_data["secret_key"] def clean_ldap_user_dn_template(self): tpl = self.cleaned_data["ldap_user_dn_template"] try: test = tpl % {"user": "******"} except (KeyError, ValueError): raise forms.ValidationError(_("Invalid syntax")) return tpl def clean_rounds_number(self): value = self.cleaned_data["rounds_number"] if value < 1000 or value > 999999999: raise forms.ValidationError(_("Invalid rounds number")) return value def clean_default_password(self): """Check password complexity.""" value = self.cleaned_data["default_password"] password_validation.validate_password(value) return value def clean(self): """Custom validation method Depending on 'ldap_auth_method' value, we check for different required parameters. """ super(GeneralParametersForm, self).clean() cleaned_data = self.cleaned_data if cleaned_data["authentication_type"] != "ldap": return cleaned_data if cleaned_data["ldap_auth_method"] == "searchbind": required_fields = ["ldap_search_base", "ldap_search_filter"] else: required_fields = ["ldap_user_dn_template"] for f in required_fields: if f not in cleaned_data or cleaned_data[f] == u'': self.add_error(f, _("This field is required")) return cleaned_data def to_django_settings(self): """Apply LDAP related parameters to Django settings. Doing so, we can use the django_auth_ldap module. """ try: import ldap from django_auth_ldap.config import (LDAPSearch, PosixGroupType, GroupOfNamesType) ldap_available = True except ImportError: ldap_available = False values = dict(param_tools.get_global_parameters("core")) if not ldap_available or values["authentication_type"] != "ldap": return if not hasattr(settings, "AUTH_LDAP_USER_ATTR_MAP"): setattr(settings, "AUTH_LDAP_USER_ATTR_MAP", { "first_name": "givenName", "email": "mail", "last_name": "sn" }) ldap_uri = "ldaps://" if values["ldap_secured"] else "ldap://" ldap_uri += "%s:%s" % (values["ldap_server_address"], values["ldap_server_port"]) setattr(settings, "AUTH_LDAP_SERVER_URI", ldap_uri) if values["ldap_group_type"] == "groupofnames": setattr(settings, "AUTH_LDAP_GROUP_TYPE", GroupOfNamesType()) searchfilter = "(objectClass=groupOfNames)" else: setattr(settings, "AUTH_LDAP_GROUP_TYPE", PosixGroupType()) searchfilter = "(objectClass=posixGroup)" setattr( settings, "AUTH_LDAP_GROUP_SEARCH", LDAPSearch(values["ldap_groups_search_base"], ldap.SCOPE_SUBTREE, searchfilter)) if values["ldap_auth_method"] == "searchbind": setattr(settings, "AUTH_LDAP_BIND_DN", values["ldap_bind_dn"]) setattr(settings, "AUTH_LDAP_BIND_PASSWORD", values["ldap_bind_password"]) search = LDAPSearch(values["ldap_search_base"], ldap.SCOPE_SUBTREE, values["ldap_search_filter"]) setattr(settings, "AUTH_LDAP_USER_SEARCH", search) else: setattr(settings, "AUTH_LDAP_USER_DN_TEMPLATE", values["ldap_user_dn_template"]) if values["ldap_is_active_directory"]: if not hasattr(settings, "AUTH_LDAP_GLOBAL_OPTIONS"): setattr(settings, "AUTH_LDAP_GLOBAL_OPTIONS", {ldap.OPT_REFERRALS: False}) else: settings.AUTH_LDAP_GLOBAL_OPTIONS[ldap.OPT_REFERRALS] = False
class DomainFormOptions(forms.Form): """A form containing options for domain creation.""" create_dom_admin = YesNoField( label=ugettext_lazy("Create a domain administrator"), initial="no", help_text=ugettext_lazy( "Automatically create an administrator for this domain")) dom_admin_username = forms.CharField( label=ugettext_lazy("Name"), initial="admin", help_text=ugettext_lazy( "The administrator's name. Don't include the domain's name here, " "it will be automatically appended."), required=False) create_aliases = YesNoField( label=ugettext_lazy("Create aliases"), initial="yes", help_text=ugettext_lazy( "Automatically create standard aliases for this domain"), required=False) def __init__(self, user, *args, **kwargs): super(DomainFormOptions, self).__init__(*args, **kwargs) result = events.raiseQueryEvent('UserCanSetRole', user, 'DomainAdmins') if False in result: self.fields = {} return if args: if args[0].get("create_dom_admin", "no") == "yes": self.fields["dom_admin_username"].required = True self.fields["create_aliases"].required = True def clean_dom_admin_username(self): """Ensure admin username is an email address.""" if '@' in self.cleaned_data["dom_admin_username"]: raise forms.ValidationError(_("Invalid format")) return self.cleaned_data["dom_admin_username"] def save(self, *args, **kwargs): if not self.fields: return if self.cleaned_data["create_dom_admin"] == "no": return user = kwargs.pop("user") domain = kwargs.pop("domain") username = "******" % (self.cleaned_data["dom_admin_username"], domain.name) try: da = User.objects.get(username=username) except User.DoesNotExist: pass else: raise Conflict(_("User '%s' already exists") % username) core_signals.can_create_object.send(self.__class__, context=user, object_type="mailboxes") da = User(username=username, email=username, is_active=True) da.set_password("password") da.save() da.role = "DomainAdmins" da.post_create(user) mb = Mailbox(address=self.cleaned_data["dom_admin_username"], domain=domain, user=da, use_domain_quota=True) mb.set_quota(override_rules=user.has_perm("admin.change_domain")) mb.save(creator=user) if domain.type == "domain" and \ self.cleaned_data["create_aliases"] == "yes": core_signals.can_create_object.send(self.__class__, context=user, object_type="mailbox_aliases") alias = Alias(address=u"postmaster@{}".format(domain.name), domain=domain, enabled=True) alias.save() alias.set_recipients([mb.full_address]) alias.post_create(user) domain.add_admin(da)
class GeneralParametersForm(param_forms.AdminParametersForm): """General parameters.""" app = "core" sep1 = SeparatorField(label=ugettext_lazy("Authentication")) authentication_type = forms.ChoiceField( label=ugettext_lazy("Authentication type"), choices=[("local", ugettext_lazy("Local")), ("ldap", "LDAP")], initial="local", help_text=ugettext_lazy("The backend used for authentication"), widget=HorizontalRadioSelect()) password_scheme = forms.ChoiceField( label=ugettext_lazy("Default password scheme"), choices=[(hasher.name, ugettext_lazy(hasher.label)) for hasher in PasswordHasher.get_password_hashers() if hasher().scheme in get_dovecot_schemes()], initial="sha512crypt", help_text=ugettext_lazy("Scheme used to crypt mailbox passwords"), ) rounds_number = forms.IntegerField( label=ugettext_lazy("Rounds"), initial=70000, help_text=ugettext_lazy( "Number of rounds to use (only used by sha256crypt and " "sha512crypt). Must be between 1000 and 999999999, inclusive."), ) update_scheme = YesNoField( label=ugettext_lazy("Update password scheme at login"), initial=True, help_text=ugettext_lazy( "Update user password at login to use the default password scheme") ) default_password = forms.CharField( label=ugettext_lazy("Default password"), initial="password", help_text=ugettext_lazy( "Default password for automatically created accounts.")) random_password_length = forms.IntegerField( label=ugettext_lazy("Random password length"), min_value=8, initial=8, help_text=ugettext_lazy("Length of randomly generated passwords.")) update_password_url = forms.URLField( label=ugettext_lazy("Update password service URL"), initial="", required=False, help_text=ugettext_lazy( "The URL of an external page where users will be able" " to update their password. It applies only to non local" " users, ie. those automatically created after a successful" " external authentication (LDAP, SMTP).")) # LDAP specific settings ldap_sep = SeparatorField(label=ugettext_lazy("LDAP settings")) ldap_server_address = forms.CharField( label=ugettext_lazy("Server address"), initial="localhost", help_text=ugettext_lazy( "The IP address or the DNS name of the LDAP server"), ) ldap_server_port = forms.IntegerField( label=ugettext_lazy("Server port"), initial=389, help_text=ugettext_lazy("The TCP port number used by the LDAP server"), ) ldap_enable_secondary_server = YesNoField( label=ugettext_lazy("Enable secondary server (fallback)"), initial=False, help_text=ugettext_lazy( "Enable a secondary LDAP server which will be used " "if the primary one fails")) ldap_secondary_server_address = forms.CharField( label=ugettext_lazy("Secondary server address"), initial="localhost", help_text=ugettext_lazy( "The IP address or the DNS name of the seondary LDAP server"), ) ldap_secondary_server_port = forms.IntegerField( label=ugettext_lazy("Secondary server port"), initial=389, help_text=ugettext_lazy( "The TCP port number used by the LDAP secondary server"), ) ldap_secured = forms.ChoiceField( label=ugettext_lazy("Use a secured connection"), choices=constants.LDAP_SECURE_MODES, initial="none", help_text=ugettext_lazy( "Use an SSL/STARTTLS connection to access the LDAP server")) ldap_is_active_directory = YesNoField( label=ugettext_lazy("Active Directory"), initial=False, help_text=ugettext_lazy( "Tell if the LDAP server is an Active Directory one")) ldap_admin_groups = forms.CharField( label=ugettext_lazy("Administrator groups"), initial="", help_text=ugettext_lazy( "Members of those LDAP Posix groups will be created as domain " "administrators. Use ';' characters to separate groups."), required=False) ldap_group_type = forms.ChoiceField( label=ugettext_lazy("Group type"), initial="posixgroup", choices=constants.LDAP_GROUP_TYPES, help_text=ugettext_lazy( "The LDAP group type to use with your directory.")) ldap_groups_search_base = forms.CharField( label=ugettext_lazy("Groups search base"), initial="", help_text=ugettext_lazy( "The distinguished name of the search base used to find groups"), required=False) ldap_password_attribute = forms.CharField( label=ugettext_lazy("Password attribute"), initial="userPassword", help_text=ugettext_lazy("The attribute used to store user passwords"), ) # LDAP authentication settings ldap_auth_sep = SeparatorField( label=ugettext_lazy("LDAP authentication settings")) ldap_auth_method = forms.ChoiceField( label=ugettext_lazy("Authentication method"), choices=[("searchbind", ugettext_lazy("Search and bind")), ("directbind", ugettext_lazy("Direct bind"))], initial="searchbind", help_text=ugettext_lazy("Choose the authentication method to use"), ) ldap_bind_dn = forms.CharField( label=ugettext_lazy("Bind DN"), initial="", help_text=ugettext_lazy( "The distinguished name to use when binding to the LDAP server. " "Leave empty for an anonymous bind"), required=False, ) ldap_bind_password = forms.CharField( label=ugettext_lazy("Bind password"), initial="", help_text=ugettext_lazy( "The password to use when binding to the LDAP server " "(with 'Bind DN')"), widget=forms.PasswordInput(render_value=True), required=False) ldap_search_base = forms.CharField( label=ugettext_lazy("Users search base"), initial="", help_text=ugettext_lazy( "The distinguished name of the search base used to find users"), required=False, ) ldap_search_filter = forms.CharField( label=ugettext_lazy("Search filter"), initial="(mail=%(user)s)", help_text=ugettext_lazy( "An optional filter string (e.g. '(objectClass=person)'). " "In order to be valid, it must be enclosed in parentheses."), required=False, ) ldap_user_dn_template = forms.CharField( label=ugettext_lazy("User DN template"), initial="", help_text=ugettext_lazy( "The template used to construct a user's DN. It should contain " "one placeholder (ie. %(user)s)"), required=False, ) # LDAP sync. settings ldap_sync_sep = SeparatorField( label=ugettext_lazy("LDAP synchronization settings")) ldap_sync_bind_dn = forms.CharField( label=ugettext_lazy("Bind DN"), initial="", help_text=ugettext_lazy( "The distinguished name to use when binding to the LDAP server. " "Leave empty for an anonymous bind"), required=False, ) ldap_sync_bind_password = forms.CharField( label=ugettext_lazy("Bind password"), initial="", help_text=ugettext_lazy( "The password to use when binding to the LDAP server " "(with 'Bind DN')"), widget=forms.PasswordInput(render_value=True), required=False) ldap_enable_sync = YesNoField( label=ugettext_lazy("Enable export to LDAP"), initial=False, help_text=ugettext_lazy( "Enable automatic synchronization between local database and " "LDAP directory")) ldap_sync_delete_remote_account = YesNoField( label=ugettext_lazy( "Delete remote LDAP account when local account is deleted"), initial=False, help_text=ugettext_lazy( "Delete remote LDAP account when local account is deleted, " "otherwise it will be disabled.")) ldap_sync_account_dn_template = forms.CharField( label=ugettext_lazy("Account DN template"), initial="", help_text=ugettext_lazy( "The template used to construct an account's DN. It should contain " "one placeholder (ie. %(user)s)"), required=False) ldap_enable_import = YesNoField( label=ugettext_lazy("Enable import from LDAP"), initial=False, help_text=ugettext_lazy( "Enable account synchronization from LDAP directory to local " "database")) ldap_import_search_base = forms.CharField( label=ugettext_lazy("Users search base"), initial="", help_text=ugettext_lazy( "The distinguished name of the search base used to find users"), required=False, ) ldap_import_search_filter = forms.CharField( label=ugettext_lazy("Search filter"), initial="(cn=*)", help_text=ugettext_lazy( "An optional filter string (e.g. '(objectClass=person)'). " "In order to be valid, it must be enclosed in parentheses."), required=False, ) ldap_import_username_attr = forms.CharField( label=ugettext_lazy("Username attribute"), initial="cn", help_text=ugettext_lazy( "The name of the LDAP attribute where the username can be found."), ) dash_sep = SeparatorField(label=ugettext_lazy("Dashboard")) rss_feed_url = forms.URLField( label=ugettext_lazy("Custom RSS feed"), required=False, help_text=ugettext_lazy( "Display custom RSS feed to resellers and domain administrators")) hide_features_widget = YesNoField( label=ugettext_lazy("Hide features widget"), initial=False, help_text=ugettext_lazy( "Hide features widget for resellers and domain administrators")) notif_sep = SeparatorField(label=ugettext_lazy("Notifications")) sender_address = lib_fields.UTF8EmailField( label=_("Sender address"), initial="*****@*****.**", help_text=_("Email address used to send notifications.")) api_sep = SeparatorField(label=ugettext_lazy("Public API")) enable_api_communication = YesNoField( label=ugettext_lazy("Enable communication"), initial=True, help_text=ugettext_lazy( "Enable communication with Modoboa public API")) check_new_versions = YesNoField( label=ugettext_lazy("Check new versions"), initial=True, help_text=ugettext_lazy( "Automatically checks if a newer version is available")) send_new_versions_email = YesNoField( label=ugettext_lazy("Send an email when new versions are found"), initial=False, help_text=ugettext_lazy( "Send an email to notify admins about new versions")) new_versions_email_rcpt = lib_fields.UTF8EmailField( label=_("Recipient"), initial="*****@*****.**", help_text=_("Recipient of new versions notification emails.")) send_statistics = YesNoField(label=ugettext_lazy("Send statistics"), initial=True, help_text=ugettext_lazy( "Send statistics to Modoboa public API " "(counters and used extensions)")) sep3 = SeparatorField(label=ugettext_lazy("Miscellaneous")) inactive_account_threshold = forms.IntegerField( label=_("Inactive account threshold"), initial=30, help_text=_( "An account with a last login date greater than this threshold " "(in days) will be considered as inactive"), ) top_notifications_check_interval = forms.IntegerField( label=_("Top notifications check interval"), initial=30, help_text=_( "Interval between two top notification checks (in seconds)"), ) log_maximum_age = forms.IntegerField( label=ugettext_lazy("Maximum log record age"), initial=365, help_text=ugettext_lazy("The maximum age in days of a log record"), ) items_per_page = forms.IntegerField( label=ugettext_lazy("Items per page"), initial=30, help_text=ugettext_lazy("Number of displayed items per page"), ) default_top_redirection = forms.ChoiceField( label=ugettext_lazy("Default top redirection"), choices=[], initial="user", help_text=ugettext_lazy( "The default redirection used when no application is specified"), ) # Visibility rules visibility_rules = { "ldap_secondary_server_address": "ldap_enable_secondary_server=True", "ldap_secondary_server_port": "ldap_enable_secondary_server=True", "ldap_auth_sep": "authentication_type=ldap", "ldap_auth_method": "authentication_type=ldap", "ldap_bind_dn": "ldap_auth_method=searchbind", "ldap_bind_password": "******", "ldap_search_base": "ldap_auth_method=searchbind", "ldap_search_filter": "ldap_auth_method=searchbind", "ldap_user_dn_template": "ldap_auth_method=directbind", "ldap_admin_groups": "authentication_type=ldap", "ldap_group_type": "authentication_type=ldap", "ldap_groups_search_base": "authentication_type=ldap", "ldap_sync_delete_remote_account": "ldap_enable_sync=True", "ldap_sync_account_dn_template": "ldap_enable_sync=True", "ldap_import_search_base": "ldap_enable_import=True", "ldap_import_search_filter": "ldap_enable_import=True", "ldap_import_username_attr": "ldap_enable_import=True", "check_new_versions": "enable_api_communication=True", "send_statistics": "enable_api_communication=True", "send_new_versions_email": "check_new_versions=True", "new_versions_email_rcpt": "check_new_versions=True" } def __init__(self, *args, **kwargs): super(GeneralParametersForm, self).__init__(*args, **kwargs) self.fields["default_top_redirection"].choices = enabled_applications() def clean_ldap_user_dn_template(self): tpl = self.cleaned_data["ldap_user_dn_template"] try: tpl % {"user": "******"} except (KeyError, ValueError): raise forms.ValidationError(_("Invalid syntax")) return tpl def clean_ldap_sync_account_dn_template(self): tpl = self.cleaned_data["ldap_sync_account_dn_template"] try: tpl % {"user": "******"} except (KeyError, ValueError): raise forms.ValidationError(_("Invalid syntax")) return tpl def clean_rounds_number(self): value = self.cleaned_data["rounds_number"] if value < 1000 or value > 999999999: raise forms.ValidationError(_("Invalid rounds number")) return value def clean_default_password(self): """Check password complexity.""" value = self.cleaned_data["default_password"] password_validation.validate_password(value) return value def clean(self): """Custom validation method Depending on 'ldap_auth_method' value, we check for different required parameters. """ super(GeneralParametersForm, self).clean() cleaned_data = self.cleaned_data if cleaned_data["authentication_type"] != "ldap": return cleaned_data if cleaned_data["ldap_auth_method"] == "searchbind": required_fields = ["ldap_search_base", "ldap_search_filter"] else: required_fields = ["ldap_user_dn_template"] for f in required_fields: if f not in cleaned_data or cleaned_data[f] == u'': self.add_error(f, _("This field is required")) return cleaned_data def _apply_ldap_settings(self, values, backend): """Apply configuration for given backend.""" import ldap from django_auth_ldap.config import (LDAPSearch, PosixGroupType, GroupOfNamesType, ActiveDirectoryGroupType) if not hasattr(settings, backend.setting_fullname("USER_ATTR_MAP")): setattr(settings, backend.setting_fullname("USER_ATTR_MAP"), { "first_name": "givenName", "email": "mail", "last_name": "sn" }) ldap_uri = "ldaps://" if values["ldap_secured"] == "ssl" else "ldap://" ldap_uri += "%s:%s" % (values[backend.srv_address_setting_name], values[backend.srv_port_setting_name]) setattr(settings, backend.setting_fullname("SERVER_URI"), ldap_uri) if values["ldap_secured"] == "starttls": setattr(settings, backend.setting_fullname("START_TLS"), True) if values["ldap_is_active_directory"]: setattr(settings, backend.setting_fullname("GROUP_TYPE"), ActiveDirectoryGroupType()) searchfilter = "(objectClass=group)" elif values["ldap_group_type"] == "groupofnames": setattr(settings, backend.setting_fullname("GROUP_TYPE"), GroupOfNamesType()) searchfilter = "(objectClass=groupOfNames)" else: setattr(settings, backend.setting_fullname("GROUP_TYPE"), PosixGroupType()) searchfilter = "(objectClass=posixGroup)" setattr( settings, backend.setting_fullname("GROUP_SEARCH"), LDAPSearch(values["ldap_groups_search_base"], ldap.SCOPE_SUBTREE, searchfilter)) if values["ldap_auth_method"] == "searchbind": setattr(settings, backend.setting_fullname("BIND_DN"), values["ldap_bind_dn"]) setattr(settings, backend.setting_fullname("BIND_PASSWORD"), values["ldap_bind_password"]) search = LDAPSearch(values["ldap_search_base"], ldap.SCOPE_SUBTREE, values["ldap_search_filter"]) setattr(settings, backend.setting_fullname("USER_SEARCH"), search) else: setattr(settings, backend.setting_fullname("USER_DN_TEMPLATE"), values["ldap_user_dn_template"]) setattr(settings, backend.setting_fullname("BIND_AS_AUTHENTICATING_USER"), True) if values["ldap_is_active_directory"]: setting = backend.setting_fullname("GLOBAL_OPTIONS") if not hasattr(settings, setting): setattr(settings, setting, {ldap.OPT_REFERRALS: False}) else: getattr(settings, setting)[ldap.OPT_REFERRALS] = False def to_django_settings(self): """Apply LDAP related parameters to Django settings. Doing so, we can use the django_auth_ldap module. """ try: import ldap ldap_available = True except ImportError: ldap_available = False values = dict(param_tools.get_global_parameters("core")) if not ldap_available or values["authentication_type"] != "ldap": return from modoboa.lib.authbackends import LDAPBackend self._apply_ldap_settings(values, LDAPBackend) if not values["ldap_enable_secondary_server"]: return from modoboa.lib.authbackends import LDAPSecondaryBackend self._apply_ldap_settings(values, LDAPSecondaryBackend)
class AdminParametersForm(parameters.AdminParametersForm): app = "admin" mbsep = SeparatorField(label=ugettext_lazy("Mailboxes")) handle_mailboxes = YesNoField( label=ugettext_lazy("Handle mailboxes on filesystem"), initial="no", help_text=ugettext_lazy( "Rename or remove mailboxes on the filesystem when they get" " renamed or removed within Modoboa")) mailboxes_owner = forms.CharField( label=ugettext_lazy("Mailboxes owner"), initial="vmail", help_text=ugettext_lazy( "The UNIX account who owns mailboxes on the filesystem")) default_domain_quota = forms.IntegerField( label=ugettext_lazy("Default domain quota"), initial=0, help_text=ugettext_lazy( "Default quota (in MB) applied to freshly created domains with no " "value specified. A value of 0 means no quota.")) auto_account_removal = YesNoField( label=ugettext_lazy("Automatic account removal"), initial="no", help_text=ugettext_lazy( "When a mailbox is removed, also remove the associated account")) auto_create_domain_and_mailbox = YesNoField( label=ugettext_lazy("Automatic domain/mailbox creation"), initial="yes", help_text=ugettext_lazy( "Create a domain and a mailbox when an account is automatically " "created.")) # Visibility rules visibility_rules = { "mailboxes_owner": "handle_mailboxes=yes", } def __init__(self, *args, **kwargs): super(AdminParametersForm, self).__init__(*args, **kwargs) self.field_widths = {"default_domain_quota": 2} hide_fields = False dpath = None code, output = exec_cmd("which dovecot") if not code: dpath = output.strip() else: known_paths = getattr( settings, "DOVECOT_LOOKUP_PATH", ("/usr/sbin/dovecot", "/usr/local/sbin/dovecot")) for fpath in known_paths: if os.path.isfile(fpath) and os.access(fpath, os.X_OK): dpath = fpath if dpath: try: code, version = exec_cmd("%s --version" % dpath) except OSError: hide_fields = True else: if code or not version.strip().startswith("2"): hide_fields = True else: hide_fields = True if hide_fields: del self.fields["handle_mailboxes"] del self.fields["mailboxes_owner"] def clean_default_domain_quota(self): """Ensure quota is a positive integer.""" if self.cleaned_data['default_domain_quota'] < 0: raise forms.ValidationError( ugettext_lazy('Must be a positive integer')) return self.cleaned_data['default_domain_quota']
class DomainFormOptions(forms.Form): """A form containing options for domain creation.""" create_dom_admin = YesNoField( label=ugettext_lazy("Create a domain administrator"), initial=False, help_text=ugettext_lazy( "Automatically create an administrator for this domain" ) ) dom_admin_username = forms.CharField( label=ugettext_lazy("Name"), initial="admin", help_text=ugettext_lazy( "The administrator's name. Don't include the domain's name here, " "it will be automatically appended." ), required=False ) create_aliases = YesNoField( label=ugettext_lazy("Create aliases"), initial=True, help_text=ugettext_lazy( "Automatically create standard aliases for this domain" ), required=False ) def __init__(self, user, *args, **kwargs): super(DomainFormOptions, self).__init__(*args, **kwargs) results = core_signals.user_can_set_role.send( sender=self.__class__, user=user, role="DomainAdmins") if False in [result[1] for result in results]: self.fields = {} return def clean_dom_admin_username(self): """Ensure admin username is an email address.""" if "@" in self.cleaned_data["dom_admin_username"]: raise forms.ValidationError(_("Invalid format")) return self.cleaned_data["dom_admin_username"] def clean(self): """Check required values.""" cleaned_data = super(DomainFormOptions, self).clean() if cleaned_data.get("create_dom_admin"): if not cleaned_data.get("dom_admin_username"): self.add_error( "dom_admin_username", _("This field is required.")) if "create_aliases" not in cleaned_data: self.add_error( "create_aliases", _("This field is required.")) return cleaned_data def save(self, *args, **kwargs): if not self.fields: return if not self.cleaned_data["create_dom_admin"]: return user = kwargs.pop("user") domain = kwargs.pop("domain") username = "******" % ( self.cleaned_data["dom_admin_username"], domain.name) try: da = User.objects.get(username=username) except User.DoesNotExist: pass else: raise Conflict(_("User '%s' already exists") % username) core_signals.can_create_object.send( self.__class__, context=user, object_type="mailboxes") da = User(username=username, email=username, is_active=True) da.set_password("password") da.save() da.role = "DomainAdmins" da.post_create(user) dom_admin_username = self.cleaned_data["dom_admin_username"] mb = Mailbox( address=dom_admin_username, domain=domain, user=da, use_domain_quota=True ) mb.set_quota( override_rules=user.has_perm("admin.change_domain")) mb.save(creator=user) condition = ( domain.type == "domain" and self.cleaned_data["create_aliases"] and dom_admin_username != "postmaster" ) if condition: core_signals.can_create_object.send( self.__class__, context=user, object_type="mailbox_aliases") address = u"postmaster@{}".format(domain.name) alias = Alias.objects.create( address=address, domain=domain, enabled=True) alias.set_recipients([mb.full_address]) alias.post_create(user) domain.add_admin(da)
class UserSettings(UserParametersForm): app = "webmail" sep1 = SeparatorField(label=_("Display")) displaymode = forms.ChoiceField( initial="plain", label=_("Default message display mode"), choices=[("html", "html"), ("plain", "text")], help_text=_("The default mode used when displaying a message"), widget=InlineRadioSelect()) enable_links = YesNoField(initial="no", label=_("Enable HTML links display"), help_text=_("Enable/Disable HTML links display")) messages_per_page = forms.IntegerField( initial=40, label=_("Number of displayed emails per page"), help_text=_("Sets the maximum number of messages displayed in a page")) refresh_interval = forms.IntegerField( initial=300, label=_("Listing refresh rate"), help_text=_("Automatic folder refresh rate (in seconds)")) mboxes_col_width = forms.IntegerField( initial=200, label=_("Mailboxes container's width"), help_text=_("The width of the mailbox list container")) sep2 = SeparatorField(label=_("Mailboxes")) trash_folder = forms.CharField( initial="Trash", label=_("Trash folder"), help_text=_("Folder where deleted messages go")) sent_folder = forms.CharField( initial="Sent", label=_("Sent folder"), help_text=_("Folder where copies of sent messages go")) drafts_folder = forms.CharField(initial="Drafts", label=_("Drafts folder"), help_text=_("Folder where drafts go")) sep3 = SeparatorField(label=_("Composing messages")) editor = forms.ChoiceField( initial="plain", label=_("Default editor"), choices=[("html", "html"), ("plain", "text")], help_text=_("The default editor to use when composing a message"), widget=InlineRadioSelect()) signature = forms.CharField(initial="", label=_("Signature text"), help_text=_("User defined email signature"), required=False) visibility_rules = {"enable_links": "displaymode=html"} @staticmethod def has_access(user): return user.mailbox_set.count() != 0 def clean_mboxes_col_width(self): """Check if the entered value is a positive integer. It must also be different from 0. """ if self.cleaned_data['mboxes_col_width'] <= 0: raise forms.ValidationError( _('Value must be a positive integer (> 0)')) return self.cleaned_data['mboxes_col_width']
class ParametersForm(param_forms.AdminParametersForm): """Available admin parameters.""" app = "limits" defv_sep = SeparatorField(label=_("Default per-admin limits")) enable_admin_limits = YesNoField( label=_("Enable per-admin limits"), initial=True, help_text=_("Enable or disable per-admin limits")) deflt_user_domain_admins_limit = forms.IntegerField( label=_("Domain admins"), initial=0, help_text=_( "Maximum number of allowed domain administrators for a new " "administrator. (0 to deny any creation, -1 to allow unlimited " "creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_user_domains_limit = forms.IntegerField( label=_("Domains"), initial=0, help_text=_( "Maximum number of allowed domains for a new administrator. " "(0 to deny any creation, -1 to allow unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_user_domain_aliases_limit = forms.IntegerField( label=_("Domain aliases"), initial=0, help_text=_("Maximum number of allowed domain aliases for a new " "administrator. (0 to deny any creation, -1 to allow " "unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_user_mailboxes_limit = forms.IntegerField( label=_("Mailboxes"), initial=0, help_text=_( "Maximum number of allowed mailboxes for a new administrator. " "(0 to deny any creation, -1 to allow unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_user_mailbox_aliases_limit = forms.IntegerField( label=_("Mailbox aliases"), initial=0, help_text=_( "Maximum number of allowed aliases for a new administrator. " "(0 to deny any creation, -1 to allow unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_user_quota_limit = forms.IntegerField( label=_("Quota"), initial=0, help_text=_( "The quota a reseller will be allowed to share between the " "domains he creates. (0 means no quota)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) domain_limits_sep = SeparatorField(label=_("Default per-domain limits")) enable_domain_limits = YesNoField( label=_("Enable per-domain limits"), initial=False, help_text=_("Enable or disable per-domain limits")) deflt_domain_domain_admins_limit = forms.IntegerField( label=_("Domain admins"), initial=0, help_text=_( "Maximum number of allowed domain administrators for a new " "domain. (0 to deny any creation, -1 to allow unlimited " "creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_domain_domain_aliases_limit = forms.IntegerField( label=_("Domain aliases"), initial=0, help_text=_("Maximum number of allowed domain aliases for a new " "domain. (0 to deny any creation, -1 to allow " "unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_domain_mailboxes_limit = forms.IntegerField( label=_("Mailboxes"), initial=0, help_text=_( "Maximum number of allowed mailboxes for a new domain. " "(0 to deny any creation, -1 to allow unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_domain_mailbox_aliases_limit = forms.IntegerField( label=_("Mailbox aliases"), initial=0, help_text=_( "Maximum number of allowed aliases for a new domain. " "(0 to deny any creation, -1 to allow unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) visibility_rules = { "deflt_user_domains_limit": "enable_admin_limits=True", "deflt_user_domain_aliases_limit": "enable_admin_limits=True", "deflt_user_mailboxes_limit": "enable_admin_limits=True", "deflt_user_mailbox_aliases_limit": "enable_admin_limits=True", "deflt_user_domain_admins_limit": "enable_admin_limits=True", "deflt_domain_mailboxes_limit": "enable_domain_limits=True", "deflt_domain_mailbox_aliases_limit": "enable_domain_limits=True", "deflt_domain_domain_aliases_limit": "enable_domain_limits=True", "deflt_domain_domain_admins_limit": "enable_domain_limits=True", }
class AdminParametersForm(param_forms.AdminParametersForm): app = "admin" dom_sep = SeparatorField(label=ugettext_lazy("Domains")) enable_mx_checks = YesNoField( label=ugettext_lazy("Enable MX checks"), initial=True, help_text=ugettext_lazy( "Check that every domain has a valid MX record")) valid_mxs = forms.CharField( label=ugettext_lazy("Valid MXs"), initial="", help_text=ugettext_lazy( "A list of IP or network address every MX record should match." " A warning will be sent if a record does not respect it."), widget=forms.Textarea, required=False) domains_must_have_authorized_mx = YesNoField( label=ugettext_lazy("New domains must use authorized MX(s)"), initial=False, help_text=ugettext_lazy( "Prevent the creation of a new domain if its MX record does " "not use one of the defined addresses.")) enable_spf_checks = YesNoField( label=ugettext_lazy("Enable SPF checks"), initial=True, help_text=ugettext_lazy( "Check if every domain has a valid SPF record")) enable_dkim_checks = YesNoField( label=ugettext_lazy("Enable DKIM checks"), initial=True, help_text=ugettext_lazy( "Check if every domain with DKIM signin enabled has a valid DNS " "record")) enable_dmarc_checks = YesNoField( label=ugettext_lazy("Enable DMARC checks"), initial=True, help_text=ugettext_lazy( "Check if every domain has a valid DMARC record")) enable_autoconfig_checks = YesNoField( label=ugettext_lazy("Enable autoconfig checks"), initial=True, help_text=ugettext_lazy( "Check if every domain has a valid records for autoconfiguration")) enable_dnsbl_checks = YesNoField( label=ugettext_lazy("Enable DNSBL checks"), initial=True, help_text=ugettext_lazy( "Check every domain against major DNSBL providers")) custom_dns_server = GenericIPAddressField( label=ugettext_lazy("Custom DNS server"), required=False, help_text=ugettext_lazy( "Use a custom DNS server instead of local server configuration")) dkim_keys_storage_dir = forms.CharField( label=ugettext_lazy("DKIM keys storage directory"), initial="", help_text=ugettext_lazy( "Absolute path of the directory where DKIM private keys will " "be stored. Make sure this directory belongs to root user " "and is not readable by the outside world."), required=False) dkim_default_key_length = forms.ChoiceField( label=ugettext_lazy("Default DKIM key length"), initial=2048, choices=constants.DKIM_KEY_LENGTHS, help_text=ugettext_lazy( "Default length in bits for newly generated DKIM keys.")) default_domain_quota = forms.IntegerField( label=ugettext_lazy("Default domain quota"), initial=0, help_text=ugettext_lazy( "Default quota (in MB) applied to freshly created domains with no " "value specified. A value of 0 means no quota.")) default_domain_message_limit = forms.IntegerField( label=ugettext_lazy("Default domain sending limit"), required=False, help_text=ugettext_lazy( "Number of messages freshly created domains will be " "allowed to send per day. Leave empty for no limit.")) mbsep = SeparatorField(label=ugettext_lazy("Mailboxes")) handle_mailboxes = YesNoField( label=ugettext_lazy("Handle mailboxes on filesystem"), initial=False, help_text=ugettext_lazy( "Rename or remove mailboxes on the filesystem when they get" " renamed or removed within Modoboa")) default_mailbox_quota = forms.IntegerField( label=ugettext_lazy("Default mailbox quota"), initial=0, help_text=ugettext_lazy( "Default mailbox quota (in MB) applied to freshly created " "mailboxes with no value specified. A value of 0 means no quota.")) default_mailbox_message_limit = forms.IntegerField( label=ugettext_lazy("Default mailbox sending limit"), required=False, help_text=ugettext_lazy( "Number of messages freshly created mailboxes will be " "allowed to send per day. Leave empty for no limit.")) auto_account_removal = YesNoField( label=ugettext_lazy("Automatic account removal"), initial=False, help_text=ugettext_lazy( "When a mailbox is removed, also remove the associated account")) auto_create_domain_and_mailbox = YesNoField( label=ugettext_lazy("Automatic domain/mailbox creation"), initial=True, help_text=ugettext_lazy( "Create a domain and a mailbox when an account is automatically " "created.")) create_alias_on_mbox_rename = YesNoField( label=ugettext_lazy("Create an alias when a mailbox is renamed"), initial=False, help_text=ugettext_lazy( "Create an alias using the old address when a mailbox is renamed.") ) # Visibility rules visibility_rules = { "valid_mxs": "enable_mx_checks=True", "domains_must_have_authorized_mx": "enable_mx_checks=True" } def __init__(self, *args, **kwargs): super(AdminParametersForm, self).__init__(*args, **kwargs) self.field_widths = { "default_domain_quota": 2, "default_mailbox_quota": 2 } hide_fields = False dpath = None code, output = exec_cmd("which dovecot") if not code: dpath = force_text(output).strip() else: known_paths = getattr( settings, "DOVECOT_LOOKUP_PATH", ("/usr/sbin/dovecot", "/usr/local/sbin/dovecot")) for fpath in known_paths: if os.path.isfile(fpath) and os.access(fpath, os.X_OK): dpath = fpath if dpath: try: code, version = exec_cmd("%s --version" % dpath) except OSError: hide_fields = True else: version = force_text(version) if code or not version.strip().startswith("2"): hide_fields = True else: hide_fields = True if hide_fields: del self.fields["handle_mailboxes"] def clean_default_domain_quota(self): """Ensure quota is a positive integer.""" if self.cleaned_data["default_domain_quota"] < 0: raise forms.ValidationError( ugettext_lazy("Must be a positive integer")) return self.cleaned_data["default_domain_quota"] def clean_default_mailbox_quota(self): """Ensure quota is a positive integer.""" if self.cleaned_data["default_mailbox_quota"] < 0: raise forms.ValidationError( ugettext_lazy("Must be a positive integer")) return self.cleaned_data["default_mailbox_quota"] def clean_dkim_keys_storage_dir(self): """Check that directory exists.""" storage_dir = self.cleaned_data.get("dkim_keys_storage_dir", "") if storage_dir: if not os.path.isdir(storage_dir): raise forms.ValidationError( ugettext_lazy("Directory not found.")) code, output = exec_cmd("which openssl") if code: raise forms.ValidationError( ugettext_lazy( "openssl not found, please make sure it is installed.") ) return storage_dir def clean(self): """Check MX options.""" cleaned_data = super(AdminParametersForm, self).clean() condition = (cleaned_data.get("enable_mx_checks") and cleaned_data.get("domains_must_have_authorized_mx") and not cleaned_data.get("valid_mxs")) if condition: self.add_error( "valid_mxs", _("Define at least one authorized network / address")) return cleaned_data
class AdminParametersForm(param_forms.AdminParametersForm): app = "admin" dom_sep = SeparatorField(label=ugettext_lazy("Domains")) enable_mx_checks = YesNoField( label=ugettext_lazy("Enable MX checks"), initial=True, help_text=ugettext_lazy( "Check that every domain has a valid MX record")) valid_mxs = forms.CharField( label=ugettext_lazy("Valid MXs"), initial="", help_text=ugettext_lazy( "A list of IP or network address every MX record should match." " A warning will be sent if a record does not respect it."), widget=forms.Textarea, required=False) enable_dnsbl_checks = YesNoField( label=ugettext_lazy("Enable DNSBL checks"), initial=True, help_text=ugettext_lazy( "Check every domain against major DNSBL providers")) mbsep = SeparatorField(label=ugettext_lazy("Mailboxes")) handle_mailboxes = YesNoField( label=ugettext_lazy("Handle mailboxes on filesystem"), initial=False, help_text=ugettext_lazy( "Rename or remove mailboxes on the filesystem when they get" " renamed or removed within Modoboa")) mailboxes_owner = forms.CharField( label=ugettext_lazy("Mailboxes owner"), initial="vmail", help_text=ugettext_lazy( "The UNIX account who owns mailboxes on the filesystem")) default_domain_quota = forms.IntegerField( label=ugettext_lazy("Default domain quota"), initial=0, help_text=ugettext_lazy( "Default quota (in MB) applied to freshly created domains with no " "value specified. A value of 0 means no quota.")) default_mailbox_quota = forms.IntegerField( label=ugettext_lazy("Default mailbox quota"), initial=0, help_text=ugettext_lazy( "Default mailbox quota (in MB) applied to freshly created domains " "with no value specified. A value of 0 means no quota.")) auto_account_removal = YesNoField( label=ugettext_lazy("Automatic account removal"), initial=False, help_text=ugettext_lazy( "When a mailbox is removed, also remove the associated account")) auto_create_domain_and_mailbox = YesNoField( label=ugettext_lazy("Automatic domain/mailbox creation"), initial=True, help_text=ugettext_lazy( "Create a domain and a mailbox when an account is automatically " "created.")) # Visibility rules visibility_rules = { "valid_mxs": "enable_mx_checks=True", "mailboxes_owner": "handle_mailboxes=True", } def __init__(self, *args, **kwargs): super(AdminParametersForm, self).__init__(*args, **kwargs) self.field_widths = { "default_domain_quota": 2, "default_mailbox_quota": 2 } hide_fields = False dpath = None code, output = exec_cmd("which dovecot") if not code: dpath = output.strip() else: known_paths = getattr( settings, "DOVECOT_LOOKUP_PATH", ("/usr/sbin/dovecot", "/usr/local/sbin/dovecot")) for fpath in known_paths: if os.path.isfile(fpath) and os.access(fpath, os.X_OK): dpath = fpath if dpath: try: code, version = exec_cmd("%s --version" % dpath) except OSError: hide_fields = True else: version = force_text(version) if code or not version.strip().startswith("2"): hide_fields = True else: hide_fields = True if hide_fields: del self.fields["handle_mailboxes"] del self.fields["mailboxes_owner"] def clean_default_domain_quota(self): """Ensure quota is a positive integer.""" if self.cleaned_data["default_domain_quota"] < 0: raise forms.ValidationError( ugettext_lazy("Must be a positive integer")) return self.cleaned_data["default_domain_quota"] def clean_default_mailbox_quota(self): """Ensure quota is a positive integer.""" if self.cleaned_data["default_mailbox_quota"] < 0: raise forms.ValidationError( ugettext_lazy("Must be a positive integer")) return self.cleaned_data["default_mailbox_quota"]
class ParametersForm(AdminParametersForm): """Extension settings.""" app = "modoboa_amavis" qsettings_sep = SeparatorField(label=_("Quarantine settings")) max_messages_age = forms.IntegerField( label=_("Maximum message age"), initial=14, help_text=_( "Quarantine messages maximum age (in days) before deletion")) sep1 = SeparatorField(label=_("Messages releasing")) released_msgs_cleanup = YesNoField( label=_("Remove released messages"), initial="no", help_text=_("Remove messages marked as released while cleaning up " "the database")) am_pdp_mode = forms.ChoiceField( label=_("Amavis connection mode"), choices=[("inet", "inet"), ("unix", "unix")], initial="unix", help_text=_("Mode used to access the PDP server"), widget=InlineRadioSelect(attrs={"type": "checkbox"})) am_pdp_host = forms.CharField( label=_("PDP server address"), initial="localhost", help_text=_("PDP server address (if inet mode)"), widget=forms.TextInput(attrs={"class": "form-control"})) am_pdp_port = forms.IntegerField( label=_("PDP server port"), initial=9998, help_text=_("PDP server port (if inet mode)")) am_pdp_socket = forms.CharField( label=_("PDP server socket"), initial="/var/amavis/amavisd.sock", help_text=_("Path to the PDP server socket (if unix mode)")) user_can_release = YesNoField( label=_("Allow direct release"), initial="no", help_text=_("Allow users to directly release their messages")) self_service = YesNoField(label=_("Enable self-service mode"), initial="no", help_text=_("Activate the 'self-service' mode")) notifications_sender = forms.EmailField( label=_("Notifications sender"), initial="*****@*****.**", help_text=_("The e-mail address used to send notitications")) lsep = SeparatorField(label=_("Manual learning")) manual_learning = YesNoField( label=_("Enable manual learning"), initial="yes", help_text=_( "Allow super administrators to manually train Spamassassin")) sa_is_local = YesNoField( label=_("Is Spamassassin local?"), initial="yes", help_text=_( "Tell if Spamassassin is running on the same server than modoboa")) default_user = forms.CharField( label=_("Default user"), initial="amavis", help_text=_("Name of the user owning the default bayesian database")) spamd_address = forms.CharField( label=_("Spamd address"), initial="127.0.0.1", help_text=_("The IP address where spamd can be reached")) spamd_port = forms.IntegerField( label=_("Spamd port"), initial=783, help_text=_("The TCP port spamd is listening on")) domain_level_learning = YesNoField( label=_("Enable per-domain manual learning"), initial="no", help_text=_("Allow domain administrators to train Spamassassin " "(within dedicated per-domain databases)")) user_level_learning = YesNoField( label=_("Enable per-user manual learning"), initial="no", help_text=_("Allow simple users to personally train Spamassassin " "(within a dedicated database)")) visibility_rules = { "am_pdp_host": "am_pdp_mode=inet", "am_pdp_port": "am_pdp_mode=inet", "am_pdp_socket": "am_pdp_mode=unix", "sa_is_local": "manual_learning=yes", "default_user": "******", "spamd_address": "sa_is_local=no", "spamd_port": "sa_is_local=no", "domain_level_learning": "manual_learning=yes", "user_level_learning": "manual_learning=yes" }
class ParametersForm(AdminParametersForm): """Available admin parameters.""" app = "limits" defv_sep = SeparatorField(label=_("Default per-admin limits")) enable_admin_limits = YesNoField( label=_("Enable per-admin limits"), initial="yes", help_text=_("Enable or disable per-admin limits")) deflt_user_domain_admins_limit = forms.IntegerField( label=_("Domain admins"), initial=0, help_text=_( "Maximum number of allowed domain administrators for a new " "administrator. (0 to deny any creation, -1 to allow unlimited " "creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_user_domains_limit = forms.IntegerField( label=_("Domains"), initial=0, help_text=_( "Maximum number of allowed domains for a new administrator. " "(0 to deny any creation, -1 to allow unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_user_domain_aliases_limit = forms.IntegerField( label=_("Domain aliases"), initial=0, help_text=_("Maximum number of allowed domain aliases for a new " "administrator. (0 to deny any creation, -1 to allow " "unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_user_mailboxes_limit = forms.IntegerField( label=_("Mailboxes"), initial=0, help_text=_( "Maximum number of allowed mailboxes for a new administrator. " "(0 to deny any creation, -1 to allow unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_user_mailbox_aliases_limit = forms.IntegerField( label=_("Mailbox aliases"), initial=0, help_text=_( "Maximum number of allowed aliases for a new administrator. " "(0 to deny any creation, -1 to allow unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) domain_limits_sep = SeparatorField(label=_("Default per-domain limits")) enable_domain_limits = YesNoField( label=_("Enable per-domain limits"), initial="no", help_text=_("Enable or disable per-domain limits")) deflt_domain_domain_admins_limit = forms.IntegerField( label=_("Domain admins"), initial=0, help_text=_( "Maximum number of allowed domain administrators for a new " "domain. (0 to deny any creation, -1 to allow unlimited " "creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_domain_domain_aliases_limit = forms.IntegerField( label=_("Domain aliases"), initial=0, help_text=_("Maximum number of allowed domain aliases for a new " "domain. (0 to deny any creation, -1 to allow " "unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_domain_mailboxes_limit = forms.IntegerField( label=_("Mailboxes"), initial=0, help_text=_( "Maximum number of allowed mailboxes for a new domain. " "(0 to deny any creation, -1 to allow unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) deflt_domain_mailbox_aliases_limit = forms.IntegerField( label=_("Mailbox aliases"), initial=0, help_text=_( "Maximum number of allowed aliases for a new domain. " "(0 to deny any creation, -1 to allow unlimited creations)"), widget=forms.widgets.TextInput( attrs={"class": "col-md-1 form-control"})) visibility_rules = { "deflt_user_domains_limit": "enable_admin_limits=yes", "deflt_user_domain_aliases_limit": "enable_admin_limits=yes", "deflt_user_mailboxes_limit": "enable_admin_limits=yes", "deflt_user_mailbox_aliases_limit": "enable_admin_limits=yes", "deflt_user_domain_admins_limit": "enable_admin_limits=yes", "deflt_domain_mailboxes_limit": "enable_domain_limits=yes", "deflt_domain_mailbox_aliases_limit": "enable_domain_limits=yes", "deflt_domain_domain_aliases_limit": "enable_domain_limits=yes", "deflt_domain_domain_admins_limit": "enable_domain_limits=yes", } def __init__(self, *args, **kwargs): super(AdminParametersForm, self).__init__(*args, **kwargs) self._load_extra_parameters('A')