I am running into what appears to be a Python error on Google App Engine (localhost)
I am trying to use the Model.get_by_id() function but I run into a multiple keyword arguments error as I've pointed out in the comment in the code below. 3rd line from the bottom
I'm sure this is simple error, I just can't see it.
Thanks in advance!
'''
Created on 09/01/2013
#author: jonathan
'''
import webapp2_extras.security as security
from google.appengine.ext import db
import hashlib
import datetime
class User(db.Model):
username = db.StringProperty(required=True)
passhash = db.StringProperty(required=True)
email = db.EmailProperty()
created = db.DateTimeProperty(auto_now_add=True)
authtoken = db.StringProperty(required=True)
def __init__(self, username, password, email=None):
authtoken = security.generate_random_string(entropy=256)
passhash = security.generate_password_hash(password)
super(User, self).__init__(username=username,
passhash=passhash,
email=email,
authtoken=authtoken)
def __str__(self):
return self.username
def check_password(self, password):
return security.check_password_hash(password, self.passhash)
#classmethod
def check_unique_user(cls, username):
return not bool(cls.all().filter('username =', username).count())
def get_session_token(self, dt=None):
ID = self.key().id()
if not dt:
dt = datetime.datetime.now().strftime("%d%m%y%H%M%S")
hashstring = "{0}${1}${2}".format(ID, dt, self.authtoken)
return '{0}${1}${2}'.format(ID, dt, hashlib.sha256(hashstring).hexdigest())
#classmethod
def check_session_token(cls, session_token):
if session_token:
ID, dt = session_token.split("$")[:2]
if ID.isdigit():
user = cls.get_by_id(ids=int(ID)) # Raises TypeError: __init__() got multiple values for keyword argument 'username'
if user and user.check_session_token(session_token, dt):
return user
The rest of my code:
common.py #This one is still a work in progress...
'''
Created on 06/01/2013
#author: jonathan
'''
import os
import webapp2
import jinja2
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(template_dir),
autoescape=True)
class Handler(webapp2.RedirectHandler):
def write(self, *args, **kwargs):
self.response.out.write(*args, **kwargs)
def render_str(self, template, **params):
templated_html = jinja_env.get_template(template)
return templated_html.render(params)
def render(self, template, **kwargs):
self.write(self.render_str(template, **kwargs))
if os.environ['SERVER_SOFTWARE'].startswith('Development'):
app_scheme = 'http'
else:
app_scheme = 'https'
registration.py
'''
Created on 07/01/2013
#author: jonathan
'''
import common
from webapp2_extras.routes import RedirectRoute
import re
from models.user import User
def getroutes():
return [RedirectRoute(r'/signup', handler=SignupPage, name='signup', schemes=common.app_scheme, strict_slash=True),
(RedirectRoute(r'/welcome', handler=WelcomePage, name='welcome', strict_slash=True)),
(RedirectRoute(r"/login", handler=LoginPage, name="login", schemes=common.app_scheme, strict_slash=True)),
(RedirectRoute(r'/logout', handler=LogoutPage, name="logout", strict_slash=True))]
username_pattern = re.compile(r"^[a-zA-Z0-9_-]{3,20}$")
password_pattern = re.compile(r"^.{3,20}$")
email_pattern = re.compile("^[\S]+#[\S]+\.[\S]+$")
def valid_username(username):
return username_pattern.match(username)
def valid_password(password):
return password_pattern.match(password)
def verify_password(password, verify):
return password == verify
def valid_email(email):
return email_pattern.match(email)
class SignupPage(common.Handler):
def render(self, **kwargs):
super(SignupPage, self).render("signup.html", **kwargs)
def get(self):
session_token = self.request.cookies.get("session")
if User.check_session_token(session_token):
self.redirect_to("welcome")
self.render()
def post(self):
v_username = v_password = v_email = False
username = self.request.get("username")
password = self.request.get("password")
verify = self.request.get("verify")
email = self.request.get("email")
params = {'username_error':'',
'password_error':'',
'verify_error':'',
'email_error':'',
'username':username,
'email':email}
if valid_username(username):
if User.check_unique_user(username):
v_username = True
else:
params['username_error'] = "Username taken"
else:
params['username_error'] = "Invalid username"
if valid_password(password):
if verify_password(password, verify):
v_password = True
else:
params['verify_error'] = "Passwords do not match"
else:
params['password_error'] = "Invalid password"
if valid_email(email):
v_email = True
else:
params['email_error'] = "Invalid email"
if v_username and v_password:
if v_email:
user = User(username=username,
password=password,
email=email)
else:
user = User(username=username,
password=password)
user.put()
session_token = user.get_session_token()
self.response.set_cookie("session", session_token)
self.redirect(r'/welcome')
else:
self.render(**params)
class WelcomePage(common.Handler):
def get(self):
session_token = self.request.cookies.get("session")
user = User.check_session_token(session_token)
if not user:
self.response.delete_cookie('session')
self.redirect_to("signup")
else:
self.render("welcome.html", {'user':user})
class LoginPage(common.Handler):
def get(self):
session_token = self.request.cookies.get("session")
user = User.check_session_token(session_token)
if not user:
self.response.delete_cookie('session')
self.redirect_to("signup")
else:
self.render("login.html")
def post(self):
username = self.request.get('username')
password = self.request.get('password')
remember = self.request.get('remember')
params = {}
user = None
if valid_username(username):
user = User.all().filter('username =', username).get()
if not user:
params['username_error'] = "Can't find username"
else:
params['username_error'] = "Invalid username"
if user and user.check_password(password):
self.redirect_to('welcome')
else:
params['password_error'] = "Mismatched password"
self.render('login.html', params)
class LogoutPage(common.Handler):
def get(self):
self.response.delete_cookie("session")
self.redirect(r'/signup')
You likely have an instance of User in your datastore where "username" is not a StringProperty, but a list. When the db library fetches the entity and parses it, it's unable to convert the list into a StringProperty.
I'd suggest using the datastore viewer and checking that your entities actually have valid Strings for the username.
Edit: Just looked through the code again. It's a very bad idea to override init. The User class is not a typical class, but rather it's a metaclass for generate User instances. ie, your User instances are not actually instances of your user class. I suspect you're running into an issue there.
Related
I am trying to restrict logged user to access URL routes that are not assigned to them. As soon a user had logged, for example user1, will be redirected to https://myurl.com/user1. So far, that works good, but I would like to avoid that user1 can see the content in the route of user2 in https://myurl.com/user2.
Below you can see the code I am currently using.
import tornado
from tornado.web import RequestHandler
import sqlite3
# could define get_user_async instead
def get_user(request_handler):
return request_handler.get_cookie("user")
# could also define get_login_url function (but must give up LoginHandler)
login_url = "/login"
db_file = "user_login.db"
connection = None
cursor = None
# optional login page for login_url
class LoginHandler(RequestHandler):
def get(self):
try:
errormessage = self.get_argument("error")
except Exception:
errormessage = ""
self.render("login.html", errormessage=errormessage)
def check_permission(self, username, password):
connection = sqlite3.connect(db_file)
cursor = connection.cursor()
cursor.execute("SELECT * FROM users WHERE username=? AND password=?", (username, password))
data = cursor.fetchone()
if username == data[1] and password == data[2]:
return True
return False
def post(self):
username = self.get_argument("username", "")
password = self.get_argument("password", "")
auth = self.check_permission(username, password)
if auth:
self.set_current_user(username)
self.redirect(self.get_argument("next", f"/{username}"))
else:
error_msg = "?error=" + tornado.escape.url_escape(
"Login failed, please try again or contact your system administrator."
)
self.redirect(login_url + error_msg)
def set_current_user(self, user):
if user:
self.set_cookie("user", tornado.escape.json_encode(user))
else:
self.clear_cookie("user")
# optional logout_url, available as curdoc().session_context.logout_url
# logout_url = "/logout"
# optional logout handler for logout_url
class LogoutHandler(RequestHandler):
def get(self):
self.clear_cookie("user")
self.redirect(self.get_argument("next", "/"))
Once I get to the verify_token function it keeps executing the except statement instead of returning the value in 'id_user' and I'm not sure why. I am using these libraries. flask-login, sqlalchemy, itsdangerous for jsonwebserializer, and wtforms.
Functions
def get_reset_token(user):
serial = Serializer(app.config['SECRET_KEY'], expires_in=900) # 15 mins in seconds
return serial.dumps({'id_user':user.id}).decode('utf-8')
def verify_token(token):
serial = Serializer(app.config['SECRET_KEY'])
try:
user_id = serial.load(token)['id_user']
except:
return None
return Users.query.get('id_user')
def send_mail(user):
token = get_reset_token(user)
message = Message('Password Reset Request', recipients = [user.email], sender='noreply#gmail.com')
message.body= f'''
To Reset your password, click the following link:
{url_for('reset_token', token = token, _external = True)}
If you did not send this email, please ignore this message.
'''
mail.send(message)
ROUTES
#app.route('/password_reset', methods = ['GET', 'POST'])
def password_reset():
form = Password_request()
if request.method == "POST":
if form.validate_on_submit:
user = Users.query.filter_by(email = form.email.data).first()
send_mail(user)
flash('Check your email. Password change request has been sent')
return redirect(url_for('login'))
else:
flash('Your email was not linked to an account')
return render_template('password_reset.html', form = form)
#app.route('/password_reset/<token>', methods = ['GET', 'POST'])
def reset_token(token):
user = verify_token(token)
if user == None:
flash('The token is invalid or expired')
return redirect(url_for('password_reset'))
form = Password_success()
if form.validate_on_submit:
hashed_password=generate_password_hash(form.password.data, method = 'sha256')
user.password = hashed_password
db.session.commit()
flash('Your password has been updated!')
return redirect(url_for('signup'))
def verify_token(token):
serial = Serializer(app.config['SECRET_KEY'])
try:
user_id = serial.load(token)['id_user']
except:
return None
return Users.query.get('id_user') # this looks wrong
Shouldn't the last line of verify_token be return Users.query.get(user_id)? You're assigning the value of the token to that variable , then ignoring it and telling SQLAlchemy to find a record with the ID of the string value 'id_user' which I doubt is what you're intending to do.
def verify_token(token):
serial = Serializer(app.config['SECRET_KEY'])
try:
user_id = serial.load(token)['id_user']
except:
return None
return Users.query.get(user_id) # What happens when you change this?
I am working on a basic CRUD app in Flask and trying to not use any ORM (learning purposes). On my blueprints, I have multiple folders including a user folder. I wrote 2 classes in blueprints/user/models.py:
User: represent a User entity
UserService : register and login (login is not present yet)
I may move all of my methods from User to UserService but what I am confused about is where and when to interact with the database. Should I do it directly on my route.py vs create a new class?
For instance, to add a new User to the database, my SQL should look more or less like this:
sql = "INSERT INTO users (email, password) VALUES (%s, %s)"
cursor = conn.cursor()
cursor.execute(sql, (email, password))
cursor.fetchall()
conn.commit()
blueprints/user/views.py
from flask import Blueprint, render_template, request, jsonify
from prepsmarter.extensions import conn #database connection variable
user = Blueprint('user', __name__, template_folder='templates')
#user.route('/register')
def login():
return render_template('register.html')
#user.route('/new-user',methods = ['POST'])
def register_user():
# where I am going to register a new user
blueprints/user/models.py
class UserService():
def register_user(self,
email,
password,
registration_date,
active,
sign_in_count,
current_sign_in_on,
last_sign_in_on):
new_user = User(email, password, registration_date, active, sign_in_count, current_sign_in_on, last_sign_in_on)
return new_user.__str__()
class User():
def __init__(self, email, password, registration_date, active, sign_in_count, current_sign_in_on, last_sign_in_on ):
self.email = email
self.password = password
self.registration_date = registration_date
self.active = active
# Activity tracking
self.sign_in_count = sign_in_count
self.current_sign_in_on = current_sign_in_on
self.last_sign_in_on = last_sign_in_on
def desactivate_user(self):
if self.active == False:
print(f"User {self.email} is already inactive")
self.active = False
def reactive_user(self):
if self.active == True:
print(f"User {self.email} is already active")
self.active = True
def is_active(self):
return self.active
def update_activity_tracking(self, ip_address):
self.sign_in_count += 1
self.last_sign_in_on = self.current_sign_in_on
self.current_sign_in_on = datetime.datetime.now()
def update_password(self, new_password):
self.password = get_hashed_password(new_password)
def __str__(self):
user_attributes = vars(self)
return (', '.join("%s: %s" % item for item in user_attributes.items()))
Database.py
import pymysql
class Database:
instance = None
def __init__(self, host, user, password, db):
self.host = host
self.user = user
self. password = password
self.db = db
def connect(self):
try:
conn = pymysql.connect(
host = self.host,
user = self.user,
passwd = self.password,
db = self.db
)
return conn
except Exception as e:
print(e)
I am learning simple python JWT module. I am creating a token using restfull api and then using the same token to get the data, But unfortunately i am getting an error "User does not exist".
Python Code snippet
class User:
def __init__(self, _id, username, password):
self.id = _id
self.username = username
self.password = password
users = [
User(1, "bob", "asdf")
]
username_mapping = {u.username: u for u in users}
userid_mapping = {u.id: u for u in users}
def authenticate(username, password):
user = username_mapping.get(username, None)
if user and user.password == password:
return user
def identity(payload):
user_id = payload["identity"]
return username_mapping.get(user_id, None)
##Using this function for authentication
app = Flask(__name__)
app.secret_key = "jose"
api = Api(app)
jwt = JWT(app,authenticate, identity)
def abort_if_item_not_exist(name):
item = next(filter(lambda x: x["name"] == name, items), None)
if item == None:
abort(404, message = "This item does not exist")
else:
return {"item": item}
class Item(Resource):
#jwt_required()
def get(self,name):
return abort_if_item_not_exist(name)
I have found the answer, thanks to jsp, he pointed a website. I analyzed and got the payload identity id. Then I realized I am getting an ID and I am comparing it with wrong value. it is my typo only.
def identity(payload):
user_id = payload["identity"]
return userid_mapping.get(user_id, None) # This needs to be changed
I will dive straight into the code of the application I'm developing using Google App Engine in Python:
import os
import webapp2
import jinja2
from google.appengine.ext import db
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), autoescape=True)
class Handler(webapp2.RequestHandler):
def write(self, *a, **kw):
self.response.out.write(*a, **kw)
def render_str(self, template, **params):
t = jinja_env.get_template(template)
return t.render(params)
def render(self, template, **kw):
self.write(self.render_str(template, **kw))
class Users(db.Model):
name = db.StringProperty(required = True)
password = db.StringProperty(required = True)
email = db.EmailProperty(required = True)
address = db.PostalAddressProperty(required = True)
join_date = db.DateTimeProperty(auto_now_add = True)
dob = db.DateTimeProperty()
phone = db.PhoneNumberProperty()
class Orders(db.Model):
name = db.StringProperty(required = True)
email = db.EmailProperty(required = True)
address = db.PostalAddressProperty(required = True)
class MainPage(Handler):
def get(self):
self.render("home.html")
class Register(Handler):
def get(self):
self.render("signup-form.html")
def post(self):
name = self.request.get("username")
password = self.request.get("password")
verify = self.request.get("verify")
email = self.request.get("email")
address = self.request.get("address")
phone = self.request.get("phone")
a = Users(name = name, password = password, email = email, address = address, phone = phone)
a.put()
self.response.write("Registration successful!")
class MP(Handler):
def get(self):
self.render("mp.html")
def post(self):
self.render("order2.html")
class Order2Login(Handler, Register):
def get(self):
self.render("orderlogin.html")
def post(self):
old_usr = self.request.get("loginname")
old_pwd = self.request.get("loginpwd")
ans = a.filter("name =", old_usr).filter("password =", old_pwd)
if ans:
self.response.write("You are a registered member!")
else:
self.response.write("You are NOT registered.")
class Order2New(Handler):
def get(self):
self.response.write("New user yeah")
app = webapp2.WSGIApplication([('/', MainPage),
('/register', Register),
('/mp', MP),
('/order2new', Order2New),
('/order2login', Order2Login)], debug=True)
Now, in the Order2Login class, I needed to access the database object 'a' so that I can confirm whether a user is already a member of my website. Now, for that, I inherited the Register class in my Order2Login class, since the 'a' object was initially created in the Register class.
However, after running my application on my local machine, I get the following error:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases Handler, Register
What seems to be the problem in my code?
Inheriting like that doesn't make any sense at all. Even apart from the metaclass problem, inheriting wouldn't make that variable available anyway, since it's a local variable. And in any case, these are two completely separate requests, so data does not persist between them.
But I have no idea why you think you need access to that variable in any case. The User object was persisted to the datastore: in the login view, you don't want to query a, which is a single instance and doesn't have a filter method anyway, you want to query the User class.