4 Commits

18 changed files with 135 additions and 534 deletions

View File

@ -1,44 +0,0 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
args_bin = []
bin = "./tmp/main"
cmd = "go build -o ./tmp/main ."
delay = 0
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false
[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
main_only = false
time = false
[misc]
clean_on_exit = false
[screen]
clear_on_rebuild = false
keep_scroll = true

1
.gitignore vendored
View File

@ -0,0 +1 @@
create_tables.sql

View File

@ -1,96 +0,0 @@
USE sicherheitsunterweisung;
DROP TABLE IF EXISTS instructors;
DROP TABLE IF EXISTS briefings;
DROP TABLE IF EXISTS participants;
DROP TABLE IF EXISTS questions;
DROP TABLE IF EXISTS given_answers;
CREATE TABLE instructors (
id INT NOT NULL AUTO_INCREMENT,
first_name VARCHAR(32) NOT NULL,
last_name VARCHAR(32) NOT NULL,
personnel_id INT NOT NULL,
PRIMARY KEY(id)
);
CREATE TABLE briefings (
id INT NOT NULL AUTO_INCREMENT,
date DATE NOT NULL,
time TIME NOT NULL,
location VARCHAR(32) NOT NULL,
as_of DATE NOT NULL,
instructor_id INT NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY(instructor_id) REFERENCES instructors(id)
);
CREATE TABLE participants (
id INT NOT NULL AUTO_INCREMENT,
first_name VARCHAR(32) NOT NULL,
last_name VARCHAR(32) NOT NULL,
company VARCHAR(32) NOT NULL,
PRIMARY KEY(id)
);
CREATE TABLE questions (
id INT NOT NULL AUTO_INCREMENT,
question VARCHAR(256) NOT NULL,
answer_1 VARCHAR(64) NOT NULL,
answer_2 VARCHAR(64) NOT NULL,
answer_3 VARCHAR(64) NOT NULL,
answer_4 VARCHAR(64) NOT NULL,
correct_answer INT NOT NULL,
PRIMARY KEY(id)
);
CREATE TABLE given_answers (
briefing_id INT NOT NULL,
participant_id INT NOT NULL,
question_id INT NOT NULL,
given_answer INT NOT NULL,
PRIMARY KEY(briefing_id, participant_id, question_id),
FOREIGN KEY(briefing_id) REFERENCES briefings(id),
FOREIGN KEY(participant_id) REFERENCES participants(id),
FOREIGN KEY(question_id) REFERENCES questions(id)
);
INSERT INTO instructors
(first_name, last_name, personnel_id)
VALUES
( 'Jason', 'Streifling', '123456' ),
( 'Tim', 'Taler', '123457' ),
( 'Georg', 'aus dem Jungel', '123458' );
INSERT INTO briefings (
date, time, location, as_of, instructor_id
) VALUES
( '2023-10-16', '17:00:00', 'Werk Langenhagen', '2021-02-01', '1' ),
( '2023-10-16', '17:05:00', 'Werk Langenhagen', '2021-02-01', '2' );
INSERT INTO participants (
first_name, last_name, company
) VALUES
( 'Peter', 'Enis', 'Körber' ),
( 'Dürüm', 'Döner', 'MP Technic' );
INSERT INTO questions (
question, answer_1, answer_2, answer_3, answer_4, correct_answer
) VALUES
( 'Was ist 1+1?', '1', '2', '3', '4', '2' ),
( 'Was ist 1+2?', '1', '2', '3', '4', '3' ),
( 'Was ist 2+2?', '1', '2', '3', '4', '4' );
INSERT INTO given_answers (
briefing_id, participant_id, question_id, given_answer
) VALUES
( '1', '1', '1', '2' ),
( '1', '1', '2', '3' ),
( '1', '1', '3', '3' ),
( '2', '2', '1', '2' ),
( '2', '2', '2', '3' ),
( '2', '2', '3', '4' );

1
go.mod
View File

@ -4,6 +4,7 @@ go 1.21.1
require ( require (
github.com/go-sql-driver/mysql v1.7.1 github.com/go-sql-driver/mysql v1.7.1
github.com/google/uuid v1.3.1
golang.org/x/term v0.13.0 golang.org/x/term v0.13.0
) )

2
go.sum
View File

@ -1,5 +1,7 @@
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=

47
main.go
View File

@ -1,60 +1,29 @@
package main package main
import ( import (
"fmt"
"html/template"
"log" "log"
"net/http" "net/http"
"streifling.com/jason/sicherheitsunterweisung/packages/data" "streifling.com/jason/sicherheitsunterweisung/packages/db"
"streifling.com/jason/sicherheitsunterweisung/packages/server" "streifling.com/jason/sicherheitsunterweisung/packages/server"
"streifling.com/jason/sicherheitsunterweisung/packages/types"
) )
func waitForParticipants(sb []*types.Briefing, sp []*types.Participant, cp <-chan *types.Participant, m *http.ServeMux) {
for p := range cp {
p.Questions = data.InitQuestions()
sp = append(sp, p)
var i int
for i = range p.Questions {
m.HandleFunc("/display-question-"+fmt.Sprintf("%d", p.ID)+"-"+fmt.Sprintf("%d", i)+"/", server.DisplayQuestion(i, p))
}
m.HandleFunc("/display-question-"+fmt.Sprintf("%d", p.ID)+"-"+fmt.Sprintf("%d", i+1)+"/", server.DisplayTestResults(sb, p))
}
}
func main() { func main() {
logins := make([]string, 0) var i, j int64
participants := make([]*types.Participant, 0) i, j = 1, 1
briefings := make([]*types.Briefing, 0)
mux := http.NewServeMux() mux := http.NewServeMux()
db, err := data.OpenDB("sicherheitsunterweisung") db, err := db.Open("sicherheitsunterweisung")
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
var i, j int64
if err := db.GetLastID(&i); err != nil {
log.Fatalln(err)
}
j = i
participantChan := make(chan *types.Participant)
defer close(participantChan)
go waitForParticipants(briefings, participants, participantChan, mux)
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static/")))) mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static/"))))
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/", server.DisplayTable(db))
template.Must(template.ParseFiles("templates/index.html", "templates/login.html")).Execute(w, nil) mux.HandleFunc("/search/", server.DisplayResults(db))
})
mux.HandleFunc("/search/", server.DisplaySearchResults(db))
mux.HandleFunc("/new-briefing/", server.DisplayForm(&i)) mux.HandleFunc("/new-briefing/", server.DisplayForm(&i))
mux.HandleFunc("/add-participant/", server.AddParticipant(&i, &logins)) mux.HandleFunc("/add-participant/", server.AddParticipant(&i))
mux.HandleFunc("/submit-form/", server.SubmitForm(db, &i, &j)) mux.HandleFunc("/submit/", server.SubmitForm(db, &i, &j))
mux.HandleFunc("/internal-login/", server.DisplayTable(db))
mux.HandleFunc("/external-login/", server.DisplayParticipantForm(&logins, participantChan))
log.Fatalln(http.ListenAndServe(":8080", mux)) log.Fatalln(http.ListenAndServe(":8080", mux))
} }

