Create subgroup for enrolled students so when creating projects we do not need the exported list of students and can use the subgroup instead.
This commit is contained in:
parent
01bfb44c73
commit
5d01c74440
5 changed files with 117 additions and 57 deletions
|
@ -18,7 +18,7 @@ Operations 1 and 2 require super user privileges to the API. The rest don't.
|
|||
|
||||
4. Set up the project for the example solutions and the student projects. If you have pre-existing example solutions place them in `<some_course>/solutions/solutions`.
|
||||
```
|
||||
# abgabesystem projects -c <some_course> -d <deploy key> -s <students.csv>
|
||||
# abgabesystem projects -c <some_course> -d <deploy key>
|
||||
```
|
||||
|
||||
5. Add all administrative users (e.g. users supervising the course or checking homework solutions) to the group of the course.
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
import os
|
||||
import subprocess
|
||||
import subprocess
|
||||
import logging as log
|
||||
|
||||
from .students import Student, create_user, get_students
|
||||
from .students import Student, create_user, get_students, enroll_student, get_student_group
|
||||
from .projects import create_tag, setup_course
|
||||
from gitlab.exceptions import GitlabCreateError, GitlabGetError
|
||||
|
||||
|
||||
def create_users(gl, args):
|
||||
def enroll_students(gl, args):
|
||||
"""Creates Gitlab users from exported students list
|
||||
"""
|
||||
|
||||
student_group = get_student_group(gl, args.course)
|
||||
|
||||
with open(args.students, encoding='iso8859') as students_csv:
|
||||
for student in Student.from_csv(students_csv):
|
||||
try:
|
||||
create_user(gl, student, args.ldap_base, args.ldap_provider)
|
||||
user = create_user(gl, student, args.ldap_base, args.ldap_provider)
|
||||
# TODO this is ugly, should be group of course, but python-gitlab does not cache the query
|
||||
enroll_student(gl, user, student_group)
|
||||
except GitlabCreateError:
|
||||
log.warn('Failed to create user: %s' % student.user)
|
||||
|
||||
|
@ -85,7 +90,7 @@ def course(gl, args):
|
|||
"""Creates the group for the course
|
||||
"""
|
||||
try:
|
||||
group = gl.groups.create({
|
||||
gl.groups.create({
|
||||
'name': args.course,
|
||||
'path': args.course,
|
||||
'visibility': 'internal',
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
import logging as log
|
||||
|
||||
from gitlab import DEVELOPER_ACCESS
|
||||
from gitlab.exceptions import GitlabError, GitlabCreateError
|
||||
from .students import enrolled_students
|
||||
from .course import InvalidCourse
|
||||
|
||||
|
||||
def create_tag(project, tag, ref):
|
||||
"""Creates protected tag on ref
|
||||
|
@ -60,7 +66,7 @@ def create_project(gl, group, user, reference, deploy_key):
|
|||
try:
|
||||
subgroup.members.create({
|
||||
'user_id': user.id,
|
||||
'access_level': gitlab.DEVELOPER_ACCESS,
|
||||
'access_level': DEVELOPER_ACCESS,
|
||||
})
|
||||
except GitlabError:
|
||||
log.warning('Failed to add student %s to its own group' % user.username)
|
||||
|
@ -71,55 +77,47 @@ def create_project(gl, group, user, reference, deploy_key):
|
|||
log.warning(e.error_message)
|
||||
|
||||
|
||||
def setup_course(gl, group, students_csv, deploy_key):
|
||||
def create_reference_solution(gl, namespace):
|
||||
reference_project = gl.projects.create({
|
||||
'name': 'solutions',
|
||||
'namespace_id': namespace,
|
||||
'visibility': 'internal',
|
||||
})
|
||||
reference_project.commits.create({
|
||||
'branch': 'master',
|
||||
'commit_message': 'Initial commit',
|
||||
'actions': [
|
||||
{
|
||||
'action': 'create',
|
||||
'file_path': 'README.md',
|
||||
'content': 'Example solutions go here',
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
return reference_project
|
||||
|
||||
|
||||
def setup_projects(gl, course, deploy_key):
|
||||
"""Sets up the internal structure for the group for use with the course
|
||||
"""
|
||||
solution = None
|
||||
reference_project = None
|
||||
|
||||
try:
|
||||
solution = gl.groups.create({
|
||||
'name': 'solutions',
|
||||
'path': 'solutions',
|
||||
'parent_id': group.id,
|
||||
'visibility': 'internal',
|
||||
})
|
||||
except GitlabCreateError as e:
|
||||
log.info('Failed to create solutions group. %s' % e.error_message)
|
||||
solutions = group.subgroups.list(search='solutions')
|
||||
if len(solutions) > 0 and solutions[0].name == 'solutions':
|
||||
solution = gl.groups.get(solutions[0].id, lazy=True)
|
||||
else:
|
||||
raise(GitlabCreateError(error_message='Failed to setup solutions subgroup'))
|
||||
solutions = None
|
||||
solutions_groups = course.subgroups.list(search='solutions')
|
||||
for group in solutions_groups:
|
||||
if group.name == 'solutions':
|
||||
solutions = group
|
||||
|
||||
try:
|
||||
reference_project = gl.projects.create({
|
||||
'name': 'solutions',
|
||||
'namespace_id': solution.id,
|
||||
'visibility': 'internal',
|
||||
})
|
||||
reference_project.commits.create({
|
||||
'branch': 'master',
|
||||
'commit_message': 'Initial commit',
|
||||
'actions': [
|
||||
{
|
||||
'action': 'create',
|
||||
'file_path': 'README.md',
|
||||
'content': 'Example solutions go here',
|
||||
},
|
||||
]
|
||||
})
|
||||
except GitlabCreateError as e:
|
||||
log.info('Failed to setup group structure. %s' % e.error_message)
|
||||
projects = solution.projects.list(search='solutions')
|
||||
if len(projects) > 0 and projects[0].name == 'solutions':
|
||||
reference_project = gl.projects.get(projects[0].id)
|
||||
else:
|
||||
raise(GitlabCreateError(error_message='Failed to setup reference solutions'))
|
||||
if solutions is None:
|
||||
raise InvalidCourse("No solutions subgroup")
|
||||
|
||||
if solution is None or reference_project is None:
|
||||
raise(GitlabCreateError(error_message='Failed to setup course'))
|
||||
reference_projects = solutions.projects.list(search='solutions')
|
||||
for project in reference_projects:
|
||||
if project.name == 'solutions':
|
||||
reference_project = gl.projects.get(project.id)
|
||||
|
||||
for user in get_students(gl, students_csv):
|
||||
create_project(gl, solution, user, reference_project, deploy_key)
|
||||
if reference_project is None:
|
||||
reference_project = create_reference_solution(gl, solutions.id)
|
||||
|
||||
for user in enrolled_students(gl, course):
|
||||
create_project(gl, solutions, user, reference_project, deploy_key)
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
import csv
|
||||
import secrets
|
||||
|
||||
|
||||
class MissingStudentsGroup(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MissingCourseGroup(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Student():
|
||||
|
@ -24,7 +33,7 @@ class Student():
|
|||
+ ' ' + line['Nachname'], line['Gruppe'])
|
||||
|
||||
|
||||
def get_students(gl, students_csv):
|
||||
def get_students_csv(gl, students_csv):
|
||||
"""Returns already existing GitLab users for students from provided CSV file that have an account.
|
||||
"""
|
||||
|
||||
|
@ -34,6 +43,24 @@ def get_students(gl, students_csv):
|
|||
yield users[0]
|
||||
|
||||
|
||||
def enrolled_students(gl, course):
|
||||
"""Returns the students enrolled in the course
|
||||
"""
|
||||
|
||||
students = None
|
||||
for group in course.subgroups.list(search='students'):
|
||||
if group.name == 'students':
|
||||
students = group
|
||||
|
||||
if students is None:
|
||||
raise MissingStudentsGroup()
|
||||
|
||||
# get all members excluding inherited members
|
||||
students = gl.groups.get(students.id)
|
||||
for member in students.members.list():
|
||||
yield gl.users.get(member.id)
|
||||
|
||||
|
||||
def create_user(gl, student, ldap_base, ldap_provider):
|
||||
"""Creates a GitLab user account student.
|
||||
Requires admin privileges.
|
||||
|
@ -52,3 +79,33 @@ def create_user(gl, student, ldap_base, ldap_provider):
|
|||
|
||||
return user
|
||||
|
||||
|
||||
def get_student_group(gl, course_name):
|
||||
"""Gets the `students` subgroup for the course
|
||||
"""
|
||||
|
||||
course = None
|
||||
for g in gl.groups.list(search=course_name):
|
||||
if g.name == course_name:
|
||||
course = g
|
||||
|
||||
if course is None:
|
||||
raise MissingCourseGroup()
|
||||
|
||||
students_group = None
|
||||
|
||||
for g in course.subgroups.list(search='students'):
|
||||
if g.name == 'students':
|
||||
students_group = gl.groups.get(g.id)
|
||||
|
||||
if students_group is None:
|
||||
raise MissingStudentsGroup()
|
||||
|
||||
return students_group
|
||||
|
||||
|
||||
def enroll_student(gl, user, group):
|
||||
"""Adds a student to the course
|
||||
"""
|
||||
pass
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import gitlab
|
|||
import argparse
|
||||
import logging as log
|
||||
|
||||
from abgabesystem.commands import create_users, projects, deadline, plagiates, course
|
||||
from abgabesystem.commands import enroll_students, projects, deadline, plagiates, course
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
|
@ -17,9 +17,10 @@ if __name__ == '__main__':
|
|||
|
||||
user_parser = subparsers.add_parser(
|
||||
'users',
|
||||
help='Creates users from LDAP')
|
||||
user_parser.set_defaults(func=create_users)
|
||||
help='Creates users and enrolls them in the course')
|
||||
user_parser.set_defaults(func=enroll_students)
|
||||
user_parser.add_argument('-s', '--students', dest='students')
|
||||
user_parser.add_argument('-c', '--course', dest='course')
|
||||
user_parser.add_argument('-b', '--ldap-base', dest='ldap_base')
|
||||
user_parser.add_argument('-p', '--ldap-provider', dest='ldap_provider')
|
||||
|
||||
|
@ -35,7 +36,6 @@ if __name__ == '__main__':
|
|||
projects_parser.set_defaults(func=projects)
|
||||
projects_parser.add_argument('-c', '--course', dest='course')
|
||||
projects_parser.add_argument('-d', '--deploy-key', dest='deploy_key')
|
||||
projects_parser.add_argument('-s', '--students', dest='students')
|
||||
|
||||
deadline_parser = subparsers.add_parser(
|
||||
'deadline',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue