Merge branch 'development' of https://github.com/Rushilwiz/SkoolOS into development

This commit is contained in:
Raffu Khondaker 2020-06-16 19:46:18 -04:00
commit 92ff41ba60
9 changed files with 342 additions and 270 deletions

View File

@ -14,22 +14,28 @@ import datetime
# get teacher info from api # get teacher info from api
def getStudent(ion_user, password): def getStudent(ion_user, password):
"""
Get's student information from the api
:param ion_user: a student
:return: student information or error
"""
URL = "http://127.0.0.1:8000/api/students/" + ion_user + "/" URL = "http://127.0.0.1:8000/api/students/" + ion_user + "/"
r = requests.get(url=URL, auth=(ion_user, password)) r = requests.get(url=URL, auth=(ion_user, password))
if (r.status_code == 200): if (r.status_code == 200):
data = r.json() data = r.json()
return data return data
elif (r.status_code == 404): elif r.status_code == 404:
return None return None
print("Make new account!") print("Make new account!")
elif (r.status_code == 403): elif r.status_code == 403:
return None return None
print("Invalid username/password") print("Invalid username/password")
else: else:
return None return None
print(r.status_code) print(r.status_code)
#makes a GET request to given url, returns dict
# makes a GET request to given url, returns dict
def getDB(user, pwd, url): def getDB(user, pwd, url):
""" """
Sends a GET request to the URL Sends a GET request to the URL
@ -37,9 +43,10 @@ def getDB(user, pwd, url):
""" """
r = requests.get(url=url, auth=(user, pwd)) r = requests.get(url=url, auth=(user, pwd))
print("GET:" + str(r.status_code)) print("GET:" + str(r.status_code))
return(r.json()) return r.json()
#makes a PATCH (updates instance) request to given url, returns dict
# makes a PATCH (updates instance) request to given url, returns dict
def patchDB(user, pwd, data, url): def patchDB(user, pwd, data, url):
""" """
Sends a PATCH request to the URL Sends a PATCH request to the URL
@ -51,7 +58,7 @@ def patchDB(user, pwd, data, url):
return r.json() return r.json()
#makes a POST (makes new instance) request to given url, returns dict # makes a POST (makes new instance) request to given url, returns dict
def postDB(user, pwd, data, url): def postDB(user, pwd, data, url):
""" """
Sends a POST request to the URL Sends a POST request to the URL
@ -63,7 +70,7 @@ def postDB(user, pwd, data, url):
return r.json() return r.json()
#makes a PUT (overwrites instance) request to given url, returns dict # makes a PUT (overwrites instance) request to given url, returns dict
def putDB(user, pwd, data, url): def putDB(user, pwd, data, url):
""" """
Sends a PUT request to the URL Sends a PUT request to the URL
@ -75,7 +82,7 @@ def putDB(user, pwd, data, url):
return r.json() return r.json()
#makes a DELETE (delete instance) request to given url, returns dict # makes a DELETE (delete instance) request to given url, returns dict
def delDB(user, pwd, url): def delDB(user, pwd, url):
""" """
Sends a DELETE request to the URL Sends a DELETE request to the URL
@ -87,6 +94,10 @@ def delDB(user, pwd, url):
def command(command): def command(command):
"""
Runs a shell command
:param command: shell command
"""
ar = [] ar = []
command = command.split(" ") command = command.split(" ")
for c in command: for c in command:
@ -105,6 +116,10 @@ class Student:
def __init__(self, data, password): def __init__(self, data, password):
# teacher info already stored in API # teacher info already stored in API
# intitialze fields after GET request # intitialze fields after GET request
"""
Initializes a Student with data from the api
:param data: api data
"""
self.git = data['git'] self.git = data['git']
self.username = data['ion_user'] self.username = data['ion_user']
self.url = "http://127.0.0.1:8000/api/students/" + self.username + "/" self.url = "http://127.0.0.1:8000/api/students/" + self.username + "/"
@ -151,8 +166,8 @@ class Student:
self.snew = str(data['added_to']) self.snew = str(data['added_to'])
self.repo = data['repo'] self.repo = data['repo']
if (os.path.isdir(self.username) == False): if os.path.isdir(self.username) == False:
if (self.repo == ""): if self.repo == "":
user = self.git user = self.git
pwd = input("Enter Github password: ") pwd = input("Enter Github password: ")
# curl -i -u USER:PASSWORD -d '{"name":"REPO"}' https://api.github.com/user/repos # curl -i -u USER:PASSWORD -d '{"name":"REPO"}' https://api.github.com/user/repos
@ -176,11 +191,18 @@ class Student:
print("Synced to " + self.username) print("Synced to " + self.username)
def getClasses(self): def getClasses(self):
"""
Gets a lists of classes the student is enrolled in
"""
classes = self.classes classes = self.classes
for c in classes: for c in classes:
print(c['name']) print(c['name'])
def getAssignments(self, course, span): def getAssignments(self, span):
"""
Gets a list of assignments the student has
:param span: time span to check
"""
span = datetime.timedelta(span, 0) span = datetime.timedelta(span, 0)
classes = self.classes classes = self.classes
for c in classes: for c in classes:
@ -195,7 +217,7 @@ class Student:
diff = now - due diff = now - due
zero = datetime.timedelta(0, 0) zero = datetime.timedelta(0, 0)
# check due ddate is in span range is now past date (- timdelta) # check due ddate is in span range is now past date (- timdelta)
if (diff < span and diff > zero): if diff < span and diff > zero:
print(a + " due in:" + str(now - due)) print(a + " due in:" + str(now - due))
except Exception as e: except Exception as e:
@ -204,6 +226,9 @@ class Student:
# update API and Github, all assignments / classes # update API and Github, all assignments / classes
def update(self): def update(self):
"""
Updates the api, github, and all assignments and classes with new information
"""
cdir = os.getcwd() cdir = os.getcwd()
os.chdir(self.username) os.chdir(self.username)
command("git checkout master") command("git checkout master")
@ -226,7 +251,11 @@ class Student:
# updates 1 class, does not switch to master # updates 1 class, does not switch to master
def updateClass(self, course): def updateClass(self, course):
if ((course in self.sclass) == False): """
Updates a class with new information
:param course: class name in the format <course-name>_<ion_user>
"""
if (course in self.sclass) == False:
print("Class not found") print("Class not found")
return return
cdir = os.getcwd() cdir = os.getcwd()
@ -241,16 +270,20 @@ class Student:
# add classes from 'new' field # add classes from 'new' field
def addClass(self, cid): def addClass(self, cid):
"""
Add student to a class
:param cid: the id number of the class
:return: data from the class, None if an error occures
"""
data = getDB(self.username, self.password,'http://127.0.0.1:8000/api/classes/' + str(cid)) data = getDB(self.username, self.password,'http://127.0.0.1:8000/api/classes/' + str(cid))
if ((cid in self.snew) == False or (self.username in data['confirmed'])): if ((cid in self.snew) == False or (self.username in data['confirmed'])):
print("Already enrolled in this class.") print("Already enrolled in this class.")
return None return None
if ((cid in self.sclass) or (self.username in data['unconfirmed']) == False): if (cid in self.sclass) or not (self.username in data['unconfirmed']):
print("Not added by teacher yet.") print("Not added by teacher yet.")
return None return None
# add class teacher as cocllaborator to student repo # add class teacher as collaborator to student repo
print(os.getcwd()) print(os.getcwd())
pwd = input("Enter Github password: ") pwd = input("Enter Github password: ")
tgit = getDB(self.username, self.password,"http://127.0.0.1:8000/api/teachers/" + data['teacher'] + "/")['git'] tgit = getDB(self.username, self.password,"http://127.0.0.1:8000/api/teachers/" + data['teacher'] + "/")['git']
@ -270,7 +303,7 @@ class Student:
# os.chdir(self.username) # os.chdir(self.username)
# push to git, start at master # push to git, start at master
#os.chdir(self.username) # os.chdir(self.username)
command("git checkout master") command("git checkout master")
command("git branch " + data['name']) command("git branch " + data['name'])
command("git commit -m initial") command("git commit -m initial")
@ -292,7 +325,7 @@ class Student:
user = self.git user = self.git
self.classes.append(data) self.classes.append(data)
if (len(self.sclass) == 0): if len(self.sclass) == 0:
self.sclass = data['name'] self.sclass = data['name']
else: else:
self.sclass = self.sclass + "," + str(data['name']) self.sclass = self.sclass + "," + str(data['name'])
@ -301,7 +334,7 @@ class Student:
snew = "" snew = ""
new = [] new = []
for i in range(len(self.new)): for i in range(len(self.new)):
if (self.new[i]['name'] == data['name']): if self.new[i]['name'] == data['name']:
del self.new[i] del self.new[i]
# recreate sclass field, using ids # recreate sclass field, using ids
for c in self.new: for c in self.new:
@ -321,46 +354,12 @@ class Student:
print(patchDB(self.username, self.password,data, self.url)) print(patchDB(self.username, self.password,data, self.url))
return data return data
def submit(self, path):
# 2022rkhondak/English11_eharris1/Essay1
# check if valid assignment
parts = path.split("/")
if (len(parts) != 3):
print("Assignment path too short")
return
isclass = False
for c in self.classes:
if (c['name'] == parts[1]):
isclass == True
break
if (parts[0] != self.username and isclass and os.path.isdir(path) == False):
print("Not valid assignment")
return
if ((parts[1] + "/" + parts[2]) in self.completed):
print(parts[2] + " already submited. ")
# return
resp = input("Are you sure you want to submit? You cannot do this again.(y/N) ")
if (resp == 'y'):
os.chdir(self.username + "/" + parts[1])
command("git add .")
command("git commit -m submit")
command("git tag " + parts[1] + "-final")
command("git push -u origin " + self.username + " --tags")
self.completed = self.completed + "," + parts[1] + "/" + parts[2]
data = {
'user': self.user,
'git': self.git,
'ion_user': self.username,
'student_id': self.student_id,
'added_to': self.snew,
'url': self.url,
'classes': self.sclass,
'grade': self.grade,
'completed': self.completed
}
# print(putDB(data, "http://127.0.0.1:8000/api/students/" + self.username + "/"))
def viewClass(self, courses): def viewClass(self, courses):
"""
Sets the current git branch to view each class in courses
:param courses: a list of classes
:return:
"""
self.update() self.update()
cdir = os.getcwd() cdir = os.getcwd()
os.chdir(self.username) os.chdir(self.username)
@ -375,11 +374,20 @@ class Student:
return return
def exitCLI(self): def exitCLI(self):
"""
Exits the cli
"""
print(os.getcwd()) print(os.getcwd())
self.update() self.update()
command("git checkout master") command("git checkout master")
def submit(self, course, assignment): def submit(self, course, assignment):
"""
Submits an assignment
:param course: the class the assignment belongs to
:param assignment: the assignment
:return:
"""
cdir = os.getcwd() cdir = os.getcwd()
os.chdir(self.username) os.chdir(self.username)
print(os.getcwd()) print(os.getcwd())
@ -394,7 +402,7 @@ class Student:
inclass = True inclass = True
oname = a + "_" + course oname = a + "_" + course
break break
if (inclass == False): if inclass == False:
print(assignment + " not an assignment of " + course) print(assignment + " not an assignment of " + course)
command('git checkout master') command('git checkout master')
os.chdir(cdir) os.chdir(cdir)

