This repository has been archived on 2024-03-03. You can view files and clone it, but cannot push or open issues or pull requests.
adlin/token-validator/students.go

220 lines
6.3 KiB
Go
Raw Normal View History

2018-02-20 12:49:03 +00:00
package main
import (
2018-02-20 17:20:07 +00:00
"crypto/hmac"
"crypto/sha512"
2018-02-20 12:49:03 +00:00
"encoding/json"
"fmt"
2018-02-20 12:49:03 +00:00
"strings"
"time"
"github.com/julienschmidt/httprouter"
)
func init() {
2018-02-22 03:47:57 +00:00
router.GET("/api/progress/", apiHandler(
func(httprouter.Params, []byte) (interface{}, error) {
if stds, err := getStudents(); err != nil {
return nil, err
} else {
ret := map[string]map[string]UnlockedChallenge{}
2018-02-22 03:47:57 +00:00
for _, std := range stds {
if sts, err := std.getStates(); err == nil {
ret[std.Login] = map[string]UnlockedChallenge{}
for _, s := range sts {
ret[std.Login][fmt.Sprintf("%d", s.Challenge)] = s
}
2018-02-22 03:47:57 +00:00
}
}
return ret, nil
}
}))
2018-02-20 12:49:03 +00:00
router.GET("/api/students/", apiHandler(
2018-02-20 17:20:07 +00:00
func(httprouter.Params, []byte) (interface{}, error) {
return getStudents()
}))
router.POST("/api/students/", remoteValidatorHandler(apiHandler(createStudent)))
router.GET("/api/students/:sid/", apiHandler(studentHandler(
func(std Student, _ []byte) (interface{}, error) {
2018-02-20 17:20:07 +00:00
return std, nil
})))
router.PUT("/api/students/:sid/", remoteValidatorHandler(apiHandler(studentHandler(updateStudent))))
router.DELETE("/api/students/:sid/", remoteValidatorHandler(apiHandler(studentHandler(
func(std Student, _ []byte) (interface{}, error) {
2018-02-20 17:20:07 +00:00
return std.Delete()
}))))
2018-02-20 12:49:03 +00:00
}
type Student struct {
Id int64 `json:"id"`
Login string `json:"login"`
Time time.Time `json:"time"`
IP string `json:"ip"`
MAC string `json:"mac"`
2018-02-20 12:49:03 +00:00
}
2018-02-22 04:36:46 +00:00
type uploadedStudent struct {
Login string `json:"login"`
IP string `json:"ip"`
MAC string `json:"mac"`
}
2018-02-20 12:49:03 +00:00
func getStudents() (students []Student, err error) {
if rows, errr := DBQuery("SELECT S.id_student, S.login, MAX(L.time), L.ip, L.mac FROM students S INNER JOIN (SELECT a.id_student, a.time, a.ip, a.mac FROM student_login a INNER JOIN (SELECT id_student, MAX(time) AS time FROM student_login GROUP BY id_student) b ON a.id_student = b.id_student AND a.time = b.time) L ON S.id_student = L.id_student"); errr != nil {
2018-02-20 12:49:03 +00:00
return nil, errr
} else {
defer rows.Close()
for rows.Next() {
var s Student
if err = rows.Scan(&s.Id, &s.Login, &s.Time, &s.IP, &s.MAC); err != nil {
2018-02-20 12:49:03 +00:00
return
}
students = append(students, s)
}
if err = rows.Err(); err != nil {
return
}
return
}
}
func getStudent(id int) (s Student, err error) {
err = DBQueryRow("SELECT S.id_student, S.login, MAX(L.time), L.ip, L.mac FROM students S INNER JOIN (SELECT a.id_student, a.time, a.ip, a.mac FROM student_login a INNER JOIN (SELECT id_student, MAX(time) AS time FROM student_login GROUP BY id_student) b ON a.id_student = b.id_student AND a.time = b.time) L ON S.id_student = L.id_student WHERE S.id_student=?", id).Scan(&s.Id, &s.Login, &s.Time, &s.IP, &s.MAC)
2018-02-20 12:49:03 +00:00
return
}
func getStudentByLogin(login string) (s Student, err error) {
err = DBQueryRow("SELECT id_student, login, time FROM students WHERE login=?", login).Scan(&s.Id, &s.Login, &s.Time)
return
}
func studentExists(login string) bool {
var z int
err := DBQueryRow("SELECT 1 FROM students WHERE login=?", login).Scan(&z)
return err != nil && z == 1
}
func NewStudent(login string) (Student, error) {
if res, err := DBExec("INSERT INTO students (login, time) VALUES (?, ?)", login, time.Now()); err != nil {
2018-02-20 12:49:03 +00:00
return Student{}, err
} else if sid, err := res.LastInsertId(); err != nil {
return Student{}, err
} else {
return Student{sid, login, time.Now(), "", ""}, nil
2018-02-20 12:49:03 +00:00
}
}
2018-02-20 17:20:07 +00:00
func (s Student) GetPKey() []byte {
return hmac.New(sha512.New512_224, []byte(sharedSecret)).Sum([]byte(s.Login))
}
2018-02-20 12:49:03 +00:00
func (s Student) Update() (int64, error) {
if res, err := DBExec("UPDATE students SET login = ?, time = ? WHERE id_student = ?", s.Login, s.Time, s.Id); err != nil {
2018-02-20 12:49:03 +00:00
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
func (s Student) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM students WHERE id_student = ?", s.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
func ClearStudents() (int64, error) {
if res, err := DBExec("DELETE FROM students"); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
func createStudent(_ httprouter.Params, body []byte) (interface{}, error) {
2018-02-22 04:36:46 +00:00
var err error
var std uploadedStudent
if err = json.Unmarshal(body, &std); err != nil {
2018-02-20 12:49:03 +00:00
return nil, err
}
2018-02-22 04:36:46 +00:00
var exist Student
if exist, err = getStudentByLogin(strings.TrimSpace(std.Login)); err != nil {
if exist, err = NewStudent(strings.TrimSpace(std.Login)); err != nil {
return nil, err
}
}
2018-02-22 04:36:46 +00:00
exist.registerAccess(std.IP, std.MAC)
return exist, nil
2018-02-20 12:49:03 +00:00
}
func updateStudent(current Student, body []byte) (interface{}, error) {
var new Student
if err := json.Unmarshal(body, &new); err != nil {
return nil, err
}
current.Login = new.Login
current.Time = new.Time
return current.Update()
}
2018-02-20 17:20:07 +00:00
type UnlockedChallenge struct {
Id int64 `json:"id"`
IdStudent int64 `json:"id_student"`
Challenge int `json:"challenge"`
Time time.Time `json:"time"`
}
2018-02-22 03:47:57 +00:00
func (s Student) getStates() (ucs []UnlockedChallenge, err error) {
if rows, errr := DBQuery("SELECT id_st, challenge, time FROM student_challenges WHERE id_student = ?", s.Id); errr != nil {
return nil, errr
} else {
defer rows.Close()
for rows.Next() {
var u UnlockedChallenge
u.IdStudent = s.Id
if err = rows.Scan(&u.Id, &u.Challenge, &u.Time); err != nil {
return
}
ucs = append(ucs, u)
}
if err = rows.Err(); err != nil {
return
}
return
}
}
2018-02-20 17:20:07 +00:00
func (s Student) UnlockNewChallenge(challenge int, value string) (UnlockedChallenge, error) {
if res, err := DBExec("INSERT INTO student_challenges (id_student, challenge, time, value) VALUES (?, ?, ?, ?)", s.Id, challenge, time.Now(), value); err != nil {
return UnlockedChallenge{}, err
} else if utid, err := res.LastInsertId(); err != nil {
return UnlockedChallenge{}, err
} else {
return UnlockedChallenge{utid, s.Id, challenge, time.Now()}, err
}
}
2018-02-22 04:36:46 +00:00
func (s Student) registerAccess(ip, mac string) error {
if res, err := DBExec("INSERT INTO student_login (id_student, ip, mac, time) VALUES (?, ?, ?, ?)", s.Id, ip, mac, time.Now()); err != nil {
return err
} else if _, err := res.LastInsertId(); err != nil {
return err
} else {
return err
}
}