console

package
v0.0.0-...-0985497 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 20, 2024 License: GPL-3.0 Imports: 39 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var AdminAddCmd = &cobra.Command{
	Use:   "add [userID]",
	Short: "set gives an user global admin permission",
	Long: `Will set the gobal root flag to "true" for a given user
 bypassing all permission tests`,
	Args: cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		userID := MustInt64Parameter(args[0], "userID")

		configuration.MustFindAndReadConfiguration()

		_, stores := MustConnectAndStores()

		user, err := stores.User.Get(userID)
		if err != nil {
			log.Fatalf("user with id %v not found\n", userID)
		}

		user.Root = true
		if err := stores.User.Update(user); err != nil {
			panic(err)
		}

		fmt.Printf("The user %s %s (id:%v) has now global admin privileges\n",
			user.FirstName, user.LastName, user.ID)
	},
}
View Source
var AdminCmd = &cobra.Command{
	Use:   "admin",
	Short: "Management of global admins.",
}
View Source
var AdminRemoveCmd = &cobra.Command{
	Use:   "remove [userID]",
	Short: "removes global admin permission from a user",
	Long:  `Will set the gobal root flag to false for a user `,
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		userID := MustInt64Parameter(args[0], "userID")

		configuration.MustFindAndReadConfiguration()

		_, stores := MustConnectAndStores()

		user, err := stores.User.Get(userID)
		if err != nil {
			log.Fatalf("user with id %v not found\n", userID)
		}
		user.Root = false
		if err := stores.User.Update(user); err != nil {
			panic(err)
		}

		fmt.Printf("user %s %s (%v) is not an admin anymore\n", user.FirstName, user.LastName, user.ID)

	},
}
View Source
var ConfigurationCmd = &cobra.Command{
	Use:   "configuration",
	Short: "infomark configuration commands",
}

ConfigurationCmd starts the infomark configuration