View File

@ -96,7 +96,7 @@ def putDB(user, pwd, data, url):
:param user: a string :param user: a string
:param password: a string :param password: a string
:param url: URL for request :param url: URL for request
""" """
r = requests.put(url=url, data=data, auth=(user, pwd)) r = requests.put(url=url, data=data, auth=(user, pwd))
print("PUT:" + str(r.status_code)) print("PUT:" + str(r.status_code))
return r.json() return r.json()

View File

@ -53,20 +53,6 @@ class ClassCreationForm (forms.ModelForm):
# a list of primary key for the selected data. # a list of primary key for the selected data.
initial['unconfirmed'] = [t.pk for t in kwargs['instance'].unconfirmed.all()] initial['unconfirmed'] = [t.pk for t in kwargs['instance'].unconfirmed.all()]
# Overriding save allows us to process the value of 'unconfirmed' field
def save(self, username=""):
cleaned_data = self.cleaned_data
print(self)
# Get the unsave Class instance
instance = forms.ModelForm.save(self)
instance.unconfirmed.clear()
instance.unconfirmed.add(*cleaned_data['unconfirmed'])
instance.name = cleaned_data['subject'] + str(cleaned_data['period']) + "_" + username
print("Class name: " + instance.name)
return instance
class Meta: class Meta:
model = Class model = Class
fields = ['subject', 'period', 'description', 'unconfirmed'] fields = ['subject', 'period', 'description', 'unconfirmed']

