Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Team Crician #34

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
47 changes: 33 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
# ICC Eliminator Submisison
Teams will be required to submit their code base on GitHub by forking this repository.
Follow the following steps to submit your code base.
1. **Fork** this repository.
1. Create a **folder with your team name**
1. **Upload** your code base and videos to the repository.
1. Create a **pull request** to this repository. Make sure you raise your **pull request** as per your **team name**.
1. You can also add you team details in the README.md of your forked repository
For Example:
### Team Information
------------
###### Team Name -
###### Track -
###### Brief Description and Snapshots -
This repository contains both frontend and backend code for the ICC website project.

# Backend
The backend is built with Python and uses the FastAPI framework. It provides an API that can be consumed by the frontend. To run the backend, follow these steps:

Navigate to the backend directory in the terminal.
Run pip install -r requirements.txt to install the required Python packages.
Run python main.py to start the server.
Open a web browser and go to http://localhost:8000/docs to view the API documentation.

You are required to create a .env file with this
```
# DATABASE
DATABASE_URL = "<MYSQL DB>"

# EMAIL
SENDER_EMAIL_PASSWORD = "<EMAIL_PASSWORD>"
SENDER_EMAIL = "<EMAIL>"
```


# Frontend
The frontend is built with JavaScript using the React.js framework. To run the frontend, follow these steps:

Navigate to the frontend directory in the terminal.
Run npm install to install the required dependencies.
Run npm run dev to start the development server.
Open a web browser and go to http://localhost:3000 to view the website.
Note: The frontend is currently unfinished and may not function properly.

The main page -> shows the matches
/seats/:id -> allows for booking & seat viewing
/book -> actual booking of the seat
45 changes: 45 additions & 0 deletions backend/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# pylint: disable=(wrong-import-position, missing-module-docstring)

import os
import dotenv

import fastapi
from fastapi.middleware.cors import CORSMiddleware
import sqlalchemy.orm as orm
import sqlalchemy as sql
import uvicorn

dotenv.load_dotenv()

from models import database
from models.model import Base
import routes


app = fastapi.FastAPI()


app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)


@app.on_event("startup")
def on_startup():
# database.Database().delete_db(Base)
database.Database().init_db(Base)


app.include_router(routes.tickets_router)
app.include_router(routes.stadium_router)
app.include_router(routes.person_router)
app.include_router(routes.match_router)
app.include_router(routes.auth_router)


if __name__ == "__main__":
uvicorn.run("main:app", port=8080, reload=True)
Empty file added backend/models/__init__.py
Empty file.
45 changes: 45 additions & 0 deletions backend/models/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import os
import sqlalchemy as sql
import sqlalchemy.orm as orm
from src.patterns import SingletonMeta


__all__ = (
"Database",
"db_session",
)

DATABASE_URL = f"mysql+pymysql://{os.getenv('DATABASE_URL')}"


class Database(metaclass=SingletonMeta):
"""This class represents the database connection. It is a singleton class,
meaning that there will only be one instance of it at any given time. This
instance will be shared among all the classes that need to access the
database.
"""

engine = sql.create_engine(DATABASE_URL, echo=True)
sessionmaker = orm.sessionmaker(
autocommit=False, autoflush=False, bind=engine)

def init_db(self, base):
base.metadata.create_all(self.engine)

def delete_db(self, base):
base.metadata.drop_all(self.engine)


def db_session() -> orm.Session: # type: ignore
"""Creates a new local database session through which you can access the database and update it.
This is made using a yield such that finally the session once created will be closed.

Returns - Session: A new database session.
"""

db = Database.sessionmaker()

try:
yield db
finally:
db.close()
196 changes: 196 additions & 0 deletions backend/models/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import enum
import uuid
import string
import secrets
from datetime import datetime

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Date, DateTime, Enum, Float, ForeignKey, ForeignKeyConstraint, Index, Integer, JSON, LargeBinary, String, TIMESTAMP, text
from sqlalchemy.dialects.mysql import INTEGER, TINYINT
from sqlalchemy.orm import relationship

from .database import db_session

Base = declarative_base()


class MatchEnum(enum.Enum):
T20 = "t20"
ODI = "odi"
TEST = "test"


class GenderEnum(enum.Enum):
MALE = "male"
FEMALE = "female"


def create_ticket_id():
"""Create a new ticket id for a match
Returns new 6 digit TicketID
"""
alphabet = string.ascii_letters + string.digits
databse = db_session()
session = next(databse)

while True:
ticket_id = "".join(secrets.choice(alphabet) for _ in range(6))

if session.query(Ticket).filter_by(id=ticket_id).first():
continue

try:
next(databse)
except StopIteration:
pass

return ticket_id


class IccUser(Base):
__tablename__ = 'icc_user'

username = Column(String(50), primary_key=True, unique=True)
password = Column(String(255))


class Person(Base):
__tablename__ = 'person'

