Changeset - 7127755315ba
[Not reviewed]
default
0 2 6
Dennis Fink - 10 years ago 2015-07-05 19:09:14

Separated stuff
8 files changed with 259 insertions and 193 deletions:
0 comments (0 inline, 0 general)
run.py
Show inline comments
 
from spaceapi import app
 
from spaceapi import create_app
 

	
 
app.run(debug=True)
 
create_app().run(debug=True)
spaceapi/__init__.py
Show inline comments
 
import json
 
import os
 
import os.path
 
import calendar
 
import base64
 
import copy
 

	
 
from time import time
 
from ast import literal_eval
 

	
 
from flask import Flask, jsonify, request, render_template
 
from flask.ext.httpauth import HTTPDigestAuth
 

	
 
import jsonschema
 

	
 
from pkg_resources import resource_filename
 

	
 
ALLOWED_STATE_KEYS = {
 
    'open': bool,
 
    'lastchange': int,
 
    'trigger_person': str,
 
    'message': str
 
}
 

	
 
ALLOWED_SENSORS_KEYS = json.load(
 
    open(resource_filename('spaceapi', 'schema/sensors.json'),
 
         encoding='utf-8')
 
)
 
from flask import Flask
 

	
 
config_file = os.path.abspath('config.json')
 
default_json_file = os.path.abspath('default.json')
 
last_state_file = os.path.abspath('laststate.json')
 

	
 
default_json = {}
 
active_json = {}
 

	
 

	
 
def reload_json():
 
    global default_json
 
    global active_json
 

	
 
    default_json = json.load(open(default_json_file, encoding='utf-8'))
 

	
 
    if os.path.exists(last_state_file):
 
        with open(last_state_file, encoding='utf-8') as f:
 
            active_json = json.load(f)
 

	
 
        if os.path.getmtime(last_state_file) \
 
           < os.path.getmtime(default_json_file):
 
            backup = copy.deepcopy(active_json)
 
            active_json.update(default_json)
 
            active_json['state']['open'] = backup['state']['open']
 
            active_json['state']['lastchange'] = backup['state']['lastchange']
 
    else:
 
        active_json = copy.deepcopy(default_json)
 

	
 
reload_json()
 
def create_app():
 
	app = Flask(__name__)
 

	
 
app = Flask(__name__)
 
auth = HTTPDigestAuth()
 

	
 
_default_secret_key = base64.b64encode(os.urandom(32)).decode('utf-8')
 
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', _default_secret_key)
 

	
 
if not hasattr(app.config, 'from_json'):
 
    def from_json(file, silent=True):
 
        try:
 
            with open(file, encoding='utf-8') as json_file:
 
                obj = json.load(json_file)
 
        except IOError:
 
            if silent:
 
                return False
 
            raise
 
	_default_secret_key = base64.b64encode(os.urandom(32)).decode('utf-8')
 
	app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', _default_secret_key)
 

	
 
        for key in obj:
 
            if key.isupper():
 
                app.config[key] = obj[key]
 

	
 
        return True
 

	
 
    app.config.from_json = from_json
 

	
 
app.config.from_json(config_file, silent=True)
 

	
 

	
 
@auth.get_password
 
def get_pw(username):
 
    if username == app.config.get('HTTP_DIGEST_AUTH_USER'):
 
        return app.config.get('HTTP_DIGEST_AUTH_PASSWORD')
 
    return None
 

	
 
	if not hasattr(app.config, 'from_json'):
 
		def from_json(file, silent=True):
 
			try:
 
				with open(file, encoding='utf-8') as json_file:
 
					obj = json.load(json_file)
 
			except IOError:
 
				if silent:
 
					return False
 
				raise
 

	
 
def request_wants_json():
 
    best = request.accept_mimetypes.best_match(
 
        ['application/json', 'text/html']
 
    )
 
    return best == 'application/json' and \
 
        request.accept_mimetypes[best] > \
 
        request.accept_mimetypes['text/html']
 

	
 

	
 
def save_last_state():
 

	
 
    with open(last_state_file, mode='w', encoding='utf-8') as f:
 
        json.dump(active_json, f, sort_keys=True)
 

	
 

	
 
@app.route('/')
 
def index():
 

	
 
    if request_wants_json():
 
        return jsonify(active_json)
 
    return render_template('index.html', status=active_json)
 

	
 

	
 
@app.route('/status.json')
 
def status_json():
 
    return jsonify(active_json)
 

	
 
			for key in obj:
 
				if key.isupper():
 
					app.config[key] = obj[key]
 

	
 
@app.route('/set/state/<key>/<value>', methods=['POST'])
 
@auth.login_required
 
def set_state(key, value):
 

	
 
    value = literal_eval(value)
 

	
 
    if key in ALLOWED_STATE_KEYS and isinstance(value,
 
                                                ALLOWED_STATE_KEYS[key]):
 
        active_json['state'][key] = value
 
			return True
 

	
 
        if key == 'open':
 
            active_json['state']['lastchange'] = int(time.time())
 
    else:
 
        return 400
 

	
 
    save_last_state()
 

	
 
    return jsonify(active_json)
 

	
 
		app.config.from_json = from_json
 

	
 
