Skip to content

Commit

Permalink
♻️ changing codebase and ui interface
Browse files Browse the repository at this point in the history
  • Loading branch information
CodewithSegNet committed Sep 10, 2024
1 parent 175f839 commit aa208a8
Show file tree
Hide file tree
Showing 36 changed files with 1,007 additions and 395 deletions.
16 changes: 5 additions & 11 deletions api/v2/controllers/admin_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import os
import pymysql
from MySQLdb import OperationalError
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity
from dotenv import load_dotenv
import time
import traceback
Expand Down Expand Up @@ -129,22 +130,15 @@ def post(self):
"""
Create a JWT token
"""
token = jwt.encode(
{
"admin_user_id": user.email,
"exp": datetime.utcnow()
+ timedelta(hours=2),
},
"secret_key",
algorithm="HS256",
)
access_token = create_access_token(identity=user.email, expires_delta=timedelta(hours=2))


response = {
'token': token,
'token': access_token,
'admin_user_id': user.email
}

session["admin_token"] = token
session["admin_token"] = access_token
session["admin_user_id"] = user.email

return response, 200
Expand Down
2 changes: 1 addition & 1 deletion api/v2/controllers/homepage_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def home():
image1 = os.path.join(current_app.config["UPLOAD_FOLDER"], "section-img.png")
image2 = os.path.join(current_app.config["UPLOAD_FOLDER"], "slider.jpg")
image3 = os.path.join(current_app.config["UPLOAD_FOLDER"], "student.webp")
image4 = os.path.join(current_app.config["UPLOAD_FOLDER"], "logo_2.webp")
image4 = os.path.join(current_app.config["UPLOAD_FOLDER"], "logo_2.avif")
image5 = os.path.join(current_app.config["UPLOAD_FOLDER"], "sunPics1.webp")
image6 = os.path.join(current_app.config["UPLOAD_FOLDER"], "sunPics2.webp")
# image7 = os.path.join(app.config['UPLOAD_FOLDER'], 'icon-close.svg')
Expand Down
5 changes: 5 additions & 0 deletions api/v2/controllers/images_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@



def allowed_file(filename):
allowed_extensions = {"png", "jpg", "jpeg", "gif"}
return '.' in filename and filename.rsplit('.', 1)[1].lower() in allowed_extensions



Expand All @@ -34,6 +37,7 @@
def upload_image():
try:
if "user_id" in session:
print("Request files:", request.files)
admission_number = session.get("user_id")
token = session.get("token")

Expand All @@ -46,6 +50,7 @@ def upload_image():
filename = file.filename
image_data = os.path.join(current_app.config["UPLOAD_FOLDER"], filename)
file.save(image_data)

# Create a new image record and associate it with the student
image = Image(
student_admission_number=admission_number, image_data=image_data
Expand Down
105 changes: 81 additions & 24 deletions api/v2/controllers/notification_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,60 +41,117 @@
Notification
)
from app import cache, db
from views import *
from flask_jwt_extended import jwt_required, get_jwt_identity
from werkzeug.exceptions import Forbidden
from api.v2.controllers.admin_controller import admin_ns, login_model
from flask_restx import Namespace, Resource, fields


@admin_ns.route('/notifications')
class Notification(Resource):
@admin_ns.expect(login_model)
# Define the Namespace for the student API
notification_ns = Namespace('notification', description='notification related operations')



@notification_ns.route('/')
class Notifications(Resource):
@jwt_required()
def post(self):
"""
An Endpoint to send notifications to student
"""

admin_id = get_jwt_identity()
admin = Admin.query.get(admin_id)
admin = Admin.query.filter_by(email=admin_id).first()

if not admin:
raise Forbidden("You are not authorized to perform this action.")


data = request.get_json()
# validate input
if not all(key in data for key in ['name', 'subject', 'messages', 'semesters', 'department_name', 'department_level']):
return jsonify({"success": False, "message": "Missing required fields"}), 400

# Validate input
if not all(key in data for key in ['name', 'subject', 'message']):
return {"success": False, "message": "Missing required fields"}, 400

