Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔖 release v0.3.0 #46

Merged
merged 36 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
295ed69
:green_heart: move git volume target
bunop May 28, 2024
df10c04
:rewind: Revert ":green_heart: move git volume target"
bunop May 28, 2024
7bf7cee
:green_heart: attempt to fix coveralls step
bunop May 28, 2024
4b8fb8f
:rewind: Revert ":green_heart: attempt to fix coveralls step"
bunop May 28, 2024
8971a01
:green_heart: update container requirement
bunop May 28, 2024
5a16f75
:card_file_box: rename manifacturer into manufacturer
bunop May 28, 2024
bdcb3d8
:arrow_up: upgrade dependencies
bunop May 28, 2024
0541ef4
:bookmark: Bump version: 0.2.2 → 0.3.0.dev0
bunop May 28, 2024
be6120c
:wrench: update bunmp2version configuration file
bunop May 28, 2024
60e09f6
:arrow_up: update pymongo
bunop Jun 14, 2024
d244cc0
:arrow_up: update dependencies
bunop Jun 14, 2024
3e60b88
:pencil2: fix typos
bunop Jun 17, 2024
8f9c633
:passport_control: remove jwt related stuff from endpoints
bunop Jun 17, 2024
27b0c48
:clown_face: mock auth endpoint
bunop Jun 17, 2024
be41fa8
:white_check_mark: fix tests after removing credentials
bunop Jun 17, 2024
8b5d0e4
:heavy_minus_sign: remove unused dependencies
bunop Jun 17, 2024
80f0a6f
:fire: remove user and user blueprint
bunop Jun 17, 2024
508d8e0
:memo: update README
bunop Jun 17, 2024
2fd2106
:memo: remove authorization stuff from RTD documentation
bunop Jun 17, 2024
fc255d7
:arrow_up: Bump urllib3 from 2.0.4 to 2.2.2
dependabot[bot] Jun 17, 2024
d65eb41
:twisted_rightwards_arrows: Merge branch 'devel' into dependabot/pip/…
bunop Jun 18, 2024
983c0b5
:twisted_rightwards_arrows: Merge pull request #49 from cnr-ibba/issu…
bunop Jun 18, 2024
aeeac56
:twisted_rightwards_arrows: Merge pull request #50 from cnr-ibba/depe…
bunop Jun 18, 2024
79ec988
:whale: update poetry version
bunop Jun 18, 2024
020dfe6
:bug: fix swagger documentation for POST endpoints
bunop Jun 18, 2024
0473eba
:memo: document the installation process
bunop Jun 19, 2024
7e9d9a5
:fire: remove thirdy-party software from documentation
bunop Jun 19, 2024
0984fa6
:memo: complete the example documentation with python stuff
bunop Jun 19, 2024
56d175b
:green_heart: update readthedocs CI config
bunop Jun 19, 2024
159033b
:memo: minor changes in RTD documentation
bunop Jun 20, 2024
7b03a73
:heavy_plus_sign: add python decouple
bunop Jun 20, 2024
e636838
:recycle: configure stuff with decouple
bunop Jun 20, 2024
a5701d8
:sparkles: send error messages to admins
bunop Jun 20, 2024
841f5de
:sparkles: add requests to logging messages
bunop Jun 20, 2024
d4bb629
:twisted_rightwards_arrows: Merge pull request #51 from cnr-ibba/issue-7
bunop Jun 20, 2024
f4adf54
:loud_sound: add logs to geojson endpoint
bunop Jun 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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__ = '[email protected]'
__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 <[email protected]>
"""

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="[email protected]"),
toaddrs=[email.strip() for email in config(
'ADMINS', default="[email protected]").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
Loading