diff --git a/account/conf.py b/account/conf.py index be18bf2b..4df7ec97 100644 --- a/account/conf.py +++ b/account/conf.py @@ -28,6 +28,7 @@ class AccountAppConf(AppConf): OPEN_SIGNUP = True LOGIN_URL = "account_login" + INVITE_USER_URL = "account_invite_user" SIGNUP_REDIRECT_URL = "/" LOGIN_REDIRECT_URL = "/" LOGOUT_REDIRECT_URL = "/" diff --git a/account/forms.py b/account/forms.py index 0f20da56..7baabfda 100644 --- a/account/forms.py +++ b/account/forms.py @@ -14,7 +14,7 @@ from django.contrib.auth.models import User from account.conf import settings -from account.models import EmailAddress +from account.models import EmailAddress, SignupCode alnum_re = re.compile(r"^\w+$") @@ -213,3 +213,9 @@ def clean_email(self): if not qs.exists() or not settings.ACCOUNT_EMAIL_UNIQUE: return value raise forms.ValidationError(_("A user is registered with this email address.")) + + +class SignupCodeForm(forms.ModelForm): + class Meta: + model = SignupCode + fields = ('code', 'max_uses', 'email', 'notes',) diff --git a/account/urls.py b/account/urls.py index f83b7e0b..31012480 100644 --- a/account/urls.py +++ b/account/urls.py @@ -5,7 +5,7 @@ from account.views import SignupView, LoginView, LogoutView, DeleteView from account.views import ConfirmEmailView from account.views import ChangePasswordView, PasswordResetView, PasswordResetTokenView -from account.views import SettingsView +from account.views import SettingsView, InviteUserView urlpatterns = patterns("", @@ -18,4 +18,5 @@ url(r"^password/reset/(?P[0-9A-Za-z]+)-(?P.+)/$", PasswordResetTokenView.as_view(), name="account_password_reset_token"), url(r"^settings/$", SettingsView.as_view(), name="account_settings"), url(r"^delete/$", DeleteView.as_view(), name="account_delete"), + url(r"^invite_user/$", InviteUserView.as_view(), name="account_invite_user"), ) diff --git a/account/views.py b/account/views.py index c3774ae7..9812de80 100644 --- a/account/views.py +++ b/account/views.py @@ -8,7 +8,7 @@ from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _ from django.views.generic.base import TemplateResponseMixin, View -from django.views.generic.edit import FormView +from django.views.generic.edit import FormView, CreateView from django.contrib import auth, messages from django.contrib.auth.models import User @@ -19,7 +19,7 @@ from account.conf import settings from account.forms import SignupForm, LoginUsernameForm from account.forms import ChangePasswordForm, PasswordResetForm, PasswordResetTokenForm -from account.forms import SettingsForm +from account.forms import SettingsForm, SignupCodeForm from account.hooks import hookset from account.mixins import LoginRequiredMixin from account.models import SignupCode, EmailAddress, EmailConfirmation, Account, AccountDeletion @@ -724,3 +724,28 @@ def get_context_data(self, **kwargs): ctx.update(kwargs) ctx["ACCOUNT_DELETION_EXPUNGE_HOURS"] = settings.ACCOUNT_DELETION_EXPUNGE_HOURS return ctx + + +class InviteUserView(LoginRequiredMixin, CreateView): + + template_name = "account/invite_user.html" + form_class = SignupCodeForm + + redirect_field_name = "next" + messages = { + "password_changed": { + "level": messages.SUCCESS, + "text": _("Password successfully changed.") + } + } + + def form_valid(self, form): + signup_code = form.save() + signup_code.send() + messages.success(self.request, _("Invitation sent to user '%s'") % signup_code.email) + return super(InviteUserView, self).form_valid(form) + + def get_success_url(self, fallback_url=None, **kwargs): + if fallback_url is None: + fallback_url = settings.ACCOUNT_INVITE_USER_URL + return default_redirect(self.request, fallback_url, **kwargs)