You've already forked Mailu
							
							
				mirror of
				https://github.com/Mailu/Mailu.git
				synced 2025-10-30 23:37:43 +02:00 
			
		
		
		
	Enable self-service account signup
This commit is contained in:
		| @@ -60,6 +60,7 @@ class Domain(Base): | ||||
|     max_users = db.Column(db.Integer, nullable=False, default=0) | ||||
|     max_aliases = 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) | ||||
|  | ||||
|     @property | ||||
|     def dkim_key(self): | ||||
|   | ||||
| @@ -47,6 +47,7 @@ class DomainForm(flask_wtf.FlaskForm): | ||||
|     max_users = fields_.IntegerField(_('Maximum user count'), default=10) | ||||
|     max_aliases = fields_.IntegerField(_('Maximum alias count'), default=10) | ||||
|     max_quota_bytes = fields_.IntegerSliderField(_('Maximum user quota'), default=0) | ||||
|     signup_enabled = fields.BooleanField(_('Enable sign-up'), default=False) | ||||
|     comment = fields.StringField(_('Comment')) | ||||
|     submit = fields.SubmitField(_('Create')) | ||||
|  | ||||
| @@ -74,6 +75,13 @@ class UserForm(flask_wtf.FlaskForm): | ||||
|     submit = fields.SubmitField(_('Save')) | ||||
|  | ||||
|  | ||||
| class UserSignupForm(flask_wtf.FlaskForm): | ||||
|     localpart = fields.StringField(_('Email address')) | ||||
|     pw = fields.PasswordField(_('Password'), [validators.DataRequired()]) | ||||
|     pw2 = fields.PasswordField(_('Confirm password'), [validators.EqualTo('pw')]) | ||||
|     submit = fields.SubmitField(_('Sign up')) | ||||
|  | ||||
|  | ||||
| class UserSettingsForm(flask_wtf.FlaskForm): | ||||
|     displayed_name = fields.StringField(_('Displayed name')) | ||||
|     spam_enabled = fields.BooleanField(_('Enable spam filter')) | ||||
|   | ||||
| @@ -100,10 +100,17 @@ | ||||
|     </li> | ||||
|     {% else %} | ||||
|     <li> | ||||
|       <a href="#"> | ||||
|       <a href="{{ url_for('.login') }}"> | ||||
|         <i class="fa fa-sign-in"></i> <span>{% trans %}Sign in{% endtrans %}</span> | ||||
|       </a> | ||||
|     </li> | ||||
|     {% if signup_domains %} | ||||
|     <li> | ||||
|       <a href="{{ url_for('.user_signup') }}"> | ||||
|         <i class="fa fa-user-plus"></i> <span>{% trans %}Sign up{% endtrans %}</span> | ||||
|       </a> | ||||
|     </li> | ||||
|     {% endif %} | ||||
|     {% endif %} | ||||
|   </ul> | ||||
| </section> | ||||
|   | ||||
							
								
								
									
										20
									
								
								core/admin/mailu/ui/templates/user/signup.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								core/admin/mailu/ui/templates/user/signup.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| {% extends "base.html" %} | ||||
|  | ||||
| {% block title %} | ||||
| {% trans %}Sign up{% endtrans %} | ||||
| {% endblock %} | ||||
|  | ||||
| {% block subtitle %} | ||||
| {{ domain }} | ||||
| {% endblock %} | ||||
|  | ||||
| {% block content %} | ||||
| <form class="form" method="post" role="form"> | ||||
|   {{ form.hidden_tag() }} | ||||
|   {% call macros.box() %} | ||||
|   {{ macros.form_field(form.localpart, append='<span class="input-group-addon">@'+domain.name+'</span>') }} | ||||
|   {{ macros.form_fields((form.pw, form.pw2)) }} | ||||
|   {{ macros.form_field(form.submit) }} | ||||
|   {% endcall %} | ||||
| </form> | ||||
| {% endblock %} | ||||
							
								
								
									
										26
									
								
								core/admin/mailu/ui/templates/user/signup_domain.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								core/admin/mailu/ui/templates/user/signup_domain.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| {% extends "base.html" %} | ||||
|  | ||||
| {% block title %} | ||||
| {% trans %}Sign up{% endtrans %} | ||||
| {% endblock %} | ||||
|  | ||||
| {% block subtitle %} | ||||
| {% trans %}pick a domain for the new account{% endtrans %} | ||||
| {% endblock %} | ||||
|  | ||||
| {% block content %} | ||||
| {% call macros.table() %} | ||||
| <tr> | ||||
|   <th>{% trans %}Domain{% endtrans %}</th> | ||||
|   <th>{% trans %}Available slots{% endtrans %}</th> | ||||
|   <th>{% trans %}Quota{% endtrans %}</th> | ||||
| </tr> | ||||
| {% for domain_name, domain in available_domains.items() %} | ||||
| <tr> | ||||
|   <td><a href="{{ url_for('.user_signup', domain_name=domain_name) }}">{{ domain_name }}</a></td> | ||||
|   <td>{{ domain.max_users - domain.users if domain.max_users else '∞' }}</td> | ||||
|   <td>{{ domain.max_quota_bytes or config['DEFAULT_QUOTA'] | filesizeformat }}</td> | ||||
| </tr> | ||||
| {% endfor %} | ||||
| {% endcall %} | ||||
| {% endblock %} | ||||
| @@ -153,3 +153,35 @@ def user_reply(user_email): | ||||
|             return flask.redirect( | ||||
|                 flask.url_for('.user_list', domain_name=user.domain.name)) | ||||
|     return flask.render_template('user/reply.html', form=form, user=user) | ||||
|  | ||||
|  | ||||
| @ui.route('/user/signup', methods=['GET', 'POST']) | ||||
| @ui.route('/user/signup/<domain_name>', methods=['GET', 'POST']) | ||||
| def user_signup(domain_name=None): | ||||
|     available_domains = { | ||||
|         domain.name: domain | ||||
|         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 not available_domains: | ||||
|         flask.flash('No domain available for registration') | ||||
|     if not domain_name: | ||||
|         return flask.render_template('user/signup_domain.html', | ||||
|             available_domains=available_domains) | ||||
|     domain = available_domains.get(domain_name) or flask.abort(404) | ||||
|     quota_bytes = min(config['DEFAULT_QUOTA'], domain.max_quota_bytes) | ||||
|     form = forms.UserSignupForm() | ||||
|     if form.validate_on_submit(): | ||||
|         if domain.has_email(form.localpart.data): | ||||
|             flask.flash('Email is already used', 'error') | ||||
|         else: | ||||
|             user = models.User(domain=domain) | ||||
|             form.populate_obj(user) | ||||
|             user.set_password(form.pw.data) | ||||
|             user.quota_bytes = quota_bytes | ||||
|             db.session.add(user) | ||||
|             db.session.commit() | ||||
|             user.send_welcome() | ||||
|             flask.flash('Successfully signed up %s' % user) | ||||
|             return flask.redirect(flask.url_for('.index')) | ||||
|     return flask.render_template('user/signup.html', domain=domain, form=form) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user