Hacker News new | ask | show | jobs
by glimcat 4346 days ago
Set up a lightweight web interface using Flask. When people log in and submit a job, it gets added to an RQ task queue for asynchronous execution. If they need anything back at the end, job status, results, whatever - that goes in a database. Congratulations, you've just made a simple web app.

If people are actually getting use out of it, go back and pretty it up a bit with a Bootstrap template or whatever, it doesn't take much here to have meaningful effects on user perception. It mostly just has to be nice enough that it looks reasonably professional when people show it off in meetings, which is NOT a cutting-edge design problem.

Add more pages for more scripts as needed, and tag users with permissions so you know which scripts should be exposed to which users.

If merited, go back and add fancy features like generating PDF reports and emailing them to the head of department every week.

2 comments

This is interesting. What if users have to put in their own inputs for the scripts? For instance, specify start-date and end-date for a sql query, or upload a spreadsheet to do the python analysis on?
You'd use Flask-WTF for forms.

https://flask-wtf.readthedocs.org/en/latest/

It can also handle file uploads.

https://flask-wtf.readthedocs.org/en/latest/form.html

You'd need to define a model which describes the form fields, handle it in your view, and add it to your page template.

forms.py

    from flask_wtf import Form
    from wtforms import TextField, PasswordField
    from wtforms.validators import DataRequired
    
    class LoginForm(Form):
        email = TextField('Email', validators=[DataRequired()])
        password = PasswordField('Password', validators=[DataRequired()])
views.py

    from forms import LoginForm
    
    @app.route('/login', methods=('GET', 'POST'))
    def login():
        form = LoginForm()
        if form.validate_on_submit():
            email = form.data.get('email', None)
            password = form.data.get('password', None)
            do_login_stuff(email, password)
        else:
            return render_template('login_page.html', form=form)
login_page.html

    {% extends "base.html" %}

    {% block content %}
    <h3>Log in:</h3>
    <form method="POST" action="{{ url_for('login') }}">
      {{ form.hidden_tag() }}
      {{ form.email.label }} {{ form.email }}
      {{ form.password.label }} {{ form.password }}
      <input type="submit" value="Log in">
    </form>
    {% endblock %}
Yeah that's the tough part. I think I'd have to set up a model for each script I add to flask.
Here's an option for organizing a "bunch of scripts" app that might be less intimidating to maintain.

foo_script.py

    from flask import render_template
    from flask_wtf import Form
    from wtforms import TextField
    from wtforms.validators import DataRequired
    
    class ScriptForm(Form):
        param1 = TextField('Param1', validators=[DataRequired()])
        param2 = TextField('Param2', validators=[DataRequired()])
        param3 = TextField('Param3', validators=[DataRequired()])

    @app.route('/foo-script', methods=('GET', 'POST'))
    def foo_script():
        form = ScriptForm()
        if form.validate_on_submit():
            do_stuff(form.data)
        else:
            return render_template('foo_script.html', form=form)
    
    def do_stuff(data):
        for key in data:
            print '%s: %s' % (key, data[key])

foo_script.html

    {% extends "base.html" %}

    {% block content %}
    <h3>Run foo script:</h3>
    <form method="POST" action="{{ url_for('foo_script') }}">
      {{ form.hidden_tag() }}
      {{ form.param1.label }} {{ form.param1 }}
      {{ form.param2.label }} {{ form.param2 }}
      {{ form.param3.label }} {{ form.param3 }}
      <input type="submit" value="Run foo script">
    </form>
    {% endblock %}

base.html

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <title>FooCorp Script Service</title>
      </head>
      <body>
        {% block content %}{% endblock %}
      </body>
    </html>

app.py

    from flask import Flask
    
    app = Flask(__name__)
    app.config.from_pyfile('config.py')
    
    import foo_script, bar_script, baz_script

config.py

    # You need this for CSRF protection & cookie signing
    SECRET_KEY = randomly_generated_secret_key

You should also look into Flask's blueprints at some point if it keeps growing. But it's not really essential, just another tool to help you keep projects organized. Flask is mostly "do whatever makes sense in your specific case" rather than imposing many global constraints on structure.

Also, I'd use gunicorn if you're deploying your own server. It's a bit less intimidating to get set up than uWSGI, and the main tradeoff is that it doesn't support quite as many thousands of users (i.e. not relevant).

Where would you actually host the webapp? Would you set up a new server on your intranet and share a link to it?
That depends on your resources & priorities.

Internal if you have the IT resources & infrastructure for that to be reasonably painless. VPS if you need to access it from multiple public locations and don't want to expose an internal server, or if "internal server" isn't a thing where you work. Heroku if you don't know how to admin Linux or don't want to spend the time worrying about it.