Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
from chalicelib.api.announcements import announcements_api
from chalicelib.api.insights import insights_api
from chalicelib.api.members import members_api
from chalicelib.api.events import events_api

app = Chalice(app_name="zap")
app.register_blueprint(announcements_api)
app.register_blueprint(listings_api)
app.register_blueprint(applicants_api)
app.register_blueprint(insights_api)
app.register_blueprint(members_api)
app.register_blueprint(events_api)


@app.route("/")
Expand Down
50 changes: 50 additions & 0 deletions chalicelib/api/events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from chalice import Blueprint
from chalicelib.decorators import auth
from chalicelib.services.EventService import event_service

events_api = Blueprint(__name__)


@events_api.route("/timeframes", methods=["POST"], cors=True)
@auth(events_api, roles=["admin"])
def create_timeframe():
data = events_api.current_request.json_body
return event_service.create_timeframe(data["name"])


@events_api.route("/timeframes", methods=["GET"], cors=True)
@auth(events_api, roles=["admin"])
def get_all_timeframes():
return event_service.get_all_timeframes()


@events_api.route("/timeframes/{timeframe_id}/events", methods=["POST"], cors=True)
@auth(events_api, roles=["admin"])
def create_event(timeframe_id: str):
data = events_api.current_request.json_body
return event_service.create_event(timeframe_id, data)


@events_api.route("/events/{event_id}", methods=["GET"], cors=True)
@auth(events_api, roles=["admin"])
def get_event(event_id: str):
return event_service.get_event(event_id)


@events_api.route("/events/{event_id}/checkin", methods=["POST"], cors=True)
@auth(events_api, roles=["admin"])
def checkin(event_id: str):
data = events_api.current_request.json_body
return event_service.checkin(event_id, data)


@events_api.route("/events/{event_id}", methods=["PATCH"], cors=True)
@auth(events_api, roles=["admin"])
def update_event(event_id: str):
pass


@events_api.route("/events/{event_id}", methods=["DELETE"], cors=True)
@auth(events_api, roles=["admin"])
def delete_event(event_id: str):
return event_service.delete(event_id)
148 changes: 139 additions & 9 deletions chalicelib/modules/mongo.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from pymongo.mongo_client import MongoClient
from bson import ObjectId
import boto3
import os


class MongoModule:
"""Manages connections to MongoDB."""