first_name = Column(String(50), primary_key=True, nullable=False)
last_name = Column(String(50), primary_key=True, nullable=False)
img_path = Column(String(255))
gender = Column(Enum(GenderEnum, native_enum=True))
nationality = Column(String(3))
dob = Column(Date)
email = Column(String(255))
phone = Column(String(50))
verified = Column(TINYINT, server_default=text("'0'"))
password = Column(String(255))


class Stadium(Base):
__tablename__ = 'stadiums'

name = Column(String(255), primary_key=True)
country = Column(String(3))
pincode = Column(INTEGER, nullable=False)


class Block(Base):
__tablename__ = 'blocks'
__table_args__ = (
Index('unq_blocks_stadium_name', 'stadium_name', 'name', unique=True),
)

name = Column(String(2), primary_key=True, nullable=False)
elevation = Column(Float)
x_offset = Column(Float)
y_offset = Column(Float)
stadium_name = Column(ForeignKey('stadiums.name'),
primary_key=True, nullable=False)

stadium = relationship('Stadium', backref='blocks')


class Match(Base):
__tablename__ = 'matches'

id = Column(Integer, primary_key=True)
start_time = Column(DateTime)
stadium_name = Column(ForeignKey('stadiums.name'), index=True)
country_1 = Column(String(3))
country_2 = Column(String(3))
match_format = Column(Enum(MatchEnum, native_enum=True))
finished = Column(TINYINT(1), server_default=text("'0'"))

stadium = relationship('Stadium', backref='matches')

@property
def start_time_timestamp(self):
return int(self.start_time.timestamp())


class Seat(Base):
__tablename__ = 'seats'
__table_args__ = (
Index('seat_index', 'row_name', 'seat_no',
'block_name', 'stadium_name'),
Index('uq_seat_row_seat', 'block_name', 'row_name',
'seat_no', 'stadium_name', unique=True),
Index('unq_seats_stadium_name', 'stadium_name',
'block_name', 'row_name', 'seat_no', unique=True)
)

row_name = Column(String(2), primary_key=True, nullable=False)
row_no = Column(Integer)
seat_no = Column(Integer, primary_key=True, nullable=False)
stadium_name = Column(ForeignKey('stadiums.name'),
primary_key=True, nullable=False)
block_name = Column(ForeignKey('blocks.name'),
primary_key=True, nullable=False, index=True)

block = relationship('Block', backref='seats')
stadium = relationship('Stadium', backref='seats')


class TempTicket(Base):
__tablename__ = 'temp_ticket'
__table_args__ = (
ForeignKeyConstraint(['fname', 'lname'], [
'person.first_name', 'person.last_name']),
ForeignKeyConstraint(['stadium', 'block'], [
'blocks.stadium_name', 'blocks.name']),
Index('block', 'stadium', 'block'),
Index('person', 'fname', 'lname')
)

id = Column(Integer, primary_key=True)
match_id = Column(Integer, nullable=False)
fname = Column(String(50), nullable=False)
lname = Column(String(50), nullable=False)
stadium = Column(ForeignKey('stadiums.name'), nullable=False)
block = Column(String(2), nullable=False)
row_name = Column(String(2), nullable=False)
seat_no = Column(Integer, nullable=False)
timestamp = Column(TIMESTAMP, nullable=False,
server_default=text("CURRENT_TIMESTAMP"))

person = relationship('Person')
block1 = relationship('Block')
stadium1 = relationship('Stadium')


class Ticket(Base):
__tablename__ = 'tickets'
__table_args__ = (
ForeignKeyConstraint(['fname', 'lname'], [
'person.first_name', 'person.last_name']),
ForeignKeyConstraint(['stadium', 'block', 'row_name', 'seat_no'], [
'seats.stadium_name', 'seats.block_name', 'seats.row_name', 'seats.seat_no']),
ForeignKeyConstraint(['stadium', 'block'], [
'blocks.stadium_name', 'blocks.name']),
Index('seat', 'stadium', 'block', 'row_name', 'seat_no'),
Index('block_1', 'stadium', 'block'),
Index('secret', 'match_id', 'ticket_id'),
Index('person_1', 'fname', 'lname')
)

id = Column(Integer, primary_key=True)
match_id = Column(ForeignKey('matches.id'), nullable=False)
fname = Column(String(50), nullable=False)
lname = Column(String(50), nullable=False)
stadium = Column(ForeignKey('stadiums.name'), nullable=False)
block = Column(String(2), nullable=False)
row_name = Column(String(2), nullable=False)
seat_no = Column(Integer, nullable=False)
timestamps = Column(JSON, nullable=False, default=[""])
ticket_id = Column(String(6), default=create_ticket_id)
secret_id = Column(String(36), default=lambda: str(uuid.uuid4()))
qrcode = Column(LargeBinary, nullable=True, default=None)

person = relationship('Person', backref='tickets')
match = relationship('Match', backref='tickets')
seat = relationship('Seat', backref='tickets')
block1 = relationship('Block', backref='tickets')
stadium1 = relationship('Stadium', backref='tickets')
Loading