Im trying to understand the django-registration app, and now Im able to send emails to users with activation key. What Im not able to figure out is how to send the activation key back to server when the user clicks a link in his/her email.
class AbstractEmailUser(AbstractBaseUser, PermissionsMixin):
.....
.....
def send_activation_email(self, email):
email = email
ctx_dict = { 'activation_key' : self.activation_key,
'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS,
}
subject = render_to_string('activation_email_subject.txt', ctx_dict)
subject = ''.join(subject.splitlines())
message = render_to_string('activation_email.txt', ctx_dict)
send_mail(subject, message, 'gccFishing.com', [email], fail_silently = False)
def activate(self, activation_key):
if SHA1_RE.search(activation_key):
try:
self.get(activation_key = activation_key)
except:
self.model.DoesNotExist
return False
if not self.activation_key_expired():
self.is_active = True
self.activation_key = self.model.ACTIVATED
self.save()
return self
return False
What code should go inside activation_email.txt for creating a link that calls the activate method with activation_key ?
Or is there a better way of doing it?
Any help will be awesome. Thanks
Try something like this in your email if you are using the sites django app:
http://{{ site.domain }}{% url registration_activate activation_key %}
Or else change site.domain with the DNS of your site. your
If I remember correct, django-registration already contains an example activation_email.txt in its templates, check it out.
Update
I don't think that you should put the activation login in your User class. You definitely cannot do {% url user.registration_activate activation_key %} since you must pass a View to the url template tag! You cannot create a link without a view function (or a CBV).
What you have to do is to create a view that searches the Profiles for the activation_key and activates it. Check the ActivationView method of django-registration / registration / backends / default / views.py.
If you want to implement custom logic to your app just sublclass ActivationView and use your class in the urls.py instead of the default (django-registration / registration / backends / default / urls.py):
url(r'^activate/(?P<activation_key>\w+)/$', ActivationView.as_view(), name='registration_activate'),
Related
I am trying to add messaging functionality to my web app made in Django.
So far, I have managed to successfully send and receive messages from user to user.
But, now I have been stuck at showing all the conversation lists to the inbox.html page of the logged user.
I have tried different approaches that I can think of but can not get the expected result.
models.py
class Messaging(models.Model):
sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sender')
receiver = models.ForeignKey(User, on_delete=models.CASCADE, related_name='receiver')
message_text = models.TextField(max_length=360, verbose_name='Write Message')
message_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f'{self.sender}\'s Message to {self.receiver}'
viwes.py
Function to send and receive messages from user to user
#login_required
def messageview(request, user_name):
sender_user = request.user
receiver_user = User.objects.get(username=user_name)
message_list = Messaging.objects.filter(sender=sender_user, receiver=receiver_user).order_by('message_date') | \
Messaging.objects.filter(receiver=sender_user, sender=receiver_user).order_by('message_date')
if request.method == 'POST':
msg_text = request.POST.get('msg_text')
messaging = Messaging()
messaging.sender = sender_user
messaging.receiver = receiver_user
messaging.message_text = msg_text
messaging.save()
return redirect(request.META['HTTP_REFERER'])
context = {
'sender_user': sender_user,
'receiver_user': receiver_user,
'message_list': message_list,
}
return render(request, 'message.html', context)
Now I want to create an inboxview in views.py that will render all the conversation of the logged user.
Suppose I have two users in the database A and B, they have exchange 4 messages between them. What I want is to show the conversation as a list, which is in this case only one. For example, the logged user is A, he exchanges messages with user B and C. The inbox will show two rows. When user A clicks on either of the rows, he will be taken to the details message page corresponding to the user. It is kinds of like WhatsApp or messenger. I hope I can explain.
Edited: Added example image for better understanding
I am able to do this:
I need help to do this:
Please guide me the way.
You could try something like this.
This view will query the Messaging model and get all entries where sender or receiver is the logged in user.
#login_required
def inbox(request, user):
# Get all the records where either sender OR receiver is the logged in user
messages = Messaging.objects.filter(sender=request.user) | Messaging.objects.filter(receiver=request.user)
context = {'messages': messages}
return render(request, 'inbox.html', context)
You can add any extra lines of code to the above code that suits your requirements.
inbox.html
{% for message in messages %}
# You can show your message details here
{% endfor %}
I build an API with django and I'm automating the welcome email at creation of one user with Sendinblue. I have no problem at this step. (so we are at the url /add_user/)
I have a second url to send a link (uid + token) to a user (thanks to his email). For that I use an external package : djoser. So I use the url of djoser /auth/users/reset_password/ and /auth/users/reset_password_confirm/
My dream would be to combine /reset_password/ and /add_user/ in the single url /add_user/
My problem is that the logic in /reset_password/ and /reset_password_confirm/ was written by djoser so I can't handle it. Or I don't know how !
Here is what I tried to override djoser views :
in urls.py:
path('custom_djoser/', ChangeCredentialsView.as_view(), name='customdjoser'),
in views.py:
class ChangeCredentialsView(UserViewSet):
def post(self, *args, **kwargs):
print("hello world")
return JsonResponse({"helloworld":"success"})
got the following error :
The actions argument must be provided when calling .as_view() on a
ViewSet. For example .as_view({'get': 'list'})
So I removed the .as_view() in urls.py and got this error :
Forbidden (CSRF token missing or incorrect.): /custom_djoser/
For me its incomprehensible because I don't use csrf token, but I tried with #csrf_exempt in a dispatch function inside my class. I tried to define class ChangeCredentialsView(UserViewSet, APIView): as my other class with authorization token. Nothing to do, everytime error with csrf token.
I may explore a really painful and stupid way to do what I want to do, please tell me if there is an easier way to do this !
#Scratch'N'Purr I answer to you here because of the lack of space in comments :
currently my add_user view looks like this (the most important part because its huge)
class AddUserView(generics.CreateAPIView, APIView):
def post(self, request):
newUser = User(
username = request.POST.get('username'),
password = request.POST.get('password'),
email = request.POST.get('email'),
image = request.FILES['image'],
full_name = request.POST.get('full_name'),
user_type = request.POST.get('usertype'),
contact_number = request.POST.get('phone')
)
newUser.save()
**** then lines of code to send email with Sendinblue ****
Usually I use request.data to get the request body but here there is a file so I had to use formdata.
and I have to confess I don't know a lot about serializers and don't use it
Below is how I am trying to add extra fields to the confirm register form. When I enter my credentials in my application the application takes all the built in fields, sends it to my data base, and sends me a working confirmation email. However, the name, country, age fields are missing. I know the correct form is being used because the Captcha validate check is being done.
class NHRegisterForm(ConfirmRegisterForm):
name = db.StringField('Full Name', [DataRequired()])
country = db.StringField('Country', [DataRequired()])
age = db.StringField('Age', [DataRequired()])
def validate(self):
if not recaptcha.verify():
self.password.errors = self.password.errors + ("Error completing ReCaptcha below", )
return False
return super(NHRegisterForm, self).validate()
This is how I am passing my custom forms into the flask security initializer.
security = Security(app, user_datastore, confirm_register_form=NHRegisterForm, login_form=NHLoginForm)
Is there something I am missing here?
You need to also override the view to show those fields in the form. See docs on how to override (basically create folder: templates/security) and add register_user.html form override with your new fields.
I'm looking at implementing user authentication to a Django project. I'm reading through the documentation. It mostly seems straightforward, but there's one thing that I don't understand.
Apparently the authentication includes eight views:
accounts/login/ [name='login']
accounts/logout/ [name='logout']
accounts/password_change/ [name='password_change']
accounts/password_change/done/ [name='password_change_done']
accounts/password_reset/ [name='password_reset']
accounts/password_reset/done/ [name='password_reset_done']
accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/reset/done/ [name='password_reset_complete']
When implementing a password reset I assume that what I want to do implement accounts/password_reset/, which forwards the user an email. Then, I need to implement accounts/reset/<uidb64>/<token>/, which is where the user is directed to via the email. What I'm not clear on is what that should do when the user has updated their password successfully.
What's the difference between accounts/reset/done/ (or password_resest_complete) and accounts/password_reset/done/ (or password_reset_done)?
password_reset_done shows a success message when email is sent (after email is entered in password_reset). password_reset_complete shows a success message when password is successfully changed.
If you look at the source code for these views, there is a comment explaining the process. Lines 237 - 242:
# 4 views for password reset:
# - password_reset sends the mail
# - password_reset_done shows a success message for the above
# - password_reset_confirm checks the link the user clicked and
# prompts for a new password
# - password_reset_complete shows a success message for the above
Good question. This is how they look like:
class PasswordResetCompleteView(PasswordContextMixin, TemplateView):
template_name = 'registration/password_reset_complete.html'
title = _('Password reset complete')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['login_url'] = resolve_url(settings.LOGIN_URL)
return context
class PasswordResetDoneView(PasswordContextMixin, TemplateView):
template_name = 'registration/password_reset_done.html'
title = _('Password reset sent')
The main difference is that PasswordResetCompleteView passes the LOGIN_URL to your template context.
Maybe I am not asking the right question in the search area, but I can't find an answer for this. I am pretty sure that many people have this use case, but as a beginner in Django + Python, I need to ask it.
I have user that fills up a form and the data is stored in the database. Basically this form asks for an access to a Database and after the form is submitted I want my program to send an email to the user's manager and to the DBA to APPROVE or DENY it. Very simple, right?
My idea is that in this e-mail I send two URL's, one for approving and one for denying the request. When the URL the is clicked I send a response to the server with an update in the manager_approval field.
Has anyone implemented this solution, or could point me to something that could help me?
I am doing everything using Django + Python.
Regards,
Marcos Freccia
Basically this technique used in email verification. This is where you should look into.
Let's say you have model, named request, which has field like username to identify the person who requested access, database name, well, everything. But it will also have two "password-like" fields which will be used to determine if request was declined or not.
class Request(models.Model):
user = models.ForeignKey ...
databasename =
date =
...
access_granted = models.BooleanField(default=False)
deny_token = models.CharField()
allow_token = models.CharField()
The point is to generate those tokens on saving request in the View:
if request.method == POST:
form = RequestForm(request.POST)
if form.is_valid():
data['user'] = form.cleaned_data['user'])
data['databasename'] = form.cleaned_data['databasename'])
...
data['access_token'] = GENERATE_USING_HASH_FUNCTION()
data['deny_token'] = GENERATE_USING_HASH_FUNCTION()
form.save(data)
Then you can use module EmailMultiAlternatives to send html email like so:
subject, from_email, to = 'Request', 'admin#example.com', form.cleaned_data['manager_email']
html_content = render_to_string(HTML_TEMPLATE, CONTEXT) # Just as any regular templates
text_content = strip_tags(html_content)
msg = EmailMultiAlternatives(subject, text_content, from_email, [to], reply_to=["admin#example.com"])
msg.attach_alternative(html_content, "text/html")
msg.send()
And inside that template you construct reverse url:
{% url 'app:grant_access' allow_token=token %} # "token" you get from context
{% url 'app:deny_access' deny_token=token %} # will become example.com/deny_access/7ea3c95, where 7ea3c95 is token
Then add lines to urls.py of your app like that:
url(r'^allow_access/(?P<allow_token>[0-9]+)$', CheckAcessView.as_view(), name="app:grant_access"),
url(r'^deny_access/(?P<deny_token>[0-9]+)$', CheckAcessView.as_view(), name="app:deny_access"),]
Then create CheckAcessView view. Where you access request stored in your database and check if, for example, parameter of url "allow_token" is equal stored allow_token. If so, change request status to allowed.