diff --git a/backend/app/app/api/api_v1/api.py b/backend/app/app/api/api_v1/api.py index 96dec82..cc2e2a8 100644 --- a/backend/app/app/api/api_v1/api.py +++ b/backend/app/app/api/api_v1/api.py @@ -2,7 +2,6 @@ from fastapi import APIRouter, Depends, Security -from app.core import config from app.api.api_v1.endpoints import login, users, utils from app.api.api_v1.endpoints.farms import farms, info, logs, assets, terms, areas from app.api.utils.security import get_farm_access diff --git a/backend/app/app/api/api_v1/endpoints/login.py b/backend/app/app/api/api_v1/endpoints/login.py index 148ce12..1c193e2 100644 --- a/backend/app/app/api/api_v1/endpoints/login.py +++ b/backend/app/app/api/api_v1/endpoints/login.py @@ -8,7 +8,7 @@ from app import crud from app.api.utils.db import get_db from app.api.utils.security import get_current_user -from app.core import config +from app.core.config import settings from app.core.jwt import create_access_token from app.core.security import get_password_hash from app.models.user import User as DBUser @@ -40,7 +40,7 @@ def login_access_token( raise HTTPException(status_code=400, detail="Incorrect email or password") elif not crud.user.is_active(user): raise HTTPException(status_code=400, detail="Inactive user") - access_token_expires = timedelta(minutes=config.ACCESS_TOKEN_EXPIRE_MINUTES) + access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) logger.debug(f"New user login with scopes: {form_data.scopes}") return { "access_token": create_access_token( diff --git a/backend/app/app/api/api_v1/endpoints/users.py b/backend/app/app/api/api_v1/endpoints/users.py index 33f91d4..b257428 100644 --- a/backend/app/app/api/api_v1/endpoints/users.py +++ b/backend/app/app/api/api_v1/endpoints/users.py @@ -8,7 +8,7 @@ from app import crud from app.api.utils.db import get_db from app.api.utils.security import get_current_active_superuser, get_current_active_user -from app.core import config +from app.core.config import settings from app.models.user import User as DBUser from app.schemas.user import User, UserCreate, UserInDB, UserUpdate from app.utils import send_new_account_email @@ -47,7 +47,7 @@ def create_user( detail="The user with this username already exists in the system.", ) user = crud.user.create(db, user_in=user_in) - if config.EMAILS_ENABLED and user_in.email: + if settings.EMAILS_ENABLED and user_in.email: send_new_account_email( email_to=user_in.email, username=user_in.email, password=user_in.password ) @@ -100,7 +100,7 @@ def create_user_open( """ Create new user without the need to be logged in. """ - if not config.USERS_OPEN_REGISTRATION: + if not settings.USERS_OPEN_REGISTRATION: raise HTTPException( status_code=403, detail="Open user resgistration is forbidden on this server", diff --git a/backend/app/app/api/utils/security.py b/backend/app/app/api/utils/security.py index e08c278..7113620 100644 --- a/backend/app/app/api/utils/security.py +++ b/backend/app/app/api/utils/security.py @@ -9,7 +9,7 @@ from app import crud from app.api.utils.db import get_db -from app.core import config +from app.core.config import settings from app.core.jwt import ALGORITHM from app.models.user import User from app.schemas.token import TokenData, FarmAccess @@ -31,12 +31,12 @@ } optional_oauth2 = OAuth2PasswordBearer( - tokenUrl="/api/v1/login/access-token", + tokenUrl=f"{settings.API_V1_STR}/login/access-token", scopes=oauth_scopes, auto_error=False ) reusable_oauth2 = OAuth2PasswordBearer( - tokenUrl="/api/v1/login/access-token", + tokenUrl=f"{settings.API_V1_STR}/login/access-token", scopes=oauth_scopes, auto_error=True ) @@ -193,7 +193,7 @@ def get_farm_access_allow_public( farm_access = None # If open registration is enabled, allow minimal access. - if config.AGGREGATOR_OPEN_FARM_REGISTRATION is True: + if settings.AGGREGATOR_OPEN_FARM_REGISTRATION is True: farm_access = FarmAccess(scopes=[], farm_id_list=[], all_farms=False) # Still check for a request with higher permissions. @@ -217,7 +217,7 @@ def get_farm_access_allow_public( def _validate_token(token): - payload = jwt.decode(token, config.SECRET_KEY, algorithms=[ALGORITHM]) + payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[ALGORITHM]) user_id: int = payload.get("sub", None) farm_id = payload.get("farm_id", []) token_scopes = payload.get("scopes", []) diff --git a/backend/app/app/core/config.py b/backend/app/app/core/config.py index 16b94b8..a3ce8f9 100644 --- a/backend/app/app/core/config.py +++ b/backend/app/app/core/config.py @@ -1,70 +1,103 @@ import os +import secrets +from typing import List +from pydantic import AnyHttpUrl, BaseSettings, EmailStr, HttpUrl, PostgresDsn, validator from celery.schedules import crontab -def getenv_boolean(var_name, default_value=False): - result = default_value - env_value = os.getenv(var_name) - if env_value is not None: - result = env_value.upper() in ("TRUE", "1") - return result - - -API_V1_STR = "/api/v1" - -SECRET_KEY = os.getenvb(b"SECRET_KEY") -if not SECRET_KEY: - SECRET_KEY = os.urandom(32) - -ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 8 # 60 minutes * 24 hours * 8 days = 8 days - -SERVER_NAME = os.getenv("SERVER_NAME") -SERVER_HOST = os.getenv("SERVER_HOST") -BACKEND_CORS_ORIGINS = os.getenv( - "BACKEND_CORS_ORIGINS" -) # a string of origins separated by commas, e.g: "http://localhost, http://localhost:4200, http://localhost:3000, http://localhost:8080, http://local.dockertoolbox.tiangolo.com" -PROJECT_NAME = os.getenv("PROJECT_NAME") -SENTRY_DSN = os.getenv("SENTRY_DSN") - -POSTGRES_SERVER = os.getenv("POSTGRES_SERVER") -POSTGRES_USER = os.getenv("POSTGRES_USER") -POSTGRES_PASSWORD = os.getenv("POSTGRES_PASSWORD") -POSTGRES_DB = os.getenv("POSTGRES_DB") -SQLALCHEMY_DATABASE_URI = ( - f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_SERVER}/{POSTGRES_DB}" -) - -SMTP_TLS = getenv_boolean("SMTP_TLS", True) -SMTP_PORT = None -_SMTP_PORT = os.getenv("SMTP_PORT") -if _SMTP_PORT is not None: - SMTP_PORT = int(_SMTP_PORT) -SMTP_HOST = os.getenv("SMTP_HOST") -SMTP_USER = os.getenv("SMTP_USER") -SMTP_PASSWORD = os.getenv("SMTP_PASSWORD") -EMAILS_FROM_EMAIL = os.getenv("EMAILS_FROM_EMAIL") -EMAILS_FROM_NAME = PROJECT_NAME -EMAIL_RESET_TOKEN_EXPIRE_HOURS = 48 -EMAIL_TEMPLATES_DIR = "/app/app/email-templates/build" -EMAILS_ENABLED = SMTP_HOST and SMTP_PORT and EMAILS_FROM_EMAIL - -FIRST_SUPERUSER = os.getenv("FIRST_SUPERUSER") -FIRST_SUPERUSER_PASSWORD = os.getenv("FIRST_SUPERUSER_PASSWORD") - -USERS_OPEN_REGISTRATION = getenv_boolean("USERS_OPEN_REGISTRATION") -CELERY_WORKER_PING_INTERVAL = crontab(minute='0', hour='0,12') - -TEST_FARM_NAME = "farmOS-test-instance" -TEST_FARM_URL = os.getenv("TEST_FARM_URL") -TEST_FARM_USERNAME = os.getenv("TEST_FARM_USERNAME") -TEST_FARM_PASSWORD = os.getenv("TEST_FARM_PASSWORD") +class Settings(BaseSettings): + API_V1_STR: str = "/api/v1" + + SECRET_KEY: str = secrets.token_urlsafe(32) + + ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 8 # 60 minutes * 24 hours * 8 days = 8 days + + SERVER_NAME: str + SERVER_HOST: AnyHttpUrl + # BACKEND_CORS_ORIGINS is a JSON-formatted list of origins. + # e.g: '["http://localhost", "http://localhost:4200"]' + + BACKEND_CORS_ORIGINS: List[AnyHttpUrl] = [] + + @validator("BACKEND_CORS_ORIGINS", pre=True) + def assemble_cors_origins(cls, v): + if isinstance(v, str): + return [i.strip() for i in v.split(",")] + return v + + PROJECT_NAME: str + + SENTRY_DSN: HttpUrl = None + @validator("SENTRY_DSN", pre=True) + def sentry_dsn_can_be_blank(cls, v): + if len(v) == 0: + return None + return v + + POSTGRES_SERVER: str + POSTGRES_USER: str + POSTGRES_PASSWORD: str + POSTGRES_DB: str + SQLALCHEMY_DATABASE_URI: PostgresDsn = None + + @validator("SQLALCHEMY_DATABASE_URI", pre=True) + def assemble_db_connection(cls, v, values): + if isinstance(v, str): + return v + return PostgresDsn.build( + scheme="postgresql", + user=values.get("POSTGRES_USER"), + password=values.get("POSTGRES_PASSWORD"), + host=values.get("POSTGRES_SERVER"), + path=f"/{values.get('POSTGRES_DB') or ''}", + ) + + SMTP_TLS: bool = True + SMTP_PORT: int = None + SMTP_HOST: str = None + SMTP_USER: str = None + SMTP_PASSWORD: str = None + EMAILS_FROM_EMAIL: EmailStr = None + EMAILS_FROM_NAME: str = None + + @validator("EMAILS_FROM_NAME") + def get_project_name(cls, v, values): + if not v: + return values["PROJECT_NAME"] + return v + + EMAIL_RESET_TOKEN_EXPIRE_HOURS: int = 48 + EMAIL_TEMPLATES_DIR: str = "/app/app/email-templates/build" + EMAILS_ENABLED: bool = False + + @validator("EMAILS_ENABLED", pre=True) + def get_emails_enabled(cls, v, values): + return bool( + values.get("SMTP_HOST") + and values.get("SMTP_PORT") + and values.get("EMAILS_FROM_EMAIL") + ) + + EMAIL_TEST_USER: EmailStr = "test@example.com" + + FIRST_SUPERUSER: EmailStr + FIRST_SUPERUSER_PASSWORD: str + + USERS_OPEN_REGISTRATION: bool = False + + TEST_FARM_NAME: str = "farmOS-test-instance" + TEST_FARM_URL: HttpUrl = None + TEST_FARM_USERNAME: str = None + TEST_FARM_PASSWORD: str = None + + AGGREGATOR_OPEN_FARM_REGISTRATION: bool = False + AGGREGATOR_INVITE_FARM_REGISTRATION: bool = False + FARM_ACTIVE_AFTER_REGISTRATION: bool = False + + class Config: + case_sensitive = True -def has_valid_test_configuration(): - """Check if sufficient info is provided to run integration tests with a farmOS server.""" - return TEST_FARM_URL is not None and TEST_FARM_USERNAME is not None and TEST_FARM_PASSWORD is not None - +CELERY_WORKER_PING_INTERVAL = crontab(minute='0', hour='0,12') -AGGREGATOR_OPEN_FARM_REGISTRATION = getenv_boolean("AGGREGATOR_OPEN_FARM_REGISTRATION") -AGGREGATOR_INVITE_FARM_REGISTRATION = getenv_boolean("AGGREGATOR_INVITE_FARM_REGISTRATION") -FARM_ACTIVE_AFTER_REGISTRATION = getenv_boolean("FARM_ACTIVE_AFTER_REGISTRATION") +settings = Settings() diff --git a/backend/app/app/core/jwt.py b/backend/app/app/core/jwt.py index ed57233..dd548aa 100644 --- a/backend/app/app/core/jwt.py +++ b/backend/app/app/core/jwt.py @@ -3,7 +3,7 @@ import jwt -from app.core import config +from app.core.config import settings ALGORITHM = "HS256" @@ -15,12 +15,12 @@ def create_access_token(*, data: dict, expires_delta: timedelta = None): else: expire = datetime.utcnow() + timedelta(minutes=15) to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, config.SECRET_KEY, algorithm=ALGORITHM) + encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt def create_farm_api_token(farm_id: List[int], scopes: List[str]): - delta = timedelta(hours=config.EMAIL_RESET_TOKEN_EXPIRE_HOURS) + delta = timedelta(hours=settings.EMAIL_RESET_TOKEN_EXPIRE_HOURS) now = datetime.utcnow() expires = now + delta encoded_jwt = jwt.encode( @@ -30,7 +30,7 @@ def create_farm_api_token(farm_id: List[int], scopes: List[str]): "farm_id": farm_id, "scopes": scopes, }, - config.SECRET_KEY, + settings.SECRET_KEY, algorithm=ALGORITHM, ) return encoded_jwt diff --git a/backend/app/app/crud/farm.py b/backend/app/app/crud/farm.py index b378775..8640a2a 100644 --- a/backend/app/app/crud/farm.py +++ b/backend/app/app/crud/farm.py @@ -6,7 +6,7 @@ from sqlalchemy.orm import Session from app import crud -from app.core import config +from app.core.config import settings from app.models.farm import Farm from app.schemas.farm import FarmCreate, FarmUpdate from app.models.farm_token import FarmToken @@ -55,7 +55,7 @@ def create(db_session: Session, *, farm_in: FarmCreate) -> Farm: logging.debug(f"New farm provided 'active = {farm_in.active}'") active = farm_in.active # Enable farm profile if configured and not overridden above. - elif config.FARM_ACTIVE_AFTER_REGISTRATION: + elif settings.FARM_ACTIVE_AFTER_REGISTRATION: logging.debug(f"FARM_ACTIVE_AFTER_REGISTRATION is enabled. New farm will be active.") active = True diff --git a/backend/app/app/db/init_db.py b/backend/app/app/db/init_db.py index 1521297..96ba33c 100644 --- a/backend/app/app/db/init_db.py +++ b/backend/app/app/db/init_db.py @@ -1,5 +1,5 @@ from app import crud -from app.core import config +from app.core.config import settings from app.schemas.user import UserCreate # make sure all SQL Alchemy schemas are imported before initializing DB @@ -13,11 +13,11 @@ def init_db(db_session): # the tables un-commenting the next line # Base.metadata.create_all(bind=engine) - user = crud.user.get_by_email(db_session, email=config.FIRST_SUPERUSER) + user = crud.user.get_by_email(db_session, email=settings.FIRST_SUPERUSER) if not user: user_in = UserCreate( - email=config.FIRST_SUPERUSER, - password=config.FIRST_SUPERUSER_PASSWORD, + email=settings.FIRST_SUPERUSER, + password=settings.FIRST_SUPERUSER_PASSWORD, is_superuser=True, ) user = crud.user.create(db_session, user_in=user_in) diff --git a/backend/app/app/db/session.py b/backend/app/app/db/session.py index e4698d5..b7bf6ea 100644 --- a/backend/app/app/db/session.py +++ b/backend/app/app/db/session.py @@ -1,9 +1,9 @@ from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session, sessionmaker -from app.core import config +from app.core.config import settings -engine = create_engine(config.SQLALCHEMY_DATABASE_URI, pool_pre_ping=True) +engine = create_engine(settings.SQLALCHEMY_DATABASE_URI, pool_pre_ping=True) db_session = scoped_session( sessionmaker(autocommit=False, autoflush=False, bind=engine) ) diff --git a/backend/app/app/main.py b/backend/app/app/main.py index 555a1f5..aca53c1 100644 --- a/backend/app/app/main.py +++ b/backend/app/app/main.py @@ -5,32 +5,25 @@ from starlette.requests import Request from app.api.api_v1.api import api_router -from app.core import config +from app.core.config import settings from app.db.session import Session # Configure logging. Change INFO to DEBUG for development logging. logging.basicConfig(level=logging.INFO) -app = FastAPI(title=config.PROJECT_NAME, openapi_url="/api/v1/openapi.json") - -# CORS -origins = [] +app = FastAPI(title=settings.PROJECT_NAME, openapi_url=f"{settings.API_V1_STR}/openapi.json") # Set all CORS enabled origins -if config.BACKEND_CORS_ORIGINS: - origins_raw = config.BACKEND_CORS_ORIGINS.split(",") - for origin in origins_raw: - use_origin = origin.strip() - origins.append(use_origin) +if settings.BACKEND_CORS_ORIGINS: app.add_middleware( CORSMiddleware, - allow_origins=origins, + allow_origins=[str(origin for origin in settings.BACKEND_CORS_ORIGINS)], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ), -app.include_router(api_router, prefix=config.API_V1_STR) +app.include_router(api_router, prefix=settings.API_V1_STR) @app.middleware("http") diff --git a/backend/app/app/tests/api/api_v1/test_farm.py b/backend/app/app/tests/api/api_v1/test_farm.py index b9aee6e..6485e5e 100644 --- a/backend/app/app/tests/api/api_v1/test_farm.py +++ b/backend/app/app/tests/api/api_v1/test_farm.py @@ -2,7 +2,7 @@ import pytest from app import crud -from app.core import config +from app.core.config import settings from app.db.session import db_session from app.schemas.farm import FarmCreate from app.tests.utils.utils import get_server_api, random_lower_string, get_scope_token_headers @@ -50,7 +50,7 @@ def test_create_delete_farm(farm_create_headers, farm_delete_headers): "token": token, } r = requests.post( - f"{server_api}{config.API_V1_STR}/farms/", + f"{server_api}{settings.API_V1_STR}/farms/", headers=farm_create_headers, json=data, ) @@ -72,7 +72,7 @@ def test_create_delete_farm(farm_create_headers, farm_delete_headers): # Delete the farm r = requests.delete( - f"{server_api}{config.API_V1_STR}/farms/{farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/{farm.id}", headers=farm_delete_headers, ) assert 200 <= r.status_code < 300 @@ -91,7 +91,7 @@ def test_create_farm_update_token(farm_create_headers, farm_update_headers, farm "scope": 'user_access', } r = requests.post( - f"{server_api}{config.API_V1_STR}/farms/", + f"{server_api}{settings.API_V1_STR}/farms/", headers=farm_create_headers, json=data, ) @@ -116,7 +116,7 @@ def test_create_farm_update_token(farm_create_headers, farm_update_headers, farm "token": token, } r = requests.put( - f"{server_api}{config.API_V1_STR}/farms/{farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/{farm.id}", headers=farm_update_headers, json=data, ) @@ -139,7 +139,7 @@ def test_create_farm_update_token(farm_create_headers, farm_update_headers, farm # Delete the farm r = requests.delete( - f"{server_api}{config.API_V1_STR}/farms/{farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/{farm.id}", headers=farm_delete_headers, ) assert 200 <= r.status_code < 300 @@ -167,7 +167,7 @@ def test_create_farm_delete_token(farm_create_headers, farm_update_headers, farm "token": token, } r = requests.post( - f"{server_api}{config.API_V1_STR}/farms/", + f"{server_api}{settings.API_V1_STR}/farms/", headers=farm_create_headers, json=data, ) @@ -194,7 +194,7 @@ def test_create_farm_delete_token(farm_create_headers, farm_update_headers, farm "token": new_token, } r = requests.put( - f"{server_api}{config.API_V1_STR}/farms/{farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/{farm.id}", headers=farm_update_headers, json=data, ) @@ -217,7 +217,7 @@ def test_create_farm_delete_token(farm_create_headers, farm_update_headers, farm # Delete the farm r = requests.delete( - f"{server_api}{config.API_V1_STR}/farms/{farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/{farm.id}", headers=farm_delete_headers, ) assert 200 <= r.status_code < 300 @@ -228,7 +228,7 @@ def test_get_all_farms(test_farm, farm_read_headers): farm_id = test_farm.id r = requests.get( - f"{server_api}{config.API_V1_STR}/farms/", + f"{server_api}{settings.API_V1_STR}/farms/", headers=farm_read_headers, ) assert 200 <= r.status_code < 300 @@ -243,7 +243,7 @@ def test_get_farm_by_id(test_farm, farm_read_headers): farm_id = test_farm.id r = requests.get( - f"{server_api}{config.API_V1_STR}/farms/{farm_id}", + f"{server_api}{settings.API_V1_STR}/farms/{farm_id}", headers=farm_read_headers, ) assert 200 <= r.status_code < 300 @@ -252,11 +252,11 @@ def test_get_farm_by_id(test_farm, farm_read_headers): assert farm.farm_name == response["farm_name"] """ -Skip this test for now. Need more config to test configurable public/private endpoints. +Skip this test for now. Need more settings to test settingsurable public/private endpoints. def test_farm_create_oauth_scope(): server_api = get_server_api() - r = requests.post(f"{server_api}{config.API_V1_STR}/farms/") + r = requests.post(f"{server_api}{settings.API_V1_STR}/farms/") assert r.status_code == 401 """ @@ -264,26 +264,26 @@ def test_farm_create_oauth_scope(): def test_farm_read_oauth_scope(): server_api = get_server_api() - r = requests.get(f"{server_api}{config.API_V1_STR}/farms/") + r = requests.get(f"{server_api}{settings.API_V1_STR}/farms/") assert r.status_code == 401 def test_farm_read_by_id_oauth_scope(): server_api = get_server_api() - r = requests.get(f"{server_api}{config.API_V1_STR}/farms/1") + r = requests.get(f"{server_api}{settings.API_V1_STR}/farms/1") assert r.status_code == 401 def test_farm_update_oauth_scope(): server_api = get_server_api() - r = requests.put(f"{server_api}{config.API_V1_STR}/farms/1") + r = requests.put(f"{server_api}{settings.API_V1_STR}/farms/1") assert r.status_code == 401 def test_farm_delete_oauth_scope(): server_api = get_server_api() - r = requests.get(f"{server_api}{config.API_V1_STR}/farms/1") + r = requests.get(f"{server_api}{settings.API_V1_STR}/farms/1") assert r.status_code == 401 diff --git a/backend/app/app/tests/api/api_v1/test_farm_areas.py b/backend/app/app/tests/api/api_v1/test_farm_areas.py index 88dad2d..5ab6e99 100644 --- a/backend/app/app/tests/api/api_v1/test_farm_areas.py +++ b/backend/app/app/tests/api/api_v1/test_farm_areas.py @@ -1,7 +1,7 @@ import requests import pytest -from app.core import config +from app.core.config import settings from app.tests.utils.utils import farmOS_testing_server, get_server_api, get_scope_token_headers @@ -15,7 +15,7 @@ def areas_vid(test_farm, all_scopes_token_headers): server_api = get_server_api() response = requests.get( - f"{server_api}{config.API_V1_STR}/farms/info/?farm_id={test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/info/?farm_id={test_farm.id}", headers=all_scopes_token_headers, ) # Check response @@ -48,7 +48,7 @@ def test_create_area(test_farm, test_area, areas_vid, farm_areas_headers): print(areas_vid) response = requests.post( - f"{server_api}{config.API_V1_STR}/farms/areas/?farm_id={test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/areas/?farm_id={test_farm.id}", headers=farm_areas_headers, json=data, ) @@ -68,7 +68,7 @@ def test_create_area(test_farm, test_area, areas_vid, farm_areas_headers): # Check that the created area has correct attributes response = requests.get( - f"{server_api}{config.API_V1_STR}/farms/areas/?farm_id={test_farm.id}&tid={test_area['id']}", + f"{server_api}{settings.API_V1_STR}/farms/areas/?farm_id={test_farm.id}&tid={test_area['id']}", headers=farm_areas_headers, json=data, ) @@ -89,7 +89,7 @@ def test_get_areas(test_farm, farm_areas_headers): server_api = get_server_api() r = requests.get( - f"{server_api}{config.API_V1_STR}/farms/areas/?farm_id={test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/areas/?farm_id={test_farm.id}", headers=farm_areas_headers, ) # Check response @@ -126,7 +126,7 @@ def test_update_area(test_farm, test_area, areas_vid, farm_areas_headers): data['vocabulary'] = areas_vid response = requests.put( - f"{server_api}{config.API_V1_STR}/farms/areas/?farm_id={test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/areas/?farm_id={test_farm.id}", headers=farm_areas_headers, json=data, ) @@ -143,7 +143,7 @@ def test_update_area(test_farm, test_area, areas_vid, farm_areas_headers): # Check that the updated area has correct attributes response = requests.get( - f"{server_api}{config.API_V1_STR}/farms/areas/?farm_id={test_farm.id}&tid={test_area['id']}", + f"{server_api}{settings.API_V1_STR}/farms/areas/?farm_id={test_farm.id}&tid={test_area['id']}", headers=farm_areas_headers, ) # Check response @@ -163,7 +163,7 @@ def test_delete_area(test_farm, test_area, farm_areas_headers): server_api = get_server_api() response = requests.delete( - f"{server_api}{config.API_V1_STR}/farms/areas/?farm_id={test_farm.id}&id={test_area['id']}", + f"{server_api}{settings.API_V1_STR}/farms/areas/?farm_id={test_farm.id}&id={test_area['id']}", headers=farm_areas_headers, ) @@ -176,5 +176,5 @@ def test_delete_area(test_farm, test_area, farm_areas_headers): def test_farm_areas_oauth_scope(): server_api = get_server_api() - r = requests.get(f"{server_api}{config.API_V1_STR}/farms/areas") + r = requests.get(f"{server_api}{settings.API_V1_STR}/farms/areas") assert r.status_code == 401 diff --git a/backend/app/app/tests/api/api_v1/test_farm_assets.py b/backend/app/app/tests/api/api_v1/test_farm_assets.py index aad5c6a..fefbe36 100644 --- a/backend/app/app/tests/api/api_v1/test_farm_assets.py +++ b/backend/app/app/tests/api/api_v1/test_farm_assets.py @@ -1,7 +1,7 @@ import requests import pytest -from app.core import config +from app.core.config import settings from app.tests.utils.utils import farmOS_testing_server, get_server_api, get_scope_token_headers @@ -17,7 +17,7 @@ def test_create_asset(test_farm, test_asset, farm_assets_headers): data = test_asset response = requests.post( - f"{server_api}{config.API_V1_STR}/farms/assets/?farm_id={test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/assets/?farm_id={test_farm.id}", headers=farm_assets_headers, json=data, ) @@ -37,7 +37,7 @@ def test_create_asset(test_farm, test_asset, farm_assets_headers): # Check that the creats asset has correct attributes response = requests.get( - f"{server_api}{config.API_V1_STR}/farms/assets/?farm_id={test_farm.id}&id={test_asset['id']}", + f"{server_api}{settings.API_V1_STR}/farms/assets/?farm_id={test_farm.id}&id={test_asset['id']}", headers=farm_assets_headers, json=data, ) @@ -58,7 +58,7 @@ def test_get_assets(test_farm, farm_assets_headers): server_api = get_server_api() r = requests.get( - f"{server_api}{config.API_V1_STR}/farms/assets/?farm_id={test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/assets/?farm_id={test_farm.id}", headers=farm_assets_headers, ) # Check response @@ -92,7 +92,7 @@ def test_update_asset(test_farm, test_asset, farm_assets_headers): data = test_asset response = requests.put( - f"{server_api}{config.API_V1_STR}/farms/assets/?farm_id={test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/assets/?farm_id={test_farm.id}", headers=farm_assets_headers, json=data, ) @@ -109,7 +109,7 @@ def test_update_asset(test_farm, test_asset, farm_assets_headers): # Check that the updated asset has correct attributes response = requests.get( - f"{server_api}{config.API_V1_STR}/farms/assets/?farm_id={test_farm.id}&id={test_asset['id']}", + f"{server_api}{settings.API_V1_STR}/farms/assets/?farm_id={test_farm.id}&id={test_asset['id']}", headers=farm_assets_headers, ) # Check response @@ -129,7 +129,7 @@ def test_delete_asset(test_farm, test_asset, farm_assets_headers): server_api = get_server_api() response = requests.delete( - f"{server_api}{config.API_V1_STR}/farms/assets/?farm_id={test_farm.id}&id={test_asset['id']}", + f"{server_api}{settings.API_V1_STR}/farms/assets/?farm_id={test_farm.id}&id={test_asset['id']}", headers=farm_assets_headers, ) @@ -142,5 +142,5 @@ def test_delete_asset(test_farm, test_asset, farm_assets_headers): def test_farm_assets_oauth_scope(): server_api = get_server_api() - r = requests.get(f"{server_api}{config.API_V1_STR}/farms/assets") + r = requests.get(f"{server_api}{settings.API_V1_STR}/farms/assets") assert r.status_code == 401 diff --git a/backend/app/app/tests/api/api_v1/test_farm_authorize.py b/backend/app/app/tests/api/api_v1/test_farm_authorize.py index 7170cc1..bb72497 100644 --- a/backend/app/app/tests/api/api_v1/test_farm_authorize.py +++ b/backend/app/app/tests/api/api_v1/test_farm_authorize.py @@ -3,7 +3,7 @@ import requests import pytest -from app.core import config +from app.core.config import settings from app.schemas.farm_token import FarmAuthorizationParams from app.tests.utils.utils import farmOS_testing_server, get_server_api, random_lower_string, get_scope_token_headers from app.api.utils.security import _validate_token @@ -26,7 +26,7 @@ def test_authorize_farm(test_farm, farm_authorize_headers): ) r = requests.post( - f"{server_api}{config.API_V1_STR}/utils/authorize-farm/{test_farm.id}", + f"{server_api}{settings.API_V1_STR}/utils/authorize-farm/{test_farm.id}", headers=farm_authorize_headers, json=data.dict(), ) @@ -51,16 +51,16 @@ def test_authorize_farm(test_farm, farm_authorize_headers): def test_farm_authorize_oauth_scope(test_farm): server_api = get_server_api() - r = requests.post(f"{server_api}{config.API_V1_STR}/utils/authorize-farm/{test_farm.id}") + r = requests.post(f"{server_api}{settings.API_V1_STR}/utils/authorize-farm/{test_farm.id}") assert r.status_code == 401 def test_get_farm_auth_link(test_farm, superuser_token_headers): server_api = get_server_api() - server_host = config.SERVER_HOST + server_host = settings.SERVER_HOST r = requests.post( - f"{server_api}{config.API_V1_STR}/utils/farm-auth-link/{test_farm.id}", + f"{server_api}{settings.API_V1_STR}/utils/farm-auth-link/{test_farm.id}", headers=superuser_token_headers, ) assert 200 <= r.status_code < 300 @@ -95,7 +95,7 @@ def test_get_farm_auth_link(test_farm, superuser_token_headers): # Test that the api_token has access to read /api/v1/farms/{id} r = requests.get( - f"{server_api}{config.API_V1_STR}/farms/{test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/{test_farm.id}", headers={'api-token': token}, ) assert 200 <= r.status_code < 300 @@ -113,7 +113,7 @@ def test_get_farm_auth_link(test_farm, superuser_token_headers): ) r = requests.post( - f"{server_api}{config.API_V1_STR}/utils/authorize-farm/{test_farm.id}", + f"{server_api}{settings.API_V1_STR}/utils/authorize-farm/{test_farm.id}", headers={'api-token': token}, json=data.dict(), ) diff --git a/backend/app/app/tests/api/api_v1/test_farm_logs.py b/backend/app/app/tests/api/api_v1/test_farm_logs.py index 91fbe73..ed4a251 100644 --- a/backend/app/app/tests/api/api_v1/test_farm_logs.py +++ b/backend/app/app/tests/api/api_v1/test_farm_logs.py @@ -1,7 +1,7 @@ import requests import pytest -from app.core import config +from app.core.config import settings from app.tests.utils.utils import farmOS_testing_server, get_server_api, get_scope_token_headers @@ -15,7 +15,7 @@ def test_get_logs(test_farm, farm_logs_headers): server_api = get_server_api() r = requests.get( - f"{server_api}{config.API_V1_STR}/farms/logs/?farm_id={test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/logs/?farm_id={test_farm.id}", headers=farm_logs_headers, ) # Check response @@ -46,7 +46,7 @@ def test_create_log(test_farm, test_log, farm_logs_headers): data = test_log response = requests.post( - f"{server_api}{config.API_V1_STR}/farms/logs/?farm_id={test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/logs/?farm_id={test_farm.id}", headers=farm_logs_headers, json=data, ) @@ -66,7 +66,7 @@ def test_create_log(test_farm, test_log, farm_logs_headers): # Check that the created log has correct attributes response = requests.get( - f"{server_api}{config.API_V1_STR}/farms/logs/?farm_id={test_farm.id}&id={test_log['id']}", + f"{server_api}{settings.API_V1_STR}/farms/logs/?farm_id={test_farm.id}&id={test_log['id']}", headers=farm_logs_headers, json=data, ) @@ -92,7 +92,7 @@ def test_update_log(test_farm, test_log, farm_logs_headers): data = test_log response = requests.put( - f"{server_api}{config.API_V1_STR}/farms/logs/?farm_id={test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/logs/?farm_id={test_farm.id}", headers=farm_logs_headers, json=data, ) @@ -109,7 +109,7 @@ def test_update_log(test_farm, test_log, farm_logs_headers): # Check that the updated log has correct attributes response = requests.get( - f"{server_api}{config.API_V1_STR}/farms/logs/?farm_id={test_farm.id}&id={test_log['id']}", + f"{server_api}{settings.API_V1_STR}/farms/logs/?farm_id={test_farm.id}&id={test_log['id']}", headers=farm_logs_headers, ) # Check response @@ -129,7 +129,7 @@ def test_delete_log(test_farm, test_log, farm_logs_headers): server_api = get_server_api() response = requests.delete( - f"{server_api}{config.API_V1_STR}/farms/logs/?farm_id={test_farm.id}&id={test_log['id']}", + f"{server_api}{settings.API_V1_STR}/farms/logs/?farm_id={test_farm.id}&id={test_log['id']}", headers=farm_logs_headers, ) @@ -142,5 +142,5 @@ def test_delete_log(test_farm, test_log, farm_logs_headers): def test_farm_logs_oauth_scope(): server_api = get_server_api() - r = requests.get(f"{server_api}{config.API_V1_STR}/farms/logs") + r = requests.get(f"{server_api}{settings.API_V1_STR}/farms/logs") assert r.status_code == 401 diff --git a/backend/app/app/tests/api/api_v1/test_farm_terms.py b/backend/app/app/tests/api/api_v1/test_farm_terms.py index 523088b..5c113ca 100644 --- a/backend/app/app/tests/api/api_v1/test_farm_terms.py +++ b/backend/app/app/tests/api/api_v1/test_farm_terms.py @@ -1,7 +1,7 @@ import requests import pytest -from app.core import config +from app.core.config import settings from app.tests.utils.utils import farmOS_testing_server, get_server_api, get_scope_token_headers @@ -17,7 +17,7 @@ def test_create_term(test_farm, test_term, farm_terms_headers): data = test_term response = requests.post( - f"{server_api}{config.API_V1_STR}/farms/terms/?farm_id={test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/terms/?farm_id={test_farm.id}", headers=farm_terms_headers, json=data, ) @@ -37,7 +37,7 @@ def test_create_term(test_farm, test_term, farm_terms_headers): # Check that the creats term has correct attributes response = requests.get( - f"{server_api}{config.API_V1_STR}/farms/terms/?farm_id={test_farm.id}&tid={test_term['id']}", + f"{server_api}{settings.API_V1_STR}/farms/terms/?farm_id={test_farm.id}&tid={test_term['id']}", headers=farm_terms_headers, json=data, ) @@ -58,7 +58,7 @@ def test_get_terms(test_farm, farm_terms_headers): server_api = get_server_api() r = requests.get( - f"{server_api}{config.API_V1_STR}/farms/terms/?farm_id={test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/terms/?farm_id={test_farm.id}", headers=farm_terms_headers, ) # Check response @@ -92,7 +92,7 @@ def test_update_term(test_farm, test_term, farm_terms_headers): data = test_term response = requests.put( - f"{server_api}{config.API_V1_STR}/farms/terms/?farm_id={test_farm.id}", + f"{server_api}{settings.API_V1_STR}/farms/terms/?farm_id={test_farm.id}", headers=farm_terms_headers, json=data, ) @@ -109,7 +109,7 @@ def test_update_term(test_farm, test_term, farm_terms_headers): # Check that the updated term has correct attributes response = requests.get( - f"{server_api}{config.API_V1_STR}/farms/terms/?farm_id={test_farm.id}&tid={test_term['id']}", + f"{server_api}{settings.API_V1_STR}/farms/terms/?farm_id={test_farm.id}&tid={test_term['id']}", headers=farm_terms_headers, ) # Check response @@ -129,7 +129,7 @@ def test_delete_term(test_farm, test_term, farm_terms_headers): server_api = get_server_api() response = requests.delete( - f"{server_api}{config.API_V1_STR}/farms/terms/?farm_id={test_farm.id}&tid={test_term['id']}", + f"{server_api}{settings.API_V1_STR}/farms/terms/?farm_id={test_farm.id}&tid={test_term['id']}", headers=farm_terms_headers, ) @@ -142,5 +142,5 @@ def test_delete_term(test_farm, test_term, farm_terms_headers): def test_farm_terms_oauth_scope(): server_api = get_server_api() - r = requests.get(f"{server_api}{config.API_V1_STR}/farms/terms") + r = requests.get(f"{server_api}{settings.API_V1_STR}/farms/terms") assert r.status_code == 401 diff --git a/backend/app/app/tests/api/api_v1/test_login.py b/backend/app/app/tests/api/api_v1/test_login.py index 015ec00..26506f8 100644 --- a/backend/app/app/tests/api/api_v1/test_login.py +++ b/backend/app/app/tests/api/api_v1/test_login.py @@ -1,17 +1,17 @@ import requests -from app.core import config +from app.core.config import settings from app.tests.utils.utils import get_server_api def test_get_access_token(): server_api = get_server_api() login_data = { - "username": config.FIRST_SUPERUSER, - "password": config.FIRST_SUPERUSER_PASSWORD, + "username": settings.FIRST_SUPERUSER, + "password": settings.FIRST_SUPERUSER_PASSWORD, } r = requests.post( - f"{server_api}{config.API_V1_STR}/login/access-token", data=login_data + f"{server_api}{settings.API_V1_STR}/login/access-token", data=login_data ) tokens = r.json() assert r.status_code == 200 @@ -22,7 +22,7 @@ def test_get_access_token(): def test_use_access_token(superuser_token_headers): server_api = get_server_api() r = requests.post( - f"{server_api}{config.API_V1_STR}/login/test-token", + f"{server_api}{settings.API_V1_STR}/login/test-token", headers=superuser_token_headers, ) result = r.json() diff --git a/backend/app/app/tests/api/api_v1/test_users.py b/backend/app/app/tests/api/api_v1/test_users.py index 04f3c34..f1f752a 100644 --- a/backend/app/app/tests/api/api_v1/test_users.py +++ b/backend/app/app/tests/api/api_v1/test_users.py @@ -1,7 +1,7 @@ import requests from app import crud -from app.core import config +from app.core.config import settings from app.db.session import db_session from app.schemas.user import UserCreate from app.tests.utils.user import user_authentication_headers @@ -11,13 +11,13 @@ def test_get_users_superuser_me(superuser_token_headers): server_api = get_server_api() r = requests.get( - f"{server_api}{config.API_V1_STR}/users/me", headers=superuser_token_headers + f"{server_api}{settings.API_V1_STR}/users/me", headers=superuser_token_headers ) current_user = r.json() assert current_user assert current_user["is_active"] is True assert current_user["is_superuser"] - assert current_user["email"] == config.FIRST_SUPERUSER + assert current_user["email"] == settings.FIRST_SUPERUSER def test_create_user_new_email(superuser_token_headers): @@ -26,7 +26,7 @@ def test_create_user_new_email(superuser_token_headers): password = random_lower_string() data = {"email": username, "password": password} r = requests.post( - f"{server_api}{config.API_V1_STR}/users/", + f"{server_api}{settings.API_V1_STR}/users/", headers=superuser_token_headers, json=data, ) @@ -44,7 +44,7 @@ def test_get_existing_user(superuser_token_headers): user = crud.user.create(db_session, user_in=user_in) user_id = user.id r = requests.get( - f"{server_api}{config.API_V1_STR}/users/{user_id}", + f"{server_api}{settings.API_V1_STR}/users/{user_id}", headers=superuser_token_headers, ) assert 200 <= r.status_code < 300 @@ -62,7 +62,7 @@ def test_create_user_existing_username(superuser_token_headers): user = crud.user.create(db_session, user_in=user_in) data = {"email": username, "password": password} r = requests.post( - f"{server_api}{config.API_V1_STR}/users/", + f"{server_api}{settings.API_V1_STR}/users/", headers=superuser_token_headers, json=data, ) @@ -80,7 +80,7 @@ def test_create_user_by_normal_user(): user_token_headers = user_authentication_headers(server_api, username, password) data = {"email": username, "password": password} r = requests.post( - f"{server_api}{config.API_V1_STR}/users/", headers=user_token_headers, json=data + f"{server_api}{settings.API_V1_STR}/users/", headers=user_token_headers, json=data ) assert r.status_code == 400 @@ -98,7 +98,7 @@ def test_retrieve_users(superuser_token_headers): user2 = crud.user.create(db_session, user_in=user_in2) r = requests.get( - f"{server_api}{config.API_V1_STR}/users/", headers=superuser_token_headers + f"{server_api}{settings.API_V1_STR}/users/", headers=superuser_token_headers ) all_users = r.json() diff --git a/backend/app/app/tests/crud/test_farm.py b/backend/app/app/tests/crud/test_farm.py index d6d72c3..9d08673 100644 --- a/backend/app/app/tests/crud/test_farm.py +++ b/backend/app/app/tests/crud/test_farm.py @@ -1,4 +1,4 @@ -from app.core import config +from app.core.config import settings from app import crud from app.db.session import db_session from app.schemas.farm import FarmCreate, FarmUpdate @@ -29,7 +29,7 @@ def test_create_delete_default_farm_with_token(): assert farm.farm_name == farm_name assert farm.url == url - if config.FARM_ACTIVE_AFTER_REGISTRATION: + if settings.FARM_ACTIVE_AFTER_REGISTRATION: assert farm.active is True else: assert farm.active is False @@ -63,7 +63,7 @@ def test_create_farm_update_token(): assert farm.url == url assert farm.token is None - if config.FARM_ACTIVE_AFTER_REGISTRATION: + if settings.FARM_ACTIVE_AFTER_REGISTRATION: assert farm.active is True else: assert farm.active is False @@ -142,7 +142,7 @@ def test_create_farm_cant_delete_token(): assert farm.farm_name == farm_name assert farm.url == url - if config.FARM_ACTIVE_AFTER_REGISTRATION: + if settings.FARM_ACTIVE_AFTER_REGISTRATION: assert farm.active is True else: assert farm.active is False @@ -175,7 +175,7 @@ def test_create_farm_cant_delete_token(): def test_create_delete_active_farm(): - """Configure the active flag to True.""" + """settingsure the active flag to True.""" farm_name = random_lower_string() url = random_lower_string() @@ -197,7 +197,7 @@ def test_create_delete_active_farm(): def test_create_delete_inactive_farm(): - """Configure the active flag to False.""" + """settingsure the active flag to False.""" farm_name = random_lower_string() url = random_lower_string() diff --git a/backend/app/app/tests/utils/farm.py b/backend/app/app/tests/utils/farm.py index 3829185..8086457 100644 --- a/backend/app/app/tests/utils/farm.py +++ b/backend/app/app/tests/utils/farm.py @@ -1,4 +1,4 @@ -from app.core import config +from app.core.config import settings from app import crud from app.db.session import db_session from app.schemas.farm import FarmCreate @@ -7,26 +7,26 @@ def get_test_farm_instance(): """Populates database with a farmOS testing farm This creates a farm object in the database with valid credentials - for the configured farmOS testing instance. + for the settingsured farmOS testing instance. Returns: the test_farm object """ # Remove existing farm from DB if it has the testing URL - old_farm = crud.farm.get_by_url(db_session, farm_url=config.TEST_FARM_URL) + old_farm = crud.farm.get_by_url(db_session, farm_url=settings.TEST_FARM_URL) if old_farm is not None: crud.farm.delete(db_session, farm_id=old_farm.id) # Create test farm - if config.has_valid_test_configuration(): + if settings.TEST_FARM_URL is not None: farm_in = FarmCreate( - farm_name=config.TEST_FARM_NAME, - url=config.TEST_FARM_URL, + farm_name=settings.TEST_FARM_NAME, + url=settings.TEST_FARM_URL, scope="user_access", active=True ) else: farm_in = FarmCreate( - farm_name=config.TEST_FARM_NAME, + farm_name=settings.TEST_FARM_NAME, url="http://localhost", scope="user_access", active=True diff --git a/backend/app/app/tests/utils/user.py b/backend/app/app/tests/utils/user.py index f6c8f0e..b0dfd68 100644 --- a/backend/app/app/tests/utils/user.py +++ b/backend/app/app/tests/utils/user.py @@ -1,7 +1,7 @@ import requests from app import crud -from app.core import config +from app.core.config import settings from app.db.session import db_session from app.schemas.user import UserCreate from app.tests.utils.utils import random_lower_string @@ -10,7 +10,7 @@ def user_authentication_headers(server_api, email, password): data = {"username": email, "password": password} - r = requests.post(f"{server_api}{config.API_V1_STR}/login/access-token", data=data) + r = requests.post(f"{server_api}{settings.API_V1_STR}/login/access-token", data=data) response = r.json() auth_token = response["access_token"] headers = {"Authorization": f"Bearer {auth_token}"} diff --git a/backend/app/app/tests/utils/utils.py b/backend/app/app/tests/utils/utils.py index 5bde419..4fe0a1e 100644 --- a/backend/app/app/tests/utils/utils.py +++ b/backend/app/app/tests/utils/utils.py @@ -4,11 +4,11 @@ import requests import pytest -from app.core import config +from app.core.config import settings farmOS_testing_server = pytest.mark.skipif( - not config.has_valid_test_configuration(), + settings.TEST_FARM_URL is None, reason="farmOS Testing Server not configured. Skipping farmOS test server integration tests.", ) @@ -18,18 +18,18 @@ def random_lower_string(): def get_server_api(): - server_name = f"http://{config.SERVER_NAME}" + server_name = f"http://{settings.SERVER_NAME}" return server_name def get_superuser_token_headers(): server_api = get_server_api() login_data = { - "username": config.FIRST_SUPERUSER, - "password": config.FIRST_SUPERUSER_PASSWORD, + "username": settings.FIRST_SUPERUSER, + "password": settings.FIRST_SUPERUSER_PASSWORD, } r = requests.post( - f"{server_api}{config.API_V1_STR}/login/access-token", data=login_data + f"{server_api}{settings.API_V1_STR}/login/access-token", data=login_data ) tokens = r.json() a_token = tokens["access_token"] @@ -49,12 +49,12 @@ def get_scope_token_headers(scopes): def _create_headers_with_scopes(scopes): server_api = get_server_api() login_data = { - "username": config.FIRST_SUPERUSER, - "password": config.FIRST_SUPERUSER_PASSWORD, + "username": settings.FIRST_SUPERUSER, + "password": settings.FIRST_SUPERUSER_PASSWORD, "scope": scopes, } r = requests.post( - f"{server_api}{config.API_V1_STR}/login/access-token", data=login_data + f"{server_api}{settings.API_V1_STR}/login/access-token", data=login_data ) tokens = r.json() a_token = tokens["access_token"] diff --git a/backend/app/app/utils.py b/backend/app/app/utils.py index 7671d34..2ceb833 100644 --- a/backend/app/app/utils.py +++ b/backend/app/app/utils.py @@ -8,80 +8,80 @@ from emails.template import JinjaTemplate from jwt.exceptions import InvalidTokenError -from app.core import config +from app.core.config import settings from app.core.jwt import create_farm_api_token password_reset_jwt_subject = "preset" def send_email(email_to: str, subject_template="", html_template="", environment={}): - assert config.EMAILS_ENABLED, "no provided configuration for email variables" + assert settings.EMAILS_ENABLED, "no provided configuration for email variables" message = emails.Message( subject=JinjaTemplate(subject_template), html=JinjaTemplate(html_template), - mail_from=(config.EMAILS_FROM_NAME, config.EMAILS_FROM_EMAIL), + mail_from=(settings.EMAILS_FROM_NAME, settings.EMAILS_FROM_EMAIL), ) - smtp_options = {"host": config.SMTP_HOST, "port": config.SMTP_PORT} - if config.SMTP_TLS: + smtp_options = {"host": settings.SMTP_HOST, "port": settings.SMTP_PORT} + if settings.SMTP_TLS: smtp_options["tls"] = True - if config.SMTP_USER: - smtp_options["user"] = config.SMTP_USER - if config.SMTP_PASSWORD: - smtp_options["password"] = config.SMTP_PASSWORD + if settings.SMTP_USER: + smtp_options["user"] = settings.SMTP_USER + if settings.SMTP_PASSWORD: + smtp_options["password"] = settings.SMTP_PASSWORD response = message.send(to=email_to, render=environment, smtp=smtp_options) logging.info(f"send email result: {response}") def send_test_email(email_to: str): - project_name = config.PROJECT_NAME + project_name = settings.PROJECT_NAME subject = f"{project_name} - Test email" - with open(Path(config.EMAIL_TEMPLATES_DIR) / "test_email.html") as f: + with open(Path(settings.EMAIL_TEMPLATES_DIR) / "test_email.html") as f: template_str = f.read() send_email( email_to=email_to, subject_template=subject, html_template=template_str, - environment={"project_name": config.PROJECT_NAME, "email": email_to}, + environment={"project_name": settings.PROJECT_NAME, "email": email_to}, ) def send_reset_password_email(email_to: str, email: str, token: str): - project_name = config.PROJECT_NAME + project_name = settings.PROJECT_NAME subject = f"{project_name} - Password recovery for user {email}" - with open(Path(config.EMAIL_TEMPLATES_DIR) / "reset_password.html") as f: + with open(Path(settings.EMAIL_TEMPLATES_DIR) / "reset_password.html") as f: template_str = f.read() if hasattr(token, "decode"): use_token = token.decode() else: use_token = token - server_host = config.SERVER_HOST + server_host = settings.SERVER_HOST link = f"{server_host}/reset-password?token={use_token}" send_email( email_to=email_to, subject_template=subject, html_template=template_str, environment={ - "project_name": config.PROJECT_NAME, + "project_name": settings.PROJECT_NAME, "username": email, "email": email_to, - "valid_hours": config.EMAIL_RESET_TOKEN_EXPIRE_HOURS, + "valid_hours": settings.EMAIL_RESET_TOKEN_EXPIRE_HOURS, "link": link, }, ) def send_new_account_email(email_to: str, username: str, password: str): - project_name = config.PROJECT_NAME + project_name = settings.PROJECT_NAME subject = f"{project_name} - New account for user {username}" - with open(Path(config.EMAIL_TEMPLATES_DIR) / "new_account.html") as f: + with open(Path(settings.EMAIL_TEMPLATES_DIR) / "new_account.html") as f: template_str = f.read() - link = config.SERVER_HOST + link = settings.SERVER_HOST send_email( email_to=email_to, subject_template=subject, html_template=template_str, environment={ - "project_name": config.PROJECT_NAME, + "project_name": settings.PROJECT_NAME, "username": username, "password": password, "email": email_to, @@ -91,13 +91,13 @@ def send_new_account_email(email_to: str, username: str, password: str): def generate_password_reset_token(email): - delta = timedelta(hours=config.EMAIL_RESET_TOKEN_EXPIRE_HOURS) + delta = timedelta(hours=settings.EMAIL_RESET_TOKEN_EXPIRE_HOURS) now = datetime.utcnow() expires = now + delta exp = expires.timestamp() encoded_jwt = jwt.encode( {"exp": exp, "nbf": now, "sub": password_reset_jwt_subject, "email": email}, - config.SECRET_KEY, + settings.SECRET_KEY, algorithm="HS256", ) return encoded_jwt @@ -105,7 +105,7 @@ def generate_password_reset_token(email): def verify_password_reset_token(token) -> Optional[str]: try: - decoded_token = jwt.decode(token, config.SECRET_KEY, algorithms=["HS256"]) + decoded_token = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"]) assert decoded_token["sub"] == password_reset_jwt_subject return decoded_token["email"] except InvalidTokenError: @@ -115,8 +115,8 @@ def verify_password_reset_token(token) -> Optional[str]: def generate_farm_authorization_link(farm_id): token = create_farm_api_token(farm_id=[farm_id], scopes=["farm:read", "farm:authorize", "farm.info"]) - server_host = config.SERVER_HOST - api_path = config.API_V1_STR + server_host = settings.SERVER_HOST + api_path = settings.API_V1_STR link = f"{server_host}/authorize-farm/?farm_id={farm_id}&api_token={token.decode()}" return link @@ -125,8 +125,8 @@ def generate_farm_authorization_link(farm_id): def generate_farm_registration_link(): token = create_farm_api_token(farm_id=[], scopes=["farm:create", "farm:info"]) - server_host = config.SERVER_HOST - api_path = config.API_V1_STR + server_host = settings.SERVER_HOST + api_path = settings.API_V1_STR link = f"{server_host}/register-farm?api_token={token.decode()}" return link diff --git a/backend/app/app/worker.py b/backend/app/app/worker.py index 7fcc062..c05123e 100644 --- a/backend/app/app/worker.py +++ b/backend/app/app/worker.py @@ -2,13 +2,13 @@ from raven import Client -from app.core import config +from app.core.config import settings from app.core.celery_app import celery_app from app.db.session import Session from app import crud from app.api.utils.farms import get_farm_client -client_sentry = Client(config.SENTRY_DSN) +client_sentry = Client(settings.SENTRY_DSN) @celery_app.task() diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index f18a4e2..09553d4 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -9,6 +9,7 @@ services: command: /start-reload.sh environment: - 'JUPYTER=jupyter notebook --ip=0.0.0.0 --allow-root' + - SERVER_NAME=${DOMAIN} - SERVER_HOST=http://${DOMAIN} networks: default: diff --git a/env-backend.env b/env-backend.env index 97b0909..67d6447 100644 --- a/env-backend.env +++ b/env-backend.env @@ -1,4 +1,4 @@ -BACKEND_CORS_ORIGINS=http://localhost, http://localhost:4200, http://localhost:3000, http://localhost:8080, https://localhost, https://localhost:4200, https://localhost:3000, https://localhost:8080, http://dev.localhost, https://stag.localhost, https://localhost, http://local.dockertoolbox.tiangolo.com, http://localhost.tiangolo.com +BACKEND_CORS_ORIGINS=["http://localhost", "http://localhost:4200", "http://localhost:3000", "http://localhost:8080", "https://localhost", "https://localhost:4200", "https://localhost:3000", "https://localhost:8080", "http://dev.{{cookiecutter.domain_main}}", "https://{{cookiecutter.domain_staging}}", "https://{{cookiecutter.domain_main}}", "http://local.dockertoolbox.tiangolo.com", "http://localhost.tiangolo.com"] PROJECT_NAME=farmOS-aggregator SECRET_KEY=1f034e80442f37b6cfe1e9b442ef431b73fc4b727bf94bd93ed963adb2dec58a FIRST_SUPERUSER=admin@example.com