Compare commits

...

3 commits

Author SHA1 Message Date
e718ae905d added EventNotifyer 2024-01-08 22:03:51 +02:00
a63b31da04 remove unused infra 2024-01-08 21:34:00 +02:00
7778626bcb added notifyed col to db 2024-01-08 21:12:29 +02:00
7 changed files with 131 additions and 53 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_id (string, required, foreign key)
- Event_id (Integer, required, foreign key)
- Notification Made (bool, required)
- Notifiyed Made (bool, default: false)
# API EndPoints

19
app.py
View file

@ -9,6 +9,8 @@ from middlewares.errorHandlers import handle_auth_error, handle_invalid_token
from flask_jwt_extended.exceptions import NoAuthorizationError
from jwt.exceptions import InvalidTokenError
from datetime import timedelta
from flask_apscheduler import APScheduler
from services.EventNotifyerService import EventNotifyerServer
class App:
def __init__(self):
@ -18,6 +20,15 @@ class App:
self.set_up_jwt()
self.register_blueprints()
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):
self.app.config.from_object(config.Config)
@ -44,6 +55,7 @@ class App:
def run(self):
with self.app.app_context():
db.create_all()
self.setup_scheduler() # Setup scheduler
self.app.run(debug=True)
def print_endpoints(self):
@ -54,6 +66,13 @@ class App:
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_instance = app_class_instance.app

View file

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

View file

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

View file

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