from flask import Flask, request, jsonify from flask_sqlalchemy import SQLAlchemy from flask_cors import CORS import datetime import os import json # Flask app instance app = Flask(__name__) CORS(app) # Flask app should allow the necessary HTTP methods in CORS. CORS( app, resources={r"/*": {"origins": "*"}}, allow_headers=["Content-Type", "Authorization"] ) # Configuration for SQLAlchemy app.config[ 'SQLALCHEMY_DATABASE_URI' ] = os.environ.get( "SQLALCHEMY_DATABASE_URI" ) db = SQLAlchemy(app) # Database Model for Records class Record(db.Model): __tablename__ = 'records' id = db.Column(db.Integer, primary_key=True) timestamp = db.Column(db.String(255), nullable=False) description = db.Column(db.String(255), nullable=False) # Parse a timestamp string into a datetime object def parse_timestamp(timestamp_str): try: return datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S') except ValueError: return None # Function to validate API keys based on their values and access level def validate_api_key(api_key, required_access_level): api_keys_json = os.environ.get('API_KEYS_JSON', '{}') api_keys_dict = json.loads(api_keys_json) if api_key in api_keys_dict: access_level = api_keys_dict[api_key].get("access_level") return access_level == required_access_level return False # API key authentication @app.before_request def authenticate(): # Check if the API key provided in the request headers is valid api_key = request.headers.get("Authorization") # Allow all requests with RW keys if validate_api_key(api_key, "RW"): return None # Allow the request to proceed # Allow GET requests with RO keys if request.method == "GET" and validate_api_key(api_key, "RO"): return None # Allow the request to proceed # Return a 401 Unauthorized response for invalid API keys or access levels return jsonify({'error': 'Invalid API key or access level'}), 401 # Route to add a new record @app.route( '/add_record', methods=['POST'] ) def add_record(): try: data = request.get_json() timestamp = data['timestamp'] description = data['description'] # Create a new record with provided data and add it to the db new_record = Record( timestamp=timestamp, description=description ) db.session.add(new_record) db.session.commit() return jsonify({'message': 'Record added successfully'}), 201 except Exception as e: # Return a 500 Internal Server Error response if an exception occurs return jsonify({'error': 'An error occurred: {}'.format(e)}), 500 # Route to get the last recorded entry @app.route( '/get_last_record', methods=['GET'] ) def get_last_record(): # Retrieve the last record from the database based on its ID last_record = Record.query.order_by(Record.id.desc()).first() if last_record: # Return the data of the last record as JSON return jsonify({ 'id': last_record.id, 'timestamp': last_record.timestamp, 'description': last_record.description }) else: # Return a 404 Not Found response if no records are found return jsonify({'message': 'No records found'}), 404 # Route to get all records @app.route( '/get_all_records', methods=['GET'] ) def get_all_records(): # Retrieve all records from the database # and format them into a list of dictionaries records = Record.query.order_by(Record.id.desc()).all() records_list = [] for record in records: record_data = { 'id': record.id, 'timestamp': record.timestamp, 'description': record.description } records_list.append(record_data) # Return the list of records as JSON return jsonify(records_list) # Route to get records since a given timestamp @app.route( '/get_records_since/', methods=['GET'] ) def get_records_since(timestamp_str): timestamp = parse_timestamp(timestamp_str) if timestamp is None: return jsonify({'error': 'Invalid timestamp format'}), 400 # Retrieve records from the database where # the timestamp is greater than or equal to the provided timestamp records = Record.query.filter( Record.timestamp >= timestamp ).order_by(Record.id.desc()).all() records_list = [] for record in records: record_data = { 'id': record.id, 'timestamp': record.timestamp, 'description': record.description } records_list.append(record_data) # Return the list of matching records as JSON return jsonify(records_list) # Route to get records between two timestamps @app.route( '/get_records_between/' '/', methods=['GET'] ) def get_records_between(start_timestamp_str, end_timestamp_str): # Parse the provided start and end timestamps into datetime objects start_timestamp = parse_timestamp(start_timestamp_str) end_timestamp = parse_timestamp(end_timestamp_str) if start_timestamp is None or end_timestamp is None: return jsonify({'error': 'Invalid timestamp format'}), 400 # Retrieve records from the database # that fall within the provided timestamp range records = Record.query.filter( Record.timestamp.between(start_timestamp, end_timestamp) ).order_by(Record.id.desc()).all() records_list = [] for record in records: record_data = { 'id': record.id, 'timestamp': record.timestamp, 'description': record.description } records_list.append(record_data) return jsonify(records_list) # Route to get records until a given timestamp @app.route('/get_records_until/', methods=['GET']) def get_records_until(timestamp_str): timestamp = parse_timestamp(timestamp_str) if timestamp is None: return jsonify({'error': 'Invalid timestamp format'}), 400 records = Record.query.filter( Record.timestamp <= timestamp ).order_by(Record.id.desc()).all() records_list = [] for record in records: record_data = { 'id': record.id, 'timestamp': record.timestamp, 'description': record.description } records_list.append(record_data) return jsonify(records_list) # Run the Flask app if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)