View File

@ -1,42 +0,0 @@
package data
import "streifling.com/jason/sicherheitsunterweisung/packages/types"
func InitQuestions() []types.Question {
Q := make([]types.Question, 0)
Q = append(Q, types.Question{
Text: "Wie viel ist 1+1?",
Answers: []types.Answer{
{ID: 0, Text: "1"},
{ID: 1, Text: "2"},
{ID: 2, Text: "3"},
{ID: 3, Text: "4"},
},
Correct: 1,
})
Q = append(Q, types.Question{
Text: "Wie viel ist 2+2?",
Answers: []types.Answer{
{ID: 0, Text: "1"},
{ID: 1, Text: "2"},
{ID: 2, Text: "3"},
{ID: 3, Text: "4"},
},
Correct: 3,
})
Q = append(Q, types.Question{
Text: "Wie viel ist 1+2?",
Answers: []types.Answer{
{ID: 0, Text: "1"},
{ID: 1, Text: "2"},
{ID: 2, Text: "3"},
{ID: 3, Text: "4"},
},
Correct: 2,
})
return Q
}

View File

@ -1,4 +1,4 @@
package data package db
import ( import (
"bufio" "bufio"
@ -19,54 +19,31 @@ type DB struct {
Name string Name string
} }
func getUsername() (string, error) {
user := os.Getenv("DB_USER")
if user == "" {
var err error
fmt.Printf("DB Benutzer: ")
user, err = bufio.NewReader(os.Stdin).ReadString('\n')
if err != nil {
return "", fmt.Errorf("getUsername: bufio.NewReader(os.Stdin).ReadString('\n'): %v", err)
}
}
return strings.TrimSpace(user), nil
}
func getPassword() (string, error) {
pass := os.Getenv("DB_PASS")
if pass == "" {
fmt.Printf("DB Passwort: ")
bytePass, err := term.ReadPassword(int(syscall.Stdin))
if err != nil {
return "", fmt.Errorf("getCredentials: term.ReadPassword(int(syscall.Stdin)): %v", err)
}
fmt.Println()
pass = strings.TrimSpace(string(bytePass))
}
return pass, nil
}
func getCredentials() (string, string, error) { func getCredentials() (string, string, error) {
user, err := getUsername() fmt.Printf("DB Benutzer: ")
user, err := bufio.NewReader(os.Stdin).ReadString('\n')
if err != nil { if err != nil {
return "", "", fmt.Errorf("getCredentials: getUsername(): %v", err) return "", "", fmt.Errorf("getCredentials: bufio.NewReader(os.Stdin).ReadString('\n'): %v", err)
} }
pass, err := getPassword() fmt.Printf("DB Passwort: ")
bytePass, err := term.ReadPassword(int(syscall.Stdin))
if err != nil { if err != nil {
return "", "", fmt.Errorf("getCredentials: getPassword(): %v", err) return "", "", fmt.Errorf("getCredentials: term.ReadPassword(int(syscall.Stdin)): %v", err)
} }
fmt.Println()
pass := string(bytePass)
return user, pass, nil return strings.TrimSpace(user), strings.TrimSpace(pass), nil
} }
func reverseOrder(bs []*types.Briefing) { func reverseOrder(bs *[]types.Briefing) {
for i, j := 0, len(bs)-1; i < j; i, j = i+1, j-1 { for i, j := 0, len(*bs)-1; i < j; i, j = i+1, j-1 {
bs[i], bs[j] = bs[j], bs[i] (*bs)[i], (*bs)[j] = (*bs)[j], (*bs)[i]
} }
} }
func OpenDB(dbName string) (*DB, error) { func Open(dbName string) (*DB, error) {
var err error var err error
db := new(DB) db := new(DB)
@ -115,8 +92,8 @@ func (db *DB) WriteBriefing(b *types.Briefing) error {
return nil return nil
} }
func (db *DB) ReadAll() ([]*types.Briefing, error) { func (db *DB) ReadAll() (*[]types.Briefing, error) {
bs := make([]*types.Briefing, 0) bs := make([]types.Briefing, 0)
rows, err := db.Query("SELECT *" + " FROM " + db.Name) rows, err := db.Query("SELECT *" + " FROM " + db.Name)
if err != nil { if err != nil {
@ -133,16 +110,16 @@ func (db *DB) ReadAll() ([]*types.Briefing, error) {
return nil, fmt.Errorf("*DB.ReadAll: db.Query(): %v\n", err) return nil, fmt.Errorf("*DB.ReadAll: db.Query(): %v\n", err)
} }
b.Participants = append(b.Participants, p) b.Participants = append(b.Participants, *p)
bs = append(bs, b) bs = append(bs, *b)
} }
reverseOrder(bs) reverseOrder(&bs)
return bs, nil return &bs, nil
} }
func (db *DB) ReadByName(name string) ([]*types.Briefing, error) { func (db *DB) ReadByName(name string) (*[]types.Briefing, error) {
bs := make([]*types.Briefing, 0) bs := make([]types.Briefing, 0)
rows, err := db.Query("SELECT *"+ rows, err := db.Query("SELECT *"+
" FROM "+db.Name+ " FROM "+db.Name+
@ -171,22 +148,10 @@ func (db *DB) ReadByName(name string) ([]*types.Briefing, error) {
" &b.LastName, &b.Date, &b.Time, &b.State, &b.Location, &p.FirstName,"+ " &b.LastName, &b.Date, &b.Time, &b.State, &b.Location, &p.FirstName,"+
" &p.LastName, &p.Company): %v\n", err) " &p.LastName, &p.Company): %v\n", err)
} }
b.Participants = append(b.Participants, p) b.Participants = append(b.Participants, *p)
bs = append(bs, b) bs = append(bs, *b)
} }
reverseOrder(bs) reverseOrder(&bs)
return bs, nil return &bs, nil
}
func (db *DB) GetLastID(i *int64) error {
row := db.QueryRow("SELECT id" +
" FROM " + db.Name +
" ORDER BY id DESC LIMIT 0, 1")
if err := row.Scan(i); err != nil {
return fmt.Errorf("*DB.GetLastID: row.Scan(&i): %v\n", err)
}
return nil
} }