View Source
var CourseCmd = &cobra.Command{
	Use:   "course",
	Short: "Management of cours assignment",
}
View Source
var CreateConfiguration = &cobra.Command{
	Use:   "create",
	Short: "will create and print a configuration to stdout",
	Args:  cobra.ExactArgs(0),
	Run: func(cmd *cobra.Command, args []string) {

		ex, err := os.Executable()
		if err != nil {
			log.Fatalf("error: %v", err)
		}
		exPath := path.Join(filepath.Dir(ex), "files")

		config := GenerateExampleConfiguration("localhost", exPath)
		serialized_config, err := yaml.Marshal(&config)
		if err != nil {
			log.Fatalf("error: %v", err)
		}
		fmt.Println(string(serialized_config))
	},
}
View Source
var CreateDockercompose = &cobra.Command{
	Use:   "create-compose [configfile]",
	Short: "create docker-compose file from config",
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		config, err := configuration.ParseConfiguration(args[0])
		if err != nil {
			log.Fatalf("error: %v", err)
		}

		docker_compose, err := template.New("docker-compose").Parse(
			`version: "3"
services:
  rabbitmq_host:
    image: rabbitmq:3.7.3-management-alpine
    environment:
      - RABBITMQ_DEFAULT_USER={{.Server.Services.RabbitMQ.User}}
      - RABBITMQ_DEFAULT_PASS={{.Server.Services.RabbitMQ.Password}}
    ports:
      - 127.0.0.1:{{.Server.Services.RabbitMQ.Port}}:5672
      - 127.0.0.1:15672:15672
    volumes:
      - rabbitmq_volume:/data
  postgres_host:
    image: postgres:11.2-alpine
    environment:
      - POSTGRES_DB={{.Server.Services.Postgres.Database}}
      - POSTGRES_USER={{.Server.Services.Postgres.User}}
      - POSTGRES_PASSWORD={{.Server.Services.Postgres.Password}}
      - PGPASSWORD={{.Server.Services.Postgres.Password}}
    ports:
      - 127.0.0.1:{{.Server.Services.Postgres.Port}}:5432
    volumes:
      - postgres_volume:/var/lib/postgresql/data
  redis_host:
    image: redis:5.0.4-alpine
    ports:
      - 127.0.0.1:{{.Server.Services.Redis.Port}}:6379
volumes:
  rabbitmq_volume:
  postgres_volume:`)

		if err != nil {
			log.Fatalf("error: %v", err)
		}

		var tpl bytes.Buffer
		err = docker_compose.Execute(&tpl, config)
		if err != nil {
			log.Fatalf("error: %v", err)
		}

		fmt.Println(tpl.String())
	},
}
View Source
var DatabaseBackupCmd = &cobra.Command{
	Use:   "backup [file.sql.gz]",
	Short: "backup database to a file",
	Long:  `Will dump the entire database to a snapshot file`,
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		file := args[0]

		if helper.FileExists(file) {
			log.Fatalf("The file %s does exists! Will not override!\n", file)
		}

		configuration.MustFindAndReadConfiguration()

		shell1 := exec.Command("pg_dump",
			"-h", configuration.Configuration.Server.Services.Postgres.Host,
			"-U", configuration.Configuration.Server.Services.Postgres.User,
			"-p", fmt.Sprintf("%v", configuration.Configuration.Server.Services.Postgres.Port),
			"-d", configuration.Configuration.Server.Services.Postgres.Database)
		shell1.Env = os.Environ()
		shell1.Env = append(shell1.Env, fmt.Sprintf("PGPASSWORD=%s", configuration.Configuration.Server.Services.Postgres.Password))

		shell2 := exec.Command("gzip")

		r, w := io.Pipe()
		shell1.Stdout = w
		shell2.Stdin = r

		var b2 bytes.Buffer
		shell2.Stdout = &b2

		err := shell1.Start()
		if err != nil {
			log.Fatalf("Cannot call pg_dump and gzip! Did your run 'sudo apt install postgresql-client gzip'\n")
		}
		shell2.Start()
		err = shell1.Wait()
		if err != nil {
			log.Fatalf("Cannot call pg_dump and gzip! Did your run 'sudo apt install postgresql-client gzip'\n")
		}
		w.Close()
		err = shell2.Wait()
		if err != nil {
			panic(err)
		}

		destination, err := os.Create(file)
		if err != nil {
			panic(err)
		}
		defer destination.Close()
		_, err = io.Copy(destination, &b2)
		if err != nil {
			log.Fatalf("storing snapshot was not successful\n %s", err)
		}

	},
}
View Source
var DatabaseCmd = &cobra.Command{
	Use:   "database",
	Short: "Management of database.",
}
View Source
var DatabaseMigrateCmd = &cobra.Command{
	Use:   "migrate",
	Short: "migrate database to latest version",
	Long:  `manually run database migration`,
	Args:  cobra.ExactArgs(0),
	Run: func(cmd *cobra.Command, args []string) {
		log := logrus.New()
		log.SetFormatter(&logrus.TextFormatter{
			DisableColors: false,
			FullTimestamp: true,
		})
		log.Out = os.Stdout

		configuration.MustFindAndReadConfiguration()

		db, err := sqlx.Connect("postgres", configuration.Configuration.Server.PostgresURL())
		if err != nil {
			log.WithField("module", "database").Error(err)
		}

		migration.UpdateDatabase(db, log)

	},
}
View Source
var DatabaseRestoreCmd = &cobra.Command{
	Use:   "restore [file.sql.gz]",
	Short: "restore database from a file",
	Long:  `Will clean entire database and load a snapshot`,
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		file := args[0]

		if !helper.FileExists(file) {
			log.Fatalf("The file %s does not exists!\n", file)
		}

		configuration.MustFindAndReadConfiguration()

		shell := exec.Command("dropdb",
			"-h", configuration.Configuration.Server.Services.Postgres.Host,
			"-U", configuration.Configuration.Server.Services.Postgres.User,
			"-p", fmt.Sprintf("%v", configuration.Configuration.Server.Services.Postgres.Port),
			configuration.Configuration.Server.Services.Postgres.Database)
		shell.Env = os.Environ()
		shell.Env = append(shell.Env, fmt.Sprintf("PGPASSWORD=%s", configuration.Configuration.Server.Services.Postgres.Password))
		out, err := shell.CombinedOutput()
		fmt.Printf("%s", out)
		if err != nil {
			log.Fatal("dropping db was not successful")
		}

		shell = exec.Command("createdb",
			"-h", configuration.Configuration.Server.Services.Postgres.Host,
			"-U", configuration.Configuration.Server.Services.Postgres.User,
			"-p", fmt.Sprintf("%v", configuration.Configuration.Server.Services.Postgres.Port),
			"--owner", configuration.Configuration.Server.Services.Postgres.User,
			configuration.Configuration.Server.Services.Postgres.Database)
		shell.Env = os.Environ()
		shell.Env = append(shell.Env, fmt.Sprintf("PGPASSWORD=%s", configuration.Configuration.Server.Services.Postgres.Password))
		out, err = shell.CombinedOutput()
		fmt.Printf("%s", out)
		if err != nil {
			log.Fatal("creating db was not successful")
		}

		shell1 := exec.Command("gunzip",
			"-c", file)
		shell2 := exec.Command("psql",
			"-h", configuration.Configuration.Server.Services.Postgres.Host,
			"-U", configuration.Configuration.Server.Services.Postgres.User,
			"-p", fmt.Sprintf("%v", configuration.Configuration.Server.Services.Postgres.Port),
			configuration.Configuration.Server.Services.Postgres.Database)
		shell2.Env = os.Environ()
		shell2.Env = append(shell2.Env, fmt.Sprintf("PGPASSWORD=%s", configuration.Configuration.Server.Services.Postgres.Password))

		r, w := io.Pipe()
		shell1.Stdout = w
		shell2.Stdin = r

		var b2 bytes.Buffer
		shell2.Stdout = &b2

		shell1.Start()
		shell2.Start()
		shell1.Wait()
		w.Close()
		err = shell2.Wait()

		if err != nil {
			log.Fatalf("load db from was not successful\n %s", err)
		}
	},
}
View Source
var DatabaseRunCmd = &cobra.Command{
	Use:   "run [sql]",
	Short: "run a sql command",
	Long:  `run a SQl statement. This statement will persistently changes entries!`,
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		sql := args[0]

		configuration.MustFindAndReadConfiguration()

		shell := exec.Command("psql",
			"-h", configuration.Configuration.Server.Services.Postgres.Host,
			"-U", configuration.Configuration.Server.Services.Postgres.User,
			"-p", fmt.Sprintf("%v", configuration.Configuration.Server.Services.Postgres.Port),
			"-d", configuration.Configuration.Server.Services.Postgres.Database,
			"-c", sql)
		shell.Env = os.Environ()
		shell.Env = append(shell.Env, fmt.Sprintf("PGPASSWORD=%s", configuration.Configuration.Server.Services.Postgres.Password))
		out, err := shell.CombinedOutput()
		fmt.Printf("%s", out)
		if err != nil {
			log.Fatal("executing SQL-statement was not successful")
		}

	},
}
View Source
var GroupCmd = &cobra.Command{
	Use:   "group",
	Short: "Management of groups",
}
View Source
var GroupEnroll = &cobra.Command{
	Use:   "enroll [groupID] [userID]",
	Short: "enroll a student to a group",
	Long: `enroll a student to a group or update enrollment if student is
already enrolled in another group`,
	Args: cobra.ExactArgs(2),
	Run: func(cmd *cobra.Command, args []string) {
		groupID := MustInt64Parameter(args[0], "groupID")
		userID := MustInt64Parameter(args[1], "userID")

		configuration.MustFindAndReadConfiguration()

		_, stores := MustConnectAndStores()

		user, err := stores.User.Get(userID)
		failWhenSmallestWhiff(err)

		course, err := stores.Group.IdentifyCourseOfGroup(groupID)
		failWhenSmallestWhiff(err)

		enrollment, err := stores.Group.GetGroupEnrollmentOfUserInCourse(userID, course.ID)

		if err != nil {

			enrollment := &model.GroupEnrollment{
				UserID:  userID,
				GroupID: groupID,
			}

			_, err := stores.Group.CreateGroupEnrollmentOfUserInCourse(enrollment)
			failWhenSmallestWhiff(err)

		} else {
			group, err := stores.Group.Get(enrollment.GroupID)
			failWhenSmallestWhiff(err)

			fmt.Printf("user %s %s (id: %v) was    enrolled in group (%v) %s\n",
				user.FirstName,
				user.LastName,
				user.ID,
				group.ID, group.Description)

			enrollment.GroupID = groupID
			err = stores.Group.ChangeGroupEnrollmentOfUserInCourse(enrollment)
			failWhenSmallestWhiff(err)

		}

		group, err := stores.Group.Get(groupID)
		failWhenSmallestWhiff(err)

		fmt.Printf("user %s %s (id: %v) is now enrolled in group (%v) %s\n",
			user.FirstName,
			user.LastName,
			user.ID,
			group.ID, group.Description)

	},
}
View Source
var GroupList = &cobra.Command{
	Use:   "list [courseID]",
	Short: "list all groups from a specific course",
	Long: `shows information about exercise groups with their description and
number of assigned students`,
	Args: cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		courseID := MustInt64Parameter(args[0], "courseID")

		configuration.MustFindAndReadConfiguration()

		db, _ := MustConnectAndStores()

		groupSummaries := []groupSummary{}

		err := db.Select(&groupSummaries, `
SELECT
  count(*), ug.group_id, g.description
FROM
  user_group ug
INNER JOIN groups g ON g.id = ug.group_id
WHERE
  g.course_id = $1
GROUP BY
  ug.group_id, g.description
ORDER BY g.description
    `, courseID)
		failWhenSmallestWhiff(err)

		fmt.Printf("count   groupID    description\n")
		for k, v := range groupSummaries {
			fmt.Printf("%5d  %7d   %s\n", v.Count, v.GroupID, v.Description)
			if k%5 == 0 {
				fmt.Println("")
			}
		}
	},
}
View Source
var GroupLocate = &cobra.Command{
	Use:   "locate [courseID] [userID]",
	Short: "locate a student in a group",
	Long:  `show the exercise group for a given student`,
	Args:  cobra.ExactArgs(2),
	Run: func(cmd *cobra.Command, args []string) {
		courseID := MustInt64Parameter(args[0], "courseID")
		userID := MustInt64Parameter(args[1], "userID")

		configuration.MustFindAndReadConfiguration()

		_, stores := MustConnectAndStores()
		user, err := stores.User.Get(userID)
		if err != nil {
			log.Fatalf("user with id %v not found\n", userID)
		}

		course, err := stores.Course.Get(courseID)
		if err != nil {
			log.Fatalf("course with id %v not found\n", courseID)
		}

		groups, err := stores.Group.GetInCourseWithUser(user.ID, course.ID)
		failWhenSmallestWhiff(err)

		if len(groups) == 0 {
			log.Fatalf("user %s %s (%d) is not enrolled as a student in course %s (%d)",
				user.FirstName, user.LastName, user.ID, course.Name, course.ID)
		}

		group := groups[0]

		fmt.Printf("found\n")
		fmt.Printf(" - Group (%d):   %s\n", group.ID, group.Description)
		fmt.Printf(" - Tutor (%d):   %s %s\n", group.TutorID, group.TutorFirstName, group.TutorLastName)
		fmt.Printf(" - Student (%d): %s %s \n", user.ID, user.FirstName, user.LastName)

	},
}
View Source
var GroupParseBidsSolution = &cobra.Command{

	Use:   "import-assignments [courseID] [file]",
	Short: "parse solution and assign students to groups",
	Long:  `for assignment`,
	Args:  cobra.ExactArgs(2),
	Run: func(cmd *cobra.Command, args []string) {

		type Assignment struct {
			GroupID int64
			UserID  int64
		}

		courseID := MustInt64Parameter(args[0], "courseID")

		configuration.MustFindAndReadConfiguration()

		db, stores := MustConnectAndStores()

		course, err := stores.Course.Get(courseID)
		if err != nil {
			log.Fatalf("course with id %v not found\n", course.ID)
		}
		fmt.Println("work on course", course.ID)

		file, err := os.Open(args[1])
		failWhenSmallestWhiff(err)
		defer file.Close()

		reader := bufio.NewReader(file)
		uids := []int64{}
		assignments := []Assignment{}
		for {
			line, _, err := reader.ReadLine()
			if err == io.EOF {
				break
			}

			line_string := string(line)
			if strings.HasPrefix(line_string, "assign[") {
				parts := strings.Split(line_string, "[")
				parts = strings.Split(parts[1], "]")
				parts = strings.Split(parts[0], ",")

				v, err := strconv.Atoi(parts[0][1:])
				failWhenSmallestWhiff(err)
				w, err := strconv.Atoi(parts[1][1:])
				failWhenSmallestWhiff(err)

				assignments = append(assignments, Assignment{GroupID: int64(w), UserID: int64(v)})
				uids = append(uids, int64(v))
			}

		}

		tx, err := db.Begin()
		failWhenSmallestWhiff(err)

		_, err = tx.Exec(`
DELETE FROM
  user_group ug
USING
  groups g
WHERE
  ug.group_id = g.id
AND
  g.course_id = $1
AND
  ug.user_id = ANY($2)`, course.ID, pq.Array(uids))
		if err != nil {
			fmt.Println(err)
			tx.Rollback()
			failWhenSmallestWhiff(err)
		}

		for _, assignment := range assignments {
			fmt.Printf("%v %v\n", assignment.UserID, assignment.GroupID)

			_, err = tx.Exec("INSERT INTO user_group (id,user_id,group_id) VALUES (DEFAULT,$1,$2);", assignment.UserID, assignment.GroupID)
			if err != nil {
				tx.Rollback()
				failWhenSmallestWhiff(err)
			}
		}

		err = tx.Commit()
		if err != nil {
			tx.Rollback()
			failWhenSmallestWhiff(err)
		}

		fmt.Println("Done")

	},
}
View Source
var GroupReadBids = &cobra.Command{
	Use:   "dump-bids [courseID] [file]  [min_per_group] [max_per_group]",
	Short: "export group-bids of all users in a course",
	Long:  `for assignment`,
	Args:  cobra.ExactArgs(4),
	Run: func(cmd *cobra.Command, args []string) {

		courseID := MustInt64Parameter(args[0], "courseID")
		minPerGroup := MustIntParameter(args[2], "minPerGroup")
		maxPerGroup := MustIntParameter(args[3], "maxPerGroup")

		if minPerGroup > maxPerGroup {
			log.Fatalf("minPerGroup %d > maxPerGroup %d is infeasible",
				minPerGroup, maxPerGroup)
		}

		fmt.Printf("bound Group Capacitiy >= %v\n", minPerGroup)
		fmt.Printf("bound Group Capacitiy <= %v\n", maxPerGroup)

		f, err := os.Create(fmt.Sprintf("%s.dat", args[1]))
		failWhenSmallestWhiff(err)
		defer f.Close()

		configuration.MustFindAndReadConfiguration()

		db, stores := MustConnectAndStores()

		course, err := stores.Course.Get(courseID)
		if err != nil {
			log.Fatalf("course with id %v not found\n", course.ID)
		}

		groups, err := stores.Group.GroupsOfCourse(course.ID)
		failWhenSmallestWhiff(err)

		fmt.Printf("found %v groups\n", len(groups))

		groupIDArray := []int64{}
		for _, group := range groups {
			groupIDArray = append(groupIDArray, group.ID)
		}

		gids := strings.Trim(strings.Replace(fmt.Sprint(groupIDArray), " ", " g", -1), "[]")

		students, err := stores.Course.EnrolledUsers(course.ID,
			[]string{"0"},
			"%%",
			"%%",
			"%%",
			"%%",
			"%%",
		)
		failWhenSmallestWhiff(err)

		fmt.Printf("found %v students\n", len(students))
		fmt.Printf("\n")
		fmt.Printf("\n")

		uids := ""
		for _, student := range students {
			g := strconv.FormatInt(student.ID, 10)
			uids = uids + " u" + g
		}

		f.WriteString(fmt.Sprintf("set group := g%s;\n", gids))
		f.WriteString(fmt.Sprintf("set student := %s;\n", uids))
		f.WriteString("\n")
		f.WriteString("param pref:\n")
		f.WriteString(fmt.Sprintf("     g%s:=\n", gids))

		for _, student := range students {
			uid := strconv.FormatInt(student.ID, 10)
			bids := []model.GroupBid{}

			err := db.Select(&bids, `
SELECT
  *
FROM
  group_bids
WHERE
  user_id = $1
AND
  group_id = ANY($2)
ORDER BY
  group_id ASC`, student.ID, pq.Array(groupIDArray))
			if err != nil {
				panic(err)
			}

			f.WriteString(fmt.Sprintf("u%s", uid))

			for _, group := range groups {
				bidValue := 10
				for _, bid := range bids {
					if bid.GroupID == group.ID {
						bidValue = bid.Bid
						break
					}
				}
				f.WriteString(fmt.Sprintf(" %v", bidValue))
			}
			f.WriteString("\n")
		}

		f.WriteString(";\n")
		f.WriteString("\n")
		f.WriteString("end;\n")

		fmod, err := os.Create(fmt.Sprintf("%s.mod", args[1]))
		failWhenSmallestWhiff(err)
		defer fmod.Close()

		fmod.WriteString("set student;\n")
		fmod.WriteString("set group;\n")
		fmod.WriteString("\n")
		fmod.WriteString("var assign{i in student, j in group} binary;\n")
		fmod.WriteString("param pref{i in student, j in group};\n")
		fmod.WriteString("\n")
		fmod.WriteString("maximize totalPref:\n")
		fmod.WriteString("    sum{i in student, j in group} pref[i,j]*assign[i,j];\n")
		fmod.WriteString("\n")
		fmod.WriteString("subject to exactly_one_group {i in student}:\n")
		fmod.WriteString("    sum {j in group} assign[i,j] =1;\n")
		fmod.WriteString("\n")
		fmod.WriteString("subject to min3{j in group}:\n")
		fmod.WriteString(fmt.Sprintf("    sum{i in student} assign[i,j]>=%v;\n", minPerGroup))
		fmod.WriteString("\n")
		fmod.WriteString("subject to max4{j in group}:\n")
		fmod.WriteString(fmt.Sprintf("    sum{i in student} assign[i,j]<=%v;\n", maxPerGroup))
		fmod.WriteString("\n")
		fmod.WriteString("end;\n")
		fmod.WriteString("\n")
		fmod.WriteString("\n")

		fmt.Println("run the command")
		fmt.Println("")
		fmt.Println("")
		fmt.Printf("sudo docker run -v \"$PWD\":/data -it patwie/symphony  /var/symphony/bin/symphony -F %s.mod -D /data/%s.dat -f /data/%s.par\n", args[1], args[1], args[1])
		fmt.Println("")

		fpar, err := os.Create(fmt.Sprintf("%s.par", args[1]))
		failWhenSmallestWhiff(err)
		fpar.WriteString("time_limit 50\n")
		fpar.WriteString("\n")
		defer fpar.Close()

	},
}
View Source
var GroupUserBids = &cobra.Command{
	Use:   "bids [courseID] [userID]",
	Short: "list all bids of a user",
	Args:  cobra.ExactArgs(2),
	Run: func(cmd *cobra.Command, args []string) {
		courseID := MustInt64Parameter(args[0], "courseID")
		userID := MustInt64Parameter(args[1], "userID")

		configuration.MustFindAndReadConfiguration()

		db, stores := MustConnectAndStores()

		user, err := stores.User.Get(userID)
		if err != nil {
			log.Fatalf("user with id %v not found\n", userID)
		}

		course, err := stores.Course.Get(courseID)
		if err != nil {
			log.Fatalf("course with id %v not found\n", courseID)
		}

		userBidSummaries := []userBidSummary{}

		err = db.Select(&userBidSummaries, `
SELECT
  bid, group_id, description
FROM
  group_bids gb
INNER JOIN groups g ON gb.group_id = g.id
WHERE
  gb.user_id = $1
AND
  g.course_id = $2
    `, user.ID, course.ID)
		failWhenSmallestWhiff(err)

		fmt.Printf("  bid   groupID    description\n")
		for k, v := range userBidSummaries {
			fmt.Printf("%5d  %7d   %s\n", v.Bid, v.GroupID, v.Description)
			if k%5 == 0 && k > 0 {
				fmt.Println("")
			}
		}

	},
}
View Source
var SubmissionCmd = &cobra.Command{
	Use:   "submission",
	Short: "Management of submission",
}

