From 2fbed247ea2447a8cb254508b2abff7ee9c94d42 Mon Sep 17 00:00:00 2001 From: AbaadirYasin Date: Fri, 17 May 2024 13:25:49 +0100 Subject: [PATCH] Initial commit with Flask app and notifications feature --- server/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 132 bytes server/notifications/__init__.py | 5 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 262 bytes .../__pycache__/app.cpython-310.pyc | Bin 0 -> 980 bytes .../__pycache__/models.cpython-310.pyc | Bin 0 -> 1595 bytes .../__pycache__/routes.cpython-310.pyc | Bin 0 -> 3526 bytes server/notifications/app.py | 24 +++++ server/notifications/models.py | 26 ++++++ server/notifications/routes.py | 86 ++++++++++++++++++ 9 files changed, 141 insertions(+) create mode 100644 server/__pycache__/__init__.cpython-310.pyc create mode 100644 server/notifications/__init__.py create mode 100644 server/notifications/__pycache__/__init__.cpython-310.pyc create mode 100644 server/notifications/__pycache__/app.cpython-310.pyc create mode 100644 server/notifications/__pycache__/models.cpython-310.pyc create mode 100644 server/notifications/__pycache__/routes.cpython-310.pyc create mode 100644 server/notifications/app.py create mode 100644 server/notifications/models.py create mode 100644 server/notifications/routes.py diff --git a/server/__pycache__/__init__.cpython-310.pyc b/server/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..60a980bd74b1136185e0b265d9fa923967826792 GIT binary patch literal 132 zcmd1j<>g`kf{E#_X(0MBh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o2BV4e5Ztv7giavk8C-)aibzqERB1@0i0&H8V4tvJpTWK)qRwmbCAU<3AywAU zFw)NM%&um`Y*qu|e)ZBB>Zc-Z!ALw&r8$uXjSf7vh-GGudERmagFnz#h7*r8Uqe%! z=^7f$_4u+O435(}iNLN$p4QS&Ia1Hv22jVGyFkL`{f+D2tn zw)_Ju`K8&i>MyWB+;P+rG1eTN`RPmJ3R^kd(J(X6yD%CuV*1THjuf%oQ@EX9?u=*8wI%$U5g~VPG z{SJ8>WaE4@tcCS&Lbc(PyRF~DeW;Cjr56YJ#XT05#HH|*D>R7Ww!)Q3P8iomX%Wq$ zX;4II!j+RWFSy!C&r(*vX)Q{k!Vj`+D&!uP5EG4cVCUBW1uF0z{sQgYqH`&f4pAtV zOaWFYnF_30G7VU*WOZPTlIg&jCEIxPZ62aR{;u4jAJAA)d1T1M0`17@hYnz>8e>m>;d;N~-_QxY<*~)2=?UU<(W--~Hrj$2^W`E#2mi@u9 zqhkpnUMoE(W7~DPUh)aZy8~yreUmQO9uco_w64*7$g)S~&{}T&OWS*BhOcr?Ovm{+ zw!3_*Jkqs#=49Z)^`ow3w^auBBd+nU94kG(poBRVdc+XHwO0E literal 0 HcmV?d00001 diff --git a/server/notifications/__pycache__/models.cpython-310.pyc b/server/notifications/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6d1dddf014d2a17ce2195e6396f2d5b5be10c02 GIT binary patch literal 1595 zcmcJPOK;Oa6ooyG9Xl`jpj71{1Og<&qFJy-s4A!x0wScAO$4&0nMvx@k92HP!WOpu z4`tZ}e`vO>vS-y5=h~)Cr51q@mgZ>Y%-DDQ-8&PvT6F`@`&XNTZ_&Ls-K8VhCHZQRQ=`XThlo2aZ!ZHXK*f;M7W|3a2g_ za2loKh~}2jZcQ0NwV5`>&J;cBx`L-N^+VYwWA?EzSVK$JA=2nEVf0K{8ChtyV8T2! zd(~omZJ^|~0`Pq1a@_B*{D0vt;A-nloTLR^braz>)Get01IJU{ zMz7nR`vaKj4wkCBBn82KjIxeWb&o89r|y$HAUUnu8A1;+LFq~;tG@`XFh%~q@R=z^ zGrtV-E8|=_;!?P%97{epr@OH#2~7pIQxM8w{SBdD#@!qWKteu7f7uMR@`FQj7-f!L;hs9!! zz_a%8wboBXLVm|W`Z1vJ9=y@dkZ{7OPXbz}0jsk>t80{S#x-9LjJgq+bu-A+Gl5mN zf^0oYiA%Ze=D5MlM_N7a=GO~6!>v`yvyT|h@%%&bfYytuzQBva`VyZ~^(9q5&1Z)7 zWj?Fwr&Rrc(KrYBAyq%E>JN|VkMN_aeuf|8#~+eWLlL2dQc@`@Y|GJHl(n zG9%nOT{nWvdK9+3R&R%*j3F6ck%h%D_F7)kiM_Bb&4q9+6tUEAgdnfqj9ej$?UY2+ zFV)7%RVs5`;Ws+MZF%?lMlEvN9QuE{vU{J9yM`Q&mPn{T4e#==toHU7h|$T zx5*|MkS)gPHr=Eu#~{ZBRLl-oG#6`JlxsXdDn9L}ZL41>UnW%la5rrS|q z7z!m|M#nAf?nM^TGfL_{CgK!~_~iB4S{S%BXT@>2Cu(;#YJt-MIK*97j1yE7VK;W8 zbDf?%jN53WM{KA@T;m@nAz{p-Irv$$ObhVK!M6mzIcj~${uVER2mpE+sJ}F{(7e>H zU0rS>@y{OA$B4f+6o3P=PS@E0&i^C2r2&aF*74*&Bm?>ZoMK>3AMs=K-T;1>;>YC1 zfQ|UkxtXSI$Pc^E6hH7){A3raRB3Q*RSXt_23dkPdIgeII1OJ+!%3j)u!?p3vMr61 zZOrMMey@MS?!d@Z)}N`|I$H_OR=8cceyQ@wrOHxOm(1e|H<^t+pfq-Zj?8#bL%0sF z8scS`LbVH=Oj=PaS|}*0P^>b^&YhREt&Eu@r%^0-+4rIt_~^_ZgK|`Y#3annpXy)? zc%SwwNLt#4(Yech*mV489x~5*i-XWp9KvJz&Q|}s+Mq@$BGv*K~htjo7uB+Twinq62{5^9W%_o@GY4m zkjKH> zHT1;K4SgF#9wm_(v1#=dMr>xem0}ae%PQ$y%C}9jnO{uIacD8+^wF!>t*{F&=36*O z%ZV2|J|+@4;r$y#6z6}1&O1WD6fTlDz7DwKrx3& z%EoeP!UDoZiRaoImpXL^LQ?SRL?11!pz%tBIS;v(iT-u35hgGa91H>Vn`cZ=cm*DEo!WE;GV5H zoz7%5v*1X?4QRNDGvM{2M8&)CS**@Vqvbo%ZGpAPF+tZV%^>8iA0_%w2SOber6Y7| z(rPsD#5Wq^9V{B^cBZaf0!bI>9R)J1_N!(~ElY*l)7a6v3^R3ocOJD6;rTm2=4gqP TSdNya;4Q*ifOj@W3se69Z*4t^ literal 0 HcmV?d00001 diff --git a/server/notifications/app.py b/server/notifications/app.py new file mode 100644 index 00000000..74b9300d --- /dev/null +++ b/server/notifications/app.py @@ -0,0 +1,24 @@ +from flask import Flask +from . import db, mail +from .models import User, Notification, Post, Cohort +from .routes import init_app + +def create_app(): + app = Flask(__name__) + app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://username:password@localhost/moringa_alumni' + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + app.config['MAIL_SERVER'] = 'smtp.example.com' + app.config['MAIL_PORT'] = 587 + app.config['MAIL_USE_TLS'] = True + app.config['MAIL_USERNAME'] = 'your-email@example.com' + app.config['MAIL_PASSWORD'] = 'your-email-password' + app.config['MAIL_DEFAULT_SENDER'] = 'your-email@example.com' + + db.init_app(app) + mail.init_app(app) + init_app(app) + return app + +if __name__ == '__main__': + app = create_app() + app.run(debug=True) diff --git a/server/notifications/models.py b/server/notifications/models.py new file mode 100644 index 00000000..ee1ee0e6 --- /dev/null +++ b/server/notifications/models.py @@ -0,0 +1,26 @@ +from . import db +from datetime import datetime + +class User(db.Model): + id = db.Column(db.Integer, primary_key=True) + email = db.Column(db.String(120), unique=True, nullable=False) + notifications = db.relationship('Notification', backref='user', lazy=True) + +class Notification(db.Model): + id = db.Column(db.Integer, primary_key=True) + user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) + message = db.Column(db.String(250), nullable=False) + timestamp = db.Column(db.DateTime, default=datetime.utcnow, nullable=False) + is_read = db.Column(db.Boolean, default=False, nullable=False) + +class Post(db.Model): + id = db.Column(db.Integer, primary_key=True) + user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) + content = db.Column(db.String(500), nullable=False) + timestamp = db.Column(db.DateTime, default=datetime.utcnow, nullable=False) + +class Cohort(db.Model): + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(100), nullable=False) + user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) + timestamp = db.Column(db.DateTime, default=datetime.utcnow, nullable=False) diff --git a/server/notifications/routes.py b/server/notifications/routes.py new file mode 100644 index 00000000..0dea43be --- /dev/null +++ b/server/notifications/routes.py @@ -0,0 +1,86 @@ +from flask import Blueprint, request, jsonify +from .models import db, Notification, Cohort, Post, User + +notifications_bp = Blueprint('notifications', __name__, url_prefix='/notifications') + +@notifications_bp.route('/send', methods=['POST']) +def send_notification_route(): + try: + data = request.get_json() + user_id = data.get('user_id') + message = data.get('message') + if not user_id or not message: + return jsonify({'error': 'Invalid input data'}), 400 + notification = Notification(user_id=user_id, message=message) + db.session.add(notification) + db.session.commit() + return jsonify({'message': 'Notification sent successfully'}), 200 + except Exception as e: + print(f"An error occurred: {e}") + return jsonify({'error': 'An error occurred while sending notification'}), 500 + +@notifications_bp.route('/', methods=['GET']) +def get_notifications(user_id): + try: + notifications = Notification.query.filter_by(user_id=user_id).all() + return jsonify([{ + 'id': n.id, + 'message': n.message, + 'timestamp': n.timestamp.strftime("%Y-%m-%d %H:%M:%S"), + 'is_read': n.is_read + } for n in notifications]), 200 + except Exception as e: + print(f"An error occurred: {e}") + return jsonify({'error': 'An error occurred while retrieving notifications'}), 500 + +@notifications_bp.route('/read/', methods=['PATCH']) +def read_notification(notification_id): + try: + notification = Notification.query.get(notification_id) + if not notification: + return jsonify({'error': 'Notification not found'}), 404 + notification.is_read = True + db.session.commit() + return jsonify({'message': 'Notification marked as read'}), 200 + except Exception as e: + print(f"An error occurred: {e}") + return jsonify({'error': 'An error occurred while marking notification as read'}), 500 + +@notifications_bp.route('/cohorts/join', methods=['POST']) +def join_cohort(): + try: + data = request.get_json() + user_id = data.get('user_id') + name = data.get('name') + if not user_id or not name: + return jsonify({'error': 'Invalid input data'}), 400 + new_cohort = Cohort(name=name, user_id=user_id) + db.session.add(new_cohort) + db.session.commit() + message = "You have joined a new cohort" + notification = Notification(user_id=user_id, message=message) + db.session.add(notification) + db.session.commit() + return jsonify({'message': 'Joined cohort successfully'}), 200 + except Exception as e: + print(f"An error occurred: {e}") + return jsonify({'error': 'An error occurred while joining cohort'}), 500 + +@notifications_bp.route('/posts', methods=['POST']) +def create_post(): + try: + data = request.get_json() + user_id = data.get('user_id') + content = data.get('content') + if not user_id or not content: + return jsonify({'error': 'Invalid input data'}), 400 + new_post = Post(user_id=user_id, content=content) + db.session.add(new_post) + db.session.commit() + return jsonify({'message': 'Post created successfully'}), 201 + except Exception as e: + print(f"An error occurred: {e}") + return jsonify({'error': 'An error occurred while creating post'}), 500 + +def init_app(app): + app.register_blueprint(notifications_bp)