I have django app with authentication in it and email verification. When user is created activation email is sent with link inside of it, when user clicks this link is doesn't take him nowhere.
views.py
class customer_register(CreateView):
model = User
form_class = CustomerSignUpForm
template_name = 'authentication/customer_register.html'
def form_valid(self, form):
user = form.save()
user.token = str(uuid.uuid4())
subject = 'Verify your account | Zane'
message = f"http://127.0.0.1:8000/accounts/verify/{user.token}/"
recipient_list = [user.email]
send_mail(
subject,
message,
'from#example.com',
['to#example.com'],
fail_silently=False,
)
return redirect('/')
def activate(request, token):
try:
obj = models.User.objects.get(email_token = token)
obj.signup_confirmation = True
obj.save()
return HttpResponse('Your account is verified')
except Exception as e:
return HttpResponse('Invalid token')
urls.py
path('verify/<uuid:pk>/', views.activate, name='activate'),
models.py
...
token = models.CharField(max_length=200, blank=True)
signup_confirmation = models.BooleanField(default=False)
I wonder what do I need to put in my url to trigger my function?
I would rewrite your active view as a class. Here is an example:
class ActivateView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
token = kwargs['pk']
try:
obj = User.objects.get(email_token = token)
obj.signup_confirmation = True
obj.save()
return HttpResponse('Your account is verified')
except Exception as e:
return HttpResponse('Invalid token')
urls.py
path('verify/<uuid:pk>/', ActivateView.as_view(), name='activate'),
Related
My goal is to reset the password via mail. But the profile_obj of the ChangePassword view returns None and 'NoneType' object has no attribute 'user'. Why? I tried different ways but did not work. The ForgetPassword view working well. The ChangePassword view doesn't work. Where is the problem? give me a relevant solution.
views.py:
def ForgetPassword(request):
try:
if request.method == 'POST':
email = request.POST.get('email')
if not User.objects.filter(email=email).first():
messages.warning(request, 'Not email found with this email.')
return redirect('ForgetPassword')
user_obj = User.objects.get(email = email)
token = str(uuid.uuid4())
send_forget_password_mail(user_obj.email , token)
messages.success(request, 'Please check your mail box an email is send.')
return redirect('ForgetPassword')
except Exception as e:
print(e)
context = {
}
return render(request, "forget_password_email.html", context)
def ChangePassword(request, token):
context = {}
try:
profile_obj = User.objects.filter(forget_password_token=token).first()
print(profile_obj)
if request.method == 'POST':
new_password = request.POST.get('new_password')
confirm_password = request.POST.get('reconfirm_password')
user_id = request.POST.get('user_id')
if user_id is None:
messages.warning(request, 'No user id found.')
return redirect(f'/ChangePassword/{token}/')
if new_password != confirm_password:
messages.warning(request, 'both should be equal.')
return redirect(f'/ChangePassword/{token}/')
profile_obj.password = new_password
profile_obj.save()
user_obj = User.objects.get(id = user_id)
user_obj.set_password(new_password)
user_obj.save()
return redirect('Login')
context = {'user_id' : profile_obj.user.id}
except Exception as e:
print(e)
context = {
}
return render(request,'change_password.html', context)
helpers.py:
from django.core.mail import send_mail
from django.conf import settings
def send_forget_password_mail(email , token ):
subject = 'Your forget password link'
message = f'Hi , click on the link to reset your password http://127.0.0.1:8000/ChangePassword/{token}/'
email_from = settings.EMAIL_HOST_USER
recipient_list = [email]
send_mail(subject, message, email_from, recipient_list)
return True
models.py:
class User(AbstractUser):
email = models.EmailField(max_length=50, unique=True, error_messages={"unique":"The email must be unique!"})
REQUIRES_FIELDS = ["email"]
objects = CustomeUserManager()
forget_password_token = models.CharField(null= True, max_length=100, blank=True)
def __str__(self):
return f"{self.pk}.{self.email}"
urls.py:
path('ForgetPassword/', views.ForgetPassword, name="ForgetPassword"),
path('ChangePassword/<token>/', views.ChangePassword, name="ChangePassword")
Your context in the ChangePassword function is :
context = {'user_id' : profile_obj.user.id}
Your error here is that profile_obj is a QuerySet and you are looking for a user field in a queryset and not in a model instance(model) like user_obj.
Also, you can't change a password this way in a queryset:
profile_obj.password = new_password
profile_obj.save()
This works on model instances.
You need to rewrite your view to either get a User instance and then return it's id to your context or use the already created user_obj you are getting later in your code.
context = {'user_id' : user_obj.id}
So I have a view that sends a confirmation email to the new user to activate with a uid and token. That part works fine. When the user clicks on the link it's suppose to send a PUT to my ActivateUserAPI where it grabs the 'uid' and 'token' from the url and sets email_confirmed = True, but it is not getting past djangos check_token function
url:
path('api/auth/activate/<path:uid>/<path:token>',
ActivateUserAPI.as_view(), name='activate'),
tokens.py
from django.contrib.auth.tokens import PasswordResetTokenGenerator
import six
class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (six.text_type(user.pk) + six.text_type(timestamp)) + six.text_type(user.email)
account_activation_token = AccountActivationTokenGenerator()
serializer:
class ActivationSerializer(serializers.ModelSerializer)
class Meta:
model = User
fields = ('id', 'email_confirmed',)
view:
class ActivateUserAPI(generics.UpdateAPIView):
serializer_class = ActivationSerializer
permission_classes = [
permissions.AllowAny
]
def put(self, request, *args, **kwargs):
token = self.kwargs['token']
try:
uid = force_str(urlsafe_base64_decode(self.kwargs['uid']))
user = User.objects.get(pk=uid)
print(account_activation_token.check_token(user, token)) # **this always returns False**
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
serializer = ActivationSerializer(user, data=request.data)
if serializer.is_valid():
user.email_confirmed = True
user.save()
return Response(serializer.data)
return HttpResponse('Thank you for your email confirmation. Now you can login your account.')
else:
return HttpResponse('Activation link is invalid!')
The weird thing is that if I access the api directly through the url it works fine, like in the link below
View of DRF
I am create a application where admin and customer login same browser.
I read many blog not able not fix my problem. As Django use session based login.
I am facing issue while logout my admin then my customer automatic logout. maybe session based functionally
My admin LoginView and Logoutview:
class AdminLoginView(SuccessMessageMixin,LoginView):
authentication_form = LoginForm
template_name = 'login.html'
redirect_field_name = reverse_lazy('admin_panel:dashboard')
redirect_authenticated_user = False
success_message = '%(username)s login Successfully !'
def dispatch(self, *args, **kwargs):
if self.request.user.is_authenticated:
# messages.info(self.request, f"{self.request.user.firstname} is already Logged In")
return redirect('/admin/dashboard/')
return super().dispatch(*args, **kwargs)
def get_success_url(self):
url = self.get_redirect_url()
LOGIN_REDIRECT_URL = reverse_lazy('admin_panel:dashboard')
return url or resolve_url(LOGIN_REDIRECT_URL)
class LogoutView(LogoutView):
"""
Log out the user and display the 'You are logged out' message.
"""
next_page = "/admin/login"
def dispatch(self, request, *args, **kwargs):
response = super().dispatch(request, *args, **kwargs)
messages.add_message(request, messages.INFO,'Successfully logged out.')
return response
I have implemented customer based login & logout
def LoginView(request):
form = LoginForm(request.POST or None)
if form.is_valid():
username = form.cleaned_data["username"]
password = form.cleaned_data["password"]
remember_me = form.cleaned_data["remember_me"]
user = User.objects.get(email=username)
if user and user.check_password(password):
if user.is_active:
if remember_me == False:
request.session.set_expiry(0)
request.session['user_id'] = user.id
request.session['username'] = user.email
return HttpResponseRedirect('/')
else:
context = {'auth_error': "You're account is disabled"}
return render(request, 'forntend-signin.html', context )
else:
context = {
'auth_error': 'username and password incorrect'
}
return render(request, 'forntend-signin.html', context)
else:
context = {
"form": form
}
return render(request, 'forntend-signin.html', context)
def customer_logout(request):
try:
if request.session['username']:
del request.session['user_id']
del request.session['username']
else:
del request.session['user_id']
except KeyError:
HttpResponseRedirect("/")
return HttpResponseRedirect("/")
Please suggest me how to fix this issue.
If there any documentation available the please share.
I have the following view that works except that it is ignoring get_success_url(). It sends the user back to the same url for the form. The user is created. The view class is just an extended createview that I use in many other places without an issue.
class SignUpView(BSModalCreateView):
model = User
form_class = SignUpForm
success_message = 'Please check your email to complete the registration'
template_name = 'form_modal.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['heading'] = 'Create ID'
return context
def form_valid(self, form):
user = form.save(commit=False)
user.is_active = False
user.save()
# current_site = get_current_site(request)
current_site = '127.0.0.1:8000'
mail_subject = 'Activate your account.'
message = render_to_string('registration/confirm_email.html', {
'user': user,
# 'domain': current_site.domain,
'domain': '127.0.0.1:8000',
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': default_token_generator.make_token(user),
})
to_email = form.cleaned_data.get('email')
email = EmailMessage(
mail_subject, message, to=[to_email]
)
email.send()
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse('dashboard')
I have tried a bunch of different things t no avail but hope someone else can help.
I did some more testing and BSModal seems to be what is stopping this. I am not sure why but it is just easier and cleaner to just send a signal when a user is created. I created a field called is_self_registered on the user model and added the receiver:
#receiver(post_save, sender=User)
def send_activate_email(sender, instance, created, **kwargs):
user = User.objects.get(pk=instance.id)
if created and user.is_self_registered:
print('do email thing')
If one of the admins creates the ID it will be active. If self registration is used the id is not active.
i am getting error while signing up, it's throwing me error that, RelatedObjectDoesNotExist at /signup/ . User has no profile.
i am getting error while signing up, it's throwing me error that, RelatedObjectDoesNotExist at /signup/ . User has no profile.
RelatedObjectDoesNotExist at /signup/ . User has no profile.
models.py
class Profile(models.Model):
"""
Model that represents a profile.
"""
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='profile', on_delete=models.CASCADE)
dp = models.ImageField(upload_to='dps/', blank=True, null=True)
member_since = models.DateTimeField(default=timezone.now)
email_confirmed = models.BooleanField(default=False)
class Meta:
ordering = ('-member_since', )
def __str__(self):
"""Unicode representation for a profile model."""
return self.user.username
def screen_name(self):
"""Returns screen name."""
try:
if self.user.get_full_name():
return self.user.get_full_name()
else:
return self.user.username
except: # noqa: E722
return self.user.username
def get_picture(self):
"""Returns profile picture url (if any)."""
default_picture = settings.STATIC_URL + 'admin/staff/default.jpg'
if self.dp:
return self.dp.url
else:
return default_picture
forms.py
class SignUpForm(UserCreationForm):
email = forms.EmailField(max_length=100, )
username = forms.CharField(label='Username', max_length=30, min_length=1,
)
class Meta:
model = User
fields = ('username', 'email',)
views.py
def signup(request):
form_filling = True
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = False
user.save()
current_site = get_current_site(request)
subject = 'Verify Your Deebaco Account'
message = render_to_string('account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
'token': account_activation_token.make_token(user),
})
user.email_user(subject, message)
return redirect('account_activation_sent')
else:
form = SignUpForm()
return render(request, 'registration/register.html', {'form': form, 'form_filling': form_filling})
def account_activation_sent(request):
return render(request, 'account_activation_sent.html')
def activate(request, uidb64, token, backend='django.contrib.auth.backends.ModelBackend'):
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 not None and account_activation_token.check_token(user, token):
user.is_active = True
user.profile.email_confirmed = True
user.save()
login(request, user, backend='django.contrib.auth.backends.ModelBackend')
messages.success(
request, "Thanks for confirming your email address.", extra_tags='alert alert-success alert-dismissible fade show')
return redirect('/')
else:
return render(request, 'account_activation_invalid.html')
tokens.py
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils import six
class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (
six.text_type(user.pk) + six.text_type(timestamp) +
six.text_type(user.profile.email_confirmed)
)
account_activation_token = AccountActivationTokenGenerator()
i have made little changes in my models.py file, then it's work.
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
"""
Signals the Profile about User creation.
"""
if created:
Profile.objects.create(user=instance)
instance.profile.save()