SubmissionCmd is the command all submission related actions.

View Source
var SubmissionRunCmd = &cobra.Command{
	Use:   "run [submissionID]",
	Short: "run tests for a submission without writing to db",
	Long:  `will enqueue a submission again into the testing queue`,
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {

		submissionID := MustInt64Parameter(args[0], "submissionID")

		configuration.MustFindAndReadConfiguration()
		_, stores := MustConnectAndStores()

		submission, err := stores.Submission.Get(submissionID)
		failWhenSmallestWhiff(err)

		task, err := stores.Task.Get(submission.TaskID)
		failWhenSmallestWhiff(err)

		log.Println("try starting docker...")

		ds, err := service.NewDockerServiceWithTimeout(configuration.Configuration.Worker.Docker.Timeout)
		if err != nil {
			log.Fatal(err)
		}
		defer ds.Client.Close()

		var exit int64
		var stdout string

		submissionHnd := helper.NewSubmissionFileHandle(submission.ID)
		if !submissionHnd.Exists() {
			log.Fatalf("submission file %s for id %v is missing", submissionHnd.Path(), submission.ID)
		}

		if task.PublicDockerImage.Valid {
			frameworkHnd := helper.NewPublicTestFileHandle(task.ID)
			if frameworkHnd.Exists() {

				log.Printf("use docker image \"%v\"\n", task.PublicDockerImage.String)
				log.Printf("use framework file \"%v\"\n", frameworkHnd.Path())
				stdout, exit, err = ds.Run(
					task.PublicDockerImage.String,
					submissionHnd.Path(),
					frameworkHnd.Path(),
					int64(configuration.Configuration.Worker.Docker.MaxMemory),
				)
				if err != nil {
					log.Fatal(err)
				}

				fmt.Println(" --- STDOUT -- BEGIN ---")
				fmt.Println(stdout)
				fmt.Println(" --- STDOUT -- END   ---")
				fmt.Printf("exit-code: %v\n", exit)
			} else {
				fmt.Println("skip public test, there is no framework file")

			}

		} else {
			fmt.Println("skip public test, there is no docker file")
		}

		if task.PrivateDockerImage.Valid {
			frameworkHnd := helper.NewPrivateTestFileHandle(task.ID)
			if frameworkHnd.Exists() {

				log.Printf("use docker image \"%v\"\n", task.PrivateDockerImage.String)
				log.Printf("use framework file \"%v\"\n", frameworkHnd.Path())
				stdout, exit, err = ds.Run(
					task.PrivateDockerImage.String,
					submissionHnd.Path(),
					frameworkHnd.Path(),
					int64(configuration.Configuration.Worker.Docker.MaxMemory),
				)
				if err != nil {
					log.Fatal(err)
				}

				fmt.Println(" --- STDOUT -- BEGIN ---")
				fmt.Println(stdout)
				fmt.Println(" --- STDOUT -- END   ---")
				fmt.Printf("exit-code: %v\n", exit)
			} else {
				fmt.Println("skip private test, there is no framework file")

			}

		} else {
			fmt.Println("skip private test, there is no docker file")
		}

	},
}

