def collect_repos(auth, university, course, get_repos_filepath): call_dir = os.getcwd() repos_filepath = os.path.join(call_dir, get_repos_filepath, "%s_all_repos" % course) if not os.path.isdir(repos_filepath): os.mkdir(repos_filepath) #else: # TODO: check if there are student repos here allready org = "%s-%s" % (university, course) url_orgs = 'https://api.github.com/orgs/%s' % (org) url_repos = 'https://api.github.com/repositories/' classroom = Classroom(auth, url_orgs) repos = classroom.get_repos() #SSH_base = "[email protected]:%s/" % org # Create the SSH links SSH_links = [] for repo in repos: if course in repo['name'].encode('utf-8'): r = get(url_repos + str(repo['id']), auth=auth) SSH_links.append(r.json()['ssh_url']) # Change to destination folder os.chdir(repos_filepath) # Clone into the repos for SSH_link in SSH_links: result = os.system('git clone ' + SSH_link) print(result) # Change back to call dir os.chdir(call_dir)
def collect_repos(auth, university, course, get_repos_filepath): call_dir = os.getcwd() repos_filepath = os.path.join(call_dir, get_repos_filepath, "%s_all_repos" % course) if not os.path.isdir(repos_filepath): os.makedirs(repos_filepath) else: if os.listdir(repos_filepath) != []: print "There are already repos in this folder, pleace \ remove them before cloning new into this folder" sys.exit(0) org = "%s-%s" % (university, course) url_orgs = 'https://api.github.com/orgs/%s' % (org) url_repos = 'https://api.github.com/repositories/' classroom = Classroom(auth, url_orgs) repos = classroom.get_repos() # Create the SSH links SSH_links = [] for repo in repos: if course in repo['name'].encode('utf-8'): r = get(url_repos + str(repo['id']), auth=auth) SSH_links.append(r.json()['ssh_url']) # Change to destination folder os.chdir(repos_filepath) # Clone into the repos for SSH_link in SSH_links: result = os.system('git clone ' + SSH_link) #print(result) # Change back to call dir os.chdir(call_dir)
def collect_repos(auth, university, course, get_repos_filepath): """ Clone (download) all repositories of a course """ call_dir = os.getcwd() repos_filepath = os.path.join(call_dir, get_repos_filepath, "%s_all_repos" % course) if not os.path.isdir(repos_filepath): os.makedirs(repos_filepath) else: if os.listdir(repos_filepath) != []: print "There are already repos in this folder, please \ remove them before cloning new into this folder" sys.exit(0) org = "%s-%s" % (university, course) url_orgs = 'https://api.github.com/orgs/%s' % (org) url_repos = 'https://api.github.com/repositories/' classroom = Classroom(auth, url_orgs) print "Getting list of repositories..." repos = classroom.get_repos() print "Found {} repositories.".format(len(repos)) # Create the SSH links SSH_links = [] for i, repo in enumerate(repos): print "Getting repository links: {}%".format((100 * i) / len(repos)) if course in repo['name'].encode('utf-8'): r = get(url_repos + str(repo['id']), auth=auth) SSH_links.append(r.json()['ssh_url']) # Change to destination folder os.chdir(repos_filepath) # Clone into the repos for i, SSH_link in enumerate(SSH_links): print "Cloning repositories {}%".format((100 * i) / len(SSH_links)) result = os.system('git clone ' + SSH_link) print "done." # Change back to call dir os.chdir(call_dir)
def collect_repos(auth, university, course, get_repos_filepath): """ Clone (download) all repositories of a course """ call_dir = os.getcwd() repos_filepath = os.path.join(call_dir, get_repos_filepath, "%s_all_repos" % course) if not os.path.isdir(repos_filepath): os.makedirs(repos_filepath) else: if os.listdir(repos_filepath) != []: print "There are already repos in this folder, please \ remove them before cloning new into this folder" sys.exit(0) org = "%s-%s" % (university, course) url_orgs = 'https://api.github.com/orgs/%s' % (org) url_repos = 'https://api.github.com/repositories/' classroom = Classroom(auth, url_orgs) print "Getting list of repositories..." repos = classroom.get_repos() print "Found {} repositories.".format(len(repos)) # Create the SSH links SSH_links = [] for i, repo in enumerate(repos): print "Getting repository links: {}%".format((100*i)/len(repos)) if course in repo['name'].encode('utf-8'): r = get(url_repos + str(repo['id']), auth=auth) SSH_links.append(r.json()['ssh_url']) # Change to destination folder os.chdir(repos_filepath) # Clone into the repos for i, SSH_link in enumerate(SSH_links): print "Cloning repositories {}%".format((100*i)/len(SSH_links)) result = os.system('git clone ' + SSH_link) print "done." # Change back to call dir os.chdir(call_dir)
# Get username and password for admin to classroom admin = input('Username: '******'Password:'******'https://api.github.com/orgs/%s' % (org) classroom = Classroom(auth, url_orgs) list_teams = classroom.get_teams() list_repos = classroom.get_repos() # Find list of teams to delete teams_to_delete = [] text = open(path.join(path.dirname(__file__), "Attendance", course + "students_base.txt"), 'r') for line in text: line = re.split(r'\s*\/\/\s*', line) teams_to_delete.append(line[1]) # Delete teams for team in list_teams: if team['name'].encode('utf-8') in teams_to_delete: print "Deleting ", team["name"] r = requests.delete(url + "/teams/" + str(team['id']), auth=auth) print r.status_code
# Get username and password for admin to classroom admin = input('Username: '******'Password:'******'https://api.github.com/orgs/%s' % (org) classroom = Classroom(auth, url_orgs) list_teams = classroom.get_teams() list_repos = classroom.get_repos() # Only delete members, not owners list_members = classroom.get_members(role='member') # Find list of teams and members to delete teams_to_delete = [] members_to_delete = [] #text = open(path.join(path.dirname(__file__), "Attendance", course + "students_base.txt"), 'r') #for line in text: # line = re.split(r'\s*\/\/\s*', line) # teams_to_delete.append(line[1]) # members_to_delete.append(line[2]) # Delete members for member in list_members:
class Feedbacks: def __init__(self, auth, university, course, output_path): self.auth = auth self.university = university self.course = course #self.output_path = output_path self.org = "%s-%s" % (university, course) url_orgs = 'https://api.github.com/orgs/%s' % (self.org) # Need help functions from classroom self.classroom = Classroom(auth, url_orgs) # To look up information about students attendance_path = os.path.join(os.path.dirname(__file__), \ 'Attendance', '%s-students_base.txt' % course) if os.path.isfile(attendance_path): self.students_base_dict = self.get_students( codecs.open(attendance_path, 'r', encoding='utf-8').readlines()) else: attendance_path = input('There is no file %s, pleace provide the' % attendance_path \ + 'filepath to where the student base file is located:') self.students_base_dict = self.get_students( open(attendance_path, 'r').readlines()) # Header for each file self.header = "/"*50 + "\n// Name: %(name)s \n" + "// Email: %(email)s \n" + \ "// Username: %(username)s \n" + "// Repo: %(repo)s \n" + \ "// Editors: %(editors)s \n" + "/"*50 + "\n\n" self.header = self.header.encode('utf-8') # TODO: these should be accessible through default_parameters # User defined variables assignment_name = input('What is this assignment called: ') feedback_name_base = input('\nWhat are the base filename of your feedback ' \ + 'files called, e.g.\nif you answer "PASSED" the ' \ + 'program will look for "PASSED_YES \nand "PASSED_NO" ' \ + '(case insensetive) : ').lower() # The files to look for self.file_feedback = [ feedback_name_base + '_yes', feedback_name_base + '_no' ] # Create path original_dir = os.getcwd() if output_path == "": feedback_filepath = os.path.join(original_dir, "%s_all_feedbacks" % course) else: feedback_filepath = os.path.join(original_dir, output_path, \ "%s_all_feedbacks" % course) # Path for feedback self.passed_path = os.path.join(feedback_filepath, assignment_name, 'PASSED') self.not_passed_path = os.path.join(feedback_filepath, assignment_name, 'NOT_PASSED') self.not_done_path = os.path.join(feedback_filepath, assignment_name) # Create folder structure try: os.makedirs(self.passed_path) os.makedirs(self.not_passed_path) except Exception as e: if os.listdir(self.passed_path) == [] and os.listdir( self.not_passed_path) == []: pass else: print("There are already collected feedbacks for %s." % assignment_name \ + " Remove these or copy them to another directory.") sys.exit(1) def __call__(self): print("\nLooking for feedbacks, this may take some time ...\n") repos = self.classroom.get_repos() not_done = [] for repo in repos: # Assumes that no repo has the same naming convension if self.course + "-" in repo['name'].encode('utf-8'): # Get sha from the last commit url_commits = repo['commits_url'][:-6] sha = get(url_commits, auth=self.auth).json()[0]['sha'] # Get tree self.url_trees = repo['trees_url'][:-6] r = get(self.url_trees + '/' + sha, auth=self.auth) # Get feedback file success, contents, status, path, extension = self.find_file( r.json()['tree']) # Get infomation about user and the file # Need some extra tests since multiple teams can have # access to the same repo. r = get(repo['teams_url'], auth=self.auth) for i in range(len(r.json())): try: personal_info = self.students_base_dict[ r.json()[i]['name'].encode('utf-8')] personal_info['repo'] = repo['name'].encode('utf-8') break except Exception as e: if i == len(r.json()) - 1: print("There are no owners (team) of this repo " \ + "matching student base. " + r.json()[i]['name']) personal_info['name'] = repo['name'] if success: # Check if there is reason to belive that the user have cheated personal_info['editors'] = ", ".join( self.get_editors(path, repo)) #print(personal_info['name']) #print(personal_info['editors']) #if (personal_info['name'].encode('utf-8') or personal_info['username']) \ #in personal_info['editors']: #print(personal_info['name']) #TODO: Store this feedback in a list of potential cheaters # Write feedback with header to file try: text = self.header % personal_info text += contents.decode('utf-8') except UnicodeDecodeError as e: if 'ascii' in e: for key, value in personal_info.iteritems(): print value personal_info[key] = value.decode('utf-8') text = self.header % personal_info elif 'utf-8' in e: text += contents.decode('latin1') except Exception as e: print("Could not get the contents of %(name)s feedback file. Error:" \ % personal_info) print(e) filename = personal_info['name'].replace( ' ', '_') + '.' + extension folder = self.passed_path if status == 'yes' else self.not_passed_path folder = os.path.join(folder, filename) feedback = codecs.open(folder, 'w', encoding='utf-8') feedback.write(text) feedback.close() # No feedback else: not_done.append(personal_info) # TODO: Only write those how where pressent at group and didn't get feedback # now it just writes everyone how has not gotten any feedback. text = "Students that didn't get any feedbacks\n" text += "Name // username // email\n" for student in not_done: text += "%(name)s // %(username)s // %(email)s\n" % student not_done_file = codecs.open(os.path.join(self.not_done_path, 'No_feedback.txt'), 'w', encoding='utf-8') not_done_file.write(text) not_done_file.close() number_of_feedbacks = len(repos) - len(not_done) print("\nFetched feedback from %s students and %s have not gotten any feedback" % \ (number_of_feedbacks, len(not_done))) def get_students(self, text): student_dict = {} for line in text[1:]: pressent, name, username, email = re.split(r"\s*\/\/\s*", line.replace('\n', '')) student_dict[name.encode('utf-8')] = { 'name': name, 'username': username, 'email': email } return student_dict def find_file(self, tree): for file in tree: # Explore the subdirectories recursively if file['type'].encode('utf-8') == 'tree': r = get(file['url'], auth=self.auth) success, contents, status, path, extension = self.find_file( r.json()['tree']) if success: return success, contents, status, path, extension # Check if the files in the folder match file_feedback if file['path'].split(os.path.sep)[-1].split( '.')[0].lower() in self.file_feedback: # Get filename and extension if '.' in file['path'].split(os.path.sep)[-1]: file_name, extension = file['path'].split( os.path.sep)[-1].lower().split('.') else: file_name = file['path'].split(os.path.sep)[-1].lower() extension = 'txt' r = get(file['url'], auth=self.auth) return True, base64.b64decode(r.json()['content']), \ file_name.split('_')[-1], file['path'], extension # If file not found return False, "", "", "", "" def get_editors(self, path, repo): url_commit = 'https://api.github.com/repos/%s/%s/commits' % ( self.org, repo['name']) r = get(url_commit, auth=self.auth, params={'path': path}) # TODO: Change commiter with author? editors = [commit['commit']['author']['name'] for commit in r.json()] return editors
class Feedbacks: def __init__(self, auth, university, course, output_path): self.auth = auth self.university = university self.course = course #self.output_path = output_path self.org = "%s-%s" % (university, course) url_orgs = 'https://api.github.com/orgs/%s' % (self.org) # Need help functions from classroom self.classroom = Classroom(auth, url_orgs) # To look up information about students attendance_path = os.path.join(os.path.dirname(__file__), \ 'Attendance', '%s-students_base.txt' % course) if os.path.isfile(attendance_path): self.students_base_dict = self.get_students(codecs.open(attendance_path, 'r', encoding='utf-8').readlines()) else: attendance_path = input('There is no file %s, pleace provide the' % attendance_path \ + 'filepath to where the student base file is located:') self.students_base_dict = self.get_students(open(attendance_path, 'r').readlines()) # Header for each file self.header = "/"*50 + "\n// Name: %(name)s \n" + "// Email: %(email)s \n" + \ "// Username: %(username)s \n" + "// Repo: %(repo)s \n" + \ "// Editors: %(editors)s \n" + "/"*50 + "\n\n" self.header = self.header.encode('utf-8') # TODO: these should be accessible through default_parameters # User defined variables assignment_name = input('What is this assignment called: ') feedback_name_base = input('\nWhat are the base filename of your feedback ' \ + 'files called, e.g.\nif you answer "PASSED" the ' \ + 'program will look for "PASSED_YES \nand "PASSED_NO" ' \ + '(case insensetive) : ').lower() # The files to look for self.file_feedback = [feedback_name_base + '_yes', feedback_name_base + '_no'] # Create path original_dir = os.getcwd() if output_path == "": feedback_filepath = os.path.join(original_dir, "%s_all_feedbacks" % course) else: feedback_filepath = os.path.join(original_dir, output_path, \ "%s_all_feedbacks" % course) # Path for feedback self.passed_path = os.path.join(feedback_filepath, assignment_name, 'PASSED') self.not_passed_path = os.path.join(feedback_filepath, assignment_name, 'NOT_PASSED') self.not_done_path = os.path.join(feedback_filepath, assignment_name) # Create folder structure try: os.makedirs(self.passed_path) os.makedirs(self.not_passed_path) except Exception as e: if os.listdir(self.passed_path) == [] and os.listdir(self.not_passed_path) == []: pass else: print("There are already collected feedbacks for %s." % assignment_name \ + " Remove these or copy them to another directory.") sys.exit(1) def __call__(self): print("\nLooking for feedbacks, this may take some time ...\n") repos = self.classroom.get_repos() not_done = [] for repo in repos: # Assumes that no repo has the same naming convension if self.course + "-" in repo['name'].encode('utf-8'): # Get sha from the last commit url_commits = repo['commits_url'][:-6] sha = get(url_commits, auth=self.auth).json()[0]['sha'] # Get tree self.url_trees = repo['trees_url'][:-6] r = get(self.url_trees + '/' + sha, auth=self.auth) # Get feedback file success, contents, status, path, extension = self.find_file(r.json()['tree']) # Get infomation about user and the file # Need some extra tests since multiple teams can have # access to the same repo. r = get(repo['teams_url'], auth=self.auth) for i in range(len(r.json())): try: personal_info = self.students_base_dict[r.json()[i]['name'].encode('utf-8')] personal_info['repo'] = repo['name'].encode('utf-8') break except Exception as e: if i == len(r.json()) - 1: print("There are no owners (team) of this repo " \ + "matching student base. " + r.json()[i]['name']) personal_info['name'] = repo['name'] if success: # Check if there is reason to belive that the user have cheated personal_info['editors'] = ", ".join(self.get_correctorss(path, repo)) #TODO: Store this feedback in a list of potential cheaters # Write feedback with header to file # Work around for files with different # formats, could be fixed with google forms. try: text = self.header % personal_info text += contents.decode('utf-8') except UnicodeDecodeError as e: if 'ascii' in e: for key, value in personal_info.iteritems(): print value personal_info[key] = value.decode('utf-8') text = self.header % personal_info elif 'utf-8' in e: text += contents.decode('latin1') except Exception as e: print("Could not get the contents of %(name)s feedback file. Error:" \ % personal_info) print(e) filename = personal_info['name'].replace(' ', '_') + '.' + extension folder = self.passed_path if status == 'yes' else self.not_passed_path folder = os.path.join(folder, filename) feedback = codecs.open(folder, 'w', encoding='utf-8') feedback.write(text) feedback.close() # No feedback else: not_done.append(personal_info) # TODO: Only write those how where pressent at group and didn't get feedback # now it just writes everyone how has not gotten any feedback. text = "Students that didn't get any feedbacks\n" text += "Name // username // email\n" for student in not_done: text += "%(name)s // %(username)s // %(email)s\n" % student not_done_file = codecs.open(os.path.join(self.not_done_path, 'No_feedback.txt'), 'w', encoding='utf-8') not_done_file.write(text) not_done_file.close() number_of_feedbacks = len(repos) - len(not_done) print("\nFetched feedback from %s students and %s have not gotten any feedback" % \ (number_of_feedbacks, len(not_done))) def get_students(self, text): student_dict = {} for line in text[1:]: pressent, name, username, email, rank = re.split(r"\s*\/\/\s*", line.replace('\n', '')) student_dict[name.encode('utf-8')] = {'name': name, 'username': username, 'email': email} return student_dict def find_file(self, tree): for file in tree: # Explore the subdirectories recursively if file['type'].encode('utf-8') == 'tree': r = get(file['url'], auth=self.auth) success, contents, status, path, extension = self.find_file(r.json()['tree']) if success: return success, contents, status, path, extension # Check if the files in the folder match file_feedback if file['path'].split(os.path.sep)[-1].split('.')[0].lower() in self.file_feedback: # Get filename and extension if '.' in file['path'].split(os.path.sep)[-1]: file_name, extension = file['path'].split(os.path.sep)[-1].lower().split('.') else: file_name = file['path'].split(os.path.sep)[-1].lower() extension = 'txt' r = get(file['url'], auth=self.auth) return True, base64.b64decode(r.json()['content']), \ file_name.split('_')[-1], file['path'], extension # If file not found return False, "", "", "", "" def get_correctors(self, path, repo): url_commit = 'https://api.github.com/repos/%s/%s/commits' % (self.org, repo['name']) r = get(url_commit, auth=self.auth, params={'path': path}) # TODO: Change commiter with author? editors = [commit['commit']['author']['name'] for commit in r.json()] return editors