Specifically, pages using an optional regular expression. By optional, I mean PAGE_RE below.
I am creating a Wiki. If a user searches a term, and that term doesn't already exist, then the user is redirected to an edit page so they can create the new content. This only happens, however, if the user is logged in. To determine if the user is logged in, I check for a cookie. If the user isn't logged in(no cookie), then I redirect, not to the edit page, to create the new content, but to the login page, dealt with by the Login class below. The user logs in, a cookie is created, and then they are redirected to the edit page to create the content they originally searched for. In order to remember what their topic was, so I can redirect after the login, I send the topic(in the form '/topic') to the Login class, where it's received as a parameter by the get and post methods. If a user just comes to the site and logs in normally, they are redirected to the home page, but in this case, because the topic has been received by get and post and is not None, I use the line self.redirect('/edit/%s' % topic[1:]) below, to send them on to their original destination. The problem is, css isn't working for the two urls in below that use PAGE_RE. JsFiddler4 shows that there is a 404 involving /login/css/wiki.css. It suddenly clicked after some time that that url is not the url for the login page when it receives the extra 'topic' param. It is also the case with EditPage. How can I get css to work on these pages/urls when they are sometimes different? I didn't know what was going on for ages, then I downloaded and ran JsFiddler4 and figured it out. I am using Google App Engine, webapp2, jinja2. Any help much appreciated. Apart from those two pages, css works fine.
This code is out of order and incomplete, but I hope it's sufficient
PAGE_RE = r'(/?(?:[A-Za-z0-9_-]+/?)*)'
app = webapp2.WSGIApplication([
('/signup', Register),
('/logout', Logout),
('/login' + PAGE_RE, Login),
('/edit' + PAGE_RE, EditPage),
('/', Front),
(PAGE_RE, WikiPage),
], debug=True)
class Login(Main):
""" Validate form and validate users cookie """
def get(self, topic):
self.render('login.html', error={})
def post(self, topic):
username = self.request.get('username')
password = self.request.get('password')
if not username or not self.valid(user=username):
self.login_error(user=username)
elif not password or not self.valid(pw=password):
self.login_error(user=username)
elif not self.user_exists(username):
self.render('login.html', error={'no_user':'That user does not exist'})
else:
self.login(username, password, topic=topic)
def login(self, name, pw, topic):
user_hash = User.get_user_hash(name)
if self.valid_pw(name, pw, user_hash):
self.create_secure_cookie('user_id', name)
if topic:
self.redirect('/edit/%s' % topic[1:])
else:
self.redirect('/')
else:
self.login_error(user=name)
def login_error(self, user):
self.render('login.html', username=user, error={'login': errors['login']})
def valid_pw(self, name, pw, user_hash):
salt = user_hash.split('|')[0]
return user_hash == self.create_user_hash(name, pw, salt)
Ok, I solved this. Here's what appeared to be happening.
This redirect was sending a parameter to the Login class above:
self.redirect('login/%s' % wiki_topic) #wiki_topic = something like 'topic'
when looking for the css for a page, what seems to happen is that the last part of the path up to the '/' is taken off, and replaced by the path to the css, '/css/wiki.css' in my case.
So I was passing 'login/topic' and just 'topic' was being replaced by the css path to give:
'login/css/wiki.css' instead of the correct just 'css/wiki/css'.
To stop this from happening, I changed the line redirecting to the Login class from:
self.redirect('login/%s' % wiki_topic) to >> self.redirect('login%s' % wiki_topic)
the second version has no slash before the %s.
Related
I'm building a SSO login meant to be used from links send by emails.
Each link should auto-connect the user (SSO), and be clickable multiple times (they have a TTL, which depends on the email)
It works fine, but I'm concerned about the end-user sharing his url on social networks (basically copy/pasting the url, which contains the SSO token), allowing anyone following the link to be logged in automatically.
My first attempt was to try to remove the GET SSO_TOKEN parameter, from my SSOMiddleware, as follow:
if remove_token_middleware:
request.GET._mutable = True # GET is not mutable by default, we force it
# Remove the token from the url to avoid displaying it to the client (avoids sharing sso token when copy/pasting url)
del request.GET[SSO_TOKEN_PARAM]
request.GET._mutable = False # Restore default mutability
return login(request, user) if service.get("auto_auth") else None
Basically, my thought was that since the SSO_TOKEN is in the request.get object, removing it from it would eventually change the url where the user gets redirected
In my controller, here is how the user gets "redirected" (using render)
return render(request, 'campagne_emprunt/liste_offres_prets.html', locals())
When using render, there is no redirection, and the SSO token is still visible in the URL (in the browser address bar).
Is there a way to somehow tell Django to change the destination url, on the fly?
So in order to redirect, there is a builtin redirect function of Django that you use instead of rendering I think .. give it a shot,
from django.shortcuts import redirect
def redirect_view(request):
response = redirect('/redirect-success/')
return response
and for reference-
https://realpython.com/django-redirects/
If I go to http://localhost:8000/login/, login form will be displayed and you have to input username and password. If the credentials are right then you will be redirected to http://localhost:8000/dashboard/. The problem I am facing while testing is even though my username and password are correct it is not redirected to http://localhost:8000/dashboard/ but rather it goes to http://testserver/admin/login/?next=/dashboard/. I am using the below code to rest redirection functionality in django:
class UrlTests(TestCase):
def test_client_cart(self):
response = self.client.get('/login/')
self.assertEqual(200, response.status_code)
def test_login_client(self):
User.objects.create_user('rakesh', 'rrs402#nyu.edu', 'ranjan')
self.client.get('/login/')
self.client.login(username='rakesh', password='ranjan')
print self.client.get('/dashboard/')
Could anyone tell me why i am redirected to http://testserver/admin/login/?next=/dashboard/ instead http://localhost:8000/dashboard/.
In my settings.py file:
LOGIN_URL = '/'
LOGOUT_URL = '/logout/'
LOGIN_REDIRECT_URL = '/dashboard/'
LOGOUT_REDIRECT_URL = '/'
My application is working fine but I am not able to test redirection thing. Could anyone give me some pointers where I am going wrong?
If I print out print self.client.login(username='rakesh', password='ranjan') it is coming out to be True which means I am able to login but why not redirection ?
Update : I also tried using selenium
def login_user(self):
# User opens his web browser, and goes to the website
self.browser.get(self.live_server_url + '/login/')
# User types in his username and passwords and hits return
username_field = self.browser.find_element_by_name('username')
username_field.send_keys('rakesh')
password_field = self.browser.find_element_by_name('password')
password_field.send_keys('ranjan')
#User submits the form
password_field.send_keys(Keys.RETURN)
body = self.browser.find_element_by_tag_name('body')
print body.text
Here also I am getting the body.text of admin page but not dashboard page.
Update :
Dashboard view :
class PortalDashboardView(RequireStaffMixinView, TemplateView):
template_name = "portal/dashboard.html"
Because you aren't getting logged in. The password you are sending to the login call is different to the one you use when creating the user within your test case, so the credentials are invalid.
Note you don't need to call client.get('/login/') there, anyway.
I have made a signup page using python. Following is the link to the code :
Signup Page Code
As soon as a user signs up, he should be redirected to /welcome which says :
Welcome user
But I cannot display it by the above mentioned code.
Whereas when I write
self.redirect('/welcome?username = '+user)
I get redirected to a page which says
Welcome user
Why is it so?
When you write:
self.redirect('/welcome?username=' + user) #no whitespaces in the url
you are adding to the url a GET parameter(of the type name=value), in your case username=user.
So, when your welcomeHandler class handles the get request:
username=self.request.get('username')
it sets the username to the value of the GET parameter in the url with the name 'username' (username = user) and your welcome message is correctly displayed.
If you:
self.redirect('/welcome')
there are no GET parameters in the url and username is set to the default empty string and just Welcome is displayed.
Check here the Request documentation.
I'm trying to create user sessions as explained here http://www.essentialtech.co.nz/content/using_session_google_app_engine_and_python_27 . Below is the Login page handler class. Everything is fine, but I'm not able to understand what the 'self.session.get('referrer')' would do. I googled for it and found that 'HTTP_REFERER' refers to the site url where you are coming from. But why do we need it in the Login handler here? I feel glad if some one can explain it to me.
class LogIn(BaseHandler):
def get(self):
if self.session.get('user'):
del self.session['user']
if not self.session.get('referrer'):
self.session['referrer'] = \
self.request.environ['HTTP_REFERER'] \
if 'HTTP_REFERER' in self.request.environ \
else '/'
template_values = {
}
template = jinja_environment.get_template('login.html')
self.response.out.write(template.render(template_values))
def post(self):
user = self.request.get('user')
self.session['user'] = user
logging.info("%s just logged in" % user)
self.redirect('/')
I presume it's used to know where to redirect the user after login. But the POST redirects to '/' so doesn't look like it's plugged in, at least not in this snippet. This doesn't make sense though, if you come in from a totally different website. So maybe it's just used for logging / tracking purposes. Again, not detailed in this snippet.
class XX(MethodView):
def get(self):
....
def post(self):
error = None
user = request.form['username']
password = request.form['password']
print user,password
if user == 'xxx' and password == 'xx':
session['logged_in'] = True
session['session_user'] = 'xx'
return redirect("control")
else:
errors = []
errors.append("Login error")
return render_template("login.html" , errors=errors)
#adding rule for control Blueprint
control.add_url_rule("/control",view_func= ControlView.as_view('control'))
The code snippet checks for specific username,password and should redirect to a specific page.
When requested for the login page, a GET request is sent.The above snippet gets username and password and adds to session dictionary.The redirect method results in a POST request and response code is 302 FOUND followed by a GET request to desired page with 200 OK response code.
But the redirection does not happen, it remains on same login page.
what should redirect have as parameters?
redirect('control')
redirect(url_for('control'))
redirect(url_for('control.control'))
Why using render_template('XX.html') responds with 500 response code ??
Is this code inside of a blueprint named 'control'? I'm guessing yes, based on the code shown above.
When you're using blueprints, you cannot know the final URL (eg: /control) in advance, since the blueprint user can map the base URL anywhere they'd like.
The best way to redirect to your view, assuming this is a blueprint, is using the blueprint URL notation: redirect(url_for('control.control')).
If this is NOT going to be used in a blueprint, you should be able to do something like: redirect(url_for('control')) so long as that's your view name when added to the route.
Hope this was clear.
If you're still having errors when trying to two above examples, enable Flask debugging (app.config['DEBUG'] = True) and re-try. The traceback should explain what's happening in more depth.