Просмотр исходного кода

Auth app merged into Users app

Ralfp 12 лет назад
Родитель
Сommit
4ad8a63bcc
46 измененных файлов с 448 добавлено и 417 удалено
  1. 0 0
      misago/auth/__init__.py
  2. 0 116
      misago/auth/fixtures.py
  3. 0 9
      misago/auth/urls.py
  4. 0 215
      misago/auth/views.py
  5. 0 1
      misago/settings_base.py
  6. 0 1
      misago/urls.py
  7. 112 5
      misago/users/fixtures.py
  8. 0 0
      misago/users/forms.py
  9. 13 8
      misago/users/urls.py
  10. 1 56
      misago/users/views.py
  11. 77 0
      misago/users/views/__init__.py
  12. 79 0
      misago/users/views/activation.py
  13. 83 0
      misago/users/views/password.py
  14. 25 0
      misago/users/views/profiles.py
  15. 58 0
      misago/users/views/usercp.py
  16. 0 0
      templates/_email/users/activation_0_html.html
  17. 0 0
      templates/_email/users/activation_0_plain.html
  18. 0 0
      templates/_email/users/activation_1_html.html
  19. 0 0
      templates/_email/users/activation_1_plain.html
  20. 0 0
      templates/_email/users/activation_2_html.html
  21. 0 0
      templates/_email/users/activation_2_plain.html
  22. 0 0
      templates/_email/users/activation_resend_html.html
  23. 0 0
      templates/_email/users/activation_resend_plain.html
  24. 0 0
      templates/_email/users/reset_confirm_html.html
  25. 0 0
      templates/_email/users/reset_confirm_plain.html
  26. 0 0
      templates/_email/users/reset_new_html.html
  27. 0 0
      templates/_email/users/reset_new_plain.html
  28. 0 6
      templates/_message/auth/invalid_confirmation_password.html
  29. 0 0
      templates/_message/users/activations/admin.html
  30. 0 0
      templates/_message/users/activations/new.html
  31. 0 0
      templates/_message/users/activations/not_required.html
  32. 0 0
      templates/_message/users/activations/only_by_admin.html
  33. 0 0
      templates/_message/users/activations/password.html
  34. 0 0
      templates/_message/users/activations/required.html
  35. 0 0
      templates/_message/users/activations/resent.html
  36. 0 0
      templates/_message/users/activations/user.html
  37. 0 0
      templates/_message/users/invalid_confirmation_link.html
  38. 0 0
      templates/_message/users/passwords/reset_confirm.html
  39. 0 0
      templates/_message/users/passwords/reset_done.html
  40. 0 0
      templates/_message/users/registrations/registered_activation_admin.html
  41. 0 0
      templates/_message/users/registrations/registered_activation_none.html
  42. 0 0
      templates/_message/users/registrations/registered_activation_user.html
  43. 0 0
      templates/_message/users/registrations/registrations_off.html
  44. 0 0
      templates/sora/users/forgot_password.html
  45. 0 0
      templates/sora/users/register.html
  46. 0 0
      templates/sora/users/resend_activation.html

+ 0 - 0
misago/auth/__init__.py


+ 0 - 116
misago/auth/fixtures.py

