├── mylms ├── __init__.py ├── lmsstatic │ └── assets │ │ ├── img │ │ └── header.jpg │ │ └── js │ │ ├── bs-init.js │ │ └── creative.js ├── __pycache__ │ └── custom_azure.cpython-39.pyc ├── asgi.py ├── wsgi.py ├── views.py ├── custom_azure.py ├── templates │ ├── 403.html │ └── mylms │ │ └── home.html ├── urls.py └── settings.py ├── accounts ├── __init__.py ├── tests.py ├── static │ └── accounts │ │ ├── assets │ │ ├── img │ │ │ └── header.jpg │ │ └── js │ │ │ ├── bs-init.js │ │ │ └── creative.js │ │ └── js │ │ └── theme.js ├── apps.py ├── passtests.py ├── templates │ └── accounts │ │ ├── index.html │ │ ├── student_stream.html │ │ ├── teacher_stream.html │ │ ├── teacher_signup.html │ │ ├── login.html │ │ ├── base.html │ │ └── student_signup.html ├── admin.py ├── urls.py ├── views.py ├── forms.py └── models.py ├── students ├── __init__.py ├── models.py ├── admin.py ├── tests.py ├── static │ └── students │ │ ├── img │ │ └── avatars │ │ │ └── avatar5.jpeg │ │ ├── fonts │ │ └── fontawesome5-overrides.min.css │ │ └── js │ │ └── theme.js ├── apps.py ├── forms.py ├── templates │ └── students │ │ ├── deletesubmission.html │ │ ├── classroom_detail.html │ │ ├── resources.html │ │ ├── dashboard.html │ │ ├── assignments.html │ │ ├── assignmentsubmission.html │ │ ├── join_classroom.html │ │ ├── my_assignment.html │ │ └── base.html ├── urls.py └── views.py ├── teachers ├── __init__.py ├── models.py ├── admin.py ├── tests.py ├── apps.py ├── static │ └── teachers │ │ ├── img │ │ └── avatars │ │ │ └── 2022-04-21_15-55-27-569_lQA2GHZJMk.png │ │ ├── fonts │ │ └── fontawesome5-overrides.min.css │ │ └── js │ │ └── theme.js ├── templates │ └── teachers │ │ ├── add_resource.html │ │ ├── add_section.html │ │ ├── add_assignment.html │ │ ├── addclassroom.html │ │ ├── delete_section.html │ │ ├── delete_resource.html │ │ ├── deleteclassroom.html │ │ ├── delete_assignment.html │ │ ├── classroomstudents.html │ │ ├── dashboard.html │ │ ├── submissions.html │ │ ├── classroom_detail.html │ │ ├── resources.html │ │ ├── assignments.html │ │ └── base.html ├── forms.py ├── urls.py └── views.py ├── cc_erd.png ├── db.sqlite3 ├── Final CCL Journal.pdf ├── screenshots └── 2022-04-22_11-58-18-957_hwgAvOaf6J.png ├── manage.py ├── requirements.txt ├── .github └── workflows │ └── master_lms-app.yml ├── README.md └── .gitignore /mylms/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /accounts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /students/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /teachers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /students/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /teachers/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /accounts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /students/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /students/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /teachers/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /teachers/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /cc_erd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rishimule/django-learning-management-system/HEAD/cc_erd.png -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rishimule/django-learning-management-system/HEAD/db.sqlite3 -------------------------------------------------------------------------------- /Final CCL Journal.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rishimule/django-learning-management-system/HEAD/Final CCL Journal.pdf -------------------------------------------------------------------------------- /mylms/lmsstatic/assets/img/header.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rishimule/django-learning-management-system/HEAD/mylms/lmsstatic/assets/img/header.jpg -------------------------------------------------------------------------------- /accounts/static/accounts/assets/img/header.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rishimule/django-learning-management-system/HEAD/accounts/static/accounts/assets/img/header.jpg -------------------------------------------------------------------------------- /mylms/__pycache__/custom_azure.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rishimule/django-learning-management-system/HEAD/mylms/__pycache__/custom_azure.cpython-39.pyc -------------------------------------------------------------------------------- /students/static/students/img/avatars/avatar5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rishimule/django-learning-management-system/HEAD/students/static/students/img/avatars/avatar5.jpeg -------------------------------------------------------------------------------- /screenshots/2022-04-22_11-58-18-957_hwgAvOaf6J.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rishimule/django-learning-management-system/HEAD/screenshots/2022-04-22_11-58-18-957_hwgAvOaf6J.png -------------------------------------------------------------------------------- /accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'accounts' 7 | -------------------------------------------------------------------------------- /students/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class StudentsConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'students' 7 | -------------------------------------------------------------------------------- /teachers/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class TeachersConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'teachers' 7 | -------------------------------------------------------------------------------- /teachers/static/teachers/img/avatars/2022-04-21_15-55-27-569_lQA2GHZJMk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rishimule/django-learning-management-system/HEAD/teachers/static/teachers/img/avatars/2022-04-21_15-55-27-569_lQA2GHZJMk.png -------------------------------------------------------------------------------- /mylms/lmsstatic/assets/js/bs-init.js: -------------------------------------------------------------------------------- 1 | 2 | if (window.innerWidth < 768) { 3 | [].slice.call(document.querySelectorAll('[data-bss-disabled-mobile]')).forEach(function (elem) { 4 | elem.classList.remove('animated'); 5 | elem.removeAttribute('data-bss-hover-animate'); 6 | elem.removeAttribute('data-aos'); 7 | }); 8 | } 9 | 10 | document.addEventListener('DOMContentLoaded', function() { 11 | AOS.init(); 12 | }, false); -------------------------------------------------------------------------------- /accounts/static/accounts/assets/js/bs-init.js: -------------------------------------------------------------------------------- 1 | 2 | if (window.innerWidth < 768) { 3 | [].slice.call(document.querySelectorAll('[data-bss-disabled-mobile]')).forEach(function (elem) { 4 | elem.classList.remove('animated'); 5 | elem.removeAttribute('data-bss-hover-animate'); 6 | elem.removeAttribute('data-aos'); 7 | }); 8 | } 9 | 10 | document.addEventListener('DOMContentLoaded', function() { 11 | AOS.init(); 12 | }, false); -------------------------------------------------------------------------------- /students/forms.py: -------------------------------------------------------------------------------- 1 | from accounts.models import Classroom,Teacher, Section, Resource,Assignment,AssignmentSubmission 2 | from django import forms 3 | 4 | class AssignmentSubmissionForm(forms.ModelForm): 5 | 6 | class Meta: 7 | model = AssignmentSubmission 8 | fields = ("file",) 9 | 10 | class JoinClassroomForm(forms.Form): 11 | code = forms.CharField(max_length=50, required=True) 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /mylms/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for mylms project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mylms.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /mylms/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mylms project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mylms.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /teachers/templates/teachers/add_resource.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% load static %} {% load bootstrap4 %} {% block title %}Add Resource{% endblock title %} {% bootstrap_messages %} {% block content %} 2 | 3 |

Add Resource

4 |
5 |
6 | {% csrf_token %} {% bootstrap_form form%} 7 | 8 | 9 | 10 |
11 | 12 | {% endblock content %} -------------------------------------------------------------------------------- /teachers/templates/teachers/add_section.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% load static %} {% load bootstrap4 %} {% block title %}Add Section{% endblock title %} {% bootstrap_messages %} {% block content %} 2 | 3 |

Add Section

4 |
5 |
6 | {% csrf_token %} {% bootstrap_form form%} 7 | 8 | 9 | 10 |
11 | 12 | {% endblock content %} -------------------------------------------------------------------------------- /teachers/templates/teachers/add_assignment.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% load static %} {% load bootstrap4 %} {% block title %}Add Assignment{% endblock title %} {% bootstrap_messages %} {% block content %} 2 | 3 |

Add Assignment

4 |
5 |
6 | {% csrf_token %} {% bootstrap_form form%} 7 | 8 | 9 | 10 |
11 | 12 | {% endblock content %} -------------------------------------------------------------------------------- /teachers/templates/teachers/addclassroom.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% load static %} {% load bootstrap4 %} {% block title %}Add Classroom{% endblock title %} {% bootstrap_messages %} {% block content %} 2 | 3 |

Add Classroom

4 |
5 |
6 | {% csrf_token %} {% bootstrap_form form%} 7 | 8 | 9 | 10 |
11 | 12 | {% endblock content %} -------------------------------------------------------------------------------- /accounts/passtests.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.mixins import UserPassesTestMixin 2 | 3 | class StudentTestMixin(UserPassesTestMixin): 4 | def test_func(self): 5 | if self.request.user.is_authenticated: 6 | return self.request.user.is_student 7 | else: 8 | return False 9 | 10 | class TeacherTestMixin(UserPassesTestMixin): 11 | def test_func(self): 12 | if self.request.user.is_authenticated: 13 | return self.request.user.is_teacher 14 | else: 15 | return False -------------------------------------------------------------------------------- /students/templates/students/deletesubmission.html: -------------------------------------------------------------------------------- 1 | {% extends 'students/base.html' %} 2 | 3 | 4 | {% load static %} 5 | 6 | 7 | {% block title %}Resources{% endblock title %} 8 | 9 | 10 | {% block content %} 11 | 12 |
13 | 14 |
15 | {% csrf_token %} {{form}} 16 | 17 |
18 | 19 |
20 | {% endblock content %} -------------------------------------------------------------------------------- /mylms/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import redirect, render 2 | from django.views.generic import TemplateView, CreateView, ListView 3 | from django.contrib.auth.decorators import login_required, user_passes_test 4 | 5 | 6 | class HomeView(TemplateView): 7 | template_name = "mylms/home.html" 8 | 9 | @login_required 10 | def DashboardView(request): 11 | if request.user.is_student: 12 | return redirect('students:dashboard') 13 | if request.user.is_teacher: 14 | return redirect('teachers:dashboard') 15 | if request.user.is_superuser: 16 | return redirect('admin:index') -------------------------------------------------------------------------------- /students/static/students/fonts/fontawesome5-overrides.min.css: -------------------------------------------------------------------------------- 1 | .fab.fa-bitcoin:before{content:"\f379"}.far.fa-calendar:before,.fas.fa-calendar:before{content:"\f133"}.far.fa-clipboard:before,.fas.fa-clipboard:before{content:"\f328"}.fab.fa-facebook-f:before{content:"\f39e"}.fab.fa-google-plus:before{content:"\f2b3"}.fas.fa-hotel:before{content:"\f594"}.fab.fa-linkedin:before{content:"\f08c"}.fas.fa-reply:before{content:"\f3e5"}.fas.fa-thermometer:before{content:"\f491"}.fab.fa-vimeo:before{content:"\f40a"}.far.fa-window-close:before,.fas.fa-window-close:before{content:"\f410"}.fab.fa-youtube-square:before{content:"\f431"} -------------------------------------------------------------------------------- /teachers/static/teachers/fonts/fontawesome5-overrides.min.css: -------------------------------------------------------------------------------- 1 | .fab.fa-bitcoin:before{content:"\f379"}.far.fa-calendar:before,.fas.fa-calendar:before{content:"\f133"}.far.fa-clipboard:before,.fas.fa-clipboard:before{content:"\f328"}.fab.fa-facebook-f:before{content:"\f39e"}.fab.fa-google-plus:before{content:"\f2b3"}.fas.fa-hotel:before{content:"\f594"}.fab.fa-linkedin:before{content:"\f08c"}.fas.fa-reply:before{content:"\f3e5"}.fas.fa-thermometer:before{content:"\f491"}.fab.fa-vimeo:before{content:"\f40a"}.far.fa-window-close:before,.fas.fa-window-close:before{content:"\f410"}.fab.fa-youtube-square:before{content:"\f431"} -------------------------------------------------------------------------------- /teachers/templates/teachers/delete_section.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% load static %} {% block title %}Delete Section{% endblock title %} {% block content %} 2 | 3 |
4 |

Confirm Delete?

