I am building an application using webapp2 in Google App Engine. How do I pass the username into the url so that when the profile button is clicked, it takes the user to "/profile/username" where "username" is specific to the user?
My current handlers:
app = webapp2.WSGIApplication([('/', MainPage),
('/signup', Register),
('/login', Login),
('/logout', Logout),
('/profile', Profile)
],
debug=True)
the Profile class:
class Profile(BlogHandler):
def get(self):
email = self.request.get('email')
product = self.request.get('product')
product_list = db.GqlQuery("SELECT * FROM Post ORDER BY created DESC LIMIT 10")
self.render('profile.html', email = email, product = product, product_list = product_list)
I am trying to send each user to a Profile page that contains information in my database specific to them. Thanks
One possible solution would be to simply have one URL, i.e., /profile. The corresponding handler would render the response with data coming from the logged-in user.
If you really want to have URLs like /profile/username, you could define a route:
app = webapp2.WSGIApplication([('/', MainPage),
('/signup', Register),
('/login', Login),
('/logout', Logout),
('r/profile/(\w+)', Profile)
],
debug=True)
and access the username in your handler:
class Profile(BlogHandler):
def get(self, username):
But depending on your application, you might want to make sure only the logged-in user has access to its /profile/username by adding a check somewhere in the handler.
See http://webapp-improved.appspot.com/guide/routing.html
You could have something like
class Profile(BlogHandler):
def get(self, username):
...
app = webapp2.WSGIApplication([('/profile/(\w+)', Profile), ...])
Start by adding a capture group to /profile:
(r'/profile/(\w+)', Profile)
The r before the beginning of the string is important, as it will correctly handle regular expression characters. Otherwise, you'd have to escape the blackslash manually.
\w+ will match one or more alphanumeric characters and the underscore. That should suffice for your usernames, yes?
Then set up your RequestHandler like this:
class Profile(webapp2.RequestHandler):
def get(self, username):
# The value captured in the (\w+) part of the URL will automatically
# be passed in to the username parameter.
# Do the rest of my coding to get and render the data.
Related
I have a basic flask app, where I charge customers to view a page
from flask import Flask, render_template, request, redirect, url_for
import stripe
app = Flask(__name__)
pub_key = 'pk_test_999999999'
secret_key = 'sk_test_999999'
stripe.api_key = secret_key
#app.route('/')
def index():
return render_template('index.html', pub_key=pub_key)
#app.route('/thank_you')
def thanks():
return render_template('thanks.html')
#app.route('/pay', methods=['POST'])
def pay():
customer = stripe.Customer.create(
email=request.form['stripeEmail'],
source=request.form['stripeToken']
)
charge = stripe.Charge.create(
customer=customer.id,
amount=19900,
currency='usd',
description='The Product'
)
return redirect(url_for('thanks'))
if __name__ == '__main__':
app.run(debug=True)
What I am trying to do is restrict access to the thank you page I want no one to access the thank_you by typing the whole url in the browser only paying customers get to see the thank you page even if someone type the whole url www.example.com/thank_you it will redirect to you haven't paid please pay
I thought about adding a login page and having a decorator only login customers, I did not like the idea I don't like to create such a barrier I want no customer info to deal with just pay and access page
Any ideas on how to do that?
Try something like this. Remember this is not completely secure. As I don’t know how your ids and tokens are generated. But it’s just for the sake of simplicity.
If you want something more secure check flask sessions or flask login packages.
customers_payed = []
#app.route('/pay', methods=['POST'])
def pay():
customer = stripe.Customer.create(
email=request.form['stripeEmail'],
source=request.form['stripeToken']
)
charge = stripe.Charge.create(
customer=customer.id,
amount=19900,
currency='usd',
description='The Product'
)
# add customer id to list maybe hash it with its email and token you can make this as hard to guess as you want
customers_payed.append(str(customer.id) + request.form['stripeToken'])
return redirect(url_for('thanks', customer_id=customer.id, token= request.form['stripeToken']))
#app.route('/thank_you')
def thanks():
customer_id = requests.args.get(“customer_id”)
token = requests.args.get(“token”)
# check if its in the list, maybe pop it if customer is only allowed once
if (customer_id+token) in customers_payed:
return render_template('thanks.html')
else:
return redirect(url_for(“replace with error page”))
I am using Flask App builder to make a basic webpage.
I want to change the default landing page based on the user logged in
e.g. user1 should be redirected to /home/user1 page and user2 should login to /home/general page etc after they logged in.
Below is my custom index view
class MyIndexView(IndexView):
index_template = 'index.html'
#expose('/')
def main(self):
return redirect(url_for('AuthDBView.login'))
#expose('/index')
def index(self):
return self.render_template('index.html', message="Welcome to my website")
and starting the app by calling
appbuilder = AppBuilder(app, db.session, indexview=MyIndexView)
I have not seen any example or documentation on how to achieve this. so appreciate any help
First off all, Flask-AppBuilder depends on Flask-login to manage users so you might want to read its documentation.
Besides that, Flask-AppBuilder injects the current_user(authenticated or anonymous) in Flask's g variable before each request, so all you have to do is get the user from g variable and do what you want with it.
Below is an example of an IndexView that redirects anonymous users(not logged in) to the login page.
If the user is not anonynous and its name is John, it is redirected to the HomeView.user endpoint.
If its name is not John, it is redirected to the HomeView.general endpoint.
index.py
from flask import g, url_for, redirect
from flask_appbuilder import IndexView, expose
class MyIndexView(IndexView):
#expose('/')
def index(self):
user = g.user
if user.is_anonymous:
return redirect(url_for('AuthDBView.login'))
else:
if user.first_name == 'John':
return redirect(url_for('HomeView.user'))
else:
return redirect(url_for('HomeView.general'))
Inside views.py
class HomeView(BaseView):
route_base = "/home"
#expose('/user/')
def user(self):
greeting = "Hello John"
return self.render_template('logged_user.html', greeting=greeting)
# expose('/general/')
def general(self):
greeting = "Hello ordinary user"
return self.render_template('logged_user.html', greeting=greeting)
appbuilder.add_view_no_menu(HomeView())
I have written a code for a sign-up page asking for information like username, password and email. After the user gives correct input, the page is redirected to
'/welcome?username=name'
I am using the self.redirect. By using the methd redirect, I am getting the the new URL as '/welcome'. How will I include the query parameter? I also want the user_name to be displayed to the redirected page like :
Welcome name
How will I do this?
This is the class I have written to handle '/welcome'
class welcomeHandler(webapp2.RequestHandler):
def get(self):
self.response.out.write("Welcome")
app = webapp2.WSGIApplication([
('/', MainHandler),('/welcome',welcomeHandler)], debug=True)
If you need to encode it, you can use this:
import urllib
self.redirect('/welcome?' + urllib.urlencode({'username': name})
If you ever need to add more query parameters, just add them to the dictionary, as shown in How to urlencode a querystring in Python?.
You need to use string substitution. Suppose you are storing the username in name. Thus you need to write :
self.redirect("/Welcome/username="+name)
Why would you want to handle the user greeting like that? Either pass it as a template variable or do it as following:
class welcomeHandler(webapp2.RequestHandler):
def get(self):
self.response.out.write("Welcome %s") % username
Also, make sure you create a session for the user once they've signed up, otherwise you're just creating their credential but not actually logging them in.
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.
I asked a similar question here: create permenant unique links based on a user ID but couldn't quite get an answer. I am trying to give every user on my site a unique profile page. I have it mostly set up but I keep getting a 404 error. Now I am not sure if it is a problem with my handler or just the whole way I am doing it.
Here is my app code:
app = webapp2.WSGIApplication([('/', MainPage),
(r'/profile/(.+)', ProfilePage)])
and here is my ProfilePage handler class:
class ProfilePage(webapp2.RequestHandler):
def get(self, profile_id):
profileowner = User.get_by_id(profile_id)
if profileowner:
#Get all posts for that user and render....
#theid is their federated_id
theid = profileowner.theid
personalposts = db.GqlQuery("select * from Post where theid =:1 order by created desc limit 30", theid)
#I collect this so that I can have their username in the top of the page
global visits
logout = users.create_logout_url(self.request.uri)
currentuser = users.get_current_user()
self.render('profile.html', user = currentuser, visits = visits, logout=logout, personalposts=personalposts)
else:
self.redirect("/")
For an ID of 1201, which I found in the datastore viewer for a use, I have been testing it by typing in www.url.com/profile/1201 and that is when I get the 404 error.
Update:
It now is redirecting me to the main page with Amber's suggested change.
Now when I change this line:
profileowner = User.get_by_id(profile_id)
to this:
profileowner = User.get_by_id(17001)
it goes through correctly so I am guessing that that line is not correctly getting the profile_id from the URL
r'/profile/<profile_id>'
is not a valid regular expression. You probably want something like this instead:
r'/profile/(.+)'