def fuzzy_list_find(lst, key, value):
 

	
 
    for i, dic in enumerate(lst):
 
        if dic[key] == value:
 
            return i
 

	
 
    raise ValueError
 

	
 
	app.config.from_json(config_file, silent=True)
 

	
 
@app.route('/set/sensors/<key>', methods=['POST'])
 
@auth.login_required
 
def set_sensors(key):
 

	
 
    if key in ALLOWED_SENSORS_KEYS and key in active_json['sensors']:
 
        data = request.data
 
        try:
 
            data = json.loads(data)
 
            try:
 
                jsonschema.validate(data, ALLOWED_SENSORS_KEYS[key])
 
	@app.after_request
 
	def add_headers(response):
 
		response.headers.setdefault('Access-Control-Allow-Origin', '*')
 
		response.headers.setdefault('Cache-Control', 'no-cache')
 

	
 
                if key != 'radiation':
 
                    for subkey in ('name', 'location'):
 
                        if subkey in data:
 
                            index = fuzzy_list_find(
 
                                active_json['sensors'][key],
 
                                subkey, data[subkey]
 
                            )
 
                            active_json['sensors'][key][index].update(data)
 
                        else:
 
                            return 400
 
                else:
 
                    for first_subkey in ('alpha', 'beta',
 
                                         'gamma' 'beta_gamma'):
 
                        for second_subkey in ('name', 'location'):
 
                            if second_subkey in data[first_subkey]:
 
                                index = fuzzy_list_find(
 
                                    active_json['sensors'][key][first_subkey],
 
                                    second_subkey,
 
                                    data[first_subkey][second_subkey])
 
                                active_json['sensors'][
 
                                    key
 
                                ][first_subkey][index].update(data)
 
                            else:
 
                                return 400
 
		return response
 

	
 
	from .views import root_views
 
	app.register_blueprint(root_views)
 

	
 
            except jsonschema.ValidationError:
 
                return 400
 
        except:
 
            return 400
 
    else:
 
        return 400
 

	
 
    save_last_state()
 

	
 
    return jsonify(active_json)
 

	
 
	from .state import state_views
 
	app.register_blueprint(state_views, url_prefix='/state')
 

	
 
@app.route('/reload')
 
@auth.login_required
 
def reload():
 
    reload_json()
 
    return 200
 

	
 
	from .sensors import sensors_views
 
	app.register_blueprint(sensors_views, url_prefix='/sensors')
 

	
 
@app.after_request
 
def add_headers(response):
 
    response.headers.setdefault('Access-Control-Allow-Origin', '*')
 
    response.headers.setdefault('Cache-Control', 'no-cache')
 

	
 
    return response
 
	return app
spaceapi/active.py
Show inline comments
 
new file 100644
 
import copy
 
import json
 
import os.path
 

	
 

	
 
default_json_file = os.path.abspath('default.json')
 
last_state_file = os.path.abspath('laststate.json')
 

	
 
default_json = {}
 
active_json = {}
 

	
 
def reload_json():
 
    global default_json
 
    global active_json
 

	
 
    default_json = json.load(open(default_json_file, encoding='utf-8'))
 

	
 
    if os.path.exists(last_state_file):
 
        with open(last_state_file, encoding='utf-8') as f:
 
            active_json = json.load(f)
 

	
 
        if os.path.getmtime(last_state_file) \
 
           < os.path.getmtime(default_json_file):
 
            backup = copy.deepcopy(active_json)
 
            active_json.update(default_json)
 
            active_json['state']['open'] = backup['state']['open']
 
            active_json['state']['lastchange'] = backup['state']['lastchange']
 
    else:
 
        active_json = copy.deepcopy(default_json)
 

	
 
reload_json()
 

	
 
def save_last_state():
 

	
 
    with open(last_state_file, mode='w', encoding='utf-8') as f:
 
        json.dump(active_json, f, sort_keys=True)
spaceapi/auth.py
Show inline comments
 
new file 100644
 
from flask.ext.httpauth import HTTPDigestAuth
 
 
httpauth = HTTPDigestAuth()
 
 
@httpauth.get_password
 
def get_pw(username):
 
    if username == app.config.get('HTTP_DIGEST_AUTH_USER'):
 
        return app.config.get('HTTP_DIGEST_AUTH_PASSWORD')
 
    return None
spaceapi/sensors.py
Show inline comments
 
new file 100644
 
import json
 

	
 
from pkg_resources import resource_filename
 

	
 
import jsonschema
 
from flask import Blueprint, jsonify
 

	
 
from .auth import httpauth
 
from .active import active_json, save_last_state
 
from .utils import first, fuzzy_list_find
 

	
 
sensors_views = Blueprint('sensors', __name__)
 

	
 
