Prevent logged in user variable from changing in different context in django - django

I'm using Django 1.8.4 and Django-registration-redux for handling user registration. My problem is:
when a user logged in, i.e. james, I want to show his username in toolbar. But the problem is when I visit another user's profile,i.e. mike, the username in toolbar also changes to mike. Which is absolutely forbidden.
I'm getting logged in user as an object in my views to check if the logged in user is same as user's profile is currently visited.
I'm not sure if I should prevent request.user to change in different contexts or there's a problem in my codes:
urls.py
url(r'^users/(?P<slug>\w+)/$', UserProfileDetailView.as_view(), name="profile"),
views.py
class UserProfileDetailView(DetailView):
model = get_user_model()
slug_field = "username"
template_name = "user_detail.html"
def get_object(self, queryset=None):
user = super(UserProfileDetailView, self).get_object(queryset)
UserProfile.objects.get_or_create(user=user)
return user
base.html
{% if user.is_authenticated %}
Submit Link |
Logout |
<b>{{ user.username }}</b>
{% else %}
Register |
Login
{% endif %}
user_detail.html
{% if object == request.user and request.user.is_authenticated %}
<p><a href='{% url "edit_profile" %}'>Edit My Profile</a></p>
{% endif %}

There are 2 users in your context:
object (or user - DetailView will also return current object on lowercased model name) this is user you're viewing
request.user - this is current logged in user
You've used user.name in toolbar instead of request.user.name. That is causing issues.

Related

Why is my ModelForm not showing the right settings?

I have two Model Forms, one for notification types and one for privacy settings. Both show the defaults and not what is saved in the database. How can I make the form show the choice that's stored in the database instead of the defaults? Example: Say the user chose a Direct Message privacy of "Friends and Followers". When they visit the privacy options page again after having saved the changes, it shows "Open" instead of reflecting what is in the database. I tried assigning the values saved in the database directly to the form when rendering the page when the request is GET but that didn't do anything, even though the debug print shows that the value of form.dm_privacy is indeed what's in the database, it still shows "Open".
Both forms work fine, the changes get saved and everything. I don't understand why it's not reflecting the changes though, is this just something that Model Forms do and not something I can change?
privacy_options.html
{% extends "accbase.html" %}
{% block content %}
<h1>Privacy Options</h1>
<form method="post">
{% csrf_token %}
{{form.as_p}}
<button type="submit">Save</button>
</form>
{% endblock %}
views.py
#login_required
def privacy_options(request):
"""
Holds all privacy options such as.. open/closed DMs, who can see profile/posts on profile
"""
if request.method == "POST":
form = PrivacyOptionForm(request.POST)
if form.is_valid():
print("Before saving:",request.user.dm_privacy, request.user.profile_privacy, request.user.included_in_find_friends)
user = request.user.username
request.user.dm_privacy = form.cleaned_data['dm_privacy']
request.user.profile_privacy = form.cleaned_data['profile_privacy']
request.user.included_in_find_friends = form.cleaned_data['included_in_find_friends']
request.user.save()
print("After save:",request.user.dm_privacy, request.user.profile_privacy, request.user.included_in_find_friends)
return render(request, 'acc_manage/acc_nav.html', {'username':user})
else:
form = PrivacyOptionForm()
form.included_in_find_friends = request.user.included_in_find_friends
form.profile_privacy = request.user.profile_privacy
form.dm_privacy = request.user.dm_privacy
print("\n\n",form.dm_privacy, "\n\n")
return render(request, 'acc_manage/privacy_options.html', {'form': form})
Fixed it by changing form = PrivacyOptionForm() to form = PrivacyOptionForm(instance=request.user)

how can I ensure a user will not delete another user object in my website [Django]

