diff --git a/.gitignore b/.gitignore
index 8df82ed..e67073c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -128,11 +128,129 @@ dmypy.json
# Pyre type checker
.pyre/
-# PyCharm Files
-.idea/
-
# VSCode
.vscode/
-#lmao mac
+# PyCharm Files
+.idea/
+
+# Mac lmao
.DS_Store
+
+# Django #
+*.log
+*.pot
+*.pyc
+__pycache__
+db.sqlite3
+media
+
+# Backup files #
+*.bak
+
+# If you are using PyCharm #
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/gradle.xml
+.idea/**/libraries
+*.iws /out/
+
+# Python #
+*.py[cod]
+*$py.class
+
+# Distribution / packaging
+.Python build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+.pytest_cache/
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery
+celerybeat-schedule.*
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+
+# Sublime Text #
+*.tmlanguage.cache
+*.tmPreferences.cache
+*.stTheme.cache
+*.sublime-workspace
+*.sublime-project
+
+# sftp configuration file
+sftp-config.json
+
+# Package control specific files Package
+Control.last-run
+Control.ca-list
+Control.ca-bundle
+Control.system-ca-bundle
+GitHub.sublime-settings
+
+# Visual Studio Code #
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+.history
+
diff --git a/2022rkhondak b/2022rkhondak
new file mode 160000
index 0000000..8dca8b7
--- /dev/null
+++ b/2022rkhondak
@@ -0,0 +1 @@
+Subproject commit 8dca8b78c03fab721e9976a4675e2996802328a7
diff --git a/CLI/commands.py b/CLI/commands.py
index 1780d32..ed1c1f3 100644
--- a/CLI/commands.py
+++ b/CLI/commands.py
@@ -5,134 +5,4 @@ import os
import argparse
-#already ccrerrated account through website, has to login
-def update():
- #get data from database
- return
-
-def yesorno(question):
- questions = [
- {
- 'type': 'input',
- 'name': 'response',
- 'message': question,
- },
- ]
- answers = prompt(questions)
- if(answers["response"] == "y"):
- return True
- return False
-
-def login():
- #enter username
- #enter password
- questions = [
- {
- 'type': 'input',
- 'name': 'webmail',
- 'message': 'What\'s TJ Webmail',
- },
- {
- 'type': 'password',
- 'name': 'password',
- 'message': 'Password?',
- },
- ]
- user = prompt(questions)
- #reading from json of users (replace w GET to database) to check if user is registered
- with open('users.json', 'r') as json_file:
- data = json.load(json_file)
- for i in range(len(data)):
- if user["webmail"] == data[i]["webmail"]:
- if(user["password"] == data[i]["password"]):
- print("Logged in!")
- return data[i]
- else:
- print("Password incorrect. Try again.")
- return None
- print("User not found. Please Try again")
- return None
-
-#did not create account through website, has to signup/login
-def signup():
- questions = [
- {
- 'type': 'input',
- 'name': 'first-name',
- 'message': 'What\'s your first name',
- },
- {
- 'type': 'input',
- 'name': 'last-name',
- 'message': 'What\'s your last name?',
- },
- {
- 'type': 'list',
- 'name': 'grade',
- 'message': 'Grade?',
- 'choices':["9","10","11","12"]
- },
- {
- 'type': 'input',
- 'name': 'webmail',
- 'message': 'What\'s your TJ Webmail?',
- },
- {
- 'type': 'password',
- 'name': 'password',
- 'message': 'Password?',
- },
- ]
- user = prompt(questions)
- for i in user:
- if user[i] == "":
- print("Some forms were left blank. Try again.\n")
- return None
- if len(user["password"]) < 6:
- print("Password is too short. Try again.")
- return None
- if (("@tjhsst.edu" in user['webmail']) == False):
- print("Webmail entered was not a @tjhhsst.edu. Try again.")
- return None
-
- user["classes"] = []
- with open('users.json', 'r') as json_file:
- data = json.load(json_file)
- data.append(user)
- open("users.json", "w").write(str(json.dumps(data)))
- return user
-
-def relogin():
- questions = [
- {
- 'type': 'list',
- 'name': 'choice',
- 'message': '',
- 'choices':["Continue as current user","Login into new user","Sign up into new account"]
- },
- ]
- answer = prompt(questions)
-
-
-def setup(user):
- #Read classes/assignenments and setup directory:
- #SkoolOS/Math/Week1
- for c in user["classes"]:
- os.makedirs("../" + c)
- for a in user["classes"][c]:
- os.makedirs("../" + c + "/" + a)
-
-def start():
- if(os.path.exists(".login.txt") == False):
- b = yesorno("Do you have a SkoolOS account?(y/N)")
- if(b):
- user = login()
- if(user != None):
- setup(user)
- open(".login.txt", "w").write(str(user))
- else:
- user = signup()
- if(user != None):
- open(".login.txt").write(str(user))
-
\ No newline at end of file
diff --git a/CLI/index.html b/CLI/index.html
new file mode 100644
index 0000000..a21b847
--- /dev/null
+++ b/CLI/index.html
@@ -0,0 +1,9 @@
+
+
+
+ Sign in with Ion
+
+
+ Sign in with
+
+
\ No newline at end of file
diff --git a/CLI/oauth/index.html b/CLI/oauth/index.html
new file mode 100644
index 0000000..31fa9e2
--- /dev/null
+++ b/CLI/oauth/index.html
@@ -0,0 +1,23 @@
+
+
+ Sign into Ion
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CLI/oauth/template.html b/CLI/oauth/template.html
new file mode 100644
index 0000000..6452ea8
--- /dev/null
+++ b/CLI/oauth/template.html
@@ -0,0 +1,23 @@
+
+
+ Sign into Ion
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CLI/requirements.txt b/CLI/requirements.txt
new file mode 100644
index 0000000..fbc7e54
--- /dev/null
+++ b/CLI/requirements.txt
@@ -0,0 +1,21 @@
+asgiref==3.2.7
+certifi==2020.4.5.1
+chardet==3.0.4
+click==7.1.2
+Django==3.0.7
+django-cors-middleware==1.5.0
+django-oauth-toolkit==1.3.2
+djangorestframework==3.11.0
+idna==2.9
+oauthlib==3.1.0
+prompt-toolkit==1.0.14
+Pygments==2.6.1
+PyInquirer==1.0.3
+pytz==2020.1
+regex==2020.5.14
+requests==2.23.0
+selenium==3.141.0
+six==1.15.0
+sqlparse==0.3.1
+urllib3==1.25.9
+wcwidth==0.2.3
diff --git a/CLI/run.py b/CLI/run.py
deleted file mode 100644
index aca8859..0000000
--- a/CLI/run.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from __future__ import print_function, unicode_literals
-from PyInquirer import prompt, print_json
-from commands import start, update
-import argparse
-import json
-import os
-import argparse
-
-my_parser = argparse.ArgumentParser(prog='skool', description='Let SkoolOS control your system', epilog="Try again")
-my_parser.add_argument('--init', action="store_true") #returns true if run argument
-args = my_parser.parse_args()
-
-update()
-outputs = vars(args)
-if(outputs['init']):
- start()
-
-
-
-
-
-
diff --git a/CLI/s-git.py b/CLI/s-git.py
new file mode 100644
index 0000000..1203091
--- /dev/null
+++ b/CLI/s-git.py
@@ -0,0 +1,101 @@
+import subprocess
+import os
+import requests
+import pprint
+import json
+
+#git clone student directory ==> /classes/assignments
+def initStudent(ion_user):
+ #check if git has already been initialized
+ if(os.path.exists(str(ion_user) +"/" + ".git")):
+ print("Already synced to: " + str(ion_user))
+ return
+
+ #get student repo from API
+ URL = "http://127.0.0.1:8000/students/" + ion_user + "/"
+ r = requests.get(url = URL, auth=('student','_$YFE#34.9_37jr'))
+ if(r.status_code == 200):
+ data = r.json()
+ repo = data['repo']
+ classes = data['classes']
+ print(data)
+ #git clone repo
+ process = subprocess.Popen(['git', 'clone', repo], stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+ process.wait()
+
+ # make classes directory
+ for c in classes:
+ cpath = str(ion_user) + "/" + c['name']
+ if(os.path.exists(cpath)):
+ print(cpath + " already exists...")
+ else:
+ os.mkdir(str(ion_user) + "/" + c['name'])
+
+ #make assignments directory
+ for a in c['assignments']:
+ path = str(ion_user) + "/" + c['name'] + "/" + a['name']
+ print(path)
+ if(os.path.exists("/" +path)):
+ print(path + " already exists...")
+ else:
+ os.mkdir(str(ion_user) + "/" + c['name'] + "/" + a['name'])
+
+ #push to remote repo
+ os.chdir(ion_user)
+ process = subprocess.Popen(['git', 'init'], stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+ process.wait()
+ process = subprocess.Popen(['git', 'add', '.'], stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+ process.wait()
+ process = subprocess.Popen(['git', 'commit', '-m', "First Commit"], stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+ process.wait()
+ process = subprocess.Popen(['git', 'push', '-u', 'origin','master'], stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+ process.wait()
+
+ elif(r.status_code == 404):
+ print("Make new account!")
+ elif(r.status_code == 403):
+ print("Invalid username/password")
+ else:
+ print(r.status_code)
+
+
+
+#Teachers
+
+#make student repo by student id
+def addStudent(stid, teacher):
+ os.mkdir(stid)
+ os.chdir(os.getcwd() + "/" + stid)
+ process = subprocess.Popen(['git', 'init'], stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+ process.communicate()
+ process = subprocess.Popen(['git', 'add', '.'], stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+ process.communicate()
+ process = subprocess.Popen(['git', 'commit', '-m', "First Commit"], stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+ process.communicate()
+
+def addStudents(filename):
+ print(filename)
+
+def addAsignment(name):
+ print(name)
+
+def updateAssignment(name):
+ print(name)
+
+def comment(filename, text):
+ print(text)
+
+#initStudent("2022rkhondak")
+ion_user = "2022rkhondak"
+headers = {'Content-type': 'application/json'}
+data = {'first_name': 'Jeff',
+ 'git': 'https://github.com/',
+ 'grade': 10,
+ 'ion_user': '2022jlol1',
+ 'last_name': 'lol.',
+ 'student_id': 11111
+ }
+data = json.dumps(data)
+URL = "http://127.0.0.1:8000/students/" + ion_user + "/"
+r = requests.put(url = URL, data= data, headers=headers ,auth=('raffukhondaker','hackgroup1'))
+pprint.pprint(r.json())
\ No newline at end of file
diff --git a/CLI/server.py b/CLI/server.py
new file mode 100644
index 0000000..0aef4c5
--- /dev/null
+++ b/CLI/server.py
@@ -0,0 +1,23 @@
+from socket import *
+from selenium import webdriver
+import http.server
+import socketserver
+import threading
+
+
+def create_server():
+ port = 8000
+ handler = http.server.SimpleHTTPRequestHandler
+ httpd = socketserver.TCPServer(("", port), handler)
+ print("serving at port:" + str(port))
+ httpd.serve_forever()
+
+
+threading.Thread(target=create_server).start()
+
+print("Server has started. Continuing..")
+
+browser = webdriver.Chrome()
+browser.get("http://localhost:8000")
+
+assert "" in browser.page_source
diff --git a/CLI/skoolos.py b/CLI/skoolos.py
index bf46ef4..428415a 100644
--- a/CLI/skoolos.py
+++ b/CLI/skoolos.py
@@ -3,15 +3,19 @@ from urllib.parse import urlparse
import requests
from requests_oauthlib import OAuth2Session
-from selenium import webdriver;
+from selenium import webdriver
import os.path
import time
+import http.server
+import socketserver
+from threading import Thread
+from werkzeug.urls import url_decode
client_id = r'QeZPBSKqdvWFfBv1VYTSv9iFGz5T9pVJtNUjbEr6'
client_secret = r'0Wl3hAIGY9SvYOqTOLUiLNYa4OlCgZYdno9ZbcgCT7RGQ8x2f1l2HzZHsQ7ijC74A0mrOhhCVeZugqAmOADHIv5fHxaa7GqFNtQr11HX9ySTw3DscKsphCVi5P71mlGY'
redirect_uri = 'http://localhost:8000/'
token_url = 'https://ion.tjhsst.edu/oauth/token/'
-scope=["read"]
+scope = ["read"]
def main():
@@ -25,38 +29,79 @@ def main():
if not os.path.exists(".profile"):
authenticate()
+ print(open(".profile", "r").read())
else:
print(open(".profile", "r").read())
+ while True:
+ pass
def authenticate():
oauth = OAuth2Session(client_id=client_id, redirect_uri=redirect_uri, scope=scope)
authorization_url, state = oauth.authorization_url("https://ion.tjhsst.edu/oauth/authorize/")
+
+ web_dir = os.path.join(os.path.dirname(__file__), 'oauth')
+ 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()
+
+ # server = Thread(target=create_server)
+ # server.daemon = True
+ # server.start()
+
browser = webdriver.Chrome()
- browser.get(authorization_url)
+ browser.get("localhost:8000/")
while "http://localhost:8000/?code" not in browser.current_url:
+ http.server.
time.sleep(0.25)
- code = urlparse(browser.current_url).query[5:]
+ url = browser.current_url
+ gets = url_decode(url.replace("http://localhost:8000/?", ""))
+ code = gets.get("code")
+ if state == gets.get("state"):
+ state = gets.get("state")
+ print("states good")
browser.quit()
+ print(code)
+ print(state)
+
payload = {'grant_type': 'authorization_code', 'code': code, 'redirect_uri': redirect_uri, 'client_id': client_id,
'client_secret': client_secret, 'csrfmiddlewaretoken': state}
token = requests.post("https://ion.tjhsst.edu/oauth/token/", data=payload).json()
print(token)
- # headers = {'Authorization': f"Bearer {token['access_token']}"}
- #
- # # And finally get the user's profile!
- # profile = requests.get("https://ion.tjhsst.edu/api/profile", headers=headers).json()
- # username = profile['ion_username']
- # email = profile['tj_email']
- # first_name = profile['first_name']
- # last_name = profile['last_name']
+ headers = {'Authorization': f"Bearer {token['access_token']}"}
- #print(profile)
+ # And finally get the user's profile!
+ profile = requests.get("https://ion.tjhsst.edu/api/profile", headers=headers).json()
+ print(profile)
+ username = profile['ion_username']
+ email = profile['tj_email']
+ first_name = profile['first_name']
+ last_name = profile['last_name']
+ profileFile = open(".profile", "w")
+ profileFile.write(profile)
+ profileFile.close()
+
+ # server.stop
+
+
+def create_server():
+ port = 8000
+ handler = http.server.SimpleHTTPRequestHandler
+ httpd = socketserver.TCPServer(("", port), handler)
+ print("serving at port:" + str(port))
+ httpd.serve_forever()
if __name__ == "__main__":
main()
diff --git a/CLI/t-git-old.py b/CLI/t-git-old.py
new file mode 100644
index 0000000..d2a3316
--- /dev/null
+++ b/CLI/t-git-old.py
@@ -0,0 +1,457 @@
+import subprocess
+import os
+import requests
+import webbrowser
+import pprint
+import json
+
+#git clone student directory ==> /classes/assignments
+'''
+{
+ "url": "http://127.0.0.1:8000/teachers/eharris1/",
+ "first_name": "Errin",
+ "last_name": "Harris",
+ "classes": [
+ {
+ "url": "http://127.0.0.1:8000/classes/1/",
+ "name": "Math5",
+ "assignments": [
+ {
+ "name": "Week1_HW",
+ "due_date": "2020-06-07T07:46:30.537197Z",
+ "url": "http://127.0.0.1:8000/assignments/1/",
+ "files": [
+ {
+ "name": "instructions.txt"
+ }
+ ]
+ },
+ {
+ "name": "Week2_HW",
+ "due_date": "2020-06-07T07:46:30.548596Z",
+ "url": "http://127.0.0.1:8000/assignments/2/",
+ "files": [
+ {
+ "name": "instructions.txt"
+ }
+ ]
+ }
+ ],
+ "repo": ""
+ }
+ ],
+ "git": "therealraffi",
+ "ion_user": "eharris1"
+ },
+'''
+#get teacher info from api
+def getTeacher(ion_user):
+ URL = "http://127.0.0.1:8000/teachers/" + ion_user + "/"
+ r = requests.get(url = URL, auth=('raffukhondaker','hackgroup1'))
+ if(r.status_code == 200):
+ data = r.json()
+ return data
+ elif(r.status_code == 404):
+ return None
+ print("Make new account!")
+ elif(r.status_code == 403):
+ return None
+ print("Invalid username/password")
+ else:
+ return None
+ print(r.status_code)
+
+def getDB(url):
+ r = requests.get(url = url, auth=('raffukhondaker','hackgroup1'))
+ return r.json()
+
+class Teacher:
+ def __init__(self, data):
+ # teacher info already stored in API
+ # intitialze fields after GET request
+ self.first_name=data['first_name']
+ self.last_name=data['last_name']
+ self.git=data['git']
+ self.username=data['ion_user']
+ self.url= "http://127.0.0.1:8000/teachers/" + self.username + "/"
+
+ classes=data['classes'].split(",")
+ cdict = []
+ for cid in classes:
+ adict=[]
+ c = getDB("http://127.0.0.1:8000/classes/" + cid + "/")
+ name=c['name']
+ repo=c['repo']
+ path=c['path']
+ teacher=c['teacher']
+ id=c['id']
+ assignments=c['assignments'].split(",")
+ dfs = c['default_file'].split(' ')
+ dfdict=[]
+ for fid in dfs:
+ f = getDB("http://127.0.0.1:8000/files/" + fid + "/")
+ fname=f['name']
+ fpath=f['path']
+ dfdict.append({
+ 'name':fname,
+ 'path':fpath,
+ 'classes':classes,
+ 'assignment':"none",
+ 'id':fid,
+ })
+ for aid in assignments:
+ fdict=[]
+ a = getDB("http://127.0.0.1:8000/assignments/" + aid + "/")
+ aname= a['name']
+ due_date = a['due_date']
+ apath=a['path']
+ classes=a['classes']
+ files = a['files'].split(' ')
+ for fid in files:
+ f = getDB("http://127.0.0.1:8000/files/" + fid + "/")
+ fname=f['name']
+ fpath=f['path']
+ fdict.append({
+ 'name':fname,
+ 'path':fpath,
+ 'classes':classes,
+ 'assignment':aname,
+ 'id':fid,
+ })
+ adict.append({
+ 'name':aname,
+ 'due_date':due_date,
+ 'path':apath,
+ 'classes':classes,
+ 'teacher':teacher,
+ 'files':fdict,
+ })
+ cdict.append({
+ 'name':name,
+ 'path':path,
+ 'teacher':teacher,
+ 'assignments':adict,
+ 'default_file':adict,
+ })
+
+ self.classes = cdict
+
+ def command(self,command):
+ ar = []
+ command = command.split(" ")
+ for c in command:
+ ar.append(c)
+ process = subprocess.Popen(ar, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+ p=process.poll()
+ output = process.communicate()[0]
+ #print(output.decode('utf-8'))
+
+ def initTeacher(self):
+ if(os.path.exists(self.username )):
+ print("Already synced to: " + str(self.username))
+ return
+ os.mkdir(self.username)
+ classes = self.classes
+ # make classes directory
+ for c in classes:
+ cname= c['name']
+ cpath = self.username + "/" + cname
+
+ input("Make new Git Repo with name: " + cname + " (Press any key to continue)\n")
+ webbrowser.open('https://github.com/new')
+ input("Repo created? (Press any key to continue)\n")
+
+ url='https://github.com/' + self.git + "/" + cname
+ print(url)
+ while(requests.get(url).status_code != 200):
+ print(requests.get(url))
+ r = input("Repo not created yet. (Press any key to continue after repo created, or 'N' to exit)\n")
+ if(r=="N" or r=="No"):
+ return
+ cdir = os.getcwd()
+ os.chdir(self.username)
+ self.command('git clone ' + url)
+ os.chdir(cdir)
+
+ #make class directory
+ #make default files for each class
+ for filename in c['default_file']:
+ f=open(cpath+"/"+filename['name'], "w")
+ f.close()
+
+ #make assignments directory
+ for a in c['assignments']:
+ path = cpath + "/" + a['name']
+ if(os.path.exists(path)):
+ print(path + " already exists...")
+ else:
+ os.mkdir(path)
+ f=open(path + "/instructions.txt", "w")
+ f.close()
+
+ #push to remote repo
+ os.chdir(cpath)
+ print(cpath)
+ self.command('git add .')
+ self.command('git commit -m Hello_Class')
+ self.command('git push -u origin master')
+
+ def checkGit(self, ass):
+ for a in ass:
+ if a =='.git':
+ return True
+ return False
+
+ def compareDB(self, fdict, url):
+ URL = url
+ r = requests.get(url = URL, auth=('raffukhondaker','hackgroup1'))
+ data = r.json()['results']
+ allfiles = data
+ # far = []
+ # for f in allfiles:
+ # far.append(f['path'])
+
+ for f in fdict:
+ URL = url
+ in_db = False
+ pid=None
+ for dbf in allfiles:
+ if(dbf['path'] == f['path']):
+ in_db=True
+ break
+ if(in_db==False):
+ r = requests.post(url = URL, data=f , auth=('raffukhondaker','hackgroup1'))
+ print("POST: (" + URL + "): " + f['path'])
+ f['url']=r.json()['url']
+ print(r.status_code)
+ else:
+ URL = URL + str(dbf['id']) + "/"
+ r = requests.put(url = URL, data=f , auth=('raffukhondaker','hackgroup1'))
+ print(r.status_code)
+ print("UPDATED: (" + URL + "): " + f['path'])
+ f['url']=r.json()['url']
+ f['id']=dbf['id']
+ print(f)
+
+ return fdict
+
+ #update API and Github, all assignments / classes
+ def update(self):
+ #lists all classes
+ classes = os.listdir(self.username)
+
+ #checks all class directories first
+ for c in classes:
+ path = self.username + "/" + c
+ if(self.checkClass(path) == False):
+ return
+ cdict = []
+ for c in classes:
+ path = self.username + "/" + c
+ #lists all assignments and default files
+ ass = os.listdir(path)
+ #if no .git, directory not synced to git or API
+ if (self.checkGit(ass)==False):
+ self.addClass(path)
+ else:
+ #push to git
+ loc = os.getcwd()
+ os.chdir(path)
+ self.command('git add .')
+ self.command('git commit -m "Update"')
+ self.command('git push -u origin master')
+ os.chdir(loc)
+ ass.remove('.git')
+
+ loc = os.getcwd()
+ os.chdir(path)
+ repo = self.command('git config --get remote.origin.url')
+ os.chdir(loc)
+
+ #assignments
+ adict = []
+ #default files for classes
+ fdict=[]
+ #default files for assignments
+ afdict=[]
+ for a in ass:
+ aname=a
+ path = self.username + "/" + c + "/" + a
+ #need to add option
+ due_date= '2020-06-07T07:46:30.537197Z',
+ #check for default file
+ if(os.path.isfile(path)):
+ fdict.append({
+ 'name':a,
+ 'path':path
+ })
+ elif(os.path.isdir(path)):
+ for af in os.listdir(path):
+ path = path+ "/" + af
+ if(os.path.isfile(path)):
+ afdict.append({
+ 'name':af,
+ 'path':path
+ })
+ path = self.username + "/" + c + "/" + a
+ adict.append({
+ 'name':aname,
+ 'due_date': due_date[0],
+ 'path':path,
+ 'files':afdict
+ })
+
+ fdict=self.compareDB(fdict, "http://127.0.0.1:8000/files/")
+ afdict=self.compareDB(afdict,"http://127.0.0.1:8000/files/")
+
+ adict=self.compareDB(adict, 'http://127.0.0.1:8000/assignments/')
+
+ path = self.username + "/" + c
+ cdict.append({
+ 'name':c,
+ 'repo': repo,
+ 'path':path,
+ 'assignments':adict,
+ 'default_file':fdict,
+ })
+ cdict=self.compareDB(cdict,'http://127.0.0.1:8000/classes/')
+
+ mdict= {
+ 'first_name':self.first_name,
+ 'last_name':self.last_name,
+ 'git':self.git,
+ 'ion_user':self.username,
+ 'classes':cdict,
+ }
+
+ data = json.dumps(mdict)
+ # r = requests.put(url = 'http://127.0.0.1:8000/teachers/eharris1/', data=data, headers={'Content-type': 'application/json'} , auth=('raffukhondaker','hackgroup1'))
+ # print(print(r.json()))
+
+
+ #class name format: _
+
+ #turn existing directory into class, Pre-condition: directory exists
+ #relative path to class: 2022rkhondak/Math4
+ def checkClass(self,path):
+ cname = path.split("/")
+ cname = cname[len(cname)-1]
+ if(("_" + self.username) in cname) == False:
+ print("Incorrect class name: Must be in the format: _")
+ return False
+ dirs = os.listdir(path)
+ #checks if there is a file (not within Assignments) in class, need at least 1
+ deffile = False
+ #checks if there is a file in an Assignment, need at least 1 (default True in case no assignments)
+ as_file = True
+ as_bad = ""
+
+ for d in dirs:
+ if(os.path.isfile(d)):
+ deffile=True
+ if(os.path.isdir(d)) and d != '.git':
+ #checks if there is a file in an Assignment, need at least 1
+ as_file = False
+ asdir = os.listdir(d)
+ for a in asdir:
+ if(os.path.isfile(a)):
+ as_file=True
+ if(as_file==False):
+ as_bad = a
+ break
+ if(as_file==False):
+ print("Assignment '" + as_bad + "' does not have a default file!")
+ return False
+
+ if(deffile):
+ print("Need a default file in the " + path + " Directory!")
+ return False
+ return True
+
+ #adds class to git, not API
+ def addClasstoGit(self, path):
+ cname = path.split("/")
+ cname = cname[len(cname)-1]
+ #push to remote repo
+ if(self.checkClass(path)):
+ input("Make new Git Repo with name: " + cname + " (Press any key to continue)\n")
+ webbrowser.open('https://github.com/new')
+ input("Repo created? (Press any key to continue)\n")
+
+ url='https://github.com/' + self.git + "/" + cname
+ print(url)
+ while(requests.get(url).status_code != 200):
+ print(requests.get(url))
+ r = input("Repo not created yet. (Press any key to continue after repo created, or 'N' to exit)\n")
+ if(r=="N" or r=="No"):
+ return None
+ cdir = os.getcwd()
+ os.chdir(path)
+ self.command('git init')
+ self.command('git add .')
+ self.command('git commit -m Hello_Class')
+ self.command('git remote add origin ' + url + '.git')
+ self.command('git push -u origin master')
+ os.chdir(cdir)
+
+
+ #make a new class from scratch
+ def makeClass(self, subject):
+ cname = subject + "_" + self.username
+ os.chdir(self.username)
+ #check if class exists
+ if(os.path.exists(cname)):
+ print("Already synced to: " + str(self.username))
+ return
+ else:
+ os.mkdir(cname)
+ f=open(cname + "/README.md", "w")
+ f.close()
+ #push to remote repo
+ os.chdir(cname)
+ command(self, 'git init')
+ command(self, 'git add .')
+ command(self, 'git commit -m "Hello Class!"')
+ #git remote add origin git@github.com:alexpchin/.git
+ command(self, 'git remote add origin git@github.com:'+ self.git + "/" + cname + ".git")
+ command(self, 'git push -u origin master')
+
+ cinfo=[
+ {
+ "name":cname,
+ "assignments":[],
+ "repo": "https://github.com:" + self.git + "/" + cname + ".git",
+ "default_file": [
+ {
+ "name":"README.md"
+ }
+ ]
+ }
+ ]
+
+ #update rest API
+ self.classes.append(cinfo)
+ update(self)
+ data = {
+ "url": self.url,
+ "first_name": self.first_name,
+ "last_name": self.first_name,
+ "classes": self.classes,
+ "git": self.git,
+ "ion_user": self.username
+ },
+ r = requests.put(url = self.url, data= data, headers={'Content-type': 'application/json'} ,auth=('raffukhondaker','hackgroup1'))
+
+#make student repo by student id
+ def addStudent(self,stid):
+ print(stid)
+
+ def comment(self):
+ print("heheheh")
+
+# data = getData("eharris1")
+data={'url': 'http://127.0.0.1:8000/teachers/eharris1/', 'first_name': 'Errin', 'last_name': 'Harris', 'git': 'therealraffi', 'ion_user': 'eharris1', 'classes': [{'url': 'http://127.0.0.1:8000/classes/1/', 'name': 'Math5_eharris1', 'repo': 'http://127.0.0.1:8000/assignments/3/', 'assignments': [{'name': 'Week1_HW', 'due_date': '2020-06-07T07:46:30.537197Z', 'url': 'http://127.0.0.1:8000/assignments/1/', 'files': [{'name': 'instructions.txt'}]}, {'name': 'Week2_HW', 'due_date': '2020-06-07T07:46:30.548596Z', 'url': 'http://127.0.0.1:8000/assignments/2/', 'files': [{'name': 'instructions.txt'}]}], 'default_file': [{'name': 'instructions.txt'}]}]}
+t = Teacher(data)
+t.update()
+
+
diff --git a/CLI/t-git.py b/CLI/t-git.py
new file mode 100644
index 0000000..9c2f4e9
--- /dev/null
+++ b/CLI/t-git.py
@@ -0,0 +1,366 @@
+import subprocess
+import os
+import requests
+import webbrowser
+import pprint
+import json
+import shutil
+import time
+import pyperclip
+
+#git clone student directory ==> /classes/assignments
+
+#get teacher info from api
+def getTeacher(ion_user):
+ URL = "http://127.0.0.1:8000/teachers/" + ion_user + "/"
+ r = requests.get(url = URL, auth=('raffukhondaker','hackgroup1'))
+ if(r.status_code == 200):
+ data = r.json()
+ return data
+ elif(r.status_code == 404):
+ return None
+ print("Make new account!")
+ elif(r.status_code == 403):
+ return None
+ print("Invalid username/password")
+ else:
+ return None
+ print(r.status_code)
+
+def getDB(url):
+ r = requests.get(url = url, auth=('raffukhondaker','hackgroup1'))
+ print("GET:" + str(r.status_code))
+ return(r.json())
+
+def postDB(data, url):
+ r = requests.post(url = url, data=data, auth=('raffukhondaker','hackgroup1'))
+ print("POST:" + str(r.status_code))
+ return(r.json())
+
+def putDB(data, url):
+ r = requests.put(url = url, data=data, auth=('raffukhondaker','hackgroup1'))
+ print("PUT:" + str(r.status_code))
+ return(r.json())
+
+def delDB(url):
+ r = requests.delete(url = url, auth=('raffukhondaker','hackgroup1'))
+ print("DELETE:" + str(r.status_code))
+ return None
+
+def command(command):
+ ar = []
+ command = command.split(" ")
+ for c in command:
+ ar.append(c)
+ process = subprocess.Popen(ar, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+ p=process.poll()
+ output = process.communicate()[1]
+ #print(output.decode('utf-8'))
+
+#public methods: deleteClass, makeClass, update
+class Teacher:
+ def __init__(self, data):
+ # teacher info already stored in API
+ # intitialze fields after GET request
+ self.first_name=data['first_name']
+ self.last_name=data['last_name']
+ self.git=data['git']
+ self.username=data['ion_user']
+ self.url= "http://127.0.0.1:8000/teachers/" + self.username + "/"
+ #classes in id form (Example: 4,5)
+
+ cid=data['classes'].split(",")
+ try:
+ cid.remove('')
+ except:
+ pass
+ try:
+ cid.remove("")
+ except:
+ pass
+ classes=[]
+ for c in cid:
+ url = "http://127.0.0.1:8000/classes/" + str(c) + "/"
+ classes.append(getDB(url))
+
+ self.classes = classes
+ self.sclass=str(data['classes'])
+ if(os.path.isdir(self.username)):
+ print("Synced to " + self.username)
+ else:
+ os.mkdir(self.username)
+
+ #update API and Github, all assignments / classes
+ def update(self):
+ #lists all classes
+ ignore=['.git','.DS_Store']
+ classes = os.listdir(self.username)
+ for i in ignore:
+ try:
+ classes.remove(i)
+ except:
+ pass
+ #list of classes that have been deleted (not with deleteClass)
+ extra = []
+ for c in self.classes:
+ extra.append(c)
+ for i in range(len(extra)):
+ e = extra[i]['path']
+ extra[i] = e
+ print("Extra: "+str(extra))
+ print("Local:" + str(classes))
+ #checks all class directories first
+ for c in classes:
+ path = self.username + "/" + c
+ if(self.checkClass(path) == False):
+ return
+ extra.remove(path)
+ print("Current classes: " + path)
+
+ for e in extra:
+ self.deleteClass(e)
+
+ for i in range(len(classes)):
+ c = classes[i]
+ path = self.username + "/" + c
+ #lists all assignments and default files
+ #if no .git, directory not synced to git or API
+ if (self.checkInDB(path)==False):
+ self.addClass(path)
+ else:
+ #push to git
+ loc = os.getcwd()
+ os.chdir(path)
+ command('git fetch origin')
+ command('git pull origin master')
+ command('git add .')
+ command('git commit -m "Update"')
+ command('git push -u origin master')
+ os.chdir(loc)
+
+ #class name format: _
+
+ #turn existing directory into class, Pre-condition: directory exists
+ #relative path to class: 2022rkhondak/Math4
+ def checkClass(self,path):
+ cname = path.split("/")
+ cname = cname[len(cname)-1]
+ if(os.path.isfile(path)):
+ print(path + " must be in a Class directory.")
+ return False
+ if(("_" + self.username) in cname) == False:
+ print("Incorrect class name: Must be in the format: " + self.username+ "/_, not " + path)
+ return False
+ dirs = os.listdir(path)
+ #checks if there is a file (not within Assignments) in class, need at least 1
+ deffile = False
+ #checks if there is a file in an Assignment, need at least 1 (default True in case no assignments)
+ as_file = True
+ as_bad = ""
+
+ for d in dirs:
+ if(os.path.isfile(d)):
+ deffile=True
+ else:
+ #checks if there is a file in an Assignment, need at least 1
+ as_file = False
+ asdir = os.listdir(path + "/" + d)
+ for a in asdir:
+ if(os.path.isfile(path + "/" + d + "/" +a)):
+ as_file=True
+ if(as_file==False):
+ as_bad = d
+ break
+ if(as_file==False):
+ print("Assignment '" + as_bad + "' does not have a default file!")
+ return False
+
+ if(deffile==False):
+ print("Need a default file in the " + path + " Directory!")
+ return False
+ return True
+
+ def checkInDB(self, path):
+ n = path.split("/")
+ n = n[len(n)-1]
+ for c in self.classes:
+ if(n == c['name']):
+ return True
+ return False
+
+ #adds class to git, not API
+ #Assuming valid class name
+ def addClasstoGit(self, path):
+ cname = path.split("/")
+ cname = cname[len(cname)-1]
+ #push to remote repo
+ url='https://github.com/' + self.git + "/" + cname
+ if(requests.get(url).status_code != 200):
+ input("Make new Git Repo with name: " + cname + " (Press any key to continue)\n")
+ try:
+ pyperclip.copy(cname)
+ print(cname + " copied to clipboard.")
+ except:
+ pass
+ time.sleep(2)
+ webbrowser.open('https://github.com/new')
+ input("Repo created? (Press any key to continue)\n")
+
+ print(url)
+ while(requests.get(url).status_code != 200):
+ r = input("Repo not created yet. (Press any key to continue after repo created, or 'N' to exit)\n")
+ if(r=="N" or r=="No"):
+ return None
+ cdir = os.getcwd()
+ os.chdir(path)
+ command('git init')
+ command('git add .')
+ command('git commit -m Hello_Class')
+ command('git remote add origin ' + url + '.git')
+ command('git push -u origin master')
+ else:
+ cdir = os.getcwd()
+ os.chdir(path)
+ print("Repo already exists. Cloning instead.")
+ command('git clone')
+ command('git fetch origin')
+ command('git pull')
+ command('git add .')
+ command('git commit -m Hello_Class')
+ command('git push -u origin master')
+ os.chdir(cdir)
+ print(cdir)
+ data={
+ 'name':cname,
+ 'repo':url,
+ 'path':path,
+ 'teacher':self.username
+ }
+ return data
+
+ #make class from existing directory, add to git and api
+ def addClass(self, path):
+ if (self.checkClass(path)):
+ data = self.addClasstoGit(path)
+ #make class instance in db
+ data = postDB(data, 'http://127.0.0.1:8000/classes/')
+ #add to instance
+ #upate self.classes
+ self.classes.append(data)
+ if(len(self.sclass)==0):
+ self.sclass = data['id']
+ else:
+ self.sclass = self.sclass + "," + str(data['id'])
+
+ #update teacher instance in db, classes field
+ data={
+ 'first_name':self.first_name,
+ 'last_name':self.last_name,
+ 'git':self.git,
+ 'ion_user':self.username,
+ 'url':self.url,
+ 'classes':self.sclass
+ }
+ putDB(data, self.url)
+
+ return data
+
+
+ #make a new class from scratch
+ #subject: string, assignments: list
+ #class name must be: _
+ def makeClass(self, cname, assignments):
+ #check if class exists
+ path = self.username + "/" + cname
+ if(os.path.exists(path)):
+ print("Class already exists: " + cname)
+ return
+ else:
+ if((("_" + self.username) in cname) == False):
+ print("class name must be: "+ cname + "_" + self.username)
+ return
+ cdir = os.getcwd()
+ os.mkdir(path)
+ f=open(path + "/README.md", "w")
+ f.close()
+ #push to remote repo
+ os.chdir(path)
+ for a in assignments:
+ os.mkdir(a)
+ f=open(a + "/instructions.txt", "w")
+ f.close()
+ os.chdir(cdir)
+
+ data = self.addClass(path)
+ return data
+
+ def deleteClass(self, path):
+ if(os.path.exists(path) == False):
+ print(path + " does not exist locally.")
+ resp = input("Do you want to delete " + path + " from the SkoolOS system? (y/N) ")
+ if(resp != 'y'):
+ return
+
+ cname = path.split("/")
+ cname = cname[len(cname)-1]
+ cid = None
+ repo = ''
+ for c in self.classes:
+ if cname == c['name']:
+ cid = str(c['id'])
+ repo = c['repo']
+
+ #remove from api
+ for i in range(len(self.classes)):
+ if(self.classes[i]['id'] == int(cid)):
+ print("DELETE: " + self.classes[i]['name'])
+ del self.classes[i]
+ s=""
+ #recreate sclass field, using ids
+ for c in self.classes:
+ s = s + str(c['id']) + ","
+ print(s)
+ s = s[:-1]
+ print(s)
+ data={
+ 'first_name':self.first_name,
+ 'last_name':self.last_name,
+ 'git':self.git,
+ 'ion_user':self.username,
+ 'url':self.url,
+ 'classes':s
+ }
+ print(putDB(data, self.url))
+ delDB("http://127.0.0.1:8000/classes/" + cid + "/")
+ break
+
+ #remove locally
+ try:
+ shutil.rmtree(path)
+ except:
+ pass
+
+ #remove from git
+ input("Delete repository: " + cname + ". Scroll to the bottom of the page and press 'Delete this repository' (Press any key to continue) ")
+ print(repo)
+ time.sleep(2)
+ webbrowser.open(repo + "/settings")
+ input("Repo deleted? (Press any key to continue) ")
+
+ print(repo)
+ while(requests.get(repo).status_code == 200):
+ r = input("Repo still no deleted yet. (Press any key to continue after repo deleted, or 'N' to exit)\n")
+ if(r=="N" or r=="No" or r=='n'):
+ return None
+
+#make student repo by student id
+ def addStudent(self,stid):
+ print(stid)
+
+ def comment(self):
+ print("heheheh")
+
+data = getTeacher("eharris1")
+t = Teacher(data)
+t.makeClass('English11_eharris1', ["Essay1"])
+t.update()
diff --git a/CLI/test.py b/CLI/test.py
new file mode 100644
index 0000000..11389ac
--- /dev/null
+++ b/CLI/test.py
@@ -0,0 +1,16 @@
+import subprocess
+import os
+import time
+
+def command(command):
+ ar = []
+ command = command.split(" ")
+ for c in command:
+ ar.append(c)
+ process = subprocess.Popen(ar, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+ p=process.poll()
+ output = process.communicate()[0]
+ print(output)
+
+command('echo hello')
+command('python runtest.py')
diff --git a/CLI/text.py b/CLI/text.py
new file mode 100644
index 0000000..60b8cca
--- /dev/null
+++ b/CLI/text.py
@@ -0,0 +1,2 @@
+import textract
+text = textract.process('test.py')
\ No newline at end of file
diff --git a/CLI/users.json b/CLI/users.json
deleted file mode 100644
index bf1713e..0000000
--- a/CLI/users.json
+++ /dev/null
@@ -1 +0,0 @@
-[{"first_name": "Raffu", "last_name": "Khondaker", "password": "password", "webmail": "2022rkhondak@tjhsst.edu", "classes": {"Math": ["week1_hw", "week2_hw", "week3_hw", "unit3_quiz"], "English": ["journal1", "journal2", "journal3"]}}]
\ No newline at end of file
diff --git a/Website/api/__init__.py b/Website/api/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/Website/api/admin.py b/Website/api/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/Website/api/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/Website/api/apps.py b/Website/api/apps.py
new file mode 100644
index 0000000..d87006d
--- /dev/null
+++ b/Website/api/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class ApiConfig(AppConfig):
+ name = 'api'
diff --git a/Website/api/auth.py b/Website/api/auth.py
new file mode 100644
index 0000000..e69de29
diff --git a/Website/api/maker.py b/Website/api/maker.py
new file mode 100644
index 0000000..dd31bb6
--- /dev/null
+++ b/Website/api/maker.py
@@ -0,0 +1,128 @@
+from datetime import datetime
+
+f1 = DefFiles(
+ name="instructions.txt"
+)
+f1.save()
+f2 = DefFiles(
+ name="instructions.txt"
+)
+f2.save()
+f3 = DefFiles(
+ name="sample.txt"
+)
+f3.save()
+f4 = DefFiles(
+ name="rubric.txt"
+)
+f4.save()
+
+a1 = Assignment.objects.get(pk=1)
+a1.files.add(f1)
+a1.save()
+a2 = Assignment.objects.get(pk=2)
+a2.files.add(f2)
+a2.save()
+a3 = Assignment.objects.get(pk=3)
+a3.files.add(f3)
+a3.files.add(f4)
+a3.save()
+
+####################################
+
+from api.models import Assignment, Student, Classes, Teacher, DefFiles
+from datetime import datetime
+
+f1 = DefFiles(
+ name="instructions.txt"
+)
+f1.save()
+f2 = DefFiles(
+ name="instructions.txt"
+)
+f2.save()
+f3 = DefFiles(
+ name="sample.txt"
+)
+f3.save()
+f4 = DefFiles(
+ name="rubric.txt"
+)
+f4.save()
+
+A1 = Assignment(
+ name='Week1_HW',
+ due_date=datetime.now(),
+)
+A1.save()
+A1.files.add(f1)
+A1.save()
+
+A2 = Assignment(
+ name='Week2_HW',
+ due_date=datetime.now(),
+
+)
+A2.save()
+A2.files.add(f2)
+A2.save()
+
+A3 = Assignment(
+ name='Journal1',
+ due_date=datetime.now(),
+)
+A3.save()
+A3.files.add(f3)
+A3.files.add(f4)
+A3.save()
+
+#classes
+math = Classes(
+ name='Math5',
+
+)
+math.save()
+math.assignments.add(A1)
+math.assignments.add(A2)
+math.save()
+
+english = Classes(
+ name='English',
+)
+english.save()
+english.assignments.add(A3)
+english.save()
+
+#students
+raffu = Student(
+ first_name = "Raffu",
+ last_name = "Khondaker",
+ student_id = 1579460,
+ ion_user="2022rkhondak",
+ webmail = "2022rkhondak@tjhsst.edu",
+ grade = 10,
+ repo="https://github.com/therealraffi/2022rkhondak.git",
+)
+raffu.save()
+raffu.classes.add(math)
+raffu.classes.add(english)
+raffu.save()
+
+#teachers
+ng = Teacher(
+ first_name = "Errin",
+ last_name = "Harris",
+ ion_user="eharris1"
+)
+ng.save()
+ng.classes.add(math)
+ng.save()
+
+chao = Teacher(
+ first_name = "Abagail",
+ last_name = "Bailey",
+ ion_user="AKBailey"
+)
+chao.save()
+chao.classes.add(english)
+chao.save()
diff --git a/Website/api/migrations/0001_initial.py b/Website/api/migrations/0001_initial.py
new file mode 100644
index 0000000..11b47e4
--- /dev/null
+++ b/Website/api/migrations/0001_initial.py
@@ -0,0 +1,75 @@
+# Generated by Django 3.0.7 on 2020-06-09 02:03
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Assignment',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=100)),
+ ('due_date', models.DateTimeField()),
+ ('files', models.CharField(max_length=100)),
+ ('path', models.CharField(max_length=100)),
+ ('classes', models.CharField(max_length=100)),
+ ('teacher', models.CharField(max_length=100)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Classes',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=100)),
+ ('repo', models.URLField(default='')),
+ ('path', models.CharField(default='', max_length=100)),
+ ('teacher', models.CharField(default='', max_length=100)),
+ ('assignments', models.CharField(default='', max_length=100)),
+ ('default_file', models.CharField(default='', max_length=100)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='DefFiles',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=100)),
+ ('path', models.CharField(max_length=100)),
+ ('assignment', models.CharField(default='', max_length=100)),
+ ('classes', models.CharField(max_length=100)),
+ ('teacher', models.CharField(max_length=100)),
+ ],
+ ),
+ 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(default='', max_length=100)),
+ ('ion_user', models.CharField(max_length=100, primary_key=True, serialize=False)),
+ ('git', models.CharField(max_length=100)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Student',
+ fields=[
+ ('created', models.DateTimeField(auto_now_add=True)),
+ ('first_name', models.CharField(max_length=100)),
+ ('last_name', models.CharField(max_length=100)),
+ ('student_id', models.IntegerField()),
+ ('ion_user', models.CharField(max_length=100, primary_key=True, serialize=False)),
+ ('webmail', models.EmailField(blank=True, max_length=254)),
+ ('grade', models.IntegerField()),
+ ('git', models.CharField(max_length=100)),
+ ('repo', models.URLField(default='')),
+ ('classes', models.ManyToManyField(default='', to='api.Classes')),
+ ],
+ ),
+ ]
diff --git a/Website/api/migrations/0002_auto_20200609_0358.py b/Website/api/migrations/0002_auto_20200609_0358.py
new file mode 100644
index 0000000..bb2af02
--- /dev/null
+++ b/Website/api/migrations/0002_auto_20200609_0358.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.0.7 on 2020-06-09 03:58
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='teacher',
+ name='classes',
+ field=models.CharField(blank=True, default='', max_length=100),
+ ),
+ ]
diff --git a/Website/api/migrations/__init__.py b/Website/api/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/Website/api/models.py b/Website/api/models.py
new file mode 100644
index 0000000..a8770e4
--- /dev/null
+++ b/Website/api/models.py
@@ -0,0 +1,59 @@
+from django.db import models
+
+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):
+ name=models.CharField(max_length=100)
+ due_date=models.DateTimeField()
+ # files = models.ManyToManyField(DefFiles)
+ files=models.CharField(max_length=100)
+ 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):
+ name = models.CharField(max_length=100)
+ repo=models.URLField(default="")
+ path=models.CharField(max_length=100, default="")
+ teacher=models.CharField(max_length=100, default="")
+ assignments=models.CharField(max_length=100, default="")
+ default_file=models.CharField(max_length=100, default="")
+
+ # 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):
+ created = models.DateTimeField(auto_now_add=True)
+ first_name = models.CharField(max_length=100)
+ last_name = models.CharField(max_length=100)
+ # 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)
+
+class Student(models.Model):
+ created = models.DateTimeField(auto_now_add=True)
+ first_name = models.CharField(max_length=100)
+ last_name = models.CharField(max_length=100)
+ student_id = models.IntegerField()
+ ion_user=models.CharField(primary_key=True, max_length=100)
+ webmail = models.EmailField(blank=True)
+ grade = models.IntegerField()
+ git=models.CharField(max_length=100)
+ classes = models.ManyToManyField(Classes, default="")
+ repo = models.URLField(default="")
+
+ def save(self, *args, **kwargs):
+ return super(Student, self).save(*args, **kwargs)
+
+
+
diff --git a/Website/api/serializers.py b/Website/api/serializers.py
new file mode 100644
index 0000000..ca13238
--- /dev/null
+++ b/Website/api/serializers.py
@@ -0,0 +1,37 @@
+from django.contrib.auth.models import User, Group
+from .models import Student, Teacher, Classes, Assignment, DefFiles
+from rest_framework import serializers, permissions
+
+class DefFilesSerializer(serializers.HyperlinkedModelSerializer):
+ permissions_classes = [permissions.IsAuthenticatedOrReadOnly]
+ class Meta:
+ model = DefFiles
+ fields = ['name', 'path','assignment','classes', "teacher",'url', 'id']
+
+class AssignmentSerializer(serializers.HyperlinkedModelSerializer):
+ permissions_classes = [permissions.IsAuthenticatedOrReadOnly]
+ # files = DefFilesSerializer(many=True, read_only=True,allow_null=True)
+ class Meta:
+ model = Assignment
+ fields = ['name', 'due_date', 'url', 'path' , "classes","teacher",'files', 'id']
+
+class ClassesSerializer(serializers.HyperlinkedModelSerializer):
+ # assignments = AssignmentSerializer(many=True, read_only=True,allow_null=True)
+ # default_file=DefFilesSerializer(many=True, read_only=True,allow_null=True)
+ class Meta:
+ model = Classes
+ fields = ['url', 'name', 'repo','path', "teacher",'assignments',"default_file",'id']
+
+class StudentSerializer(serializers.HyperlinkedModelSerializer):
+ classes = ClassesSerializer(many=True, read_only=True,allow_null=True)
+ class Meta:
+ model = Student
+ fields = ['url', 'first_name', 'last_name', 'grade','webmail','student_id', 'git','repo','ion_user','classes']
+
+class TeacherSerializer(serializers.ModelSerializer):
+ # classes = ClassesSerializer(many=True, read_only=True,allow_null=True)
+ class Meta:
+ model = Teacher
+ fields = ['url', 'first_name', 'last_name','git','ion_user','classes']
+
+
diff --git a/Website/api/tests.py b/Website/api/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/Website/api/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/Website/api/urls.py b/Website/api/urls.py
new file mode 100644
index 0000000..e69de29
diff --git a/Website/api/views-back.py b/Website/api/views-back.py
new file mode 100644
index 0000000..5c936f9
--- /dev/null
+++ b/Website/api/views-back.py
@@ -0,0 +1,131 @@
+# class StudentList(APIView):
+# """
+# List all snippets, or create a new snippet.
+# """
+# def get(self, request, format=None):
+# snippets = Student.objects.all()
+# serializer = StudentSerializer(snippets, many=True)
+# return response.Response(serializer.data)
+
+# def post(self, request, format=None):
+# serializer = StudentSerializer(data=request.data)
+# if serializer.is_valid():
+# serializer.save()
+# return response.Response(serializer.data, status=status.HTTP_201_CREATED)
+# return response.Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+# class StudentDetail(APIView):
+# """
+# Retrieve, update or delete a snippet instance.
+# """
+# def get_object(self, pk):
+# try:
+# return Student.objects.get(pk=pk)
+# except Student.DoesNotExist:
+# raise Http404
+
+# def get(self, request, pk, format=None):
+# snippet = self.get_object(pk)
+# serializer = StudentSerializer(snippet)
+# return response.Response(serializer.data)
+
+# def put(self, request, pk, format=None):
+# snippet = self.get_object(pk)
+# serializer = StudentSerializer(snippet, data=request.data)
+# if serializer.is_valid():
+# serializer.save()
+# return response.Response(serializer.data)
+# return response.Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+# def delete(self, request, pk, format=None):
+# snippet = self.get_object(pk)
+# snippet.delete()
+# return response.Response(status=status.HTTP_204_NO_CONTENT)
+
+# class TeacherList(APIView):
+# """
+# List all snippets, or create a new snippet.
+# """
+# def get(self, request, format=None):
+# snippets = Teacher.objects.all()
+# serializer = TeacherSerializer(snippets, many=True)
+# return response.Response(serializer.data)
+
+# def post(self, request, format=None):
+# serializer = TeacherSerializer(data=request.data)
+# if serializer.is_valid():
+# serializer.save()
+# return response.Response(serializer.data, status=status.HTTP_201_CREATED)
+# return response.Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+# class TeacherDetail(APIView):
+# """
+# Retrieve, update or delete a snippet instance.
+# """
+# def get_object(self, pk):
+# try:
+# return Teacher.objects.get(pk=pk)
+# except Teacher.DoesNotExist:
+# raise Http404
+
+# def get(self, request, pk, format=None):
+# snippet = self.get_object(pk)
+# serializer = TeacherSerializer(snippet)
+# return response.Response(serializer.data)
+
+# def put(self, request, pk, format=None):
+# snippet = self.get_object(pk)
+# serializer = TeacherSerializer(snippet, data=request.data)
+# if serializer.is_valid():
+# serializer.save()
+# return response.Response(serializer.data)
+# return response.Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+# def delete(self, request, pk, format=None):
+# snippet = self.get_object(pk)
+# snippet.delete()
+# return response.Response(status=status.HTTP_204_NO_CONTENT)
+
+# class ClassesList(APIView):
+# """
+# List all snippets, or create a new snippet.
+# """
+# def get(self, request, format=None):
+# snippets = Classes.objects.all()
+# serializer = ClassesSerializer(snippets, many=True)
+# return response.Response(serializer.data)
+
+# def post(self, request, format=None):
+# serializer = ClassesSerializer(data=request.data)
+# if serializer.is_valid():
+# serializer.save()
+# return response.Response(serializer.data, status=status.HTTP_201_CREATED)
+# return response.Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+# class ClassesDetail(APIView):
+# """
+# Retrieve, update or delete a snippet instance.
+# """
+# def get_object(self, pk):
+# try:
+# return Classes.objects.get(pk=pk)
+# except Classes.DoesNotExist:
+# raise Http404
+
+# def get(self, request, pk, format=None):
+# snippet = self.get_object(pk)
+# serializer = ClassesSerializer(snippet)
+# return response.Response(serializer.data)
+
+# def put(self, request, pk, format=None):
+# snippet = self.get_object(pk)
+# serializer = ClassesSerializer(snippet, data=request.data)
+# if serializer.is_valid():
+# serializer.save()
+# return response.Response(serializer.data)
+# return response.Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+# def delete(self, request, pk, format=None):
+# snippet = self.get_object(pk)
+# snippet.delete()
+# return response.Response(status=status.HTTP_204_NO_CONTENT)
\ No newline at end of file
diff --git a/Website/api/views.py b/Website/api/views.py
new file mode 100644
index 0000000..439c30b
--- /dev/null
+++ b/Website/api/views.py
@@ -0,0 +1,48 @@
+from .models import Student, Teacher, Classes, Assignment, DefFiles
+from .serializers import StudentSerializer, TeacherSerializer, ClassesSerializer, AssignmentSerializer, DefFilesSerializer
+from rest_framework import generics, viewsets, permissions, response, status
+from django.http import Http404
+from rest_framework.views import APIView
+
+class StudentViewSet(viewsets.ModelViewSet):
+ """
+ API endpoint that allows users to be viewed or edited.
+ """
+ queryset = Student.objects.all()
+ serializer_class = StudentSerializer
+ permissions_classes = [permissions.IsAuthenticatedOrReadOnly]
+
+
+class TeacherViewSet(viewsets.ModelViewSet):
+ """
+ API endpoint that allows users to be viewed or edited.
+ """
+ queryset = Teacher.objects.all()
+ serializer_class = TeacherSerializer
+ permissions_classes = [permissions.IsAuthenticatedOrReadOnly]
+
+
+class ClassesViewSet(viewsets.ModelViewSet):
+ """
+ API endpoint that allows users to be viewed or edited.
+ """
+ queryset = Classes.objects.all()
+ serializer_class = ClassesSerializer
+ permissions_classes = [permissions.IsAuthenticatedOrReadOnly]
+
+
+class AssignmentViewSet(viewsets.ModelViewSet):
+ """
+ API endpoint that allows users to be viewed or edited.
+ """
+ queryset = Assignment.objects.all()
+ serializer_class = AssignmentSerializer
+ permissions_classes = [permissions.IsAuthenticatedOrReadOnly]
+
+class DefFilesViewSet(viewsets.ModelViewSet):
+ """
+ API endpoint that allows users to be viewed or edited.
+ """
+ queryset = DefFiles.objects.all()
+ serializer_class = DefFilesSerializer
+ permissions_classes = [permissions.IsAuthenticatedOrReadOnly]
diff --git a/Website/manage.py b/Website/manage.py
new file mode 100755
index 0000000..063e014
--- /dev/null
+++ b/Website/manage.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'skoolsite.settings')
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/Website/skoolsite/__init__.py b/Website/skoolsite/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/Website/skoolsite/asgi.py b/Website/skoolsite/asgi.py
new file mode 100644
index 0000000..805af95
--- /dev/null
+++ b/Website/skoolsite/asgi.py
@@ -0,0 +1,16 @@
+"""
+ASGI config for skoolsite project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'skoolsite.settings')
+
+application = get_asgi_application()
diff --git a/Website/skoolsite/settings.py b/Website/skoolsite/settings.py
new file mode 100644
index 0000000..b5bda98
--- /dev/null
+++ b/Website/skoolsite/settings.py
@@ -0,0 +1,131 @@
+"""
+Django settings for skoolsite project.
+
+Generated by 'django-admin startproject' using Django 3.0.7.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.0/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/3.0/ref/settings/
+"""
+
+import os
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = '$v+-0wm%yys7r3&e0s&*tyh-vyc9v&twb_8yk6==290io9yq3('
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'rest_framework',
+ 'api',
+
+]
+
+REST_FRAMEWORK = {
+ 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
+ 'PAGE_SIZE': 10,
+ 'DEFAULT_PERMISSION_CLASSES': [
+ 'rest_framework.permissions.IsAuthenticated',
+ ]
+}
+
+MIDDLEWARE = [
+ 'django.middleware.security.SecurityMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'skoolsite.urls'
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.request',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = 'skoolsite.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/3.0/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/3.0/howto/static-files/
+
+STATIC_URL = '/static/'
diff --git a/Website/skoolsite/urls.py b/Website/skoolsite/urls.py
new file mode 100644
index 0000000..1c8f9f2
--- /dev/null
+++ b/Website/skoolsite/urls.py
@@ -0,0 +1,22 @@
+from django.urls import path
+from rest_framework import routers
+from api import views
+from django.contrib import admin
+from django.conf.urls import include
+
+router = routers.DefaultRouter()
+router.register(r'students', views.StudentViewSet)
+router.register(r'teachers', views.TeacherViewSet)
+router.register(r'assignments', views.AssignmentViewSet)
+router.register(r'classes', views.ClassesViewSet)
+router.register(r'files', views.DefFilesViewSet)
+
+
+# Wire up our API using automatic URL routing.
+# Additionally, we include login URLs for the browsable API.
+urlpatterns = [
+ path('', include(router.urls)),
+ path('api-auth/', include('rest_framework.urls')),
+ path('admin/', admin.site.urls),
+
+]
\ No newline at end of file
diff --git a/Website/skoolsite/wsgi.py b/Website/skoolsite/wsgi.py
new file mode 100644
index 0000000..c3b05f8
--- /dev/null
+++ b/Website/skoolsite/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for skoolsite project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'skoolsite.settings')
+
+application = get_wsgi_application()
diff --git a/Website/templates/base.html b/Website/templates/base.html
new file mode 100644
index 0000000..664dcf4
--- /dev/null
+++ b/Website/templates/base.html
@@ -0,0 +1,3 @@
+
+{% block page_content %}
+{% endblock %}
diff --git a/Website/templates/oauth2_provider/authorize.html b/Website/templates/oauth2_provider/authorize.html
new file mode 100644
index 0000000..e69de29
diff --git a/Website/templates/oauth2_provider/logged_out.html b/Website/templates/oauth2_provider/logged_out.html
new file mode 100644
index 0000000..52cdfa1
--- /dev/null
+++ b/Website/templates/oauth2_provider/logged_out.html
@@ -0,0 +1,6 @@
+{% extends "base.html" %}
+
+{% block content %}
+ Logged out!
+ Click here to login again.
+{% endblock %}
\ No newline at end of file
diff --git a/Website/templates/oauth2_provider/login.html b/Website/templates/oauth2_provider/login.html
new file mode 100644
index 0000000..5018145
--- /dev/null
+++ b/Website/templates/oauth2_provider/login.html
@@ -0,0 +1,37 @@
+{% extends "base.html" %}
+
+{% block page_content %}
+
+ {% if form.errors %}
+ Your username and password didn't match. Please try again.
+ {% endif %}
+
+ {% if next %}
+ {% if user.is_authenticated %}
+ Your account doesn't have access to this page. To proceed,
+ please login with an account that has access.
+ {% else %}
+ Please login to see this page.
+ {% endif %}
+ {% endif %}
+
+
+
+ {# Assumes you setup the password_reset view in your URLconf #}
+ Lost password?
+
+{% endblock %}
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index a73f1cc..fbc7e54 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,21 @@
+asgiref==3.2.7
+certifi==2020.4.5.1
+chardet==3.0.4
+click==7.1.2
+Django==3.0.7
+django-cors-middleware==1.5.0
+django-oauth-toolkit==1.3.2
+djangorestframework==3.11.0
+idna==2.9
+oauthlib==3.1.0
prompt-toolkit==1.0.14
Pygments==2.6.1
PyInquirer==1.0.3
+pytz==2020.1
regex==2020.5.14
+requests==2.23.0
+selenium==3.141.0
six==1.15.0
+sqlparse==0.3.1
+urllib3==1.25.9
wcwidth==0.2.3
diff --git a/runtest.py b/runtest.py
new file mode 100644
index 0000000..837cd82
--- /dev/null
+++ b/runtest.py
@@ -0,0 +1,2 @@
+for i in range(0, 100000):
+ print(i)
\ No newline at end of file