Flask-Social on a CSRF enabled website - python

I'm trying to implement login/registration views in Flask that support both regular login (through Flask-Security) and OAuth login (through Flask-Social).
My website uses CSRF protection, but when I implement a link to the OAuth login page (as per the Flask-Social example project) I get a CSRF error. Here is the template:
{% extends "base.html" %}
{% from "security/_macros.html" import render_field_with_errors, render_field %}
{% block title %}Login{% endblock %}
{% block body %}
<h1>Login</h1>
{% include "security/_messages.html" %}
<form action="{{ url_for_security('login') }}" method="POST"
name="login_user_form">
{{ login_user_form.hidden_tag() }}
{{ render_field_with_errors(login_user_form.email,
class="form-control", placeholder="Your email") }}
{{ render_field_with_errors(login_user_form.password,
class="form-control", placeholder="Password") }}
{{ render_field(login_user_form.remember) }}
{{ render_field(login_user_form.next) }}
{{ render_field(login_user_form.submit, class="btn btn-primary") }}
</form>
<form action="{{ url_for('social.login', provider_id='google') }}"
name='google_login_form' method="POST">
<input class="btn btn-primary btn-large" type="submit"
name="login_google" value="Login with Google" >
</form>
{% include "security/_menu.html" %}
{% endblock %}
The problem seems to be that the second form does not have a CSRF field; what can I do about this?

You should follow the Flask-WTF docs on using templates without forms.
As per the docs, in the app
from flask_wtf.csrf import CsrfProtect
CsrfProtect(app)
and in the template
<form method="post" action="/">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
</form>
Your second form would be
<form action="{{ url_for('social.login', provider_id='google') }}"
name='google_login_form' method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input class="btn btn-primary btn-large" type="submit"
name="login_google" value="Login with Google" >
</form>

Related

LIKE button in a Django project

There is a view in the Django project (a paginated blog) that is responsible for how likes work. It has one drawback: when a user likes a post, it is redirected to the main page of the site. How can I fix this so that the user would remain on the page where they liked.
views.py
class AddLikeView(View):
def post(self, request, *args, **kwargs):
blog_post_id = int(request.POST.get('blog_post_id'))
user_id = int(request.POST.get('user_id'))
url_from = request.POST.get('url_from')
user_inst = User.objects.get(id=user_id)
blog_post_inst = News.objects.get(id=blog_post_id)
try:
blog_like_inst = BlogLikes.objects.get(blog_post=blog_post_inst, liked_by=user_inst)
except Exception as e:
blog_like = BlogLikes(blog_post=blog_post_inst,
liked_by=user_inst,
like=True)
blog_like.save()
return redirect(url_from)
template.py
<form action="{% if not is_liked_bool %}{% url 'add' %}{% else %}{% url 'remove' %}{% endif %}" method="post">
{% csrf_token %}
<input type="hidden" name="blog_post_id" value="{{ blog_post_id }}">
<input type="hidden" name="user_id" value="{% if user.is_authenticated %}{{ request.user.id }}{% else %}None{% endif %}">
<input type="hidden" name="url_from" value="{{ request.path }}">
{% if is_liked_bool %}
<input type="hidden" name="blog_likes_id" value="{{ blog_likes_id }}">
{% endif %}
<button type="submit" class="btn btn-success">
{% if not is_liked_bool %}
<i class="fi-xnluxl-heart">♥</i>
{% else %}
<i class="fi-xnluxl-heart-solid">♥</i>
{% endif %}
<span class="likes-qty">{{ likes_counter }}</span>
</button>
I think you should check the url_from field first. Just print it and if it's wrong, you should change the {{request.path}} field in your template.
You can try this:
{{ request.get_full_path }}
And also if I remember correctly, you can access the path with request.path in your view and no need to send path via template.

Django input login for an admin

How can I add attribute autocomplete="off" to the input login template form for an admin?
I'm find this in the login.html template but can't find where is the form template
<div class="form-row">
{{ form.username.errors }}
{{ form.username.label_tag }} {{ form.username }}
</div>
If you need to change behavior based on whether or not the user is admin/staff:
{% if request.user.is_staff %}
<form autocomplete="off" method="post" action="action_name">
<input autocomplete="off" name="hidden" type="text" style="display:none;">
{% else %}
<form method="post" action="action_name">
{% endif %}
<div class="form-row">
And complete the rest of the form as you would.
Reference for the form and input tags to turn autocomplete off (note autocomplete is "off" in the input tag as per testing in comments):
https://gist.github.com/niksumeiko/360164708c3b326bd1c8

How is this code supposed to be indented?

