Compare commits

..

No commits in common. "e718ae905d486afeee1ad9313ad61ba8d106e101" and "22c080572e173fdd525ad0a25c288f4e2c575b78" have entirely different histories.

7 changed files with 53 additions and 131 deletions

View file

@ -52,7 +52,7 @@ update, delete, and be reminded of events with additional advanced features.
- User Event Association (Many to Many) - User Event Association (Many to Many)
- User_id (string, required, foreign key) - User_id (string, required, foreign key)
- Event_id (Integer, required, foreign key) - Event_id (Integer, required, foreign key)
- Notifiyed Made (bool, default: false) - Notification Made (bool, required)
# API EndPoints # API EndPoints

19
app.py
View file

@ -9,8 +9,6 @@ from middlewares.errorHandlers import handle_auth_error, handle_invalid_token
from flask_jwt_extended.exceptions import NoAuthorizationError from flask_jwt_extended.exceptions import NoAuthorizationError
from jwt.exceptions import InvalidTokenError from jwt.exceptions import InvalidTokenError
from datetime import timedelta from datetime import timedelta
from flask_apscheduler import APScheduler
from services.EventNotifyerService import EventNotifyerServer
class App: class App:
def __init__(self): def __init__(self):
@ -20,15 +18,6 @@ class App:
self.set_up_jwt() self.set_up_jwt()
self.register_blueprints() self.register_blueprints()
self.setup_error_handlers() self.setup_error_handlers()
self.scheduler = APScheduler()
def setup_scheduler(self):
self.app.config.from_object(self.SchadulerConfig())
self.scheduler.init_app(self.app)
self.scheduler.start()
# Schedule the job
self.scheduler.add_job(id='locate_upcoming_events', func=self.locate_upcoming_events, trigger='interval', seconds=1)
def set_config(self): def set_config(self):
self.app.config.from_object(config.Config) self.app.config.from_object(config.Config)
@ -55,7 +44,6 @@ class App:
def run(self): def run(self):
with self.app.app_context(): with self.app.app_context():
db.create_all() db.create_all()
self.setup_scheduler() # Setup scheduler
self.app.run(debug=True) self.app.run(debug=True)
def print_endpoints(self): def print_endpoints(self):
@ -66,13 +54,6 @@ class App:
print(f" Function: {function_name}") print(f" Function: {function_name}")
def SchadulerConfig(object):
SCHEDULER_API_ENABLED = True
def locate_upcoming_events(self):
with self.app.app_context():
print(EventNotifyerServer.locate_upcoming_events())
app_class_instance = App() app_class_instance = App()
app_instance = app_class_instance.app app_instance = app_class_instance.app

7
infra/docker-compose.yml Normal file
View file

@ -0,0 +1,7 @@
version: '3'
services:
redis:
image: redis:latest
ports:
- "6379:6379"

View file