ALLOWED_SENSORS_KEYS = json.load(
 
    open(resource_filename('spaceapi', 'schema/sensors.json'),
 
         encoding='utf-8')
 
)
 

	
 
RADIATON_SUBKEYS = ('alpha', 'beta', 'gamma', 'beta_gamma')
 

	
 
IDENTIFICATION_KEYS = ('name', 'location')
 

	
 

	
 
def get_identification_key(data):
 
	return first(data, IDENTIFICATION_KEYS)
 

	
 

	
 
def set_value(data, key):
 

	
 
	try:
 
		subkey = get_identification_key(data)
 
	except ValueError:
 
		return 400
 

	
 
	try:
 
		index = fuzzy_list_find(active_json['sensors'][key],
 
								key, data[subkey])
 
		active_json['sensors'][key][index].update(data)
 
	except ValueError:
 
		active_json['sensors'][key].append(data)
 

	
 
	save_last_state()
 
	return jsonify(active_json)
 

	
 

	
 
def set_radiation_value(data):
 

	
 
	radiation_keys = [k for k in RADIATON_SUBKEYS if k in data]
 

	
 
	if not radiation_keys:
 
		return 400
 

	
 
	for first_subkey in radiation_keys:
 

	
 
		try:
 
			second_subkey = get_identification_key(data[first_subkey])
 
		except ValueError:
 
			return 400
 

	
 
		try:
 
			index = fuzzy_list_find(
 
				active_json['sensors']['radiation'][first_subkey],
 
				second_subkey,
 
				data[first_subkey][second_subkey])
 
			active_json['sensors'][
 
				'radiation'
 
			][first_subkey][index].update(data)
 
		except ValueError:
 
			active_json['sensors']['radiaton'][first_subkey].append(data)
 

	
 

	
 
	save_last_state()
 
	return jsonify(active_json)
 

	
 
@sensors_views.route('/set/<key>', methods=['POST'])
 
@httpauth.login_required
 
def set_sensors(key):
 

	
 
    if key in ALLOWED_SENSORS_KEYS and key in active_json['sensors']:
 
        data = request.data
 
        try:
 
            data = json.loads(data)
 

	
 
            try:
 
                jsonschema.validate(data, ALLOWED_SENSORS_KEYS[key])
 
            except jsonschema.ValidationError:
 
                return 400
 

	
 
            if key != 'radiation':
 
                return set_value(data, key)
 
            else:
 
                return set_radiation_value(data)
 
        except ValueError:
 
            return 400
 
    else:
 
        return 400
spaceapi/state.py
Show inline comments
 
new file 100644
 
from time import time
 

	
 
from flask import Blueprint, jsonify, request
 

	
 
from .active import active_json, save_last_state
 
from .auth import httpauth
 

	
 
state_views = Blueprint('state', __name__)
 

	
 
ALLOWED_STATE_KEYS = {
 
    'open': bool,
 
    'lastchange': int,
 
    'trigger_person': str,
 
    'message': str
 
}
 

	
 
@state_views.route('/set/<key>', methods=['POST'])
 
@httpauth.login_required
 
def set_state(key):
 

	
 
    value = request.form['value']
 
    value = literal_eval(value)
 

	
 
    if key in ALLOWED_STATE_KEYS and isinstance(value,
 
                                                ALLOWED_STATE_KEYS[key]):
 
        active_json['state'][key] = value
 

	
 
        if key == 'open':
 
            active_json['state']['lastchange'] = int(time())
 
    else:
 
        return 400
 

	
 
    save_last_state()
 

	
 
    return jsonify(active_json)
spaceapi/utils.py
Show inline comments
 
new file 100644
 
from flask import request
 
 
def request_wants_json():
 
    best = request.accept_mimetypes.best_match(
 
        ['application/json', 'text/html']
 
    )
 
    return best == 'application/json' and \
 
        request.accept_mimetypes[best] > \
 
        request.accept_mimetypes['text/html']
 
 
 
def fuzzy_list_find(lst, key, value):
 
 
    for i, dic in enumerate(lst):
 
        if dic[key] == value:
 
            return i
 
 
    raise ValueError
 
 
def first(iterable, keys):
 
	for el in keys:
 
		if el in iterable:
 
			return el
 
 
	raise ValueError
spaceapi/views.py
Show inline comments
 
new file 100644
 
from flask import Blueprint, jsonify, render_template
 

	
 
from .auth import httpauth
 
from .active import active_json, reload_json
 
from .utils import request_wants_json
 

	
 
root_views = Blueprint('root', __name__)
 

	
 
@root_views.route('/')
 
def index():
 
    if request_wants_json():
 
        return jsonify(active_json)
 
    return render_template('index.html', status=active_json)
 

	
 
@root_views.route('/status.json')
 
def status_json():
 
    return jsonify(active_json)
 

	
 
@root_views.route('/reload')
 
@httpauth.login_required
 
def reload():
 
    reload_json()
 
    return 200
0 comments (0 inline, 0 general)