View File

@ -92,3 +92,13 @@ a.article-title:hover {
.account-heading { .account-heading {
font-size: 2.5rem; font-size: 2.5rem;
} }
.class-card {
text-decoration: none;
color: gray;
}
.class-card:hover {
text-decoration: none;
color: black;
}

View File

@ -35,7 +35,6 @@
<div class="navbar-nav"> <div class="navbar-nav">
{% if user.is_authenticated %} {% if user.is_authenticated %}
{% if isTeacher %} {% if isTeacher %}
<a class="nav-item nav-link" href="{% url 'create-assignment' %}">Create Assignment</a>
<a class="nav-item nav-link" href="{% url 'create-class' %}">Create Class</a> <a class="nav-item nav-link" href="{% url 'create-class' %}">Create Class</a>
{% else %} {% else %}

View File

@ -3,9 +3,15 @@
<div class="content-section"> <div class="content-section">
{% for class in classes %} {% for class in classes %}
<div class="card-columns"> <div class="card-columns">
<a class="card" href="/class/{{ class.id }}" style="text-decoration: none;"> <a class="card class-card" href="/class/{{ class.id }}" style="">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">{{ class.name }}</h5> <h5 class="card-title">{{ class.subject }}</h5>
{% if class.period != 0 %}
<small>Period: {{ class.period }}<br></small>
{% endif %}
{% if class.name %}
<small style="font-size:.75em"><i>{{ class.name }}</i></small>
{% endif %}
<p class="card-text">{{ class.description }}</p> <p class="card-text">{{ class.description }}</p>
</div> </div>
</a> </a>

View File

@ -8,5 +8,4 @@ urlpatterns = [
path('profile/', views.profile, name='profile'), path('profile/', views.profile, name='profile'),
path("class/<str:id>", views.classDetail, name="class"), path("class/<str:id>", views.classDetail, name="class"),
path("create-class/", views.createClass, name="create-class"), path("create-class/", views.createClass, name="create-class"),
path("create-assignment/", views.createAssignment, name="create-assignment"),
] ]

View File

@ -143,8 +143,15 @@ def createClassHelper(request):
if classForm.is_valid(): if classForm.is_valid():
cleaned_data = classForm.clean() cleaned_data = classForm.clean()
print(cleaned_data) print(cleaned_data)
classForm.save(username=teacher.user.username) newClass = classForm.save(commit=False)
newClass.owner = request.user
newClass.teacher = request.user.username
newClass.name = cleaned_data['subject'].replace(' ', '')[:8].lower() + str(cleaned_data['period']) + "_" + teacher.user.username.lower()
newClass.save()
classObj = classForm.save_m2m()
messages.success(request, cleaned_data['subject'].capitalize() + " has been created!") messages.success(request, cleaned_data['subject'].capitalize() + " has been created!")
print (newClass)
teacher.classes.add(newClass)
return redirect('home') return redirect('home')
else: else:
classForm = ClassCreationForm() classForm = ClassCreationForm()
@ -157,7 +164,3 @@ def createClassHelper(request):
} }
return render(request, "skoolos/createClass.html", context) return render(request, "skoolos/createClass.html", context)
@login_required()
def createAssignment (request):
pass

