FitTrackee/fittrackee/application/app_config.py

194 lines
5.8 KiB
Python
Raw Normal View History

2021-01-02 19:28:03 +01:00
from typing import Dict, Union
2021-01-20 16:47:00 +01:00
from flask import Blueprint, current_app, request
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
2021-01-01 16:39:25 +01:00
from fittrackee import db
from fittrackee.oauth2.server import require_auth
2021-01-01 16:39:25 +01:00
from fittrackee.responses import (
2021-01-02 19:28:03 +01:00
HttpResponse,
2021-01-01 16:39:25 +01:00
InvalidPayloadErrorResponse,
handle_error_and_return_response,
)
from fittrackee.users.models import User
from fittrackee.users.utils.controls import is_valid_email
from .models import AppConfig
from .utils import update_app_config_from_database, verify_app_config
config_blueprint = Blueprint('config', __name__)
@config_blueprint.route('/config', methods=['GET'])
2021-01-02 19:28:03 +01:00
def get_application_config() -> Union[Dict, HttpResponse]:
"""
Get Application configuration.
**Example request**:
.. sourcecode:: http
GET /api/config HTTP/1.1
Content-Type: application/json
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
2022-04-03 19:47:40 +02:00
"admin_contact": "admin@example.com",
"gpx_limit_import": 10,
"is_email_sending_enabled": true,
"is_registration_enabled": false,
"max_single_file_size": 1048576,
2020-09-19 13:56:14 +02:00
"max_users": 0,
2022-04-03 19:47:40 +02:00
"max_zip_file_size": 10485760,
2020-09-19 13:56:14 +02:00
"map_attribution": "&copy; <a href=http://www.openstreetmap.org/copyright>OpenStreetMap</a> contributors"
2022-09-14 09:55:02 +02:00
"version": "0.6.12"
},
"status": "success"
}
:statuscode 200: success
:statuscode 500: error on getting configuration
"""
try:
config = AppConfig.query.one()
2021-01-01 16:39:25 +01:00
return {'status': 'success', 'data': config.serialize()}
except (MultipleResultsFound, NoResultFound) as e:
2021-01-01 16:39:25 +01:00
return handle_error_and_return_response(
e, message='error on getting configuration'
2021-01-01 16:39:25 +01:00
)
@config_blueprint.route('/config', methods=['PATCH'])
2022-06-15 19:16:14 +02:00
@require_auth(scopes=['application:write'], as_admin=True)
def update_application_config(auth_user: User) -> Union[Dict, HttpResponse]:
"""
Update Application configuration.
Authenticated user must be an admin.
**Scope**: ``application:write``
**Example request**:
.. sourcecode:: http
GET /api/config HTTP/1.1
Content-Type: application/json
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"admin_contact": "admin@example.com",
"gpx_limit_import": 10,
"is_email_sending_enabled": true,
2022-04-03 19:47:40 +02:00
"is_registration_enabled": false,
"max_single_file_size": 1048576,
2022-04-03 19:47:40 +02:00
"max_users": 10,
"max_zip_file_size": 10485760,
2022-04-03 19:47:40 +02:00
"map_attribution": "&copy; <a href=http://www.openstreetmap.org/copyright>OpenStreetMap</a> contributors"
2022-09-14 09:55:02 +02:00
"version": "0.6.12"
},
"status": "success"
}
:<json string admin_contact: email to contact the administrator
:<json integer gpx_limit_import: max number of files in zip archive
:<json boolean is_registration_enabled: is registration enabled?
:<json integer max_single_file_size: max size of a single file
:<json integer max_users: max users allowed to register on instance
2022-04-03 19:47:40 +02:00
:<json integer max_zip_file_size: max size of a zip archive
:reqheader Authorization: OAuth 2.0 Bearer Token
:statuscode 200: success
:statuscode 400: invalid payload
:statuscode 401:
- provide a valid auth token
- signature expired, please log in again
- invalid token, please log in again
- valid email must be provided for admin contact
:statuscode 403: you do not have permissions
:statuscode 500: error when updating configuration
"""
config_data = request.get_json()
if not config_data:
2021-01-01 16:39:25 +01:00
return InvalidPayloadErrorResponse()
ret = verify_app_config(config_data)
admin_contact = config_data.get('admin_contact')
if admin_contact and not is_valid_email(admin_contact):
ret.append('valid email must be provided for admin contact')
if ret:
return InvalidPayloadErrorResponse(message=ret)
try:
config = AppConfig.query.one()
if 'gpx_limit_import' in config_data:
config.gpx_limit_import = config_data.get('gpx_limit_import')
if 'max_single_file_size' in config_data:
config.max_single_file_size = config_data.get(
'max_single_file_size'
)
if 'max_zip_file_size' in config_data:
config.max_zip_file_size = config_data.get('max_zip_file_size')
if 'max_users' in config_data:
config.max_users = config_data.get('max_users')
if 'admin_contact' in config_data:
config.admin_contact = admin_contact if admin_contact else None
if config.max_zip_file_size < config.max_single_file_size:
return InvalidPayloadErrorResponse(
'Max. size of zip archive must be equal or greater than '
'max. size of uploaded files'
)
db.session.commit()
update_app_config_from_database(current_app, config)
2021-01-01 16:39:25 +01:00
return {'status': 'success', 'data': config.serialize()}
except Exception as e:
2021-01-01 16:39:25 +01:00
return handle_error_and_return_response(
e, message='error when updating configuration'
2021-01-01 16:39:25 +01:00
)
2020-05-01 18:10:34 +02:00
@config_blueprint.route('/ping', methods=['GET'])
2021-01-02 19:28:03 +01:00
def health_check() -> Union[Dict, HttpResponse]:
2020-09-16 11:09:32 +02:00
"""health check endpoint
2020-05-01 18:10:34 +02:00
**Example request**:
.. sourcecode:: http
GET /api/ping HTTP/1.1
Content-Type: application/json
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
{
"message": "pong!",
"status": "success"
}
:statuscode 200: success
"""
2021-01-01 16:39:25 +01:00
return {'status': 'success', 'message': 'pong!'}