I wrote a function that allows the user to delete his article on a blog website. The problem is, if he plays a little with the url, he can access to another article and delete it.
What is the common strategy to avoid such cases with django?
here are the codes I wrote for the fonction:
views.py
def delete_article(request, id):
deleted = False
logged_user = get_logged_user_from_request(request) #that line allow to ensure that the user is connected. I use the session to achieve that instead of extending the User model
offer = get_object_or_404(Offer, id=id)
if request.method == 'POST':
offer.delete()
deleted = True
return render(request, 'offers/delete_article.html', locals())
urls.py
urlpatterns = patterns('article.views',
url(r'^send_article$', 'send_article', name='send_article'),
url(r'^my_articles$', 'show_my_articles', name='my_articles'),
url(r'^article/(?P<id>\d+)$', 'read', name='read'),
url(r'^articles$', 'show_articles', name='articles'),
url(r'^search_article$', 'search', name='search'),
url(r'^delete_article/(?P<id>\d+)$', 'delete_offer', name='delete_offer'),
)
delete_article.html
{% if not deleted %}
Hey, are you sure you want to delete {{ article.title }}?
<form method="POST">
{% csrf_token %}
<button type="submit" class="deleting_offer_button">delete</button>
</form>
{% elif deleted %}
<p>the article was successfully deleted</p>
get back to the homepage<br />
{% endif %}
As you can see, if the user change the numer of the id in the url, he can delete other article when he is directed to the confirmation of deleting page.
What webmasters are doing to ensure users cannot interfere with objects of other users?
HttpResponseForbidden can be used here which uses a 403 status code. A 403 response generally used when authentication was provided, but the authenticated user is not permitted to perform the requested operation.
Assuming you have author as an foreign key in Offer model, you can change your views like this:
In your views.py you have to import :
from django.http import HttpResponseForbidden
And then in your delete_article method use this code
offer = get_object_or_404(Offer, id=id)
if offer.author != request.user:
return HttpResponseForbidden()
When you get the article/offer. Make sure that the owner of that article is the authenticated user.
I'm not sure what your models look like but it would be something like
offer = get_object_or_404(Offer, id=id, author=logged_user)
This way if they don't own the article, it will 404

Django Context contains not defined field when using RequestContext

Hi I'm writing a django project, and I write template code like this:
<ul id="nav">
<li>Home</li>
<li>Users</li>
{% if user %}
<li>Settings</li>
<li>Log Out</li>
{% else %}
<li>Log In</li>
<li>Sign Up</li>
{% endif %}
</ul>
Now in login view I write like this:
def login(request):
if user_logged_in(request):
return redirect('/')
if request.method == 'GET':
form = LogInForm()
return render_to_response(LOGIN_PATH, {'form':form}, context_instance=RequestContext(request))
But when I run the server, no user is logged in, and visit login page, it shows Settings and Log Out(there is a user object in context), but it shouldn't!
If I remove RequestContext, say return render_to_response(LOGIN_PATH, {'form':form}), it will be OK. And
return render_to_response(LOGIN_PATH, {'form':form, 'user':None}, context_instance=RequestContext(request))
is OK too. But I don't want to do it.
I know it's dirty design, well... I'm looking for suggestions and solutions. Many thanks~!
{% if user.is_authenticated %}
your tag just checks for a user object, not for an authenticated one.
check here for more informations on what you can do with an auth user :)
The default setting for TEMPLATE_CONTEXT_PROCESSORS includes "django.contrib.auth.context_processors.auth". This context processor adds a user to cotnext, which will be anonymous if the user is not provided in request so.
If you want to be able to know whether or not the user is authenticated in template the #Samuele Mattiuzzo answer is what you should use, but if you don't want, for any reason, to include the user in context, then you need to modify the default TEMPLATE_CONTEXT_PROCESSORS setting without the auth context processor.
For more information read the docs or the code.

Showing the logged-in user inside base.html (django)