View File

@ -1,41 +1,34 @@
package server package server
import ( import (
"crypto/rand"
"encoding/hex"
"fmt" "fmt"
"github.com/google/uuid"
"html/template" "html/template"
"io"
"log" "log"
"net/http" "net/http"
"strconv" "os"
"strings" "streifling.com/jason/sicherheitsunterweisung/packages/db"
"streifling.com/jason/sicherheitsunterweisung/packages/data"
"streifling.com/jason/sicherheitsunterweisung/packages/types" "streifling.com/jason/sicherheitsunterweisung/packages/types"
) )
type questionData struct { func DisplayTable(db *db.DB) http.HandlerFunc {
ID int64
Q types.Question
I int
J int
}
func DisplayTable(db *data.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
bs, err := db.ReadAll() bs, err := db.ReadAll()
if err != nil { if err != nil {
_ = fmt.Errorf("DisplayTable: %v\n", err) _ = fmt.Errorf("DisplayTable: %v\n", err)
return
} }
template.Must(template.ParseFiles("templates/table.html")).ExecuteTemplate(w, "content", bs) template.Must(template.ParseFiles("templates/index.html", "templates/table.html")).Execute(w, bs)
} }
} }
func DisplaySearchResults(db *data.DB) http.HandlerFunc { func DisplayResults(db *db.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
bs, err := db.ReadByName(r.PostFormValue("search")) bs, err := db.ReadByName(r.PostFormValue("search"))
if err != nil { if err != nil {
_ = fmt.Errorf("DisplayResults: db.ReadByName(r.PostFormValue()): %v\n", err) _ = fmt.Errorf("DisplayResults: db.ReadByName(r.PostFormValue()): %v\n", err)
return
} }
template.Must(template.ParseFiles("templates/table.html")).ExecuteTemplate(w, "rows", bs) template.Must(template.ParseFiles("templates/table.html")).ExecuteTemplate(w, "rows", bs)
} }
@ -43,31 +36,18 @@ func DisplaySearchResults(db *data.DB) http.HandlerFunc {
func DisplayForm(i *int64) http.HandlerFunc { func DisplayForm(i *int64) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
template.Must(template.ParseFiles("templates/briefing.html")).ExecuteTemplate(w, "content", i) template.Must(template.ParseFiles("templates/form.html")).ExecuteTemplate(w, "content", i)
} }
} }
func generateUUID() string { func AddParticipant(i *int64) http.HandlerFunc {
bs := make([]byte, 2)
if _, err := rand.Read(bs); err != nil {
_ = fmt.Errorf("GenerateUUID: rand.Read(bs): %v\n", err)
return ""
}
return hex.EncodeToString(bs)
}
func AddParticipant(i *int64, ls *[]string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
*i++ *i++
login := fmt.Sprintf("%d", *i) + "-" + generateUUID() template.Must(template.ParseFiles("templates/form.html")).ExecuteTemplate(w, "participant", i)
(*ls) = append(*ls, login)
template.Must(template.ParseFiles("templates/briefing.html")).ExecuteTemplate(w, "new", login)
} }
} }
func SubmitForm(db *data.DB, i, j *int64) http.HandlerFunc { func SubmitForm(db *db.DB, i, j *int64) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
b := new(types.Briefing) b := new(types.Briefing)
@ -79,7 +59,7 @@ func SubmitForm(db *data.DB, i, j *int64) http.HandlerFunc {
b.Location = r.PostFormValue("location") b.Location = r.PostFormValue("location")
for ; *j <= *i; *j++ { for ; *j <= *i; *j++ {
b.Participants = append(b.Participants, &types.Participant{ b.Participants = append(b.Participants, types.Participant{
ID: *j, ID: *j,
Person: types.Person{ Person: types.Person{
FirstName: r.PostFormValue("participant-first-" + fmt.Sprint(*j)), FirstName: r.PostFormValue("participant-first-" + fmt.Sprint(*j)),
@ -94,113 +74,33 @@ func SubmitForm(db *data.DB, i, j *int64) http.HandlerFunc {
bs, err := db.ReadAll() bs, err := db.ReadAll()
if err != nil { if err != nil {
_ = fmt.Errorf("SubmitForm: db.ReadAll(): %v\n", err) _ = fmt.Errorf("SubmitForm: db.ReadAll(): %v\n", err)
return
} }
template.Must(template.ParseFiles("templates/index.html", "templates/table.html")).Execute(w, bs)
template.Must(template.ParseFiles("templates/table.html")).Execute(w, bs)
} }
} }
// TODO: Make it only serve one purpose func Upload(fn, ln, d, t string) http.HandlerFunc {
func loginIsCorrect(l string, logins *[]string) bool {
for i, v := range *logins {
if l == v {
(*logins) = append((*logins)[:i], (*logins)[i+1:]...)
return true
}
}
return false
}
func newParticipant(l string) (*types.Participant, error) {
p := new(types.Participant)
idInt, err := strconv.Atoi(strings.Split(l, "-")[0])
if err != nil {
return nil, fmt.Errorf("newParticipant: strconv.Atoi(idString): %v\n", err)
}
p.ID = int64(idInt)
return p, nil
}
func DisplayParticipantForm(ls *[]string, cp chan<- *types.Participant) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
l := r.PostFormValue("login") r.ParseMultipartForm(10 << 20) // 10 MiB
if loginIsCorrect(l, ls) { tmpFile, _, err := r.FormFile("questionaire")
p, err := newParticipant(l) if err != nil {
if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError)
http.Error(w, "GetParticipantData: newParticipant(l): "+fmt.Sprint(err), http.StatusInternalServerError) return
} }
defer tmpFile.Close()
cp <- p file, err := os.Create(ln + fn + d + t + uuid.New().String() + ".png")
template.Must(template.ParseFiles("templates/participant.html")).ExecuteTemplate(w, "content", p.ID) if err != nil {
} else { http.Error(w, err.Error(), http.StatusInternalServerError)
template.Must(template.ParseFiles("templates/login.html")).ExecuteTemplate(w, "content", nil) return
}
defer file.Close()
if _, err := io.Copy(file, tmpFile); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
} }
} }
} }
func readAnswer(r *http.Request, p *types.Participant, i int) error {
v, err := strconv.Atoi(r.PostFormValue("answer"))
if err != nil {
return fmt.Errorf("readAnswer: strconv.Atoi(r.PostFormValue(\"answer\")): %v\n", err)
}
p.Questions[i].Chosen = v
return nil
}
func DisplayQuestion(i int, p *types.Participant) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if i == 0 {
p.FirstName = r.PostFormValue("participant-first-" + fmt.Sprintf("%d", p.ID))
p.LastName = r.PostFormValue("participant-last-" + fmt.Sprintf("%d", p.ID))
p.Company = r.PostFormValue("participant-company-" + fmt.Sprintf("%d", p.ID))
} else {
if err := readAnswer(r, p, i-1); err != nil {
http.Error(w, "DisplayQuestion: readAnswer(r, p, i): "+fmt.Sprint(err), http.StatusInternalServerError)
}
}
data := new(questionData)
data.ID = p.ID
data.Q = p.Questions[i]
data.I = i
data.J = i + 1
template.Must(template.ParseFiles("templates/question.html")).ExecuteTemplate(w, "content", data)
}
}
func DisplayTestResults(b *types.Briefing, p *types.Participant) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
numQuestions := len(p.Questions)
wrongAnswers := make([]int, 0)
fmt.Println(wrongAnswers)
if err := readAnswer(r, p, numQuestions-1); err != nil {
http.Error(w, "DisplayTestResults: readAnswer(r, p, i): "+fmt.Sprint(err), http.StatusInternalServerError)
}
for i, q := range p.Questions {
if q.Chosen != q.Correct {
wrongAnswers = append(wrongAnswers, i)
}
}
if wrongAnswers == nil {
b.Participants = append(b.Participants, p)
} else {
data := new(questionData)
data.ID = p.ID
data.Q = p.Questions[0]
data.I = 0
data.J = data.I + 1
template.Must(template.ParseFiles("templates/question.html")).ExecuteTemplate(w, "content", data)
}
template.Must(template.ParseFiles("templates/results.html")).ExecuteTemplate(w, "content", nil)
}
}