def __init__(self):
"""Establishes connection to MongoDB server"""
self.is_prod = os.environ.get("ENV") == "prod"
self.ssm_client = boto3.client("ssm")
self.user = self.ssm_client.get_parameter(
Name="/Zap/MONGO_ADMIN_USER", WithDecryption=True
Expand All @@ -19,6 +21,21 @@ def __init__(self):

self.mongo_client = MongoClient(self.uri)

def add_env_suffix(func):
def wrapper(self, collection_name: str, *args, **kwargs):
# users collection is dependent on vault so suffix should not be appended
if collection_name == "users":
return func(self, collection_name, *args, **kwargs)

if self.is_prod:
collection_name += "-prod"
else:
collection_name += "-dev"

return func(self, collection_name, *args, **kwargs)

return wrapper

def connect(self):
# Send a ping to confirm a successful connection
try:
Expand All @@ -30,30 +47,64 @@ def connect(self):
# store db variable
self.vault = self.client.vault

@add_env_suffix
def insert_document(self, collection: str, data: dict) -> None:
"""
Inserts a document into the specified collection.

Args:
collection (str): The name of the collection to insert the document into.
data (dict): The document to insert into the collection.

Raises:
Exception: If an error occurs while inserting the document.
"""
try:
self.mongo_client.vault[collection].insert_one(data)
except Exception as e:
print(e)

@add_env_suffix
def get_all_data(self):
"""fetches all data in specified collection"""
"""
Fetches all data in the 'users' collection.

Returns:
A MongoCursor object. If no data is found, an empty cursor is returned.
"""
try:
self.users = self.vault.users.find() # parameterize this
# assert(self.users.count() != 0) # this doesn't work, fix silent failure!!
self.users = self.vault.users.find()
except Exception as e:
print(e)
# for u in self.users:
# print(u)
return self.users

@add_env_suffix
def get_all_data_from_collection(self, collection: str):
"""Fetches all data from the specified collection."""
if collection is None:
raise ValueError("The 'collection' parameter cannot be None")

try:
# Use the specified collection to fetch data
cursor = self.mongo_client.vault[collection].find()
data = list(cursor) # Convert the cursor to a list

except Exception as e:
print(e)
return None # Handle the exception gracefully, you may want to log it or take other actions
if data is None:
raise ValueError("The data returned by the MongoDB client is None")

if data:
return data
else:
print(f"No data found in collection '{collection}'")
return []

return data
except Exception as e:
print(
f"An error occurred while fetching data from collection '{collection}': {e}"
)
raise # Handle the exception gracefully, you may want to log it or take other actions

@add_env_suffix
def update_document_by_id(
self, collection: str, document_id: str, update_data: dict
):
Expand Down Expand Up @@ -84,5 +135,84 @@ def update_document_by_id(
)
return False

@add_env_suffix
def update_document(self, collection, document_id, query):
"""
Updates a document in the specified collection with the given ID.

Args:
collection (str): The name of the collection to update the document in.
document_id (str): The ID of the document to update.
query (dict): A dictionary containing the update operators.

Returns:
bool: True if the update was successful, False otherwise.
"""
try:
print(collection)
result = self.mongo_client.vault[collection].update_one(
{"_id": ObjectId(document_id)}, query
)

if result.matched_count > 0:
print(f"Document with ID {document_id} updated successfully.")
return True
else:
print(f"No document with ID {document_id} found.")
return False
except Exception as e:
print(
f"An error occurred while updating document with ID {document_id}: {e}"
)
return False

@add_env_suffix
def get_document_by_id(self, collection, document_id):
"""
Retrieves a document from the specified collection with the given ID.

Args:
collection (str): The name of the collection to retrieve the document from.
document_id (str): The ID of the document to retrieve.

Returns:
dict: The retrieved document, or None if not found.
"""
try:
result = self.mongo_client.vault[collection].find_one(
{"_id": ObjectId(document_id)}
)
return result
except Exception as e:
print(
f"An error occurred while retrieving document with ID {document_id}: {e}"
)
return None

@add_env_suffix
def delete_document_by_id(self, collection, document_id):
"""
Deletes a document from the specified collection with the given ID.

Args:
collection (str): The name of the collection to delete the document from.
document_id (str): The ID of the document to delete.

Returns:
bool: True if the document was deleted successfully, False otherwise.
"""
try:
result = self.mongo_client.vault[collection].delete_one(
{"_id": ObjectId(document_id)}
)
if result.deleted_count > 0:
print(f"Document with ID {document_id} deleted successfully.")
return True
else:
print(f"No document with ID {document_id} found.")
return False
except Exception as e:
print(e)


mongo_module = MongoModule()
117 changes: 117 additions & 0 deletions chalicelib/services/EventService.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
from chalicelib.modules.mongo import mongo_module
from chalice import NotFoundError, BadRequestError
import json
from bson import ObjectId
import datetime


class EventService:
class BSONEncoder(json.JSONEncoder):
"""JSON encoder that converts Mongo ObjectIds and datetime.datetime to strings."""

def default(self, o):
if isinstance(o, datetime.datetime):
return o.isoformat()
elif isinstance(o, ObjectId):
return str(o)
return super().default(o)

def __init__(self):
self.collection_prefix = "events-"

def create_timeframe(self, timeframe_name: str):
timeframe_doc = {"name": timeframe_name, "dateCreated": datetime.datetime.now()}
mongo_module.insert_document(
f"{self.collection_prefix}timeframe", timeframe_doc
)

def get_all_timeframes(self):
"""Retrieve all timeframes from the database."""
timeframes = mongo_module.get_all_data_from_collection(
f"{self.collection_prefix}timeframe"
)

return json.dumps(timeframes, cls=self.BSONEncoder)

def create_event(self, timeframe_id: str, event_data: dict):
event_data["dateCreated"] = datetime.datetime.now()
event_data["timeframeId"] = timeframe_id
event_data["usersAttended"] = []

event_id = mongo_module.insert_document(
f"{self.collection_prefix}event", event_data
)

event_data["eventId"] = str(event_id)

mongo_module.update_document(
f"{self.collection_prefix}timeframe",
timeframe_id,
{"$push": {"events": event_data}},
)

def get_event(self, event_id: str):
event = mongo_module.get_document_by_id(
f"{self.collection_prefix}event", event_id
)

return json.dumps(event, cls=self.BSONEncoder)

def checkin(self, event_id: str, data: dict):
# Check if user exists
user_id = data["userId"]
member = mongo_module.get_document_by_id(f"users", user_id)
if member is None:
raise NotFoundError(f"User with ID {user_id} does not exist.")

user_name = member["name"]

# Check if user has already checked in
event = mongo_module.get_document_by_id(
f"{self.collection_prefix}event", event_id
)

if any(d["userId"] == user_id for d in event["usersAttended"]):
raise BadRequestError(f"{user_name} has already checked in.")

data["name"] = user_name
data["dateCheckedIn"] = datetime.datetime.now()

# Update the event document
mongo_module.update_document(
f"{self.collection_prefix}event",
event_id,
{"$push": {"usersAttended": data}},
)

# Return success message with the user's name
return {
"status": True,
"message": f"{user_name} has successfully been checked in.",
}

def delete(self, event_id: str):
# Check if event exists and if it doesn't return errors
event = mongo_module.get_document_by_id(
f"{self.collection_prefix}event", event_id
)

if event is None:
raise NotFoundError(f"Event with ID {event_id} does not exist.")

# If event exists, get the timeframeId (parent)
timeframe_id = event["timeframeId"]

# Remove event from timeframe
mongo_module.update_document(
f"{self.collection_prefix}timeframe",
timeframe_id,
{"$pull": {"events": {"_id": ObjectId(event_id)}}},
)

# Delete the event document
mongo_module.delete_document_by_id(
f"{self.collection_prefix}event", event_id
)

event_service = EventService()