# Create the notification
notification = Notification(
name=data['name'],
subject=data['subject'],
message=data['message']
)

# Add related semesters if provided
if 'semesters' in data:
for semester_id in data['semesters']:
semester = Semester.query.get(semester_id)
if semester:
notification.semesters.append(semester)

# Add related departments if provided
if 'department_name' in data:
for department_id in data['department_name']:
department = Department.query.get(department_id)
if department:
notification.departments.append(department)

# Add related semesters
for semester_id in data['semesters']:
semester = Semester.query.get(semester_id)
if semester:
# Handle sending to specific department based on name and level
if 'department_name' in data and 'department_level' in data:
departments = Department.query.filter_by(
department_name=data['department_name'],
department_level=data['department_level']
).all()
for department in departments:
notification.departments.append(department)

if 'semesters' in data:
semester = Semester.query.filter_by(
semester = data['semesters']
).all()
for semester in semester:
notification.semesters.append(semester)

# Add related departments
for department_id in data['department_name']:
department = Department.query.get(department_id)
if department:
notification.departments.append(department)
# Handle sending to all students in provided semesters
if 'semesters' in data:
for semester_id in data['semesters']:
students = Student.query.join(Student.semesters).filter(Semester.id == id).all()
for student in students:
notification.students.append(student)

# Handle sending to all students in a specific department
if 'department_name' in data:
students = Student.query.filter_by(department_name=data['department_name']).all()
for student in students:
notification.students.append(student)

# Handle sending to everybody
if data.get('send_to_everybody', False):
all_students = Student.query.all()
notification.students.extend(all_students)

# Save the notification to the database
db.session.add(notification)
db.session.commit()

return jsonify({"success": True, "message": "Notification sent successfully"}), 201





return {"success": True, "message": "Notification sent successfully"}, 201



@notification_ns.route('/')
class NotificationList(Resource):
@jwt_required()
def get(self):
"""
Endpoint to retrieve paginated notifications.
"""
page = request.args.get('page', 1, type=int)
per_page = 10 # Number of notifications per page

# Retrieve paginated notifications from the database
notifications = Notification.query.paginate(page=page, per_page=per_page, error_out=False)

return render_template(
'notifications.html',
notifications=notifications.items,
page=page,
total_pages=notifications.pages
)
74 changes: 72 additions & 2 deletions api/v2/controllers/student_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ def get_student_info():
student_info["semesters"] = [
{"semester": semester.semester} for semester in student.semesters
]


encoded_student_info = quote(json.dumps(student_info))

Expand Down Expand Up @@ -315,7 +316,7 @@ def post(self):
new_semester = Semester(semester=semester_name)
new_user.semesters.append(new_semester)
db.session.add(new_semester)
db.session.commit() # Commit changes after creating a new semester
db.session.commit()
else:
new_user.semesters.append(semester)

Expand Down Expand Up @@ -437,13 +438,30 @@ def student_dashboard():
token = session.get("token") or request.args.get('token')

if not admission_number or not token:
return render_template("unauthorized.html"), 401
return render_template("signin_student.html"), 401


current_user = Student.query.get(admission_number)
courses = current_user.courses
departments = current_user.departments
semesters = current_user.semesters
images = current_user.images

# Fetch notifications for the student
page = request.args.get('page', 1, type=int)
per_page_all = 6

notifications_query = (Notification.query
.join(Notification.students)
.filter(Student.id == current_user.id)
.order_by(Notification.created_at.desc()))

# For displaying only two notifications on the dashboard
notifications_dashboard = notifications_query.limit(2).all()

# For displaying all notifications in the "View All" section
notifications_paginated = notifications_query.paginate(page=page, per_page=per_page_all, error_out=False)
notifications_all = notifications_paginated.items

