I'm trying to learn the Peewee ORM in combination with Flask by following the Flask Mega Tutorial. In part 5 of the tutorial I create a login using OpenID. After overcoming a bunch of hurdles already I now get an AttributeError in the function pasted below on the following line: login_user(user, remember = remember_me).
#oid.after_login
def after_login(resp):
if resp.email is None or resp.email == "":
flash('Invalid login. Please try again.')
return redirect(url_for('login'))
user = User.select().where(User.email == resp.email)
if user.wrapped_count() == 0:
nickname = resp.nickname
if nickname is None or nickname == "":
nickname = resp.email.split('#')[0]
user = User(nickname = nickname, email = resp.email, role = models.ROLE_USER)
user.save()
remember_me = False
if 'remember_me' in session:
remember_me = session['remember_me']
session.pop('remember_me', None)
login_user(user, remember = remember_me)
return redirect(request.args.get('next') or url_for('index'))
is_active is found in my User model as follows:
class User(db.Model):
nickname = TextField()
email = TextField()
role = IntegerField(default = ROLE_USER)
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return self.id
def __repr__(self):
return '<User %r>' % (self.nickname)
I have no clue what I'm doing wrong here though. Could anybody give me a helping hand in what I'm doing wrong here?
All tips are welcome!
As the error suggests, user = User.select().where(User.email == resp.email) gives you back a SelectQuery, not an instance of User. You'll want to include an additional method call to actually fetch the record, something like .first(). first will return either an instance of User or None.
This would allow you to slightly adjust your code:
user = User.select().where(User.email == resp.email).first()
if not user: # or if user is None:
nickname = resp.nickname
...
Related
so i currently have my likes app which deals with friend requests, and it works fine however my notification dont seem to be working. Whenever some likes someone else regardless of weather they are liked by that user or not it only sends the second of the two notify.send.
heres my code:
View.py
def like_user(request, id):
pending_like = get_object_or_404(User, id=id)
user_like, created = UserLike.objects.get_or_create(user=request.user)
user = get_object_or_404(User, username=request.user)
liked_user, like_user_created = UserLike.objects.get_or_create(user=user)
if pending_like in user_like.liked_users.all():
user_like.liked_users.remove(pending_like)
elif request.user in liked_user.liked_users.all():
user_like.liked_users.add(pending_like)
notify.send(request.user,
#action=request.user.profile,
target=request.user.profile,
recipient=pending_like,
verb='sent you a friend request view'),
else:
user_like.liked_users.add(pending_like)
notify.send(request.user,
#action=request.user.profile,
target=request.user.profile,
recipient=pending_like,
verb='accepted your friend request view')
return redirect("profile", username=pending_like.username)
models.py
class UserLikeManager(models.Manager):
def get_all_mutual_likes(self, user, number):
try:
qs = user.liker.liked_users.all().order_by("?")
except:
return []
mutual_users = [][:number]
for other_user in qs:
try:
if other_user.liker.get_mutual_like(user):
mutual_users.append(other_user)
except:
pass
return mutual_users
class UserLike(models.Model):
user = models.OneToOneField(User, related_name='liker')
liked_users = models.ManyToManyField(User, related_name='liked_users', blank=True)
objects = UserLikeManager()
def __unicode__(self):
return self.user.username
def get_mutual_like(self, user_b):
i_like = False
you_like = False
if user_b in self.liked_users.all():
i_like = True
liked_user, created = UserLike.objects.get_or_create(user=user_b)
if self.user in liked_user.liked_users.all():
you_like = True
if you_like and i_like:
return True
else:
return False
as you can see in my views.py i have an if statement with one elif, however it never seems to pick up on that elif and goes direct to the else, so in my notifications i always get the 'accepted your friend request view' message. I cant seem to fix this issue if anyone can see an faults please let me know.
When i use it in my profile app to display a button showing, confirm friend request it seems to work. here is my code for the profile:
view.py
def profile_view(request, username):
user = get_object_or_404(User, username=username)
liked_user, like_user_created = UserLike.objects.get_or_create(user=user)
do_they_like = False
if request.user in liked_user.liked_users.all():
do_they_like = True
context = {
"do_they_like": do_they_like
}
return render(request, "profiles/profile_view.html", context)
Thanks
Problem in your below line
user = get_object_or_404(User, username=request.user)
Update above with below line
user = get_object_or_404(User, pk=request.user.pk)
I have been working on a small web app and I decided it would be a good idea if I used email verification. Well, when I attempted to add email verification I sort of broke my code... I keep getting a traceback telling me the following:
TypeError: <'peewee.CharField object at 0x7f46c6a7ba50> is not JSON serializable
I have come to the conclusion that I need to make my users model JSON serializable but I am not 100% sure that's what I need to do. Even if I am right, I wouldn't know how to do that.
Here is my user model:
class User(UserMixin, Model):
username = CharField(unique=True)
password = CharField(max_length=20)
email = CharField(unique=True)
confirmed = BooleanField(default=False)
confirmed_on = DateTimeField(default=datetime.datetime.now())
joined_at = DateTimeField(default=datetime.datetime.now)
class Meta:
database = db
order_by = ('-joined_at',)
#classmethod
def create_user(cls, username, email, password, confirmed):
try:
with db.transaction():
cls.create(
username=username,
email=email,
password=generate_password_hash(password),
confirmed=False)
except IntegrityError:
raise ValueError("User already exists")
as far as email verification goes here is what I tried:
def generate_serializer(secret_key=None):
return URLSafeTimedSerializer(app.config['SECRET_KEY'])
def generate_activation_url(user):
serializer = generate_serializer()
token = serializer.dumps(user.username)
return url_for('activate_user', token=token, _external=True)
#app.route('/', methods=('GET', 'POST'))
def index():
form = forms.RegisterForm()
if form.validate_on_submit():
models.User.create_user(
username=form.username.data,
email=form.email.data,
password=form.password.data,
confirmed=False
)
token = generate_activation_url(models.User)
msg =Message(render_template('activation_email.html', token=token),
recipients=[models.User.email])
mail.send(msg)
return render_template('activate.html', user=models.User)
return render_template('index.html', form=form)
#app.route('/activate/<token>')
def activate_user(token, expiration=3600):
serializer = generate_serializer()
try:
serializer.loads(token, salt=app.config[
'SECRET_KEY'], max_age=expiration)
except (BadSignature, SignatureExpired):
abort(404)
models.User.confirmed = True
flash('User activated')
return redirect(url_for('index'))
I found a script online which helps me changing login to use both username and email instead of just username, but there are quite a lot of parts which I don't really understand.
Like, I understand pretty much what each line means but I don't get why by doing that would make my login work with email.
class EmailBackend(object):
def authenticate(self, username=None, password=None):
user_cls = get_user_model()
try:
user = user_cls.objects.get(email=username)
if user.check_password(password):
return user
except user_cls.DoesNotExist:
return None
except:
return None
def get_user(self, user_id):
user_cls = get_user_model()
try:
return user_cls.objects.get(pk=user_id)
except user_cls.DoesNotExist:
return None
Thanks in advance.
Check comments :-
class EmailBackend(object):
def authenticate(self, username=None, password=None):
user_cls = get_user_model() #Getting user object in one variable
try:
user = user_cls.objects.get(email=username) #Check any user exist with input email(username) with database email(consider as an username)
if user.check_password(password): #if user match then check is password match or not
return user #If both email and password match then return user information
except user_cls.DoesNotExist: #if user not exist then return None
return None
except: #got any error in middle return None
return None
def get_user(self, user_id):
user_cls = get_user_model() #Get user object in one variable
try:
return user_cls.objects.get(pk=user_id) #check user with this user_id exist or not, may be PK (some unique id consider as an user_id)
except user_cls.DoesNotExist: #if user_id(PK) not exist return None
return None
I am trying to find a way to retrieve information such as 'mail', 'displayName', 'telephoneNumber' from an LDAP authenticated/logged in user in Flask.
My user can successfully authenticate and log in using LDAP. However how would I be able to get additional information about the user?
I am using standard python-ldap and flask-login modules and I'm trying to create a string variable for these attributes so I can call on them later in the session. When trying to run the query I am getting ldap.FILTER_ERROR: {'desc': u'Bad search filter'} . Any ideas on how to get this working?
class UserInfo():
def whoami(username, password):
conn = get_ldap_connection()
conn.simple_bind_s(username,password)
basedn = 'OU=...,OU=...,DC=...,DC=...'
userfilter = "(|(SamAccountName=\*" + username + "\*)"
userattribute = ['displayName']
userresults = conn.search_s(basedn,ldap.SCOPE_SUBTREE,userfilter, userattribute)
userinfos = UserInfo()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(100))
def __init__(self, username, password):
self.username = username
#staticmethod
def try_login(username, password):
conn = get_ldap_connection()
conn.simple_bind_s(domain+username, password)
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return unicode(self.id)
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
#app.before_request
def get_current_user():
g.user = current_user
I needed to use ldap.filter.filter_format for proper character escaping.
import ldap.filter
criteria= ldap.filter.filter_format('(&(objectClass=user)(sAMAccountName=%s))', [username])
So far I made my user object and my login function, but I don't understand the user_loader part at all. I am very confused, but here is my code, please point me in the right direction.
#app.route('/login', methods=['GET','POST'])
def login():
form = Login()
if form.validate():
user=request.form['name']
passw=request.form['password']
c = g.db.execute("SELECT username from users where username = (?)", [user])
userexists = c.fetchone()
if userexists:
c = g.db.execute("SELECT password from users where password = (?)", [passw])
passwcorrect = c.fetchone()
if passwcorrect:
#session['logged_in']=True
#login_user(user)
flash("logged in")
return redirect(url_for('home'))
else:
return 'incorrecg pw'
else:
return 'fail'
return render_template('login.html', form=form)
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('home'))
my user
class User():
def __init__(self,name,email,password, active = True):
self.name = name
self.email = email
self.password = password
self.active = active
def is_authenticated():
return True
#return true if user is authenticated, provided credentials
def is_active():
return True
#return true if user is activte and authenticated
def is_annonymous():
return False
#return true if annon, actual user return false
def get_id():
return unicode(self.id)
#return unicode id for user, and used to load user from user_loader callback
def __repr__(self):
return '<User %r>' % (self.email)
def add(self):
c = g.db.execute('INSERT INTO users(username,email,password)VALUES(?,?,?)',[self.name,self.email,self.password])
g.db.commit()
my database
import sqlite3
import sys
import datetime
conn = sqlite3.connect('data.db')#create db
with conn:
cur = conn.cursor()
cur.execute('PRAGMA foreign_keys = ON')
cur.execute("DROP TABLE IF EXISTS posts")
cur.execute("DROP TABLE IF EXISTS users")
cur.execute("CREATE TABLE users(id integer PRIMARY KEY, username TEXT, password TEXT, email TEXT)")
cur.execute("CREATE TABLE posts(id integer PRIMARY KEY, body TEXT, user_id int, FOREIGN KEY(user_id) REFERENCES users(id))")
I also set up the LoginManager in my init. I am not sure what to do next, but I know I have to some how set up this
#login_manager.user_loader
def load_user(id):
return User.query.get(id)
how do I adjust this portion code to work for my database?
EDIT: please let me know if this looks correct or can be improved :)
#login_manager.user_loader
def load_user(id):
c = g.db.execute("SELECT id from users where username = (?)", [id])
userid = c.fetchone()
return userid
#app.route('/login', methods=['GET','POST'])
def login():
form = Login()
if form.validate():
g.user=request.form['name']
g.passw=request.form['password']
c = g.db.execute("SELECT username from users where username = (?)", [g.user])
userexists = c.fetchone()
if userexists:
c = g.db.execute("SELECT password from users where password = (?)", [g.passw])
passwcorrect = c.fetchone()
if passwcorrect:
user = User(g.user, 'email', g.passw)
login_user(user)
flash("logged in")
return redirect(url_for('home'))
else:
return 'incorrecg pw'
else:
return 'fail'
return render_template('login.html', form=form)
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('home'))
import sqlite3
from flask import g
class User():
def __init__(self,name,email,password, active = True):
self.name = name
self.email = email
self.password = password
self.active = active
def is_authenticated(self):
return True
#return true if user is authenticated, provided credentials
def is_active(self):
return True
#return true if user is activte and authenticated
def is_annonymous(self):
return False
#return true if annon, actual user return false
def get_id(self):
c = g.db.execute('SELECT id from users where username = (?)', [g.user])
id = c.fetchone()
return unicode(id)
#return unicode id for user, and used to load user from user_loader callback
def __repr__(self):
return '<User %r>' % (self.email)
def add(self):
c = g.db.execute('INSERT INTO users(username,email,password)VALUES(?,?,?)',[self.name,self.email,self.password])
g.db.commit()
user_loader callback function is a way to tell Flask-Login on "how" to look for the user id from the database ? Since you are using sqllite3, you need to implement the user_loader function to query your sqllite database and fetch/return the userid/username that you have stored. Something like:
#login_manager.user_loader
def load_user(id):
c = g.db.execute("SELECT username from users where username = (?)", [id])
userrow = c.fetchone()
userid = userrow[0] # or whatever the index position is
return userid
When you call login_user(user), it calls the load_user function to figure out the user id.
This is how the process flow works:
You verify that user has entered correct username and password by checking against database.
If username/password matches, then you need to retrieve the user "object" from the user id. your user object could be userobj = User(userid,email..etc.). Just instantiate it.
Login the user by calling login_user(userobj).
Redirect wherever, flash etc.
Are you using SQLAlchemy by any chance?
Here is an example of my model.py for a project I had a while back that used Sqlite3 & Flask log-ins.
USER_COLS = ["id", "email", "password", "age"]
Did you create an engine?
engine = create_engine("sqlite:///ratings.db", echo=True)
session = scoped_session(sessionmaker(bind=engine, autocommit=False, autoflush=False))
Base = declarative_base()
Base.query = session.query_property()
Base.metadata.create_all(engine)
Here is an example of User Class:
class User(Base):
__tablename__ = "Users"
id = Column(Integer, primary_key = True)
email = Column(String(64), nullable=True)
password = Column(String(64), nullable=True)
age = Column(Integer, nullable=True)
def __init__(self, email = None, password = None, age=None):
self.email = email
self.password = password
self.age = age
Hope that helps give you a little bit of a clue.
Use SQLAlchemy it completely handles all the queries for you, so you don't have to write it all out.
But if you continue using it this way, then your user_loader function should create a "User" class object. Like:
userrow = c.fetchone()
username = userrow[0]
u = User(username=username)
return u