Flask-Admin link back to main site - html

Is there any way to modify the home button url link on the flask-admin admin top panel so that I redirect back to a main site?
I can add a link in a custom.html page eg:
{% extends 'admin/master.html' %}
{% block body %}
Home
{% endblock %}
But this is hidden away inside the custom page. I'd prefer a top-bar link out of admin.

Easiest way is to add a menu link and leave the admin home page alone (you might want to add a dashboard or suchlike in the future):
from flask_admin.menu import MenuLink
# Create admin
admin = Admin(app, name='Admin', url='/')
admin.add_view(ImageView(model=Image, session=db.session, category='Database', name='Images'))
# Add custom link to public website home page
admin.add_link(MenuLink(name='Public Website', category='', url=url_for('main.home')))
Note, url_for needs to be called within a Flask application context. For example, if using the Flask application factory pattern, this would look something like the following:
def create_app(config):
app = App('app')
# setup config
# setup blueprints
# setup Flask-Admin
from app.admin import create_admin
from app.admin.configure import configure_admin
with app.app_context():
admin = create_admin(app=app)
configure_admin(app, admin)
# more stuff
return app
__init__.py in app.admin module
def create_admin(app=None):
return Admin(app, template_mode='bootstrap3')
configure.py in app.admin module
def configure_admin(app, admin):
# setup views
# add link to home page
admin.add_link(MenuLink(name='Public Website', category='', url=url_for('home.HomeView:index')))

You can override get_url method of MenuLink. That way you get around application context problem.
from flask import url_for
from flask_admin import Admin
from flask_admin.menu import MenuLink
class MainIndexLink(MenuLink):
def get_url(self):
return url_for("main.index")
admin = Admin(name="Admin")
admin.add_link(MainIndexLink(name="Main Page"))
def create_app():
app = Flask(__name__)
from app.admin import admin
admin.init_app(app)
return app

If you are having issues with app context error when using app.app_context():
RuntimeError: Unable to build URLs outside an active request without 'SERVER_NAME' configured. Also configure 'APPLICATION_ROOT' and 'PREFERRED_URL_SCHEME' as needed.
You can simply 'test_request_context()' method.
with app.test_request_context():
admin.add_link(MenuLink(name='Name', category='', url=url_for('home.home_route')))
This is documented here

Related

Can we run appium test scripts through flask server on locally connected device

I am trying to run my appium scripts on button click in a html template, but unfortunately I have searched everywhere but still I found no solution.
My html template is inside a templates folder in the flask project directory and I am taking path as an input and want to pass that string to my Appium script and as soon as I click on the Submit button on my template it should launch the test script on my locally connected phone taking the path as a parameter.
Any kind of help will be appreciated.
Regards
I tried adding functions of my test script in the flask route but I have multiple functions in my python script and for every function I would have to create multiple routes. I was expecting to run the python script all at once on the default flask route ('/').
Following is my code for flask_server.py file as per now I am just getting the parameter in it and showing it in the next route but instead I want to pass my appium script here and run it on device on submit.
from flask import Flask
from flask import render_template
from flask import request
from Instagram.instagram_android_automation import
InstagramAndroidAutomation
from flask import Flask, redirect, url_for, request
app = Flask(__name__)
#app.route('/dashboard/<name>')
def dashboard(name):
return 'welcome %s' % name
#app.route('/login',methods = ['POST', 'GET'])
def login():
if request.method == 'POST':
user = request.form['name']
return redirect(url_for('dashboard',name = user))
else:
user = request.args.get('name')
return render_template('login.html')
if __name__ == '__main__':
app.run(debug = True)

How can I embed a server-side Shiny app into a JSP page without exposing the app elsewhere

I have a Shiny app that I want to embed into a page of my Java 8 webserver that is hosted on Amazon AWS. (Note: I say "embed" because most pages in the webserver share a common sidebar & footer - this is applied automatically to most views, such that the .jsp files only have to provide html for the real substance of the page).
The Shiny app listens on 3305 and the webserver hosts to :8080 on localhost ([server ip]/subject/index.html works fine to get webpages via other machines).
Embedding the Shiny app works fine for localhost via a shiny.jsp containing <iframe src="http://localhost:3305">, but when viewed from another machine, the page looks for a shiny server only on that other machine, when it should be looking on the host machine. Leaving off the "http://" results in the Shiny app never getting a request and the page staying blank, and exchanging "localhost" with "127.0.0.1" results in no noticeable changes.
The server uses Spring, JSTL and Apache Tomcat 7.0 .
I cannot simply port forward the Shiny app to make it visible outside the server, because the app displays confidential information. In a .jsp, this is not a concern, as the iframe can be wrapped in a <security:authorize> tag (the website requires login to access any pages in the first place).
The question is, what is the simplest way to embed the Shiny app into a .jsp page such that it remains interactive for the user but is secure (cannot be directly accessed with no authorization from outside the server) and requires no additional logins?
You can expose a proxy API from your webserver to retrieve content of Shiny app. You can then use iframe to display content of shiny app using proxy as src.
A la spring mvc rest service redirect / forward / proxy, a Controller mirrors the Shiny app, so that we retain access control:
import java.net.URI;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;
#Controller
public class ShinyController
{
private static final RestTemplate restTemplate = new RestTemplate();
#RequestMapping(path = "/shiny-proxy/**")
public ResponseEntity<String> mirrorRest(#RequestBody(required = false) String body,
HttpMethod method, HttpServletRequest request) throws URISyntaxException {
String path = StringUtils.removeStart(
request.getRequestURI(), "/project/shiny-proxy");
URI uri = new URI(request.getScheme(), null, "localhost", 3305,
path, request.getQueryString(), null);
HttpHeaders headers = new HttpHeaders();
if (path.endsWith(".css.map")) {
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
}
HttpEntity<String> httpEntity = new HttpEntity<>(body, headers);
return restTemplate.exchange(uri, method, httpEntity, String.class);
}
}
This handles the Shiny page's HTML and all of its resources. In a JSP view,
<iframe src="shiny-proxy/">
Now we just need to handle the ws://[shiny url]/websocket/ request.
In web.xml, prevent the webserver from handling it via:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/project/shiny-proxy/websocket/</url-pattern>
</servlet-mapping>
Then, enable Include conf/extra/httpd-vhosts.conf in /opt/bitnami/apache2/conf/httpd.conf,
and set httpd-vhosts.conf's content to:
<VirtualHost *:80>
RewriteEngine on
RewriteRule /project/shiny-proxy/websocket/(.*) ws://localhost:3305/websocket/$1 [P,L]
</VirtualHost>
so... turned out to be quite simple.

