I modified the first password reset page successfully. (Where the user insert his email address)
Where it doesn't work it the Password Reset Confirm page (Where the users write his new password). When I click the link that I received by email to reset the password, it load my html template but it doesn't load my form. (Only load h1 tag and other things)
html template
{% load static %}
<div class="box" align="center">
<h1>Write your new password</h1>
<div class="small-line"></div>
<form method="POST">
{% csrf_token %}
{{ context.as_p }}
<button type="submit" class="sendbut">Reset Password</button>
</form>
</div>
forms.py
class SetPasswordForm(forms.Form):
def __init__(self, *args, **kwargs):
super(SetPasswordForm, self).__init__(*args, **kwargs)
# …
new_password1 = forms.CharField(
label=("New password"),
widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
strip=False,
help_text=password_validation.password_validators_help_text_html(),
)
new_password2 = forms.CharField(
label=("New password confirmation"),
strip=False,
widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
)
views.py
#sensitive_post_parameters()
#never_cache
def PasswordResetConfirmView(request, uidb64=None, token=None,
template_name='users/password_reset_confirm.html',
token_generator=default_token_generator,
set_password_form=SetPasswordForm,
post_reset_redirect=None,
current_app=None, extra_context=None):
"""
View that checks the hash in a password reset link and presents a
form for entering a new password.
"""
UserModel = get_user_model()
assert uidb64 is not None and token is not None # checked by URLconf
if post_reset_redirect is None:
post_reset_redirect = reverse('password_reset_complete')
else:
post_reset_redirect = resolve_url(post_reset_redirect)
try:
# urlsafe_base64_decode() decodes to bytestring on Python 3
uid = force_str(urlsafe_base64_decode(uidb64))
user = UserModel._default_manager.get(pk=uid)
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
user = None
if user is not None and token_generator.check_token(user, token):
validlink = True
title = ('Enter new password')
if request.method == 'POST':
form = set_password_form(user, request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(post_reset_redirect)
else:
form = set_password_form(user)
else:
validlink = False
form = None
title = ('Password reset unsuccessful')
context = {
'form': form,
'title': title,
'validlink': validlink,
}
if extra_context is not None:
context.update(extra_context)
if current_app is not None:
request.current_app = current_app
return TemplateResponse(request, template_name, context)
urls.py
urlpatterns = [
path('password_reset/', views.password_reset, name='password_reset'),
path('password_reset/done/', views.password_reset_done, name="password_reset_done"),
path(r'reset/<uidb64>/<token>/', views.PasswordResetConfirmView, name='password_reset_confirm'),
]
please write {{form.as_p}} insted of {{context.as_p}}
{% load static %}
<div class="box" align="center">
<h1>Write your new password</h1>
<div class="small-line"></div>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="sendbut">Reset Password</button>
</form>
</div>
Related
So my login view takes the user to the home.view but first checks user is logged in and then checks if the user is an admin or not through the decorator 'admin_only'. My user will prove to be false for this scenario (which is expected). The user is then redirected to the user_page view to which first goes through the decorator allowed_users (which will be true) and then the user_page view.
My aim is to pass the primary key at login_user view to user_page view but the middle men decorators I believe are causing me problems.
views.py
#unauthenticated_user
def login_user (request):
user = None
if request.method == 'POST':
temp_username = request.POST.get('username')
temp_password = request.POST.get('password')
user = authenticate(request, username=temp_username, password=temp_password)
if user is not None:
login(request, user)
context = {'user':user}
print ('Primary key in login view = ', user.id)
return redirect('home', context)
else:
messages.info(request, "Username or Password is incorrect!")
context = {'user':user }
return render(request, 'login.html', context)
#login_required(login_url='login')
#admin_only
def home(request, pk):
user = User.objects.get(id=pk)
context = {'user':user}
return render(request,'home.html',context)
#login_required(login_url='login')
#allowed_users(allowed_roles=['customer'])
def user_page(request,pk):
user = User.objects.get(id=pk)
context = {'user':user}
return render(request, 'user.html', context)
urls.py
#url.py
path('user/<int:pk>/', views.user_page, name='user_page')
path('', views.home, name='home'),
decorators.py
def allowed_users(allowed_roles=[]):
def decorator(allow_users_view_function):
def wrapper_function(request, *args, **kwargs):
group = None
if request.user.groups.exists():
group = request.user.groups.all()[0].name
if group in allowed_roles:
user = request.user
pk = user.id
print('PK in allowed_users = ',pk )
return allow_users_view_function(request,pk,*args, **kwargs)
else:
return HttpResponse("You are not authorised to view this page")
return wrapper_function
return decorator
def admin_only(admin_view_function):
def wrapper_function(request, *args, **kwargs):
group = None
if request.user.groups.exists():
group = request.user.groups.all()[0].name
if group == 'customer':
print('group = customer')
user = kwargs.get('user')
print ('Primary key in admin_only = ', user.id)
pk = user.id
print('PK in admin_only = ',pk )
context={'pk':pk}
return redirect('user_page', context)
if group == 'admin':
print('group = admin')
return admin_view_function(request, *args, **kwargs)
return wrapper_function
login.html
{% extends 'base.html' %}
{% block content %}
<form action="{% url 'user_page' pk=user.id %}" method="POST"> # error is occuring at this line
{% csrf_token %}
<input type="text" id="username" name="username" placeholder="Enter Username">
<input type="password" id="password" name="password" placeholder="Enter Password">
<input type="submit" value="Login">
</form>
<!--Display error message for any failed login attempt-->
{% for message in messages %}
<p id="messages">{{message}}</p>
{% endfor %}
Don't have an account? <a href="{% url 'register' %}" >Sign Up</a>
{% endblock %}
I want to make the email be set in the frontend of the django application.
I have go and create this class to make the authentification based on the email
class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
user = UserModel.objects.get(email=username)
except UserModel.DoesNotExist:
return None
else:
if user.check_password(password):
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Then I have go and define the path of this class in the settings.py
Everything is good without error and I logged in by typing the email. But in the frontend, the label is still "Username". How can I modify it?
Here it's the Html code form login page:
<form method="POST">
{% csrf_token %} <!--this protect our form against certeain attacks ,added security django rquires-->
<fieldset class="form-group">
{{ form|crispy}}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Login</button>
<small class="test-muted ml-2">
<a class="ml-2" href="{% url 'password_reset' %}">Forgot Password?</a>
</small>
</div>
<!--- put div for a link if he is already have account--->
<div class="border-top pt-3">
<small class="test-muted">Need an account? <a class="ml-2" href="{% url 'register' %}">Sign Up</a></small>
<!--it a bootstrap -->
</div>
</form>
Edited:
This is the view code:
def login_view(request):
context = {}
user = request.user
destination = get_redirect_if_exists(request)
if request.method == "POST":
form = LoginForm(request.POST)
if form.is_valid():
email = form.cleaned_data["email"]
password = form.cleaned_data["password"]
user = authenticate(request, email=email, password=password)
if user == None:
attempt = request.session.get("attempt") or 0
request.session['attempt'] = attempt + 1
return render(request, 'pages/login.html')
else:
login(request, user)
destination = get_redirect_if_exists(request)
if destination:
return redirect(destination)
return redirect("home")
return render(request, 'pages/login.html')
and this is the login form code:
class LoginForm(UserCreationForm):
email = forms.CharField(label='email')
password = forms.CharField(label='password')
Probably you should change form
urlpatterns = [
path('login/', LoginView.as_view(authentication_form=YourForm), name='login'),
]
class YourForm(AuthenticationForm):
username = forms.CharField(widget=TextInput(attrs={'class':'validate','placeholder': 'Username or Email'}))
password = forms.CharField(widget=PasswordInput(attrs={'placeholder':'Password'})
I am (attempting to) implement the ability for a user to edit and update their email address on their profile page. I am getting no errors when doing this end to end but the new email is not being saved to the DB.
Everything seems to be working, even the redirect to the profile page in the edit_profile function, but the save() doesn't seem to be working, the users email doesn't update and when I am redirected back to the profile page, the email is still the current value.
Thanks!
Model:
class CustomUser(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
is_pro = models.BooleanField(default=False)
is_golfer = models.BooleanField(default=False)
def __str__(self):
return self.email
Form
class EditProfileForm(forms.Form):
email = forms.EmailField(
label='', widget=forms.TextInput(attrs={'class': 'form-field'}))
View
#login_required
def edit_profile(request):
if request.method == "POST":
form = EditProfileForm(request.POST)
if form.is_valid():
email = form.cleaned_data["email"]
user = CustomUser.objects.get(id=request.user.id)
user.save()
return redirect("typeA", username=user.username)
else:
form = EditProfileForm()
return render(request, "registration/edit_profile.html", {'form': form})
URLS
urlpatterns = [
path('type_a_signup/', ASignUpView.as_view(), name='a_signup'),
path('type_b_signup/', BSignUpView.as_view(), name='b_signup'),
path('login/', LoginView.as_view(), name='login'),
path('password_reset', PasswordResetView.as_view(), name='password_reset'),
path('typea/<username>/', typeA, name='typeA'),
path('typeb/<username>/', typeB, name='typeB'),
path('login_success/', login_success, name='login_success'),
path('edit_profile/', edit_profile, name='edit_profile'),
]
Template
<div class="container">
<div class="form-container">
<h2>Edit profile</h2>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div>
{{ form.email.label_tag }}
<input type="text" class="form-control {% if form.email.errors %}is-invalid{% endif %}" id="id_email"
name="email" value='{{ form.email.value|default:user.email }}'>
{% if form.email.errors %}
<div>{{ form.email.errors }}</div>
{% endif %}
</div>
<button type="submit">Submit</button>
</form>
<br>
</div>
You never set the email field of the object. You should set this with:
#login_required
def edit_profile(request):
if request.method == "POST":
form = EditProfileForm(request.POST)
if form.is_valid():
email = form.cleaned_data["email"]
user = request.user
user.email = email # 🖘 set the email field
user.save()
return redirect("typeA", username=user.username)
else:
form = EditProfileForm()
return render(request, "registration/edit_profile.html", {'form': form})
You should only redirect in case the form is successful. If it is not, Django will rerender the form with the errors.
I am using Django's SetPasswordForm to allow the user to reset their own password.They will have been sent an email and clicked on a link which directs them to: /users/new-password/uid/token
urls.py
path('new-password/<uidb64>/<str:token>/', views.NewPassword.as_view(), name='new-password'),
path('new-password-post/', views.NewPasswordPost.as_view(), name='new-password-post'),
views.py
class NewPassword(View):
url = 'users/new_password.html'
def get(self, request, uidb64, token):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is None or not account_activation_token.check_token(user, token):
text = 'Your password cannot be reset. Please contact support.'
messages.error(request, text)
return HttpResponseRedirect(reverse('account'))
password_form = SetPasswordForm(user=user)
context = {
'password_form': password_form,
'uidb64': uidb64,
'token': token,
}
return render(request, 'users/new_password.html', context)
class NewPasswordPost(View):
url = 'users/new_password.html'
def post(self, request):
uidb64 = request.POST['uidb64']
token = request.POST['token']
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
password_form = SetPasswordForm(request.POST)
if not password_form.is_valid():
for field in password_form.fields.items():
print(field, field[1].error_messages)
context = {
'password_form': password_form,
'uidb64': uidb64,
'token': token,
}
return render(request, self.url, context)
messages.success(request, 'Your password has been reset. You may now sign in.')
password_form.save()
return render(request, reverse('login'), context)
new_password.html
<form method="post" action="{% url 'new-password' %}">
{% csrf_token %}
<h1>Set New Password</h1>
<table>
{% for field in password_form %}
<tr>
<td>{{ field.label_tag }}</td>
<td>{{ field }}</td>
{% if field.errors %}
{% for error in field.errors %}
<td style="color: red">{{ error }}</td>
{% endfor %}
{% endif %}
</tr>
{% endfor %}
</table>
<button type="submit" class="btn btn-success">Submit</button>
<input type="hidden" id="uidb64" name="uidb64" value="{{ uidb64 }}">
<input type="hidden" id="token" name="token" value="{{ token }}">
</form>
The print statements in NewPasswordPost give:
('new_password1', <django.forms.fields.CharField object at 0x7f4a53d94940>) {'required': 'This field is required.'}
('new_password2', <django.forms.fields.CharField object at 0x7f4a53d94130>) {'required': 'This field is required.'}
but I do not see any errors on the SetPasswordForm e.g. passwords do not match
Use :- print = form.errors in signup view
The problem was that I was not referring to the form correctly in the NewPasswordPost class (and not updating the user correctly).
old version
def post(self, request):
...
password_form = SetPasswordForm(request.POST)
if not password_form.is_valid():
context = {
'password_form': password_form,
'uidb64': uidb64,
'token': token,
}
return render(request, self.url, context)
password_form.save()
...
working version
def post(self, request):
...
password_form = SetPasswordForm(request.user, request.POST)
if not password_form.is_valid():
context = {
'password_form': password_form,
'uidb64': uidb64,
'token': token,
}
return render(request, self.url, context)
user = User.objects.get(pk=uid)
new_password = request.POST['new_password1']
user.set_password(new_password)
user.save()
...
How to authenticate user until he verify the email?
In my sign up process, I create the User, which means he can login even without verify email. Is there a build-in method to set a un-verified status on a User?
models.py
email_active = models.BooleanField(default=False,
verbose_name=u'Email active ')
views.py
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(username=username, password=password)
if user is not None:
if user.email_active:
login(self.request, user)
return HttpResponse("login success")
else:
return HttpResponse("user email is not active")
else:
return HttpResponse("username or password error")
you can active email by send email with verify_code,user can use verify_code to active their email.
Demo:
models.py:
class EmailVerify(models.Model):
owner = models.ForeignKey(User,
on_delete=models.CASCADE,
verbose_name='owner')
verify_code = models.CharField(max_length=254,
null=True,
verbose_name='verify_code ')
def update(self):
self.verify_code = self.generate_key()
self.save()
return self.verify_code
def get_active_email_url(self, request):
from django.urls import reverse
url = '{}?active_code={}'.format(request.build_absolute_uri(reverse('user_login', args=())), self.verify_code)
return url
#staticmethod
def generate_key():
return binascii.hexlify(os.urandom(20)).decode()
class Meta:
verbose_name = 'EmailVerify'
utils.py :
def send_active_email(request, user):
current_site = get_current_site(request)
site_name = current_site.name
if EmailVerify.objects.filter(owner=user, category=0).exists():
verify = EmailVerify.objects.filter(owner=user).first()
else:
verify = EmailVerify.objects.create(owner=user)
verify.update()
title = u"{} active email".format(site_name)
message = "".join([
u"click this link can active your email:\n\n",
"{}\n\n".format(verify.get_active_email_url(request=request)),
])
try:
send_mail(title, message, settings.DEFAULT_FROM_EMAIL, [user.email])
message = "success"
except ConnectionRefusedError as e:
message = e.strerror
except Exception as e:
message = str(e)
return message
views.py
class LoginView(BaseContextMixin, FormView):
template_name = 'user/login.html'
form_class = LoginForm
success_url = reverse_lazy('index')
def get_context_data(self, **kwargs):
if 'form' not in kwargs:
kwargs['form'] = self.get_form()
if 'active_email' in self.request.GET:
active_email = self.request.GET.get('active_email')
try:
user = User.objects.get(email=active_email, email_active=False)
kwargs['message'] = send_active_email(self.request, user)
except (ObjectDoesNotExist, MultipleObjectsReturned):
kwargs['message'] = 'email not exist or actived'
if 'active_code' in self.request.GET:
active_code = self.request.GET.get('active_code')
try:
email_verify = EmailVerify.objects.get(verify_code=active_code)
email_verify.owner.email_active = True
email_verify.owner.save()
email_verify.delete()
kwargs['message'] = 'email {} actived'.format(email_verify.owner.email)
except ObjectDoesNotExist:
kwargs['message'] = 'unless link'
except MultipleObjectsReturned:
EmailVerify.objects.filter(verify_code=active_code).delete()
kwargs['message'] = 'error!'
return super(LoginView, self).get_context_data(**kwargs)
def get_form(self, form_class=None):
if form_class is None:
form_class = self.get_form_class()
return form_class(request=self.request, **self.get_form_kwargs())
forms.py:
class LoginForm(forms.Form):
active_email = None
username = forms.CharField(label='username')
password = forms.CharField(widget=forms.PasswordInput, label='password')
def __init__(self, request, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
self.request = request
self.fields['username'].widget.attrs.update({'class': 'form-control',
"placeholder": self.fields['username'].label})
self.fields['password'].widget.attrs.update({'class': 'form-control',
"placeholder": self.fields['password'].label})
def clean(self):
username = self.cleaned_data["username"]
password = self.cleaned_data["password"]
user = authenticate(username=username, password=password)
if user is not None:
if user.email_active:
login(self.request, user)
else:
self.active_email = user.email
self.add_error("username", "not active")
else:
self.add_error("username", "username or password error")
login.html:
{% extends "user/user_base.html" %}
{% block content %}
<div class="login-box">
<div class="login-logo">
{{ website_title|default_if_none:'' }}
</div>
<div class="login-box-body">
<form method="post" action="{% url 'user_login' %}" class="form">
{% csrf_token %}
{% for field in form %}
<div class="form-group no-margin {% if field.errors %} has-error {% endif %}">
<label class="control-label" for="{{ field.id_for_label }}">
<b>{{ field.label }}</b>
{% if message %}
{% ifequal field.name 'username' %}{{ message }}{% endifequal %}
{% endif %}
{% if field.errors %}
{{ field.errors.as_text }}
{% ifequal field.errors.as_text '* not active' %}
<a href="{% url 'user_login' %}?active_email={{ form.active_email }}">
send active emial
</a>
{% endifequal %}
{% endif %}
</label>
{{ field }}
</div>
{% endfor %}
<div class="row">
<div class="col-md-6">
<button id="btn_login" type="submit" style="width: 100%"
class="btn btn-raised btn-primary">Login
</button>
</div>
</div>
</form>
</div>
</div>
{% endblock %}