5 |

This action is irreversible

6 |
7 |

Do you want to Delete this Section

8 |
9 | {% csrf_token %} {{form.as_p}} 10 | 11 |
12 |
13 | 14 | {% endblock content %} -------------------------------------------------------------------------------- /teachers/templates/teachers/delete_resource.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% load static %} {% block title %}Delete Resource{% endblock title %} {% block content %} 2 | 3 |
4 |

Confirm Delete?

5 |

This action is irreversible

6 |
7 |

Do you want to Delete this Resource

8 |
9 | {% csrf_token %} {{form.as_p}} 10 | 11 |
12 |
13 | 14 | {% endblock content %} -------------------------------------------------------------------------------- /teachers/templates/teachers/deleteclassroom.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% load static %} {% block title %}Delete Classroom{% endblock title %} {% block content %} 2 | 3 |
4 |

Confirm Delete?

5 |

This action is irreversible

6 |
7 |

Do you want to Delete this Classroom

8 |
9 | {% csrf_token %} {{form.as_p}} 10 | 11 |
12 |
13 | 14 | {% endblock content %} -------------------------------------------------------------------------------- /teachers/templates/teachers/delete_assignment.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% load static %} {% block title %}Delete Assignment{% endblock title %} {% block content %} 2 | 3 |
4 |

Confirm Delete?

5 |

This action is irreversible

6 |
7 |

Do you want to Delete this Assignment

8 |
9 | {% csrf_token %} {{form.as_p}} 10 | 11 |
12 |
13 | 14 | {% endblock content %} -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mylms.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /accounts/templates/accounts/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'accounts/base.html' %} {% block title %}Sign Up{% endblock title %} {% block content %} 2 |
3 |
4 |


5 |

Sign Up!

6 |
7 |

Create a account!

8 |
9 |
10 |
11 |

Choose your role.

12 |
13 |

14 | I'm a Student! 15 | 16 | I'm a Teacher! 17 |

18 |
19 |
20 | 21 | {% endblock content %} -------------------------------------------------------------------------------- /accounts/templates/accounts/student_stream.html: -------------------------------------------------------------------------------- 1 | {% extends 'accounts/base.html' %} 2 | 3 | 4 | {% block title %}Sign Up{% endblock title %} 5 | 6 | 7 | {% block content %} 8 | 9 |
10 |

Select Your Stream

11 |
12 | 13 |
14 | 15 | 16 | {% for stream in stream_list %} 17 | 18 | 19 | {{stream.name}} 20 | 21 | 22 | 23 | {% endfor %} 24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 | {% endblock content %} -------------------------------------------------------------------------------- /accounts/templates/accounts/teacher_stream.html: -------------------------------------------------------------------------------- 1 | {% extends 'accounts/base.html' %} 2 | 3 | 4 | {% block title %}Sign Up{% endblock title %} 5 | 6 | 7 | {% block content %} 8 | 9 |
10 |

Select Your Stream

11 |
12 | 13 |
14 | 15 | 16 | {% for stream in stream_list %} 17 | 18 | 19 | {{stream.name}} 20 | 21 | 22 | 23 | {% endfor %} 24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 | {% endblock content %} -------------------------------------------------------------------------------- /mylms/custom_azure.py: -------------------------------------------------------------------------------- 1 | from storages.backends.azure_storage import AzureStorage 2 | from django.conf import settings 3 | 4 | class AzureMediaStorage(AzureStorage): 5 | account_name = settings.AZURE_ACCOUNT_NAME # Must be replaced by your 6 | account_key = settings.AZURE_STORAGE_ACCOUNT_KEY # Must be replaced by your 7 | azure_container = 'media' 8 | expiration_secs = None 9 | # file_overwrite = False 10 | 11 | class AzureStaticStorage(AzureStorage): 12 | account_name = settings.AZURE_ACCOUNT_NAME # Must be replaced by your storage_account_name 13 | account_key = settings.AZURE_STORAGE_ACCOUNT_KEY # Must be replaced by your 14 | azure_container = 'static' 15 | expiration_secs = None 16 | # file_overwrite = False -------------------------------------------------------------------------------- /accounts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import ( 4 | User, 5 | Stream, 6 | Class, 7 | Teacher, 8 | Classroom, 9 | Student, 10 | Section, 11 | Resource, 12 | Assignment, 13 | AssignmentSubmission 14 | ) 15 | # Register your models here. 16 | 17 | admin.site.register(User) 18 | admin.site.register(Stream) 19 | admin.site.register(Class) 20 | admin.site.register(Teacher) 21 | admin.site.register(Classroom) 22 | admin.site.register(Student) 23 | admin.site.register(Section) 24 | admin.site.register(Resource) 25 | admin.site.register(Assignment) 26 | admin.site.register(AssignmentSubmission) 27 | 28 | -------------------------------------------------------------------------------- /teachers/forms.py: -------------------------------------------------------------------------------- 1 | from accounts.models import Classroom,Teacher, Section, Resource,Assignment,AssignmentSubmission 2 | from django import forms 3 | 4 | class ClassroomForm(forms.ModelForm): 5 | 6 | class Meta: 7 | model = Classroom 8 | exclude = ('teacher',) 9 | 10 | class SectionForm(forms.ModelForm): 11 | 12 | class Meta: 13 | model = Section 14 | # fields = '__all__' 15 | exclude = ("classroom",) 16 | 17 | class ResourceForm(forms.ModelForm): 18 | 19 | class Meta: 20 | model = Resource 21 | # fields = '__all__' 22 | exclude = ("section",) 23 | 24 | class AssignmentForm(forms.ModelForm): 25 | 26 | class Meta: 27 | model = Assignment 28 | exclude = ("section",) 29 | widgets = { 30 | 'deadline' : forms.SelectDateWidget 31 | } 32 | 33 | -------------------------------------------------------------------------------- /mylms/templates/403.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Untitled 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 |
16 |
17 |

403 Forbidden

18 |
ERROR
19 |

You are not Authorized to view this page.

