new request show up when I do nothing with request monitor - mongodb

I run the codes from the book and successfully deploy it in my testing "deerdog.me" website as a portal.
There are 3 modules to work: registration, table create and requests monitor.
the 1st user registration module is good.
but when get in with the new registered id/pwd into left-top sign-in form. (under "home" hint, to click for popup)
you see the 2nd table_creating module seems good. create on table by each random number you input.
But the bug is here, here you should not touch with the 3rd module--request, but once you click the "dashboard" in the upper navigation bar.
In new page, weirdly you can see a new request be stealthy added. (theoretically ,the request row can only added by "add-request" function,but not now "get-request" function.
The biggest hint I found is that I only put the "add-request" under the route of #app.route("/newrequest/<tid>") ,but even the route #app.route("/account/createtable"... ,which only has "get-request" function ,can create request in mongodb's db.requests.().
Why does this happen, pls help me check and fix. Thank a lot.
Manipulation logic of 2nd module (creating table and display with the same "/account" route page ,
activate action == you input a random num(2,5 or 66,109) in blank and click "create button" ,then you will see the rows(include a shor url) in same "/account" page.
Manipulation logic of 3rd module (create requests then display in '/dashboard' route page.) should only be activated in such scenario (user copy the short URL in /account route page's table row, then ctrl+ p the short URl to a new browse address ,then under this new "#app.route("/newrequest/") ,a request in mongodb start to legally create" ,now user can jump the manipulation logic of 3rd module. directly create request record without initiating "#app.route("/newrequest/" ,Why does this happen?
#dbhelper.py as below
import pymongo
from bson.objectid import ObjectId
DATABASE = "waitercaller"
class DBHelper:
def __init__(self):
client = pymongo.MongoClient()
self.db = client[DATABASE]
def add_table(self, number, owner):
new_id = self.db.tables.insert({"number": number, "owner": owner})
return new_id
def update_table(self, _id, url):
self.db.tables.update({"_id": _id}, {"$set": {"url": url}})
def get_tables(self, owner_id):
return list(self.db.tables.find({"owner": owner_id}))
def get_table(self, table_id):
return self.db.tables.find_one({"_id": ObjectId(table_id)})
def delete_table(self, table_id):
self.db.tables.remove({"_id": ObjectId(table_id)})
def add_request(self, table_id, time):
table = self.get_table(table_id)
try:
self.db.requests.insert({"owner": table['owner'], "table_number": table[
'number'], "table_id": table_id, "time": time})
return True
except pymongo.errors.DuplicateKeyError:
return False
def get_requests(self, owner_id):
return list(self.db.requests.find({"owner": owner_id}))
def delete_request(self, request_id):
self.db.requests.remove({"_id": ObjectId(request_id)})
main APP code, called waitercaller.py
waitercaller.py
...
#app.route("/")
def home():
#return "Under construction"
#return render_template("home.html")
#registrationform = RegistrationForm()
return render_template("home.html", loginform=LoginForm(), registrationform=RegistrationForm())
#app.route("/dashboard")
#login_required
def dashboard():
now = datetime.datetime.now()
requests = DB.get_requests(current_user.get_id())
for req in requests:
deltaseconds = (now - req['time']).seconds
req['wait_minutes'] = "{}.{}".format((deltaseconds/60), str(deltaseconds % 60).zfill(2))
return render_template("dashboard.html", resolvesubmitform=ResolveForm(),requests=requests)
#app.route("/dashboard/resolve")
#login_required
def dashboard_resolve():
form = ResolveForm(request.form)
request_id = request.args.get("request_id")
#if form.validate():
DB.delete_request(request_id)
return redirect(url_for('dashboard'))
#return render_template("dashboard.html", resolvesubmitform=ResolveForm(),requests=DB.get_requests(request_id))
#app.route("/account")
#login_required
def account():
tables = DB.get_tables(current_user.get_id())
return render_template("account.html", createtableform=CreateTableForm(), tables=tables)
#app.route("/account/createtable", methods=["POST"])
#login_required
def account_createtable():
form = CreateTableForm(request.form)
if form.validate():
tableid = DB.add_table(form.tablenumber.data, current_user.get_id())
new_url = BH.shorten_url(config.base_url + "newrequest/" + str(tableid))
DB.update_table(tableid, new_url)
return redirect(url_for('account'))
return render_template("account.html", createtableform=form, tables=DB.get_tables(current_user.get_id()))
#app.route("/account/deletetable")
#login_required
def account_deletetable():
tableid = request.args.get("tableid")
DB.delete_table(tableid)
return redirect(url_for('account'))
#app.route("/newrequest/<tid>")
def new_request(tid):
DB.add_request(tid, datetime.datetime.now())
return "Your request has been logged and a waiter will be with you shortly"
if __name__ == '__main__':
app.run(port=5000, debug=True)

Related

Best tools for creating a REST API with static data [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 3 years ago.
Improve this question
I need some Tips for building a REST API with about 35000 static (non-changing) JSON data.
It's my first time building a REST API seriously, so I need some design decision advice.
First, I was planning to use Flask to build the API since I am familiar with it and MongoDB to store the data. But I've heard that MongoDB is not a good choice for data that do not change.
What I would like to know are:
Which DB is suitable for this kind of data?
Is Flask a good choice if I am expecting many users using the API at the same time?
What are the brief steps for doing this? What I have in my mind right now is something like below:
Steps:
1) Upload my data to DB
2) Create a REST API that helps the user fetch the data
3) Upload the REST API to some server
4) Test with Postman to see if it works
Is my overall thought correct?
Any advice would be great. Thanks in advance.
If you are unsure about what DB to use I would just go with PostgreSQL. It's scalable so if you ever need to build on your dataset it will work just fine. In terms of performance it just depends on how many requests it gets, but I bet it could handle whatever you throw at it.
Regarding the API, if you are set with Flask then I recommend the package Flask-Restful. Outline your db using an ORM in a file called models.py. In a folder called resources, make files that serve as your API resources. Example would be blogposts.py, which would have a get request for all or a single post, post, put, and delete for single posts. Here is something I have for a really lightweight blog. Using peewee as an ORM and another package called Flask-HTTPAuth for authentication.
# blogposts.py
import json
from flask import jsonify, Blueprint, abort, make_response
from flask_restful import (Resource, Api, reqparse, inputs, fields,
url_for, marshal, marshal_with)
from auth import auth
import models
blogpost_fields = {
'id': fields.Integer,
'title': fields.String,
'content': fields.String,
'created': fields.DateTime
}
def blogpost_or_404(id):
try:
blogpost = models.BlogPost.get(models.BlogPost.id==id)
except models.BlogPost.DoesNotExist:
abort(404)
else:
return blogpost
class BlogPostList(Resource):
def __init__(self):
self.reqparse = reqparse.RequestParser()
self.reqparse.add_argument(
'title',
required=True,
help='No title provided',
location=['form', 'json']
)
self.reqparse.add_argument(
'content',
required=False,
nullable=True,
location=['form', 'json'],
default=''
)
super().__init__()
def get(self):
blogpost = [marshal(blogpost, blogpost_fields)
for blogpost in models.BlogPost.select()]
return {'BlogPosts': blogpost}
#marshal_with(blogpost_fields)
#auth.login_required
def post(self):
args = self.reqparse.parse_args()
blogpost = models.BlogPost.create(**args)
return (blogpost, 201, {
'Location': url_for('resources.blogposts.blogpost', id=blogpost.id)
})
class BlogPost(Resource):
def __init__(self):
self.reqparse = reqparse.RequestParser()
self.reqparse.add_argument(
'title',
required=False,
help='No title provided',
location=['form', 'json']
)
self.reqparse.add_argument(
'content',
required=False,
nullable=True,
location=['form', 'json'],
default=''
)
super().__init__()
#marshal_with(blogpost_fields)
def get(self, id):
return (blogpost_or_404(id))
#marshal_with(blogpost_fields)
#auth.login_required
def put(self, id):
args = self.reqparse.parse_args()
try:
blogpost = models.BlogPost.select().where(
models.BlogPost.id==id).get()
except models.BlogPost.DoesNotExist:
return make_response(json.dumps(
{'error': 'That blogpost does not exist or is not editable'}
), 403)
else:
query = blogpost.update(**args).where(models.BlogPost.id==id)
query.execute()
blogpost = (blogpost_or_404(id))
return (blogpost, 200, {
'Location': url_for('resources.blogposts.blogpost', id=id)
})
#auth.login_required
def delete(self, id):
try:
blogpost = models.BlogPost.select().where(
models.BlogPost.id==id).get()
except models.BlogPost.DoesNotExist:
return make_response(json.dumps(
{'error': 'That blogpost does not exist or is not editable'}
), 403)
else:
query = blogpost.delete().where(models.BlogPost.id==id)
query.execute()
return '', 204, {'Location': url_for('resources.blogposts.blogposts')}
blogposts_api = Blueprint('resources.blogposts', __name__)
api = Api(blogposts_api)
api.add_resource(
BlogPostList,
'/blogposts',
endpoint='blogposts'
)
api.add_resource(
BlogPost,
'/blogposts/<int:id>',
endpoint='blogpost'
)
Resource classes have methods with the http method name, this is what sets which methods are allowed. For instance, if I tried to delete to /blogposts without an ID, it would respond with method not allowed. Delete is only defined for a single post. Marshaling determines what information is in the response, you define it with blogpost_fields at the top. In the init of each class, we define the Request Parser which is what determines the information the API needs. In this example we only need a title and the post content. In a users resource you would add in things like email, username, password, verify password, admin status etc.
# models.py
import datetime
import jwt
from argon2 import PasswordHasher
from peewee import *
import config
DATABASE = PostgresqlDatabase('blogdb', user=config.DB['USER'], password=config.DB['PW'], host=config.DB['HOST'])
HASHER = PasswordHasher()
class User(Model):
username = CharField(unique=True)
email = CharField(unique=True)
password = CharField()
class Meta:
database = DATABASE
#classmethod
def create_user(cls, username, email, password, **kwargs):
email = email.lower()
try:
cls.select().where(
(cls.email==email)|(cls.username**username)
).get()
except cls.DoesNotExist:
user = cls(username=username, email=email)
user.password = user.set_password(password)
user.save()
return user
else:
raise Exception("User with that email or username already exists")
#staticmethod
def verify_auth_token(token):
try:
payload = jwt.decode(token, config.SECRET_KEY)
return payload['sub']
except jwt.ExpiredSignatureError:
return 'Signature expired. Please log in again.'
except jwt.InvalidTokenError:
return 'Invalid token. Please log in again.'
#staticmethod
def set_password(password):
return HASHER.hash(password)
def verify_password(self, password):
return HASHER.verify(self.password, password)
def generate_auth_token(self, id):
try:
payload = {
'exp': datetime.datetime.utcnow() + datetime.timedelta(days=0, seconds=5),
'iat': datetime.datetime.utcnow(),
'sub': id
}
return jwt.encode(
payload,
config.SECRET_KEY,
algorithm='HS256'
)
except Exception as e:
return e
class BlogPost(Model):
title = CharField(default='', unique=True)
content = TextField(default='')
created = DateTimeField(default=datetime.datetime.now)
class Meta:
database = DATABASE
def initialize():
DATABASE.connect()
DATABASE.create_tables([User, BlogPost], safe=True)
DATABASE.close()
# auth.py
from flask import g
from flask_httpauth import HTTPTokenAuth
import models
auth = HTTPTokenAuth(scheme='Bearer')
#auth.verify_token
def verify_token(token):
user = models.User.verify_auth_token(token)
if user is not None:
g.user = user
return True
return False
Models is pretty self explanatory if you've ever worked with an ORM like SQLAlchemy. I would recommend that package since your dataset is far far far larger than the one for this example. HTTPAuth allows you to decorate your API resource methods with a required authentication method. In my example, logging in will generate a JWT which needs to be sent with each request as a Bearer token.
Once all of that is set up you register your API blueprints in app.py
# app.py
app = Flask(__name__)
app.register_blueprint(users_api, url_prefix='/api/v1')
app.register_blueprint(blogposts_api, url_prefix='/api/v1')
app.register_blueprint(login_api)
That's it!