SubmissionRunCmd will run the docker test locally and print the result to stdout.

View Source
var SubmissionTriggerAllCmd = &cobra.Command{
	Use:   "trigger_all [taskID] [kind]",
	Short: "trigger_all tests all submissions for a given task",
	Long: `Will enqueue all submissions for a given task again into the testing queue
This triggers all [kind]-tests again (private, public).
`,
	Args: cobra.ExactArgs(2),
	Run: func(cmd *cobra.Command, args []string) {

		configuration.MustFindAndReadConfiguration()

		taskID := MustInt64Parameter(args[0], "taskID")

		switch args[1] {
		case "public", "private":
		default:
			log.Fatalf("kind '%s' must be one of 'public', 'private'\n", args[2])
		}

		db, stores := MustConnectAndStores()

		task, err := stores.Task.Get(taskID)
		failWhenSmallestWhiff(err)

		sheet, err := stores.Task.IdentifySheetOfTask(task.ID)
		failWhenSmallestWhiff(err)

		course, err := stores.Sheet.IdentifyCourseOfSheet(sheet.ID)
		failWhenSmallestWhiff(err)

		log.Println("starting producer...")

		cfg := service.NewConfig(&configuration.Configuration.Server.Services.RabbitMQ)

		submissions := []SubmissionWithGradeID{}
		err = db.Select(&submissions, `
SELECT
  s.*, g.id grade_id
FROM
  submissions s
INNER JOIN grades g ON s.id = g.submission_ID
WHERE task_id = $1
    `, task.ID)
		failWhenSmallestWhiff(err)

		producer, _ := service.NewProducer(cfg)
		logger := logrus.New()
		logger.SetFormatter(&logrus.TextFormatter{
			DisableColors: false,
			FullTimestamp: true,
		})
		logger.Out = os.Stdout

		for _, submissionWithGrade := range submissions {
			sublog := logger.WithFields(logrus.Fields{"submissionID": submissionWithGrade.ID})

			sublog.Info("Try to enqueue")

			submissionHnd := helper.NewSubmissionFileHandle(submissionWithGrade.ID)
			if !submissionHnd.Exists() {
				sublog.Warn("uploaded file does not exists --> skip")
			}

			sha256, err := helper.NewSubmissionFileHandle(submissionWithGrade.ID).Sha256()
			if err != nil {
				sublog.Warn("Skip as sha cannot be computed")
			}

			tokenManager := authenticate.NewTokenAuth(&configuration.Configuration.Server.Authentication)

			accessToken, err := tokenManager.CreateAccessJWT(
				authenticate.NewAccessClaims(1, true))
			failWhenSmallestWhiff(err)

			var (
				body []byte
				merr error
			)

			if args[1] == "public" {
				body, merr = json.Marshal(shared.NewSubmissionAMQPWorkerRequest(
					course.ID, taskID, submissionWithGrade.ID, submissionWithGrade.GradeID,
					accessToken, configuration.Configuration.Server.ExternalURL(), task.PublicDockerImage.String, sha256, "public"))

			} else {
				body, merr = json.Marshal(shared.NewSubmissionAMQPWorkerRequest(
					course.ID, taskID, submissionWithGrade.ID, submissionWithGrade.GradeID,
					accessToken, configuration.Configuration.Server.ExternalURL(), task.PrivateDockerImage.String, sha256, "private"))
			}
			if merr != nil {
				log.Fatalf("json.Marshal: %s", merr)
			}

			producer.Publish(body)

		}

	},
}