View File

@ -25,7 +25,12 @@ scope = ["read"]
USER = "" USER = ""
PWD = "" PWD = ""
def main(): def main():
"""
The Command Line Interface (CLI) for SkoolOS
Serves to allow both teachers and students to access the majority of the features of SkoolOS
"""
print("") print("")
print("░██████╗██╗░░██╗░█████╗░░█████╗░██╗░░░░░  ░█████╗░░██████╗") print("░██████╗██╗░░██╗░█████╗░░█████╗░██╗░░░░░  ░█████╗░░██████╗")
print("██╔════╝██║░██╔╝██╔══██╗██╔══██╗██║░░░░░  ██╔══██╗██╔════╝") print("██╔════╝██║░██╔╝██╔══██╗██╔══██╗██║░░░░░  ██╔══██╗██╔════╝")
@ -40,13 +45,13 @@ def main():
if not ("profile" in str(profiles)): if not ("profile" in str(profiles)):
try: try:
URL = "http://127.0.0.1:8000/api/" URL = "http://127.0.0.1:8000/api/"
r = requests.get(url = URL) r = requests.get(url=URL)
except: except:
print("Run Django server on http://127.0.0.1:8000/ before continuing") print("Run Django server on http://127.0.0.1:8000/ before continuing")
sys.exit(0) sys.exit(0)
input("Welcome to SkoolOS. Press any key to create an account") input("Welcome to SkoolOS. Press any key to create an account")
#webbrowser.open("http://127.0.0.1:8000/login", new=2) # webbrowser.open("http://127.0.0.1:8000/login", new=2)
authenticate() authenticate()
else: else:
profiles = os.listdir() profiles = os.listdir()
@ -55,93 +60,113 @@ def main():
count = 1 count = 1
for i in range(len(profiles)): for i in range(len(profiles)):
p = profiles[i] p = profiles[i]
if('profile' in p): if 'profile' in p:
f = open(p,'r') f = open(p, 'r')
d = json.loads(f.read()) d = json.loads(f.read())
f.close() f.close()
info.append(d) info.append(d)
users.append(str(count) + ") " + d['username']) users.append(str(count) + ") " + d['username'])
count = count+1 count = count + 1
users.append(str(count) + ") Make new user") users.append(str(count) + ") Make new user")
user = [ user = [
{ {
'type': 'list', 'type': 'list',
'name': 'user', 'name': 'user',
'choices':users, 'choices': users,
'message': 'Select User: ', 'message': 'Select User: ',
}, },
] ]
u = int(prompt(user)['user'].split(")")[0]) -1 u = int(prompt(user)['user'].split(")")[0]) - 1
if(u+1 == count): if u + 1 == count:
authenticate() authenticate()
return return
data = info[u] data = info[u]
PWD = data['password'] PWD = data['password']
USER = data['username'] USER = data['username']
print(data['username']) print(data['username'])
if(data['is_student']): if data['is_student']:
studentCLI(USER, PWD) studentCLI(USER, PWD)
else: else:
teacherCLI(USER, PWD) teacherCLI(USER, PWD)
#################################################################################################### STUDENT METHODS #################################################################################################### STUDENT METHODS
def studentCLI(user, password): def studentCLI(user, password):
"""
The CLI for students to access
:param user: student username
:param password: student password
"""
from CLI import student from CLI import student
data = getUser(user, password, 'student') data = getUser(user, password, 'student')
student = student.Student(data, password) student = student.Student(data, password)
student.update() student.update()
EXIT = False EXIT = False
while(not EXIT): while not EXIT:
course = chooseClassStudent(student) course = chooseClassStudent(student)
if(course == "Exit SkoolOS"): if course == "Exit SkoolOS":
return return
EXIT = classOptionsStudent(student, course) EXIT = classOptionsStudent(student, course)
#return class
def chooseClassStudent(student): # return class
def chooseClassStudent(student):
"""
Chooses a class for a student to view and work on
:param student: a student
:return: a course prompt
"""
carray = student.sclass.split(",") carray = student.sclass.split(",")
if(len(carray) == 1 and carray[0] == ""): if len(carray) == 1 and carray[0] == "":
carray.remove("") carray.remove("")
print("No classes") print("No classes")
carray.append("Exit SkoolOS") carray.append("Exit SkoolOS")
courses = [ courses = [
{ {
'type': 'list', 'type': 'list',
'name': 'course', 'name': 'course',
'choices':carray, 'choices': carray,
'message': 'Select class: ', 'message': 'Select class: ',
}, },
] ]
course = prompt(courses)['course'] course = prompt(courses)['course']
print(course) print(course)
return course return course
def classOptionsStudent(student, course): def classOptionsStudent(student, course):
"""
Allows students to choose what they want to do related to a class
The student can save, exit, or go back
:param student: a student
:param course: a course
:return: True if exiting, False if going back
"""
student.viewClass(course) student.viewClass(course)
student.getAssignments(course, 100) student.getAssignments(course, 100)
choices = ["Save","Submit assignment","Back","Exit SkoolOS"] choices = ["Save","Submit assignment","Back","Exit SkoolOS"]
options = [ options = [
{ {
'type': 'list', 'type': 'list',
'name': 'option', 'name': 'option',
'choices':choices, 'choices': choices,
'message': 'Select: ', 'message': 'Select: ',
}, },
] ]
option = prompt(options)['option'] option = prompt(options)['option']
if(option == "Save"): if option == "Save":
student.update() student.update()
print("Saved!") print("Saved!")
classOptionsStudent(student, course) classOptionsStudent(student, course)
if(option == "Back"): if option == "Back":
student.exitCLI() student.exitCLI()
#dont exit cli # dont exit cli
return False return False
if(option == "Exit SkoolOS"): if option == "Exit SkoolOS":
student.exitCLI() student.exitCLI()
#exit cli # exit cli
return True return True
if(option == "Submit assignment"): if(option == "Submit assignment"):
assignments = os.listdir(student.username) assignments = os.listdir(student.username)
@ -171,9 +196,14 @@ def classOptionsStudent(student, course):
student.submit(course, ass) student.submit(course, ass)
return False return False
#################################################################################################### TEACHER METHODS #################################################################################################### TEACHER METHODS
def teacherCLI(user, password): def teacherCLI(user, password):
"""
The CLI for teachers to access
:param user: teachers username
:param password: teachers password
"""
from CLI import teacher from CLI import teacher
data = getUser(user, password, 'teacher') data = getUser(user, password, 'teacher')
print(data) print(data)
@ -184,27 +214,28 @@ def teacherCLI(user, password):
# 3. Get progress logs on a student # 3. Get progress logs on a student
# 2. make an assignment for a class # 2. make an assignment for a class
# 3. view student submissions for an assignment # 3. view student submissions for an assignment
while(not EXIT): while not EXIT:
#Options: '1) Request Student', "2) Add assignment", "3) View student information", "4) Exit" # Options: '1) Request Student', "2) Add assignment", "3) View student information", "4) Exit"
course = chooseGeneralTeacher(teacher) course = chooseGeneralTeacher(teacher)
if course == "Exit SkoolOS": if course == "Exit SkoolOS":
EXIT = True EXIT = True
elif course == "Make New Class": elif course == "Make New Class":
EXIT = makeClassTeacher(teacher) EXIT = makeClassTeacher(teacher)
#selected a class # selected a class
else: else:
#Pull confirmed students directory #Pull confirmed students directory
teacher.getStudents(course) teacher.getStudents(course)
option = classOptionsTeacher(teacher, course) option = classOptionsTeacher(teacher, course)
if(option == '1'): if option == '1':
EXIT = addStudentsTeacher(teacher, course) EXIT = addStudentsTeacher(teacher, course)
elif(option == '2'): elif option == '2':
EXIT = addAssignmentTeacher(teacher, course) EXIT = addAssignmentTeacher(teacher, course)
elif(option == '3'): elif option == '3':
EXIT = viewStudentsTeacher(teacher, course) EXIT = viewStudentsTeacher(teacher, course)
else: else:
EXIT = True EXIT = True
def chooseGeneralTeacher(teacher): def chooseGeneralTeacher(teacher):
carray = [] carray = []
for c in teacher.classes: for c in teacher.classes:
@ -212,56 +243,57 @@ def chooseGeneralTeacher(teacher):
carray.append("Make New Class") carray.append("Make New Class")
carray.append("Exit SkoolOS") carray.append("Exit SkoolOS")
courses = [ courses = [
{ {
'type': 'list', 'type': 'list',
'name': 'course', 'name': 'course',
'choices':carray, 'choices': carray,
'message': 'Select class: ', 'message': 'Select class: ',
}, },
] ]
course = prompt(courses)['course'] course = prompt(courses)['course']
return course return course
def makeClassTeacher(teacher): def makeClassTeacher(teacher):
questions = [ questions = [
{
'type': 'input',
'name': 'cname',
'message': 'Class Name (Must be: <subject>_<ion_user>): ',
},
]
cname = prompt(questions)['cname']
print(cname)
while(not ("_" + teacher.username) in cname):
print("Incorrect naming format")
questions = [
{ {
'type': 'input', 'type': 'input',
'name': 'cname', 'name': 'cname',
'message': 'Class Name (Must be: <subject>_<ion_user>): ', 'message': 'Class Name (Must be: <subject>_<ion_user>): ',
}, },
]
cname = prompt(questions)['cname']
print(cname)
while not ("_" + teacher.username) in cname:
print("Incorrect naming format")
questions = [
{
'type': 'input',
'name': 'cname',
'message': 'Class Name (Must be: <subject>_<ion_user>): ',
},
] ]
cname = prompt(questions)['cname'] cname = prompt(questions)['cname']
teacher.makeClass(cname) teacher.makeClass(cname)
soption = ["1) Add individual student", "2) Add list of students through path", "3) Exit"] soption = ["1) Add individual student", "2) Add list of students through path", "3) Exit"]
questions = [ questions = [
{ {
'type': 'list', 'type': 'list',
'choices':soption, 'choices': soption,
'name': 'students', 'name': 'students',
'message': 'Add Students): ', 'message': 'Add Students): ',
}, },
] ]
choice = prompt(questions)['students'].split(")")[0] choice = prompt(questions)['students'].split(")")[0]
if("1" == choice): if "1" == choice:
s = input("Student name: ") s = input("Student name: ")
teacher.addStudent(s, cname) teacher.addStudent(s, cname)
if("2" == choice): if "2" == choice:
print("File must be .txt and have 1 student username per line") print("File must be .txt and have 1 student username per line")
path = input("Relative Path: ") path = input("Relative Path: ")
while(not os.path.exists(path)): while not os.path.exists(path):
if(path == 'N'): if path == 'N':
return True return True
print(path + " is not a valid path") print(path + " is not a valid path")
path = input("Enter file path ('N' to exit): ") path = input("Enter file path ('N' to exit): ")
@ -270,6 +302,7 @@ def makeClassTeacher(teacher):
teacher.reqAddStudentList(students, cname) teacher.reqAddStudentList(students, cname)
return False return False
def classOptionsTeacher(teacher, course): def classOptionsTeacher(teacher, course):
print("Class: " + course) print("Class: " + course)
unconf = getDB(teacher.username, teacher.password, "http://localhost:8000/api/classes/" + course)['unconfirmed'] unconf = getDB(teacher.username, teacher.password, "http://localhost:8000/api/classes/" + course)['unconfirmed']
@ -277,49 +310,50 @@ def classOptionsTeacher(teacher, course):
teacher.addStudent(s, course) teacher.addStudent(s, course)
options = ['1) Request Student', "2) Add assignment", "3) View student information", "4) Exit"] options = ['1) Request Student', "2) Add assignment", "3) View student information", "4) Exit"]
questions = [ questions = [
{ {
'type': 'list', 'type': 'list',
'name': 'course', 'name': 'course',
'choices':options, 'choices': options,
'message': 'Select option: ', 'message': 'Select option: ',
}, },
] ]
option = prompt(questions)['course'].split(")")[0] option = prompt(questions)['course'].split(")")[0]
return option return option
def addStudentsTeacher(teacher, course): def addStudentsTeacher(teacher, course):
soption = ["1) Add individual student", "2) Add list of students through path", "3) Exit"] soption = ["1) Add individual student", "2) Add list of students through path", "3) Exit"]
questions = [ questions = [
{ {
'type': 'list', 'type': 'list',
'choices':soption, 'choices': soption,
'name': 'students', 'name': 'students',
'message': 'Add list of students (input path): ', 'message': 'Add list of students (input path): ',
}, },
] ]
schoice = prompt(questions)['students'].split(")")[0] schoice = prompt(questions)['students'].split(")")[0]
if(schoice == '1'): if schoice == '1':
questions = [ questions = [
{ {
'type': 'input', 'type': 'input',
'name': 'student', 'name': 'student',
'message': 'Student Name: ', 'message': 'Student Name: ',
}, },
] ]
s = prompt(questions)['student'] s = prompt(questions)['student']
teacher.reqStudent(s, course) teacher.reqStudent(s, course)
return False return False
if(schoice == '2'): if schoice == '2':
questions = [ questions = [
{ {
'type': 'input', 'type': 'input',
'name': 'path', 'name': 'path',
'message': 'Path: ', 'message': 'Path: ',
}, },
] ]
path = prompt(questions)['path'] path = prompt(questions)['path']
while(not os.path.exists(path)): while not os.path.exists(path):
if(path == 'N'): if path == 'N':
sys.exit(0) sys.exit(0)
print(path + " is not a valid path") print(path + " is not a valid path")
path = input("Enter file path ('N' to exit): ") path = input("Enter file path ('N' to exit): ")
@ -330,6 +364,7 @@ def addStudentsTeacher(teacher, course):
else: else:
return True return True
def addAssignmentTeacher(teacher, course): def addAssignmentTeacher(teacher, course):
nlist = os.listdir(teacher.username + "/" + course) nlist = os.listdir(teacher.username + "/" + course)
alist = getDB(teacher.username, teacher.password, "http://localhost:8000/api/classes/" + course)['assignments'] alist = getDB(teacher.username, teacher.password, "http://localhost:8000/api/classes/" + course)['assignments']
@ -339,36 +374,36 @@ def addAssignmentTeacher(teacher, course):
for n in nlist: for n in nlist:
b = True b = True
print(teacher.username + "/" + course + "/" + n) print(teacher.username + "/" + course + "/" + n)
for a in alist: for a in alist:
if(n in a or n == a): if n in a or n == a:
#print("Assignments: " + n) # print("Assignments: " + n)
b = False b = False
if(not os.path.isdir(teacher.username + "/" + course + "/" + n)): if not os.path.isdir(teacher.username + "/" + course + "/" + n):
b = False b = False
if(b): if b:
tlist.append(n) tlist.append(n)
nlist = tlist nlist = tlist
if(len(nlist) == 0): if len(nlist) == 0:
print("No new assignments found") print("No new assignments found")
print("To make an assignment: make a subdirectory in the " + course + " folder. Add a file within the new folder") print(
"To make an assignment: make a subdirectory in the " + course + " folder. Add a file within the new folder")
return False return False
questions = [ questions = [
{ {
'type': 'list', 'type': 'list',
'choices':nlist, 'choices': nlist,
'name': 'assignment', 'name': 'assignment',
'message': 'Select new assignment: ', 'message': 'Select new assignment: ',
}, },
] ]
ass = prompt(questions)['assignment'] ass = prompt(questions)['assignment']
apath = teacher.username + "/" + course + "/" + ass apath = teacher.username + "/" + course + "/" + ass
due = input("Enter due date (Example: 2020-08-11 16:58): ") due = input("Enter due date (Example: 2020-08-11 16:58): ")
due = due + ":33.383124" due = due + ":33.383124"
due = due.strip() due = due.strip()
f = False f = False
while(not f): while not f:
try: try:
datetime.datetime.strptime(due, '%Y-%m-%d %H:%M:%S.%f') datetime.datetime.strptime(due, '%Y-%m-%d %H:%M:%S.%f')
f = True f = True
@ -376,10 +411,11 @@ def addAssignmentTeacher(teacher, course):
print("Due-date format is incorrect.") print("Due-date format is incorrect.")
print(due) print(due)
due = input("Enter due date (Example: 2020-08-11 16:58): ") due = input("Enter due date (Example: 2020-08-11 16:58): ")
due = due + ":33.383124" due = due + ":33.383124"
teacher.addAssignment(apath, course, due) teacher.addAssignment(apath, course, due)
return False return False
def viewStudentsTeacher(teacher, course): def viewStudentsTeacher(teacher, course):
data = getDB(teacher.username, teacher.password, "http://127.0.0.1:8000/api/classes/" + course) data = getDB(teacher.username, teacher.password, "http://127.0.0.1:8000/api/classes/" + course)
students = data["confirmed"] students = data["confirmed"]
@ -416,93 +452,113 @@ def viewStudentsTeacher(teacher, course):
#put log stuff #put log stuff
############################################################################################################################################ ############################################################################################################################################
def getUser(ion_user, password, utype): def getUser(ion_user, password, utype):
if('student' in utype): """
URL = "http://127.0.0.1:8000/api/students/" + ion_user + "/" Returns user information
else: :param ion_user: user
URL = "http://127.0.0.1:8000/api/teachers/" + ion_user + "/" :param password: user's password
:param utype: type of user (student or teacher
:return: api user information
"""
if 'student' in utype:
URL = "http://127.0.0.1:8000/api/students/" + ion_user + "/"
else:
URL = "http://127.0.0.1:8000/api/teachers/" + ion_user + "/"
print(URL) print(URL)
r = requests.get(url = URL, auth=(ion_user,password)) r = requests.get(url=URL, auth=(ion_user, password))
print(r.json()) print(r.json())
if(r.status_code == 200): if r.status_code == 200:
data = r.json() data = r.json()
print(200) print(200)
return data return data
elif(r.status_code == 404): elif r.status_code == 404:
print("Make new account!") print("Make new account!")
return None return None
elif(r.status_code == 403): elif r.status_code == 403:
print("Invalid username/password") print("Invalid username/password")
return None return None
else: else:
print(r.status_code) print(r.status_code)
return None return None
def patchDB(USER, PWD, url, data): def patchDB(USER, PWD, url, data):
r = requests.patch(url = url, data=data, auth=(USER,PWD)) r = requests.patch(url=url, data=data, auth=(USER, PWD))
print("PATH:" + str(r.status_code)) print("PATH:" + str(r.status_code))
return(r.json()) return r.json()
def getDB(USER, PWD, url): def getDB(USER, PWD, url):
r = requests.get(url = url, auth=(USER,PWD)) r = requests.get(url=url, auth=(USER, PWD))
print("GET:" + str(r.status_code)) print("GET:" + str(r.status_code))
return(r.json()) return r.json()
def postDB(USER, PWD, url, data): def postDB(USER, PWD, url, data):
r = requests.post(url = url, data=data, auth=(USER,PWD)) r = requests.post(url=url, data=data, auth=(USER, PWD))
print("POST:" + str(r.status_code)) print("POST:" + str(r.status_code))
return(r.json()) return r.json()
def putDB(USER, PWD, url, data): def putDB(USER, PWD, url, data):
r = requests.put(url = url, data=data, auth=(USER,PWD)) r = requests.put(url=url, data=data, auth=(USER, PWD))
print("PUT:" + str(r.status_code)) print("PUT:" + str(r.status_code))
return(r.json()) return r.json()
def delDB(USER, PWD, url): def delDB(USER, PWD, url):
r = requests.delete(url = url, auth=(USER,PWD)) r = requests.delete(url=url, auth=(USER, PWD))
print("DELETE:" + str(r.status_code)) print("DELETE:" + str(r.status_code))
return None return None
def makePass(): def makePass():
"""
Prompts the user to create a password
:return: the password
"""
questions = [ questions = [
{ {
'type': 'password', 'type': 'password',
'name': 'pwd', 'name': 'pwd',
'message': 'Enter SkoolOS Password (NOT ION PASSWORD): ', 'message': 'Enter SkoolOS Password (NOT ION PASSWORD): ',
}, },
] ]
pwd = prompt(questions)['pwd'] pwd = prompt(questions)['pwd']
while(len(pwd) < 7): while len(pwd) < 7:
print("Password too short (Must be over 6 characters)") print("Password too short (Must be over 6 characters)")
pwd = prompt(questions)['pwd'] pwd = prompt(questions)['pwd']
conf = [ conf = [
{ {
'type': 'password', 'type': 'password',
'name': 'pwd', 'name': 'pwd',
'message': 'Re-enter password: ', 'message': 'Re-enter password: ',
}, },
] ]
pwd2 = prompt(conf)['pwd'] pwd2 = prompt(conf)['pwd']
while(not pwd == pwd2): while not pwd == pwd2:
print("Passwords do not match.") print("Passwords do not match.")
pwd2 = prompt(conf)['pwd'] pwd2 = prompt(conf)['pwd']
else: else:
print("PASSWORD SAVED") print("PASSWORD SAVED")
return pwd return pwd
def authenticate(): def authenticate():
"""
Authenticates the user via Ion OAuth
"""
oauth = OAuth2Session(client_id=client_id, redirect_uri=redirect_uri, scope=scope) oauth = OAuth2Session(client_id=client_id, redirect_uri=redirect_uri, scope=scope)
authorization_url, state = oauth.authorization_url("https://ion.tjhsst.edu/oauth/authorize/") authorization_url, state = oauth.authorization_url("https://ion.tjhsst.edu/oauth/authorize/")
cdir = os.getcwd() cdir = os.getcwd()
#Linux: chromdriver-linux # Linux: chromdriver-linux
#Macos: chromdriver-mac # Macos: chromdriver-mac
#Windows: chromdriver.exe # Windows: chromdriver.exe
path = os.path.join(os.getcwd(),'chromedriver','chromedriver-mac') path = os.path.join(os.getcwd(), 'chromedriver', 'chromedriver-mac')
browser = webdriver.Chrome(path) browser = webdriver.Chrome(path)
@ -513,7 +569,8 @@ def authenticate():
url = browser.current_url url = browser.current_url
gets = url_decode(url.replace("http://localhost:8000/login/?", "")) 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/ 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) time.sleep(0.25)
url = browser.current_url url = browser.current_url
@ -524,42 +581,42 @@ def authenticate():
# print("states good") # print("states good")
browser.quit() browser.quit()
questions = [ questions = [
{ {
'type': 'input', 'type': 'input',
'name': 'username', 'name': 'username',
'message': 'Enter SkoolOS Username (Same as ION Username): ', 'message': 'Enter SkoolOS Username (Same as ION Username): ',
}, },
{ {
'type': 'password', 'type': 'password',
'name': 'pwd', 'name': 'pwd',
'message': 'Enter SkoolOS Password (NOT ION PASSWORD): ', 'message': 'Enter SkoolOS Password (NOT ION PASSWORD): ',
}, },
] ]
data =prompt(questions) data = prompt(questions)
pwd = data['pwd'] pwd = data['pwd']
user = data['username'] user = data['username']
r = requests.get(url = "http://localhost:8000/api/", auth=(user,pwd)) r = requests.get(url="http://localhost:8000/api/", auth=(user, pwd))
while(r.status_code != 200): while r.status_code != 200:
print("INCORRECT LOGIN CREDENTIALS") print("INCORRECT LOGIN CREDENTIALS")
r = requests.get(url = "http://localhost:8000/api/", auth=(user,pwd)) r = requests.get(url="http://localhost:8000/api/", auth=(user, pwd))
data =prompt(questions) data = prompt(questions)
pwd = data['pwd'] pwd = data['pwd']
user = data['username'] user = data['username']
print(r.status_code) print(r.status_code)
r = requests.get(url = "http://localhost:8000/api/students/" + user + "/", auth=(user,pwd)) r = requests.get(url="http://localhost:8000/api/students/" + user + "/", auth=(user, pwd))
is_student = False is_student = False
if(r.status_code == 200): if r.status_code == 200:
is_student = True is_student = True
print("Welcome, student " + user) print("Welcome, student " + user)
r = requests.get(url = "http://localhost:8000/api/students/" + user + "/", auth=(user,pwd)) r = requests.get(url="http://localhost:8000/api/students/" + user + "/", auth=(user, pwd))
profile = r.json() profile = r.json()
username = profile['ion_user'] username = profile['ion_user']
grade = profile['grade'] grade = profile['grade']
profile = { profile = {
'username':username, 'username': username,
'grade':grade, 'grade': grade,
'is_student':is_student, 'is_student': is_student,
'password':pwd, 'password': pwd,
} }
fname = "." + username + "profile" fname = "." + username + "profile"
profileFile = open(fname, "w") profileFile = open(fname, "w")
@ -568,13 +625,13 @@ def authenticate():
else: else:
print("Welcome, teacher " + user) print("Welcome, teacher " + user)
r = requests.get(url = "http://localhost:8000/api/teachers/" + user + "/", auth=(user,pwd)) r = requests.get(url="http://localhost:8000/api/teachers/" + user + "/", auth=(user, pwd))
profile = r.json() profile = r.json()
username = profile['ion_user'] username = profile['ion_user']
profile = { profile = {
'username':username, 'username': username,
'is_student':is_student, 'is_student': is_student,
'password':pwd, 'password': pwd,
} }
fname = "." + username + "profile" fname = "." + username + "profile"
profileFile = open(fname, "w") profileFile = open(fname, "w")
@ -585,11 +642,15 @@ def authenticate():
def create_server(): def create_server():
"""
Creates a simple HTTP server for creating api requests from the CLI
"""
port = 8000 port = 8000
handler = http.server.SimpleHTTPRequestHandler handler = http.server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(("", port), handler) httpd = socketserver.TCPServer(("", port), handler)
print("serving at port:" + str(port)) print("serving at port:" + str(port))
httpd.serve_forever() httpd.serve_forever()
if __name__ == "__main__": if __name__ == "__main__":
main() main()