diff --git a/.gitignore b/.gitignore index ec79d214142423fc01c78bdc670bce1719f5d860..2ee65884724162b636cea26fc6e9d5e95eac2d88 100644 --- a/.gitignore +++ b/.gitignore @@ -164,4 +164,5 @@ cython_debug/ _docs/ .env +dotenv .DS_Store diff --git a/docker-compose.yml b/docker-compose.yml index 87cfa6339aef27858a35dc1d9bf5335d988c24db..bc8a8b04de52edc950f2ac0ce753628776fadf94 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,6 +5,13 @@ version: '3' services: + # MongoDB container + mongodb: + image: mongo:4.2 + restart: unless-stopped + ports: + - 27017:27017 + tjts5901: build: context: . @@ -38,13 +45,6 @@ services: depends_on: - mongodb - # MongoDB container - mongodb: - image: mongo:4.2 - restart: unless-stopped - ports: - - 27017:27017 - volumes: tjts5901-vscode-extensions: diff --git a/dotenv b/dotenv index cb3c9ba73b8de5c7cebd2838e0525e3c1a1584f1..41e971ce3bff48efb6b8882091cb7305cfad5067 100644 --- a/dotenv +++ b/dotenv @@ -14,9 +14,4 @@ # developers or deployments, as you can simply share the .env file rather than hardcoding the # values into the application itself. -FLASK_APP=tjts5901.app -FLASK_DEBUG=1 - -# Enable rich logging for more human readable log output. Requires installing -# `rich` and `flask-rich` packages. -#RICH_LOGGING=1 +MONGO_URL = "mongodb://localhost:27017/ \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 5d27c0a2f5623816b2835951c2f70a79b330d92c..b51d2cad1a7a85ed1c77761a53b58198465e3991 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,8 @@ importlib-metadata flask python-dotenv +flask-mongoengine==1.0 + # Git hooks pre-commit diff --git a/src/tjts5901/__init__.py b/src/tjts5901/__init__.py index e2bb8d212bf14c0f9ffbd48d061e266695cb259c..9b9a065debdeaa7f9bc73628a3c225a90bb968bc 100644 --- a/src/tjts5901/__init__.py +++ b/src/tjts5901/__init__.py @@ -6,7 +6,14 @@ JYU TJTS5901 Course project from importlib_metadata import (PackageNotFoundError, version) +from .app import create_app + try: __version__ = version(__name__) except PackageNotFoundError: __version__ = "unknown" + +__all__ = [ + "create_app", + "__version__", +] \ No newline at end of file diff --git a/src/tjts5901/app.py b/src/tjts5901/app.py index bb4edbf0d47be162f9dac6e60e576d4d684e41d9..9f15d4b781a69f98d01ed13f758b895794461d14 100644 --- a/src/tjts5901/app.py +++ b/src/tjts5901/app.py @@ -8,6 +8,7 @@ Flask tutorial: https://flask.palletsprojects.com/en/2.2.x/tutorial/ """ from os import environ +import os from typing import Dict, Optional from dotenv import load_dotenv @@ -19,6 +20,7 @@ from flask import ( ) from .utils import get_version +from .db import init_db def create_app(config: Optional[Dict] = None) -> Flask: @@ -29,16 +31,36 @@ def create_app(config: Optional[Dict] = None) -> Flask: """ flask_app = Flask(__name__, instance_relative_config=True) - if config: + flask_app.config.from_mapping( + SECRET_KEY='dev', + BRAND="Hill Valley DMC dealership", + ) + + # load the instance config, if it exists, when not testing + if config is None: + flask_app.config.from_pyfile('config.py', silent=True) + else: flask_app.config.from_mapping(config) - # Set flask config variable for "rich" loggin from environment variable. - flask_app.config.from_envvar("RICH_LOGGING", silent=True) + # ensure the instance folder exists + try: + os.makedirs(flask_app.instance_path) + except OSError: + pass + + # Initialize the database connection. + init_db(flask_app) - # Register blueprints + # Register blueprints from . import views # pylint: disable=import-outside-toplevel flask_app.register_blueprint(views.bp, url_prefix='') + # a simple page that says hello + @flask_app.route('/hello') + def hello(): + return 'Hello, World!' + + return flask_app @@ -49,13 +71,6 @@ load_dotenv() # Create the Flask application. app = create_app() -# Initialize "rich" output if enabled. It produces more human readable logs. -# You need to install `flask-rich` to use this. -if app.config.get("RICH_LOGGING"): - from flask_rich import RichApplication - RichApplication(app) - app.logger.info("Using [blue]rich[/blue] interface for logging") - @app.route("/server-info") def server_info() -> Response: diff --git a/src/tjts5901/db.py b/src/tjts5901/db.py new file mode 100644 index 0000000000000000000000000000000000000000..c97b5068c00c353f5bc107bb158c3db2fff1c865 --- /dev/null +++ b/src/tjts5901/db.py @@ -0,0 +1,25 @@ +from os import environ +from flask_mongoengine import MongoEngine + +db = MongoEngine() + + +def init_db(app): + """ + Initialize the database connection. + + Fetches the database connection string from the environment variable `MONGO_URL` + and, if present, sets the `MONGODB_SETTINGS` configuration variable to use it. + """ + + + # To keep secrets private, we use environment variables to store the database connection string. + # `MONGO_URL` is expected to be a valid MongoDB connection string, see: blah blah blah + mongodb_url = environ.get("MONGO_URL") + + if mongodb_url is not None: + app.config["MONGODB_SETTINGS"] = { + "host": mongodb_url, + } + + db.init_app(app) \ No newline at end of file diff --git a/src/tjts5901/models.py b/src/tjts5901/models.py new file mode 100644 index 0000000000000000000000000000000000000000..1b3f3097fb3c0811240c425d46db21615640c341 --- /dev/null +++ b/src/tjts5901/models.py @@ -0,0 +1,40 @@ +from datetime import datetime +from .db import db + +from mongoengine import ( + StringField, + IntField, + ReferenceField, + DateTimeField, + EmailField, +) + + +class User(db.Document): + """ + Model representing a user of the auction site. + """ + + email = EmailField(required=True, unique=True) + + password = StringField(required=True) + + created_at = DateTimeField(required=True, default=datetime.utcnow) + + +class Item(db.Document): + """ + A model for items that are listed on the auction site. + """ + + title = StringField(max_length=100, required=True) + + description = StringField(max_length=2000, required=True) + + starting_bid = IntField(required=True, min_value=0) + + seller = ReferenceField(User, required=True) + + created_at = DateTimeField(required=True, default=datetime.utcnow) + + closes_at = DateTimeField() diff --git a/src/tjts5901/views.py b/src/tjts5901/views.py index 624238c04705bcf131d49c92d7d98774af37fafe..71bff112a1a731a67a353b03a9487e3d43ec3d08 100644 --- a/src/tjts5901/views.py +++ b/src/tjts5901/views.py @@ -22,3 +22,31 @@ def index() -> str: # of arguments to be used in the template. The template file is located in the templates directory. html = render_template("index.html.j2", title="TJTS5901 Example. It was changed by Arno.") return html + +@bp.route("/test") +def test_item_adding(): + """ + Test item is added + """ + + from .models import Item, User + + # for test purpose create random number (unique mail address required) + import random + ran_int = str(random.randint(0,10000)) + + # Create a new user + user = User() + user.email = "test" + ran_int + "@gmail.com" + user.password = "placeholder" + user.save() + + # Create a new item + item = Item() + item.title = "Test title" + item.description = "This is a test description" + item.starting_bid = 100 + item.seller = user + item.save() + + return "OK"