Home 20 |
21 |
22 |
23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /accounts/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import include, path 3 | from django.conf import settings 4 | from django.conf.urls.static import static 5 | from .views import IndexView, StudentCreateView, StreamView, TeacherCreateView 6 | from django.contrib.auth.views import LoginView, LogoutView 7 | 8 | app_name = 'accounts' 9 | 10 | urlpatterns = [ 11 | path('', IndexView.as_view(), name='signup'), 12 | path('login/', LoginView.as_view(template_name='accounts/login.html',redirect_authenticated_user=True), name='login'), 13 | path('logout/', LogoutView.as_view(), name='logout'), 14 | 15 | path('signup/student/stream/', StreamView.as_view(template_name = "accounts/student_stream.html"), name='student_stream'), 16 | path('signup/student//', StudentCreateView.as_view(), name='student_signup'), 17 | 18 | path('signup/teacher/stream/', StreamView.as_view(template_name = "accounts/teacher_stream.html"), name='teacher_stream'), 19 | path('signup/teacher//', TeacherCreateView.as_view(), name='teacher_signup'), 20 | 21 | ] 22 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 23 | -------------------------------------------------------------------------------- /students/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import include, path 2 | from .views import (DashboardView, 3 | ClassroomDetailView, 4 | ResourcesView, 5 | AssignmentsView, 6 | AssignmentSubmissionCreateView, 7 | MyAssignmentView, 8 | AssignmentSubmissionDeleteView, 9 | joinClassroomView, 10 | LeaveClassroomView 11 | ) 12 | 13 | app_name = 'students' 14 | 15 | urlpatterns = [ 16 | path('', DashboardView.as_view(), name='dashboard'), 17 | path('classroom//', ClassroomDetailView,name='classroom_detail'), 18 | path('section//resources/', ResourcesView, name='resources'), 19 | path('section//assignments/', AssignmentsView, name='assignments'), 20 | path('assignment//', MyAssignmentView, name='my_assignment'), 21 | path('assignment//submit/', AssignmentSubmissionCreateView.as_view(), name='submit_assignment'), 22 | path('delete-submission//', AssignmentSubmissionDeleteView.as_view(), name='delete_submission'), 23 | path('join-new/',joinClassroomView, name='join_classroom'), 24 | path('leave-classroom//', LeaveClassroomView,name='leave_classroom'), 25 | ] 26 | -------------------------------------------------------------------------------- /mylms/urls.py: -------------------------------------------------------------------------------- 1 | """mylms URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.2/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import include, path 18 | from django.conf import settings 19 | from django.conf.urls.static import static 20 | from .views import HomeView, DashboardView 21 | 22 | urlpatterns = [ 23 | path('admin/', admin.site.urls), 24 | path("", view=HomeView.as_view(),name='home'), 25 | path('dashboard/', DashboardView, name='dashboard'), 26 | path('accounts/', include('accounts.urls', namespace='accounts')), 27 | path('students/', include('students.urls', namespace='students')), 28 | path('teachers/', include('teachers.urls', namespace='teachers')), 29 | ] 30 | 31 | if settings.DEBUG: 32 | urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) 33 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.4.1 2 | autopep8==1.6.0 3 | azure-core==1.23.1 4 | azure-storage-blob==12.11.0 5 | backoff==1.11.1 6 | beautifulsoup4==4.10.0 7 | Bottleneck==1.3.4 8 | brotlipy==0.7.0 9 | certifi==2021.10.8 10 | cffi==1.15.0 11 | charset-normalizer==2.0.4 12 | click==8.1.2 13 | colorama==0.4.4 14 | cryptography==36.0.0 15 | decorator==5.1.1 16 | distlib==0.3.4 17 | Django==3.2.5 18 | django-bootstrap4==22.1 19 | django-storages==1.12.3 20 | docopt==0.6.2 21 | filelock==3.6.0 22 | future==0.18.2 23 | geocoder==1.38.1 24 | geographiclib==1.52 25 | geopy==2.2.0 26 | idna==3.3 27 | isodate==0.6.1 28 | mkl-fft==1.3.1 29 | mkl-random==1.2.2 30 | mkl-service==2.4.0 31 | mock==4.0.3 32 | msrest==0.6.21 33 | networkx==2.8 34 | nominatim==0.1 35 | numexpr==2.8.1 36 | numpy==1.21.5 37 | oauthlib==3.2.0 38 | opencage==2.0.0 39 | packaging==21.3 40 | pandas==1.4.1 41 | pip==21.2.4 42 | pipenv==2022.4.20 43 | pipreqs==0.4.11 44 | platformdirs==2.5.2 45 | psycopg2==2.8.6 46 | pybbn==3.2.1 47 | pycodestyle==2.8.0 48 | pycparser==2.21 49 | pyOpenSSL==22.0.0 50 | pyparsing==3.0.4 51 | PySocks==1.7.1 52 | python-dateutil==2.8.2 53 | pytz==2021.3 54 | ratelim==0.1.6 55 | requests==2.27.1 56 | requests-oauthlib==1.3.1 57 | scipy==1.8.0 58 | setuptools==58.0.4 59 | six==1.16.0 60 | soupsieve==2.3.1 61 | sqlparse==0.4.1 62 | tables==3.7.0 63 | toml==0.10.2 64 | typing_extensions==4.1.1 65 | urllib3==1.26.8 66 | virtualenv==20.14.1 67 | virtualenv-clone==0.5.7 68 | wheel==0.37.1 69 | win-inet-pton==1.1.0 70 | wincertstore==0.2 71 | yarg==0.1.9 72 | -------------------------------------------------------------------------------- /mylms/lmsstatic/assets/js/creative.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; // Start of use strict 3 | 4 | var mainNav = document.querySelector('#mainNav'); 5 | 6 | if (mainNav) { 7 | 8 | var navbarCollapse = mainNav.querySelector('.navbar-collapse'); 9 | 10 | if (navbarCollapse) { 11 | 12 | var collapse = new bootstrap.Collapse(navbarCollapse, { 13 | toggle: false 14 | }); 15 | 16 | var navbarItems = navbarCollapse.querySelectorAll('a'); 17 | 18 | // Closes responsive menu when a scroll trigger link is clicked 19 | for (var item of navbarItems) { 20 | item.addEventListener('click', function (event) { 21 | collapse.hide(); 22 | }); 23 | } 24 | } 25 | 26 | // Collapse Navbar 27 | var collapseNavbar = function() { 28 | 29 | var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop; 30 | 31 | if (scrollTop > 100) { 32 | mainNav.classList.add("navbar-shrink"); 33 | } else { 34 | mainNav.classList.remove("navbar-shrink"); 35 | } 36 | }; 37 | // Collapse now if page is not at top 38 | collapseNavbar(); 39 | // Collapse the navbar when page is scrolled 40 | document.addEventListener("scroll", collapseNavbar); 41 | } 42 | 43 | // bageutteBox init 44 | if (document.getElementsByClassName('popup-gallery').length > 0) { 45 | baguetteBox.run('.popup-gallery', { animation: 'slideIn' }); 46 | } 47 | 48 | })(); // End of use strict 49 | -------------------------------------------------------------------------------- /students/templates/students/classroom_detail.html: -------------------------------------------------------------------------------- 1 | {% extends 'students/base.html' %} 2 | 3 | 4 | {% block title %}Classroom Detail{% endblock title %} 5 | 6 | 7 | {% block content %} 8 | 9 |
10 |

{{ classroom.subject|upper }}

11 |
12 | 13 | 14 | {% for section in classroom.sections.all %} 15 |
16 |
17 |
{{section.title}}
18 |
19 |
20 | 21 | Resources 22 | 23 | 24 | Assignments 25 | 26 |
27 |
28 | {% endfor %} 29 | 30 |
31 | 32 | {% endblock content %} -------------------------------------------------------------------------------- /accounts/static/accounts/assets/js/creative.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; // Start of use strict 3 | 4 | var mainNav = document.querySelector('#mainNav'); 5 | 6 | if (mainNav) { 7 | 8 | var navbarCollapse = mainNav.querySelector('.navbar-collapse'); 9 | 10 | if (navbarCollapse) { 11 | 12 | var collapse = new bootstrap.Collapse(navbarCollapse, { 13 | toggle: false 14 | }); 15 | 16 | var navbarItems = navbarCollapse.querySelectorAll('a'); 17 | 18 | // Closes responsive menu when a scroll trigger link is clicked 19 | for (var item of navbarItems) { 20 | item.addEventListener('click', function (event) { 21 | collapse.hide(); 22 | }); 23 | } 24 | } 25 | 26 | // Collapse Navbar 27 | var collapseNavbar = function() { 28 | 29 | var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop; 30 | 31 | if (scrollTop > 100) { 32 | mainNav.classList.add("navbar-shrink"); 33 | } else { 34 | mainNav.classList.remove("navbar-shrink"); 35 | } 36 | }; 37 | // Collapse now if page is not at top 38 | collapseNavbar(); 39 | // Collapse the navbar when page is scrolled 40 | document.addEventListener("scroll", collapseNavbar); 41 | } 42 | 43 | // bageutteBox init 44 | if (document.getElementsByClassName('popup-gallery').length > 0) { 45 | baguetteBox.run('.popup-gallery', { animation: 'slideIn' }); 46 | } 47 | 48 | })(); // End of use strict 49 | -------------------------------------------------------------------------------- /accounts/static/accounts/js/theme.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | "use strict"; // Start of use strict 3 | 4 | // Toggle the side navigation 5 | $("#sidebarToggle, #sidebarToggleTop").on('click', function(e) { 6 | $("body").toggleClass("sidebar-toggled"); 7 | $(".sidebar").toggleClass("toggled"); 8 | if ($(".sidebar").hasClass("toggled")) { 9 | $('.sidebar .collapse').collapse('hide'); 10 | }; 11 | }); 12 | 13 | // Close any open menu accordions when window is resized below 768px 14 | $(window).resize(function() { 15 | if ($(window).width() < 768) { 16 | $('.sidebar .collapse').collapse('hide'); 17 | }; 18 | }); 19 | 20 | // Prevent the content wrapper from scrolling when the fixed side navigation hovered over 21 | $('body.fixed-nav .sidebar').on('mousewheel DOMMouseScroll wheel', function(e) { 22 | if ($(window).width() > 768) { 23 | var e0 = e.originalEvent, 24 | delta = e0.wheelDelta || -e0.detail; 25 | this.scrollTop += (delta < 0 ? 1 : -1) * 30; 26 | e.preventDefault(); 27 | } 28 | }); 29 | 30 | // Scroll to top button appear 31 | $(document).on('scroll', function() { 32 | var scrollDistance = $(this).scrollTop(); 33 | if (scrollDistance > 100) { 34 | $('.scroll-to-top').fadeIn(); 35 | } else { 36 | $('.scroll-to-top').fadeOut(); 37 | } 38 | }); 39 | 40 | // Smooth scrolling using jQuery easing 41 | $(document).on('click', 'a.scroll-to-top', function(e) { 42 | var $anchor = $(this); 43 | $('html, body').stop().animate({ 44 | scrollTop: ($($anchor.attr('href')).offset().top) 45 | }, 1000, 'easeInOutExpo'); 46 | e.preventDefault(); 47 | }); 48 | 49 | })(jQuery); // End of use strict 50 | -------------------------------------------------------------------------------- /students/static/students/js/theme.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | "use strict"; // Start of use strict 3 | 4 | // Toggle the side navigation 5 | $("#sidebarToggle, #sidebarToggleTop").on('click', function(e) { 6 | $("body").toggleClass("sidebar-toggled"); 7 | $(".sidebar").toggleClass("toggled"); 8 | if ($(".sidebar").hasClass("toggled")) { 9 | $('.sidebar .collapse').collapse('hide'); 10 | }; 11 | }); 12 | 13 | // Close any open menu accordions when window is resized below 768px 14 | $(window).resize(function() { 15 | if ($(window).width() < 768) { 16 | $('.sidebar .collapse').collapse('hide'); 17 | }; 18 | }); 19 | 20 | // Prevent the content wrapper from scrolling when the fixed side navigation hovered over 21 | $('body.fixed-nav .sidebar').on('mousewheel DOMMouseScroll wheel', function(e) { 22 | if ($(window).width() > 768) { 23 | var e0 = e.originalEvent, 24 | delta = e0.wheelDelta || -e0.detail; 25 | this.scrollTop += (delta < 0 ? 1 : -1) * 30; 26 | e.preventDefault(); 27 | } 28 | }); 29 | 30 | // Scroll to top button appear 31 | $(document).on('scroll', function() { 32 | var scrollDistance = $(this).scrollTop(); 33 | if (scrollDistance > 100) { 34 | $('.scroll-to-top').fadeIn(); 35 | } else { 36 | $('.scroll-to-top').fadeOut(); 37 | } 38 | }); 39 | 40 | // Smooth scrolling using jQuery easing 41 | $(document).on('click', 'a.scroll-to-top', function(e) { 42 | var $anchor = $(this); 43 | $('html, body').stop().animate({ 44 | scrollTop: ($($anchor.attr('href')).offset().top) 45 | }, 1000, 'easeInOutExpo'); 46 | e.preventDefault(); 47 | }); 48 | 49 | })(jQuery); // End of use strict 50 | -------------------------------------------------------------------------------- /teachers/static/teachers/js/theme.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | "use strict"; // Start of use strict 3 | 4 | // Toggle the side navigation 5 | $("#sidebarToggle, #sidebarToggleTop").on('click', function(e) { 6 | $("body").toggleClass("sidebar-toggled"); 7 | $(".sidebar").toggleClass("toggled"); 8 | if ($(".sidebar").hasClass("toggled")) { 9 | $('.sidebar .collapse').collapse('hide'); 10 | }; 11 | }); 12 | 13 | // Close any open menu accordions when window is resized below 768px 14 | $(window).resize(function() { 15 | if ($(window).width() < 768) { 16 | $('.sidebar .collapse').collapse('hide'); 17 | }; 18 | }); 19 | 20 | // Prevent the content wrapper from scrolling when the fixed side navigation hovered over 21 | $('body.fixed-nav .sidebar').on('mousewheel DOMMouseScroll wheel', function(e) { 22 | if ($(window).width() > 768) { 23 | var e0 = e.originalEvent, 24 | delta = e0.wheelDelta || -e0.detail; 25 | this.scrollTop += (delta < 0 ? 1 : -1) * 30; 26 | e.preventDefault(); 27 | } 28 | }); 29 | 30 | // Scroll to top button appear 31 | $(document).on('scroll', function() { 32 | var scrollDistance = $(this).scrollTop(); 33 | if (scrollDistance > 100) { 34 | $('.scroll-to-top').fadeIn(); 35 | } else { 36 | $('.scroll-to-top').fadeOut(); 37 | } 38 | }); 39 | 40 | // Smooth scrolling using jQuery easing 41 | $(document).on('click', 'a.scroll-to-top', function(e) { 42 | var $anchor = $(this); 43 | $('html, body').stop().animate({ 44 | scrollTop: ($($anchor.attr('href')).offset().top) 45 | }, 1000, 'easeInOutExpo'); 46 | e.preventDefault(); 47 | }); 48 | 49 | })(jQuery); // End of use strict 50 | -------------------------------------------------------------------------------- /teachers/templates/teachers/classroomstudents.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% load static %} {% block title %}List of Students{% endblock title %} {% block content %} 2 | 3 | 4 |
5 |

{{classroom.subject|upper}}

6 |
7 |
8 |

Student List

9 |
10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | {% for student in classroom_students %} 24 | 25 | 26 | 27 | 28 | 29 | 30 | {% endfor %} 31 | 32 | 33 | 34 | 35 | 36 |
NameStudent IDClassRoll No.
{{student.user.first_name}} {{student.user.last_name}}{{student.student_id}}{{student.current_class}}{{student.roll_no}}
37 |
38 |
39 |
40 |
41 | 42 | {% endblock content %} -------------------------------------------------------------------------------- /students/templates/students/resources.html: -------------------------------------------------------------------------------- 1 | {% extends 'students/base.html' %} 2 | 3 | 4 | {% block title %}Resources{% endblock title %} 5 | 6 | 7 | {% block content %} 8 | 9 |
10 |

{{section.classroom.subject|upper}} : Resources

11 |
12 | 13 | 14 | {% for resource in section.resources.all|dictsortreversed:"created_timestamp" %} 15 |
16 | 17 |
18 |
19 |
20 |

{{resource.created_timestamp|date:"M d, Y"}}

21 |

{{resource.text|linebreaksbr}}

22 |
23 | 24 | 25 | {% if resource.file %} 26 | Download Resource {% endif %} 27 | 28 |
29 |
30 |
31 | 32 |
33 | 34 |
35 | {% endfor %} 36 | 37 |
38 | 39 | 40 | {% endblock content %} -------------------------------------------------------------------------------- /.github/workflows/master_lms-app.yml: -------------------------------------------------------------------------------- 1 | # Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy 2 | # More GitHub Actions for Azure: https://github.com/Azure/actions 3 | # More info on Python, GitHub Actions, and Azure App Service: https://aka.ms/python-webapps-actions 4 | 5 | name: Build and deploy Python app to Azure Web App - lms-app 6 | 7 | on: 8 | push: 9 | branches: 10 | - master 11 | workflow_dispatch: 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | 20 | - name: Set up Python version 21 | uses: actions/setup-python@v1 22 | with: 23 | python-version: '3.9' 24 | 25 | - name: Create and start virtual environment 26 | run: | 27 | python -m venv venv 28 | source venv/bin/activate 29 | 30 | - name: Install dependencies 31 | run: pip install -r requirements.txt 32 | 33 | # Optional: Add step to run tests here (PyTest, Django test suites, etc.) 34 | 35 | - name: Upload artifact for deployment jobs 36 | uses: actions/upload-artifact@v2 37 | with: 38 | name: python-app 39 | path: | 40 | . 41 | !venv/ 42 | 43 | deploy: 44 | runs-on: ubuntu-latest 45 | needs: build 46 | environment: 47 | name: 'Production' 48 | url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} 49 | 50 | steps: 51 | - name: Download artifact from build job 52 | uses: actions/download-artifact@v2 53 | with: 54 | name: python-app 55 | path: . 56 | 57 | - name: 'Deploy to Azure Web App' 58 | uses: azure/webapps-deploy@v2 59 | id: deploy-to-webapp 60 | with: 61 | app-name: 'lms-app' 62 | slot-name: 'Production' 63 | publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_42E0E845E61C43DCB8DA10DADAD661C8 }} 64 | -------------------------------------------------------------------------------- /students/templates/students/dashboard.html: -------------------------------------------------------------------------------- 1 | {% extends 'students/base.html' %} 2 | 3 | 4 | {% block title %}Student Dashboard{% endblock title %} 5 | 6 | 7 | {% block content %} 8 | 9 |
10 |

Classrooms

11 |
12 | 13 | 14 | {% for classroom in user.students.classrooms.all %} 15 |
16 |
17 |
18 | {{ classroom.subject|upper }} 19 |
20 | 28 |
29 |
30 |

Classroom code : {{ classroom.code }}

31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | Manage 39 | 40 |
41 |
42 | {% endfor %} 43 | 44 |
45 | 46 | 47 | {% endblock content %} -------------------------------------------------------------------------------- /teachers/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import include, path 2 | from .views import (DashboardView, 3 | ClassroomCreateView, 4 | ClassroomDeleteView, 5 | ClassroomDetailView, 6 | ResourcesView, 7 | SectionCreateView, 8 | AssignmentsView, 9 | SectionDeleteView, 10 | ResourceCreateView, 11 | ResourceDeleteView, 12 | AssignmentCreateView, 13 | AssignmentDeleteView, 14 | AssignmentSubmissionsView, 15 | ClassroomStudentsView, 16 | ) 17 | 18 | app_name = 'teachers' 19 | 20 | urlpatterns = [ 21 | path('', DashboardView.as_view(), name='dashboard'), 22 | path('classroom/add/', ClassroomCreateView.as_view(), name='add_classroom'), 23 | path('classroom//delete/', ClassroomDeleteView.as_view(), name='delete_classroom'), 24 | path('classroom//', ClassroomDetailView, name='classroom_detail'), 25 | path('classroom//students/', ClassroomStudentsView, name='classroom_students'), 26 | path('classroom//add/', SectionCreateView.as_view(), name='add_section'), 27 | path('section//delete/', SectionDeleteView.as_view(), name='delete_section'), 28 | path('resources//', ResourcesView, name='resources'), 29 | path('resources//add/', ResourceCreateView.as_view(), name='add_resource'), 30 | path('resources/delete//', ResourceDeleteView.as_view(), name='delete_resource'), 31 | path('assignments//', AssignmentsView, name='assignments'), 32 | path('assignments//add/', AssignmentCreateView.as_view(), name='add_assignment'), 33 | path('assignments/delete//', AssignmentDeleteView.as_view(), name='delete_assignment'), 34 | path('submissions//', AssignmentSubmissionsView, name='assignment_submissions'), 35 | ] 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learning Management System 2 | 3 | ### Demo: 4 | https://lmsdjango.azurewebsites.net/ 5 | 6 | ### This project is made using : 7 | - Django 3.2.5 8 | - Python 3.9.11 9 | - Bootstrap 10 | - django-bootstrap4 11 | - Microsoft Azure 12 | - django-storages 13 | 14 | 15 | ## Problem Statement 16 | 17 | The Learning Management System is for any learner or teacher which will replace 18 | existing conventional methods of chalk and board style of learning. The new system 19 | will control the following information: store the instructional materials , books , 20 | videos , and control information and various other educational resources, which will 21 | be organized by category. These services are to be provided in an effective manner, 22 | with the goal of giving and receiving simpler, prolific, and productive learning. 23 | 24 | ## Objectives 25 | The Learning Management System is designed to replace existing conventional 26 | methods of chalk and board style of learning. A Learning Management System 27 | (LMS) is software that automates the administration of teaching events. All 28 | Learning Management Systems manage the log-in of registered users, manage 29 | course catalogs, record data from learners, and provide reports to management. 30 | However, most of the LMS in service have different characteristics and are mutually 31 | incompatible, hence, effective Learning Management System needs to be 32 | standardized thus, we are implementing LMS. 33 | 34 | 35 | 36 | ## Installation 37 | 38 | ```bash 39 | $ git clone https://github.com/radonintro1234/django-learning-management-system.git 40 | 41 | $ cd django-learning-management-system 42 | 43 | $ pip install -r requirements.txt 44 | ``` 45 | 46 | ## Usage 47 | 48 | ```bash 49 | $ python manage.py makemigrations 50 | 51 | $ python manage.py migrate 52 | 53 | $ python manage.py runserver 54 | ``` 55 | 56 | ## Relation Schema of the database 57 | 58 | ![ER](https://raw.githubusercontent.com/radonintro1234/django-learning-management-system/master/screenshots/2022-04-22_11-58-18-957_hwgAvOaf6J.png) 59 | 60 | ## Contributing 61 | Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. 62 | 63 | Please make sure to update tests as appropriate. 64 | 65 | ## License 66 | [MIT](https://choosealicense.com/licenses/mit/) 67 | -------------------------------------------------------------------------------- /accounts/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import redirect, render 2 | from django.contrib.auth import login, logout 3 | from django.views.generic import TemplateView, CreateView, ListView 4 | from .models import User, Student, Teacher, Stream 5 | from .forms import StudentForm, TeacherForm 6 | from accounts.passtests import StudentTestMixin, TeacherTestMixin 7 | 8 | 9 | # Create your views here. 10 | 11 | class IndexView(TemplateView): 12 | template_name = "accounts/index.html" 13 | 14 | 15 | class StudentCreateView(CreateView): 16 | model = User 17 | form_class = StudentForm 18 | template_name = "accounts/student_signup.html" 19 | 20 | def get_context_data(self, **kwargs): 21 | kwargs['user_type'] = 'student' 22 | return super().get_context_data(**kwargs) 23 | 24 | def form_valid(self, form): 25 | user = form.save() 26 | login(self.request, user) 27 | return redirect('dashboard') 28 | 29 | def get_form_kwargs(self): 30 | kwargs = super().get_form_kwargs() 31 | print(self.kwargs) 32 | kwargs.update({ 33 | 'stream': Stream.objects.filter(pk=self.kwargs['stream_pk']).first(), 34 | }) 35 | print(Stream.objects.filter(pk=self.kwargs['stream_pk']).first()) 36 | return kwargs 37 | 38 | class StreamView(TemplateView): 39 | 40 | def get_context_data(self, **kwargs): 41 | context = super(StreamView, self).get_context_data(**kwargs) 42 | context['stream_list'] = Stream.objects.all() 43 | print 44 | return context 45 | 46 | class TeacherCreateView(CreateView): 47 | model = User 48 | form_class = TeacherForm 49 | template_name = "accounts/teacher_signup.html" 50 | 51 | def get_context_data(self, **kwargs): 52 | kwargs['user_type'] = 'teacher' 53 | return super().get_context_data(**kwargs) 54 | 55 | def form_valid(self, form): 56 | user = form.save() 57 | login(self.request, user) 58 | return redirect('dashboard') 59 | 60 | def get_form_kwargs(self): 61 | kwargs = super().get_form_kwargs() 62 | print(self.kwargs) 63 | kwargs.update({ 64 | 'stream': Stream.objects.filter(pk=self.kwargs['stream_pk']).first(), 65 | }) 66 | print(Stream.objects.filter(pk=self.kwargs['stream_pk']).first()) 67 | return kwargs -------------------------------------------------------------------------------- /teachers/templates/teachers/dashboard.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% block title %}Dashboard{% endblock title %} {% block content %} 2 | 3 |
4 |

Classrooms

5 |
6 | 7 | 8 | {% for classrom in user.teachers.classrooms.all %} 9 |
10 |
11 |
{{ classrom.subject }}
12 | 15 |
16 |
17 |

Classroom code : {{ classrom.code }}

18 |
19 | 20 |
21 |
22 | Manage 25 | 26 |
27 |
28 | Students 31 | 32 |
33 |
34 |
35 |
36 | 37 | {% endfor %} 38 |
39 | 40 | {% endblock content %} -------------------------------------------------------------------------------- /teachers/templates/teachers/submissions.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% load static %} {% block title %}Submissions{% endblock title %} {% block content %} 2 | 3 | 4 |
5 |

Assignment Submissions

6 |
7 |
8 |

{{assignment.title}}

9 |
10 |
11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {% for submission in assignment_submissions %} 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | {% endfor %} 36 | 37 | 38 | 39 | 40 | 41 |
NameStudent IDClassRoll No.Submission dateDownload File
{{submission.student.user.first_name}} {{submission.student.user.last_name}}{{submission.student.student_id}}{{submission.student.current_class}}{{submission.student.roll_no}}{{submission.submission_timestamp|date:"d/m/Y"}} {{submission.submission_timestamp|date:"h:i A"}}Download 
42 |
43 |
44 |
45 |
46 | 47 | {% endblock content %} -------------------------------------------------------------------------------- /teachers/templates/teachers/classroom_detail.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% load static %} {% block title %}Classroom Detail{% endblock title %} {% block content %} 2 | 3 |
4 |

{{ classroom.subject|upper }}

5 |
6 | 7 |
8 | 9 | Add Section 11 | 12 |
13 |
14 | 15 | 16 | {% for section in classroom.sections.all %} 17 |
18 |
19 |
{{section.title}}
20 |
21 |
22 |
23 |
24 | Resources 27 | 28 | Assignments 31 | 32 |
33 |
34 | Delete 36 | 37 |
38 |
39 |
40 |
41 | 42 | {% endfor %} 43 |
44 | 45 | 46 | {% endblock content %} -------------------------------------------------------------------------------- /students/templates/students/assignments.html: -------------------------------------------------------------------------------- 1 | {% extends 'students/base.html' %} 2 | 3 | 4 | {% block title %}Resources{% endblock title %} 5 | 6 | 7 | {% block content %} 8 | 9 |
10 |

{{section.classroom.subject|upper}} : Assignments

11 |
12 | 13 | 14 |
15 | 16 | {% for assignment in section.assignments.all|dictsortreversed:"created_timestamp" %} 17 |
18 |
19 |
20 | 21 |

{{assignment.text|linebreaksbr}}

22 | 23 | 24 |
25 |
26 |
27 | {% if assignment.file %} 28 | 29 | 30 | 31 | 32 | 33 | Download Assignment 34 | 35 | 36 | {% endif %} 37 |
38 | 39 | 49 |
50 | 51 |
52 |
53 |
54 | 55 |
56 | 57 | {% endfor %} 58 |
59 | 60 |
61 | 62 | 63 | {% endblock content %} -------------------------------------------------------------------------------- /students/templates/students/assignmentsubmission.html: -------------------------------------------------------------------------------- 1 | {% extends 'students/base.html' %} 2 | 3 | 4 | {% load static %} 5 | 6 | 7 | {% block title %}Resources{% endblock title %} 8 | 9 | 10 | {% block content %} 11 | 12 |
13 | 14 |
15 |
16 |
Assignment Title
17 |
18 |
19 | 22 | 23 |
24 | 25 |
26 |
27 |
28 |
29 |
30 |
31 |

Upload your File....

32 |
33 |
34 | {% csrf_token %} 35 |
36 |
37 | {{form.file}} 38 | 39 | 40 |
41 |
42 | 43 |
44 |
45 |
46 |
47 |
48 |
49 | 50 |
51 | 52 |
53 |
54 | 55 |
56 | 57 | 60 | 61 | 62 | 63 | 70 | 71 | 72 | {% endblock content %} -------------------------------------------------------------------------------- /students/templates/students/join_classroom.html: -------------------------------------------------------------------------------- 1 | {% extends 'students/base.html' %} 2 | 3 | 4 | {% load static %} 5 | 6 | 7 | {% block title %}Resources{% endblock title %} 8 | 9 | 10 | {% block content %} 11 | 12 |
13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 |

Class code

21 |

Ask your teacher for the class code , then enter it here !

22 |
23 |
24 | {% csrf_token %} 25 |
{{form.code}}
26 | 27 |
28 |
29 |
30 |
31 |

To sign in with a class code                                                          32 |                          Use an authorized account                                33 |                                                  Use a class code with 5-7 letters or numbers, and no 34 | spaces or                   symbols.                                          35 |                                                                   36 |  If you have trouble joining the class, go to the Help.

37 |
38 |
39 |
40 |
41 | 42 |
43 | 44 | 49 | 50 | {% endblock content %} -------------------------------------------------------------------------------- /teachers/templates/teachers/resources.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% load static %} {% block title %}Resources{% endblock title %} {% block content %} 2 | 3 |
4 |

Resources

5 |
6 | Add Resources 7 | 8 |
9 |
10 | 11 | 12 | {% for resource in section.resources.all|dictsortreversed:"created_timestamp" %} 13 |
14 | 15 | 16 |
{{resource.title}} 17 |
18 |
19 |

{{resource.created_timestamp|date:"M d, Y"}}

20 |
21 |

{{resource.text|linebreaksbr}}

22 |
23 | 24 |
25 | {% if resource.file %} 26 |
27 | Download Resource 28 | 29 |
30 | {% endif %} 31 |
32 | 33 | 34 | Delete 35 | 36 |
37 |
38 |
39 |
40 |
41 | 42 |
43 | 44 |
45 | 46 | {% endfor %} 47 |
48 | 49 | 50 | {% endblock content %} -------------------------------------------------------------------------------- /teachers/templates/teachers/assignments.html: -------------------------------------------------------------------------------- 1 | {% extends 'teachers/base.html' %} {% load static %} {% block title %}Assignments{% endblock title %} {% block content %} 2 | 3 |
4 |

Assignments

5 |
6 | 7 |
8 | Add Assignment 9 | 10 |
11 |
12 | 13 | 14 | {% for assignment in section.assignments.all|dictsortreversed:"created_timestamp" %} 15 |
16 | 17 |
{{assignment.title}} 18 |
19 |
20 | 21 |

{{assignment.text|linebreaksbr}}

22 |
23 | 24 |
25 | {% if assignment.file %} 26 |
27 | Download Assignment 28 | 29 |
30 | {% endif %} 31 |
32 | Submissions 33 | 34 |
35 |
36 | Delete 37 | 38 |
39 |
40 |
41 |
42 |
43 |
44 | 45 |
46 | 47 |
48 | 49 | {% endfor %} 50 |
51 | 52 | {% endblock content %} -------------------------------------------------------------------------------- /students/templates/students/my_assignment.html: -------------------------------------------------------------------------------- 1 | {% extends 'students/base.html' %} 2 | 3 | 4 | {% load static %} 5 | 6 | 7 | {% block title %}Resources{% endblock title %} 8 | 9 | 10 | {% block content %} 11 | 12 |
13 | 14 |
15 |
16 |
{{assignment.title}}
17 |
18 |
19 | 27 | 28 | 29 |
30 | 36 |
37 |
38 | 39 |
40 |
41 |
42 | 52 | 62 |
63 |
64 |
65 |
66 | 67 |
68 |
69 | 70 |
71 | 72 | 73 | {% endblock content %} -------------------------------------------------------------------------------- /accounts/templates/accounts/teacher_signup.html: -------------------------------------------------------------------------------- 1 | {% load static %} {% load bootstrap4 %} {% bootstrap_messages %} 2 | 3 | 4 | 5 | 6 | 7 | Register - Teacher 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |

Create an Teacher Account!

21 |
22 |
23 | {% csrf_token %} 24 |
25 |
{{form.first_name}}
26 |
{{form.last_name}}
27 |
28 |
{{form.email}}
29 |
{{form.username}}
30 |
31 |
{{form.password1}}
32 |
{{form.password2}}
33 |
34 | {{form.username.errors}} {{form.password1.errors}} {{form.password2.errors}} {{ form.non_field_errors }} 35 | 36 | 39 |
40 |
41 |
42 | Forgot Password? 44 |
45 | 50 |
51 |
52 |
53 |
54 |
55 |
56 | 57 | 58 | 59 | 60 | 80 | 81 | -------------------------------------------------------------------------------- /accounts/templates/accounts/login.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | Login - LMS 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |

Welcome Back!

23 |
24 |
25 | {% csrf_token %} 26 |
27 | {{form.username}} 28 | 29 |
30 |
31 | {{form.password}} 32 | 33 |
34 |
35 |
36 |
37 | 38 | 39 |
40 |
41 |
42 |
43 |
44 | 45 | 46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | 55 | 56 | 57 | 58 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /students/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponseRedirect 2 | from django import forms 3 | from django import views 4 | from django.shortcuts import redirect, render, get_object_or_404 5 | from django.urls import reverse, reverse_lazy 6 | from django.views.generic import TemplateView, CreateView, ListView, DeleteView, DetailView 7 | from accounts.models import Classroom,Teacher,User,Section, Resource,Assignment,AssignmentSubmission 8 | from accounts.passtests import StudentTestMixin, TeacherTestMixin 9 | from .forms import AssignmentSubmissionForm, JoinClassroomForm 10 | 11 | # Create your views here. 12 | 13 | class DashboardView(StudentTestMixin, TemplateView): 14 | template_name = "students/dashboard.html" 15 | 16 | def ClassroomDetailView(request,code): 17 | context_dict = {} 18 | room = get_object_or_404(Classroom, code=code) 19 | context_dict['classroom'] = room 20 | return render(request, 'students/classroom_detail.html', context=context_dict) 21 | 22 | def ResourcesView(request, pk): 23 | context_dict = {} 24 | section = get_object_or_404(Section, pk=pk) 25 | print(section) 26 | context_dict['section'] = section 27 | return render(request, 'students/resources.html', context=context_dict) 28 | 29 | def AssignmentsView(request, pk): 30 | context_dict = {} 31 | section = get_object_or_404(Section, pk=pk) 32 | print(section) 33 | context_dict['section'] = section 34 | return render(request, 'students/assignments.html', context=context_dict) 35 | 36 | class AssignmentSubmissionCreateView(CreateView): 37 | model = AssignmentSubmission 38 | form_class = AssignmentSubmissionForm 39 | template_name = "students/assignmentsubmission.html" 40 | 41 | def form_valid(self, form): 42 | form.instance.assignment = get_object_or_404(Assignment, pk=self.kwargs['pk']) 43 | form.instance.student = self.request.user.students 44 | return super().form_valid(form) 45 | 46 | def get_success_url(self): 47 | return reverse('students:assignments', kwargs={'pk':Assignment.objects.get(pk=self.kwargs['pk']).section.pk}) 48 | 49 | def MyAssignmentView(request, pk): 50 | context_dict = {} 51 | student = request.user.students 52 | assignment = Assignment.objects.get(pk=pk) 53 | 54 | if AssignmentSubmission.objects.filter(assignment=assignment).filter(student=student).exists(): 55 | context_dict['assignment'] = assignment 56 | context_dict['submission'] = AssignmentSubmission.objects.filter(assignment=assignment).filter(student=student)[0] 57 | context_dict['assignmentfilename'] = context_dict['submission'].file.name.split('/')[-1] 58 | return render(request, template_name='students/my_assignment.html', context=context_dict) 59 | else: 60 | return redirect('students:submit_assignment', pk=pk) 61 | 62 | class AssignmentSubmissionDeleteView(DeleteView): 63 | model = AssignmentSubmission 64 | template_name = "students/deletesubmission.html" 65 | 66 | def get_success_url(self): 67 | return reverse('students:assignments', kwargs={'pk':self.object.assignment.section.pk}) 68 | 69 | def joinClassroomView(request): 70 | form = JoinClassroomForm() 71 | 72 | if request.method == 'POST': 73 | form = JoinClassroomForm(request.POST) 74 | 75 | if form.is_valid(): 76 | code = form.cleaned_data['code'] 77 | print(code) 78 | if Classroom.objects.filter(code=code).exists(): 79 | print('Exists', form.cleaned_data['code']) 80 | 81 | if request.user.students.classrooms.filter(code=code).exists(): 82 | print('User already a member') 83 | return HttpResponseRedirect(reverse('students:dashboard')) 84 | else: 85 | print('User not a member') 86 | request.user.students.classrooms.add(Classroom.objects.filter(code=code).first()) 87 | print('User joined the classroom') 88 | return HttpResponseRedirect(reverse('students:dashboard')) 89 | else: 90 | print('Classroom dosent exist') 91 | return render(request, 'students/join_classroom.html', {'form':form}) 92 | 93 | 94 | def LeaveClassroomView(request,code): 95 | request.user.students.classrooms.remove(Classroom.objects.filter(code=code).first()) 96 | return HttpResponseRedirect(reverse('students:dashboard')) 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /accounts/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.contrib.auth.forms import UserCreationForm 3 | from django.db import transaction 4 | from .models import Student, User, Teacher, Class, Classroom 5 | 6 | 7 | class StudentForm(UserCreationForm): 8 | def __init__(self,*args,**kwargs): 9 | self.stream = kwargs.pop('stream') 10 | print('stream is ', self.stream) 11 | super(StudentForm,self).__init__(*args,**kwargs) 12 | 13 | if Class.objects.all().exists(): 14 | self.fields['current_class'].queryset = Class.objects.filter(stream=self.stream).order_by('name') 15 | 16 | email = forms.EmailField(label='Email', required=True) 17 | 18 | first_name = forms.CharField( 19 | label='First Name', max_length=250, required=True) 20 | 21 | last_name = forms.CharField( 22 | label='Last Name', max_length=250, required=True) 23 | 24 | current_class = forms.ModelChoiceField(queryset=None, empty_label=None, required=True) 25 | 26 | roll_no =forms.IntegerField(label='Roll No.', required=True, min_value=1, max_value=500) 27 | 28 | student_id = forms.CharField(label='Student ID', max_length=50, required=True, min_length=4) 29 | 30 | class Meta(UserCreationForm.Meta): 31 | model = User 32 | 33 | @transaction.atomic 34 | def save(self): 35 | user = super().save(commit=False) 36 | user.is_student = True 37 | user.first_name = self.cleaned_data['first_name'] 38 | user.last_name = self.cleaned_data['last_name'] 39 | user.email = self.cleaned_data['email'] 40 | user.save() 41 | student = Student.objects.create( 42 | user=user, 43 | current_class = self.cleaned_data['current_class'], 44 | roll_no = self.cleaned_data['roll_no'], 45 | student_id = self.cleaned_data['student_id'], 46 | ) 47 | student.save() 48 | return user 49 | 50 | def clean(self): 51 | cleaned_data = super().clean() 52 | current_class = cleaned_data.get('current_class') 53 | roll_no = self.cleaned_data.get('roll_no') 54 | student_id = self.cleaned_data.get('student_id') 55 | email = self.cleaned_data.get('email') 56 | 57 | # Class and Roll No. Unique Constraint Validation 58 | if Student.objects.filter(current_class=current_class).filter(roll_no=roll_no).exists(): 59 | print("Roll no in class") 60 | raise forms.ValidationError('Student with Roll No. already exists.') 61 | 62 | # Student id validation 63 | if Student.objects.filter(student_id=student_id).exists(): 64 | print("Student ID exists") 65 | raise forms.ValidationError('Student with Student ID already exists.') 66 | 67 | # Email Validations 68 | if User.objects.filter(email=email).exists(): 69 | print("Email exists") 70 | raise forms.ValidationError('User with Email already exists.') 71 | 72 | 73 | class TeacherForm(UserCreationForm): 74 | def __init__(self,*args,**kwargs): 75 | self.stream = kwargs.pop('stream') 76 | print('stream is ', self.stream) 77 | print(type(self.stream)) 78 | super(TeacherForm,self).__init__(*args,**kwargs) 79 | 80 | email = forms.EmailField(label='Email', required=True) 81 | 82 | first_name = forms.CharField( 83 | label='First Name', max_length=250, required=True) 84 | 85 | last_name = forms.CharField( 86 | label='Last Name', max_length=250, required=True) 87 | 88 | class Meta(UserCreationForm.Meta): 89 | model = User 90 | 91 | @transaction.atomic 92 | def save(self): 93 | user = super().save(commit=False) 94 | user.is_teacher = True 95 | user.first_name = self.cleaned_data['first_name'] 96 | user.last_name = self.cleaned_data['last_name'] 97 | user.email = self.cleaned_data['email'] 98 | user.save() 99 | teacher = Teacher.objects.create( 100 | user=user, 101 | stream = self.stream 102 | ) 103 | teacher.save() 104 | return user 105 | 106 | def clean(self): 107 | cleaned_data = super().clean() 108 | email = self.cleaned_data.get('email') 109 | 110 | # Email Validations 111 | if User.objects.filter(email=email).exists(): 112 | print("Email exists") 113 | raise forms.ValidationError('User with Email already exists.') 114 | -------------------------------------------------------------------------------- /mylms/templates/mylms/home.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | {% block title %}L.M.S{% endblock title %} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 34 |
35 | 36 | {% block content %} 37 |
38 |
39 |
40 |

41 | Get started with
the learning management system
42 |

43 |
44 | 45 |
46 |
47 |
48 |

49 | Login 50 |
51 |
52 | 53 | {% endblock content %} 54 |
55 |
56 |
57 |
58 |
59 |

Let's Get In Touch!

60 |
61 |

62 | Facing any problems?  Give us a call or send us an email and we will get back to you as soon as possible! 63 |

64 |
65 |
66 |
67 |
68 | 69 |

123-456-6789

70 |
71 |
72 | 73 |

74 | support@lmsportal.com 75 |

76 |
77 |
78 |
79 |
80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /accounts/templates/accounts/base.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | {% block title %}L.M>S{% endblock title %} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 35 |
36 | 37 | {% block content %} 38 |
39 |
40 |
41 |

42 | Get started with
the learning management system
43 |

44 |
45 | 46 |
47 |
48 |
49 |

50 | Login 51 |
52 |
53 | 54 | {% endblock content %} 55 |
56 |
57 |
58 |
59 |
60 |

Let's Get In Touch!

61 |
62 |

63 | Facing any problems?  Give us a call or send us an email and we will get back to you as soon as possible! 64 |

65 |
66 |
67 |
68 |
69 | 70 |

123-456-6789

71 |
72 |
73 | 74 |

75 | support@lmsportal.com 76 |

77 |
78 |
79 |
80 |
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /mylms/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for mylms project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.2.5. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.2/ref/settings/ 11 | """ 12 | import environ 13 | # Initialise environment variables 14 | env = environ.Env() 15 | environ.Env.read_env() 16 | 17 | from pathlib import Path 18 | 19 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 20 | BASE_DIR = Path(__file__).resolve().parent.parent 21 | 22 | 23 | # Quick-start development settings - unsuitable for production 24 | # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ 25 | 26 | # SECURITY WARNING: keep the secret key used in production secret! 27 | SECRET_KEY = env('SECRET_KEY') 28 | 29 | # SECURITY WARNING: don't run with debug turned on in production! 30 | DEBUG = True 31 | 32 | ALLOWED_HOSTS = ['*'] 33 | 34 | 35 | # Application definition 36 | 37 | INSTALLED_APPS = [ 38 | 39 | 'django.contrib.admin', 40 | 'django.contrib.auth', 41 | 'django.contrib.contenttypes', 42 | 'django.contrib.sessions', 43 | 'django.contrib.messages', 44 | 'django.contrib.staticfiles', 45 | 'storages', 46 | 'accounts', 47 | 'bootstrap4', 48 | 'students', 49 | 'teachers', 50 | ] 51 | 52 | MIDDLEWARE = [ 53 | 'django.middleware.security.SecurityMiddleware', 54 | 'django.contrib.sessions.middleware.SessionMiddleware', 55 | 'django.middleware.common.CommonMiddleware', 56 | 'django.middleware.csrf.CsrfViewMiddleware', 57 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 58 | 'django.contrib.messages.middleware.MessageMiddleware', 59 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 60 | ] 61 | 62 | ROOT_URLCONF = 'mylms.urls' 63 | 64 | TEMPLATES = [ 65 | { 66 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 67 | 'DIRS': [BASE_DIR / 'mylms/templates'], 68 | 'APP_DIRS': True, 69 | 'OPTIONS': { 70 | 'context_processors': [ 71 | 'django.template.context_processors.debug', 72 | 'django.template.context_processors.request', 73 | 'django.contrib.auth.context_processors.auth', 74 | 'django.contrib.messages.context_processors.messages', 75 | ], 76 | }, 77 | }, 78 | ] 79 | 80 | WSGI_APPLICATION = 'mylms.wsgi.application' 81 | 82 | 83 | # Database 84 | # https://docs.djangoproject.com/en/3.2/ref/settings/#databases 85 | 86 | DATABASES = { 87 | 'default': { 88 | 'ENGINE': 'django.db.backends.sqlite3', 89 | 'NAME': BASE_DIR / 'db.sqlite3', 90 | } 91 | } 92 | 93 | 94 | # Password validation 95 | # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators 96 | 97 | AUTH_PASSWORD_VALIDATORS = [ 98 | { 99 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 100 | }, 101 | { 102 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 103 | }, 104 | { 105 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 106 | }, 107 | { 108 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 109 | }, 110 | ] 111 | 112 | 113 | # Internationalization 114 | # https://docs.djangoproject.com/en/3.2/topics/i18n/ 115 | 116 | LANGUAGE_CODE = 'en-us' 117 | 118 | TIME_ZONE = 'Asia/Kolkata' 119 | 120 | USE_I18N = True 121 | 122 | USE_L10N = True 123 | 124 | USE_TZ = True 125 | 126 | 127 | # Static files (CSS, JavaScript, Images) 128 | # https://docs.djangoproject.com/en/3.2/howto/static-files/ 129 | 130 | STATIC_URL = '/static/' 131 | STATIC_FILES_DIRS = [BASE_DIR / 'mylms/lmsstatic'] 132 | 133 | # Default primary key field type 134 | # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field 135 | 136 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 137 | 138 | AUTH_USER_MODEL = 'accounts.User' 139 | 140 | MEDIA_ROOT = BASE_DIR / 'media/' 141 | MEDIA_URL = "/cloud/media/" 142 | 143 | LOGIN_REDIRECT_URL = "/dashboard/" 144 | LOGIN_URL = '/accounts/login/' 145 | 146 | LOGOUT_REDIRECT_URL = '/' 147 | 148 | 149 | DEFAULT_FILE_STORAGE = 'mylms.custom_azure.AzureMediaStorage' 150 | STATICFILES_STORAGE = 'mylms.custom_azure.AzureStaticStorage' 151 | 152 | STATIC_LOCATION = "static" 153 | MEDIA_LOCATION = "media" 154 | 155 | AZURE_ACCOUNT_NAME = env('AZURE_ACCOUNT_NAME') 156 | AZURE_STORAGE_ACCOUNT_KEY = env('AZURE_STORAGE_ACCOUNT_KEY') 157 | 158 | AZURE_CUSTOM_DOMAIN = f'{AZURE_ACCOUNT_NAME}.blob.core.windows.net' 159 | STATIC_URL = f'https://{AZURE_CUSTOM_DOMAIN}/{STATIC_LOCATION}/' 160 | MEDIA_URL = f'https://{AZURE_CUSTOM_DOMAIN}/{MEDIA_LOCATION}/' -------------------------------------------------------------------------------- /accounts/templates/accounts/student_signup.html: -------------------------------------------------------------------------------- 1 | {% load static %} {% load bootstrap4 %} {% bootstrap_messages %} 2 | 3 | 4 | 5 | 6 | 7 | Register - Student 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |

Create an Student Account!

21 |
22 |
23 | {% csrf_token %} 24 |
25 |
{{form.first_name}}
26 |
{{form.last_name}}
27 |
28 |
29 |
30 | {{form.current_class}} 31 |
32 |
{{form.roll_no}}
33 |
34 |
35 |
{{form.username}}
36 |
{{form.student_id}}
37 |
38 |
{{form.email}}
39 |
40 |
{{form.password1}}
41 |
{{form.password2}}
42 |
43 | {{form.username.errors}} {{form.password1.errors}} {{form.password2.errors}} {{ form.non_field_errors }} 44 | 45 | 48 |
49 |
50 |
51 | Forgot Password? 53 |
54 | 59 |
60 |
61 |
62 |
63 |
64 |
65 | 66 | 67 | 68 | 69 | 98 | 99 | -------------------------------------------------------------------------------- /teachers/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponseRedirect 2 | from django.shortcuts import render, get_object_or_404 3 | from django.urls import reverse, reverse_lazy 4 | from django.views.generic import TemplateView, CreateView, ListView, DeleteView, DetailView 5 | from accounts.models import Classroom,Teacher,User,Section, Resource,Assignment,AssignmentSubmission 6 | from .forms import ClassroomForm, SectionForm,ResourceForm, AssignmentForm 7 | from accounts.passtests import StudentTestMixin, TeacherTestMixin 8 | 9 | 10 | # Create your views here. 11 | 12 | class DashboardView(TeacherTestMixin,TemplateView): 13 | template_name = "teachers/dashboard.html" 14 | 15 | def get_context_data(self, **kwargs): 16 | context = super().get_context_data(**kwargs) 17 | context['classrooms'] = self.request.user.teachers.classrooms.all() 18 | return context 19 | 20 | def add_classroom(request): 21 | form = ClassroomForm() 22 | 23 | def form_valid(self, form): 24 | classroom = form.save(commit=False) 25 | classroom.teacher = Teacher.objects.get(user=self.request.user.teachers) 26 | classroom.save() 27 | return HttpResponseRedirect(self.get_success_url()) 28 | 29 | class ClassroomCreateView(CreateView): 30 | model = Classroom 31 | form_class = ClassroomForm 32 | template_name = "teachers/addclassroom.html" 33 | 34 | def form_valid(self, form): 35 | form.instance.teacher = self.request.user.teachers 36 | return super().form_valid(form) 37 | 38 | def get_success_url(self): 39 | return reverse('teachers:dashboard') 40 | 41 | class ClassroomDeleteView(DeleteView): 42 | model = Classroom 43 | template_name = "teachers/deleteclassroom.html" 44 | 45 | # Should match the value after ':' from url 46 | slug_url_kwarg = 'code' 47 | 48 | # Should match the name of the slug field on the model 49 | slug_field = 'code' # DetailView's default value: optional 50 | 51 | def get_success_url(self): 52 | return reverse('teachers:dashboard') 53 | 54 | def ClassroomDetailView(request,code): 55 | context_dict = {} 56 | room = get_object_or_404(Classroom, code=code) 57 | context_dict['classroom'] = room 58 | return render(request, 'teachers/classroom_detail.html', context=context_dict) 59 | 60 | class SectionCreateView(CreateView): 61 | model = Section 62 | form_class = SectionForm 63 | template_name = "teachers/add_section.html" 64 | 65 | def form_valid(self, form): 66 | form.instance.classroom = get_object_or_404(Classroom, code=self.kwargs['code']) 67 | return super().form_valid(form) 68 | 69 | def get_success_url(self): 70 | return reverse('teachers:classroom_detail', kwargs={'code':self.kwargs['code']}) 71 | 72 | class SectionDeleteView(DeleteView): 73 | model = Section 74 | template_name = "teachers/delete_section.html" 75 | 76 | def get_success_url(self): 77 | return reverse('teachers:classroom_detail', kwargs={'code':self.object.classroom.code}) 78 | 79 | def ResourcesView(request, pk): 80 | context_dict = {} 81 | section = get_object_or_404(Section, pk=pk) 82 | print(section) 83 | context_dict['section'] = section 84 | return render(request, 'teachers/resources.html', context=context_dict) 85 | 86 | class ResourceCreateView(CreateView): 87 | model = Resource 88 | form_class = ResourceForm 89 | template_name = "teachers/add_resource.html" 90 | 91 | def form_valid(self, form): 92 | form.instance.section = get_object_or_404(Section, pk=self.kwargs['pk']) 93 | return super().form_valid(form) 94 | 95 | def get_success_url(self): 96 | return reverse('teachers:resources', kwargs={'pk':self.kwargs['pk']}) 97 | 98 | class ResourceDeleteView(DeleteView): 99 | model = Resource 100 | template_name = "teachers/delete_resource.html" 101 | 102 | def get_success_url(self): 103 | return reverse('teachers:resources', kwargs={'pk':self.object.section.pk}) 104 | 105 | 106 | def AssignmentsView(request, pk): 107 | context_dict = {} 108 | section = get_object_or_404(Section, pk=pk) 109 | print(section) 110 | context_dict['section'] = section 111 | return render(request, 'teachers/assignments.html', context=context_dict) 112 | 113 | 114 | class AssignmentCreateView(CreateView): 115 | model = Assignment 116 | form_class = AssignmentForm 117 | template_name = "teachers/add_assignment.html" 118 | 119 | def form_valid(self, form): 120 | form.instance.section = get_object_or_404(Section, pk=self.kwargs['pk']) 121 | return super().form_valid(form) 122 | 123 | def get_success_url(self): 124 | return reverse('teachers:assignments', kwargs={'pk':self.kwargs['pk']}) 125 | 126 | class AssignmentDeleteView(DeleteView): 127 | model = Assignment 128 | template_name = "teachers/delete_assignment.html" 129 | 130 | def get_success_url(self): 131 | return reverse('teachers:assignments', kwargs={'pk':self.object.section.pk}) 132 | 133 | def AssignmentSubmissionsView(request,pk): 134 | context_dict = {} 135 | assignment = Assignment.objects.get(pk=pk) 136 | 137 | context_dict['assignment'] = assignment 138 | context_dict['assignment_submissions'] = AssignmentSubmission.objects.filter(assignment=assignment) 139 | 140 | return render(request, template_name='teachers/submissions.html', context=context_dict) 141 | 142 | def ClassroomStudentsView(request,code): 143 | context_dict = {} 144 | classroom = get_object_or_404(Classroom, code=code) 145 | 146 | context_dict['classroom'] = classroom 147 | context_dict['classroom_students'] = classroom.students.all() 148 | 149 | return render(request, template_name='teachers/classroomstudents.html', context=context_dict) 150 | 151 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/launch.json 2 | accounts/__pycache__/__init__.cpython-39.pyc 3 | accounts/__pycache__/admin.cpython-39.pyc 4 | accounts/__pycache__/apps.cpython-39.pyc 5 | accounts/__pycache__/forms.cpython-39.pyc 6 | accounts/__pycache__/models.cpython-39.pyc 7 | accounts/__pycache__/passtests.cpython-39.pyc 8 | accounts/__pycache__/urls.cpython-39.pyc 9 | accounts/__pycache__/views.cpython-39.pyc 10 | accounts/migrations/__pycache__/__init__.cpython-39.pyc 11 | accounts/migrations/__pycache__/0001_initial.cpython-39.pyc 12 | accounts/migrations/__pycache__/0002_alter_student_current_class.cpython-39.pyc 13 | accounts/migrations/__pycache__/0003_alter_class_year.cpython-39.pyc 14 | accounts/migrations/__pycache__/0004_alter_student_classrooms.cpython-39.pyc 15 | accounts/migrations/__pycache__/0005_alter_classroom_code.cpython-39.pyc 16 | accounts/migrations/__pycache__/0006_auto_20220319_0130.cpython-39.pyc 17 | accounts/migrations/__pycache__/0007_auto_20220402_1009.cpython-39.pyc 18 | accounts/migrations/__pycache__/0008_alter_resource_title.cpython-39.pyc 19 | accounts/migrations/__pycache__/0009_alter_assignmentsubmission_file.cpython-39.pyc 20 | accounts/migrations/__init__.py 21 | accounts/migrations/0001_initial.py 22 | accounts/migrations/0002_alter_student_current_class.py 23 | accounts/migrations/0003_alter_class_year.py 24 | accounts/migrations/0004_alter_student_classrooms.py 25 | accounts/migrations/0005_alter_classroom_code.py 26 | accounts/migrations/0006_auto_20220319_0130.py 27 | accounts/migrations/0007_auto_20220402_1009.py 28 | accounts/migrations/0008_alter_resource_title.py 29 | accounts/migrations/0009_alter_assignmentsubmission_file.py 30 | media/files/assignment_submission/55zrrva4/chapter-1-asasa/assignment-1/st1/pdf/qa-question-bankpdf/qa-question-bank.pdf 31 | media/files/assignment_submission/55zrrva4/chapter-1-asasa/assignment-1/st1/svg/digitourssvg/digitours.svg 32 | media/files/assignment_submission/pmnz4czl/virtual-machines-cloud-computing/exp-1/rishim/pdf/generated-1pdf/generated-1_JYTiAGf.pdf 33 | media/files/assignment_submission/pmnz4czl/virtual-machines-cloud-computing/exp-1/rishim/pdf/generated-1pdf/generated-1.pdf 34 | media/files/assignment_submission/yhy76bt9/ip-1-ip/assip1/st1/pdf/assignment-front-page-mc-ass-1-n-2pdf/assignment-front-page-mc-ass-1-n-2_DgqOZpC.pdf 35 | media/files/assignment_submission/yhy76bt9/ip-1-ip/assip1/st1/pdf/assignment-front-page-mc-ass-1-n-2pdf/assignment-front-page-mc-ass-1-n-2_mzt8neC.pdf 36 | media/files/assignment_submission/yhy76bt9/ip-1-ip/assip1/st1/pdf/assignment-front-page-mc-ass-1-n-2pdf/assignment-front-page-mc-ass-1-n-2.pdf 37 | media/files/assignment_submission/yhy76bt9/ip-1-ip/assip1/st1/pdf/scan-2022-04-01-1107pdf/scan-2022-04-01-1107_xeHfnRb.pdf 38 | media/files/assignment_submission/yhy76bt9/ip-1-ip/assip1/st1/pdf/scan-2022-04-01-1107pdf/scan-2022-04-01-1107.pdf 39 | media/files/assignment_submission/yhy76bt9/ip-1-ip/assip1/st1/png/screenshot-2022-04-11-at-10-00-57-absolute-loaderpng/screenshot-2022-04-11-at-10-00-57-absolute-loader.png 40 | media/files/assignment_submission/yhy76bt9/ip-1-ip/new-assignment-2/st1/pdf/system-programming-and-compiler-construction-spccpdf/system-programming-and-compiler-construction-spcc_8cYNChI.pdf 41 | media/files/assignment_submission/yhy76bt9/ip-1-ip/new-assignment-2/st1/pdf/system-programming-and-compiler-construction-spccpdf/system-programming-and-compiler-construction-spcc.pdf 42 | media/files/assignment_submission/yhy76bt9/ip-1-ip/new-assignment-2/st1/png/screenshot-2022-04-11-at-10-00-57-absolute-loaderpng/screenshot-2022-04-11-at-10-00-57-absolute-loader_RqDjqxg.png 43 | media/files/assignment_submission/yhy76bt9/ip-1-ip/new-assignment-2/st1/png/screenshot-2022-04-11-at-10-00-57-absolute-loaderpng/screenshot-2022-04-11-at-10-00-57-absolute-loader.png 44 | media/files/assignments/55zrrva4/chapter-1-asasa/assignment-1/2022-04-02-0912031605740000/docx/expt-7docx/expt-7.docx 45 | media/files/assignments/55zrrva4/chapter-1-asasa/assignment1/2022-04-02-0617203783230000/docx/expt-7docx/expt-7.docx 46 | media/files/assignments/55zrrva4/chapter-1-asasa/assignment1/2022-04-02-0618074343560000/docx/expt-7docx/expt-7.docx 47 | media/files/assignments/55zrrva4/chapter-1-asasa/assignment2/2022-04-02-0618581688390000/pptx/team-meraki-sih-1-1pptx/team-meraki-sih-1-1.pptx 48 | media/files/assignments/55zrrva4/chapter-1-asasa/assignment2/2022-04-21-1123373444610000/pdf/generated-1pdf/generated-1.pdf 49 | media/files/assignments/pmnz4czl/virtual-machines-cloud-computing/exp-1/2022-04-21-1336347187860000/conf/de6a1_ch_wgconf/de6a1_ch_wg.conf 50 | media/files/assignments/yhy76bt9/ip-1-ip/new-assignment-2/2022-04-05-1805032091080000/png/2022-04-02_19-25-07-935-msedge_ucws2urw5kpng/2022-04-02_19-25-07-935-msedge_ucws2urw5k.png 51 | media/files/resources/55zrrva4/chapter-1-asasa/res1/2022-03-30-1824265869670000/json/widget_statejson/json.json 52 | media/files/resources/55zrrva4/chapter-1-asasa/res1/2022-03-30-1824265869670000/pdf/studentpdf.pdf 53 | media/files/resources/55zrrva4/chapter-1-asasa/res1/2022-04-01-1855123282940000/docx/css_lab_manualdocx/css_lab_manualdocx.docx 54 | media/files/resources/55zrrva4/chapter-1-asasa/res2/2022-03-30-1824462272620000/pdf/gopalakrishnan2017pdf/gopalakrishnan2017pdf.pdf 55 | media/files/resources/55zrrva4/chapter-1-asasa/res2/2022-03-30-1824462272620000/png/workflowpng/png.png 56 | media/files/resources/55zrrva4/chapter-1-asasa/res2/2022-03-30-1824462272620000/pptx/team-meraki-sihpptx/pptx.pptx 57 | media/files/resources/55zrrva4/chapter-1-asasa/resource-3/2022-04-01-1906412724830000/pdf/rishi_mule_resumepdf/rishi_mule_resume.pdf 58 | media/files/resources/55zrrva4/chapter-1-asasa/resource-book/2022-04-02-0742252706380000/pdf/hr_employee_attrition_analysis1pdf/hr_employee_attrition_analysis1.pdf 59 | media/files/resources/55zrrva4/section-3-asasa/pdf/2022-04-02-0915185818980000/docx/css_lab_manualdocx/css_lab_manual.docx 60 | media/files/resources/pmnz4czl/virtual-machines-cloud-computing/software-links/2022-04-21-1335299711850000/pdf/generated-1pdf/generated-1.pdf 61 | media/files/resources/yhy76bt9/ip-1-ip/resource-no-1/2022-04-05-1541339433010000/png/2022-03-28_10-17-21-044-chrome_umjivy9tgmpng/2022-03-28_10-17-21-044-chrome_umjivy9tgm.png 62 | mylms/__pycache__/__init__.cpython-39.pyc 63 | mylms/__pycache__/settings.cpython-39.pyc 64 | mylms/__pycache__/urls.cpython-39.pyc 65 | mylms/__pycache__/views.cpython-39.pyc 66 | mylms/__pycache__/wsgi.cpython-39.pyc 67 | students/__pycache__/__init__.cpython-39.pyc 68 | students/__pycache__/admin.cpython-39.pyc 69 | students/__pycache__/apps.cpython-39.pyc 70 | students/__pycache__/forms.cpython-39.pyc 71 | students/__pycache__/models.cpython-39.pyc 72 | students/__pycache__/urls.cpython-39.pyc 73 | students/__pycache__/views.cpython-39.pyc 74 | students/migrations/__init__.py 75 | students/migrations/__pycache__/__init__.cpython-39.pyc 76 | teachers/migrations/__init__.py 77 | teachers/migrations/__pycache__/__init__.cpython-39.pyc 78 | teachers/__pycache__/__init__.cpython-39.pyc 79 | teachers/__pycache__/admin.cpython-39.pyc 80 | teachers/__pycache__/apps.cpython-39.pyc 81 | teachers/__pycache__/forms.cpython-39.pyc 82 | teachers/__pycache__/models.cpython-39.pyc 83 | teachers/__pycache__/urls.cpython-39.pyc 84 | teachers/__pycache__/views.cpython-39.pyc 85 | mylms/.env 86 | mylms/__pycache__/ 87 | .gitignore 88 | -------------------------------------------------------------------------------- /students/templates/students/base.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | {% block title %}Student Dashboard{% endblock title %} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 40 |
41 |
42 | 94 | 95 | {% block content %} 96 | 97 | {% endblock content %} 98 | 99 |
100 |
101 |
102 | 105 |
106 |
107 |
108 | 109 |
110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /teachers/templates/teachers/base.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | {% block title %}Base{% endblock title %} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 40 |
41 |
42 | 96 |
97 | 98 | {% block content %} 99 | 100 | 101 | {% endblock content %} 102 |
103 | 104 |
105 |
106 |
107 | 110 |
111 |
112 |
113 | 114 |
115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import AbstractUser 3 | from django.forms import CharField 4 | from django.urls import reverse 5 | from django.utils import timezone, text 6 | from django.core.validators import MaxValueValidator, MinValueValidator 7 | import os 8 | import datetime 9 | import random 10 | import string 11 | 12 | 13 | def _(something): 14 | return something 15 | 16 | 17 | class User(AbstractUser): 18 | is_student = models.BooleanField('student status', default=False) 19 | is_teacher = models.BooleanField('teacher status', default=False) 20 | 21 | 22 | class Stream(models.Model): 23 | 24 | name = models.CharField( 25 | _("Stream Name"), 26 | max_length=250, 27 | blank=False, 28 | unique=True) 29 | 30 | class Meta: 31 | verbose_name = _("stream") 32 | verbose_name_plural = _("streams") 33 | 34 | def __str__(self): 35 | return self.name 36 | 37 | def get_absolute_url(self): 38 | return reverse("stream_detail", kwargs={"pk": self.pk}) 39 | 40 | 41 | class Class(models.Model): 42 | 43 | stream = models.ForeignKey( 44 | "Stream", 45 | on_delete=models.CASCADE, 46 | related_name="classes", 47 | blank=False) 48 | 49 | name = models.CharField( 50 | _("Class Name"), 51 | max_length=250, 52 | blank=False, 53 | unique=True) 54 | 55 | semester = models.PositiveIntegerField( 56 | blank=False, 57 | default=1, 58 | validators=[ 59 | MaxValueValidator(8), 60 | MinValueValidator(1) 61 | ] 62 | ) 63 | 64 | year = models.PositiveIntegerField( 65 | blank=False, 66 | default=2022, 67 | validators=[ 68 | MaxValueValidator(2030), 69 | MinValueValidator(2015) 70 | ] 71 | ) 72 | 73 | class Meta: 74 | verbose_name = _("class") 75 | verbose_name_plural = _("classes") 76 | 77 | def __str__(self): 78 | return self.name 79 | 80 | def get_absolute_url(self): 81 | return reverse("class_detail", kwargs={"pk": self.pk}) 82 | 83 | 84 | class Teacher(models.Model): 85 | 86 | user = models.OneToOneField( 87 | User, 88 | on_delete=models.CASCADE, 89 | primary_key=True, 90 | related_name='teachers') 91 | 92 | stream = models.ForeignKey( 93 | "Stream", 94 | on_delete=models.CASCADE, 95 | related_name="teachers", 96 | blank=False) 97 | 98 | class Meta: 99 | verbose_name = _("teacher") 100 | verbose_name_plural = _("teachers") 101 | 102 | def __str__(self): 103 | return self.user.username 104 | 105 | def get_absolute_url(self): 106 | return reverse("teacher_detail", kwargs={"pk": self.pk}) 107 | 108 | def random_string(size=8, chars=string.ascii_uppercase + string.digits): 109 | return ''.join(random.choice(chars) for _ in range(size)) 110 | 111 | class Classroom(models.Model): 112 | 113 | teacher = models.ForeignKey( 114 | "Teacher", 115 | on_delete=models.CASCADE, 116 | blank=False, 117 | related_name='classrooms') 118 | 119 | subject = models.CharField( 120 | _("Subject Name"), 121 | max_length=50, 122 | blank=False) 123 | 124 | code = models.SlugField( 125 | _("Subject Code"), 126 | max_length=10, 127 | default=random_string, 128 | unique=True) 129 | 130 | semester = models.PositiveIntegerField( 131 | blank=False, 132 | default=1, 133 | validators=[ 134 | MaxValueValidator(8), 135 | MinValueValidator(1) 136 | ] 137 | ) 138 | 139 | created_timestamp = models.DateTimeField( 140 | default=timezone.now, 141 | editable=False) 142 | 143 | class Meta: 144 | verbose_name = _("Classroom") 145 | verbose_name_plural = _("Classrooms") 146 | 147 | def __str__(self): 148 | return self.code 149 | 150 | def get_absolute_url(self): 151 | return reverse("Classroom_detail", kwargs={"pk": self.pk}) 152 | 153 | 154 | class Student(models.Model): 155 | 156 | user = models.OneToOneField( 157 | User, 158 | on_delete=models.CASCADE, 159 | primary_key=True, 160 | related_name='students') 161 | 162 | current_class = models.ForeignKey( 163 | "Class", 164 | verbose_name=_("Class"), 165 | on_delete=models.CASCADE, 166 | blank=False, 167 | related_name='students') 168 | 169 | roll_no = models.PositiveIntegerField( 170 | _("Roll No."), 171 | blank=False) 172 | 173 | student_id = models.CharField( 174 | _("Student ID"), 175 | max_length=50, 176 | blank=False, 177 | unique=True) 178 | 179 | classrooms = models.ManyToManyField("Classroom", related_name='students', blank=True) 180 | 181 | class Meta: 182 | verbose_name = _("student") 183 | verbose_name_plural = _("students") 184 | unique_together = ('roll_no', 'current_class') 185 | 186 | def __str__(self): 187 | return self.user.username 188 | 189 | def get_absolute_url(self): 190 | return reverse("Student_detail", kwargs={"pk": self.pk}) 191 | 192 | 193 | class Section(models.Model): 194 | 195 | classroom = models.ForeignKey( 196 | "Classroom", 197 | on_delete=models.CASCADE, 198 | blank=False, 199 | related_name='sections') 200 | 201 | title = models.CharField( 202 | _("section title"), 203 | max_length=150) 204 | 205 | created_timestamp = models.DateTimeField( 206 | default=timezone.now, 207 | editable=False 208 | ) 209 | 210 | class Meta: 211 | verbose_name = _("section") 212 | verbose_name_plural = _("sections") 213 | 214 | def __str__(self): 215 | return f'{self.title} -> {self.classroom.subject}' 216 | 217 | def get_absolute_url(self): 218 | return reverse("section_detail", kwargs={"pk": self.pk}) 219 | 220 | 221 | def resource_rename_upload_file(instance, filename): 222 | ogfilename = filename.rsplit('.', 1)[0] 223 | ext = filename.split('.')[-1] 224 | filename = f'{text.slugify(instance.section.classroom)}/{text.slugify(instance.section)}/{text.slugify(instance.title)}/{text.slugify(instance.created_timestamp)}/{text.slugify(ext)}/{text.slugify(filename)}/{text.slugify(ogfilename)}.{text.slugify(ext)}' 225 | print(filename) 226 | return os.path.join('files/resources/', filename) 227 | 228 | 229 | class Resource(models.Model): 230 | 231 | title = models.CharField( 232 | _("resource title"), 233 | max_length=150) 234 | 235 | created_timestamp = models.DateTimeField( 236 | default=timezone.now, 237 | editable=False 238 | ) 239 | 240 | text = models.TextField() 241 | 242 | section = models.ForeignKey( 243 | "Section", 244 | on_delete=models.CASCADE, 245 | related_name='resources', 246 | blank=False) 247 | 248 | file = models.FileField( 249 | upload_to=resource_rename_upload_file, 250 | blank=True, 251 | max_length=999) 252 | 253 | class Meta: 254 | verbose_name = _("resource") 255 | verbose_name_plural = _("resources") 256 | 257 | def __str__(self): 258 | return self.title 259 | 260 | def get_absolute_url(self): 261 | return reverse("resource_detail", kwargs={"pk": self.pk}) 262 | 263 | 264 | def assignment_rename_upload_file(instance, filename): 265 | ogfilename = filename.rsplit('.', 1)[0] 266 | ext = filename.split('.')[-1] 267 | filename = f'{text.slugify(instance.section.classroom)}/{text.slugify(instance.section)}/{text.slugify(instance.title)}/{text.slugify(instance.created_timestamp)}/{text.slugify(ext)}/{text.slugify(filename)}/{text.slugify(ogfilename)}.{text.slugify(ext)}' 268 | print(filename) 269 | return os.path.join('files/assignments/', filename) 270 | 271 | 272 | class Assignment(models.Model): 273 | 274 | title = models.CharField( 275 | _("section title"), 276 | max_length=150) 277 | 278 | section = models.ForeignKey( 279 | "Section", 280 | on_delete=models.CASCADE, 281 | related_name='assignments', 282 | blank=False) 283 | 284 | text = models.TextField() 285 | 286 | created_timestamp = models.DateTimeField( 287 | default=timezone.now, 288 | editable=False 289 | ) 290 | 291 | deadline = models.DateTimeField( 292 | default=timezone.now, 293 | blank=False 294 | ) 295 | 296 | file = models.FileField( 297 | upload_to=assignment_rename_upload_file, 298 | blank=True, 299 | max_length=999) 300 | 301 | class Meta: 302 | verbose_name = _("assignment") 303 | verbose_name_plural = _("assignments") 304 | 305 | def __str__(self): 306 | return self.title 307 | 308 | def get_absolute_url(self): 309 | return reverse("assignment_detail", kwargs={"pk": self.pk}) 310 | 311 | 312 | def submission_rename_upload_file(instance, filename): 313 | ogfilename = filename.rsplit('.', 1)[0] 314 | ext = filename.split('.')[-1] 315 | filename = f'{text.slugify(instance.assignment.section.classroom)}/{text.slugify(instance.assignment.section)}/{text.slugify(instance.assignment.title)}/{text.slugify(instance.student)}/{text.slugify(ext)}/{text.slugify(filename)}/{text.slugify(ogfilename)}.{text.slugify(ext)}' 316 | print(filename) 317 | return os.path.join('files/assignment_submission/', filename) 318 | 319 | 320 | 321 | class AssignmentSubmission(models.Model): 322 | 323 | student = models.ForeignKey( 324 | "Student", 325 | verbose_name=_("Submitted by"), 326 | on_delete=models.CASCADE, 327 | related_name='assignment_submissions', 328 | blank=False) 329 | 330 | assignment = models.ForeignKey( 331 | "Assignment", 332 | on_delete=models.CASCADE, 333 | related_name='assignment_submissions', 334 | blank=False) 335 | 336 | file = models.FileField( 337 | upload_to=submission_rename_upload_file, 338 | blank=False, 339 | max_length=999) 340 | 341 | submission_timestamp = models.DateTimeField( 342 | default=timezone.now, 343 | editable=False 344 | ) 345 | 346 | class Meta: 347 | verbose_name = _("assignmentsubmission") 348 | verbose_name_plural = _("assignmentsubmissions") 349 | unique_together = ('student', 'assignment') 350 | 351 | def __str__(self): 352 | return f'{self.assignment} -> {self.student}' 353 | 354 | def get_absolute_url(self): 355 | return reverse("assignmentsubmission_detail", kwargs={"pk": self.pk}) 356 | 357 | --------------------------------------------------------------------------------