Skip to content

Commit

Permalink
Merge d4bb629 into 123ee7c
Browse files Browse the repository at this point in the history
  • Loading branch information
bunop committed Jun 20, 2024
2 parents 123ee7c + d4bb629 commit ae67eac
Show file tree
Hide file tree
Showing 43 changed files with 1,256 additions and 1,357 deletions.
10 changes: 7 additions & 3 deletions .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
[bumpversion]
current_version = 0.2.2
current_version = 0.3.0.dev0
commit = True
tag = False
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\.(?P<release>[a-z]+)(?P<build>\d+))?
serialize =
serialize =
{major}.{minor}.{patch}.{release}{build}
{major}.{minor}.{patch}
message = :bookmark: Bump version: {current_version} → {new_version}

[bumpversion:part:release]
optional_value = prod
first_value = dev
values =
values =
dev
prod

Expand All @@ -27,4 +27,8 @@ replace = {new_version}
search = {current_version}
replace = {new_version}

[bumpversion:file:pyproject.toml]
search = {current_version}
replace = {new_version}

[bumpversion:part:build]
8 changes: 4 additions & 4 deletions .readthedocs.yml → .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ version: 2
build:
os: "ubuntu-22.04"
tools:
python: "3.10"
python: "3.11"
jobs:
post_create_environment:
# Install poetry
# https://python-poetry.org/docs/#installing-manually
- pip install poetry
# Tell poetry to not use a virtual environment
- poetry config virtualenvs.create false
post_install:
# Install dependencies with 'docs' dependency group
# https://python-poetry.org/docs/managing-dependencies/#dependency-groups
- poetry install
# VIRTUAL_ENV needs to be set manually for now.
# See https://github.com/readthedocs/readthedocs.org/pull/11152/
- VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --no-root

# Build documentation in the docs/ directory with Sphinx
sphinx:
Expand Down
16 changes: 15 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
{
"esbonio.sphinx.confDir": "${workspaceFolder}/flask-data/smarter/docs/source"
"esbonio.sphinx.confDir": "${workspaceFolder}/flask-data/smarter/docs/source",
"cSpell.words": [
"affymetrix",
"exitfirst",
"iname",
"INITDB",
"jsonify",
"mongodump",
"mongorestore",
"pytest",
"reqparse",
"showlocals",
"uwsgi",
"uwsgitop"
]
}
19 changes: 3 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,12 @@ MONGODB_ROOT_USER=<root user>
MONGODB_ROOT_PASS=<root pass>
MONGODB_SMARTER_USER=<smarter user>
MONGODB_SMARTER_PASS=<smarter pass>
JWT_SECRET_KEY=<secret key>
```

> *TODO*: manage sensitive data using secret in docker-compose, as described
[here](https://docs.docker.com/engine/swarm/secrets/#use-secrets-in-compose) and
[here](https://docs.docker.com/compose/compose-file/#secrets)

### Genereate the JWT secret key

[Here](https://stackoverflow.com/a/23728630/4385116) you can find hints on
how to define a secret key with python:

```python
import string
import secrets
print(''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(50)))
```

## Setting the proper permissions

Set `mongodb-home` folder permissions with:
Expand All @@ -53,12 +41,11 @@ cd flask-data/
find . -type f -iname "*.py" -exec chmod g-w {} \;
```

## Add a smarter user

Add a smarter user by calling a *flask script*:
## Build and run the application

```bash
docker-compose run --rm uwsgi flask users create smarter
docker-compose build
docker-compose up
```

## Connect to mongodb
Expand Down
2 changes: 0 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@

# User/password credentials are stored in .env file
version: '3.8'

services:

mongo:
Expand Down
2 changes: 1 addition & 1 deletion flask-data/smarter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
__copyright__ = "Copyright 2021, IBBA-CNR"
__credits__ = ["Paolo Cozzi, ..."]
__license__ = "GNU General Public License v3"
__version__ = "0.2.2"
__version__ = "0.3.0.dev0"
__maintainer__ = "Paolo Cozzi"
__email__ = 'paolo.cozzi@ibba.cnr.it'
__status__ = "Development"
90 changes: 59 additions & 31 deletions flask-data/smarter/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,24 @@
@author: Paolo Cozzi <paolo.cozzi@ibba.cnr.it>
"""

import os

from bson import ObjectId
import logging
from logging.config import dictConfig
from logging.handlers import SMTPHandler

from flask import Flask, redirect, url_for
from decouple import config
from flask import Flask, redirect, url_for, has_request_context, request
from flask.logging import default_handler
from flask_restful import Api
from flask_bcrypt import Bcrypt
from flask_jwt_extended import JWTManager
from flask.json import JSONEncoder
from flask_cors import CORS
from flasgger import Swagger

from database.db import initialize_db, DB_ALIAS
from resources.errors import errors
from resources.routes import initialize_routes
from commands import usersbp

__version__ = "0.2.2"
__version__ = "0.3.0.dev0"

# https://flask.palletsprojects.com/en/2.0.x/logging/#basic-configuration
dictConfig({
Expand All @@ -43,6 +42,43 @@
}
})

mail_handler = SMTPHandler(
mailhost=(
config('EMAIL_HOST', default='localhost'),
config('EMAIL_PORT', cast=int, default=1025)
),
fromaddr=config('DEFAULT_FROM_EMAIL', default="server-error@example.com"),
toaddrs=[email.strip() for email in config(
'ADMINS', default="admin@example.com").split(',')],
subject='SMARTER-backend Application Error',
credentials=(
config('EMAIL_HOST_USER', default=None),
config('EMAIL_HOST_PASSWORD', default=None)
),
secure=()
)
mail_handler.setLevel(logging.ERROR)


class RequestFormatter(logging.Formatter):
def format(self, record):
if has_request_context():
record.url = request.url
record.remote_addr = request.remote_addr
else:
record.url = None
record.remote_addr = None

return super().format(record)


formatter = RequestFormatter(
'[%(asctime)s] %(remote_addr)s requested %(url)s\n'
'%(levelname)s in %(module)s: %(message)s'
)
mail_handler.setFormatter(formatter)
default_handler.setFormatter(formatter)


class CustomJSONEncoder(JSONEncoder):
def default(self, obj):
Expand All @@ -54,33 +90,30 @@ def default(self, obj):


# https://stackoverflow.com/a/56474420/4385116
def create_app(config={}):
def create_app():
"""This function create Flask app. Is required by wsgi because it need to
be called after service is started and forked, not when importing the
module during initialization. To start the flask app, first import
the module and then create all the stuff by invoking this function
You need call the run method on the returned values to start acception
You need call the run method on the returned values to start accepting
requests
Args:
config (dict): pass parameters to this app (not yet defined)
Returns:
Flask: a flask initialized application
"""

app = Flask(__name__)
CORS(app)
api = Api(app, errors=errors)
Bcrypt(app)
JWTManager(app)

# check debug mode
if config('DEBUG', cast=bool, default=True):
# in debug mode, the default logging will be set to DEBUG level
app.debug = True

# deal with ObjectId in json responses
app.json_encoder = CustomJSONEncoder

# workaround to make flasgger deal with jwt-token headers
app.config["JWT_AUTH_URL_RULE"] = True

# Swagger stuff
swagger_template = {
"swagger": "2.0",
Expand Down Expand Up @@ -115,38 +148,33 @@ def create_app(config={}):

# http://docs.mongoengine.org/projects/flask-mongoengine/en/latest/#configuration
app.config['MONGODB_SETTINGS'] = {
'host': 'mongodb://mongo/smarter',
'username': os.getenv("MONGODB_SMARTER_USER"),
'password': os.getenv("MONGODB_SMARTER_PASS"),
'host': config(
'MONGODB_SMARTER_DB',
default='mongodb://mongo/smarter'
),
'username': config('MONGODB_SMARTER_USER'),
'password': config("MONGODB_SMARTER_PASS"),
'authentication_source': 'admin',
'alias': DB_ALIAS,
# NOTE: This fixes "UserWarning: MongoClient opened before fork."
# I'm not aware of side effects yet. Default value is/was "True"
'connect': False
}

# override configuration with custom values
if 'host' in config:
app.logger.error(f"Setting custom host: {config['host']}")
app.config['MONGODB_SETTINGS']['host'] = config['host']

# https://flask-jwt-extended.readthedocs.io/en/stable/basic_usage/
app.config["JWT_SECRET_KEY"] = os.getenv('JWT_SECRET_KEY')

# connect to database
initialize_db(app)

app.logger.debug("Database initialized")
app.logger.debug(f"Got encoder {app.json_encoder}")

# you MUST register the blueprint
app.register_blueprint(usersbp)

# add resources
initialize_routes(api)

app.logger.debug("Routes initialized")

if not app.debug:
app.logger.addHandler(mail_handler)

# add a redirect for the index page
@app.route('/smarter-api/')
def index():
Expand Down
41 changes: 0 additions & 41 deletions flask-data/smarter/commands.py

This file was deleted.

17 changes: 1 addition & 16 deletions flask-data/smarter/database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@

from enum import Enum

from flask_bcrypt import check_password_hash

from .db import db, DB_ALIAS

# Get an instance of a logger
Expand Down Expand Up @@ -39,19 +37,6 @@ class SmarterDBException(Exception):
pass


class User(db.Document):
username = db.StringField(required=True, unique=True)
password = db.StringField(required=True, min_length=6)

def check_password(self, password):
return check_password_hash(self.password, password)

meta = {
'db_alias': DB_ALIAS,
'collection': 'user'
}


class SmarterInfo(db.Document):
"""A class to track database status informations"""

Expand Down Expand Up @@ -96,7 +81,7 @@ def __str__(self):
class SupportedChip(db.Document):
name = db.StringField(required=True, unique=True)
species = db.StringField(required=True)
manifacturer = db.StringField()
manufacturer = db.StringField()
n_of_snps = db.IntField(default=0)

meta = {
Expand Down
Loading

0 comments on commit ae67eac

Please sign in to comment.