Is there a way to access the logged in user's firstname inside the base.html file?
I'm trying to do this, because i want to display who is currently logged in on the navigation bar, but it won't access the user's information, nor will it correctly check if the user is authenticated.
html inside base.html
Hi there,
{% if user.is_authenticated %}
{{user.first_name}}
{% else %}
Stranger
{% endif %}
request.user gives you the user object that is currently logged in. So you have full access to all the attributes and methods the User class has. To get the first_name, you can do {{ request.user.first_name }}. To get the full name you use {{ request.user.get_full_name }}.
If you use [RequestContext][1], by default you get user instance in your templates so you can use it as for its attributes as {{user.first_name}} and others. The user will be same a currently authenticated user which is also available in request.user in the views.
The RequestContext by default adds some default template contexts defined in TEMPLATE_CONTEXT_PROCESSORS in your settings.py.
In your view, you can use it as
#your view code
....
#send response by rendering the template and use Requestcontext while rendering template
return render_to_response('polls/detail.html', {'poll': p},
context_instance=RequestContext(request))
Reference - Django Tutorial 04

How to reset user password from the admin interface

In my website, I want to let the admins reset the password of any user.
With reset I mean exactly what the password_reset view does (under contrib.auth): Send a confirmation link to that user email.
How would be the best way of doing that? Is there an already app/snippet that does that?
Edit:
Let's suppose user john is an admin. What I want is to let john reset any user's password through the admin interface. For example, to reset max password, he will just go to the max user, and click on any link to reset his password.
What I finally did was to add a custom ModelAdmin:
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.admin import UserAdmin
class CustomUserAdmin(UserAdmin):
...
def reset_password(self, request, user_id):
if not self.has_change_permission(request):
raise PermissionDenied
user = get_object_or_404(self.model, pk=user_id)
form = PasswordResetForm(data={'email': user.email})
form.is_valid()
form.save(email_template_name='my_template.html')
return HttpResponseRedirect('..')
def get_urls(self):
urls = super(UserAdmin, self).get_urls()
my_urls = patterns('',
(r'^(\d+)/reset-password/$',
self.admin_site.admin_view(self.reset_password)
),
)
return my_urls + urls
and I also had to override the change_form.html template, like this:
{% extends "admin/change_form.html" %}
{% load i18n %}
{% block object-tools %}
{% if change %}{% if not is_popup %}
<ul class="object-tools">
{# You can also give a name to that pattern and refer to it below using 'url' #}
<li>Reset password</li>
<li>{% trans "History" %}</li>
{% if has_absolute_url %}
<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">
{% trans "View on site" %}</a>
</li>
{% endif%}
</ul>
{% endif %}{% endif %}
{% endblock %}
The result looks like this:
If you want a more detailed explanation, I blogged about it.
The passreset app just exposes the django views via urls.py, and adjusts the login template to show a "Forgot my password" link.
The built-in django password reset views and templates are meant for self-reset. I guess the reset form could be prepopulated with a different user's email address (in the query string) but you'd still need to make adjustments such as changing the email template - "You're receiving this e-mail because you requested a password reset for your user account" is probably not what you want:
https://code.djangoproject.com/browser/django/trunk/django/contrib/admin/templates/registration/password_reset_email.html
Therefore you should expose the views at different URLs if you want to include self-reset as well.
Hook the django views into urls.py like so:
urlpatterns += patterns('django.contrib.auth.views',
url(r'^accounts/password/reset/$',
'password_reset',
name='password-reset'),
url(r'^accounts/password/reset/done/$',
'password_reset_done',
name='password-reset-done'),
url(r'^accounts/password/reset/confirm/(?P<uidb36>[-\w]+)/(?P<token>[-\w]+)/$',
'password_reset_confirm',
name='password-reset-confirm'),
url(r'^accounts/password/reset/complete/$',
'views.password_reset_complete',
name='password-reset-complete')
)
and where you want to make adjustments, pass in e.g. your own email template:
url(r'^/accounts/password/reset/$',
'password_reset',
{'email_template_name': 'my_templates/password_reset_email.html'}
name='password-reset'),
The "password_reset" view has more parameters you can tweak:
https://docs.djangoproject.com/en/dev/topics/auth/#module-django.contrib.auth.views
("post_reset_redirect" comes to mind as another one for your purposes)
To show a corresponding link you'd either change the User admin (careful, already registered - unregister then register your own, subclassed plus additional link field) or the change_form template itself.
I'm unaware of an app that provides this out-of-the-box, so I upvoted the question :-).
Yep, there is an app for that. Check here:
https://github.com/bendavis78/django-passreset