Getting name of previous test step of type Rest Request in SoapUI groovy script

I'm using groovy script to transfer a certain property from the response of a REST request like this:
def setCookie = testRunner.testCase.testSteps["SubmitCompleteDeviceRegistration"].testRequest.response.responseHeaders["Set-Cookie"]
def global = com.eviware.soapui.SoapUI.globalProperties
re = /(SESSION_AUTHENTICATION_TOKEN=[A-Za-z0-9_-]+;)/
matcher = ( setCookie =~ re )
def cookie = matcher[0][0]
global.setPropertyValue("SESSION_AUTHENTICATION_TOKEN","$cookie")
return cookie
Now what I want to do is make the name of the above teststep, "SubmitCompleteDeviceRegistration", variable, so I can use the transfer for various REST-Requests.
The name of this variable TestStep should equal the name of the previous TestStep of the RestRequest type.
How can I go about defining the TestStep that equals this condition?
I'm trying to use something like
def prevGroovyTestStep =
testRunner.testCase.findPreviousStepOfType(testRunner.testCase.getTestStepByName
("SubmitCompleteDeviceRegistration"),RestRequest)
log.info(prevGroovyTestStep.getName())
But I'm not sure how to implement this.
Any help would be really appreciated!
Getting the previous step name
def previousStepName = context.testCase.testStepList[context.currentStepIndex - 1].name
log.info "Previous step name is : ${previousStepName}"
Getting the previous step name if its type is Rest Request
def testStep = context.testCase.testStepList[context.currentStepIndex - 1]
def previousStepName
if (testStep instanceof com.eviware.soapui.impl.wsdl.teststeps.RestTestRequestStep) {
previousStepName = testStep.name
} else {
log.error "Previous step is not of Rest Request Type"
}
if (previousStepName) {
log.info "Previous step name is : ${previousStepName}"
}
If type does not match in the above case, it will log the error message.
UPDATE - updating as per the latest comments from the author of this question. The below one helps all your need and the above may not needed any more.
Add a custom property for the test case, whose name is STEP_NAME and its value is the test step name to which http header needs to be added. As you commented, the last test step name in this case.
Go the request test step where you are getting the Cookie as response header.
Add an assertion of type Script Assertion and have the below code. Note that, you need to modify the test step name to which you want to add the request header Cookie. Using the place holder for now.
/**Below script should be used as script assertion for first test request step
* Assumes below
* a. test response contains http header called 'Set-Cookie'
* b. other request needs to send http header called 'Cookie'
* In case if there is any change in the two header names you may need to
* change its references below
**/
def responseCookieKey = 'Set-Cookie'
def requestCookieKey = 'Cookie'
def setHttpHeaders(String nextStepName, def headers) {
def nextRequest = context.testCase.testSteps[nextStepName].httpRequest
def existingHeaders = nextRequest.requestHeaders
headers.each {
existingHeaders[it.key] = it.value
}
nextRequest.requestHeaders = existingHeaders
}
if (messageExchange.responseHeaders.containsKey(responseCookieKey)) {
log.info "Found Cookie in the response headers"
def cookiez = messageExchange.responseHeaders[responseCookieKey]
assert null != cookiez, "Response does not contain Cookie"
def headers = [(requestCookieKey) : (cookiez)]
setHttpHeaders(context.testCase.getProvertyValue('STEP_NAME'), headers)
} else {
log.error "Not Found Cookie in the response headers"
}

