MyIndexView error in theme example does not work in Flask-AppBuilder - flask-appbuilder

I implemented steps 1, 2 and 3 from the "Changing the index" section of this page https://flask-appbuilder.readthedocs.io/en/latest/customizing.html?highlight=theme.
I get the following error:
\app__init__.py", line 4, in
from app.index import MyIndexView
ImportError: cannot import name 'MyIndexView'
I have made these changes to a barebone Flask-AppBuilder app.
The code is exactly as is shown on the site.
I expect the example to work as described. But I receive the message I posted above when I run it.

Your index.py should look like this(base version).
# Import flask functions for redirecting and getting user status
from flask import g, url_for, redirect
# Import IndexView class to overwrite files/redirects and expose to expose custom index view
from flask_appbuilder import IndexView, expose
# File to display custom made different views based off if user is signed
class MyIndexView(IndexView):
# Checking user and redirecting for user when user goes to index view
#expose('/')
def index(self):
# Get user status
user = g.user
# Check user
if user.is_anonymous:
# user is not authenticated and gets redirected to New user page
return redirect(url_for('HomeView.new'))
else:
# user is authenticated and has an account redirect to General page
return redirect(url_for('HomeView.general'))
Then in your views.py create a simle view like this
# Views for any home paths
class HomeView(BaseView):
# add route base for views as /home
route_base = "/home"
# Route for new or logged out users
#expose('/new')
def new(self):
return self.render_template('new_user.py')
# Route for signed in users or users who want to just view data
#expose('/general')
def general(self):
return self.render_template('my_index.py')
Also, make sure to add it to your appbuilder object in your init.py
appbuilder = AppBuilder(app, db.session, indexview=MyIndexView)

Related

How can I restrict who has access to the GraphiQL API browser with graphene-django?

Graphene-Django docs note that you can pass graphiql=False when instantiating the GraphQLView if you do not want to use the GraphiQL API browser. However, I'd like to keep the GraphiQL API browser available, and merely restrict who has access to it. How can that be done?
For instance, how would I make it so that only "staff" users (who can access the Admin site) have permission to access the GraphiQL browser?
You can extend the Graphene-Django GraphQLView and override its can_display_graphiql method (defined here) to add this sort of logic.
from graphene_django.views import GraphQLView as BaseGraphQLView
class GraphQLView(BaseGraphQLView):
#classmethod
def can_display_graphiql(cls, request, data):
# Only allow staff users to access the GraphiQL interface
if not request.user or not request.user.is_staff:
return False
return super().can_display_graphiql(request, data)
Then in your urls.py file, use your new GraphQLView instead of the default one:
# import the GraphQLView defined above
urlpatterns = [
# ...
path("graphql", GraphQLView.as_view(graphiql=True)),
]

How to make a controller on Odoo for custom value?

I need to make a custom controller on Odoo for getting information from the particular task. And I can able to produce the result also. But now I'm facing an issue.
The client needs to retrieve the information with a particular field.
For example,
The client needs to retrieve the information with the tracking number and the data must be JSON format also. If the tracking number is 15556456356, the url should be www.customurl.com/dataset/15556456356
The route of that URL should be #http.route('/dataset/<string:tracking_number>', type='http or json', auth="user or public"), basically the method should be like this:
import json
from odoo import http
from odoo.http import Response, request
class tracking(http.Controller):
# if user must be authenticated use auth="user"
#http.route('/dataset/<string:tracking_number>', type='http', auth="public")
def tracking(self, tracking_number): # use the same variable name
result = # compute the result with the given tracking_number and the result should be a dict to pass it json.dumps
return Response(json.dumps(result), content_type='application/json;charset=utf-8',status=200)
This method accept http request and return a json response, if the client is sending a json requests you should change type='json'. don't forget to import the file in the __init___.py.
Lets take an example let say that I want to return some information about a sale.order by a giving ID in the URL:
import json
from odoo import http
from odoo.http import Response, request
class Tracking(http.Controller):
#http.route('/dataset/<int:sale_id>', type='http', auth="public")
def tracking(self, sale_id):
# get the information using the SUPER USER
result = request.env['sale.order'].sudo().browse([sale_id]).read(['name', 'date_order'])
return Response(json.dumps(result), content_type='application/json;charset=utf-8',status=200)
So when I enter this URL using my Browser: http://localhost:8069/dataset/1:

Users granted entry through flask_login

I have a problem with my website which is built using python, flask, gunicorn + supervisorctl, nginx stack.
The problem is: if I am logged on as a user (say admin for e.g.) after restarting my website through "sudo supervisorctl reload' after making some updates to it, any user who attempts to login afterwards becomes logged in as admin even if they enter a random username and password combination. Obviously this is very alarming.
I'm currently using the flask_login plugin to handle the login but I suspect is something to do with flask sessions and how it interacts.
My login code is below
from flask import render_template, flash, redirect, url_for, request, current_app, session
from flask_login import current_user, login_user, logout_user, login_required
#bp.route('/login', methods = ['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('main.user'))
form=LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username = form.username.data).first()
if user is None or not user.check_password(form.password.data):
return redirect(url_for('auth.login'))
login_user(user, remember=form.remember_me.data)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('main.user')
return redirect(next_page)
return render_template('auth/login.html', title=_('登录'), form=form)
I also use flask session to identify the current language and mange translations
in main routing:
#bp.before_app_request ####Michael: becareful of these
def before_request():
if current_user.is_authenticated:
current_user.last_seen = datetime.utcnow()
db.session.commit()
#bp.context_processor
def inject_conf_var():
return dict(CURRENT_LANGUAGE=session.get('language',
request.accept_languages.best_match(current_app.config['LANGUAGES'])))
and in my init
#babel.localeselector
def get_locale():
# if the user has set up the language manually it will be stored in the session,
# so we use the locale from the user settings
try:
language = session['language']
print(session['language'])
except KeyError:
language = None
if language is not None:
return language
return
request.accept_languages.best_match(current_app.config['LANGUAGES'])
I'm not really sure where to start identifying what the problem is, its a bit beyond me at the moment. Closest thing i saw was this:
Users appear to be logged in as another user
but the same thing seems to happen across computers in my case so not really a VPN issue, I'm not sure if the same solution would work.
Grateful for any help!

