I'm learning about testing in Django. I need to first create user and login before I can test anything. I have tried the following...
class ProjectTest(TestCase):
def setUp(self):
self.email = 'test#test.com'
self.password = 'test'
self.new_user = AppUser.objects.create_superuser(email=self.email, password=self.password)
new_user = authenticate(username=self.email,
password=self.password)
login(request, new_user)
self.assertEqual(login, True)
def tearDown(self):
self.new_user.delete()
which gives me the error: AttributeError: 'str' object has no attribute 'session'
I have also tried:
def setUp(self):
self.email = 'test#test.com'
self.password = 'test'
self.new_user = AppUser.objects.create_superuser(email=self.email, password=self.password)
login = self.new_user.login(username=self.email, password=self.password)
But it states I don't have anything called login.
What is the correct way of doing this?
You don't call login on a user, you call it on an instance of the test client.
self.client.login(username=self.email, password=self.password)
class ProjectTest(TestCase):
def test_login_feature(self):
user = User.objects.create_user(username='joe', password='pass')
self.client.login(username='joe', password='pass')
# client now authenticated and can access
# restricted views.
So this is how you would do it. Create a user and use self.client.login you can read more about how to use it in the documentation
Related
I'm trying to access the currently logged in user eslewhere in my code (i.e in other classes). I've managed to do this to some extent with global (frowned upon I know but didn't find any other way), as shown below:
class Login(Screen):
def login(self, email, password):
try:
global user
user = auth.sign_in_with_email_and_password(email, password)
print(user['localId']) #This is the users uid
class SelectChat(Screen):
def __init__(self, **kwargs):
super(SelectChat, self).__init__(**kwargs)
grid = GridLayout(cols=1)
self.add_widget(grid)
docs = db.collection(u'users').where(u'value', u'==', True).stream()
for doc in docs: # cycle through database and create Buttons for each value found
dict = doc.to_dict()
btn = Button(text="{} {}".format(dict['first_name'], dict['last_name']), id=doc.id)
btn.bind(on_release=self.move_to_chat(doc.id))
grid.add_widget(btn)
def move_to_chat(self, *args):
group_id = str(user['localId']) + str(doc.id) # This is where I'm trying to access the user variable but it's getting called on startup due to the above ```btn.bind()``` call.
print(group_id)
MDApp.get_running_app().sm.current = "chat"
The problem I'm having now is that I want to access the user['localId'] value in the __init__ method of another class. As this is run when as soon as the app has loaded the login method hasn't started and therefore there's no user variable.
Error message: NameError: name 'user' is not defined
I have an Angular app that is making API calls to the backend Flask app. The Flask app is using Flask-Login to authenticate users when they login. When the user logs in with the login() function I defined, current_user.is_authenticated returns True. When I call another function called get_is_logged_in(), current_user.is_authenticated returns False.
My User class inherits from UserMixin, so it has all of the required properties and methods as explained in the documentation (https://flask-login.readthedocs.io/en/latest/#your-user-class). In the login() function, after calling login_user(), I checked current_user.id to verify that the proper user is being logged in. I also checked current_user.is_anonymous and it returned False, as expected.
user.py
from sqlalchemy import Column, String, Text, Integer
from flask_login import UserMixin
from .database import Base, Session
class User(Base, UserMixin): # Inherits UserMixin
__tablename__ = "USER"
id = Column(Integer, primary_key=True)
email = Column(String(450), unique=True, nullable=False)
first_name = Column(String, nullable=False)
last_name = Column(String, nullable=False)
password = Column(Text, nullable=False)
def __init__(self, email, first_name, last_name, password):
self.email = email
self.first_name = first_name
self.last_name = last_name
self.password = password
database.py
from sqlalchemy import create_engine, Column, String, Integer, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import pymssql
db_url = "DB_URL"
db_name = "DB_NAME"
db_user = "DB_USER"
db_password = "DB_PW"
engine = create_engine(f'mssql+pymssql://{db_user}:{db_password}#{db_url}/{db_name}')
Session = sessionmaker(bind=engine)
Base = declarative_base()
main.py
from flask import Flask, jsonify, request
from flask_login import LoginManager, login_user, login_required,
logout_user, current_user
from .entities.database import Session, engine, Base
from .entities.user import User
import json
# Other necessary imports
#login_manager.user_loader
def load_user(user_id):
return Session().query(User).filter_by(id=user_id).first()
#app.route('/api/login', methods=['POST'])
def login():
try:
posted_email = request.json['email'].lower()
posted_password = request.json['password']
user_json = get_user_by_email(posted_email)
if not bcrypt.check_password_hash(user_json.get_json() ['password'], posted_password): # The password was incorrect
return jsonify(success=False, message='The password is incorrect')
else: # The login was successful, so pass in all user credentials (except password)
# Get user object from the database
user = load_user(1) # Hard-coded id for testing
# Login the user
login_user(user, remember=False, force=True)
return jsonify(
success=True,
user=current_user.is_authenticated # Returns True
)
except KeyError: # A KeyError is only thrown if the user does not exist
return jsonify(success=False, message='A user with that email does not exist')
#app.route('/api/isLoggedIn', methods=['POST'])
def get_is_logged_in():
return jsonify(success=current_user.is_authenticated) # Returns False when called
Notice that I am using the declarative base from SQLAlchemy. Any help is appreciated.
return jsonify(
success=True,
user=current_user.is_authenticated # Returns True
)
This will always return true because you're explicitly setting success = True regardless of the value of current_user.is_authenticated
I don't see you calling get_is_logged_in anywhere, but the most obvious reason for it returning false is because current_user.is_authenticated isn't actually equal to True when the function is being called, thus you're setting success to false.
A code snippet of you calling get_is_logged_in would be helpful to know for sure.
There is a chance that the current_user is not being persisted between requests, especially if your methods of calling /api/login and /api/isLoggedIn vary.
The load_user() function will run for each request so you might find it helpful to check the user_id it is loading each request (i.e. add a print statement).
When I try getting a kind from my datastore it returns NoneType, as if the query is empty. I know the datastore is working properly while saving, but pulling a kind from the a query is not.
Also using the GQL Query in the Google cloud Console website and using SELECT * FROM User does return all the kinds. User kind has no parents, it is at the root. I made sure all the properties are indexed as well.
I am not sure what I am doing wrong on GET.
MyApp.py
import webapp2
from google.appengine.ext import ndb
from google.appengine.ext.db import GqlQuery
class MainHandler(webapp2.RequestHandler):
def post(self):
message = self.request.body
message = message.splitlines()
if message[0] == "register":
user = User.create_user(message[1], message[2], message[3])
user_key = User.save_user(user)
if user_key is not None:
self.response.write(user_key)
else:
user = User.get_by_id(User.email == message[0])
if User.token == message[1]:
self.response.write("CURRENT")
else:
User.token = message[1]
User.save_user(user)
self.response.write("UPDATED")
def get(self):
self.response.write("CONNECTED")
user= User.query().get()
self.response.write("\n" + query.email)
class User(ndb.Model):
email = ndb.StringProperty()
token = ndb.StringProperty()
name = ndb.StringProperty()
#classmethod
def create_user(cls, email, token, name):
user = User(email=email, token=token, name=name, id=email)
return user
#classmethod
def save_user(cls, user):
user_key = user.put()
return user_key
#classmethod
def get_user(cls, email):
return User.get_by_id(User.email == email)
app = webapp2.WSGIApplication([
('/', MainHandler)
], debug=True)
You seem to be confusing .get_by_id() with a query.
The get_by_id method is actually mapped to ndb.Model._get_by_id which invokes ndb.Model._get_by_id_async, which requires an entity key identifier to determine the entity's key used to do a direct entity lookup (not a query!). From appengine.ext.ndb.model.py:
#classmethod
#utils.positional(3)
def _get_by_id_async(cls, id, parent=None, app=None, namespace=None,
**ctx_options):
"""Returns an instance of Model class by ID (and app, namespace).
This is the asynchronous version of Model._get_by_id().
"""
key = Key(cls._get_kind(), id, parent=parent, app=app, namespace=namespace)
return key.get_async(**ctx_options)
But in your code you're passing as id a bool: User.email == message[0], which most likely won't match any existing entity key identifiers, hence the None result causing the error you see.
Since the info you have available is the value of an entity's property (the email value) you probably want to perform a query, something along these lines:
results = User.query(User.email == message[0]).fetch(limit=1)
if results:
user = results[0]
So I figured out what was wrong. So there seems to be an issue with the way Google Cloud SDK is set up on my computer. When running the same code on the google servers rather than on my network everything seems to work properly.
I'm learning how to implement user login in GAE following the instruction in http://gosurob.com/post/20024043690/gaewebapp2accounts.
Below is a portion of the code that creates a user aware handler that my other handlers are supposed to inherit. This allows me to simply return user info by self.user. Now my question is how do I retrieve the user info in a ndb class which obviously inherits ndb.Model rather than BaseHandler. Please advise. Thanks!
class BaseHandler(webapp2.RequestHandler):
def dispatch(self):
# Get a session store for this request.
self.session_store = sessions.get_store(request=self.request)
try:
# Dispatch the request.
webapp2.RequestHandler.dispatch(self)
#super(BaseHandler,self).dispatch()
finally:
# Save all sessions.
self.session_store.save_sessions(self.response)
#webapp2.cached_property
def auth(self):
return auth.get_auth(request=self.request)
#webapp2.cached_property
def user(self):
user = self.auth.get_user_by_session()
return user
#webapp2.cached_property
def user_model(self):
user_model, timestamp = self.auth.store.user_model.get_by_auth_token(
self.user['user_id'],
self.user['token']) if self.user else (None, None)
return user_model
class Global_Var(ndb.Model): #<<< This is the ndb class from which I want to use the user info.
current_user = ndb.StringProperty()
#staticmethod
def get_id():
return user['email'] #<<< This, of course, errors out since user is not defined in this class
I'm trying to implement a decorator that authenticates the user's token before granting access to a function. My current implementation is kind of wonky in that I need to do two queries since I can't get locals in the decorator. Is there a better way to do this?
def require_auth(func):
print 'require_auth'
#wraps(func)
def inner():
if 'token' in request.json:
token = request.json['token']
session = Session()
for instance in session.query(SQLTypes.User).filter(SQLTypes.User.token==token):
auth_user = instance.username
try:
auth_user
print 'authenticated!'
except NameError:
abort(401)
else:
abort(401)
return func()
return inner
#app.route('/st/projects', methods=['POST'])
#require_auth
def post_project():
session = Session()
for instance in session.query(SQLTypes.User).filter(SQLTypes.User.token==request.json['token']):
auth_user = instance.username
# do something with auth_user
session.close()
You can store your authenticated user in flask.g:
from flask import g
# ...
def require_auth(func):
# ...
for instance in session.query(SQLTypes.User).filter(SQLTypes.User.token==token):
g.auth_user = instance.username
try:
g.auth_user
print 'authenticated!'
except AttributeError:
abort(401)
# ...
Then in your view function you can access the user as g.auth_user.