# Encode admission number
encoded_admission_number = current_user.admission_number.replace("/", "%2F")
Expand All @@ -459,10 +477,21 @@ def student_dashboard():
user_image=image1,
user_image_path=user_image_path,
images=images,
notifications_dashboard=notifications_dashboard,
notifications_all=notifications_all,
page=page,
per_page=per_page_all,
total=notifications_paginated.total,
pages=notifications_paginated.pages,
has_next=notifications_paginated.has_next,
has_prev=notifications_paginated.has_prev,
next_page=notifications_paginated.next_num,
prev_page=notifications_paginated.prev_num,
)




@pages_bp.route("/images", methods=["GET"])
def get_image():
admission_number = request.args.get("admission_number")
Expand Down Expand Up @@ -492,3 +521,44 @@ def get_image():

# Handle case where admission_number is not provided or image not found
return jsonify({"error": "Image not found"}), 404








@pages_bp.route("/students/notifications", methods=['GET'])
def notification_list():
"""
Renders the notifications page with pagination.
"""
# Retrieve admission number from session or request args
admission_number = session.get("user_id") or request.args.get('admission_number')

current_user = Student.query.get(admission_number)

# Fetch all notifications with pagination
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 10, type=int)

notifications_query = (Notification.query
.join(Notification.students)
.filter(Student.id == current_user.id)
.order_by(Notification.created_at.desc()))
notifications_paginated = notifications_query.paginate(page=page, per_page=per_page, error_out=False)
notifications = notifications_paginated.items

return render_template(
"notifications.html",
notifications=notifications,
page=page,
per_page=per_page,
total=notifications_paginated.total,
pages=notifications_paginated.pages,
has_next=notifications_paginated.has_next,
has_prev=notifications_paginated.has_prev,
next_page=notifications_paginated.next_num,
prev_page=notifications_paginated.prev_num,
)
15 changes: 13 additions & 2 deletions api/v2/models/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import uuid


# Association tables
# Association tables for many-to-many relationships
notification_semester = db.Table('notification_semester',
db.Column('notification_id', db.String(36), db.ForeignKey('notifications.id'), primary_key=True),
db.Column('semester_id', db.String(36), db.ForeignKey('semesters.id'), primary_key=True)
Expand All @@ -20,6 +20,11 @@
db.Column('department_id', db.String(36), db.ForeignKey('departments.id'), primary_key=True)
)

student_notification = db.Table('student_notification',
db.Column('student_id', db.String(50), db.ForeignKey('students.admission_number'), primary_key=True),
db.Column('notification_id', db.String(36), db.ForeignKey('notifications.id'), primary_key=True)
)

class Notification(db.Model):
__tablename__ = "notifications"
id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()), nullable=False)
Expand All @@ -35,6 +40,12 @@ class Notification(db.Model):
# Many-to-many relationships
semesters = db.relationship('Semester', secondary=notification_semester, backref='notifications')
departments = db.relationship('Department', secondary=notification_department, backref='notifications')
students = db.relationship('Student', secondary=student_notification)


def mark_as_read(self):
self.is_read = True
self.is_read = True
db.session.commit()

def __repr__(self):
return f'<Notification id={self.id} name={self.name} subject={self.subject}>'
5 changes: 5 additions & 0 deletions api/v2/models/student_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from api.v2.models.course_model import Course
from api.v2.models.department_model import Department
from api.v2.models.image import Image
from api.v2.models.notifications import Notification, student_notification
from app import db
from datetime import datetime
import re
Expand All @@ -22,6 +23,7 @@ class Student(db.Model):
"""

__tablename__ = "students"
id = db.Column(db.String(36), default=lambda: str(uuid.uuid4()), nullable=False)
admission_number = db.Column(db.String(50), primary_key=True, nullable=False)
password = db.Column(db.String(255), nullable=False)
name = db.Column(db.String(255), nullable=True)
Expand All @@ -47,6 +49,9 @@ class Student(db.Model):

# Relationship with semester
semesters = db.relationship("Semester", backref="students")

# Relationship with notification
notifications = db.relationship("Notification", secondary=student_notification, backref='student_notifications')

def set_password(self, password):
self.password = generate_password_hash(password)
Expand Down
Loading

0 comments on commit aa208a8

Please sign in to comment.