Django-Rest-Framework: How to Document GET-less Endpoint?

My co-worker implemented an API that only allows GET requests with an ID parameter (so I can GET /foo/5 but can't GET /foo/). If I try to access the API's endpoint without providing an ID parameter, it (correctly) throws an unimplemented exception.
I want to fix this endpoint to show its documentation when viewed, without an ID, over the web. However, I still want it to throw an exception when that endpoint is accessed programatically.
As I remember it, django-rest-framework is capable of distinguishing those two cases (via request headers), but I'm not sure how to define the endpoint such that it returns either documentation HTML or an exception as appropriate.
Can anyone help provide the pattern for this?
Based on the description, I would guess that the endpoint is a function based view, which is registered on a route where it listens for get requests WITH parameters. I would suggest to register another route where you will listen for get requests without parameters...
from rest_framework.decorators import api_view
from rest_framework import status
#api_view(['GET'])
def existing_get_item_api(request, item_id, *args, **kwargs):
# query and return the item here ...
pass
#api_view(['GET'])
def get_help(request, *args, **kwargs):
# compose the help
return Response(data=help, status = status.HTTP_200_OK)
# somewhere in urls.py
urlpatterns = [
url(r'api/items/(?P<item_id>[0-9]+)/', existing_get_item_api),
url(r'api/items/', get_help),
]
Let me know how is this working out for you.
We can user modelviewsets and routers for this implementation
viewsets.py
class AccountViewSet(viewsets.ModelViewSet):
"""
A simple ViewSet for viewing and editing accounts.
"""
http_method_names = ['GET']
queryset = Account.objects.all()
serializer_class = AccountSerializer
routers.py
from rest_framework import routers
router = routers.SimpleRouter()
router.register(r'accounts', AccountViewSet)

Google Analytics Management API - Insert method - Insufficient permissions HTTP 403

I am trying to add users to my Google Analytics account through the API but the code yields this error:
googleapiclient.errors.HttpError: https://www.googleapis.com/analytics/v3/management/accounts/**accountID**/entityUserLinks?alt=json returned "Insufficient Permission">
I have Admin rights to this account - MANAGE USERS. I can add or delete users through the Google Analytics Interface but not through the API. I have also added the service account email to GA as a user. Scope is set to analytics.manage.users
This is the code snippet I am using in my add_user function which has the same code as that provided in the API documentation.
def add_user(service):
try:
service.management().accountUserLinks().insert(
accountId='XXXXX',
body={
'permissions': {
'local': [
'EDIT',
]
},
'userRef': {
'email': 'ABC.DEF#gmail.com'
}
}
).execute()
except TypeError, error:
# Handle errors in constructing a query.
print 'There was an error in constructing your query : %s' % error
return None
Any help will be appreciated. Thank you!!
The problem was I using a service account when I should have been using an installed application. I did not need a service account since I had access using my own credentials.That did the trick for me!
Also remember that you have to specify the scope you would like to use, this example here (using the slightly altered example by Google) defines by default two scopes which would NOT allow to insert users (as they both give read only permissions) and would result in "Error 403 Forbidden" trying so.
The required scope is given in the code below:
from apiclient.discovery import build
from googleapiclient.errors import HttpError
from oauth2client.service_account import ServiceAccountCredentials
def get_service(api_name, api_version, scopes, key_file_location):
"""Get a service that communicates to a Google API.
Args:
api_name: The name of the api to connect to.
api_version: The api version to connect to.
scopes: A list auth scopes to authorize for the application.
key_file_location: The path to a valid service account JSON key file.
Returns:
A service that is connected to the specified API.
"""
credentials = ServiceAccountCredentials.from_json_keyfile_name(
key_file_location, scopes=scopes)
# Build the service object.
service = build(api_name, api_version, credentials=credentials)
return service
def get_first_profile_id(service):
# Use the Analytics service object to get the first profile id.
# Get a list of all Google Analytics accounts for this user
accounts = service.management().accounts().list().execute()
if accounts.get('items'):
# Get the first Google Analytics account.
account = accounts.get('items')[0].get('id')
# Do something, e.g. get account users & insert new ones
# ...
def main():
# Define the auth scopes to request.
# Add here
# https://www.googleapis.com/auth/analytics.manage.users
# to be able to insert users as well:
scopes = [
'https://www.googleapis.com/auth/analytics.readonly',
'https://www.googleapis.com/auth/analytics.manage.users.readonly',
]
key_file_location = 'my_key_file.json'
# Authenticate and construct service.
service = get_service(
api_name='analytics',
api_version='v3',
scopes=scopes,
key_file_location=key_file_location)
profile_id = get_first_profile_id(service)
print_results(get_results(service, profile_id))
if __name__ == '__main__':
main()
Regards,
HerrB92