Pipeline workflow and variables

I have Facebook authentication working on my site, but I need the user to fill a profile form during his authentication. I have used an authentication pipeline to do so but whithout success. The pipeline is being called like it should, but the result is an error.
Let's say I need his mobile number - consider it does not come from Facebook.
Please consider:
models.py
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User)
mobile = models.IntegerField()
settings.py
SOCIAL_AUTH_PIPELINE = (
'social.pipeline.social_auth.social_details',
'social.pipeline.social_auth.social_uid',
'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user',
'social.pipeline.user.get_username',
'social.pipeline.mail.mail_validation',
'social.pipeline.user.create_user',
'social.pipeline.social_auth.associate_user',
'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.user_details',
'myapp.pipeline.fill_profile',
)
pipeline.py
from myapp.models import Profile
from social.pipeline.partial import partial
#partial
def fill_profile(strategy, details, user=None, is_new=False, *args, **kwargs):
try:
if user and user.profile:
return
except:
return redirect('myapp.views.profile')
myapp/views.py
from django.shortcuts import render, redirect
from myapp.models import Perfil
def profile(request):
if request.method == 'POST':
profile = Perfil(user=request.user,mobile=request.POST.get('mobile'))
profile.save()
backend = request.session['partial_pipeline']['backend']
redirect('social:complete', backend=)
return render(request,'profile.html')
The profile.html is just a form with an input text box named 'mobile' and a submit button.
Then I get this error:
Cannot assign "<SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x03C2FB10>>": "Profile.user" must be a "User" instance.
Why can't I access the User instance since the user in auth_user table is already there (I suppose)?
Please, what's wrong with this?
You can't access the user in request.user because it's not logged in yet, the user will be logged in social complete view after the pipeline executed. Usually partial pipeline views will save the form data into the session and then the pipeline will pick it and save it. Also you can set the user id in the session in your pipeline and then pick that value in your view. For example:
#partial
def fill_profile(strategy, user, *args, **kwargs):
...
strategy.session_set('user_id', user.id)
return redirect(...)