I'm learning django and python and I want to know how to indent this code properly. How should it be done?
{% block content %}
<h2>Nyinkommet</h2>
{% if request.GET.sorting == 'desc' %}
<form method="get" action=".">
<input type="hidden" name="sorting" value="asc">
<input type="submit" value="Visa äldsta ärende först">
</form>
{% else %}
<form method="get" action=".">
<input type="hidden" name="sorting" value="desc">
<input type="submit" value="Visa nyaste ärende först">
</form>
{% endif %}
You could use the template tags {{ sortvalue }} to check the value and set the specific attribute value.
You could achieve it somewhere as:
my_template.html
{% block content %}
<h2>Nyinkommet</h2>
<form method="post" action="/postingUrl">
<input type="hidden" name="sorting" value="{{ sortvalue }}">
<input type="submit" value="Visa äldsta ärende först">
</form>
{% endblock %}
Pass the sortvalue in the rendering of template:
The view that returns "my_template.html":
def get_home_page(request):
sortvalue = "asc" # Calculate what value you want, (asc or desc)
return render_to_response('my_template.html',
{ 'sortvalue' : sortvalue },
context_instance=RequestContext(request))
Code indentation comes down to personal preference. As long as your code is readable it is up to you and those you work with; do what you want.
For ideas and general good practises you should look through the django documentation. It is contributed to by x00's of developers and will give you a good idea of formatting and best practices.
Personally I would indent the elements inside the forms. I also try to keep all HTML dom elements at the same nesting level as their siblings even when using django template operations.
{% block content %}
<h2>Nyinkommet</h2>
{% if request.GET.sorting == 'desc' %}
<form method="get" action=".">
<input type="hidden" name="sorting" value="asc">
<input type="submit" value="Visa äldsta ärende först">
</form>
{% else %}
<form method="get" action=".">
<input type="hidden" name="sorting" value="desc">
<input type="submit" value="Visa nyaste ärende först">
</form>
{% endif %}
One small improvement you could make to the code is the following:
{% block content %}
<h2>Nyinkommet</h2>
<form method="get" action=".">
{% if request.GET.sorting == 'desc' %}
<input type="hidden" name="sorting" value="asc">
{% else %}
<input type="hidden" name="sorting" value="desc">
{% endif %}
<input type="submit" value="Visa äldsta ärende först">
</form>
{% endblock content %}

Django allauth signup form empty

I'm trying allauth for the first time and having difficulty signing up for the first time. I am using the Facebook support and I connect to Facebook successfully, logging in and get to /accounts/social/signup:
where my Facebook name and email address are pre-filled, but the button doesn't work, quite possibly because the form action is empty. I checked the allauth package template, and it seems designed this way. I'm not sure what's going on, but it's not working for me. Please help!
Excerpt from rendered page http://localhost:8000/accounts/social/signup/
<p>{% blocktrans with provider_name=account.get_provider.name site_name=site.name %}You are
about to use your {{provider_name}} account to login to
{{site_name}}. As a final step, please complete the following form:{% endblocktrans %}</p>
<form class="signup" id="signup_form" method="post" action="">
{% csrf_token %}
{{ form.as_p }}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<button type="submit">{% trans "Sign Up" %} »</button>
</form>
excerpt from /virtualenvs/myproject/lib/python2.7/site-packages/allauth/templates/socialaccount/signup.html
<form class="signup" id="signup_form" method="post" action="">
{% csrf_token %}
{{ form.as_p }}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<button type="submit">{% trans "Sign Up" %} »</button>
</form>
Action was left out in code and has now been changed on github, although apparently not in the pip package directory, thus I installed the error.

Django Comments-Redirecting

how can I get rid of users being directed to the “Thanks you
for your comment” page after commenting in Django site? I want users to be
redirected to the same page they commented. I’m using Django
comments.
I’ve tried adding:
<input type=”hidden” name=”next” value=”"{% url
django.contrib.comments.views.comments.comment_done %}" />
But it’s not working. Below is codes in my comment/form.html
{% load comments %}
{% get_comment_count for sol as comment_count %}
{% get_comment_list for sol as comment_list %}
{% get_comment_form for sol as form %}
{% if user.is_authenticated %}
<form action="{% comment_form_target %}" method="post">
{% csrf_token %}
{% if next %}<input type="hidden" name="next" value="{% url
django.contrib.comments.views.comments.comment_done %}" />{% endif %}
{% for field in form %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% if field.name != "name" and field.name != "email"
and field.name != "url" %}
{% if field.errors %}{{ field.errors }}{% endif %}
{{ field }}
{% endif %}
{% endif %}
{% endfor %}
<input class="submit-post" name="post" type="submit" value="Comment" />
</form>
{% else %}
I'm sorry, but you must be <a href="javascript:alert('send to
login page')">logged in</a> to submit comments.
{% endif %}
First let's review your code:
<input type=”hidden” name=”next” value=”"{% url
django.contrib.comments.views.comments.comment_done %}" />
Two double quotes: value=”"{% url
The url is comment_done: so this will redirect to the "Thank you for your comment page", which you want to avoid
Use url names instead of module name: {% url comments-comment-done %} rather than {% url django.contrib.comments.views.comments.comment_done %}
Instead, you can redirect the comment poster to the absolute url of the object he commented:
<input type="hidden" name="next" value="{{ form.instance.content_object.get_absolute_url }}" />
This assume that your model has the standard get_absolute_url() method defined.
Or even, you can redirect the user to the very same page he's on:
<input type="hidden" name="next" value="{{ request.path }}" />
Or the previous page he visited:
<input type="hidden" name="next" value="{{ request.META.HTTP_REFERER }}" />

Categories