@ -1,44 +0,0 @@
"""AddA_col_Notifyed_Bool
Revision ID: 04e41f293ec2
Revises: 902a6851ae27
Create Date: 2024-01-08 21:11:13.952001
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '04e41f293ec2'
down_revision = '902a6851ae27'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('user_event', schema=None) as batch_op:
batch_op.add_column(sa.Column('notified', sa.Boolean(), nullable=True))
batch_op.alter_column('user_id',
existing_type=sa.VARCHAR(length=36),
nullable=False)
batch_op.alter_column('event_id',
existing_type=sa.INTEGER(),
nullable=False)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('user_event', schema=None) as batch_op:
batch_op.alter_column('event_id',
existing_type=sa.INTEGER(),
nullable=True)
batch_op.alter_column('user_id',
existing_type=sa.VARCHAR(length=36),
nullable=True)
batch_op.drop_column('notified')
# ### end Alembic commands ###

View file

@ -1,27 +1,28 @@
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt from flask_bcrypt import Bcrypt
from sqlalchemy import Column, Integer, ForeignKey, String, Boolean from sqlalchemy import Table, Column, Integer, ForeignKey, String
import uuid import uuid
db = SQLAlchemy() db = SQLAlchemy()
bcrypt = Bcrypt() bcrypt = Bcrypt()
class UserEventAssociation(db.Model):
__tablename__ = 'user_event' user_event_association = Table('user_event', db.Model.metadata,
user_id = Column(String(36), ForeignKey('user.id'), primary_key=True) Column('user_id', String(36), ForeignKey('user.id')),
event_id = Column(Integer, ForeignKey('event.id'), primary_key=True) Column('event_id', Integer, ForeignKey('event.id'))
notified = Column(Boolean, default=False) )
class Event(db.Model): class Event(db.Model):
id = Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
title = Column(db.String(100), nullable=False) title = db.Column(db.String(100), nullable=False)
description = Column(db.String(200), nullable=False) description = db.Column(db.String(200), nullable=False)
location = Column(db.String(100), nullable=False) location = db.Column(db.String(100), nullable=False)
deleted = Column(Boolean, default=False) deleted = db.Column(db.Boolean, default=False)
duedate = Column(db.DateTime, nullable=False) duedate = db.Column(db.DateTime, nullable=False)
created_at = Column(db.DateTime, default=db.func.now()) created_at = db.Column(db.DateTime, default=db.func.now())
user_id = Column(String(36), db.ForeignKey('user.id'), nullable=False) user_id = db.Column(db.String(36), db.ForeignKey('user.id'), nullable=False)
users = db.relationship('User', secondary='user_event', back_populates='events') users = db.relationship('User', secondary=user_event_association, back_populates='events')
def to_dict(self): def to_dict(self):
return { return {
@ -35,12 +36,14 @@ class Event(db.Model):
} }
class User(db.Model): class User(db.Model):
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
name = Column(db.String(100), nullable=False) name = db.Column(db.String(100), nullable=False)
email = Column(db.String(120), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = Column(db.String(128), nullable=False) password_hash = db.Column(db.String(128), nullable=False)
location = Column(db.String(100), nullable=False) location = db.Column(db.String(100), nullable=False)
events = db.relationship('Event', secondary='user_event', back_populates='users') events = db.relationship('Event', secondary=user_event_association, back_populates='users')
def set_password(self, password): def set_password(self, password):
self.password_hash = bcrypt.generate_password_hash(password).decode('utf-8') self.password_hash = bcrypt.generate_password_hash(password).decode('utf-8')
@ -55,3 +58,4 @@ class User(db.Model):
'email': self.email, 'email': self.email,
'location': self.location 'location': self.location
} }

View file

@ -1,10 +0,0 @@
# this Class is for the scheduler
#this class will have a function that locates the upcomming events Using the Event service.
from services.EventService import EventService
class EventNotifyerServer:
def __init__(self):
pass
def locate_upcoming_events():
return EventService.get_all_upcomming_events()

View file

@ -1,10 +1,9 @@
from sqlalchemy.sql import exists from sqlalchemy.sql import exists
from models import db, Event, UserEventAssociation, User from models import db, Event, user_event_association
from services.UserService import UserService from services.UserService import UserService
from datetime import datetime from datetime import datetime
from flask import g from flask import g
from sqlalchemy import func from sqlalchemy import func
from datetime import timedelta
class EventService: class EventService:
@staticmethod @staticmethod
@ -32,9 +31,7 @@ class EventService:
if sort_by == 'date': if sort_by == 'date':
query = query.order_by(Event.duedate) query = query.order_by(Event.duedate)
elif sort_by == 'popularity': elif sort_by == 'popularity':
query = query.join(UserEventAssociation, Event.id == UserEventAssociation.event_id)\ query = query.outerjoin(user_event_association).group_by(Event.id).order_by(func.count(user_event_association.c.user_id).desc())
.group_by(Event.id)\
.order_by(func.count(UserEventAssociation.user_id).desc())
elif sort_by == 'creation': elif sort_by == 'creation':
query = query.order_by(Event.created_at) query = query.order_by(Event.created_at)
@ -85,26 +82,25 @@ class EventService:
return {'error': 'Event not found or already passed'} return {'error': 'Event not found or already passed'}
# Check if the user is already associated with the event # Check if the user is already associated with the event
is_already_attending = UserEventAssociation.query.filter_by( is_already_attending = db.session.query(exists().where(
user_id=user_id, user_event_association.c.user_id == user_id,
event_id=event_id user_event_association.c.event_id == event_id
).first() )).scalar()
if is_already_attending: if is_already_attending:
return {'error': 'User already attending this event'} return {'error': 'User already attending this event'}
# Add the user to the event # Add the user to the event
user_event_association = UserEventAssociation( user = UserService.get_user_by_id(user_id)
user_id=user_id, if not user:
event_id=event_id return {'error': 'User not found'}
)
db.session.add(user_event_association) event.users.append(user)
db.session.commit() db.session.commit()
return {'message': 'User successfully added to the event'} return {'message': 'User successfully added to the event'}
@staticmethod @staticmethod
def unattend_event(event_id): def unattend_event(event_id):
user_id = g.user_id # Assuming user_id is stored in Flask's global g object user_id = g.user_id # Assuming user_id is stored in Flask's global g object
@ -118,33 +114,21 @@ class EventService:
if not event: if not event:
return {'error': 'Event not found or already passed'} return {'error': 'Event not found or already passed'}
user_event_association = UserEventAssociation.query.filter_by( # Check if the user is already associated with the event
user_id=user_id, is_already_attending = db.session.query(exists().where(
event_id=event_id user_event_association.c.user_id == user_id,
).first() user_event_association.c.event_id == event_id
)).scalar()
if not is_already_attending:
if not user_event_association:
return {'error': 'User not attending this event'} return {'error': 'User not attending this event'}
# Remove the user from the event
user = UserService.get_user_by_id(user_id) user = UserService.get_user_by_id(user_id)
if not user: if not user:
return {'error': 'User not found'} return {'error': 'User not found'}
event.users.remove(user)
db.session.delete(user_event_association)
db.session.commit() db.session.commit()
return {'message': 'User successfully removed from the event'} return {'message': 'User successfully removed from the event'}
@staticmethod
def get_all_upcomming_events():
now = datetime.now()
upcoming_deadline = now + timedelta(minutes=30)
events = Event.query.filter(
Event.duedate <= upcoming_deadline,
Event.deleted == False
).all()
return [event.to_dict() for event in events]