Initial commit

This commit is contained in:
Luka Radenovic 2021-09-27 12:03:35 +02:00
parent b8bdc46525
commit 4cd9db36cd
10 changed files with 206 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.venv
*.pyc

28
Dockerfile Normal file
View file

@ -0,0 +1,28 @@
FROM python:3.6-slim
RUN apt-get update
RUN apt-get install -y libpq-dev python-dev gcc
## make a local directory
RUN mkdir /app
# set "app" as the working directory from which CMD, RUN, ADD references
WORKDIR /app
# copy requirements.txt to /app
ADD requirements.txt .
# required to be able to install old MarkupSafe==1.0.0 version
RUN pip install --upgrade pip setuptools==45.2.0
# pip install the local requirements.txt
RUN pip install -r requirements.txt
# now copy all the files in this directory to /code
ADD . .
# Listen to port 80 at runtime
EXPOSE 5000
# Define our command to be run when launching the container
CMD ["gunicorn", "app:app", "-b", "0.0.0.0:5000", "--workers", "4", "--reload", "--capture-output", "--enable-stdio-inheritance", "--log-level", "DEBUG"]

3
api/__init__.py Normal file
View file

@ -0,0 +1,3 @@
from flask import Blueprint
api_v1 = Blueprint('api_v1', __name__, url_prefix='/api/v1')

66
api/apps.py Normal file
View file

@ -0,0 +1,66 @@
from flask import jsonify
from flask_jwt_extended import jwt_required
from flask_cors import cross_origin
from . import api_v1
CONFIG_DATA = [
{
"id": "values.yml",
"description": "Some user friendly description",
"raw": "cronjob:\n # Set curl to accept insecure connections when acme staging is used\n curlInsecure: false",
"fields": [
{"name": "cronjob", "type": "string", "value": ""},
{"name": "curlInsecure", "type": "boolean", "value": "false"}
]
}
]
APPS_DATA = [
{"id": 1, "name": "Nextcloud", "enabled": True, "status": "ON for everyone"},
{"id": 2, "name": "Rocketchat", "enabled": True, "status": "ON for everyone"},
{"id": 3, "name": "Wordpress", "enabled": False, "status": "ON for everyone"}
]
APP_DATA = {"id": 1, "name": "Nextcloud", "selected": True, "status": "ON for everyone", "config": CONFIG_DATA},
@api_v1.route('/apps', methods=['GET'])
@jwt_required()
@cross_origin()
def get_apps():
return jsonify(APPS_DATA)
@api_v1.route('/apps/<string:slug>', methods=['GET'])
@jwt_required()
def get_app(slug):
return jsonify(APPS_DATA[0])
@api_v1.route('/apps', methods=['POST'])
@jwt_required()
@cross_origin()
def post_app():
return jsonify(APPS_DATA), 201
@api_v1.route('/apps/<string:slug>', methods=['PUT'])
@jwt_required()
@cross_origin()
def put_app(slug):
return jsonify(APPS_DATA)
@api_v1.route('/apps/<string:slug>/config', methods=['GET'])
@jwt_required()
@cross_origin()
def get_config(slug):
return jsonify(CONFIG_DATA)
@api_v1.route('/apps/<string:slug>/config', methods=['DELETE'])
@jwt_required()
@cross_origin()
def delete_config(slug):
return jsonify(CONFIG_DATA)

21
api/auth.py Normal file
View file

@ -0,0 +1,21 @@
from flask import request, jsonify
from flask_jwt_extended import create_access_token
from flask_cors import cross_origin
from . import api_v1
USERNAME = 'admin'
PASSWORD = 'admin'
@api_v1.route('/login', methods=['POST'])
@cross_origin()
def login():
username = request.json.get('username')
password = request.json.get('password')
if username != USERNAME or password != PASSWORD:
return jsonify({'errorMessage': 'Invalid username or password'}), 401
access_token = create_access_token(identity=username)
return jsonify({'username': USERNAME, 'access_token': access_token})

38
api/users.py Normal file
View file

@ -0,0 +1,38 @@
from flask import jsonify
from flask_jwt_extended import jwt_required
from flask_cors import cross_origin
from . import api_v1
USER_DATA = [
{"id": 1, "email": "john@doe.com", "name": "John Doe", "status": "active", "last_login": "2021-08-03T07:40:51+00:00"}
]
@api_v1.route('/users', methods=['GET'])
@jwt_required()
@cross_origin()
def get_users():
return jsonify(USER_DATA)
@api_v1.route('/users', methods=['POST'])
@jwt_required()
@cross_origin()
def post_user():
return jsonify(USER_DATA), 201
@api_v1.route('/users/<int:id>', methods=['PUT'])
@jwt_required()
@cross_origin()
def put_user(id):
return jsonify(USER_DATA)
@api_v1.route('/users/<int:id>', methods=['DELETE'])
@jwt_required()
@cross_origin()
def delete_user(id):
return jsonify(USER_DATA)

27
app.py Normal file
View file

@ -0,0 +1,27 @@
from flask import Flask, jsonify
from flask_jwt_extended import JWTManager
from flask_cors import CORS, cross_origin
from config import *
from api import api_v1, auth, users, apps
app = Flask(__name__)
cors = CORS(app)
app.config['SECRET_KEY'] = SECRET_KEY
app.register_blueprint(api_v1)
jwt = JWTManager(app)
# When token is not valid or missing handler
@jwt.invalid_token_loader
@jwt.unauthorized_loader
@jwt.expired_token_loader
def expired_token_callback(*args):
return jsonify({'errorMessage': 'Unauthorized'}), 401
@app.route('/')
def index():
return 'Open App Stack API v1.0'

3
config.py Normal file
View file

@ -0,0 +1,3 @@
import os
SECRET_KEY = os.environ.get('SECRET_KEY')

14
requirements.txt Normal file
View file

@ -0,0 +1,14 @@
cffi==1.14.6
click==8.0.1
cryptography==3.4.7
Flask==2.0.1
Flask-Cors==3.0.10
Flask-JWT-Extended==4.2.3
gunicorn==20.1.0
itsdangerous==2.0.1
Jinja2==3.0.1
MarkupSafe==2.0.1
pycparser==2.20
PyJWT==2.1.0
six==1.16.0
Werkzeug==2.0.1

4
run_app.sh Executable file
View file

@ -0,0 +1,4 @@
export FLASK_APP=app.py
export FLASK_ENV=development
export SECRET_KEY="e38hq!@0n64g@qe6)5csk41t=ljo2vllog(%k7njnm4b@kh42c"
flask run