parent
e2d29a29ad
commit
26050c0bf6
@ -0,0 +1,202 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
color: #333;
|
||||
background-color: #f4f4f9;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
nav {
|
||||
background-color: #333;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
nav a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin: 0 1rem;
|
||||
padding: 0.5rem 1rem;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 1rem;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.3s ease, color 0.3s ease;
|
||||
}
|
||||
|
||||
nav a:hover {
|
||||
background-color: #555;
|
||||
color: #f5f5f5;
|
||||
}
|
||||
|
||||
nav a:active {
|
||||
background-color: #777;
|
||||
}
|
||||
|
||||
p.no-courses {
|
||||
text-align: center;
|
||||
color: #777;
|
||||
font-size: 1.2rem;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.body a, .submit {
|
||||
display: inline-block;
|
||||
padding: 0.7rem 0.8rem;
|
||||
background-color: #4a90e2;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
font-size: 1rem;
|
||||
text-align: center;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.body a {
|
||||
margin: .5rem;
|
||||
}
|
||||
|
||||
.body a:hover, .submit:hover {
|
||||
background-color: #357abd;
|
||||
}
|
||||
|
||||
.body {
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 60%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
form {
|
||||
width: 500px;
|
||||
padding: 1.5rem;
|
||||
background-color: #f7f7f7;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
margin-top: 1rem;
|
||||
display: block;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
legend h1 {
|
||||
text-align: center;
|
||||
font-size: 1.8rem;
|
||||
color: #333;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
input, textarea, select {
|
||||
padding: 0.6rem;
|
||||
margin-top: 0.5rem;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.input, textarea, select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: 100px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background-color: #ee332d;
|
||||
color: white;
|
||||
width: 100%;
|
||||
padding: 15px 0;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.success-message {
|
||||
background-color: #51c961;
|
||||
color: white;
|
||||
width: 100%;
|
||||
padding: 15px 0;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.submit-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: end;
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.div-container {
|
||||
width: 500px;
|
||||
padding: 1.5rem;
|
||||
background-color: #f7f7f7;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.create-container {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.plus {
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.create-course {
|
||||
padding: 0 10 !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
flex-direction: row !important;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.create-course>p {
|
||||
margin: 0 5px 0 0 !important;
|
||||
}
|
||||
|
||||
.notifications {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.notifications h1 {
|
||||
vertical-align: middle;
|
||||
line-height: 50px;
|
||||
}
|
@ -0,0 +1,230 @@
|
||||
import redis
|
||||
import uuid
|
||||
|
||||
|
||||
|
||||
DEFAULT_EXPIRE_TIME = 300
|
||||
EXPIRE_REFRESH_TIME = 60
|
||||
|
||||
redis_connection = redis.Redis(host='localhost', port=6379, decode_responses=True)
|
||||
|
||||
####################################################################################
|
||||
# - PERSONS - #
|
||||
####################################################################################
|
||||
|
||||
def getPersonId(person_name, person_role):
|
||||
query = f"@name:{person_name} @role:{person_role}"
|
||||
results = redis_connection.execute_command('FT.SEARCH', 'idx:persons', query)
|
||||
if results[0] > 0:
|
||||
person_key = results[1]
|
||||
return person_key
|
||||
return False
|
||||
|
||||
def getPerson(person_id):
|
||||
return redis_connection.hgetall(f"person:{person_id}")
|
||||
|
||||
def register_redis(name, role):
|
||||
query = f"@name:{name} @role:{role}"
|
||||
results = redis_connection.execute_command('FT.SEARCH', 'idx:persons', query)
|
||||
# First element = number of results
|
||||
if results[0] > 0:
|
||||
return False
|
||||
person_key = f"person:{get_uuid4()}"
|
||||
redis_connection.hset(person_key, mapping={
|
||||
'name': name,
|
||||
'role': role
|
||||
})
|
||||
|
||||
return redis_connection.hgetall(person_key)
|
||||
|
||||
def login_redis(name, role):
|
||||
query = f"@name:{name} @role:{role}"
|
||||
results = redis_connection.execute_command('FT.SEARCH', 'idx:persons', query)
|
||||
# First element = number of results
|
||||
if results[0] > 0:
|
||||
person_key = results[1]
|
||||
return redis_connection.hgetall(person_key)
|
||||
return False
|
||||
|
||||
####################################################################################
|
||||
# - COURSES - #
|
||||
####################################################################################
|
||||
|
||||
def isExpired(course_id):
|
||||
ttl = redis_connection.ttl(f"course:{course_id}")
|
||||
if ttl == -2 or ttl == 0: # If -1, the key has no expiration
|
||||
return True
|
||||
return False
|
||||
|
||||
def isCourseFull(course):
|
||||
students = course.get('students', '') # Because it crashes with ['students'], we have to put a default value: '' here
|
||||
if not students:
|
||||
return False
|
||||
|
||||
try:
|
||||
places = int(course['places'])
|
||||
if len(students.split(',')) >= places:
|
||||
return True
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def getCourseId2(course_title, course_teacher):
|
||||
query = f"@title:{course_title} @teacher:{course_teacher}"
|
||||
results = redis_connection.execute_command('FT.SEARCH', 'idx:courses', query)
|
||||
if results[0] > 0:
|
||||
course_key = results[1]
|
||||
return course_key
|
||||
return False
|
||||
|
||||
def getCourseId(course):
|
||||
return getCourseId2(course['title'], course['teacher'])
|
||||
|
||||
def getCourse(course_id):
|
||||
return redis_connection.hgetall(f"course:{course_id}")
|
||||
|
||||
def delete_course(course_id):
|
||||
course = redis_connection.hgetall(f"course:{course_id}")
|
||||
if not course:
|
||||
return False
|
||||
redis_connection.delete(f"course:{course_id}")
|
||||
return True
|
||||
|
||||
def create_course(course_title, course_summary, course_level, course_places, course_teacher):
|
||||
course_id = get_uuid4()
|
||||
redis_connection.hset(f"course:{course_id}", mapping={
|
||||
"title": course_title,
|
||||
"summary": course_summary,
|
||||
"level": course_level,
|
||||
"places": course_places,
|
||||
"teacher": course_teacher
|
||||
})
|
||||
redis_connection.expire(f"course:{course_id}", DEFAULT_EXPIRE_TIME)
|
||||
|
||||
def update_course(course_id, course_title, course_summary, course_level, course_places, course_teacher):
|
||||
redis_connection.hset(f"course:{course_id}", mapping={
|
||||
"title": course_title,
|
||||
"summary": course_summary,
|
||||
"level": course_level,
|
||||
"places": course_places,
|
||||
"teacher": course_teacher
|
||||
})
|
||||
redis_connection.expire(f"course:{course_id}", DEFAULT_EXPIRE_TIME)
|
||||
publish(course_id, f"UPDATE: Course:{course_id} is now: Title: {course_title}, Summary: {course_summary}, Level: {course_level}, Places: {course_places}, Teacher: {course_teacher}")
|
||||
|
||||
def course_register(course_id, person_id):
|
||||
course = redis_connection.hgetall(f"course:{course_id}")
|
||||
person = redis_connection.hgetall(f"person:{person_id}")
|
||||
if not course or not person:
|
||||
return False
|
||||
|
||||
students = course.get('students', '')
|
||||
if person_id in students.split(','):
|
||||
return True
|
||||
|
||||
try:
|
||||
places = int(course['places'])
|
||||
if students != '':
|
||||
students_nb = len(students.split(','))
|
||||
if students_nb and students_nb >= places:
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
if not students:
|
||||
new_students = person_id
|
||||
else:
|
||||
new_students = students + "," + person_id
|
||||
|
||||
redis_connection.hset(f"course:{course_id}", "students", new_students)
|
||||
return True
|
||||
|
||||
def course_unregister(course_id, person_id):
|
||||
course = redis_connection.hgetall(f"course:{course_id}")
|
||||
person = redis_connection.hgetall(f"person:{person_id}")
|
||||
if not course or not person:
|
||||
return False
|
||||
|
||||
students = course.get('students', '')
|
||||
if person_id not in students.split(','):
|
||||
return True
|
||||
|
||||
students_list = students.split(",")
|
||||
if len(students_list) == 1:
|
||||
new_students = ""
|
||||
else:
|
||||
new_students = ",".join([student for student in students_list if student != person_id])
|
||||
|
||||
redis_connection.hset(f"course:{course_id}", "students", new_students)
|
||||
return True
|
||||
|
||||
def refresh_expire(course_id):
|
||||
course = redis_connection.hgetall(f"course:{course_id}")
|
||||
if not course:
|
||||
return False
|
||||
ttl = redis_connection.ttl(f"course:{course_id}")
|
||||
if ttl <= 0:
|
||||
return False
|
||||
redis_connection.expire(f"course:{course_id}", ttl + EXPIRE_REFRESH_TIME)
|
||||
return True
|
||||
|
||||
####################################################################################
|
||||
# - LINKS - #
|
||||
####################################################################################
|
||||
|
||||
def getCoursesFromPerson(person_id):
|
||||
course_keys = redis_connection.keys(f"course:*")
|
||||
courses = []
|
||||
person = redis_connection.hgetall(f"person:{person_id}")
|
||||
for key in course_keys:
|
||||
course_data = redis_connection.hgetall(key)
|
||||
if person['role'] == "Student":
|
||||
if person_id in course_data.get('students', '').split(","):
|
||||
course_id = getCourseId2(course_data['title'], course_data['teacher'])
|
||||
if course_id == False:
|
||||
continue
|
||||
course_data['id'] = course_id.split(":")[1]
|
||||
courses.append(course_data)
|
||||
else:
|
||||
teacher_id = course_data["teacher"]
|
||||
if teacher_id == person_id:
|
||||
course_id = getCourseId2(course_data['title'], course_data['teacher'])
|
||||
if course_id == False:
|
||||
continue
|
||||
course_data['id'] = course_id.split(":")[1]
|
||||
courses.append(course_data)
|
||||
return courses
|
||||
|
||||
def isPersonRegisteredToCourse(course, person):
|
||||
if not person:
|
||||
return False
|
||||
|
||||
person_id = getPersonId(person["name"], person["role"]).split(":")[1]
|
||||
if not person_id:
|
||||
return False
|
||||
|
||||
course_id = getCourseId(course)
|
||||
if not course_id:
|
||||
return False
|
||||
|
||||
course_keys = redis_connection.keys(f"course:*")
|
||||
for key in course_keys:
|
||||
course_data = redis_connection.hgetall(key)
|
||||
if person['role'] == "Student":
|
||||
if person_id in course_data.get('students', '').split(","):
|
||||
current_course_id = getCourseId2(course_data['title'], course_data['teacher'])
|
||||
if current_course_id == False:
|
||||
continue
|
||||
if course_id == current_course_id:
|
||||
return True
|
||||
return False
|
||||
|
||||
####################################################################################
|
||||
# - UTILS - #
|
||||
####################################################################################
|
||||
|
||||
def get_uuid4():
|
||||
return str(uuid.uuid4()).replace('-', '')
|
||||
|
||||
def publish(course_id, message):
|
||||
redis_connection.publish(course_id, message)
|
Loading…
Reference in new issue