@@ -1,116 +0,0 @@
-from misago.settings.fixtures import load_settings_fixture
-from misago.utils import ugettext_lazy as _
-from misago.utils import get_msgid
-
-settings_fixtures = (
-   # Register and Sign-In Settings
-   ('register-and-signin', {
-        'name': _("Register and Sign-In Settings"),
-        'description': _("Those settings allow you to increase security of your members accounts."),
-        'settings': (
-            ('account_activation', {
-                'type':         "string",
-                'input':        "choice",
-                'extra':        {'choices': [('', _("No validation required")), ('user', _("Activation Token sent to User")), ('admin', _("Activation by Administrator")), ('block', _("Dont allow new registrations"))]},
-                'separator':    _("Users Registrations"),
-                'name':         _("New accounts validation"),
-            }),
-            ('default_timezone', {
-                'value':        "utc",
-                'type':         "string",
-                'input':        "select",
-                'extra':        {'choices': '#TZ#'},
-                'name':         _("Default Timezone"),
-                'description':  _("Used by guests, crawlers and newly registered users."),
-            }),
-            ('password_length', {
-                'value':        4,
-                'type':         "integer",
-                'input':        "text",
-                'extra':        {'min': 1},
-                'separator':    _("Users Passwords"),
-                'name':         _("Minimum user password length"),
-            }),
-            ('password_complexity', {
-                'value':        [],
-                'type':         "array",
-                'input':        "mlist",
-                'extra':        {'choices': [('case', _("Require mixed Case")), ('digits', _("Require digits")), ('special', _("Require special characters"))]},
-                'name':         _("Password Complexity"),
-            }),
-            ('password_lifetime', {
-                'value':        0,
-                'type':         "integer",
-                'input':        "text",
-                'extra':        {'min': 0},
-                'name':         _("Password Lifetime"),
-                'description':  _("Enter number of days since password was set to force member to change it with new one, or 0 to dont force your members to change their passwords."),
-            }),
-            ('sessions_hidden', {
-                'value':        True,
-                'type':         "boolean",
-                'input':        "yesno",
-                'separator':    _("Sessions Settings"),
-                'name':         _("Allow hidden sessions"),
-                'description':  _("Enabling this option will allow users to hide their presence on forums from other members."),
-            }),
-            ('sessions_validate_ip', {
-                'value':        True,
-                'type':         "boolean",
-                'input':        "yesno",
-                'name':         _("Check IP on session authorization"),
-                'description':  _("Makes sessions more secure, but can cause problems with proxies and VPN's."),
-            }),
-            ('remember_me_allow', {
-                'value':        True,
-                'type':         "boolean",
-                'input':        "yesno",
-                'separator':    _("Sign-In Settings"),
-                'name':         _('Enable "Remember Me" functionality'),
-                'description':  _("Turning this option on allows users to sign in on to your board using cookie-based tokens. This may result in account compromisation when user fails to sign out on shared computer."),
-            }),
-            ('remember_me_lifetime', {
-                'value':        90,
-                'type':         "integer",
-                'input':        "text",
-                'name':         _('"Remember Me" token lifetime'),
-                'description':  _('Number of days since either last use or creation of "Remember Me" token to its expiration.'),
-            }),
-            ('remember_me_extensible', {
-                'value':        1,
-                'type':         "boolean",
-                'input':        "yesno",
-                'name':         _('Allow "Remember Me" tokens refreshing'),
-                'description':  _('Set this setting to off if you want to force your users to periodically update their "Remember Me" tokens by signing in. If this option is on, Tokens are updated when they are used to open new session.'),
-            }),
-            ('login_attempts_limit', {
-                'value':        3,
-                'default':      3,
-                'type':         "integer",
-                'input':        "text",
-                'separator':    _("Brute-Force Countermeasures"),
-                'name':         _("Limit Sign In attempts"),
-                'description':  _('Enter maximal number of allowed Sign In attempts before IP address "jams".'),
-            }),
-            ('registrations_jams', {
-                'value':        1,
-                'default':      1,
-                'type':         "boolean",
-                'input':        "yesno",
-                'name':         _("Count failed register attempts too"),
-                'description':  _("Set this setting to yes if you want failed register attempts to count into limit."),
-            }),
-            ('jams_lifetime', {
-                'value':        15,
-                'default':      15,
-                'type':         "integer",
-                'input':        "text",
-                'name':         _("Automaticaly unlock jammed IPs"),
-                'description':  _('Enter number of minutes since IP address "jams" to automatically unlock it, or 0 to never unlock jammed IP adresses. Jams dont count as bans.'),
-            }),
-        ),
-    }),
-)
-
-def load_fixture():
-    load_settings_fixture(settings_fixtures)

+ 0 - 9
misago/auth/urls.py

@@ -1,9 +0,0 @@
-from django.conf.urls import patterns, url, include
-
-urlpatterns = patterns('misago.auth.views',
-    url(r'^register/$', 'register', name="register"),
-    url(r'^activate/(?P<username>\w+)-(?P<user>\d+)/(?P<token>[a-zA-Z0-9]+)/$', 'activate', name="activate"),
-    url(r'^resend-activation/$', 'send_activation', name="send_activation"),
-    url(r'^reset-pass/$', 'forgot_password', name="forgot_password"),
-    url(r'^reset-pass/(?P<username>\w+)-(?P<user>\d+)/(?P<token>[a-zA-Z0-9]+)/$', 'reset_password', name="reset_password"),
-)

+ 0 - 215
misago/auth/views.py

