Code Monkey home page Code Monkey logo

canonicalwebteam.flask-base's Introduction

Canonical Webteam Flask-Base

Flask extension that applies common configurations to all of webteam's flask apps.

Usage

from canonicalwebteam.flask_base.app import FlaskBase

app = FlaskBase(__name__, "app.name")

Or:

from canonicalwebteam.flask_base.app import FlaskBase

app = FlaskBase(
    __name__,
    "app.name",
    template_404="404.html",
    template_500="500.html",
    favicon_url="/static/favicon.ico",
)

Local development

For local development, it's best to test this module with one of our website projects like ubuntu.com. For more information, follow this guide (internal only).

Features

Redirects and deleted paths

FlaskBase uses yaml-responses to allow easy configuration of redirects and return of deleted responses, by creating redirects.yaml, permanent-redirects.yaml and deleted.yaml in the site root directory.

Error templates

FlaskBase can optionally use templates to generate the 404 and 500 error responses:

app = FlaskBase(
    __name__,
    "app.name",
    template_404="404.html",
    template_500="500.html",
)

This will lead to e.g. http://localhost/non-existent-path returning a 404 status with the contents of templates/404.html.

Redirect /favicon.ico

FlaskBase can optionally provide redirects for the commonly queried paths /favicon.ico, /robots.txt and /humans.txt to sensible locations:

from canonicalwebteam.flask_base.app import FlaskBase

app = FlaskBase(
    __name__,
    "app.name",
    template_404="404.html",
    template_500="500.html",
    favicon_url="/static/favicon.ico",
    robots_url="/static/robots.txt",
    humans_url="/static/humans.txt"
)

This will lead to e.g. http://localhost/favicon.ico returning a 302 redirect to http://localhost/static/favicon.ico.

Jinja2 helpers

You get two jinja2 helpers to use in your templates from flask-base:

  • now is a function that outputs the current date in the passed format - {{ now('%Y') }} -> YYYY
  • versioned_static is a function that fingerprints the passed asset - {{ versioned_static('asset.js') }} -> static/asset?v=asset-hash

robots.txt and humans.txt

If you create a robots.txt or humans.txt in the root of your project, these will be served at /robots.txt and /humans.txt respectively.

Tests

To run the tests execute SECRET_KEY=fake python3 -m unittest discover tests.

canonicalwebteam.flask-base's People

Contributors

albertkol avatar anthonydillon avatar bartaz avatar jkfran avatar jpmartinspt avatar mtruj013 avatar nottrobin avatar petesfrench avatar renovate-bot avatar sowasred2012 avatar tbille avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

canonicalwebteam.flask-base's Issues

All cookies should be set using "secure" flag, if using HTTPS

This is speculative - I haven't done all that much research yet.

Should snapcraft.io be creating its auth cookies with the "secure" flag enabled, to protect against a possible scenario where those cookies might accidentally be send over HTTP? The main case where this is possible would be if people type http://snapcraft.io into the browser - the initial request would contain the cookies sent in clear text.

https://stackoverflow.com/questions/13729749/how-does-cookie-secure-flag-work

Maybe they already have the secure flag? But it's worth checking.

Setting cache control attributes to None doesn't work as expected

Expected behavior: response.cache_control.max_age = None should not raise an exception, and the response should not contain max-age in the Cache-Control header.

I ran into this while investigating upgrading to Flask 2.x.

Prior to Werkzeug 1.0 there is a bug that raises a KeyError when None is assigned to a CacheControl attribute. The flask-base test app sets attributes to None in the /cache/none view, and a KeyError is indeed raised. The corresponding test happens to pass because no Cache-Control headers are set due to the exception in the view, and the status code (500) is not validated.

In running the tests against Flask 2.0.1 and Werkzeug 2.0.1, the same test fails. Since the bug in Werkzeug has been fixed, no KeyError is raised in the /cache/none view, and a 200 code is returned. However, flask-base sets defaults for unset attributes of the CacheControl, and the test fails with:

FAIL: test_cache_override (test_flask_base.TestFlaskBase)
Check each part of the cache-control instruction can be overridden
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/morgan/canonical/code/canonicalwebteam.flask-base/tests/test_flask_base.py", line 104, in test_cache_override
    self.assertIsNone(none_cache)
AssertionError: 'max-age=60, stale-while-revalidate=86400, stale-if-error=300' is not None

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: undefined

Lock versions of dependencies

Occasionally there are issues with latest versions of flask-base dependencies (gevent seems to be the one that causes problems most often).

Recent release 20.5.1 was not installing at all for a while, now it installs but causes pkg_resources.DistributionNotFound: The 'setuptools' distribution was not found and is required by zope.interface when running server (in docker).

We should lock the versions of our dependencies to avoid situations when releasing new versions of them breaks our sites, causes CI fails or prevents us from releasing.

Static files endpoint - solve cache issues

We should add an endpoint to serve static files:

  • Use property flask.static_folder to know the static folder path
  • Do a md5 hash of the file and compare it with the request hash
    • If they don't match return a 404
    • If they match then serve the static file
  • If the request comes without a hash on the URL serve the static file

Key parts of the conversation about this issue on Mattermost:

Fran: The only explanation that I see for this issue is that the HTML is served by a new deployed pod and the request to the static file hit an old pod that is going to disappear soon

Robin: Yeah I think that sounds fairly likely. I wonder if we should write a custom endpoint for static files that will check the md5 on request and 404 if it doesn't match?

Fran: It could be easy to do and to implement if we do it with flask-base adding a before_request and check only for static file requests. To me create a view to serve static files when flask has a functionality to serve static files from a folder seems bad

Robin: So I think it's a neater architecture to create our own endpoint for this custom functionality rather than overloading the standard and well understood basic static behaviour. Since our function is going to have to read the content anyway, to calculate it's md5 hash, it's weird not to then be directly serving that same content isn't it?

Add stale-if-error header

We sometimes get transitory issues with API backends being unavailable, e.g. here.

We should probably set a stale-if-error header by default that is some relatively short time, just to protect users from seeing short-lived issues.

I guess stale-if-error should always be longer than max-age. But how long? 5 minutes?

Create a reliable notification & response system for 5xx errors

Hi,

Currently:

stale-while-revalidate=360

This was added in #17, I think it is too low and if/when there are issues with the K8s cluster hosting the various websites, we'll want the content cache to serve objects out of it's cache rather than some error page. I think something like 2-3 hours should be used here.

Or maybe I'm misunderstanding how stale-while-revalidate works for caches fronting backend (e.g. Nginx in our case).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.