import subprocess import os import requests import webbrowser import pprint import json import shutil import time import prompt_toolkit.clipboard.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) spam = pyperclip.paste() 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'] print(cid) #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="" for c in self.classes: s = s + str(self.classes[i]['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.deleteClass("eharris1/Crypto_eharris1") t.update()