Added styles to pages + starting to refactor code to multiple files

master
Corentin LEMAIRE 6 months ago
parent e2d29a29ad
commit 26050c0bf6

@ -132,7 +132,7 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = 'static/'
STATIC_URL = '/static/'
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

@ -84,16 +84,16 @@ OR
### Expiration
Expiration of the course: The course expires after 2 minutes.
Expiration of the course: The course expires after 5 minutes. If a student register to the course, it add 1 minute.
---
### Design
### Students management
Design is not existing yet.
As a teacher, you can't manage students registered to your course.
---
### Students management
### Searching
As a teacher, you can't manage students registered to your course.
The search looks for title, description and level fo the course. There's no advanced search for the moment.

@ -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;
}

@ -1,4 +1,8 @@
<html>
<head>
{% load static %}
<link rel="stylesheet" href="{% static 'redis_app/style.css' %}">
</head>
<body>
<nav>
<a href="{% url 'home' %}">Home</a>
@ -16,22 +20,46 @@
<a href="{% url 'logout' %}">Logout</a>
{% endif %}
</nav>
<div class="body">
<div class="container">
<div class="div-container">
<div class="create-container">
{% if error_message %}
<p class="error-message">{{ error_message }}</p>
{% endif %}
{% if success_message %}
<p class="success-message">{{ success_message }}</p>
{% endif %}
{% if person %}
{% if person.role == "Teacher" %}
<div>
<a href="{% url 'create_course' %}" class="create-course">
<p class="plus">
+
</p>
<p>
Create
</p>
</a>
</div>
{% endif %}
{% endif %}
</div>
<h1>Courses for {{ person.name }}</h1>
{% if courses %}
<div class="courses">
{% for course in courses %}
<a href="{% url 'details' course.id %}">{{ course.title }}</a>
<a href="{% url 'details' course.id %}" class="course-link">{{ course.title }}</a>
{% endfor %}
</div>
{% else %}
<p>No course yet</p>
<p class="no-courses">No course yet</p>
{% endif %}
<p>
<p class="register-link">
Register to a course by <a href="{% url 'search' %}">Searching</a>
</p>
<br/>
{% if person %}
{% if person.role == "Teacher" %}
<a href="{% url 'create_course' %}">Create</a>
{% endif %}
{% endif %}
</div>
</div>
</div>
</body>
</html>

@ -1,4 +1,8 @@
<html>
<head>
{% load static %}
<link rel="stylesheet" href="{% static 'redis_app/style.css' %}">
</head>
<body>
<nav>
<a href="{% url 'home' %}">Home</a>
@ -16,33 +20,42 @@
<a href="{% url 'logout' %}">Logout</a>
{% endif %}
</nav>
<div class="body">
<div class="container">
<form action="{% url 'create_course_form' %}" method="POST">
{% csrf_token %}
<fieldset>
<legend><h1>Create a course</h1></legend>
{% if error_message %}
{{ error_message }}
<p class="error-message">{{ error_message }}</p>
{% endif %}
{% if success_message %}
<p class="success-message">{{ success_message }}</p>
{% endif %}
<label for="title">Course Title</label><br>
<input type="text" name="title" id="title" required><br/>
<label for="title">Course Title</label>
<input type="text" name="title" id="title" class="input" required>
<label for="summary">Course Summary</label><br>
<textarea name="summary" id="summary" required></textarea><br/>
<label for="summary">Course Summary</label>
<textarea name="summary" id="summary" required></textarea>
<label for="level">Course Level</label><br>
<label for="level">Course Level</label>
<select name="level" id="level" required>
<option value="Beginner">Beginner</option>
<option value="Intermediate">Intermediate</option>
<option value="Advanced">Advanced</option>
</select><br/>
</select>
<label for="places">Number of Places</label><br>
<input type="number" name="places" id="places" min="1" required><br/>
<label for="places" class="input">Number of Places</label>
<input type="number" name="places" id="places" min="1" class="input" required>
</fieldset>
<input type="submit" value="Create Course">
<div class="submit-container">
<input type="submit" value="Create Course" class="submit">
</div>
</form>
</div>
</div>
</body>
</html>

@ -1,4 +1,8 @@
<html>
<head>
{% load static %}
<link rel="stylesheet" href="{% static 'redis_app/style.css' %}">
</head>
<body>
<nav>
<a href="{% url 'home' %}">Home</a>
@ -16,11 +20,14 @@
<a href="{% url 'logout' %}">Logout</a>
{% endif %}
</nav>
<div class="body">
<div class="container">
<div class="div-container">
{% if error_message %}
{{ error_message }}
<p class="error-message">{{ error_message }}</p>
{% endif %}
{% if success_message %}
{{ success_message }}
<p class="success-message">{{ success_message }}</p>
{% endif %}
{% if course %}
<h1>Welcome in the course {{ course.title }}!</h1>
@ -28,7 +35,7 @@
{{ course.summary }}
</p>
<p>
This course is for {{ course.getLevel }} students
This course is for {{ course.level }} students
</p>
<p>
There's only {{ course.places }} places
@ -55,5 +62,8 @@
{% endif %}
{% endif %}
{% endif %}
</div>
</div>
</div>
</body>
</html>

@ -1,4 +1,8 @@
<html>
<head>
{% load static %}
<link rel="stylesheet" href="{% static 'redis_app/style.css' %}">
</head>
<body>
<nav>
<a href="{% url 'home' %}">Home</a>
@ -16,10 +20,22 @@
<a href="{% url 'logout' %}">Logout</a>
{% endif %}
</nav>
<div class="body">
<div class="container">
<div class="div-container">
{% if error_message %}
<p class="error-message">{{ error_message }}</p>
{% endif %}
{% if success_message %}
<p class="success-message">{{ success_message }}</p>
{% endif %}
{% if person != '' %}
<h1>Welcome {{ person.name }}!</h1>
{% else %}
<h1>Welcome young padawan!</h1>
{% endif %}
</div>
</div>
</div>
</body>
</html>

@ -1,4 +1,8 @@
<html>
<head>
{% load static %}
<link rel="stylesheet" href="{% static 'redis_app/style.css' %}">
</head>
<body>
<nav>
<a href="{% url 'home' %}">Home</a>
@ -16,20 +20,31 @@
<a href="{% url 'logout' %}">Logout</a>
{% endif %}
</nav>
<div class="body">
<div class="container">
<form action="{% url 'login' %}" method="POST">
{% csrf_token %}
<fieldset>
<legend><h1>Login</h1></legend>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<label for="name">Name</label><br>
<input name="name" id="name" value="{{ person.name }}"><br/>
<label for="role">Role</label><br>
{% if error_message %}
<p class="error-message">{{ error_message }}</p>
{% endif %}
{% if success_message %}
<p class="success-message">{{ success_message }}</p>
{% endif %}
<label for="name">Name</label>
<input name="name" id="name" value="{{ person.name }}" class="input">
<label for="role">Role</label>
<select name="role" id="role">
<option value="Student" {% if person.role == 'Student' %}selected{% endif %}>Student</option>
<option value="Teacher" {% if person.role == 'Teacher' %}selected{% endif %}>Teacher</option>
</select>
</fieldset>
<input type="submit" value="Login">
<div class="submit-container">
<input type="submit" value="Login" class="submit">
</div>
</form>
</div>
</div>
</body>
</html>

@ -1,4 +1,8 @@
<html>
<head>
{% load static %}
<link rel="stylesheet" href="{% static 'redis_app/style.css' %}">
</head>
<body>
<nav>
<a href="{% url 'home' %}">Home</a>
@ -16,11 +20,18 @@
<a href="{% url 'logout' %}">Logout</a>
{% endif %}
</nav>
<div class="body">
<div class="container">
<div class="notifications">
<h1>Notifications</h1>
<a href="{% url 'clear_notifications' %}">Clear notifications</a>
</div>
{% for message in messages %}
<a href="{% url 'details' message.channel %}">{{ message.data }}</a><br/>
<a href="{% url 'details' message.channel %}">{{ message.data }}</a>
{% endfor %}
<a href="{% url 'clear_notifications' %}">Clear notifications</a>
</div>
</div>
<script>
setInterval(function() {
window.location.reload();

@ -1,4 +1,8 @@
<html>
<head>
{% load static %}
<link rel="stylesheet" href="{% static 'redis_app/style.css' %}">
</head>
<body>
<nav>
<a href="{% url 'home' %}">Home</a>
@ -16,20 +20,31 @@
<a href="{% url 'logout' %}">Logout</a>
{% endif %}
</nav>
<div class="body">
<div class="container">
<form action="{% url 'change_profile' %}" method="POST">
{% csrf_token %}
<fieldset>
<legend><h1>Profile</h1></legend>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<label for="name">Name</label><br>
<input name="name" id="name" value="{{ person.name }}"><br/>
<label for="role">Role</label><br>
{% if error_message %}
<p class="error-message">{{ error_message }}</p>
{% endif %}
{% if success_message %}
<p class="success-message">{{ success_message }}</p>
{% endif %}
<label for="name">Name</label>
<input name="name" id="name" value="{{ person.name }}" class="input">
<label for="role">Role</label>
<select name="role" id="role">
<option value="Student" {% if person.role == 'Student' %}selected{% endif %}>Student</option>
<option value="Teacher" {% if person.role == 'Teacher' %}selected{% endif %}>Teacher</option>
</select>
</fieldset>
<input type="submit" value="Update">
<div class="submit-container">
<input type="submit" value="Update profile" class="submit">
</div>
</form>
</div>
</div>
</body>
</html>

@ -1,4 +1,8 @@
<html>
<head>
{% load static %}
<link rel="stylesheet" href="{% static 'redis_app/style.css' %}">
</head>
<body>
<nav>
<a href="{% url 'home' %}">Home</a>
@ -16,27 +20,36 @@
<a href="{% url 'logout' %}">Logout</a>
{% endif %}
</nav>
<div class="body">
<div class="container">
<form action="{% url 'publish_message_form' %}" method="POST">
{% csrf_token %}
<fieldset>
<legend><h1>Publish a message</h1></legend>
{% if error_message %}
{{ error_message }}
<p class="error-message">{{ error_message }}</p>
{% endif %}
{% if success_message %}
<p class="success-message">{{ success_message }}</p>
{% endif %}
<label for="course_id">Course</label><br>
<label for="course_id">Course</label>
<select name="course_id" id="course_id" required>
{% for course in courses %}
<option value="{{ course.id }}">{{ course.title }}</option>
{% endfor %}
</select><br/>
</select>
<label for="message">Message</label><br>
<input name="message" id="message" required><br/>
<label for="message">Message</label>
<input name="message" id="message" class="input" required>
</fieldset>
<input type="submit" value="Publish the message">
<div class="submit-container">
<input type="submit" value="Publish" class="submit">
</div>
</form>
</div>
</div>
</body>
</html>

@ -1,4 +1,8 @@
<html>
<head>
{% load static %}
<link rel="stylesheet" href="{% static 'redis_app/style.css' %}">
</head>
<body>
<nav>
<a href="{% url 'home' %}">Home</a>
@ -16,20 +20,31 @@
<a href="{% url 'logout' %}">Logout</a>
{% endif %}
</nav>
<div class="body">
<div class="container">
<form action="{% url 'register' %}" method="POST">
{% csrf_token %}
<fieldset>
<legend><h1>Register</h1></legend>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<label for="name">Name</label><br>
<input name="name" id="name" value="{{ person.name }}"><br/>
<label for="role">Role</label><br>
{% if error_message %}
<p class="error-message">{{ error_message }}</p>
{% endif %}
{% if success_message %}
<p class="success-message">{{ success_message }}</p>
{% endif %}
<label for="name">Name</label>
<input name="name" id="name" value="{{ person.name }}" class="input">
<label for="role">Role</label>
<select name="role" id="role">
<option value="Student" {% if person.role == 'Student' %}selected{% endif %}>Student</option>
<option value="Teacher" {% if person.role == 'Teacher' %}selected{% endif %}>Teacher</option>
</select>
</fieldset>
<input type="submit" value="Register">
<div class="submit-container">
<input type="submit" value="Register" class="submit">
</div>
</form>
</div>
</div>
</body>
</html>

@ -1,4 +1,8 @@
<html>
<head>
{% load static %}
<link rel="stylesheet" href="{% static 'redis_app/style.css' %}">
</head>
<body>
<nav>
<a href="{% url 'home' %}">Home</a>
@ -16,15 +20,24 @@
<a href="{% url 'logout' %}">Logout</a>
{% endif %}
</nav>
<div class="body">
<div class="container">
<form action="{% url 'search_form' %}" method="POST">
{% csrf_token %}
<fieldset>
<legend><h1>Search</h1></legend>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<label for="keywords">Keywords</label><br>
<input name="keywords" id="keywords" placeholder="Keywords separated by spaces"><br/>
{% if error_message %}
<p class="error-message">{{ error_message }}</p>
{% endif %}
{% if success_message %}
<p class="success-message">{{ success_message }}</p>
{% endif %}
<label for="keywords">Keywords</label>
<input name="keywords" id="keywords" placeholder="Keywords separated by spaces" class="input">
</fieldset>
<input type="submit" value="Search">
<div class="submit-container">
<input type="submit" value="Search" class="submit">
</div>
</form>
{% if courses %}
{% for course in courses %}
@ -33,5 +46,7 @@
{% else %}
<p>No course found</p>
{% endif %}
</div>
</div>
</body>
</html>

@ -1,4 +1,8 @@
<html>
<head>
{% load static %}
<link rel="stylesheet" href="{% static 'redis_app/style.css' %}">
</head>
<body>
<nav>
<a href="{% url 'home' %}">Home</a>
@ -13,22 +17,27 @@
<a href="{% url 'logout' %}">Logout</a>
{% endif %}
</nav>
<div class="body">
<div class="container">
<form action="{% url 'update_course_form' course.id %}" method="POST">
{% csrf_token %}
<fieldset>
<legend><h1>Update a course</h1></legend>
{% if error_message %}
{{ error_message }}
<p class="error-message">{{ error_message }}</p>
{% endif %}
<br/>
<label for="title">Course Title</label><br>
<input type="text" name="title" id="title" value="{{ course.title }}" required><br/>
{% if success_message %}
<p class="success-message">{{ success_message }}</p>
{% endif %}
<label for="title">Course Title</label>
<input type="text" name="title" id="title" value="{{ course.title }}" class="input" required>
<label for="summary">Course Summary</label><br>
<textarea name="summary" id="summary" required>{{ course.summary }}</textarea><br/>
<label for="summary">Course Summary</label>
<textarea name="summary" id="summary" required>{{ course.summary }}</textarea>
<label for="level">Course Level</label><br>
<label for="level">Course Level</label>
<select name="level" id="level" required>
{% if course.level == 'Beginner' %}
<option value="Beginner" selected>Beginner</option>
@ -43,13 +52,17 @@
<option value="Intermediate">Intermediate</option>
<option value="Advanced" selected>Advanced</option>
{% endif %}
</select><br/>
</select>
<label for="places">Number of Places</label><br>
<input type="number" name="places" id="places" value="{{ course.places }}" min="1" required><br/>
<label for="places">Number of Places</label>
<input type="number" name="places" id="places" value="{{ course.places }}" min="1" class="input" required>
</fieldset>
<input type="submit" value="Update Course">
<div class="submit-container">
<input type="submit" value="Update Course" class="submit">
</div>
</form>
</div>
</div>
</body>
</html>

@ -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)

@ -1,167 +1,52 @@
from django.shortcuts import render
from django.http import Http404
import redis
import uuid
from redis_app.utils.index import create_index
from redis_app.utils.model import *
# This model only helps us the development part to set rules on objects (we do not use the django model to save objects in it)
from .models import Person
DEFAULT_EXPIRE_TIME = 1200
EXPIRE_REFRESH_TIME = 60
messages = [] # All messages obtained with pub/sub. Will refresh the view every time a message is received
redis_connection = redis.Redis(host='localhost', port=6379, decode_responses=True)
pub_sub = redis_connection.pubsub()
create_index(redis_connection=redis_connection)
def get_uuid4():
return str(uuid.uuid4()).replace('-', '')
def getCoursesFromPerson(person_id):
global redis_connection
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 isExpired(course_id):
global redis_connection
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 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 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 home(request):
person = request.session.get("person", "")
return render(request, 'home.html', {'person': person})
def isPersonRegisteredToCourse(course, person):
global redis_connection
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
def details(request, course_id, error_message=''):
def details(request, course_id, error_message='', success_message=''):
person = request.session.get("person", "")
global redis_connection
if isExpired(course_id):
raise Http404("Course has expired... Get faster next time!")
course = redis_connection.hgetall(f"course:{course_id}")
course = getCourse(course_id)
if not course:
raise Http404("Course does not exist")
course['id'] = course_id
teacher = redis_connection.hgetall(f"person:{course['teacher']}")
teacher = getPerson(course['teacher'])
if not teacher:
raise Http404("Teacher does not exist")
course['teacher_name'] = teacher['name']
register = isPersonRegisteredToCourse(course, person)
full = isCourseFull(course)
return render(request, 'details.html', {'course': course, 'person': person, 'register': register, 'full': full, 'error_message': error_message})
return render(request, 'details.html', {'course': course, 'person': person, 'register': register, 'full': full, 'error_message': error_message, 'success_message': success_message})
def register(request):
if request.method == 'POST':
person_name = request.POST['name']
person_role = request.POST['role']
query = f"@name:{person_name} @role:{person_role}"
results = redis_connection.execute_command('FT.SEARCH', 'idx:persons', query)
# First element = number of results
if results[0] > 0:
person = register_redis(request.POST['name'], request.POST['role'])
if not person:
return render(request, 'register.html', {'person': Person(name="", role=""), "error_message": "This user already exists!"})
person_key = f"person:{get_uuid4()}"
redis_connection.hset(person_key, mapping={
'name': person_name,
'role': person_role
})
request.session["person"] = redis_connection.hgetall(person_key)
request.session["person"] = person
return home(request)
return render(request, 'register.html', {'person': Person(name="", role=""), "error_message": "The form has been wrongly filled!"})
def login(request):
if request.method == 'POST':
person_name = request.POST['name']
person_role = request.POST['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]
request.session["person"] = redis_connection.hgetall(person_key)
return home(request)
person = login_redis(request.POST["name"], request.POST["role"])
if not person:
return render(request, 'login.html', {'person': Person(name="", role=""), "error_message": "No user found!"})
request.session["person"] = person
return home(request)
return login_form(request)
def register_form(request):
@ -174,14 +59,14 @@ def logout(request):
request.session["person"] = ""
return render(request, 'login.html', {'person': Person(name="", role="")})
def courses(request):
def courses(request, error_message="", success_message=""):
person = request.session.get("person", "")
if person == "":
return render(request, 'login.html', {'person': Person(name="", role=""), "error_message": "You must login!"})
person_id = getPersonId(person["name"], person["role"]).split(":")[1]
courses = getCoursesFromPerson(person_id)
return render(request, 'courses.html', {'person': person, 'courses': courses})
return render(request, 'courses.html', {'person': person, 'courses': courses, 'error_message': error_message, 'success_message': success_message})
def change_profile(request):
person = request.session.get("person", "")
@ -200,7 +85,7 @@ def change_profile(request):
person["name"] = person_name
person["role"] = person_role
request.session["person"] = person
return render(request, 'profile.html', {'person': person})
return render(request, 'profile.html', {'person': person, 'success_message': 'Your profile has been successfully changed!'})
return login_form(request)
@ -210,18 +95,6 @@ def profile(request):
return render(request, 'login.html', {'person': Person(name="", role=""), "error_message": "You must login!"})
return render(request, 'profile.html', {'person': person})
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 delete_course_view(request, course_id):
if isExpired(course_id):
raise Http404("Course has expired... Get faster next time!")
@ -231,40 +104,17 @@ def delete_course_view(request, course_id):
publish(course_id, f"DELETE: Course:{course_id} has been deleted!")
return courses(request)
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 publish_message(request):
person = request.session.get("person", "")
courses_fetched = getCoursesFromPerson(getPersonId(person['name'], person['role']).split(":")[1])
for course in courses_fetched:
course['id'] = getCourseId(course).split(':')[1]
if not courses_fetched:
return courses(request)
return render(request, 'publish_message.html', {'person': person, 'courses': courses_fetched})
return courses(request, 'You don\'t have any course. You must create one to publish a message!')
return render(request, 'publish_message.html', {'person': person, 'courses': courses_fetched, 'success_message': 'The message has been successfully sent!'})
def publish_message_form(request):
person = request.session.get("person", "")
global redis_connection
if person == '':
return render(request, 'login.html', {'person': Person(name="", role=""), "error_message": "You must login!"})
if person['role'] == 'Student':
@ -299,7 +149,6 @@ def update_course_view(request, course_id):
def create_course_form(request):
person = request.session.get("person", "")
global redis_connection
if person == '':
return render(request, 'login.html', {'person': Person(name="", role=""), "error_message": "You must login!"})
if request.method == 'POST':
@ -309,13 +158,12 @@ def create_course_form(request):
course_places = request.POST['places']
course_teacher = getPersonId(person['name'], person['role']).split(":")[1]
create_course(course_title, course_summary, course_level, course_places, course_teacher)
return courses(request)
return courses(request, "", "The course has been successfully created!")
return render(request, 'create.html', {'person': person, "error_message": "The form has been wrongly filled!"})
def update_course_form(request, course_id):
person = request.session.get("person", "")
global redis_connection
if isExpired(course_id):
raise Http404("Course has expired... Get faster next time!")
if person == '':
@ -335,60 +183,12 @@ def update_course_form(request, course_id):
except:
return render(request, 'update.html', {'person': person, "error_message": "The number of places has not the right format!", "course": course})
update_course(course_id, course_title, course_summary, course_level, course_places, course_teacher)
return courses(request)
return courses(request, "", "The course has been successfully changed!")
return render(request, 'update.html', {'person': person, "error_message": "The form has been wrongly filled!", "course": course})
# Test if places are not limited
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 course_register_view(request, course_id):
person = request.session.get("person", "")
global redis_connection
if isExpired(course_id):
raise Http404("Course has expired... Get faster next time!")
person_id = getPersonId(person["name"], person["role"]).split(":")[1]
@ -403,13 +203,12 @@ def course_register_view(request, course_id):
raise Http404("Teacher does not exist")
course['teacher_name'] = teacher['name']
if course_register(course_id, person_id):
return details(request, course_id)
return details(request, course_id, '', 'Successfully registered to the course.')
return details(request, course_id, "Could not register to the course. Try again later.")
def course_unregister_view(request, course_id):
person = request.session.get("person", "")
global redis_connection
if personLoggedIn == "":
if person == "":
return render(request, 'login.html', {'person': Person(name="", role=""), "error_message": "You must login!"})
if isExpired(course_id):
raise Http404("Course has expired... Get faster next time!")
@ -425,35 +224,9 @@ def course_unregister_view(request, course_id):
raise Http404("Teacher does not exist")
course['teacher_name'] = teacher['name']
if course_unregister(course_id, person_id):
return details(request, course_id)
return details(request, course_id, '', "Successfully unregistered to the course.")
return details(request, course_id, "Could not unregister to the course. Try again later.")
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
def publish(course_id, message):
global redis_connection
redis_connection.publish(course_id, message)
# Courses is a list of course id to subscribe to
def subscribe(courses_id):
pub_sub.psubscribe(*courses_id)
for message in pub_sub.listen():
if message["type"] != 'pmessage':
continue
send_new_course_notification(message)
def send_new_course_notification(message):
print(message)
def search(keywords):
courses = []
for keyword in keywords.split(' '):
@ -483,7 +256,6 @@ def search_view(request):
def search_form(request):
person = request.session.get("person", "")
global redis_connection
if request.method == 'POST':
keywords = request.POST['keywords']
courses = []
@ -500,29 +272,31 @@ def search_form(request):
def notifications_view(request):
person = request.session.get("person", "")
global messages
messages = request.session.get("messages", [])
return render(request, 'notifications.html', {'person': person, 'messages': messages})
def notifications(request):
person = request.session.get("person", "")
global messages
messages = request.session.get("messages", [])
if person == "":
return render(request, 'login.html', {'person': Person(name="", role=""), "error_message": "You must login!"})
pub_sub.punsubscribe()
courses_id = [course['id'] for course in getCoursesFromPerson(getPersonId(person['name'], person['role']).split(":")[1])]
if not courses_id:
return courses(request)
return courses(request, "You're not registered to any course. Please register to one to follow notifications.")
pub_sub.psubscribe(*courses_id)
for message in pub_sub.listen():
if message["type"] != 'pmessage':
continue
messages.append(message)
messages.reverse()
request.session["message"] = messages
break
return notifications_view(request)
def clear_notifications(request):
global messages
messages = []
request.session["messages"] = []
return notifications_view(request)
# Every id is only the number, not the course:number or person:number
Loading…
Cancel
Save