From 55a65d38d9bfd461a05f93e157b1fbed03783e80 Mon Sep 17 00:00:00 2001 From: Nathaniel Kenschaft Date: Sun, 14 Jun 2020 18:59:54 -0400 Subject: [PATCH 01/21] more work on daemonizing background service --- BackgroundService/bgservice.py | 2 -- BackgroundService/event_processor2.py | 52 +++++++++++++++++++++++++++ requirements.txt | 34 ++++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 BackgroundService/event_processor2.py diff --git a/BackgroundService/bgservice.py b/BackgroundService/bgservice.py index ed26c76..c2a81e9 100644 --- a/BackgroundService/bgservice.py +++ b/BackgroundService/bgservice.py @@ -40,8 +40,6 @@ class SkoolOSDaemon: time.strftime("%H:%M:%S", time.gmtime(self.end_time - self.start_time))) - - logger = None def Main(): diff --git a/BackgroundService/event_processor2.py b/BackgroundService/event_processor2.py new file mode 100644 index 0000000..f3f9a0b --- /dev/null +++ b/BackgroundService/event_processor2.py @@ -0,0 +1,52 @@ +import pyinotify + +wm = pyinotify.WatchManager() +mask = pyinotify.IN_CREATE | pyinotify.IN_CLOSE_WRITE | pyinotify.IN_DELETE | \ + pyinotify.IN_MOVED_TO | pyinotify.IN_MOVED_FROM | pyinotify.IN_OPEN + +class EventHandler(pyinotify.ProcessEvent): + _methods = ["IN_CREATE", + "IN_CLOSE_WRITE", + "IN_DELETE", + "IN_MOVED_TO", + "IN_MOVED_FROM", + "IN_OPEN", + ] + def __process_generator(self, event): + description = \ + "Event: {}\n" \ + "Event Path: {}\n" \ + "Timestamp: {}\n".format( + method, + event.pathname, + time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime()) + ) + if "IN_DELETE" in description: + description += "WARNING: Unexpected file deletion\n" + if "IN_MOVED_TO" in description: + description += "WARNING: Unexpected file add to work\n" + if "IN_MOVED_FROM" in description: + description += "WARNING: Unexpected file moved out of directory\n" + return description + + def process_IN_CREATE(self, event): + self.__process_generator(event) + def process_IN_CLOSE_WRITE(self, event): + self.__process_generator(event) + def process_IN_DELETE(self, event): + self.__process_generator(event) + def process_IN_MOVED_TO(self, event): + self.__process_generator(event) + def process_IN_MOVED_FROM(self, event): + self.__process_generator(event) + def process_IN_OPEN(self, event): + self.__process_generator(event) + + +notifier = pyinotify.ThreadedNotifier(wm, EventHandler()) +notifier.start() + +wdd = wm.add_watch('/tmp', mask, rec=True) +input("Press any key to continue...") + +notifier.stop() diff --git a/requirements.txt b/requirements.txt index 9a6e972..ceb2027 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,27 +1,61 @@ +appdirs==1.4.3 +arandr==0.1.10 asgiref==3.2.7 +astroid==2.4.2 +CacheControl==0.12.6 certifi==2020.4.5.1 chardet==3.0.4 click==7.1.2 +colorama==0.4.3 +contextlib2==0.6.0 +distlib==0.3.0 +distro==1.4.0 Django==3.0.7 django-cors-middleware==1.5.0 django-crispy-forms==1.9.1 django-oauth-toolkit==1.3.2 djangorestframework==3.11.0 +greenlet==0.4.16 +html5lib==1.0.1 idna==2.9 +isort==4.3.21 +lazy-object-proxy==1.4.3 +mccabe==0.6.1 +meson==0.53.2 +msgpack==0.6.2 oauthlib==3.1.0 +ordered-set==3.1.1 +packaging==20.1 +pep517==0.8.1 +Pillow==7.1.2 +progress==1.5 prompt-toolkit==1.0.14 +pulsemixer==1.5.0 +pycairo==1.19.1 pyclipper==1.1.0.post3 Pygments==2.6.1 +PyGObject==3.34.0 pyinotify==0.9.6 PyInquirer==1.0.3 +pylint==2.5.3 +pynvim==0.4.1 +pyparsing==2.4.6 pyperclip==1.8.0 +pytoml==0.1.21 pytz==2020.1 +pywal==3.3.0 regex==2020.5.14 requests==2.23.0 requests-oauthlib==1.3.0 +retrying==1.3.3 selenium==3.141.0 six==1.15.0 sqlparse==0.3.1 +team==1.0 +toml==0.10.0 urllib3==1.25.9 wcwidth==0.2.3 +webencodings==0.5.1 Werkzeug==1.0.1 +wpgtk==6.1.3 +wrapt==1.12.1 From c59890628d53978aafd56bb93ba9c8c9e13b58c3 Mon Sep 17 00:00:00 2001 From: Raffu Khondaker <2022rkhondak@tjhsst.edu> Date: Sun, 14 Jun 2020 20:32:48 -0400 Subject: [PATCH 02/21] authorization --- CLI/oauth/index.html | 23 ------- Website/api/serializers.py | 2 +- skoolos.py | 129 +++++++++++++++++++++++-------------- 3 files changed, 81 insertions(+), 73 deletions(-) delete mode 100644 CLI/oauth/index.html diff --git a/CLI/oauth/index.html b/CLI/oauth/index.html deleted file mode 100644 index 9ffd6ef..0000000 --- a/CLI/oauth/index.html +++ /dev/null @@ -1,23 +0,0 @@ - - - Sign into Ion - - - - - - -
- - - Sign in with Ion - -
- - \ No newline at end of file diff --git a/Website/api/serializers.py b/Website/api/serializers.py index 2a05750..2904a07 100644 --- a/Website/api/serializers.py +++ b/Website/api/serializers.py @@ -42,7 +42,7 @@ class StudentSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Student # fields = ['url','first_name', 'last_name', 'grade','email','student_id', 'git','ion_user','classes','added_to','completed', 'repo','owner'] - fields = ['first_name', 'last_name', 'grade','email','student_id', 'git','ion_user','classes','added_to','completed', 'repo','owner'] + fields = ['grade','email','student_id', 'git','ion_user','classes','added_to','completed', 'repo','owner'] class TeacherSerializer(serializers.ModelSerializer): # classes = ClassesSerializer(many=True, read_only=True,allow_null=True) diff --git a/skoolos.py b/skoolos.py index f95da87..a802814 100644 --- a/skoolos.py +++ b/skoolos.py @@ -14,6 +14,7 @@ from PyInquirer import prompt, print_json import json import os import argparse +import webbrowser client_id = r'QeZPBSKqdvWFfBv1VYTSv9iFGz5T9pVJtNUjbEr6' client_secret = r'0Wl3hAIGY9SvYOqTOLUiLNYa4OlCgZYdno9ZbcgCT7RGQ8x2f1l2HzZHsQ7ijC74A0mrOhhCVeZugqAmOADHIv5fHxaa7GqFNtQr11HX9ySTw3DscKsphCVi5P71mlGY' @@ -34,31 +35,31 @@ def main(): print("") if not os.path.exists(".profile"): - try: - URL = "http://127.0.0.1:8000/api/" - r = requests.get(url = URL, auth=('raffukhondaker','hackgroup1')) - print("End service at http://127.0.0.1:8000/ before continuing.") - sys.exit(0) - except: - pass + # try: + # URL = "http://127.0.0.1:8000/api/" + # r = requests.get(url = URL) + # print("Stop any processes running on http://127.0.0.1:8000/ before continuing") + # except: + # pass input("Welcome to SkoolOS. Press any key to create an account") + #webbrowser.open("http://127.0.0.1:8000/login", new=2) authenticate() - else: - try: - URL = "http://127.0.0.1:8000/api/" - r = requests.get(url = URL, auth=('raffukhondaker','hackgroup1')) - except: - print("Start Django server first") - sys.exit(0) - f = open('.profile','r') - data = json.loads(f.read()) - f.close() - PWD = data['password'] - USER = data['username'] - if(data['is_student']): - studentCLI() - else: - teacherCLI() + # else: + # try: + # URL = "http://127.0.0.1:8000/api/" + # f = open('.profile','r') + # data = json.loads(f.read()) + # f.close() + # PWD = data['password'] + # USER = data['username'] + # r = requests.get(url = URL, auth=(USER,PWD)) + # except: + # print("Incorrect password.") + # sys.exit(0) + # if(data['is_student']): + # studentCLI() + # else: + # teacherCLI() @@ -152,40 +153,70 @@ def authenticate(): path = os.path.join(os.getcwd(), 'chromedriver-mac') browser = webdriver.Chrome(path) - web_dir = os.path.join(os.getcwd(), 'CLI', 'oauth') - print(web_dir) - os.chdir(web_dir) - if os.path.exists("index.html"): - os.remove("index.html") + # web_dir = os.path.join(os.getcwd(), 'CLI', 'oauth') + # print(web_dir) + # os.chdir(web_dir) + # if os.path.exists("index.html"): + # os.remove("index.html") - template = open("template.html", "r") - index = open("index.html", "w") - for line in template: - index.write(line.replace('AUTH_URL', authorization_url)) - template.close() - index.close() + # template = open("template.html", "r") + # index = open("index.html", "w") + # for line in template: + # index.write(line.replace('AUTH_URL', authorization_url)) + # template.close() + # index.close() - server = Thread(target=create_server) - server.daemon = True - server.start() + # server = Thread(target=create_server) + # server.daemon = True + # server.start() - browser.get("localhost:8000/") + browser.get("localhost:8000/login") - while "http://localhost:8000/callback/?code" not in browser.current_url: + # while "http://localhost:8000/callback/?code" not in browser.current_url: + # time.sleep(0.25) + + url = browser.current_url + gets = url_decode(url.replace("http://localhost:8000/login/?", "")) + while "http://localhost:8000/login/?username=" not in browser.current_url and (not browser.current_url == "http://localhost:8000/"): #http://localhost:8000/ time.sleep(0.25) url = browser.current_url - gets = url_decode(url.replace("http://localhost:8000/callback/?", "")) - while "http://localhost:8000/callback/?code" not in browser.current_url: - time.sleep(0.25) - - url = browser.current_url - gets = url_decode(url.replace("http://localhost:8000/callback/?", "")) - code = gets.get("code") - if state == gets.get("state"): - state = gets.get("state") - print("states good") + gets = url_decode(url.replace("http://localhost:8000/login/?username=", "")) + # code = gets.get("code") + # if state == gets.get("state"): + # state = gets.get("state") + # print("states good") browser.quit() + questions = [ + { + 'type': 'input', + 'name': 'username', + 'message': 'Enter SkoolOS Username (Same as ION Username): ', + }, + { + 'type': 'password', + 'name': 'pwd', + 'message': 'Enter SkoolOS Password (NOT ION PASSWORD): ', + }, + ] + data =prompt(questions) + pwd = data['pwd'] + user = data['username'] + r = requests.get(url = "http://localhost:8000/api/", auth=(user,pwd)) + while(r.status_code != 200): + print("INCORRECT LOGIN CREDENTIALS") + r = requests.get(url = "http://localhost:8000/api/", auth=(user,pwd)) + data =prompt(questions) + pwd = data['pwd'] + user = data['username'] + print(r.status_code) + r = requests.get(url = "http://localhost:8000/students/" + user + "/", auth=(user,pwd)) + is_student = False + if(r.status_code == 200): + is_student = True + print("Welcome, student " + user) + else: + print("Welcome, teacher " + user) #print(code) print(state) From db50da3d4256847091b1e9639bde943facce1ec8 Mon Sep 17 00:00:00 2001 From: Nathaniel Kenschaft Date: Sun, 14 Jun 2020 22:54:11 -0400 Subject: [PATCH 03/21] simplified and finalized background service --- BackgroundService/bgservice.py | 144 +++++++++++++++++--------- BackgroundService/event_processor.py | 65 ------------ BackgroundService/event_processor2.py | 52 ---------- BackgroundService/test.py | 19 ---- 4 files changed, 95 insertions(+), 185 deletions(-) delete mode 100644 BackgroundService/event_processor.py delete mode 100644 BackgroundService/event_processor2.py delete mode 100644 BackgroundService/test.py diff --git a/BackgroundService/bgservice.py b/BackgroundService/bgservice.py index c2a81e9..e2c4411 100644 --- a/BackgroundService/bgservice.py +++ b/BackgroundService/bgservice.py @@ -1,56 +1,102 @@ -import os -import sys -import signal import time -import event_processor +import sys +import os +import pyinotify -class SkoolOSDaemon: - """Constructor""" - def __init__(self, work_dir='/tmp'): - self.work_dir = work_dir - self.start_time = None - self.end_time = None - self.log_file = None - def __write_pid_file(self): - try: - dirName = "/tmp/skooloslogs" - # Create log Directory - os.mkdir(dirName) - except FileExistsError: - pass - pid = str(os.getpid()) - file_ = open('/tmp/skoolosdaemonpid', 'w') - file_.write(pid) - file_.close() - def readable_time(self, input_time): - return time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime(input_time)) - def start(self): - self.__write_pid_file() - self.start_time = time.time() - self.log_file = open('/tmp/skooloslogs/' + str(self.start_time), 'w') - self.log_file.write("Start time: \n" + self.readable_time(self.start_time) + "\n\n") - sys.stdout = self.log_file - event_processor.watch_dir(self.work_dir) - def stop(self): - event_processor.stop_watching() - self.end_time = time.time() - self.log_file.write("Stop time: \n" + self.readable_time(self.end_time)) - self.log_file.write("Total work time: " + - time.strftime("%H:%M:%S", time.gmtime(self.end_time - self.start_time))) +class EventHandler(pyinotify.ProcessEvent): + _methods = [ + "IN_CREATE", + "IN_CLOSE_WRITE", + "IN_DELETE", + "IN_MOVED_TO", + "IN_MOVED_FROM", + "IN_OPEN", + ] + + def process_IN_CREATE(self, event): + description = \ + "Event: Created file\n" \ + "Event Path: {}\n" \ + "Timestamp: {}\n".format( + event.pathname, + time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime()) + ) + print(description) + + def process_IN_CLOSE_WRITE(self, event): + description = \ + "Event: Wrote to a file\n" \ + "Event Path: {}\n" \ + "Timestamp: {}\n".format( + event.pathname, + time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime()) + ) + print(description) + + def process_IN_DELETE(self, event): + description = \ + "Event: Deleted file\n" \ + "Event Path: {}\n" \ + "Timestamp: {}\n".format( + event.pathname, + time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime()) + ) + print(description) + + def process_IN_MOVED_TO(self, event): + description = \ + "Event: Moved a file in\n" \ + "Event Path: {}\n" \ + "Timestamp: {}\n".format( + event.pathname, + time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime()) + ) + print(description) + + def process_IN_MOVED_FROM(self, event): + description = \ + "Event: Moved a file out\n" \ + "Event Path: {}\n" \ + "Timestamp: {}\n".format( + event.pathname, + time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime()) + ) + print(description) + + def process_IN_OPEN(self, event): + description = \ + "Event: Opened file\n" \ + "Event Path: {}\n" \ + "Timestamp: {}\n".format( + event.pathname, + time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime()) + ) + print(description) -logger = None - -def Main(): - def signal_handler(signum, frame): - logger.stop() - signal.signal(signal.SIGINT, signal_handler) - # signal.signal(signal.SIGTERM, signal_handler) - global logger - logger = SkoolOSDaemon("/tmp") - logger.start() +NOTIFIER = None -if __name__ == "__main__": - Main() +def watch_dir(watched_dir="/tmp", logdir="/tmp/skooloslogs"): + if not os.path.exists(logdir): + os.makedirs(logdir) + logfile = open( + logdir + "skoolos_" + time.strftime("%m%d%Y-%H%M%S", time.localtime()), + 'w') + sys.stdout = logfile + print("Start time: " + + time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime()) + "\n\n") + global NOTIFIER + wm = pyinotify.WatchManager() + mask = pyinotify.IN_CREATE | pyinotify.IN_CLOSE_WRITE | pyinotify.IN_DELETE | \ + pyinotify.IN_MOVED_TO | pyinotify.IN_MOVED_FROM | pyinotify.IN_OPEN + NOTIFIER = pyinotify.ThreadedNotifier(wm, EventHandler()) + NOTIFIER.start() + wm.add_watch(watched_dir, mask, rec=True) + + +def stop_watching(): + NOTIFIER.stop() + print("End time: " + + time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime()) + "\n\n") diff --git a/BackgroundService/event_processor.py b/BackgroundService/event_processor.py deleted file mode 100644 index 55c5e15..0000000 --- a/BackgroundService/event_processor.py +++ /dev/null @@ -1,65 +0,0 @@ -import time -import pyinotify - - -def readable_time(input_time): - return time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime(input_time)) - - -class EventProcessor(pyinotify.ProcessEvent): - _methods = ["IN_OPEN", - "IN_CREATE", - "IN_CLOSE_WRITE", - "IN_DELETE", - "IN_MOVED_TO", - "IN_MOVED_FROM", - ] - - -def __method_format(method): - return { - "IN_OPEN":"Opened a file", - "IN_CREATE":"Created a file", - "IN_CLOSE_WRITE":"Wrote to a file", - "IN_DELETE":"Deleted a file", - "IN_MOVED_TO":"Moved a file or directory in from elsewhere", - "IN_MOVED_FROM":"Moved a file or directory elsewhere", - }.get(method, "Unknown event") - - -def __process_generator(cls, method): - def _method_name(self, event): - description = "Event description: {}\n" \ - "Path name: {}\n" \ - "Event Name: {}\n" \ - "Timestamp: {}\n".format(__method_format(method), - event.pathname, - event.maskname, - readable_time(time.time()) - ) - if "IN_DELETE" in description: - description += "WARNING: Unexpected file deletion\n" - if "IN_MOVED_TO" in description: - description += "WARNING: Unexpected file add to work\n" - if "IN_MOVED_FROM" in description: - description += "WARNING: Unexpected file moved out of directory\n" - print(description) - _method_name.__name__ = "process_{}".format(method) - setattr(cls, _method_name.__name__, _method_name) - - -EVENT_NOTIFIER = None - - -def watch_dir(dir_to_watch): - global EVENT_NOTIFIER - for method in EventProcessor._methods: - __process_generator(EventProcessor, method) - watch_manager = pyinotify.WatchManager() - EVENT_NOTIFIER = pyinotify.ThreadedNotifier(watch_manager, EventProcessor()) - watch_manager.add_watch(dir_to_watch, pyinotify.ALL_EVENTS, rec=True) - EVENT_NOTIFIER.loop() - - -def stop_watching(): - EVENT_NOTIFIER.stop() diff --git a/BackgroundService/event_processor2.py b/BackgroundService/event_processor2.py deleted file mode 100644 index f3f9a0b..0000000 --- a/BackgroundService/event_processor2.py +++ /dev/null @@ -1,52 +0,0 @@ -import pyinotify - -wm = pyinotify.WatchManager() -mask = pyinotify.IN_CREATE | pyinotify.IN_CLOSE_WRITE | pyinotify.IN_DELETE | \ - pyinotify.IN_MOVED_TO | pyinotify.IN_MOVED_FROM | pyinotify.IN_OPEN - -class EventHandler(pyinotify.ProcessEvent): - _methods = ["IN_CREATE", - "IN_CLOSE_WRITE", - "IN_DELETE", - "IN_MOVED_TO", - "IN_MOVED_FROM", - "IN_OPEN", - ] - def __process_generator(self, event): - description = \ - "Event: {}\n" \ - "Event Path: {}\n" \ - "Timestamp: {}\n".format( - method, - event.pathname, - time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime()) - ) - if "IN_DELETE" in description: - description += "WARNING: Unexpected file deletion\n" - if "IN_MOVED_TO" in description: - description += "WARNING: Unexpected file add to work\n" - if "IN_MOVED_FROM" in description: - description += "WARNING: Unexpected file moved out of directory\n" - return description - - def process_IN_CREATE(self, event): - self.__process_generator(event) - def process_IN_CLOSE_WRITE(self, event): - self.__process_generator(event) - def process_IN_DELETE(self, event): - self.__process_generator(event) - def process_IN_MOVED_TO(self, event): - self.__process_generator(event) - def process_IN_MOVED_FROM(self, event): - self.__process_generator(event) - def process_IN_OPEN(self, event): - self.__process_generator(event) - - -notifier = pyinotify.ThreadedNotifier(wm, EventHandler()) -notifier.start() - -wdd = wm.add_watch('/tmp', mask, rec=True) -input("Press any key to continue...") - -notifier.stop() diff --git a/BackgroundService/test.py b/BackgroundService/test.py deleted file mode 100644 index b797228..0000000 --- a/BackgroundService/test.py +++ /dev/null @@ -1,19 +0,0 @@ -from bgservice import SkoolOSDaemon as sod -import threading - -logger = sod() - - -if __name__ == "__main__": - line=1 - print(line) - line+=1 - logger.start() - print(line) - line+=1 - input("Enter any key when you are done modifyng the /tmp/ directory") - print(line) - line+=1 - logger.stop() - print(line) - line+=1 From 8e6f6ebf25c3cfba26890882f123c6d573f96ed0 Mon Sep 17 00:00:00 2001 From: rushilwiz Date: Sun, 14 Jun 2020 23:08:28 -0400 Subject: [PATCH 04/21] Basic interface created --- Website/api/admin.py | 4 +- Website/api/maker.py | 16 +-- Website/api/migrations/0001_initial.py | 44 ++++---- .../api/migrations/0002_auto_20200614_2034.py | 52 --------- .../api/migrations/0002_auto_20200615_0046.py | 31 ++++++ .../api/migrations/0003_auto_20200614_2044.py | 43 -------- .../api/migrations/0003_auto_20200615_0233.py | 18 ++++ .../api/migrations/0004_auto_20200614_2107.py | 18 ---- .../api/migrations/0004_auto_20200615_0255.py | 22 ++++ Website/api/models.py | 100 ++++++++++-------- Website/api/serializers.py | 28 +++-- Website/api/urls.py | 6 +- Website/api/views.py | 22 ++-- Website/config/urls.py | 2 +- Website/skoolos/static/skoolos/styles.css | 68 +----------- Website/skoolos/static/skoolos/tj_trans.png | Bin 0 -> 4322 bytes Website/skoolos/templates/skoolos/base.html | 4 +- Website/skoolos/templates/skoolos/home.html | 12 +++ Website/skoolos/views.py | 14 +++ Website/users/views.py | 2 +- 20 files changed, 218 insertions(+), 288 deletions(-) delete mode 100644 Website/api/migrations/0002_auto_20200614_2034.py create mode 100644 Website/api/migrations/0002_auto_20200615_0046.py delete mode 100644 Website/api/migrations/0003_auto_20200614_2044.py create mode 100644 Website/api/migrations/0003_auto_20200615_0233.py delete mode 100644 Website/api/migrations/0004_auto_20200614_2107.py create mode 100644 Website/api/migrations/0004_auto_20200615_0255.py create mode 100644 Website/skoolos/static/skoolos/tj_trans.png diff --git a/Website/api/admin.py b/Website/api/admin.py index 8446cf4..5f8cd8c 100644 --- a/Website/api/admin.py +++ b/Website/api/admin.py @@ -2,7 +2,7 @@ from django.contrib import admin from .models import ( DefFiles, Assignment, - Classes, + Class, Teacher, Student ) @@ -13,4 +13,4 @@ admin.site.register(Teacher) admin.site.register(Student) admin.site.register(DefFiles) admin.site.register(Assignment) -admin.site.register(Classes) +admin.site.register(Class) diff --git a/Website/api/maker.py b/Website/api/maker.py index fb383ed..0f0b07f 100644 --- a/Website/api/maker.py +++ b/Website/api/maker.py @@ -30,7 +30,7 @@ # # #################################### # -# from api.models import Assignment, Student, Classes, Teacher, DefFiles +# from api.models import Assignment, Student, Class, Teacher, DefFiles # from datetime import datetime # # f1 = DefFiles( @@ -76,8 +76,8 @@ # A3.files.add(f4) # A3.save() # -# #classes -# math = Classes( +# #Class +# math = Class( # name='Math5', # # ) @@ -86,7 +86,7 @@ # math.assignments.add(A2) # math.save() # -# english = Classes( +# english = Class( # name='English', # ) # english.save() @@ -104,8 +104,8 @@ # repo="https://github.com/therealraffi/2022rkhondak.git", # ) # raffu.save() -# raffu.classes.add(math) -# raffu.classes.add(english) +# raffu.Class.add(math) +# raffu.Class.add(english) # raffu.save() # # #teachers @@ -115,7 +115,7 @@ # ion_user="eharris1" # ) # ng.save() -# ng.classes.add(math) +# ng.Class.add(math) # ng.save() # # chao = Teacher( @@ -124,5 +124,5 @@ # ion_user="AKBailey" # ) # chao.save() -# chao.classes.add(english) +# chao.Class.add(english) # chao.save() diff --git a/Website/api/migrations/0001_initial.py b/Website/api/migrations/0001_initial.py index 96b239b..428a21e 100644 --- a/Website/api/migrations/0001_initial.py +++ b/Website/api/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.7 on 2020-06-14 19:14 +# Generated by Django 3.0.7 on 2020-06-14 23:00 from django.conf import settings from django.db import migrations, models @@ -14,6 +14,19 @@ class Migration(migrations.Migration): ] operations = [ + migrations.CreateModel( + name='Class', + fields=[ + ('name', models.CharField(max_length=100, primary_key=True, serialize=False)), + ('description', models.CharField(default='Class Description', max_length=500)), + ('repo', models.URLField(blank=True, default='')), + ('path', models.CharField(default='', max_length=100)), + ('assignments', models.TextField(blank=True, default='')), + ('default_file', models.CharField(blank=True, default='', max_length=100)), + ('confirmed', models.TextField(blank=True, default='')), + ('unconfirmed', models.TextField(blank=True, default='')), + ], + ), migrations.CreateModel( name='DefFiles', fields=[ @@ -28,13 +41,9 @@ class Migration(migrations.Migration): migrations.CreateModel( name='Teacher', fields=[ - ('created', models.DateTimeField(auto_now_add=True)), - ('first_name', models.CharField(max_length=100)), - ('last_name', models.CharField(max_length=100)), - ('classes', models.CharField(blank=True, default='', max_length=100)), - ('ion_user', models.CharField(max_length=100, primary_key=True, serialize=False)), - ('git', models.CharField(max_length=100)), - ('email', models.CharField(blank=True, default='', max_length=100)), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('git', models.CharField(blank=True, default='', max_length=100)), + ('classes', models.ManyToManyField(to='api.Class')), ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], ), @@ -42,21 +51,12 @@ class Migration(migrations.Migration): name='Student', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('website', models.CharField(blank=True, default='https://google.com', max_length=150)), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.CreateModel( - name='Classes', - fields=[ - ('name', models.CharField(max_length=100, primary_key=True, serialize=False)), + ('grade', models.IntegerField(blank=True, default=0)), + ('git', models.CharField(blank=True, default='', max_length=100)), ('repo', models.URLField(blank=True, default='')), - ('path', models.CharField(default='', max_length=100)), - ('teacher', models.CharField(default='', max_length=100)), - ('assignments', models.TextField(blank=True, default='')), - ('default_file', models.CharField(blank=True, default='', max_length=100)), - ('confirmed', models.TextField(blank=True, default='')), - ('unconfirmed', models.TextField(blank=True, default='')), + ('classes', models.CharField(blank=True, default='', max_length=100)), + ('added_to', models.CharField(blank=True, default='', max_length=100)), + ('completed', models.TextField(blank=True, default='')), ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], ), diff --git a/Website/api/migrations/0002_auto_20200614_2034.py b/Website/api/migrations/0002_auto_20200614_2034.py deleted file mode 100644 index f6c6f87..0000000 --- a/Website/api/migrations/0002_auto_20200614_2034.py +++ /dev/null @@ -1,52 +0,0 @@ -# Generated by Django 3.0.7 on 2020-06-14 20:34 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('api', '0001_initial'), - ] - - operations = [ - migrations.RemoveField( - model_name='student', - name='website', - ), - migrations.AddField( - model_name='student', - name='added_to', - field=models.CharField(blank=True, default='', max_length=100), - ), - migrations.AddField( - model_name='student', - name='classes', - field=models.CharField(blank=True, default='', max_length=100), - ), - migrations.AddField( - model_name='student', - name='completed', - field=models.TextField(blank=True, default=''), - ), - migrations.AddField( - model_name='student', - name='git', - field=models.CharField(blank=True, default='https://github.com/', max_length=100), - ), - migrations.AddField( - model_name='student', - name='grade', - field=models.IntegerField(blank=True, default=9), - ), - migrations.AddField( - model_name='student', - name='repo', - field=models.URLField(blank=True, default=''), - ), - migrations.AddField( - model_name='student', - name='student_id', - field=models.IntegerField(blank=True, default=0), - ), - ] diff --git a/Website/api/migrations/0002_auto_20200615_0046.py b/Website/api/migrations/0002_auto_20200615_0046.py new file mode 100644 index 0000000..94bb36e --- /dev/null +++ b/Website/api/migrations/0002_auto_20200615_0046.py @@ -0,0 +1,31 @@ +# Generated by Django 3.0.7 on 2020-06-15 00:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='class', + name='confirmed', + ), + migrations.AddField( + model_name='class', + name='confirmed', + field=models.ManyToManyField(blank=True, related_name='confirmed', to='api.Student'), + ), + migrations.RemoveField( + model_name='class', + name='unconfirmed', + ), + migrations.AddField( + model_name='class', + name='unconfirmed', + field=models.ManyToManyField(blank=True, related_name='unconfirmed', to='api.Student'), + ), + ] diff --git a/Website/api/migrations/0003_auto_20200614_2044.py b/Website/api/migrations/0003_auto_20200614_2044.py deleted file mode 100644 index d5a7a69..0000000 --- a/Website/api/migrations/0003_auto_20200614_2044.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 3.0.7 on 2020-06-14 20:44 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('api', '0002_auto_20200614_2034'), - ] - - operations = [ - migrations.RemoveField( - model_name='student', - name='student_id', - ), - migrations.RemoveField( - model_name='teacher', - name='created', - ), - migrations.RemoveField( - model_name='teacher', - name='email', - ), - migrations.RemoveField( - model_name='teacher', - name='first_name', - ), - migrations.RemoveField( - model_name='teacher', - name='last_name', - ), - migrations.AlterField( - model_name='student', - name='git', - field=models.CharField(blank=True, default='', max_length=100), - ), - migrations.AlterField( - model_name='student', - name='grade', - field=models.IntegerField(blank=True), - ), - ] diff --git a/Website/api/migrations/0003_auto_20200615_0233.py b/Website/api/migrations/0003_auto_20200615_0233.py new file mode 100644 index 0000000..031aa1a --- /dev/null +++ b/Website/api/migrations/0003_auto_20200615_0233.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.7 on 2020-06-15 02:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0002_auto_20200615_0046'), + ] + + operations = [ + migrations.AlterField( + model_name='teacher', + name='classes', + field=models.ManyToManyField(blank=True, related_name='teacher', to='api.Class'), + ), + ] diff --git a/Website/api/migrations/0004_auto_20200614_2107.py b/Website/api/migrations/0004_auto_20200614_2107.py deleted file mode 100644 index 75e2a7c..0000000 --- a/Website/api/migrations/0004_auto_20200614_2107.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 3.0.7 on 2020-06-14 21:07 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('api', '0003_auto_20200614_2044'), - ] - - operations = [ - migrations.AlterField( - model_name='student', - name='grade', - field=models.IntegerField(blank=True, default=0), - ), - ] diff --git a/Website/api/migrations/0004_auto_20200615_0255.py b/Website/api/migrations/0004_auto_20200615_0255.py new file mode 100644 index 0000000..e126c18 --- /dev/null +++ b/Website/api/migrations/0004_auto_20200615_0255.py @@ -0,0 +1,22 @@ +# Generated by Django 3.0.7 on 2020-06-15 02:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0003_auto_20200615_0233'), + ] + + operations = [ + migrations.RemoveField( + model_name='teacher', + name='classes', + ), + migrations.AddField( + model_name='class', + name='teachers', + field=models.ManyToManyField(blank=True, related_name='teachers', to='api.Teacher'), + ), + ] diff --git a/Website/api/models.py b/Website/api/models.py index e8bb2b3..268c451 100644 --- a/Website/api/models.py +++ b/Website/api/models.py @@ -1,52 +1,7 @@ from django.db import models from django.contrib.auth.models import User -class DefFiles(models.Model): - name=models.CharField(max_length=100) - path=models.CharField(max_length=100) - assignment=models.CharField(max_length=100, default="") - classes=models.CharField(max_length=100) - teacher=models.CharField(max_length=100) -class Assignment(models.Model): - owner = models.ForeignKey('auth.User', related_name='assignments', on_delete=models.CASCADE) - - name=models.CharField(max_length=100, primary_key=True) - due_date=models.DateTimeField() - # files = models.ManyToManyField(DefFiles) - files=models.CharField(max_length=100, default="", blank=True) - path=models.CharField(max_length=100) - classes=models.CharField(max_length=100) - teacher=models.CharField(max_length=100) - def __str__(self): - return '%s' % (self.name) - -class Classes(models.Model): - user = models.OneToOneField(User, on_delete=models.CASCADE) - - name = models.CharField(primary_key=True, max_length=100) - repo=models.URLField(default="", blank=True) - path=models.CharField(max_length=100, default="") - teacher=models.CharField(max_length=100, default="") - assignments=models.TextField(default="", blank=True) - default_file=models.CharField(max_length=100, default="", blank=True) - confirmed=models.TextField(default="", blank=True) - unconfirmed=models.TextField(default="", blank=True) - - # assignments = models.ManyToManyField(Assignment, default="") - # default_file = models.ManyToManyField(DefFiles) - def save(self, *args, **kwargs): - return super(Classes, self).save(*args, **kwargs) - -class Teacher(models.Model): - user = models.OneToOneField(User, on_delete=models.CASCADE) - # classes = models.ManyToManyField(Classes, default="") - classes=models.CharField(max_length=100, default="", blank=True) - ion_user=models.CharField(primary_key=True, max_length=100) - git=models.CharField(max_length=100) - - def save(self, *args, **kwargs): - super(Teacher, self).save(*args, **kwargs) class Student(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) @@ -62,3 +17,58 @@ class Student(models.Model): def __str__(self): return f"{self.user.username}'s Profile" + +class Class(models.Model): + name = models.CharField(primary_key=True, max_length=100) + description = models.CharField(default="Class Description", max_length=500) + repo=models.URLField(default="", blank=True) + path=models.CharField(max_length=100, default="") + assignments=models.TextField(default="", blank=True) + default_file=models.CharField(max_length=100, default="", blank=True) + confirmed=models.ManyToManyField(Student, blank=True, related_name='confirmed') + unconfirmed=models.ManyToManyField(Student, blank=True, related_name='unconfirmed') + + # assignments = models.ManyToManyField(Assignment, default="") + # default_file = models.ManyToManyField(DefFiles) + def save(self, *args, **kwargs): + return super(Class, self).save(*args, **kwargs) + + def __str__(self): + return self.name + +class Teacher(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + classes=models.ManyToManyField(Class, blank=True, related_name='classes') + git=models.CharField(max_length=100, default="", blank=True) + + + def __str__(self): + return f"{self.user.username}'s Profile" + + def save(self, *args, **kwargs): + super(Teacher, self).save(*args, **kwargs) + + + + + +class Assignment(models.Model): + owner = models.ForeignKey('auth.User', related_name='assignments', on_delete=models.CASCADE) + + name=models.CharField(max_length=100, primary_key=True) + due_date=models.DateTimeField() + # files = models.ManyToManyField(DefFiles) + files=models.CharField(max_length=100, default="", blank=True) + path=models.CharField(max_length=100) + classes=models.CharField(max_length=100) + teacher=models.CharField(max_length=100) + def __str__(self): + return '%s' % (self.name) + + +class DefFiles(models.Model): + name=models.CharField(max_length=100) + path=models.CharField(max_length=100) + assignment=models.CharField(max_length=100, default="") + classes=models.CharField(max_length=100) + teacher=models.CharField(max_length=100) diff --git a/Website/api/serializers.py b/Website/api/serializers.py index 2b4bb54..46571fc 100644 --- a/Website/api/serializers.py +++ b/Website/api/serializers.py @@ -1,5 +1,5 @@ from django.contrib.auth.models import User, Group -from .models import Student, Teacher, Classes, Assignment, DefFiles +from .models import Student, Teacher, Class, Assignment, DefFiles from rest_framework import serializers, permissions from django.contrib.auth.models import User from .permissions import IsOwnerOrReadOnly,isTeacher @@ -15,41 +15,39 @@ class UserSerializer(serializers.HyperlinkedModelSerializer): # class DefFilesSerializer(serializers.HyperlinkedModelSerializer): # class Meta: # model = DefFiles -# fields = ['name', 'path','assignment','classes', "teacher",'url', 'id'] +# fields = ['name', 'path','assignment','Class', "teacher",'url', 'id'] class AssignmentSerializer(serializers.HyperlinkedModelSerializer): - #permissions_classes = [permissions.IsAuthenticatedOrReadOnly] + #permissions_Class = [permissions.IsAuthenticatedOrReadOnly] # files = DefFilesSerializer(many=True, read_only=True,allow_null=True) owner = serializers.ReadOnlyField(source='owner.username') class Meta: model = Assignment - # fields = ['url','name', 'due_date', 'path' , "classes","teacher",'owner'] - fields = ['name', 'due_date', 'path' , "classes","teacher",'owner'] + # fields = ['url','name', 'due_date', 'path' , "Class","teacher",'owner'] + fields = ['name', 'due_date', 'path' , "Class","teacher",'owner'] -class ClassesSerializer(serializers.HyperlinkedModelSerializer): +class ClassSerializer(serializers.HyperlinkedModelSerializer): # assignments = AssignmentSerializer(many=True, read_only=True,allow_null=True) # default_file=DefFilesSerializer(many=True, read_only=True,allow_null=True) owner = serializers.ReadOnlyField(source='owner.username') class Meta: - model = Classes + model = Class # fields = ['url','name', 'repo','path', "teacher",'assignments',"default_file", 'confirmed', 'unconfirmed','owner'] fields = ['name', 'repo','path', "teacher",'assignments',"default_file", 'confirmed', 'unconfirmed','owner'] class StudentSerializer(serializers.HyperlinkedModelSerializer): - # classes = ClassesSerializer(many=True, read_only=True,allow_null=True) + # Class = ClassSerializer(many=True, read_only=True,allow_null=True) owner = serializers.ReadOnlyField(source='owner.username') class Meta: model = Student - # fields = ['url','first_name', 'last_name', 'grade','email','student_id', 'git','ion_user','classes','added_to','completed', 'repo','owner'] - fields = ['first_name', 'last_name', 'grade','email','student_id', 'git','ion_user','classes','added_to','completed', 'repo','owner'] + # fields = ['url','first_name', 'last_name', 'grade','email','student_id', 'git','ion_user','Class','added_to','completed', 'repo','owner'] + fields = ['first_name', 'last_name', 'grade','email','student_id', 'git','ion_user','Class','added_to','completed', 'repo','owner'] class TeacherSerializer(serializers.ModelSerializer): - # classes = ClassesSerializer(many=True, read_only=True,allow_null=True) + # Class = ClassSerializer(many=True, read_only=True,allow_null=True) owner = serializers.ReadOnlyField(source='owner.username') class Meta: model = Teacher - # fields = ['url','first_name', 'last_name','git','ion_user', 'email','classes','owner'] - fields = ['first_name', 'last_name','git','ion_user', 'email','classes','owner'] - - + # fields = ['url','first_name', 'last_name','git','ion_user', 'email','Class','owner'] + fields = ['first_name', 'last_name','git','ion_user', 'email','Class','owner'] diff --git a/Website/api/urls.py b/Website/api/urls.py index f130d15..6434309 100644 --- a/Website/api/urls.py +++ b/Website/api/urls.py @@ -9,8 +9,8 @@ urlpatterns = [ path('teachers//', views.TeacherDetail.as_view()), path('assignments/', views.AssignmentList.as_view()), path('assignments//', views.AssignmentDetail.as_view()), - path('classes/', views.ClassesList.as_view()), - path('classes//', views.ClassesDetail.as_view()), + path('classes/', views.ClassList.as_view()), + path('classes//', views.ClassDetail.as_view()), ] -urlpatterns = format_suffix_patterns(urlpatterns) \ No newline at end of file +urlpatterns = format_suffix_patterns(urlpatterns) diff --git a/Website/api/views.py b/Website/api/views.py index 3876c0a..11af2b1 100644 --- a/Website/api/views.py +++ b/Website/api/views.py @@ -1,5 +1,5 @@ -from .models import Student, Teacher, Classes, Assignment, DefFiles -from .serializers import StudentSerializer, TeacherSerializer, ClassesSerializer, AssignmentSerializer, UserSerializer +from .models import Student, Teacher, Class, Assignment, DefFiles +from .serializers import StudentSerializer, TeacherSerializer, ClassSerializer, AssignmentSerializer, UserSerializer from rest_framework import generics, viewsets, permissions, response, status from django.http import Http404 from rest_framework.views import APIView @@ -14,7 +14,7 @@ from rest_framework.response import Response class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer - permission_classes = [permissions.IsAuthenticated] + permission_Class = [permissions.IsAuthenticated] class StudentViewSet(viewsets.ModelViewSet): @@ -23,7 +23,7 @@ class StudentViewSet(viewsets.ModelViewSet): """ queryset = Student.objects.all() serializer_class = StudentSerializer - permission_classes = [permissions.IsAuthenticated, IsOwnerOrReadOnly] + permission_Class = [permissions.IsAuthenticated, IsOwnerOrReadOnly] def perform_create(self, serializer): serializer.save(owner=self.request.user) @@ -34,18 +34,18 @@ class TeacherViewSet(viewsets.ModelViewSet): """ queryset = Teacher.objects.all() serializer_class = TeacherSerializer - permission_classes = [permissions.IsAuthenticated, IsOwnerOrReadOnly] + permission_Class = [permissions.IsAuthenticated, IsOwnerOrReadOnly] def perform_create(self, serializer): serializer.save(owner=self.request.user) -class ClassesViewSet(viewsets.ModelViewSet): +class ClassViewSet(viewsets.ModelViewSet): """ API endpoint that allows users to be viewed or edited. """ - queryset = Classes.objects.all() - serializer_class = ClassesSerializer - permission_classes = [permissions.IsAuthenticated, IsOwnerOrReadOnly] + queryset = Class.objects.all() + serializer_class = ClassSerializer + permission_Class = [permissions.IsAuthenticated, IsOwnerOrReadOnly] def perform_create(self, serializer): if(self.request.user.groups.filter(name__in=['teachers']).exists() or self.request.user.is_superuser): @@ -61,7 +61,7 @@ class AssignmentViewSet(viewsets.ModelViewSet): """ queryset = Assignment.objects.all() serializer_class = AssignmentSerializer - permission_classes = [permissions.IsAuthenticated, isTeacher, IsOwnerOrReadOnly] + permission_Class = [permissions.IsAuthenticated, isTeacher, IsOwnerOrReadOnly] def perform_create(self, serializer): if(self.request.user.groups.filter(name__in=['teachers']).exists() or self.request.user.is_superuser): @@ -76,4 +76,4 @@ class AssignmentViewSet(viewsets.ModelViewSet): # """ # queryset = DefFiles.objects.all() # serializer_class = DefFilesSerializer -# permissions_classes = [permissions.IsAuthenticatedOrReadOnly] +# permissions_Class = [permissions.IsAuthenticatedOrReadOnly] diff --git a/Website/config/urls.py b/Website/config/urls.py index 420beb6..297739c 100644 --- a/Website/config/urls.py +++ b/Website/config/urls.py @@ -9,7 +9,7 @@ router = routers.DefaultRouter() router.register(r'students', api_views.StudentViewSet) router.register(r'teachers', api_views.TeacherViewSet) router.register(r'assignments', api_views.AssignmentViewSet) -router.register(r'classes', api_views.ClassesViewSet) +router.register(r'classes', api_views.ClassViewSet) # router.register(r'files', api_views.DefFilesViewSet) router.register(r'users', api_views.UserViewSet) diff --git a/Website/skoolos/static/skoolos/styles.css b/Website/skoolos/static/skoolos/styles.css index 8eb8163..5da71bb 100644 --- a/Website/skoolos/static/skoolos/styles.css +++ b/Website/skoolos/static/skoolos/styles.css @@ -13,22 +13,20 @@ body { color: #333333; margin-top: 5rem; font-family: 'Segoe UI'; + margin-left: 2.5rem; + margin-right: 2.5rem; } h1, h2, h3, h4, h5, h6 { color: #444444; } -ul { - margin: 0; -} - .bg-steel { background: #3cba54; } .site-header .navbar-nav .nav-link { - color: #cbd5db; + color: #e1e1e1; } .site-header .navbar-nav .nav-link:hover { @@ -38,63 +36,3 @@ ul { .site-header .navbar-nav .nav-link.active { font-weight: 500; } - -.content-section { - background: #ffffff; - padding: 10px 20px; - border: 1px solid #dddddd; - border-radius: 3px; - margin-bottom: 20px; -} - -.article-title { - color: #444444; -} - -a.article-title:hover { - color: #428bca; - text-decoration: none; -} - -.article-content { - white-space: pre-line; -} - -.article-img { - height: 65px; - width: 65px; - margin-right: 16px; -} - -.article-metadata { - padding-bottom: 1px; - margin-bottom: 4px; - border-bottom: 1px solid #e3e3e3 -} - -.article-metadata a:hover { - color: #333; - text-decoration: none; -} - -.article-svg { - width: 25px; - height: 25px; - vertical-align: middle; -} - -.account-img { - height: 125px; - width: 125px; - margin-right: 20px; - margin-bottom: 16px; -} - -.account-heading { - font-size: 2.5rem; -} - -.nounderline { - text-decoration: none !important; - color: black !important; -} diff --git a/Website/skoolos/static/skoolos/tj_trans.png b/Website/skoolos/static/skoolos/tj_trans.png new file mode 100644 index 0000000000000000000000000000000000000000..873c2498cd0ffa83c68986f690d17f5c73c8ef71 GIT binary patch literal 4322 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 l
- - Bootstrap + + SkoolOS +
+ {% endfor %} + {% endif %} {% block content %}{% endblock %} diff --git a/Website/skoolos/templates/skoolos/class_detail.html b/Website/skoolos/templates/skoolos/class_detail.html new file mode 100644 index 0000000..e6c02c5 --- /dev/null +++ b/Website/skoolos/templates/skoolos/class_detail.html @@ -0,0 +1,28 @@ +{% extends "skoolos/base.html" %} +{% block content %} +
+
+

