Skip to content

Commit

Permalink
Add card entity
Browse files Browse the repository at this point in the history
  • Loading branch information
Saluev committed Mar 9, 2019
1 parent b2ce789 commit 3ced773
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 4 deletions.
3 changes: 3 additions & 0 deletions backend/dev_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MONGO_HOST = "mongo"
MONGO_PORT = 27017
MONGO_DATABASE = "core"
29 changes: 25 additions & 4 deletions backend/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
import flask
import flask_cors

from backend.storage.card import CardNotFound
from backend.wiring import Wiring


env = os.environ.get("APP_ENV", "dev")
print(f"Starting application in {env} mode")


class HabrAppDemo(flask.Flask):

Expand All @@ -11,11 +18,25 @@ def __init__(self, *args, **kwargs):

flask_cors.CORS(self)

self.wiring = Wiring(env)

app = HabrAppDemo("habr-app-demo")
self.route("/api/v1/card/<card_id_or_slug>")(self.card)

env = os.environ.get("APP_ENV", "dev")
print(f"Starting application in {env} mode")
app.config.from_object(f"backend.{env}_settings")
def card(self, card_id_or_slug):
try:
card = self.wiring.card_dao.get_by_slug(card_id_or_slug)
except CardNotFound:
try:
card = self.wiring.card_dao.get_by_id(card_id_or_slug)
except (CardNotFound, ValueError):
return flask.abort(404)
return flask.jsonify({
k: v
for k, v in card.__dict__.items()
if v is not None
})


app = HabrAppDemo("habr-app-demo")
app.config.from_object(f"backend.{env}_settings")
app.secret_key = "nu privet habravchanin"
Empty file added backend/storage/__init__.py
Empty file.
38 changes: 38 additions & 0 deletions backend/storage/card.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import abc
from typing import Iterable


class Card(object):
def __init__(self, id: str = None, slug: str = None, name: str = None, markdown: str = None, html: str = None):
self.id = id
self.slug = slug
self.name = name
self.markdown = markdown
self.html = html


class CardDAO(object, metaclass=abc.ABCMeta):

@abc.abstractmethod
def create(self, card: Card) -> Card:
pass

@abc.abstractmethod
def update(self, card: Card) -> Card:
pass

@abc.abstractmethod
def get_all(self) -> Iterable[Card]:
pass

@abc.abstractmethod
def get_by_id(self, card_id: str) -> Card:
pass

@abc.abstractmethod
def get_by_slug(self, slug: str) -> Card:
pass


class CardNotFound(Exception):
pass
63 changes: 63 additions & 0 deletions backend/storage/card_impl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from typing import Iterable

import bson
import bson.errors
from pymongo.collection import Collection
from pymongo.database import Database

from backend.storage.card import Card, CardDAO, CardNotFound


class MongoCardDAO(CardDAO):

def __init__(self, mongo_database: Database):
self.mongo_database = mongo_database
self.collection.create_index("slug", unique=True)

@property
def collection(self) -> Collection:
return self.mongo_database["cards"]

@classmethod
def to_bson(cls, card: Card):
result = {
k: v
for k, v in card.__dict__.items()
if v is not None
}
if "id" in result:
result["_id"] = bson.ObjectId(result.pop("id"))
return result

@classmethod
def from_bson(cls, document) -> Card:
document["id"] = str(document.pop("_id"))
return Card(**document)

def create(self, card: Card) -> Card:
card.id = str(self.collection.insert_one(self.to_bson(card)).inserted_id)
return card

def update(self, card: Card) -> Card:
card_id = bson.ObjectId(card.id)
self.collection.update_one({"_id": card_id}, {"$set": self.to_bson(card)})
return card

def get_all(self) -> Iterable[Card]:
for document in self.collection.find():
yield self.from_bson(document)

def get_by_id(self, card_id: str) -> Card:
try:
return self._get_by_query({"_id": bson.ObjectId(card_id)})
except bson.errors.InvalidId:
raise ValueError

def get_by_slug(self, slug: str) -> Card:
return self._get_by_query({"slug": slug})

def _get_by_query(self, query) -> Card:
document = self.collection.find_one(query)
if document is None:
raise CardNotFound()
return self.from_bson(document)
24 changes: 24 additions & 0 deletions backend/wiring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import os

from pymongo import MongoClient
from pymongo.database import Database

import backend.dev_settings
from backend.storage.card import CardDAO
from backend.storage.card_impl import MongoCardDAO


class Wiring(object):

def __init__(self, env=None):
if env is None:
env = os.environ.get("APP_ENV", "dev")
self.settings = {
"dev": backend.dev_settings,
}[env]

self.mongo_client: MongoClient = MongoClient(
host=self.settings.MONGO_HOST,
port=self.settings.MONGO_PORT)
self.mongo_database: Database = self.mongo_client[self.settings.MONGO_DATABASE]
self.card_dao: CardDAO = MongoCardDAO(self.mongo_database)
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ flask
flask-cors
gevent
gunicorn
pymongo

0 comments on commit 3ced773

Please sign in to comment.