View File

@ -1,5 +1,7 @@
package types package types
import "os"
type Person struct { type Person struct {
FirstName string FirstName string
LastName string LastName string
@ -7,23 +9,11 @@ type Person struct {
type Instructor Person type Instructor Person
type Answer struct {
ID int
Text string
}
type Question struct {
Text string
Answers []Answer
Chosen int
Correct int
}
type Participant struct { type Participant struct {
ID int64 ID int64
Person Person
Company string Company string
Questions []Question Questionaire string
} }
type Briefing struct { type Briefing struct {
@ -32,5 +22,5 @@ type Briefing struct {
Time string Time string
State string State string
Location string Location string
Participants []*Participant Participants []Participant
} }

View File

@ -1,38 +0,0 @@
{{ define "add-button" }}
<button type="button" hx-post="/add-participant/" hx-target="this" hx-swap="outerHTML">
Neuer Teilnehmer
</button>
{{ end }}
{{ define "new" }}
<span>{{ . }}</span>
{{ template "add-button" . }}
{{ end }}
{{ define "content" }}
<form>
<div id="instructor">
<label for="instructor-first-input">Unterweiser Vorname</label>
<input type="text" name="instructor-first" id="instructor-first-input" />
<label for="instructor-last-input">Unterweiser Nachname</label>
<input type="text" name="instructor-last" id="instructor-last-input" />
</div>
<div id="location">
<label for="location-input">Ort</label>
<input type="text" name="location" id="location-input" />
</div>
<div id="state">
<label for="state-input">Stand vom</label>
<input type="date" name="state" id="state-input" />
</div>
{{ template "add-button" . }}
<button type="submit" hx-post="/submit-form/" hx-target="#content" hx-swap="innerHTML">
OK
</button>
</form>
{{ end }}

58
templates/form.html Normal file
View File

@ -0,0 +1,58 @@
{{ define "participant" }}
<div id="participant-{{ . }}">
<label for="participant-first-input-{{ . }}">Vorname</label>
<input type="text" name="participant-first-{{ . }}" id="participant-first-input-{{ . }}" />
<label for="participant-last-input-{{ . }}">Nachname</label>
<input type="text" name="participant-last-{{ . }}" id="participant-last-input-{{ . }}" />
<label for="participant-company-input-{{ . }}">Firma</label>
<input type="text" name="participant-company-{{ . }}" id="participant-company-input-{{ . }}" />
<button type="button" hx-post="/upload/">Fragebogen hochladen</button>
</div>
{{ end }}
{{ define "content" }}
<form>
<div id="instructor">
<label for="instructor-first-input">Unterweiser Vorname</label>
<input type="text" name="instructor-first" id="instructor-first-input" />
<label for="instructor-last-input">Unterweiser Nachname</label>
<input type="text" name="instructor-last" id="instructor-last-input" />
</div>
<div id="date">
<label for="date-input">Datum</label>
<input type="date" name="date" id="date-input" />
</div>
<div id="time">
<label for="time-input">Uhrzeit</label>
<input type="time" name="time" id="time-input" />
</div>
<div id="state">
<label for="state-input">Stand vom</label>
<input type="date" name="state" id="state-input" />
</div>
<div id="location">
<label for="location-input">Ort</label>
<input type="text" name="location" id="location-input" />
</div>
<div id="participants">
<button type="button" hx-post="/add-participant/" hx-target="#participants" hx-swap="beforeend" hx-trigger="click">
+
</button>
{{ template "participant" . }}
</div>
<button type="submit" hx-post="/submit/" hx-target="#content" hx-swap="innerHTML">
Senden
</button>
</form>
{{ end }}

View File

@ -1,16 +0,0 @@
{{ define "content" }}
<h2>Login</h2>
<form>
<label for="login-input">Code</label>
<input type="text" name="login" id="login-input" />
<button type="submit" hx-post="/external-login/" hx-target="#content">
Anmelden
</button>
<button type="submit" hx-post="/internal-login/" hx-target="#content">
Intern
</button>
</form>
{{ end }}

View File

@ -1,16 +0,0 @@
{{ define "content" }}
<form id="participant-{{ . }}">
<label for="participant-first-input-{{ . }}">Vorname</label>
<input type="text" name="participant-first-{{ . }}" id="participant-first-input-{{ . }}" />
<label for="participant-last-input-{{ . }}">Nachname</label>
<input type="text" name="participant-last-{{ . }}" id="participant-last-input-{{ . }}" />
<label for="participant-company-input-{{ . }}">Firma</label>
<input type="text" name="participant-company-{{ . }}" id="participant-company-input-{{ . }}" />
<button type="button" hx-post="/display-question-{{ . }}-0/" hx-target="#content">
Fertig
</button>
</form>
{{ end }}

View File

@ -1,21 +0,0 @@
{{ define "answers" }}
{{ range .Q.Answers }}
<div>
<input type="radio" name="answer" id="answer-{{ .ID }}" value="{{ .ID }}" />
<label for="answer-{{ .ID }}">{{ .Text }}</label>
</div>
{{ end }}
{{ end }}
{{ define "content" }}
<h2>Frage {{ .I }}</h2>
<p>{{ .Q.Text }}</p>
<form>
{{ template "answers" . }}
<button type="submit" hx-post="/display-question-{{ .ID }}-{{ .J }}/" hx-target="#content" hx-swap="innerHTML">
Weiter
</button>
</form>
{{ end }}

View File

@ -1,11 +0,0 @@
{{ define "passed" }}
{{ end }}
{{ define "failed" }}
{{ end }}
{{ define "content" }}
{{ q := range .Participant.Questions }}
<p>{{ . }}{{ q.Text }}</p>
{{ end }}
{{ end }}

View File

@ -1 +0,0 @@
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1

BIN
tmp/main

Binary file not shown.