@@ -1,215 +0,0 @@
-from django.core.urlresolvers import reverse
-from django.shortcuts import redirect
-from django.template import RequestContext
-from django.utils import timezone
-from django.utils.translation import ugettext as _
-from misago.banning.models import check_ban
-from misago.banning.decorators import block_banned
-from misago.banning.views import error_banned
-from misago.forms.layouts import FormLayout
-from misago.messages import Message
-from misago.security import get_random_string
-from misago.security.auth import sign_user_in
-from misago.security.decorators import *
-from misago.sessions.models import *
-from misago.auth.forms import *
-from misago.users.models import User, Group
-from misago.views import error403, error404
-
-@block_banned
-@block_authenticated
-@block_jammed
-def register(request):
-    if request.settings['account_activation'] == 'block':
-        return error403(request, Message(request, 'auth/registrations_off'))
-    message = None
-    if request.method == 'POST':
-        form = UserRegisterForm(request.POST, request=request)
-        if form.is_valid():
-            need_activation = 0
-            if request.settings['account_activation'] == 'user':
-                need_activation = User.ACTIVATION_USER
-            if request.settings['account_activation'] == 'admin':
-                need_activation = User.ACTIVATION_ADMIN
-            new_user = User.objects.create_user(
-                                                form.cleaned_data['username'],
-                                                form.cleaned_data['email'],
-                                                form.cleaned_data['password'],
-                                                Group.objects.get(pk=3), # Registered members
-                                                ip=request.session.get_ip(request),
-                                                activation=need_activation,
-                                                request=request
-                                                )
-            if need_activation == User.ACTIVATION_NONE:
-                # No need for activation, sign in user
-                sign_user_in(request, new_user)
-                request.messages.set_flash(Message(request, 'auth/registered_activation_none', extra={'user':new_user}), 'success')
-            if need_activation == User.ACTIVATION_USER:
-                # Mail user activation e-mail
-                request.messages.set_flash(Message(request, 'auth/registered_activation_user', extra={'user':new_user}), 'info')
-                new_user.email_user(
-                                    request,
-                                    'auth/activation_0',
-                                    _("Welcome aboard, %(username)s!" % {'username': new_user.username}),
-                                    )
-            if need_activation == User.ACTIVATION_ADMIN:
-                # Require admin activation
-                request.messages.set_flash(Message(request, 'users/registered_activation_admin', extra={'user':new_user}), 'info')
-            new_user.email_user(
-                                request,
-                                ('auth/activation_%s' % need_activation),
-                                _("Welcome aboard, %(username)s!" % {'username': new_user.username}),
-                                {'password': form.cleaned_data['password']}
-                                )
-            return redirect(reverse('index'))
-        else:
-            message = Message(request, form.non_field_errors()[0])
-            if request.settings['registrations_jams']:
-                SignInAttempt.objects.register_attempt(request.session.get_ip(request))
-            # Have we jammed our account?
-            if SignInAttempt.objects.is_jammed(request.session.get_ip(request)):
-                request.jam.expires = timezone.now()
-                return redirect(reverse('register'))
-    else:
-        form = UserRegisterForm(request=request)
-    return request.theme.render_to_response('auth/register.html',
-                                            {
-                                             'message': message,
-                                             'form': FormLayout(form),
-                                             'hide_signin': True, 
-                                            },
-                                            context_instance=RequestContext(request));
-
-
-@block_banned
-@block_authenticated
-@block_jammed
-def send_activation(request):
-    message = None
-    if request.method == 'POST':
-        form = UserSendSpecialMailForm(request.POST, request=request)
-        if form.is_valid():
-            user = form.found_user
-            user_ban = check_ban(username=user.username, email=user.email)
-            if user_ban:
-                return error_banned(request, user, user_ban)
-            if user.activation == User.ACTIVATION_NONE:
-                return error403(request, Message(request, 'auth/activation_not_required', extra={'user': user}))
-            if user.activation == User.ACTIVATION_ADMIN:
-                return error403(request, Message(request, 'auth/activation_only_by_admin', extra={'user': user}))
-            request.messages.set_flash(Message(request, 'auth/activation_resent', extra={'user':user}), 'success')
-            user.email_user(
-                            request,
-                            'auth/activation_resend',
-                            _("New Account Activation"),
-                            )
-            return redirect(reverse('index'))
-        else:
-            message = Message(request, form.non_field_errors()[0])
-    else:
-        form = UserSendSpecialMailForm(request=request)
-    return request.theme.render_to_response('auth/resend_activation.html',
-                                            {
-                                             'message': message,
-                                             'form': FormLayout(form),
-                                            },
-                                            context_instance=RequestContext(request));
-                                            
-                                            
-@block_banned
-@block_authenticated
-@block_jammed
-def activate(request, username="", user="0", token=""):
-    user = int(user)
-    try:
-        user = User.objects.get(pk=user)
-        current_activation = user.activation
-        # Run checks
-        user_ban = check_ban(username=user.username, email=user.email)
-        if user_ban:
-            return error_banned(request, user, user_ban)
-        if user.activation == User.ACTIVATION_NONE:
-            return error403(request, Message(request, 'auth/activation_not_required', extra={'user': user}))
-        if user.activation == User.ACTIVATION_ADMIN:
-            return error403(request, Message(request, 'auth/activation_only_by_admin', extra={'user': user}))
-        if not token or not user.token or user.token != token:
-            return error403(request, Message(request, 'auth/invalid_confirmation_activation', extra={'user': user}))
-        # Activate and sign in our member
-        user.activation = User.ACTIVATION_NONE
-        sign_user_in(request, user)
-        if current_activation == User.ACTIVATION_PASSWORD:
-            request.messages.set_flash(Message(request, 'auth/activated_password', extra={'user':user}), 'success')
-        else:
-            request.messages.set_flash(Message(request, 'auth/activated_new', extra={'user':user}), 'success')
-        return redirect(reverse('index'))
-    except User.DoesNotExist:
-        return error404(request)
-
-
-@block_banned
-@block_authenticated
-@block_jammed   
-def forgot_password(request):
-    message = None
-    if request.method == 'POST':
-        form = UserSendSpecialMailForm(request.POST, request=request)
-        if form.is_valid():
-            user = form.found_user
-            user_ban = check_ban(username=user.username, email=user.email)
-            if user_ban:
-                return error_banned(request, user, user_ban)
-            elif user.activation != User.ACTIVATION_NONE:
-                return error403(request, Message(request, 'auth/activation_required', {'user': user}))
-            user.token = get_random_string(12)
-            user.save(force_update=True)
-            request.messages.set_flash(Message(request, 'auth/password_reset_confirm', extra={'user':user}), 'success')
-            user.email_user(
-                            request,
-                            'auth/reset_confirm',
-                            _("Confirm New Password Request")
-                            )
-            return redirect(reverse('index'))
-        else:
-            message = Message(request, form.non_field_errors()[0])
-    else:
-        form = UserSendSpecialMailForm(request=request)
-    return request.theme.render_to_response('auth/forgot_password.html',
-                                            {
-                                             'message': message,
-                                             'form': FormLayout(form),
-                                            },
-                                            context_instance=RequestContext(request));
-
-
-@block_banned
-@block_authenticated
-@block_jammed
-def reset_password(request, username="", user="0", token=""):
-    user = int(user)
-    try:
-        user = User.objects.get(pk=user)
-        user_ban = check_ban(username=user.username, email=user.email)
-        if user_ban:
-            return error_banned(request, user, user_ban)
-        if user.activation != User.ACTIVATION_NONE:
-            return error403(request, Message(request, 'auth/activation_required', {'user': user}))
-        if not token or not user.token or user.token != token:
-            return error403(request, Message(request, 'auth/invalid_confirmation_link', {'user': user}))
-        new_password = get_random_string(6)
-        user.token = None
-        user.set_password(new_password)
-        user.save(force_update=True)
-        # Logout signed in and kill remember me tokens
-        Session.objects.filter(user=user).update(user=None)
-        Token.objects.filter(user=user).delete()
-        # Set flash and mail new password
-        request.messages.set_flash(Message(request, 'auth/password_reset_done', extra={'user':user}), 'success')
-        user.email_user(
-                        request,
-                        'auth/reset_new',
-                        _("Your New Password"),
-                        {'password': new_password}
-                        )
-        return redirect(reverse('sign_in'))
-    except User.DoesNotExist:
-        return error404(request)

