Initial commit
This commit is contained in:
parent
b8bdc46525
commit
4cd9db36cd
10 changed files with 206 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.venv
|
||||
*.pyc
|
28
Dockerfile
Normal file
28
Dockerfile
Normal 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
3
api/__init__.py
Normal 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
66
api/apps.py
Normal 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
21
api/auth.py
Normal 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
38
api/users.py
Normal 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
27
app.py
Normal 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
3
config.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
import os
|
||||
|
||||
SECRET_KEY = os.environ.get('SECRET_KEY')
|
14
requirements.txt
Normal file
14
requirements.txt
Normal 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
4
run_app.sh
Executable 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
|
Loading…
Reference in a new issue