How to change default page of odoo with other webcontroller odoo 9.0

I have created a new webcontroller with specific functionality and I want this webcontroller as a home page of odoo 9.0.
I have tried to put #http.route('/', type='http', auth='public', website=True) in main.py of my custom webcontroller file as a route, but still it redirect to default home page of odoo.
But if I put url as #http.route('/index', type='http', auth='public', website=True), the page is working fine.
So my question is what is best way to replace existing odoo home page with custom controller or module.
# -*- coding: utf-8 -*-
from openerp import http
from openerp.addons.website.controllers.main import Website
class Website(Website):
#http.route(auth='public')
def index(self, data={},**kw):
super(Website, self).index(**kw)
return http.request.render('<your_addon>.<your_template_id>', data)

Django compressor minifying the css but not gziping [duplicate]

I'm running a django 1.4.1 app.
I didn't realize that just including django.contrib.staticfiles into INSTALLED_APPS in your settings is enough to get static files served while settings.DEBUG is True, i.e., you don't have to manually add anything to your urls file.
I also noticed that this bypasses the django middleware. Does anyone know how or why this happens?
I just created a blank new project, my views.py:
from django.http import HttpResponse
def index(request):
html = '<html><body>Logo: <img src="/static/logo.gif"></body></html>'
return HttpResponse(html)
My urls.py:
from django.conf.urls import patterns, include, url
urlpatterns = patterns('',
url(r'^$', 'testapp.views.index', name='home'),
)
My settings.py has specified a directory to look for static files, and it also has this added:
MIDDLEWARE_CLASSES = (
'testapp.middleware.TestMiddleware',
...
)
Using this middleware:
from __future__ import print_function
class TestMiddleware(object):
def process_request(self, request):
print("[REQUEST]", request.path)
And when I make a request, this gets printed out:
[REQUEST] /
[18/Jan/2013 15:30:27] "GET / HTTP/1.1" 200 60
[18/Jan/2013 15:30:27] "GET /static/logo.gif HTTP/1.1" 200 2190
[REQUEST] /favicon.ico
Is it something to do with how the test server starts up?
I just figured this out after posting…
If you're using django-admin.py runserver or python manage.py runserver, then it does some extra magic to add a staticfiles handler that your regular middleware can't touch.
You can disable this by running django-admin.py runserver --nostatic — see the django docs
And when you do --nostatic it will fall back to the urls in your app, such as if you include staticfiles_urls() directly with:
urlpatterns += staticfiles_urlpatterns()
then your middleware will run for those urls (and of course all your others).
Found this issue when trying to modify request.path with middleware.
Discovered urls resolve against request.path_info not request.path

Django passes incorrect query results to template

I am writing a web app that displays user profiles.
The profile includes a display of the user's interest in other users, which can be uni- or bidirectional. I am using django's included User model to handle authentication and authorization.
The problem I have is that under some circumstances the rendered pages present data from queries executed earlier. Specifically, this happens when I am using the app as two different users on the same computer but on different browsers (Chrome and Safari on OS X; using the django development web server). Right after I load a page for user 1, if I reload a page for user 2 I see user 1's query results.
I have confirmed that my queries are correct by printing them to the console. I think the problem may be at the web server, because the pages load the right queries right after a server restart.
Any ideas?
** Edit: as Daniel points out, the problem is that the interest_view function has a dictionary as a default parameter.**
Relevant code snippets:
models.py
class Profile(UserenaBaseProfile):
user = models.OneToOneField(User, unique=True)
class Interest(models.Model):
user = models.ForeignKey(User, related_name=u'interests')
interest = models.ForeignKey(User)
views.py
from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
def interest_view(request, username, extra_context={}):
user = get_object_or_404(User, username__iexact=username)
profile = user.get_profile()
if not profile.can_view_profile(request.user):
return HttpResponseForbidden("You can't view this page.")
interests = Interest.objects.filter(user=user)
if len(interests) > 0:
extra_context['active_interests'] = interests
return render_to_response('interest_detail.html',
extra_context,
context_instance=RequestContext(request)
)
interest_detail.html
{% if active_interests %}
{% for interest in active_interests %}
<li>
{{ interest.interest.first_name }} {{ interest.interest.last_name }}
</li>
{% endfor %}
{% endif %}
You haven't shown any code, so this is impossible to debug. But the issue is almost certainly that you are defining queries at module level, where they persist for the lifetime of the process (which is many requests).
Edit:
Well, I was almost right - it is an issue with things being defined at module level, although in your case it's the Python default argument gotcha. See the effbot for a great explanation, although the default SO question on this is one: Least astonishment in Python.