-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
27 changed files
with
1,118 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Flask configuration | ||
FLASK_ENV=development | ||
FLASK_APP=woodcamrm | ||
SECRET_KEY=dev | ||
|
||
# Database configuration | ||
DATABASE_SERVER=127.0.0.1 | ||
DATABASE_PORT=5432 | ||
DATABASE_NAME= | ||
DATABASE_USER= | ||
DATABASE_PASSWORD= | ||
|
||
# External hydrometric observations API terminaison | ||
API_URL=https://hubeau.eaufrance.fr/api/v1/hydrometrie/observations_tr | ||
|
||
# App configuration | ||
DEFAULT_USER=admin | ||
DEFAULT_PASSWORD=admin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
FROM python:alpine | ||
COPY requirements.txt ./requirements.txt | ||
RUN pip install -r requirements.txt | ||
COPY . ./ | ||
|
||
CMD gunicorn -b 0.0.0.0:80 app.app:server |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
include woodcamrm/schema.sql | ||
graft woodcamrm/templates | ||
global-exclude *.pyc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,17 @@ | ||
# woodcam-rd | ||
WoodCam Records Downloader | ||
# WoodCam RM | ||
WoodCam Records Manager | ||
|
||
## Quick start | ||
|
||
# Create python virtualenv | ||
python -m venv env --prompt woodcam-rm | ||
source env/bin/activate | ||
|
||
# Install dependencies | ||
python -m pip install -r requirements.txt | ||
|
||
# Initialize database | ||
flask init-db | ||
|
||
# Run application | ||
flask run |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
python-dotenv==0.19.2 | ||
Flask==2.0.2 | ||
requests | ||
flask_restful | ||
psycopg2 | ||
pytest | ||
pytest-dotenv | ||
coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[tool:pytest] | ||
testpaths = tests | ||
|
||
[coverage:run] | ||
branch = True | ||
source = | ||
woodcamrm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from setuptools import find_packages, setup | ||
|
||
setup( | ||
name='woodcam_rm', | ||
version='1.0.0', | ||
packages=find_packages(), | ||
include_package_data=True, | ||
zip_safe=False, | ||
install_requires=[ | ||
'flask', | ||
'flask_restful', | ||
'requests', | ||
'psycopg2', | ||
'python-dotenv' | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import os | ||
|
||
import pytest | ||
from woodcamrm import create_app | ||
from woodcamrm.db import get_db, init_db | ||
|
||
with open(os.path.join(os.path.dirname(__file__), 'data.sql'), 'rb') as f: | ||
_data_sql = f.read().decode('utf8') | ||
|
||
|
||
@pytest.fixture | ||
def app(): | ||
|
||
app = create_app({ | ||
'TESTING': True, | ||
'DATABASE_NAME': 'woodcamrmtesting', | ||
}) | ||
|
||
with app.app_context(): | ||
init_db() | ||
db = get_db() | ||
cur = db.cursor() | ||
cur.execute(_data_sql) | ||
cur.close() | ||
db.commit() | ||
|
||
yield app | ||
|
||
|
||
@pytest.fixture | ||
def client(app): | ||
return app.test_client() | ||
|
||
|
||
@pytest.fixture | ||
def runner(app): | ||
return app.test_cli_runner() | ||
|
||
|
||
class AuthActions(object): | ||
def __init__(self, client): | ||
self._client = client | ||
|
||
def login(self, username='test', password='test'): | ||
return self._client.post( | ||
'/auth/login', | ||
data={'username': username, 'password': password} | ||
) | ||
|
||
def logout(self): | ||
return self._client.get('/auth/logout') | ||
|
||
|
||
@pytest.fixture | ||
def auth(client): | ||
return AuthActions(client) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
INSERT INTO users (username, password, role) | ||
VALUES | ||
('test', 'pbkdf2:sha256:50000$TCI4GzcX$0de171a4f4dac32e3364c7ddc7c14f3e2fa61f2d17574483f7ffbb431b4acb2f', 'viewer'), | ||
('other', 'pbkdf2:sha256:50000$kJPKsz6N$d2d4784f1b030a9761f5ccaeeaca413f27f2ecb76d6168407af962ddce849f79', 'administrator'); | ||
|
||
INSERT INTO stations (common_name, api_name) | ||
VALUES | ||
('Ain-Chazey', 'V2942010'), | ||
('Station Test', NULL); | ||
|
||
INSERT INTO hydrodata (api_name, metric, date_begin_serie, date_end_serie, date_obs, observation) | ||
VALUES | ||
('V2942010', 'H', TIMESTAMP '2022-01-26 00:00', TIMESTAMP '2022-01-26 15:00', TIMESTAMP '2022-01-26 14:12', 920.0); | ||
|
||
INSERT INTO records (station_id, date_begin_record, date_end_record, host, path) | ||
VALUES | ||
(1, TIMESTAMP '2022-01-26 15:00', TIMESTAMP '2022-01-26 15:59', '127.0.0.1', '/data/records/15to16.mkv'), | ||
(1, TIMESTAMP '2022-01-26 16:00', TIMESTAMP '2022-01-26 16:59', '127.0.0.1', '/data/records/16to17.mkv'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import pytest | ||
from flask import g, session | ||
from woodcamrm.db import get_db | ||
|
||
|
||
# def test_register(client, app): | ||
# assert client.get('/auth/register').status_code == 200 | ||
# response = client.post( | ||
# '/auth/register', data={'username': 'a', 'password': 'a'} | ||
# ) | ||
# assert 'http://localhost/auth/login' == response.headers['Location'] | ||
|
||
# with app.app_context(): | ||
# assert get_db().execute( | ||
# "SELECT * FROM user WHERE username = 'a'", | ||
# ).fetchone() is not None | ||
|
||
|
||
# @pytest.mark.parametrize(('username', 'password', 'message'), ( | ||
# ('', '', b'Username is required.'), | ||
# ('a', '', b'Password is required.'), | ||
# ('test', 'test', b'already registered'), | ||
# )) | ||
# def test_register_validate_input(client, username, password, message): | ||
# response = client.post( | ||
# '/auth/register', | ||
# data={'username': username, 'password': password} | ||
# ) | ||
# assert message in response.data | ||
|
||
|
||
def test_login(client, auth): | ||
assert client.get('/auth/login').status_code == 200 | ||
response = auth.login() | ||
assert response.headers['Location'] == 'http://localhost/' | ||
|
||
with client: | ||
client.get('/') | ||
assert session['user_id'] == 2 | ||
assert g.user['username'] == 'test' | ||
|
||
|
||
@pytest.mark.parametrize(('username', 'password', 'message'), ( | ||
('a', 'test', b'Incorrect username.'), | ||
('test', 'a', b'Incorrect password.'), | ||
)) | ||
def test_login_validate_input(auth, username, password, message): | ||
response = auth.login(username, password) | ||
assert message in response.data | ||
|
||
|
||
def test_logout(client, auth): | ||
auth.login() | ||
|
||
with client: | ||
auth.logout() | ||
assert 'user_id' not in session |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import psycopg2 | ||
|
||
import pytest | ||
from woodcamrm.db import get_db | ||
|
||
|
||
# def test_get_close_db(app): | ||
# with app.app_context(): | ||
# db = get_db() | ||
# assert db is get_db() | ||
|
||
# with pytest.raises(psycopg2.ProgrammingError) as e: | ||
# cur = db.cursor() | ||
# db.execute('SELECT 1;') | ||
# cur.close() | ||
# db.commit() | ||
|
||
# assert 'closed' in str(e.value) | ||
|
||
|
||
def test_init_db_command(runner, monkeypatch): | ||
class Recorder(object): | ||
called = False | ||
|
||
def fake_init_db(): | ||
Recorder.called = True | ||
|
||
monkeypatch.setattr('woodcamrm.db.init_db', fake_init_db) | ||
result = runner.invoke(args=['init-db']) | ||
assert 'Initialized' in result.output | ||
assert Recorder.called |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from woodcamrm import create_app | ||
|
||
|
||
def test_config(): | ||
assert not create_app().testing | ||
assert create_app({'TESTING': True}).testing | ||
|
||
|
||
def test_hello(client): | ||
response = client.get('/hello') | ||
assert response.data == b'Hello, World!' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
from ensurepip import bootstrap | ||
import os | ||
|
||
from psycopg2.extras import RealDictCursor | ||
|
||
from flask import Flask | ||
|
||
|
||
def create_app(test_config=None): | ||
# create and configure the app | ||
app = Flask(__name__, instance_relative_config=True) | ||
app.config.from_mapping( | ||
SECRET_KEY=os.environ.get("SECRET_KEY"), | ||
DATABASE_SERVER=os.environ.get("DATABASE_SERVER"), | ||
DATABASE_PORT=os.environ.get("DATABASE_PORT"), | ||
DATABASE_NAME=os.environ.get("DATABASE_NAME"), | ||
DATABASE_USER=os.environ.get("DATABASE_USER"), | ||
DATABASE_PASSWORD=os.environ.get("DATABASE_PASSWORD"), | ||
DEFAULT_USER=os.environ.get("DEFAULT_USER"), | ||
DEFAULT_PASSWORD=os.environ.get("DEFAULT_PASSWORD"), | ||
) | ||
|
||
if test_config is None: | ||
# load the instance config, if it exists, when not testing | ||
app.config.from_pyfile('config.py', silent=True) | ||
else: | ||
# load the test config if passed in | ||
app.config.from_mapping(test_config) | ||
|
||
# ensure the instance folder exists | ||
try: | ||
os.makedirs(app.instance_path) | ||
except OSError: | ||
pass | ||
|
||
from . import db | ||
db.init_app(app) | ||
|
||
# List all stations for sidebar | ||
@app.context_processor | ||
def inject_pages(): | ||
database = db.get_db() | ||
cur = database.cursor(cursor_factory=RealDictCursor) | ||
cur.execute(f"SELECT id, common_name FROM stations;") | ||
stations = cur.fetchall() | ||
cur.close() | ||
|
||
return dict(pages=stations) | ||
|
||
from . import auth | ||
app.register_blueprint(auth.bp) | ||
|
||
from . import station | ||
app.register_blueprint(station.bp) | ||
|
||
from . import home | ||
app.register_blueprint(home.bp) | ||
app.add_url_rule('/', endpoint='index') | ||
|
||
return app |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import threading | ||
import requests | ||
import urllib.parse | ||
import time | ||
from flask import Flask | ||
from flask_restful import Resource, Api | ||
|
||
app = Flask(__name__) | ||
api = Api(app) | ||
|
||
uptime_data = {'seconds': 0} | ||
hydrodata = {} | ||
hydrodata_api = "https://hubeau.eaufrance.fr/api/" | ||
|
||
def update_uptime(): | ||
while True: | ||
time.sleep(1) | ||
vals = {'seconds': uptime_data['seconds'] + 1} | ||
uptime_data.update(vals) | ||
|
||
uptime_thread = threading.Thread(name='update_uptime', target=update_uptime) | ||
uptime_thread.setDaemon(True) | ||
uptime_thread.start() | ||
|
||
class uptime(Resource): | ||
def get(self): | ||
return uptime_data | ||
|
||
def update_hydrodata(): | ||
while True: | ||
time.sleep(30) | ||
obs_url = urllib.parse.urljoin(hydrodata_api, "v1/hydrometrie/observations_tr") | ||
rep = requests.get(obs_url, data={"code_entite":"V2942010"}) | ||
data = rep.json()['data'][0] | ||
hydrodata.update(data) | ||
|
||
hydrodata_thread = threading.Thread(name='update_hydrodata', target=update_hydrodata) | ||
hydrodata_thread.setDaemon(True) | ||
hydrodata_thread.start() | ||
|
||
class hydro(Resource): | ||
def get(self): | ||
return hydrodata | ||
|
||
|
||
@app.route("/") | ||
def root_page(): | ||
return hydrodata | ||
|
||
api.add_resource(uptime, '/api/uptime') | ||
api.add_resource(hydro, '/api/hydro') | ||
|
||
if __name__ == "__main__": | ||
app.run() |
Oops, something went wrong.