You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

190 lines
6.5 KiB

import datetime
from django.core.mail import EmailMessage
from django.conf import settings
from django.contrib.sites.models import Site, RequestSite
from django.core import signing
from django.core.mail import send_mail
from django.template import Context
from django.core.urlresolvers import reverse, reverse_lazy
from django.shortcuts import get_object_or_404, redirect
from django.http import Http404
from django.template import loader
from django.utils import timezone
from django.views import generic
from django.template.loader import get_template
from email.MIMEImage import MIMEImage
from .forms import PasswordRecoveryForm, PasswordResetForm
from .utils import get_user_model, get_username
from .signals import user_recovers_password
class SaltMixin(object):
salt = 'password_recovery'
url_salt = 'password_recovery_url'
def loads_with_timestamp(value, salt):
"""Returns the unsigned value along with its timestamp, the time when it
got dumped."""
try:
signing.loads(value, salt=salt, max_age=-1)
except signing.SignatureExpired as e:
age = float(str(e).split('Signature age ')[1].split(' >')[0])
timestamp = timezone.now() - datetime.timedelta(seconds=age)
return timestamp, signing.loads(value, salt=salt)
class RecoverDone(SaltMixin, generic.TemplateView):
template_name = "password_reset/reset_sent.html"
def get_context_data(self, **kwargs):
ctx = super(RecoverDone, self).get_context_data(**kwargs)
try:
ctx['timestamp'], ctx['email'] = loads_with_timestamp(
self.kwargs['signature'], salt=self.url_salt,
)
except signing.BadSignature:
raise Http404
return ctx
recover_done = RecoverDone.as_view()
class Recover(SaltMixin, generic.FormView):
case_sensitive = True
form_class = PasswordRecoveryForm
template_name = 'password_reset/recovery_form.html'
success_url_name = 'password_reset_sent'
email_template_name = 'password_reset/recovery_email_expo.html'
email_subject_template_name = 'password_reset/recovery_email_subject.txt'
search_fields = ['username', 'email']
def get_success_url(self):
return reverse(self.success_url_name, args=[self.mail_signature])
def get_context_data(self, **kwargs):
kwargs['url'] = self.request.get_full_path()
return super(Recover, self).get_context_data(**kwargs)
def get_form_kwargs(self):
kwargs = super(Recover, self).get_form_kwargs()
kwargs.update({
'case_sensitive': self.case_sensitive,
'search_fields': self.search_fields,
})
return kwargs
def get_site(self):
if Site._meta.installed:
return Site.objects.get_current()
else:
return RequestSite(self.request)
def send_notification(self):
context = {
'site': self.get_site(),
'user': self.user,
'username': get_username(self.user),
'token': signing.dumps(self.user.pk, salt=self.salt),
'secure': self.request.is_secure(),
}
#body = loader.render_to_string(self.email_template_name,
# context).strip()
message = get_template(self.email_template_name).render(Context(context))
subject = loader.render_to_string(self.email_subject_template_name,
context).strip()
msg = EmailMessage(subject, message, settings.DEFAULT_FROM_EMAIL, [self.user.email])
msg.content_subtype = "html"
images =(('/img/logo_reg.png', 'logo'),
('/img/soc-medias/sm-icon-rss.png', 'rss'),
('/img/soc-medias/sm-icon-fb.png', 'fb'),
('/img/soc-medias/sm-icon-lin.png', 'linkedin'),
('/img/soc-medias/sm-icon-vk.png', 'vk'),
('/img/soc-medias/sm-icon-twit.png', 'twit'),
('/img/mail-logo-2.jpg','logo2'))
for img in images:
fp = open(settings.STATIC_ROOT+img[0], 'rb')
msg_img = MIMEImage(fp.read())
fp.close()
msg_img.add_header('Content-ID', '<'+img[1]+'>')
msg.attach(msg_img)
msg.send()
#send_mail(subject, body, settings.DEFAULT_FROM_EMAIL,
# [self.user.email])
def form_valid(self, form):
self.user = form.cleaned_data['user']
self.send_notification()
if (
len(self.search_fields) == 1 and
self.search_fields[0] == 'username'
):
# if we only search by username, don't disclose the user email
# since it may now be public information.
email = self.user.username
else:
email = self.user.email
self.mail_signature = signing.dumps(email, salt=self.url_salt)
return super(Recover, self).form_valid(form)
recover = Recover.as_view()
class Reset(SaltMixin, generic.FormView):
form_class = PasswordResetForm
token_expires = 3600 * 48 # Two days
template_name = 'password_reset/reset.html'
success_url = reverse_lazy('password_reset_done')
def dispatch(self, request, *args, **kwargs):
self.request = request
self.args = args
self.kwargs = kwargs
try:
pk = signing.loads(kwargs['token'], max_age=self.token_expires,
salt=self.salt)
except signing.BadSignature:
return self.invalid()
self.user = get_object_or_404(get_user_model(), pk=pk)
return super(Reset, self).dispatch(request, *args, **kwargs)
def invalid(self):
return self.render_to_response(self.get_context_data(invalid=True))
def get_form_kwargs(self):
kwargs = super(Reset, self).get_form_kwargs()
kwargs['user'] = self.user
return kwargs
def get_context_data(self, **kwargs):
ctx = super(Reset, self).get_context_data(**kwargs)
if 'invalid' not in ctx:
ctx.update({
'username': get_username(self.user),
'token': self.kwargs['token'],
})
return ctx
def form_valid(self, form):
form.save()
user_recovers_password.send(
sender=get_user_model(),
user=form.user,
request=self.request
)
return redirect(self.get_success_url())
reset = Reset.as_view()
class ResetDone(generic.TemplateView):
template_name = 'password_reset/recovery_done.html'
reset_done = ResetDone.as_view()