diff --git a/README b/README
deleted file mode 100644
index 01d8296..0000000
--- a/README
+++ /dev/null
@@ -1,49 +0,0 @@
-DJ-BaseSite was written in Python 2.7 and Django 1.4
-
-Description:
-DJ-BaseSite is a customizable login and register system with required email activation. While most people just use django-registration, I decided to write my own to learn more about Django.
-
-NOTE TO DEVS:
-A deactivation system hasn't been added. The login system needs to check attempts and display a CAPTCHA after a certain amount, this isn't included either. It also doesn't have an account recovery option. I plan to implement all of these things in future updates.
-
-DJ-BaseSite is released under the New BSD License (The BSD 3-Clause License), refer to the LICENSE file.
-
-
-Instructions
-1. Install Python 2.7 (python.org) and Django 1.4 (djangoproject.com)
-2. Open up the config.txt file and change the data under CUSTOM VARIABLES to your information. The configuration variable meanings are below.
-3. Execute the SetupProject.py script and enter the project name, it will create a project based on your configuration.
-4. Run the SyncDB script or "python manage.py syncdb" and create a super user.
-5. Run the RunServer script or "python manage.py runserver" and check out your new website at localhost:8000 or 127.0.0.1:8000 in your browser.
-
-DJ-BaseSite uses Recaptcha to prevent bots from creating accounts, so you'll need to get private and public keys from the website: http://www.google.com/recaptcha
-
-Configuration Variable Meanings.
-===================================
--baseurl
-It is used to create activation and deactivation links [in views.py in register_user()]
-
--admin_name/email
-Adds a name and email to the ADMINS tuple in settings.py
-http://docs.djangoproject.com/en/dev/ref/settings/#admins
-
--secret_key
-A string used to provide cryptographic signing. (don't use spaces due to the configurtion system)
-https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
-http://www.random.org/passwords/?mode=advanced
-
--captcha_publickey/privatekey
-DJ-BaseSite uses Recaptcha to prevent bots from creating accounts, get keys at http://www.google.com/recaptcha
-
--HOSTsmpt
-The SMPT server address with the email used to send activation emails. If your email doesn't support SMPT I highly suggest GMAIL.
-
--HOSTemail
-The email address
-
--HOSTpass
-The email's password
-===================================
-
-
-NOTE: It creates a development project, DEBUG is set to True in the settings.py so it is in no condition for deployment.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f262e4e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,50 @@
+# DJ-BaseSite
+
+DJ-BaseSite is a base Django **development** website project that adds basic user interaction to the site. Features include: The Django admin site, a login and logout system, a user registration system with required activation (via email), deactivation (an option during activation) and account recovery.
+
+#### _This project is currently in the Alpha phase. Therefore it is suggested you thoroughly read and test when forking, etc._
+
+DJ-BaseSite was written with [Python 2.7](http://www.python.org/download/releases/2.7/) and [Django 1.4](https://www.djangoproject.com/download/) on Windows 7 Home Premium 64 bit (Service Pack 1)
+
+## License
+DJ-BaseSite is released under the New BSD License, refer to the LICENSE file in the root of the repository before continuing.
+
+## Change Log
+
+### `0.7` (Oct 20, 2012)
+* Added the deactivation and account recovery systems.
+* Variable `EMAIL_MESSAGE` was replaced with `ACTIVATE_EMAIL` & `RECOVERY_EMAIL` was added.
+* The `response` variable was changed in all views to the correct spelling. derp.
+* Function `clean_emailRE()` was added to `validation.py`
+* The function `UserActivationKey()` in `views.py` was renamed to `KeyGen()`
+
+### [`0.5`](https://github.com/Kris619/DJ-BaseSite/zipball/80cdb11749afa9d2ecfcbb0a91f3f867f183bfc3) (Oct 13, 2012) SHA: 80cdb11749afa9d2ecfcbb0a91f3f867f183bfc3
+* login / registration system with Django's default authentication backend
+* activation system (deactivation system not implemented)
+* reCAPTCHA support for registration
+
+## Quick Start
+1. Open up the `config.txt` file and change the data under `CUSTOM VARIABLES` to your information. The configuration is explained below.
+2. Execute the `SetupProject.py` script and enter a project name, it will replicate the project out of `/myproject/` to `/yourproject/` with your information.
+3. Run syncdb via terminal/console in the root of the project: `python manage.py syncdb`
+ * Windows users will need to add the path of their Python 2.7 installation (example: `C:/Python27/`) to the [path variable](http://showmedo.com/videotutorials/video?name=960000&fromSeriesID=96)
+4. Run the development server: `python manage.py runserver`
+
+> You should be done at this point. So check out your new website at [http://localhost:8000](http://localhost:8000) or [http://127.0.0.1:8000](http://127.0.0.1:8000) in your browser.
+
+## Configuration
+
+* `baseurl`
+ * Used to create activation, deactivation and recovery links
+* `admin_name/email` `(`[`official documentation`](https://docs.djangoproject.com/en/1.4/ref/settings/#admins)`)`
+ * Adds a name and email to the ADMINS tuple in settings. On an error your website will email you logged errors.
+* `secret_key` `(`[`official documentation`](https://docs.djangoproject.com/en/1.4/ref/settings/#secret-key)`)`
+ * A secure string used to provide cryptographic signing. It is automatically added to a [default Django project](https://docs.djangoproject.com/en/dev/intro/tutorial01/#creating-a-project) in settings.
+* `captcha_publickey/privatekey`
+ * DJ-BaseSite uses [reCAPTCHA](http://www.google.com/recaptcha/learnmore) to prevent bots from creating accounts, so you'll need to [get a private and public key from the website](http://www.google.com/recaptcha)
+* `HOSTsmtp`
+ * The SMTP server
+* `HOSTemail`
+ * The email address
+* `HOSTpass`
+ * HOSTemail's password
\ No newline at end of file
diff --git a/config.txt b/config.txt
index e85ef9a..8192614 100644
--- a/config.txt
+++ b/config.txt
@@ -69,6 +69,9 @@ dir templates/admin
// Activation Email
%here%/myproject/myproject/activation_email.html 2
+// Recovery Email
+%here%/myproject/myproject/recovery_email.html 2
+
// HTML/CSS
dir static
dir static/css
@@ -80,12 +83,16 @@ dir static/css
// Auth
dir templates/auth
%here%/myproject/myproject/templates/auth/activated.html 2
+%here%/myproject/myproject/templates/auth/deactivated.html 2
%here%/myproject/myproject/templates/auth/disabled.html 2
%here%/myproject/myproject/templates/auth/logged_in.html 2
%here%/myproject/myproject/templates/auth/logged_out.html 2
%here%/myproject/myproject/templates/auth/login.html 2
%here%/myproject/myproject/templates/auth/newaccount.html 2
%here%/myproject/myproject/templates/auth/registration.html 2
+%here%/myproject/myproject/templates/auth/recovery.html 2
+%here%/myproject/myproject/templates/auth/recoveryattempt.html 2
+%here%/myproject/myproject/templates/auth/recoverysuccess.html 2
// Backend Django app
dir backends root
diff --git a/myproject/RunServer.bat b/myproject/RunServer.bat
index 97e4146..46b68bd 100644
--- a/myproject/RunServer.bat
+++ b/myproject/RunServer.bat
@@ -1 +1,2 @@
@python manage.py runserver
+@pause
diff --git a/myproject/SyncDB.bat b/myproject/SyncDB.bat
index 374476f..c355760 100644
--- a/myproject/SyncDB.bat
+++ b/myproject/SyncDB.bat
@@ -1 +1,2 @@
@python manage.py syncdb
+@pause
diff --git a/myproject/accountprofile/models.py b/myproject/accountprofile/models.py
index bf75eb7..e3d3212 100644
--- a/myproject/accountprofile/models.py
+++ b/myproject/accountprofile/models.py
@@ -4,4 +4,6 @@ from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
activated = models.BooleanField()
- activatekey = models.CharField(max_length=25, blank=True)
\ No newline at end of file
+ activate_key = models.CharField(max_length=25, blank=True)
+ recovery_key = models.CharField(max_length=25, blank=True)
+ recovery_time = models.DateTimeField(blank=True)
diff --git a/myproject/myproject/recovery_email.html b/myproject/myproject/recovery_email.html
new file mode 100644
index 0000000..3c5cd97
--- /dev/null
+++ b/myproject/myproject/recovery_email.html
@@ -0,0 +1,5 @@
+Hello <$user>,
+Seems you have lost access to your account. The recovery link expires at: <$time> UTC
+Recovery links last 2 hours.
+
+Recovery link: <$recoverylink>
\ No newline at end of file
diff --git a/myproject/myproject/settings.py b/myproject/myproject/settings.py
index 336fbdc..f9f49ed 100644
--- a/myproject/myproject/settings.py
+++ b/myproject/myproject/settings.py
@@ -18,6 +18,9 @@ TEMPLATE_DEBUG = DEBUG
baseurl = "<%baseurl%>" # "example.com"
base_title = "<%basetitle%>"
+# Time zone support
+USE_TZ = True
+
'''
You need to sign up at http://recaptcha.net/ for a public/private key to use their CAPTCHA service.
'''
@@ -31,7 +34,8 @@ EMAIL_HOST_USER = "<%HOSTemail%>"
EMAIL_HOST_PASSWORD = "<%HOSTpass%>"
EMAIL_PORT = 587
-EMAIL_MESSAGE = ROOTDIR + "/<%myproject%>/activation_email.html"
+ACTIVATE_EMAIL = ROOTDIR + "/<%myproject%>/activation_email.html"
+RECOVERY_EMAIL = ROOTDIR + "/<%myproject%>/recovery_email.html"
ADMINS = (
("<%admin_name%>", "<%admin_email%>"),
diff --git a/myproject/myproject/static/css/default.css b/myproject/myproject/static/css/default.css
index ef7d2c0..b3ceda1 100644
--- a/myproject/myproject/static/css/default.css
+++ b/myproject/myproject/static/css/default.css
@@ -59,6 +59,11 @@ table.loginform td {
.returnlink a:hover {color:#000000;} /* mouse over link */
.returnlink a:active {color:#000000;} /* selected link */
+.cannotlogin {
+ text-align: center;
+ }
+
+
/* REGISTER CSS */
.register_form {
text-align: center;
diff --git a/myproject/myproject/templates/auth/deactivated.html b/myproject/myproject/templates/auth/deactivated.html
new file mode 100644
index 0000000..a6be1c2
--- /dev/null
+++ b/myproject/myproject/templates/auth/deactivated.html
@@ -0,0 +1,8 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+ The account "{{user_name}}" has been deactivated. No one with this email can reregister unless you contact the admin.
+
+{% endblock %}
\ No newline at end of file
diff --git a/myproject/myproject/templates/auth/login.html b/myproject/myproject/templates/auth/login.html
index 1c01188..5a64e02 100644
--- a/myproject/myproject/templates/auth/login.html
+++ b/myproject/myproject/templates/auth/login.html
@@ -19,7 +19,7 @@
+
+{% endblock %}
\ No newline at end of file
diff --git a/myproject/myproject/templates/auth/recoveryattempt.html b/myproject/myproject/templates/auth/recoveryattempt.html
new file mode 100644
index 0000000..23df29b
--- /dev/null
+++ b/myproject/myproject/templates/auth/recoveryattempt.html
@@ -0,0 +1,30 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+
Account Recovery
+
+{% endblock %}
\ No newline at end of file
diff --git a/myproject/myproject/templates/auth/recoverysuccess.html b/myproject/myproject/templates/auth/recoverysuccess.html
new file mode 100644
index 0000000..4384f91
--- /dev/null
+++ b/myproject/myproject/templates/auth/recoverysuccess.html
@@ -0,0 +1,7 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+ Password successfully changed. Recovery success. Next time just remember your password ;)
+
+{% endblock %}
\ No newline at end of file
diff --git a/myproject/myproject/templates/auth/registration.html b/myproject/myproject/templates/auth/registration.html
index fb634eb..f40f2e9 100644
--- a/myproject/myproject/templates/auth/registration.html
+++ b/myproject/myproject/templates/auth/registration.html
@@ -21,11 +21,11 @@
-
Pass*
+
Password*
-
Pass (again)*
+
Password (again)*
diff --git a/myproject/myproject/urls.py b/myproject/myproject/urls.py
index c8fb806..348b1c0 100644
--- a/myproject/myproject/urls.py
+++ b/myproject/myproject/urls.py
@@ -25,7 +25,9 @@ urlpatterns = patterns('<%myproject%>.views',
url(r'^logout/$', 'logout_user'),
url(r'^register/$', 'register_user'),
url(r'^activate/$', 'activate_user'),
- #url(r'^deactivate/$', 'activate_user'), Deactivate needs to be written.
+ url(r'^deactivate/$', 'deactivate_user'),
+ url(r'^recovery/$', 'recover_user'),
+ url(r'^recover/$', 'recover_attempt')
)
urlpatterns += staticfiles_urlpatterns()
\ No newline at end of file
diff --git a/myproject/myproject/validation.py b/myproject/myproject/validation.py
index d853d26..86e84c4 100644
--- a/myproject/myproject/validation.py
+++ b/myproject/myproject/validation.py
@@ -68,5 +68,10 @@ def clean_usernameRE(data):
else:
return False
+def clean_emailRE(data):
+ if match("^[\w\d._%-+]+@[\w\d._%-]+.[\w]{2,6}$", data):
+ return data
+ else:
+ return False
\ No newline at end of file
diff --git a/myproject/myproject/views.py b/myproject/myproject/views.py
index 3196b2e..84c3e56 100644
--- a/myproject/myproject/views.py
+++ b/myproject/myproject/views.py
@@ -12,10 +12,11 @@ Please take a momemt to read the short 3 Clause LICENSE file.
# Built in imports
import random
import hashlib
+import datetime
-# Responce imports
-from django.http import HttpResponseRedirect
+# response imports
from django.shortcuts import render_to_response, RequestContext
+from django.http import HttpResponseRedirect
# Authentication/Session/Validation imports
from django.contrib.auth import authenticate, login, logout
@@ -26,12 +27,16 @@ from django.core.exceptions import ObjectDoesNotExist
import validation as v
import captcha
+# Time related Django imports
+from django.utils.timezone import now
+
# Email imports
from django.core.mail import EmailMessage
from django.core import mail
# Variables from Settings.py
-from settings import EMAIL_HOST_USER, EMAIL_MESSAGE
+from settings import EMAIL_HOST_USER, ACTIVATE_EMAIL, RECOVERY_EMAIL
+from settings import captcha_publickey, captcha_privatekey
from settings import baseurl, base_title
# User Profile model
@@ -55,7 +60,12 @@ def get_or_create_profile(user):
try:
profile = user.get_profile()
except ObjectDoesNotExist:
- profile = UserProfile(activated=True, user=user)
+ profile = UserProfile(
+ activated=True,
+ recovery_time=now(),
+ user=user
+ )
+
profile.save()
return profile
@@ -66,8 +76,9 @@ def get_ip(request):
else:
ip = request.META.get('REMOTE_ADDR')
return ip
+
-def UserActivationKey():
+def KeyGen():
random.seed()
choices = "abcdefghijklmnopqrstuvwxyzABCDEFG0123456789"
@@ -93,11 +104,12 @@ def index(request):
else:
user_navigation = user_nav(False)
- responce = render_to_response('index.html', locals())
- return responce
+ response = render_to_response('index.html', locals())
+ return response
def logout_user(request):
logout(request)
+ user_navigation = user_nav(False)
return render_to_response('auth/logged_out.html', locals())
def login_user(request):
@@ -136,20 +148,21 @@ def login_user(request):
# User account is activated (via email)
login(request, user)
user_name = user.username
- responce = render_to_response('auth/logged_in.html', locals())
+ user_navigation = user_nav(user.username)
+ response = render_to_response('auth/logged_in.html', locals())
else:
# The account is not activated via email
error = "Please activate your account through email."
- responce = render_to_response('error.html', locals())
+ response = render_to_response('error.html', locals())
else:
# The account is disabled. No login.
message = "Your account has been disabled."
- responce = render_to_response('auth/disabled.html', locals())
+ response = render_to_response('auth/disabled.html', locals())
else:
# No object so the username and password are invalid.
login_errors = True
- responce = render_to_response(
+ response = render_to_response(
'auth/login.html',
locals(),
context_instance=RequestContext(request)
@@ -157,7 +170,7 @@ def login_user(request):
else:
# User isn't online and hasn't sent any POST data, give them a login form.
- responce = render_to_response(
+ response = render_to_response(
'auth/login.html',
locals(),
context_instance=RequestContext(request)
@@ -167,9 +180,9 @@ def login_user(request):
# User is logged on, don't let them login until he's logged out.
user_navigation = user_nav(request.user.username)
error = "You're already logged on."
- responce = render_to_response('error.html',locals())
+ response = render_to_response('error.html',locals())
- return responce
+ return response
def register_user(request):
global base_title
@@ -261,11 +274,18 @@ def register_user(request):
new_user.save()
# Create activation key and user profile
- activation_key = UserActivationKey()
+ activation_key = KeyGen()
+
+ # Add 2 hours so a recovery key can be made instantly after
+ # account creation.
+ thetime = new_user.date_joined + datetime.timedelta(hours=2)
+
profile = UserProfile(
- activatekey=activation_key,
+ activate_key=activation_key,
activated=False,
+ recovery_time=thetime,
user=new_user)
+
profile.save()
# User is created and saved. Send an activation link via email
@@ -278,13 +298,15 @@ def register_user(request):
message_deactivateurl = baseurl+"/deactivate/?key="+str(activation_key)
message_deactivateurl = message_deactivateurl+"&user="+str(new_user.username)
- f = open(EMAIL_MESSAGE, 'r')
+ # Open email and replace data
+ f = open(ACTIVATE_EMAIL, 'r')
message = f.read()
message = message.replace("<$user>", str(new_user.username))
message = message.replace("<$activatelink>", message_activateurl)
message = message.replace("<$disablelink>", message_deactivateurl)
+ # Send email
email = EmailMessage(
"Account Activation",
message,
@@ -297,7 +319,7 @@ def register_user(request):
# Return new account page
accountname = new_user.username
- responce = render_to_response(
+ response = render_to_response(
'auth/newaccount.html',
locals(),
context_instance=RequestContext(request)
@@ -305,7 +327,7 @@ def register_user(request):
else:
# Return registration form with errors in registration_errors
- responce = render_to_response(
+ response = render_to_response(
'auth/registration.html',
locals(),
context_instance=RequestContext(request)
@@ -313,7 +335,7 @@ def register_user(request):
# If user hasn't sent POST data (not logged on)
else:
- responce = render_to_response(
+ response = render_to_response(
'auth/registration.html',
locals(),
context_instance=RequestContext(request)
@@ -323,14 +345,14 @@ def register_user(request):
else:
user_navigation = user_nav(request.user.username)
error = "You cannot register while logged in."
- responce = render_to_response(
+ response = render_to_response(
'error.html',
locals()
)
- return responce
+ return response
def activate_user(request):
- if request.method == 'GET':
+ if request.method == 'GET' and not request.user.is_authenticated():
# Check if data could be valid through regex
key = v.clean_key(request.GET["key"])
u_name = v.clean_usernameRE(request.GET["user"])
@@ -341,8 +363,16 @@ def activate_user(request):
# Check profile for key and compare.
user = User.objects.get(username=u_name)
user_profile = get_or_create_profile(user)
+
+ # You're already activated
+ if user_profile.activated:
+ key_correct = False
+
+ # You're disabled.
+ elif user.is_active == False:
+ key_correct = False
- if user_profile.activatekey == key:
+ elif user_profile.activate_key == key:
# Activate user
user_profile.activated = True
user_profile.save()
@@ -355,17 +385,295 @@ def activate_user(request):
else:
key_correct = False
- if key_correct:
- user_name = user.username
- responce = render_to_response(
- 'auth/activated.html',
- locals()
- )
- else:
- error = "Activation failed."
- responce = render_to_response(
- 'error.html',
- locals()
- )
+ user_navigation = user_nav(False)
+
+ if key_correct:
+ user_name = user.username
+ response = render_to_response(
+ 'auth/activated.html',
+ locals()
+ )
+ else:
+ error = "Activation failed."
+ response = render_to_response(
+ 'error.html',
+ locals()
+ )
- return responce
+ return response
+
+ # Logged on or didn't give GET data.
+ return HttpResponseRedirect('/')
+
+def deactivate_user(request):
+ if request.method == 'GET' and not request.user.is_authenticated():
+ # Check if data could be valid through regex
+ key = v.clean_key(request.GET["key"])
+ u_name = v.clean_usernameRE(request.GET["user"])
+
+ # If key and username are valid
+ if request.GET["key"] == key and u_name:
+ try:
+ # Check profile for key and compare.
+ user = User.objects.get(username=u_name)
+ user_profile = get_or_create_profile(user)
+
+ # If you wish to have your users deactivate with the same
+ # link sent in activation, remove this if statement
+ if user_profile.activated:
+ key_correct = False
+
+
+ elif user_profile.activate_key == key:
+ # Disable account.
+ user_profile.activated = False
+ user_profile.save()
+
+ user.is_active = False
+ user.save()
+
+ key_correct = True
+ else:
+ key_correct = False
+
+ except ObjectDoesNotExist:
+ key_correct = False
+ else:
+ key_correct = False
+
+ if key_correct:
+ user_name = user.username
+ response = render_to_response(
+ 'auth/deactivated.html',
+ locals()
+ )
+ else:
+ error = "Deactivation failed."
+ response = render_to_response(
+ 'error.html',
+ locals()
+ )
+
+ return response
+
+ # Logged on or didn't give GET data.
+ return HttpResponseRedirect('/')
+
+def recover_user(request):
+ global base_title
+ global global_nav, user_nav
+
+ title = base_title + "Recovery"
+ global_navigation=global_nav()
+
+ # If user is not logged on
+ if not request.user.is_authenticated():
+
+ # Return user navigation for an anonymous session
+ user_navigation = user_nav(False)
+
+ # Set up captcha html.
+ captcha_test = captcha.displayhtml(captcha_publickey)
+
+ # If user has sent POST data (not logged in)
+ if request.method == 'POST':
+ # Check info via regex
+ u_name = v.clean_usernameRE(request.POST["usern"])
+ email = v.clean_emailRE(request.POST["email"])
+
+
+ if email == request.POST["email"] and u_name:
+ try:
+ user = User.objects.get(username__iexact=u_name)
+ user_profile = get_or_create_profile(user)
+
+ # Current time
+ time_now = now()
+
+ # Recovery time
+ recovery_time = user_profile.recovery_time
+
+ if time_now > recovery_time:
+ # Key has been requested too many times in 2 hours.
+ error = "Recovery keys can only be requested once every 2 hours."
+ response = render_to_response(
+ 'error.html',
+ locals()
+ )
+ else:
+ # Connect to SMTP server
+ connection = mail.get_connection()
+ connection.open()
+
+ # Create a recovery key
+ user_profile.recovery_key = KeyGen()
+ user_profile.save()
+
+ # Create account recovery link
+ message_recoveryurl = baseurl+"/recover/?key="+str(user_profile.recovery_key)
+ message_recoveryurl = message_recoveryurl+"&user="+str(user.username)
+
+
+ # Open email template
+ f = open(RECOVERY_EMAIL, 'r')
+ message = f.read()
+ print message
+
+ # Replace information
+ message = message.replace("<$user>", str(user.username))
+ message = message.replace("<$recoverylink>", message_recoveryurl)
+ message = message.replace("<$time>", str(user_profile.recovery_time))
+
+ # Send email
+ email = EmailMessage(
+ "Account Recovery",
+ message,
+ EMAIL_HOST_USER,
+ [user.email]
+ )
+
+ email.send()
+ connection.close()
+
+ # Tell user to check their email.
+ error = "Check your email for a recovery link."
+ response = render_to_response(
+ 'error.html',
+ locals()
+ )
+
+ except User.DoesNotExist:
+ error = "No user with that email exists."
+ response = render_to_response(
+ 'error.html',
+ locals()
+ )
+ else:
+ error = "No user with that email exists."
+ response = render_to_response(
+ 'error.html',
+ locals()
+ )
+ else:
+ # Didn't submit, give recovery form.
+ response = render_to_response(
+ 'auth/recovery.html',
+ locals(),
+ context_instance=RequestContext(request)
+ )
+ # You're signed in, no recovery for you.
+ else:
+ return HttpResponseRedirect('/')
+
+ return response
+
+def recover_attempt(request):
+ global base_title
+ global global_nav, user_nav
+
+ title = base_title + "Recovery"
+ global_navigation=global_nav()
+
+ # If user is not logged on
+ if request.method == 'GET' and not request.user.is_authenticated():
+ # Check if data could be valid through regex
+ key = v.clean_key(request.GET["key"])
+ u_name = v.clean_usernameRE(request.GET["user"])
+
+
+ # If valid data
+ if request.GET["key"] == key and u_name:
+ # return new password form
+ the_user = u_name
+ the_key = key
+ response = render_to_response(
+ 'auth/recoveryattempt.html',
+ locals(),
+ context_instance=RequestContext(request)
+ )
+ else:
+ error = "User does not exist."
+ response = render_to_response(
+ 'error.html',
+ locals()
+ )
+
+ # If user isn't online and is sending post data
+ elif request.method == 'POST' and not request.user.is_authenticated():
+ # Check if data could be valid through regex
+ key = v.clean_key(request.POST["key"])
+ u_name = v.clean_usernameRE(request.POST["user"])
+
+ # If key/username is validated by regex
+ if request.POST["key"] == key and u_name:
+ try:
+ # Check profile for key and compare.
+ user = User.objects.get(username=u_name)
+ user_profile = get_or_create_profile(user)
+
+ # Get database key and key time limit
+ key_db = user_profile.recovery_key
+ keylimit_db = user_profile.recovery_time
+
+ # Current time
+ time_now = now()
+
+ # If the key hasn't expired and is correct
+ if now() < keylimit_db and key_db == key:
+
+ password = v.clean_password(request.POST["p1"])
+
+ recover_error = ""
+ if not request.POST["p1"] == request.POST["p2"]:
+ recover_error = "Passwords don't match."
+ elif password == None:
+ recover_error = "No password entered."
+ elif password == -1:
+ recover_error = "Passwords have to be at least 5 characters."
+
+ # If there is an error
+ if recover_error != '':
+ # Set error variable for template
+ error = recover_error
+
+ response = render_to_response(
+ 'error.html',
+ locals()
+ )
+ else:
+ # No errors, change password
+ user.set_password(password)
+ user.save()
+
+ # Expire recovery time.
+ user_profile.recovery_time = now()
+ user_profile.save()
+
+ response = render_to_response(
+ 'auth/recoverysuccess.html',
+ locals()
+ )
+ else:
+ error = "Invalid key and/or username."
+ response = render_to_response(
+ 'error.html',
+ locals()
+ )
+ except User.DoesNotExist:
+ error = "User doesn't exist."
+ response = render_to_response(
+ 'error.html',
+ locals()
+ )
+ else:
+ error = "Invalid key and/or username."
+ response = render_to_response(
+ 'error.html',
+ locals()
+ )
+ else:
+ # logged on, no recovery.
+ return HttpResponseRedirect('/')
+
+ return response
+
\ No newline at end of file