Compare commits

..

No commits in common. "b78e30d109d1baf59abb954f3172992d9704284c" and "5019432b24a30c330e82ac68298a7532e676a094" have entirely different histories.

12 changed files with 97 additions and 100 deletions

2
.gitignore vendored
View File

@ -1,2 +0,0 @@
tmp
test.sql

View File

@ -1,12 +1,9 @@
USE sicherheitsunterweisung; USE sicherheitsunterweisung;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS instructors; DROP TABLE IF EXISTS instructors;
DROP TABLE IF EXISTS briefings; DROP TABLE IF EXISTS briefings;
DROP TABLE IF EXISTS participants; DROP TABLE IF EXISTS participants;
DROP TABLE IF EXISTS questions; DROP TABLE IF EXISTS questions;
DROP TABLE IF EXISTS given_answers; DROP TABLE IF EXISTS given_answers;
SET FOREIGN_KEY_CHECKS = 1;
CREATE TABLE instructors ( CREATE TABLE instructors (
id INT NOT NULL AUTO_INCREMENT, id INT NOT NULL AUTO_INCREMENT,
@ -71,7 +68,7 @@ VALUES
( 'Georg', 'aus dem Jungel', '123458' ); ( 'Georg', 'aus dem Jungel', '123458' );
INSERT INTO briefings ( INSERT INTO briefings (
date, time, location, document_name, as_of, instructor_id date, time, location, as_of, instructor_id
) VALUES ) VALUES
( '2023-10-16', '17:00:00', 'Werk Langenhagen', 'ICS-2021-LGH', '2021-02-01', '1' ), ( '2023-10-16', '17:00:00', 'Werk Langenhagen', 'ICS-2021-LGH', '2021-02-01', '1' ),
( '2023-10-16', '17:05:00', 'Werk Langenhagen', 'ICS-2021-LGH', '2021-02-01', '2' ); ( '2023-10-16', '17:05:00', 'Werk Langenhagen', 'ICS-2021-LGH', '2021-02-01', '2' );
@ -87,8 +84,7 @@ INSERT INTO questions (
) VALUES ) VALUES
( 'Was ist 1+1?', '1', '2', '3', '4', '2' ), ( 'Was ist 1+1?', '1', '2', '3', '4', '2' ),
( 'Was ist 1+2?', '1', '2', '3', '4', '3' ), ( 'Was ist 1+2?', '1', '2', '3', '4', '3' ),
( 'Was ist 2+2?', '1', '2', '3', '4', '4' ), ( 'Was ist 2+2?', '1', '2', '3', '4', '4' );
( 'Was ist 0+1?', '1', '2', '3', '4', '1' );
INSERT INTO given_answers ( INSERT INTO given_answers (
briefing_id, participant_id, question_id, given_answer briefing_id, participant_id, question_id, given_answer
@ -96,8 +92,6 @@ INSERT INTO given_answers (
( '1', '1', '1', '2' ), ( '1', '1', '1', '2' ),
( '1', '1', '2', '3' ), ( '1', '1', '2', '3' ),
( '1', '1', '3', '3' ), ( '1', '1', '3', '3' ),
( '1', '1', '4', '1' ),
( '2', '2', '1', '2' ), ( '2', '2', '1', '2' ),
( '2', '2', '2', '3' ), ( '2', '2', '2', '3' ),
( '2', '2', '3', '4' ), ( '2', '2', '3', '4' );
( '2', '2', '4', '1' );

1
go.mod
View File

@ -4,7 +4,6 @@ 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,7 +1,5 @@
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=

29
main.go
View File

@ -1,44 +1,33 @@
package main package main
import ( import (
"fmt"
"html/template" "html/template"
"log" "log"
"net/http" "net/http"
"streifling.com/jason/sicherheitsunterweisung/packages/db" "streifling.com/jason/sicherheitsunterweisung/packages/data"
"streifling.com/jason/sicherheitsunterweisung/packages/server" "streifling.com/jason/sicherheitsunterweisung/packages/server"
"streifling.com/jason/sicherheitsunterweisung/packages/types"
) )
func handleSessions(mux *http.ServeMux, db *db.DB, ss []*types.Session, cs <-chan *types.Session) {
for session := range cs {
ss = append(ss, session)
mux.HandleFunc("/add-participant-"+fmt.Sprint(session.ID)+"/", server.AddParticipant(session))
mux.HandleFunc("/submit-form-"+fmt.Sprint(session.ID)+"/", server.SubmitBriefingForm(session, db))
}
}
func main() { func main() {
db, err := db.Open("sicherheitsunterweisung") logins := make([]string, 0)
db, err := data.OpenDB("sicherheitsunterweisung")
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
sessions := make([]*types.Session, 0)
sessionChan := make(chan *types.Session)
mux := http.NewServeMux() mux := http.NewServeMux()
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("/", func(w http.ResponseWriter, r *http.Request) {
template.Must(template.ParseFiles("templates/index.html", "templates/login.html")).Execute(w, nil) template.Must(template.ParseFiles("templates/index.html", "templates/login.html")).Execute(w, nil)
}) })
mux.HandleFunc("/internal-login/", server.DisplayTable(db))
mux.HandleFunc("/external-login/", server.DisplayParticipantForm(sessions))
mux.HandleFunc("/search/", server.DisplaySearchResults(db)) mux.HandleFunc("/search/", server.DisplaySearchResults(db))
mux.HandleFunc("/new-briefing/", server.DisplayInstructorForm(sessionChan)) mux.HandleFunc("/new-briefing/", server.DisplayInstructorForm())
mux.HandleFunc("/add-participant/", server.AddParticipant(&logins))
go handleSessions(mux, db, sessions, sessionChan) mux.HandleFunc("/submit-form/", server.SubmitBriefingForm(db, &logins))
mux.HandleFunc("/internal-login/", server.DisplayTable(db))
mux.HandleFunc("/external-login/", server.DisplayParticipantForm(&logins))
log.Fatalln(http.ListenAndServe(":8080", mux)) log.Fatalln(http.ListenAndServe(":8080", mux))
} }

View File

@ -1,4 +1,4 @@
package db package data
import ( import (
"bufio" "bufio"
@ -8,9 +8,10 @@ import (
"strings" "strings"
"syscall" "syscall"
"streifling.com/jason/sicherheitsunterweisung/packages/types"
"github.com/go-sql-driver/mysql" "github.com/go-sql-driver/mysql"
"golang.org/x/term" "golang.org/x/term"
"streifling.com/jason/sicherheitsunterweisung/packages/types"
) )
type DB struct { type DB struct {
@ -59,7 +60,7 @@ func getCredentials() (string, string, error) {
return user, pass, nil return user, pass, nil
} }
func Open(dbName string) (*DB, error) { func OpenDB(dbName string) (*DB, error) {
var err error var err error
db := new(DB) db := new(DB)
@ -154,7 +155,7 @@ func (db *DB) WriteAllDataOfBriefing(b *types.Briefing, sp *[]*types.Participant
return nil return nil
} }
func (db *DB) GetAllOverviewTableData() ([]*types.OverviewTableData, error) { func (db *DB) GetAllOverviewTableData() (*[]*types.OverviewTableData, error) {
rows, err := db.Query(` rows, err := db.Query(`
SELECT SELECT
i.first_name, i.first_name,
@ -172,12 +173,8 @@ func (db *DB) GetAllOverviewTableData() ([]*types.OverviewTableData, error) {
ON b.id = g.briefing_id ON b.id = g.briefing_id
INNER JOIN participants AS p INNER JOIN participants AS p
ON p.id = g.participant_id ON p.id = g.participant_id
INNER JOIN questions AS q
ON q.id = g.question_id
INNER JOIN instructors AS i INNER JOIN instructors AS i
ON i.id = b.instructor_id ON i.id = b.instructor_id
WHERE
q.id = 1
ORDER BY ORDER BY
b.id DESC, b.id DESC,
p.id p.id
@ -210,7 +207,7 @@ func (db *DB) GetAllOverviewTableData() ([]*types.OverviewTableData, error) {
data = append(data, otd) data = append(data, otd)
} }
return data, nil return &data, nil
} }
func (db *DB) GetOverviewTableDataByName(n string) (*[]*types.OverviewTableData, error) { func (db *DB) GetOverviewTableDataByName(n string) (*[]*types.OverviewTableData, error) {
@ -234,7 +231,6 @@ func (db *DB) GetOverviewTableDataByName(n string) (*[]*types.OverviewTableData,
INNER JOIN instructors AS i INNER JOIN instructors AS i
ON i.id = b.instructor_id ON i.id = b.instructor_id
WHERE WHERE
q.id = 1 AND
i.first_name LIKE ? OR i.first_name LIKE ? OR
i.last_name LIKE ? OR i.last_name LIKE ? OR
p.first_name LIKE ? OR p.first_name LIKE ? OR

View File

@ -0,0 +1,42 @@
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

@ -9,12 +9,18 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/google/uuid" "streifling.com/jason/sicherheitsunterweisung/packages/data"
"streifling.com/jason/sicherheitsunterweisung/packages/db"
"streifling.com/jason/sicherheitsunterweisung/packages/types" "streifling.com/jason/sicherheitsunterweisung/packages/types"
) )
func DisplayTable(db *db.DB) http.HandlerFunc { // type questionData struct {
// 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.GetAllOverviewTableData() bs, err := db.GetAllOverviewTableData()
if err != nil { if err != nil {
@ -24,7 +30,7 @@ func DisplayTable(db *db.DB) http.HandlerFunc {
} }
} }
func DisplaySearchResults(db *db.DB) http.HandlerFunc { func DisplaySearchResults(db *data.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
bs, err := db.GetOverviewTableDataByName(r.PostFormValue("search")) bs, err := db.GetOverviewTableDataByName(r.PostFormValue("search"))
if err != nil { if err != nil {
@ -34,13 +40,9 @@ func DisplaySearchResults(db *db.DB) http.HandlerFunc {
} }
} }
func DisplayInstructorForm(cs chan<- *types.Session) http.HandlerFunc { func DisplayInstructorForm() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
session := new(types.Session) template.Must(template.ParseFiles("templates/briefing.html")).ExecuteTemplate(w, "content", nil)
session.ID = uuid.New()
cs <- session
template.Must(template.ParseFiles("templates/briefing.html")).ExecuteTemplate(w, "content", session.ID)
} }
} }
@ -54,21 +56,21 @@ func generateUUID() (string, error) {
return hex.EncodeToString(bs), nil return hex.EncodeToString(bs), nil
} }
func AddParticipant(s *types.Session) http.HandlerFunc { func AddParticipant(sl *[]string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
login, err := generateUUID() login, err := generateUUID()
if err != nil { if err != nil {
http.Error(w, "AddParticipant: generateUUID(): "+fmt.Sprint(err), http.StatusInternalServerError) http.Error(w, "AddParticipant: generateUUID(): "+fmt.Sprint(err), http.StatusInternalServerError)
} }
s.Logins = append(s.Logins, login) (*sl) = append(*sl, login)
template.Must(template.ParseFiles("templates/briefing.html")).ExecuteTemplate(w, "new", login) template.Must(template.ParseFiles("templates/briefing.html")).ExecuteTemplate(w, "new", login)
} }
} }
// TODO: Hier weiter machen, irgendwie die b.ID herausgeben, // TODO: Hier weiter machen, irgendwie die b.ID herausgeben,
// am besten hier auch die p.IDs rausgeben, damit diese später verknüpft werden können // am besten hier auch die p.IDs rausgeben, damit diese später verknüpft werden können
func SubmitBriefingForm(s *types.Session, db *db.DB) http.HandlerFunc { func SubmitBriefingForm(db *data.DB, sl *[]string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
now := time.Now() now := time.Now()
briefing := new(types.Briefing) briefing := new(types.Briefing)
@ -85,18 +87,15 @@ func SubmitBriefingForm(s *types.Session, db *db.DB) http.HandlerFunc {
// briefing.InstructorID = r.PostFormValue("instructor-id") // TODO: aus Dropdown holen // briefing.InstructorID = r.PostFormValue("instructor-id") // TODO: aus Dropdown holen
db.WriteBriefing(briefing) db.WriteBriefing(briefing)
s.BriefingID = briefing.ID
} }
} }
// TODO: Make it only serve one purpose // TODO: Make it only serve one purpose
func loginIsCorrect(l string, ss []*types.Session) bool { func loginIsCorrect(l string, logins *[]string) bool {
for _, session := range ss { for i, v := range *logins {
for i, v := range session.Logins { if l == v {
if l == v { (*logins) = append((*logins)[:i], (*logins)[i+1:]...)
session.Logins = append(session.Logins[:i], session.Logins[i+1:]...) return true
return true
}
} }
} }
return false return false
@ -114,23 +113,15 @@ func newParticipant(l string) (*types.Participant, error) {
return p, nil return p, nil
} }
func DisplayParticipantForm(ss []*types.Session) http.HandlerFunc { func DisplayParticipantForm(sl *[]string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
type data struct { if loginIsCorrect(r.PostFormValue("login"), sl) {
SessionID uuid.UUID uuid, err := generateUUID()
UUID string
}
if loginIsCorrect(r.PostFormValue("login"), ss) {
data := new(data)
var err error
data.UUID, err = generateUUID()
if err != nil { if err != nil {
http.Error(w, "DisplayParticipantForm: generateUUID(): "+fmt.Sprint(err), http.StatusInternalServerError) http.Error(w, "DisplayParticipantForm: generateUUID(): "+fmt.Sprint(err), http.StatusInternalServerError)
} }
template.Must(template.ParseFiles("templates/participant.html")).ExecuteTemplate(w, "content", data) template.Must(template.ParseFiles("templates/participant.html")).ExecuteTemplate(w, "content", uuid)
} else { } else {
template.Must(template.ParseFiles("templates/login.html")).ExecuteTemplate(w, "content", nil) template.Must(template.ParseFiles("templates/login.html")).ExecuteTemplate(w, "content", nil)
} }

View File

@ -1,7 +1,5 @@
package types package types
import "github.com/google/uuid"
type Person struct { type Person struct {
ID int64 ID int64
FirstName string FirstName string
@ -56,12 +54,3 @@ type OverviewTableData struct {
ParticipantLastName string ParticipantLastName string
ParticipantCompany string ParticipantCompany string
} }
type Session struct {
ID uuid.UUID
InstructorID int64
BriefingID int64
Logins []string
ParticipantIDs []int64
QuestionIDs []int64
}

View File

@ -1,16 +1,17 @@
{{ define "rows" }} {{ define "rows" }}
{{ range . }} {{ range . }}
<tr> <tr>
<td>{{ .InstructorFirstName }}</td> <td>{{ .FirstName }}</td>
<td>{{ .InstructorLastName }}</td> <td>{{ .LastName }}</td>
<td>{{ .BriefingDate }}</td> <td>{{ .Date }}</td>
<td>{{ .BriefingTime }}</td> <td>{{ .Time }}</td>
<td>{{ .BriefingLocation }}</td> <td>{{ .State }}</td>
<td>{{ .BriefingDocumentName }}</td> <td>{{ .Location }}</td>
<td>{{ .BriefingAsOf }}</td> {{ range .Participants }}
<td>{{ .ParticipantFirstName }}</td> <td>{{ .FirstName }}</td>
<td>{{ .ParticipantLastName }}</td> <td>{{ .LastName }}</td>
<td>{{ .ParticipantCompany }}</td> <td>{{ .Company }}</td>
{{ end }}
</tr> </tr>
{{ end }} {{ end }}
{{ end }} {{ end }}
@ -34,9 +35,8 @@
<th colspan="2">Unterweiser</th> <th colspan="2">Unterweiser</th>
<th>Datum</th> <th>Datum</th>
<th>Uhrzeit</th> <th>Uhrzeit</th>
<th>Ort</th>
<th>Dokument</th>
<th>Stand</th> <th>Stand</th>
<th>Ort</th>
<th colspan="2">Teilnehmer</th> <th colspan="2">Teilnehmer</th>
<th>Firma</th> <th>Firma</th>
</tr> </tr>

1
tmp/build-errors.log Normal file
View File

@ -0,0 +1 @@
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 Executable file

Binary file not shown.