SubmissionTriggerAllCmd will enqeue all submission for a given task into the testing queue. This is useful, when something in the testing framework has changed (eg. bug in the solution or a test case).

View Source
var SubmissionTriggerCmd = &cobra.Command{
	Use:   "trigger [submissionID]",
	Short: "put submission into testing queue",
	Long:  `will enqueue a submission again into the testing queue`,
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {

		configuration.MustFindAndReadConfiguration()

		submissionID := MustInt64Parameter(args[0], "submissionID")

		_, stores := MustConnectAndStores()

		submission, err := stores.Submission.Get(submissionID)
		failWhenSmallestWhiff(err)

		task, err := stores.Task.Get(submission.TaskID)
		failWhenSmallestWhiff(err)

		sheet, err := stores.Task.IdentifySheetOfTask(submission.TaskID)
		failWhenSmallestWhiff(err)

		course, err := stores.Sheet.IdentifyCourseOfSheet(sheet.ID)
		failWhenSmallestWhiff(err)

		grade, err := stores.Grade.GetForSubmission(submission.ID)
		failWhenSmallestWhiff(err)

		log.Println("starting producer...")

		cfg := service.NewConfig(&configuration.Configuration.Server.Services.RabbitMQ)

		sha256, err := helper.NewSubmissionFileHandle(submission.ID).Sha256()
		failWhenSmallestWhiff(err)

		tokenManager := authenticate.NewTokenAuth(&configuration.Configuration.Server.Authentication)

		accessToken, err := tokenManager.CreateAccessJWT(
			authenticate.NewAccessClaims(1, true))
		failWhenSmallestWhiff(err)

		bodyPublic, err := json.Marshal(shared.NewSubmissionAMQPWorkerRequest(
			course.ID, task.ID, submission.ID, grade.ID,
			accessToken, configuration.Configuration.Server.ExternalURL(), task.PublicDockerImage.String, sha256, "public"))
		if err != nil {
			log.Fatalf("json.Marshal: %s", err)
		}

		bodyPrivate, err := json.Marshal(shared.NewSubmissionAMQPWorkerRequest(
			course.ID, task.ID, submission.ID, grade.ID,
			accessToken, configuration.Configuration.Server.ExternalURL(), task.PrivateDockerImage.String, sha256, "private"))
		if err != nil {
			log.Fatalf("json.Marshal: %s", err)
		}

		producer, _ := service.NewProducer(cfg)
		producer.Publish(bodyPublic)
		producer.Publish(bodyPrivate)

	},
}

