Skip to content

Commit

Permalink
Add Create Auction to frontend + connect auction/items services backend
Browse files Browse the repository at this point in the history
  • Loading branch information
yixinliu99 committed Dec 9, 2024
1 parent 9d462d3 commit d2c771e
Show file tree
Hide file tree
Showing 14 changed files with 273 additions and 255 deletions.
1 change: 1 addition & 0 deletions src/Auction/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ services:
environment:
- MONGODB_URI=mongodb://mongodb:27017
- USER_SERVICE_ADDRESS=http://user-service-nginx
- ITEM_SERVICE_ADDRESS=http://item-service-nginx
ports:
- "50010:50051"
networks:
Expand Down
12 changes: 11 additions & 1 deletion src/Auction/models/auction.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import datetime

from bson import ObjectId
from google.protobuf.json_format import MessageToDict

from Auction.consts.consts import AUCTIONS_COLLECTION
from Auction.dao.mongoDAO import MongoDao
from Auction.models.bid import Bid
from Auction.service_connectors.user_connector import UserConnector
from Auction.service_connectors.item_connector import ItemConnector


class Auction:
Expand Down Expand Up @@ -50,7 +52,15 @@ def from_dict(auction_dict: dict):
def create(self, dao: MongoDao) -> list[str]:
create_dict = self.to_dict()
del create_dict["_id"]
return dao.write_to_db(AUCTIONS_COLLECTION, create_dict)
response = dao.write_to_db(AUCTIONS_COLLECTION, create_dict)

# update item with auction id
item_connector = ItemConnector()
item = item_connector.get_item_by_id(self.item_id)
item["auction_id"] = response[0]
item_connector.update_item(self.item_id, item)

return response

def update(self, dao: MongoDao) -> int:
update_dict = self.to_dict()
Expand Down
24 changes: 3 additions & 21 deletions src/Auction/service_connectors/item_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,12 @@ def __init__(self):
raise ValueError("ITEM_SERVICE_ADDRESS environment variable not set")
self.item_service_address = os.getenv("ITEM_SERVICE_ADDRESS")

def get_item(self, item_id):
response = requests.get(f"{self.item_service_address}/item/{item_id}")
return response.json()

def get_items(self):
response = requests.get(f"{self.item_service_address}/items")
return response.json()
def get_item_by_id(self, item_id):
response = requests.get(f"{self.item_service_address}/items/{item_id}")

def add_item(self, item):
response = requests.post(f"{self.item_service_address}/item", json=item)
return response.json()

def update_item(self, item_id, item):
response = requests.put(f"{self.item_service_address}/item/{item_id}", json=item)
return response.json()
response = requests.put(f"{self.item_service_address}/items/{item_id}", json=item)

def delete_item(self, item_id):
response = requests.delete(f"{self.item_service_address}/item/{item_id}")
return response.json()

def get_item_bids(self, item_id):
response = requests.get(f"{self.item_service_address}/item/{item_id}/bids")
return response.json()

def add_bid_to_item(self, item_id, bid):
response = requests.post(f"{self.item_service_address}/item/{item_id}/bid", json=bid)
return response.json()
1 change: 1 addition & 0 deletions src/Auction/tests/testMongoDao.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import uuid
from unittest.mock import MagicMock

import mongomock
import pytest
Expand Down
55 changes: 8 additions & 47 deletions src/Auction/tests/testRPC.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import datetime
from datetime import timedelta
from unittest import mock
from unittest.mock import MagicMock, patch

import pytest
Expand All @@ -21,6 +22,13 @@ def auction_service(mock_dao):
return AuctionService(mock_dao)


@pytest.fixture(scope='module')
def mock_item_connector():
patcher = mock.patch('Auction.service_connectors.item_connector.ItemConnector.__init__')
patcher.start()
yield patcher
patcher.stop()

@pytest.fixture(scope='module')
def grpc_add_to_server():
return service_pb2_grpc.add_AuctionServiceServicer_to_server
Expand All @@ -35,24 +43,6 @@ def grpc_servicer(auction_service):
def grpc_stub_cls():
return service_pb2_grpc.AuctionServiceStub


@patch('Auction.task_scheduler.tasks.start_auction_task.apply_async', MagicMock())
def test_create_auction_success(grpc_stub, mock_dao):
mock_dao.write_to_db.return_value = ["wakemeupwhenseptemberends"]

request = service_pb2.CreateAuctionRequest(
starting_price=100.00,
starting_time=(datetime.datetime.now(tz=datetime.timezone.utc) + timedelta(seconds=10)).isoformat(),
ending_time=(datetime.datetime.now(tz=datetime.timezone.utc) + timedelta(seconds=20)).isoformat(),
item_id="1",
seller_id="asd",
)

response = grpc_stub.CreateAuction(request)
assert response.success
assert response.auction_id == "wakemeupwhenseptemberends"


def test_create_auction_failure(grpc_stub, mock_dao):
mock_dao.write_to_db.side_effect = Exception()

Expand All @@ -68,35 +58,6 @@ def test_create_auction_failure(grpc_stub, mock_dao):
assert not response.success


@patch('Auction.task_scheduler.tasks.start_auction_task.AsyncResult', MagicMock())
@patch('Auction.task_scheduler.tasks.start_auction_task.apply_async', MagicMock())
def test_update_auction_success(grpc_stub, mock_dao):
fake_id = str(ObjectId())
mock_dao.read_from_db.return_value = [{
"_id": fake_id,
"starting_price": 100.00,
"starting_time": "2024-11-25T10:30:00",
"ending_time": "2024-11-25T12:30:00",
"seller_id": "2",
"item_id": "1",
"current_price": 100.00,
"bids": []
}]
mock_dao.update.return_value = 1

request = service_pb2.UpdateAuctionRequest(
auction_id=fake_id,
starting_price=120.00,
starting_time="2024-11-25T10:30:00",
ending_time="2024-11-25T12:30:00",
seller_id="2",
item_id="1"
)

response = grpc_stub.UpdateAuction(request)
assert response.success


def test_start_auction_success(grpc_stub, mock_dao):
fake_id = str(ObjectId())
mock_dao.read_from_db.return_value = [{
Expand Down
11 changes: 9 additions & 2 deletions src/Item/compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
services:
web:
item-service-nginx:
image: nginx
volumes:
- ./nginx/nginx.conf:/tmp/nginx.conf
Expand All @@ -10,6 +10,9 @@ services:
- 8081:80
depends_on:
- backend
networks:
- user_external
- default

backend:
build: .
Expand All @@ -21,4 +24,8 @@ services:
mongodb:
image: mongo
ports:
- 27010:27017
- 27010:27017

networks:
user_external:
external: true
5 changes: 5 additions & 0 deletions src/Item/dao/mongoDAO.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
from typing import Any, Callable

import bson
from pymongo import MongoClient
from pymongo.errors import ConnectionFailure

Expand Down Expand Up @@ -58,6 +59,8 @@ def read_from_db(self, collection_name, query: dict, projection=None) -> list:
"""
Retrieve documents based on query ignoring hidden documents.
"""
if "_id" in query and not isinstance(query["_id"], bson.ObjectId):
query["_id"] = bson.ObjectId(query["_id"])
collection = self.db[collection_name]
query = {**query, "hidden": {"$ne": True}}
results = []
Expand All @@ -71,6 +74,8 @@ def update_db(self, collection_name, query: dict, update: Any, many=False) -> in
"""
Replace filtered documents with update.
"""
if "_id" in query and not isinstance(query["_id"], bson.ObjectId):
query["_id"] = bson.ObjectId(query["_id"])
collection = self.db[collection_name]
if many:
result = collection.update_many(query, update)
Expand Down
7 changes: 5 additions & 2 deletions src/Item/models/item.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from Item.consts.consts import ITEM_COLLECTION

import bson

class Item:
def __init__(self, user_id: str, starting_price: float, quantity: int, shipping_cost: float, description: str,
Expand Down Expand Up @@ -55,7 +55,10 @@ def delete(self, dao):
@staticmethod
def get_by_id(dao, item_id):
r = dao.read_from_db(ITEM_COLLECTION, {"_id": item_id})
return Item.from_dict(r) if r else None
if r:
return Item.from_dict(r[0])
else:
return None

@staticmethod
def get_all(dao):
Expand Down
6 changes: 4 additions & 2 deletions src/Item/tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import bson
import pytest
from flask import Flask
import bson
from unittest.mock import MagicMock, patch

# Import the app object from your Flask application
Expand Down Expand Up @@ -38,7 +40,7 @@ def test_get_all_items(client, mock_dao, mock_item1, mock_item2):
assert response.json == [mock_item1, mock_item2]

def test_get_item_by_id_success(client, mock_dao, mock_item1):
mock_dao.read_from_db.return_value = mock_item1
mock_dao.read_from_db.return_value = [mock_item1]
response = client.get("/items/1")
assert response.status_code == 200
assert response.json == mock_item1
Expand Down Expand Up @@ -84,7 +86,7 @@ def test_delete_item_not_found(client, mock_dao):
def test_flag_item_success(client, mock_dao, mock_item1):
flagged_item = mock_item1
flagged_item["flagged"] = True
mock_dao.read_from_db.return_value = mock_item1
mock_dao.read_from_db.return_value = [mock_item1]
mock_dao.update_db.return_value = flagged_item

response = client.put("/items/flag/1")
Expand Down
2 changes: 2 additions & 0 deletions web_app/backend/app.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import os

from flask import Flask
from flask_cors import CORS

from views import auction_api

app = Flask(__name__)
CORS(app)
app.register_blueprint(auction_api)

if __name__ == "__main__":
Expand Down
16 changes: 11 additions & 5 deletions web_app/backend/connectors/auction/auction_rpc_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
import json

import grpc
from google.protobuf.json_format import MessageToDict

import web_app.backend.connectors.auction.service_pb2 as service_pb2
import web_app.backend.connectors.auction.service_pb2_grpc as service_pb2_grpc

SERVER_ADDRESS = 'localhost:50010'


def filter_auctions(query):
with grpc.insecure_channel(SERVER_ADDRESS) as channel:
stub = service_pb2_grpc.AuctionServiceStub(channel)
Expand All @@ -18,18 +20,22 @@ def filter_auctions(query):

return get_response

def create_auction(starting_price, starting_time, ending_time, seller_id, item_id):

def create_auction(starting_price, starting_time, ending_time, seller_id, item_id, buy_now_price=None):
with grpc.insecure_channel(SERVER_ADDRESS) as channel:
stub = service_pb2_grpc.AuctionServiceStub(channel)

create_request = service_pb2.CreateAuctionRequest(
starting_price=starting_price,
starting_time=datetime.datetime.isoformat(starting_time),
ending_time=datetime.datetime.isoformat(ending_time),
starting_time=datetime.datetime.isoformat(starting_time) if isinstance(starting_time,
datetime.datetime) else starting_time,
ending_time=datetime.datetime.isoformat(ending_time) if isinstance(ending_time,
datetime.datetime) else ending_time,
seller_id=seller_id,
item_id=item_id
item_id=item_id,
buy_now_price=buy_now_price
)
create_response = stub.CreateAuction(create_request)
create_response = MessageToDict(stub.CreateAuction(create_request))

return create_response

Expand Down
18 changes: 16 additions & 2 deletions web_app/backend/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from Item.models.item import Item
from werkzeug.exceptions import NotFound, BadRequest
from flask import Blueprint
from connectors.auction.auction_rpc_client import filter_auctions
from connectors.auction.auction_rpc_client import filter_auctions, create_auction
import bson
auction_api = Blueprint("auction", __name__)

Expand All @@ -16,4 +16,18 @@ def get_auctions_by_ids():
query = {"_id": {"$in": data}}
response = filter_auctions(query)

return jsonify(response)
return jsonify(response)

@auction_api.route("/auctions/create", methods=["POST"])
def create_auction_api():
data = request.json
response = create_auction(
float(data["starting_price"]),
data["starting_time"],
data["ending_time"],
data["seller_id"],
data["item_id"],
float(data["buy_now_price"])
)

return jsonify(response)
Loading

0 comments on commit d2c771e

Please sign in to comment.