Assignments:

+
+ {% for assignment in assignments %} +
+ {% endfor %} +
+ +
+

{{ class.name }}

+

Teachers:

+
    + {% for teacher in teachers %} +
  • {{ teacher.user.first_name }} {{ teacher.user.last_name }} ({{teacher.ion_user}})
  • + {% endfor %} +
+
+
+ +{% endblock content %} diff --git a/Website/skoolos/templates/skoolos/home.html b/Website/skoolos/templates/skoolos/home.html index d6e5432..6822cb6 100644 --- a/Website/skoolos/templates/skoolos/home.html +++ b/Website/skoolos/templates/skoolos/home.html @@ -3,7 +3,7 @@
{% for class in classes %}
- + +{% endblock content %} diff --git a/Website/skoolos/templates/skoolos/profile_teacher.html b/Website/skoolos/templates/skoolos/profile_teacher.html new file mode 100644 index 0000000..3da2f41 --- /dev/null +++ b/Website/skoolos/templates/skoolos/profile_teacher.html @@ -0,0 +1,34 @@ +{% extends "skoolos/base.html" %} +{% load crispy_forms_tags %} +{% block content %} +
+
+
+ + {{ user.first_name }} {{ user.last_name }} +

+ {{ user.email }} + GitHub +

+
+
+ Classes +
    + {% for class in classes %} +
  • {{ class.name }}
  • + {% endfor %} +