how to use facebook api on a group

i created an application to test facebook api using Python, then, in the application, i created its Group, but, the problem that this Group dont know who i'm; it shows me that am the Admin, but when i try to publish something using Tornado, i get the error
GraphAPIError: (#210) User not visible
and this is because it seems that it deletes the cookie, because when am using the group's profile, then i cant see the GraphAPI since it dont know who is authentificated!
here is the code:
class MainHandler(BaseHandler, tornado.auth.FacebookGraphMixin):
#tornado.web.authenticated
#tornado.web.asynchronous
def get(self):
self.facebook_request("/me/home", self.print_callback,access_token=self.current_user["access_token"])
a = self.current_user["access_token"]
self.graph = GraphAPI(a)
def print_callback(self, data):
self.graph.post_wall(self, "heloooooooo")
an sorry, because i dont get well the logic behind users Token, and Groups tokens? here i got a user Token? and because am the admin, i cant post!
EDIT: here are some snapshots i took from the application:
picture 1
picture 2
Update: i tried this:
def print_callback(self, me):
self.graph.post_wall(self, "helooooo", profile_id="267914489995838")
and got the error:
self.graph.post_wall(self, "helooooo", profile_id="267914489995838")
TypeError: post_wall() got multiple values for keyword argument 'profile_id'
and i used what is in the Tornado-Facebook-API
def post_wall(self, message, profile_id='me', body=None, **kwargs):
#XXX move to separate User class?
body = body or {}
body['message'] = message
self._make_request("{0}/feed".format(profile_id), method='POST',
body=body, **kwargs)
update2: here is the full code
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
user_json = self.get_secure_cookie("user")
if not user_json: return None
return tornado.escape.json_decode(user_json)
class MainHandler(BaseHandler, tornado.auth.FacebookGraphMixin):
#tornado.web.authenticated
#tornado.web.asynchronous
def get(self):
self.facebook_request("/me/accounts", self._on_accounts,
access_token=self.current_user["access_token"])
self.a = self.current_user["access_token"]
self.graph = GraphAPI(self.a)
def _on_accounts(self, account):
if account is None:
# Session may have expired
print "on accounts failed"
return
for acc in account["data"]:
if acc["id"] == "267914489995838":
print acc["access_token"]
self.facebook_request("/PAGE_ID/feed",
post_args={"message": "Test"},
access_token=acc["access_token"],
callback=self.async_callback(self._on_page_post))
def _on_page_post(self, post):
if not post:
# Post failed
return
class AuthLoginHandler(BaseHandler, tornado.auth.FacebookGraphMixin):
#tornado.web.asynchronous
def get(self):
my_url = (self.request.protocol + "://" + self.request.host +
"/auth/login?next=" +
tornado.escape.url_escape(self.get_argument("next", "/")))
if self.get_argument("code", False):
self.get_authenticated_user(
redirect_uri=my_url,
client_id=self.settings["facebook_api_key"],
client_secret=self.settings["facebook_secret"],
code=self.get_argument("code"),
callback=self._on_auth)
return
self.authorize_redirect(redirect_uri=my_url,
client_id=self.settings["facebook_api_key"],
extra_params={"scope": "read_stream, publish_stream"})
def _on_auth(self, user):
if not user:
raise tornado.web.HTTPError(500, "Facebook auth failed")
self.set_secure_cookie("user", tornado.escape.json_encode(user))
self.redirect(self.get_argument("next", "/"))
class AuthLogoutHandler(BaseHandler, tornado.auth.FacebookGraphMixin):
def get(self):
self.clear_cookie("user")
self.redirect(self.get_argument("next", "/"))
class PostModule(tornado.web.UIModule):
def render(self, post):
return self.render_string("modules/post.html", post=post)
Some clarifications:
A #200 error is a permission error. In this case, you don't have permissions to post somewhere.
There are two main types of tokens: user tokens and page tokens
You can add a group to an application's roles http://developers.facebook.com/blog/post/531/
As far as I know, there is no way to add an application to a group
So I think based on the Facebook id given you either want to do two things
Post to an application's timeline
Post to a group via an application
Posting to an application's timeline
This requires the application page access token, which you get from /me/accounts using the manage_pages and publish_stream permissions
self.facebook_request("/me/accounts", self._on_accounts,
access_token=self.current_user["access_token"])
def _on_accounts(self, account):
if account is None:
# Session may have expired
print "on accounts failed"
return
for acc in account["data"]:
if acc["id"] == "PAGE_ID":
print acc["access_token"]
self.facebook_request("/PAGE_ID/feed",
post_args={"message": "Test"},
access_token=acc["access_token"],
callback=self.async_callback(self._on_page_post))
def _on_page_post(self, post):
if not post:
# Post failed
return
See http://developers.facebook.com/docs/reference/api/application/ for more info
A full example can be seen at https://gist.github.com/3867203 (Which doesn't handle duplicate posting)

using flask-login with postgresql

I'm working on a flask app that needs authentication. I've hooked up flask-login but it doesn't seem very graceful.
First flask-login needs to make sure the user exists:
#login_manager.user_loader
def load_user(id):
return User.query.get(id)
But you also need to use 'login_user' to create the user object
# Some code above
user = User.query.filter_by(email = form.email.data, password = form.password.data).first()
user.login_status = 1
db.session.commit()
login_user(objects.SignedInUser(user.id, user.email, user.login_status == LoginStatus.Active))
# Some code below
In the code above 'User' is a model for postgres and SignedInUser is just an object to be used for flask-login.
Does anyone have an example of flask-login used with postgres?
It looks like you might be misunderstanding what Flask-Login handles. It's there to keep track of everything about the user's session after you tell it authentication was successful (by calling login_user.) The user_loader callback only tells it how to reload the object for a user that has already been authenticated, such as when someone reconnects to a "remember me" session. The docs are not especially clear on that.
There should be no need to keep a flag in the database for the user's login status. Also, the code you included will raise an AttributeError if the credentials are incorrect (user = None).
Here's an example from a Flask-SQLAlchemy application. It uses an external authentication source and a wrapper for the SQLAlchemy User object, but the process is basically the same.
user_loader callback:
#login_manager.user_loader
def load_user(user_id):
user = User.query.get(user_id)
if user:
return DbUser(user)
else:
return None
User class (wrapper for SQLAlchemy object):
# User class
class DbUser(object):
"""Wraps User object for Flask-Login"""
def __init__(self, user):
self._user = user
def get_id(self):
return unicode(self._user.id)
def is_active(self):
return self._user.enabled
def is_anonymous(self):
return False
def is_authenticated(self):
return True
Login handler:
#app.route('/login', methods=['GET', 'POST'])
def login():
error = None
next = request.args.get('next')
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if authenticate(app.config['AUTH_SERVER'], username, password):
user = User.query.filter_by(username=username).first()
if user:
if login_user(DbUser(user)):
# do stuff
flash("You have logged in")
return redirect(next or url_for('index', error=error))
error = "Login failed"
return render_template('login.html', login=True, next=next, error=error)
Note that login fails if:
external auth fails
user query returns None (user does not exist)
login_user returns False (user.is_active() == False)
Logout
#app.route('/logout')
#login_required
def logout():
logout_user()
flash('You have logged out')
return(redirect(url_for('login')))