+ 0 - 1
misago/settings_base.py

@@ -104,7 +104,6 @@ INSTALLED_APPS = (
     'misago.utils', # Utility classes
     # Applications with dependencies
     'misago.acl', # Web crawlers handling
-    'misago.auth', # User register, sign-in and sign-out
     'misago.banning', # Banning and blacklisting users
     'misago.crawlers', # Web crawlers handling
     'misago.cookie_jar', # Cookies helper

+ 0 - 1
misago/urls.py

@@ -6,7 +6,6 @@ from misago.admin import ADMIN_PATH, site
 # Include frontend patterns
 urlpatterns = patterns('',
     (r'^', include('misago.security.urls')),
-    (r'^', include('misago.auth.urls')),
     (r'^', include('misago.users.urls')),
     url(r'^$', 'misago.views.home', name="index"),
 )

+ 112 - 5
misago/users/fixtures.py

@@ -14,11 +14,11 @@ monitor_fixtures = {
                   }
 
 settings_fixtures = (
-   # Avatars Settings
-   ('avatars', {
-        'name': _("Users Avatars Settings"),
-        'description': _("Those settings allow you to control your users avatars."),
-        'settings': (
+    # Avatars Settings
+    ('avatars', {
+         'name': _("Users Avatars Settings"),
+         'description': _("Those settings allow you to control your users avatars."),
+         'settings': (
             ('avatars_types', {
                 'value':        ['gravatar', 'gallery'],
                 'type':         "array",
@@ -45,6 +45,113 @@ settings_fixtures = (
                 'name':         _("Maxmimum size of uploaded file"),
                 'description':  _("Select maximum allowed file size (in KB) for Avatar uploads."),
             }),
+       ),
+    }),
+    # Register and Sign-In Settings
+    ('register-and-signin', {
+        'name': _("Register and Sign-In Settings"),
+        'description': _("Those settings allow you to increase security of your members accounts."),
+        'settings': (
+            ('account_activation', {
+                'type':         "string",
+                'input':        "choice",
+                'extra':        {'choices': [('', _("No validation required")), ('user', _("Activation Token sent to User")), ('admin', _("Activation by Administrator")), ('block', _("Dont allow new registrations"))]},
+                'separator':    _("Users Registrations"),
+                'name':         _("New accounts validation"),
+            }),
+            ('default_timezone', {
+                'value':        "utc",
+                'type':         "string",
+                'input':        "select",
+                'extra':        {'choices': '#TZ#'},
+                'name':         _("Default Timezone"),
+                'description':  _("Used by guests, crawlers and newly registered users."),
+            }),
+            ('password_length', {
+                'value':        4,
+                'type':         "integer",
+                'input':        "text",
+                'extra':        {'min': 1},
+                'separator':    _("Users Passwords"),
+                'name':         _("Minimum user password length"),
+            }),
+            ('password_complexity', {
+                'value':        [],
+                'type':         "array",
+                'input':        "mlist",
+                'extra':        {'choices': [('case', _("Require mixed Case")), ('digits', _("Require digits")), ('special', _("Require special characters"))]},
+                'name':         _("Password Complexity"),
+            }),
+            ('password_lifetime', {
+                'value':        0,
+                'type':         "integer",
+                'input':        "text",
+                'extra':        {'min': 0},
+                'name':         _("Password Lifetime"),
+                'description':  _("Enter number of days since password was set to force member to change it with new one, or 0 to dont force your members to change their passwords."),
+            }),
+            ('sessions_hidden', {
+                'value':        True,
+                'type':         "boolean",
+                'input':        "yesno",
+                'separator':    _("Sessions Settings"),
+                'name':         _("Allow hidden sessions"),
+                'description':  _("Enabling this option will allow users to hide their presence on forums from other members."),
+            }),
+            ('sessions_validate_ip', {
+                'value':        True,
+                'type':         "boolean",
+                'input':        "yesno",
+                'name':         _("Check IP on session authorization"),
+                'description':  _("Makes sessions more secure, but can cause problems with proxies and VPN's."),
+            }),
+            ('remember_me_allow', {
+                'value':        True,
+                'type':         "boolean",
+                'input':        "yesno",
+                'separator':    _("Sign-In Settings"),
+                'name':         _('Enable "Remember Me" functionality'),
+                'description':  _("Turning this option on allows users to sign in on to your board using cookie-based tokens. This may result in account compromisation when user fails to sign out on shared computer."),
+            }),
+            ('remember_me_lifetime', {
+                'value':        90,
+                'type':         "integer",
+                'input':        "text",
+                'name':         _('"Remember Me" token lifetime'),
+                'description':  _('Number of days since either last use or creation of "Remember Me" token to its expiration.'),
+            }),
+            ('remember_me_extensible', {
+                'value':        1,
+                'type':         "boolean",
+                'input':        "yesno",
+                'name':         _('Allow "Remember Me" tokens refreshing'),
+                'description':  _('Set this setting to off if you want to force your users to periodically update their "Remember Me" tokens by signing in. If this option is on, Tokens are updated when they are used to open new session.'),
+            }),
+            ('login_attempts_limit', {
+                'value':        3,
+                'default':      3,
+                'type':         "integer",
+                'input':        "text",
+                'separator':    _("Brute-Force Countermeasures"),
+                'name':         _("Limit Sign In attempts"),
+                'description':  _('Enter maximal number of allowed Sign In attempts before IP address "jams".'),
+            }),
+            ('registrations_jams', {
+                'value':        1,
+                'default':      1,
+                'type':         "boolean",
+                'input':        "yesno",
+                'name':         _("Count failed register attempts too"),
+                'description':  _("Set this setting to yes if you want failed register attempts to count into limit."),
+            }),
+            ('jams_lifetime', {
+                'value':        15,
+                'default':      15,
+                'type':         "integer",
+                'input':        "text",
+                'name':         _("Automaticaly unlock jammed IPs"),
+                'description':  _('Enter number of minutes since IP address "jams" to automatically unlock it, or 0 to never unlock jammed IP adresses. Jams dont count as bans.'),
+            }),
         ),
     }),
 )

+ 0 - 0
misago/auth/forms.py → misago/users/forms.py


+ 13 - 8
misago/users/urls.py

@@ -1,12 +1,17 @@
 from django.conf.urls import patterns, url, include
 
 urlpatterns = patterns('misago.users.views',
-    url(r'^users/$', 'users', name="users"),
-    url(r'^users/(?P<username>\w+)-(?P<user>\d+)/$', 'user_profile', name="user"),
-    url(r'^usercp/$', 'usercp_options', name="usercp"),
-    url(r'^usercp/credentials$', 'usercp_credentials', name="usercp_credentials"),
-    url(r'^usercp/username$', 'usercp_username', name="usercp_username"),
-    url(r'^usercp/avatar$', 'usercp_avatar', name="usercp_avatar"),
-    url(r'^usercp/signature$', 'usercp_signature', name="usercp_signature"),
-    url(r'^usercp/ignored$', 'usercp_ignored', name="usercp_ignored"),
+    url(r'^register/$', 'register', name="register"),
+    url(r'^activate/(?P<username>\w+)-(?P<user>\d+)/(?P<token>[a-zA-Z0-9]+)/$', 'activation.activate', name="activate"),
+    url(r'^resend-activation/$', 'activation.form', name="send_activation"),
+    url(r'^reset-pass/$', 'password.form', name="forgot_password"),
+    url(r'^reset-pass/(?P<username>\w+)-(?P<user>\d+)/(?P<token>[a-zA-Z0-9]+)/$', 'password.reset', name="reset_password"),
+    url(r'^users/$', 'profiles.list', name="users"),
+    url(r'^users/(?P<username>\w+)-(?P<user>\d+)/$', 'profiles.show', name="user"),
+    url(r'^usercp/$', 'usercp.options', name="usercp"),
+    url(r'^usercp/credentials$', 'usercp.credentials', name="usercp_credentials"),
+    url(r'^usercp/username$', 'usercp.username', name="usercp_username"),
+    url(r'^usercp/avatar$', 'usercp.avatar', name="usercp_avatar"),
+    url(r'^usercp/signature$', 'usercp.signature', name="usercp_signature"),
+    url(r'^usercp/ignored$', 'usercp.ignored', name="usercp_ignored"),
 )

+ 1 - 56
misago/users/views.py

@@ -1,7 +1,6 @@
 from django.core.urlresolvers import reverse
 from django.shortcuts import redirect
 from django.template import RequestContext
-from misago.security.decorators import *
 from misago.users.models import User, Group
 from misago.views import error403, error404
 
@@ -23,58 +22,4 @@ def user_profile(request, user, username):
                                             },
                                             context_instance=RequestContext(request));
     except User.DoesNotExist:
-        return error404(request)
-
-
-@block_guest   
-def usercp_options(request):
-    return request.theme.render_to_response('users/usercp/options.html',
-                                            {
-                                             'tab': 'options',
-                                             },
-                                            context_instance=RequestContext(request));
-    
- 
-@block_guest
-def usercp_credentials(request):
-    return request.theme.render_to_response('users/usercp/credentials.html',
-                                            {
-                                             'tab': 'credentials',
-                                             },
-                                            context_instance=RequestContext(request));
-    
- 
-@block_guest
-def usercp_username(request):
-    return request.theme.render_to_response('users/usercp/username.html',
-                                            {
-                                             'tab': 'username',
-                                             },
-                                            context_instance=RequestContext(request));
-    
- 
-@block_guest
-def usercp_avatar(request):
-    return request.theme.render_to_response('users/usercp/avatar.html',
-                                            {
-                                             'tab': 'avatar',
-                                             },
-                                            context_instance=RequestContext(request));
-    
- 
-@block_guest
-def usercp_signature(request):
-    return request.theme.render_to_response('users/usercp/signature.html',
-                                            {
-                                             'tab': 'signature',
-                                             },
-                                            context_instance=RequestContext(request));
-    
- 
-@block_guest
-def usercp_ignored(request):
-    return request.theme.render_to_response('users/usercp/ignored.html',
-                                            {
-                                             'tab': 'ignored',
-                                             },
-                                            context_instance=RequestContext(request));
+        return error404(request)

+ 77 - 0
misago/users/views/__init__.py

@@ -0,0 +1,77 @@
+from django.core.urlresolvers import reverse
+from django.shortcuts import redirect
+from django.template import RequestContext
+from django.utils import timezone
+from django.utils.translation import ugettext as _
+from misago.banning.decorators import block_banned
+from misago.forms.layouts import FormLayout
+from misago.messages import Message
+from misago.security.auth import sign_user_in
+from misago.security.decorators import *
+from misago.users.forms import *
+from misago.users.models import User, Group
+from misago.views import error403
+
+@block_banned
+@block_authenticated
+@block_jammed
+def register(request):
+    if request.settings['account_activation'] == 'block':
+        return error403(request, Message(request, 'auth/registrations_off'))
+    message = None
+    if request.method == 'POST':
+        form = UserRegisterForm(request.POST, request=request)
+        if form.is_valid():
+            need_activation = 0
+            if request.settings['account_activation'] == 'user':
+                need_activation = User.ACTIVATION_USER
+            if request.settings['account_activation'] == 'admin':
+                need_activation = User.ACTIVATION_ADMIN
+            new_user = User.objects.create_user(
+                                                form.cleaned_data['username'],
+                                                form.cleaned_data['email'],
+                                                form.cleaned_data['password'],
+                                                Group.objects.get(pk=3), # Registered members
+                                                ip=request.session.get_ip(request),
+                                                activation=need_activation,
+                                                request=request
+                                                )
+            if need_activation == User.ACTIVATION_NONE:
+                # No need for activation, sign in user
+                sign_user_in(request, new_user)
+                request.messages.set_flash(Message(request, 'auth/registered_activation_none', extra={'user':new_user}), 'success')
+            if need_activation == User.ACTIVATION_USER:
+                # Mail user activation e-mail
+                request.messages.set_flash(Message(request, 'auth/registered_activation_user', extra={'user':new_user}), 'info')
+                new_user.email_user(
+                                    request,
+                                    'auth/activation_0',
+                                    _("Welcome aboard, %(username)s!" % {'username': new_user.username}),
+                                    )
+            if need_activation == User.ACTIVATION_ADMIN:
+                # Require admin activation
+                request.messages.set_flash(Message(request, 'users/registered_activation_admin', extra={'user':new_user}), 'info')
+            new_user.email_user(
+                                request,
+                                ('auth/activation_%s' % need_activation),
+                                _("Welcome aboard, %(username)s!" % {'username': new_user.username}),
+                                {'password': form.cleaned_data['password']}
+                                )
+            return redirect(reverse('index'))
+        else:
+            message = Message(request, form.non_field_errors()[0])
+            if request.settings['registrations_jams']:
+                SignInAttempt.objects.register_attempt(request.session.get_ip(request))
+            # Have we jammed our account?
+            if SignInAttempt.objects.is_jammed(request.session.get_ip(request)):
+                request.jam.expires = timezone.now()
+                return redirect(reverse('register'))
+    else:
+        form = UserRegisterForm(request=request)
+    return request.theme.render_to_response('auth/register.html',
+                                            {
+                                             'message': message,
+                                             'form': FormLayout(form),
+                                             'hide_signin': True, 
+                                            },
+                                            context_instance=RequestContext(request));

+ 79 - 0
misago/users/views/activation.py

@@ -0,0 +1,79 @@
+from django.core.urlresolvers import reverse
+from django.shortcuts import redirect
+from django.template import RequestContext
+from django.utils.translation import ugettext as _
+from misago.banning.models import check_ban
+from misago.banning.decorators import block_banned
+from misago.banning.views import error_banned
+from misago.forms.layouts import FormLayout
+from misago.messages import Message
+from misago.security.auth import sign_user_in
+from misago.security.decorators import *
+from misago.users.forms import *
+from misago.users.models import User
+from misago.views import error403, error404
+
+
+@block_banned
+@block_authenticated
+@block_jammed
+def activate(request, username="", user="0", token=""):
+    user = int(user)
+    try:
+        user = User.objects.get(pk=user)
+        current_activation = user.activation
+        # Run checks
+        user_ban = check_ban(username=user.username, email=user.email)
+        if user_ban:
+            return error_banned(request, user, user_ban)
+        if user.activation == User.ACTIVATION_NONE:
+            return error403(request, Message(request, 'users/activations/not_required', extra={'user': user}))
+        if user.activation == User.ACTIVATION_ADMIN:
+            return error403(request, Message(request, 'users/activations/only_by_admin', extra={'user': user}))
+        if not token or not user.token or user.token != token:
+            return error403(request, Message(request, 'users/invalid_confirmation_link', extra={'user': user}))
+        # Activate and sign in our member
+        user.activation = User.ACTIVATION_NONE
+        sign_user_in(request, user)
+        if current_activation == User.ACTIVATION_PASSWORD:
+            request.messages.set_flash(Message(request, 'users/activations/password', extra={'user':user}), 'success')
+        else:
+            request.messages.set_flash(Message(request, 'users/activations/new', extra={'user':user}), 'success')
+        return redirect(reverse('index'))
+    except User.DoesNotExist:
+        return error404(request)
+
+
+@block_banned
+@block_authenticated
+@block_jammed
+def form(request):
+    message = None
+    if request.method == 'POST':
+        form = UserSendSpecialMailForm(request.POST, request=request)
+        if form.is_valid():
+            user = form.found_user
+            user_ban = check_ban(username=user.username, email=user.email)
+            if user_ban:
+                return error_banned(request, user, user_ban)
+            if user.activation == User.ACTIVATION_NONE:
+                return error403(request, Message(request, 'users/activations/not_required', extra={'user': user}))
+            if user.activation == User.ACTIVATION_ADMIN:
+                return error403(request, Message(request, 'users/activations/only_by_admin', extra={'user': user}))
+            request.messages.set_flash(Message(request, 'users/activations/resent', extra={'user':user}), 'success')
+            user.email_user(
+                            request,
+                            'users/activations/resend',
+                            _("New Account Activation"),
+                            )
+            return redirect(reverse('index'))
+        else:
+            message = Message(request, form.non_field_errors()[0])
+    else:
+        form = UserSendSpecialMailForm(request=request)
+    return request.theme.render_to_response('users/resend_activation.html',
+                                            {
+                                             'message': message,
+                                             'form': FormLayout(form),
+                                            },
+                                            context_instance=RequestContext(request));

+ 83 - 0
misago/users/views/password.py

@@ -0,0 +1,83 @@
+from django.core.urlresolvers import reverse
+from django.shortcuts import redirect
+from django.template import RequestContext
+from django.utils.translation import ugettext as _
+from misago.banning.models import check_ban
+from misago.banning.decorators import block_banned
+from misago.banning.views import error_banned
+from misago.forms.layouts import FormLayout
+from misago.messages import Message
+from misago.security import get_random_string
+from misago.security.decorators import *
+from misago.users.forms import *
+from misago.users.models import User
+from misago.views import error403, error404
+
+
+@block_banned
+@block_authenticated
+@block_jammed   
+def form(request):
+    message = None
+    if request.method == 'POST':
+        form = UserSendSpecialMailForm(request.POST, request=request)
+        if form.is_valid():
+            user = form.found_user
+            user_ban = check_ban(username=user.username, email=user.email)
+            if user_ban:
+                return error_banned(request, user, user_ban)
+            elif user.activation != User.ACTIVATION_NONE:
+                return error403(request, Message(request, 'users/activations/required', {'user': user}))
+            user.token = get_random_string(12)
+            user.save(force_update=True)
+            request.messages.set_flash(Message(request, 'users/passwords/reset_confirm', extra={'user':user}), 'success')
+            user.email_user(
+                            request,
+                            'users/reset_confirm',
+                            _("Confirm New Password Request")
+                            )
+            return redirect(reverse('index'))
+        else:
+            message = Message(request, form.non_field_errors()[0])
+    else:
+        form = UserSendSpecialMailForm(request=request)
+    return request.theme.render_to_response('users/forgot_password.html',
+                                            {
+                                             'message': message,
+                                             'form': FormLayout(form),
+                                            },
+                                            context_instance=RequestContext(request));
+
+
+@block_banned
+@block_authenticated
+@block_jammed
+def reset(request, username="", user="0", token=""):
+    user = int(user)
+    try:
+        user = User.objects.get(pk=user)
+        user_ban = check_ban(username=user.username, email=user.email)
+        if user_ban:
+            return error_banned(request, user, user_ban)
+        if user.activation != User.ACTIVATION_NONE:
+            return error403(request, Message(request, 'users/activations/required', {'user': user}))
+        if not token or not user.token or user.token != token:
+            return error403(request, Message(request, 'users/invalid_confirmation_link', {'user': user}))
+        new_password = get_random_string(6)
+        user.token = None
+        user.set_password(new_password)
+        user.save(force_update=True)
+        # Logout signed in and kill remember me tokens
+        Session.objects.filter(user=user).update(user=None)
+        Token.objects.filter(user=user).delete()
+        # Set flash and mail new password
+        request.messages.set_flash(Message(request, 'users/passwords/reset_done', extra={'user':user}), 'success')
+        user.email_user(
+                        request,
+                        'users/reset_new',
+                        _("Your New Password"),
+                        {'password': new_password}
+                        )
+        return redirect(reverse('sign_in'))
+    except User.DoesNotExist:
+        return error404(request)

+ 25 - 0
misago/users/views/profiles.py

@@ -0,0 +1,25 @@
+from django.core.urlresolvers import reverse
+from django.shortcuts import redirect
+from django.template import RequestContext
+from misago.users.models import User, Group
+from misago.views import error404
+
+
+def list(request):
+    pass
+
+
+def show(request, user, username):
+    user = int(user)
+    try:
+        user = User.objects.get(pk=user)
+        if user.username_slug != username:
+            # Force crawlers to take notice of updated username
+            return redirect(reverse('user', args=(user.username_slug, user.pk)), permanent=True)
+        return request.theme.render_to_response('users/profile.html',
+                                            {
+                                             'profile': user,
+                                            },
+                                            context_instance=RequestContext(request));
+    except User.DoesNotExist:
+        return error404(request)

+ 58 - 0
misago/users/views/usercp.py

@@ -0,0 +1,58 @@
+from django.core.urlresolvers import reverse
+from django.shortcuts import redirect
+from django.template import RequestContext
+from misago.security.decorators import *
+
+
+@block_guest   
+def options(request):
+    return request.theme.render_to_response('users/usercp/options.html',
+                                            {
+                                             'tab': 'options',
+                                             },
+                                            context_instance=RequestContext(request));
+    
+ 
+@block_guest
+def credentials(request):
+    return request.theme.render_to_response('users/usercp/credentials.html',
+                                            {
+                                             'tab': 'credentials',
+                                             },
+                                            context_instance=RequestContext(request));
+    
+ 
+@block_guest
+def username(request):
+    return request.theme.render_to_response('users/usercp/username.html',
+                                            {
+                                             'tab': 'username',
+                                             },
+                                            context_instance=RequestContext(request));
+    
+ 
+@block_guest
+def avatar(request):
+    return request.theme.render_to_response('users/usercp/avatar.html',
+                                            {
+                                             'tab': 'avatar',
+                                             },
+                                            context_instance=RequestContext(request));
+    
+ 
+@block_guest
+def signature(request):
+    return request.theme.render_to_response('users/usercp/signature.html',
+                                            {
+                                             'tab': 'signature',
+                                             },
+                                            context_instance=RequestContext(request));
+    
+ 
+@block_guest
+def ignored(request):
+    return request.theme.render_to_response('users/usercp/ignored.html',
+                                            {
+                                             'tab': 'ignored',
+                                             },
+                                            context_instance=RequestContext(request));

+ 0 - 0
templates/_email/auth/activation_0_html.html → templates/_email/users/activation_0_html.html


+ 0 - 0
templates/_email/auth/activation_0_plain.html → templates/_email/users/activation_0_plain.html


+ 0 - 0
templates/_email/auth/activation_1_html.html → templates/_email/users/activation_1_html.html


+ 0 - 0
templates/_email/auth/activation_1_plain.html → templates/_email/users/activation_1_plain.html


+ 0 - 0
templates/_email/auth/activation_2_html.html → templates/_email/users/activation_2_html.html


+ 0 - 0
templates/_email/auth/activation_2_plain.html → templates/_email/users/activation_2_plain.html


+ 0 - 0
templates/_email/auth/activation_resend_html.html → templates/_email/users/activation_resend_html.html


+ 0 - 0
templates/_email/auth/activation_resend_plain.html → templates/_email/users/activation_resend_plain.html


+ 0 - 0
templates/_email/auth/reset_confirm_html.html → templates/_email/users/reset_confirm_html.html


+ 0 - 0
templates/_email/auth/reset_confirm_plain.html → templates/_email/users/reset_confirm_plain.html


+ 0 - 0
templates/_email/auth/reset_new_html.html → templates/_email/users/reset_new_html.html


+ 0 - 0
templates/_email/auth/reset_new_plain.html → templates/_email/users/reset_new_plain.html


+ 0 - 6
templates/_message/auth/invalid_confirmation_password.html

@@ -1,6 +0,0 @@
-{% extends "_message/base.html" %}
-{% load i18n %}
-
-{% block content %}
-  <p>{% trans %}Confirmation link is invalid. Please check your inbox and request new confirmation e-mail if necessary.{% endtrans %}</p>
-{% endblock %}

+ 0 - 0
templates/_message/auth/activation_admin.html → templates/_message/users/activations/admin.html


+ 0 - 0
templates/_message/auth/activated_new.html → templates/_message/users/activations/new.html


+ 0 - 0
templates/_message/auth/activation_not_required.html → templates/_message/users/activations/not_required.html


+ 0 - 0
templates/_message/auth/activation_only_by_admin.html → templates/_message/users/activations/only_by_admin.html


+ 0 - 0
templates/_message/auth/activated_password.html → templates/_message/users/activations/password.html


+ 0 - 0
templates/_message/auth/activation_required.html → templates/_message/users/activations/required.html


+ 0 - 0
templates/_message/auth/activation_resent.html → templates/_message/users/activations/resent.html


+ 0 - 0
templates/_message/auth/activation_user.html → templates/_message/users/activations/user.html


+ 0 - 0
templates/_message/auth/invalid_confirmation_activation.html → templates/_message/users/invalid_confirmation_link.html


+ 0 - 0
templates/_message/auth/password_reset_confirm.html → templates/_message/users/passwords/reset_confirm.html


+ 0 - 0
templates/_message/auth/password_reset_done.html → templates/_message/users/passwords/reset_done.html


+ 0 - 0
templates/_message/auth/registered_activation_admin.html → templates/_message/users/registrations/registered_activation_admin.html


+ 0 - 0
templates/_message/auth/registered_activation_none.html → templates/_message/users/registrations/registered_activation_none.html


+ 0 - 0
templates/_message/auth/registered_activation_user.html → templates/_message/users/registrations/registered_activation_user.html


+ 0 - 0
templates/_message/auth/registrations_off.html → templates/_message/users/registrations/registrations_off.html


+ 0 - 0
templates/sora/auth/forgot_password.html → templates/sora/users/forgot_password.html


+ 0 - 0
templates/sora/auth/register.html → templates/sora/users/register.html


+ 0 - 0
templates/sora/auth/resend_activation.html → templates/sora/users/resend_activation.html