+
+ {% csrf_token %} +
+ Your profile + {{ userForm|crispy}} + {{ profileForm|crispy }} +
+
+ +
+
+
+
+{% endblock content %} diff --git a/Website/skoolos/urls.py b/Website/skoolos/urls.py index 182fea5..a028497 100644 --- a/Website/skoolos/urls.py +++ b/Website/skoolos/urls.py @@ -6,5 +6,5 @@ from . import views urlpatterns = [ path('', views.home, name='home'), path('profile/', views.profile, name='profile'), - path("class/", views.classDetail, name="class"), + path("class/", views.classDetail, name="class"), ] diff --git a/Website/skoolos/views.py b/Website/skoolos/views.py index 2748b71..c26311a 100644 --- a/Website/skoolos/views.py +++ b/Website/skoolos/views.py @@ -1,6 +1,11 @@ from django.shortcuts import render, redirect from django.contrib.auth.decorators import login_required from django.views.generic import ListView +from django.contrib import messages + +from django.contrib.auth.models import User + +from .forms import UserUpdateForm, StudentUpdateForm, TeacherUpdateForm from api.models import Student, Teacher, Class, Assignment @@ -16,7 +21,7 @@ def home (request): try: teacher = Teacher.objects.get(user=request.user) - return render(request, "skoolos/home.html", {'classes': teacher.classes}) + return render(request, "skoolos/home.html", {'classes': teacher.classes.all()}) except Teacher.DoesNotExist: pass @@ -26,6 +31,89 @@ def home (request): def profile (request): pass +@login_required() def classDetail (request, id): classObj = Class.objects.get(id=id) + + try: + student = Student.objects.get(user=request.user) + except Student.DoesNotExist: + pass + else: + if classObj.confirmed.filter(user=student.user).count() != 1: + return redirect('/') + else: + return render(request, "skoolos/class_detail.html", {'class': classObj,'assignments': classObj.assignments.all(), 'teachers': classObj.classes.all()}) + + try: + teacher = Teacher.objects.get(user=request.user) + return render(request, "skoolos/home.html", {'classes': teacher.classes.all()}) + except Teacher.DoesNotExist: + pass + else: + if classObj.confirmed.filter(user=student.user).count() != 1: + return redirect('/') + else: + return render(request, "skoolos/class_detail.html", {'class': classObj,'assignments': classObj.assignments.all(), 'teachers': classObj.classes.all()}) + return redirect('/') + +@login_required() +def profile (request): + try: + student = Student.objects.get(user=request.user) + return student_profile(request) + except Student.DoesNotExist: + pass + + try: + teacher = Teacher.objects.get(user=request.user) + return teacher_profile(request) + except Teacher.DoesNotExist: + pass + + return redirect("/") + +def student_profile (request): + if request.method == "POST": + userForm = UserUpdateForm(request.POST, instance=request.user) + profileForm = StudentUpdateForm(request.POST, + instance=request.user.student) + if userForm.is_valid() and profileForm.is_valid(): + userForm.save() + profileForm.save() + messages.success(request, "Your account has been updated!") + return redirect('profile') + else: + userForm = UserUpdateForm(instance=request.user) + profileForm = StudentUpdateForm(instance=request.user.student) + + context = { + 'userForm': userForm, + 'profileForm': profileForm, + 'classes': request.user.student.confirmed.all() + } + + return render(request, 'skoolos/profile_student.html', context) + +def teacher_profile (request): + if request.method == "POST": + userForm = UserUpdateForm(request.POST, instance=request.user) + profileForm = TeacherUpdateForm(request.POST, + instance=request.user.student) + if userForm.is_valid() and profileForm.is_valid(): + userForm.save() + profileForm.save() + messages.success(request, "Your account has been updated!") + return redirect('profile') + else: + userForm = UserUpdateForm(instance=request.user) + profileForm = TeacherUpdateForm(instance=request.user.student) + + context = { + 'userForm': userForm, + 'profileForm': profileForm, + 'classes': request.user.teacher.classes.all() + } + + return render(request, 'skoolos/profile_teacher.html', context)