SubmissionTriggerCmd will enqeue a submitted submission again into the testing queue.

View Source
var TestConfiguration = &cobra.Command{
	Use:   "test [configfile]",
	Short: "will create and print a configuration to stdout",
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		report := goblin.DetailedReporter{}
		report.SetTextFancier(&goblin.TerminalFancier{})

		report.BeginDescribe("Test configuration")
		status_code := 0
		config, err := configuration.ParseConfiguration(args[0])
		showResult(&report, err, "read configuration from file")
		if err != nil {
			status_code = -1
		}
		report.EndDescribe()

		if test == "server" {

			report.BeginDescribe("Test services")

			db, err := sqlx.Connect("postgres", config.Server.PostgresURL())
			showResult(&report, err, "connect to postgres db")
			if err != nil {
				status_code = -1
			} else {
				db.Close()
			}

			option, _ := redis.ParseURL(config.Server.RedisURL())
			redisClient := redis.NewClient(option)
			_, err = redisClient.Ping(context.Background()).Result()
			showResult(&report, err, "connect to redis url")
			if err != nil {
				status_code = -1
			} else {
				redisClient.Close()
			}

			mqConnection, err := amqp.Dial(config.Server.Services.RabbitMQ.URL())
			showResult(&report, err, "connect to rabbit mq")
			if err != nil {
				status_code = -1
			} else {
				mqConnection.Close()
			}
			report.EndDescribe()

			report.BeginDescribe("Test paths")
			err = fs.DirExists(config.Server.Paths.Common)
			showResult(&report, err, "common path readable")
			if err != nil {
				status_code = -1
			}

			err = fs.IsDirWriteable(config.Server.Paths.Uploads)
			showResult(&report, err, "upload path writeable")
			if err != nil {
				status_code = -1
			}

			err = fs.IsDirWriteable(config.Server.Paths.GeneratedFiles)
			showResult(&report, err, "generated_files path writeable")
			if err != nil {
				status_code = -1
			}

			privacyFile := fmt.Sprintf("%s/privacy_statement.md", config.Server.Paths.Common)
			err = fs.FileExists(privacyFile)
			showResult(&report, err, fmt.Sprintf("Read privacy Statement from %s", privacyFile))
			if err != nil {
				status_code = -1
			}
			report.EndDescribe()

		} else {

			report.BeginDescribe("Test services")

			mqConnection, err := amqp.Dial(config.Server.Services.RabbitMQ.URL())
			showResult(&report, err, "connect to rabbit mq")
			if err != nil {
				status_code = -1
			} else {
				mqConnection.Close()
			}

			dockerClient, err := client.NewClientWithOpts(client.WithAPIVersionNegotiation())
			showResult(&report, err, "create docker client")
			if err != nil {
				status_code = -1
			} else {
				ctx := context.Background()
				resp, err := dockerClient.ContainerCreate(ctx, &container.Config{
					Image:           "hello-world",
					Cmd:             []string{},
					Tty:             true,
					AttachStdin:     false,
					AttachStdout:    true,
					AttachStderr:    true,
					NetworkDisabled: true,
				}, nil, nil, nil, "")
				showResult(&report, err, "create docker container")

				if err != nil {
					status_code = -1
				} else {
					dockerClient.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{})
					if err != nil {
						status_code = -1
					}

				}

				dockerClient.Close()
			}
			report.EndDescribe()

		}

		os.Exit(status_code)
	},
}
View Source
var UserCmd = &cobra.Command{
	Use:   "user",
	Short: "Management of users",
}
View Source
var UserConfirmCmd = &cobra.Command{
	Use:   "confirm [email]",
	Short: "confirms the email address manually",
	Long:  `Will run confirmation procedure for an user `,
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		configuration.MustFindAndReadConfiguration()

		_, stores := MustConnectAndStores()

		email := args[0]
		if err := is.Email.Validate(email); err != nil {
			log.Fatalf("email '%s' is not a valid email\n", email)
		}

		user, err := stores.User.FindByEmail(email)
		if err != nil {
			log.Fatalf("user with email %v not found\n", email)
		}

		user.ConfirmEmailToken = null.String{}
		if err := stores.User.Update(user); err != nil {
			panic(err)
		}

		fmt.Printf("email %s of user %s %s has been confirmed\n",
			email, user.FirstName, user.LastName)
	},
}
View Source
var UserEnrollInCourse = &cobra.Command{
	Use:   "enroll [courseID] [userID] [role]",
	Short: "will enroll a user into course",
	Args:  cobra.ExactArgs(3),
	Run: func(cmd *cobra.Command, args []string) {
		var err error

		courseID := MustInt64Parameter(args[0], "courseID")
		userID := MustInt64Parameter(args[1], "userID")

		role := int64(0)
		switch args[2] {
		case "admin":
			role = int64(2)
		case "tutor":
			role = int64(1)
		case "student":
			role = int64(0)
		default:
			log.Fatalf("role '%s' must be one of 'student', 'tutor', 'admin'\n", args[2])
		}

		configuration.MustFindAndReadConfiguration()

		_, stores := MustConnectAndStores()

		user, err := stores.User.Get(userID)
		if err != nil {
			log.Fatalf("user with id %v not found\n", userID)
		}

		course, err := stores.Course.Get(courseID)
		if err != nil {
			log.Fatalf("user with id %v not found\n", userID)
		}

		if err := stores.Course.Enroll(course.ID, user.ID, role); err != nil {
			panic(err)
		}

		fmt.Printf("user %s %s is now enrolled in course %v with role %v\n",
			user.FirstName, user.LastName, course.ID, role)
	},
}
View Source
var UserFindCmd = &cobra.Command{
	Use:   "find [query]",
	Short: "find user by first_name, last_name or email",
	Long:  `List all users matching the query`,
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		configuration.MustFindAndReadConfiguration()

		db, _ := MustConnectAndStores()

		query := fmt.Sprintf("%%%s%%", args[0])

		users := []model.User{}
		err := db.Select(&users, `
SELECT
  *
FROM
  users
WHERE
 last_name LIKE $1
OR
 first_name LIKE $1
OR
 email LIKE $1`, query)
		failWhenSmallestWhiff(err)

		fmt.Printf("found %v users matching %s\n", len(users), query)
		for k, user := range users {
			fmt.Printf("%4d %20s %20s %50s\n",
				user.ID, user.FirstName, user.LastName, user.Email)
			if k%10 == 0 && k != 0 {
				fmt.Println("")
			}
		}

		fmt.Printf("found %v users matching %s\n", len(users), query)
	},
}
View Source
var UserSetEmailCmd = &cobra.Command{
	Use:   "set-email [userID] [email]",
	Short: "will alter the email address",
	Long:  `Will change email address of an user without confirmation procedure`,
	Args:  cobra.ExactArgs(2),
	Run: func(cmd *cobra.Command, args []string) {
		userID := MustInt64Parameter(args[0], "userID")
		email := args[1]
		if err := is.Email.Validate(email); err != nil {
			log.Fatalf("email '%s' is not a valid email\n", email)
		}

		configuration.MustFindAndReadConfiguration()

		_, stores := MustConnectAndStores()

		user, err := stores.User.Get(userID)
		if err != nil {
			fmt.Printf("user with id %v not found\n", userID)
			return
		}

		user.Email = email
		if err := stores.User.Update(user); err != nil {
			panic(err)
		}

		fmt.Printf("email of user %s %s is now %s\n",
			user.FirstName, user.LastName, user.Email)
	},
}

Functions

func ByteFromString

func ByteFromString(str string) bytefmt.ByteSize

func ConnectAndStores

func ConnectAndStores() (*sqlx.DB, *app.Stores, error)

func DurationFromString

func DurationFromString(dur string) time.Duration

func GenerateExampleConfiguration

func GenerateExampleConfiguration(domain string, root_path string) *configuration.ConfigurationSchema

func MustConnectAndStores

func MustConnectAndStores() (*sqlx.DB, *app.Stores)

func MustInt64Parameter

func MustInt64Parameter(argStr string, name string) int64

func MustIntParameter

func MustIntParameter(argStr string, name string) int

Types

type SubmissionWithGradeID

type SubmissionWithGradeID struct {
	*model.Submission
	GradeID int64 `db:"grade_id"`
}

SubmissionWithGradeID represents a submission and the gradeID.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL