Include Session in exam template

This commit is contained in:
Andrea Fazzi 2024-05-25 18:09:31 +02:00
parent 875775e1e4
commit 007236bd0f
11 changed files with 64 additions and 50 deletions

View file

@ -9,6 +9,6 @@ var (
filterTypeFormats = map[string]string{ filterTypeFormats = map[string]string{
"participants": "👫 Participants filter 👫", "participants": "👫 Participants filter 👫",
"quizzes": "❓ Quizzes filter ❓", "quizzes": "❓ Quizzes filter ❓",
"responses": "📝 Responsesfilter 📝", "responses": "📝 Responses filter 📝",
} }
) )

View file

@ -67,8 +67,8 @@ func runServer(cmd *cobra.Command, args []string) {
mux.Handle("POST /login", serve.Recover(loginController)) mux.Handle("POST /login", serve.Recover(loginController))
mux.Handle("GET /sessions", serve.Recover(sessionsController)) mux.Handle("GET /sessions", serve.Recover(sessionsController))
mux.Handle("GET /sessions/{uuid}/exams/{token}", serve.Recover(examController)) mux.Handle("GET /sessions/{uuid}/exams/{participantID}", serve.Recover(examController))
mux.Handle("POST /sessions/{uuid}/exams/{token}", serve.Recover(examController)) mux.Handle("POST /sessions/{uuid}/exams/{participantID}", serve.Recover(examController))
mux.Handle("GET /public/", http.StripPrefix("/public", http.FileServer(http.Dir("public")))) mux.Handle("GET /public/", http.StripPrefix("/public", http.FileServer(http.Dir("public"))))

View file

@ -14,22 +14,22 @@ var ExamHandler = func(c *Controller, w http.ResponseWriter, r *http.Request) {
panic(err) panic(err)
} }
participantToken := r.PathValue("token") participantID := r.PathValue("participantID")
session, err := c.sStore.Read(r.PathValue("uuid")) session, err := c.sStore.Read(r.PathValue("uuid"))
if err != nil { if err != nil {
panic(err) panic(err)
} }
exam, ok := session.Exams[participantToken] exam, ok := session.Exams[participantID]
if !ok { if !ok {
panic(errors.New("Exam not found in the store!")) panic(errors.New("Exam not found in the store!"))
} }
examWithSession := struct { examWithSession := struct {
*models.Exam *models.Exam
SessionID string Session *models.Session
}{exam, session.ID} }{exam, session}
switch r.Method { switch r.Method {
@ -49,12 +49,14 @@ var ExamHandler = func(c *Controller, w http.ResponseWriter, r *http.Request) {
answers := make([]*models.ParticipantAnswer, 0) answers := make([]*models.ParticipantAnswer, 0)
participant := session.Participants[participantID]
for quizID, values := range r.Form { for quizID, values := range r.Form {
correct := false correct := false
quiz := session.Quizzes[quizID] quiz := session.Quizzes[quizID]
for _, answerID := range values { for _, answerID := range values {
log.Info(answerID)
if quiz.Correct.ID == answerID { if quiz.Correct.ID == answerID {
correct = true correct = true
} }
@ -64,8 +66,9 @@ var ExamHandler = func(c *Controller, w http.ResponseWriter, r *http.Request) {
response, err := c.rStore.Create( response, err := c.rStore.Create(
&models.Response{ &models.Response{
SessionID: session.ID, SessionTitle: session.Title,
Answers: answers, Participant: participant,
Answers: answers,
}) })
if err != nil { if err != nil {
panic(err) panic(err)

View file

@ -15,7 +15,7 @@ var SessionsHandler = func(c *Controller, w http.ResponseWriter, r *http.Request
claims := token.Claims.(jwt.MapClaims) claims := token.Claims.(jwt.MapClaims)
var participantSessions []struct { var participantSessions []struct {
Token string ParticipantID string
*models.Session *models.Session
} }
@ -23,9 +23,9 @@ var SessionsHandler = func(c *Controller, w http.ResponseWriter, r *http.Request
for _, exam := range session.Exams { for _, exam := range session.Exams {
if exam.Participant.Token == claims["token"] { if exam.Participant.Token == claims["token"] {
s := struct { s := struct {
Token string ParticipantID string
*models.Session *models.Session
}{exam.Participant.Token, session} }{exam.Participant.ID, session}
participantSessions = append(participantSessions, s) participantSessions = append(participantSessions, s)
break break
} }

View file

@ -96,8 +96,9 @@ func New(path string, stdin string) *SessionModel {
viewport := viewport.New() viewport := viewport.New()
table := table.New(table.WithRelWidths(20, 30, 30, 20)) table := table.New(table.WithRelWidths(20, 10, 25, 25, 20))
table.Model.SetColumns([]btTable.Column{ table.Model.SetColumns([]btTable.Column{
{Title: "UUID", Width: 20},
{Title: "Token", Width: 20}, {Title: "Token", Width: 20},
{Title: "Lastname", Width: 20}, {Title: "Lastname", Width: 20},
{Title: "Firstname", Width: 20}, {Title: "Firstname", Width: 20},
@ -285,9 +286,10 @@ func (m *SessionModel) showErrorOnStatusBar(err error) {
func (m *SessionModel) updateTableContent(session *models.Session) { func (m *SessionModel) updateTableContent(session *models.Session) {
rows := make([]btTable.Row, 0) rows := make([]btTable.Row, 0)
for token, exam := range session.Exams { for _, exam := range session.Exams {
rows = append(rows, btTable.Row{ rows = append(rows, btTable.Row{
token, sanitize(exam.Participant.ID),
exam.Participant.Token,
exam.Participant.Lastname, exam.Participant.Lastname,
exam.Participant.Firstname, exam.Participant.Firstname,
exam.Participant.Attributes.Get("class"), exam.Participant.Attributes.Get("class"),
@ -303,8 +305,8 @@ func (m *SessionModel) updateViewportContent(session *models.Session) {
panic(errors.New("Session have not exams")) panic(errors.New("Session have not exams"))
} }
currentToken := m.table.SelectedRow()[0] currentUUID := m.table.SelectedRow()[0]
currentExam := session.Exams[currentToken] currentExam := session.Exams[desanitize(currentUUID)]
if currentExam == nil { if currentExam == nil {
panic("Current token is not associate to any exam!") panic("Current token is not associate to any exam!")
@ -466,3 +468,10 @@ func sanitize(text string) string {
// required to resolve this problem. // required to resolve this problem.
return strings.Replace(text, "-", "", -1) return strings.Replace(text, "-", "", -1)
} }
func desanitize(text string) string {
// FIXME: The use of a standard '-' character causes rendering
// issues within the viewport. Further investigation is
// required to resolve this problem.
return strings.Replace(text, "", "-", -1)
}

View file

@ -8,35 +8,30 @@
</head> </head>
<body> <body>
<header class="d-flex flex-wrap align-items-center justify-content-between py-3 border-bottom p-3 text-bg-dark border-bottom sticky-top"> <nav class="navbar bg-body-tertiary">
<a href="/" class="d-flex align-items-center mb-2 mb-lg-0 text-white text-decoration-none"> <div class="container">
<span class="fs-4 mx-2">Probo_</span> <a class="navbar-brand" href="#">
</a> <svg xmlns="http://www.w3.org/2000/svg" width="30" height="24" fill="currentColor" class="bi bi-book d-inline-block align-text-top" viewBox="0 0 16 16">
<path d="M1 2.828c.885-.37 2.154-.769 3.388-.893 1.33-.134 2.458.063 3.112.752v9.746c-.935-.53-2.12-.603-3.213-.493-1.18.12-2.37.461-3.287.811zm7.5-.141c.654-.689 1.782-.886 3.112-.752 1.234.124 2.503.523 3.388.893v9.923c-.918-.35-2.107-.692-3.287-.81-1.094-.111-2.278-.039-3.213.492zM8 1.783C7.015.936 5.587.81 4.287.94c-1.514.153-3.042.672-3.994 1.105A.5.5 0 0 0 0 2.5v11a.5.5 0 0 0 .707.455c.882-.4 2.303-.881 3.68-1.02 1.409-.142 2.59.087 3.223.877a.5.5 0 0 0 .78 0c.633-.79 1.814-1.019 3.222-.877 1.378.139 2.8.62 3.681 1.02A.5.5 0 0 0 16 13.5v-11a.5.5 0 0 0-.293-.455c-.952-.433-2.48-.952-3.994-1.105C10.413.809 8.985.936 8 1.783"/>
</svg>
Probo_
</a>
<span class="navbar-text">
{{.Session.Title}}
</span>
<div class="text-end">
<input type="submit" value="Salva" class="btn btn-primary me-2" form="submit-exam-form"/>
</div>
<div class="text-end">
<input type="submit" value="Salva" class="btn btn-primary me-2" form="submit-exam-form"/>
</div> </div>
</header> </nav>
<form action="/sessions/{{.SessionID}}/exams/{{.Participant.Token}}" method="POST" id="submit-exam-form"/> <form action="/sessions/{{.Session.ID}}/exams/{{.Participant.Token}}" method="POST" id="submit-exam-form"/>
{{template "content" .}} {{template "content" .}}
<footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
<div class="col-md-4 d-flex align-items-center">
<a href="/" class="mb-3 me-2 mb-md-0 text-body-secondary text-decoration-none lh-1">
<svg class="bi" width="30" height="24"><use xlink:href="#bootstrap"></use></svg>
</a>
<span class="mb-3 mb-md-0 text-body-secondary">© 2024 Andrea Fazzi</span>
</div>
<ul class="nav col-md-4 justify-content-end list-unstyled d-flex">
<li class="ms-3"><a class="text-body-secondary" href="#"><svg class="bi" width="24" height="24"><use xlink:href="#twitter"></use></svg></a></li>
<li class="ms-3"><a class="text-body-secondary" href="#"><svg class="bi" width="24" height="24"><use xlink:href="#instagram"></use></svg></a></li>
<li class="ms-3"><a class="text-body-secondary" href="#"><svg class="bi" width="24" height="24"><use xlink:href="#facebook"></use></svg></a></li>
</ul>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body> </body>
</html> </html>

View file

@ -8,7 +8,7 @@
<h5 class="card-title">{{$session.Title}}</h5> <h5 class="card-title">{{$session.Title}}</h5>
<h6 class="card-subtitle mb-2 text-body-secondary">{{$session.CreatedAt}}</h6> <h6 class="card-subtitle mb-2 text-body-secondary">{{$session.CreatedAt}}</h6>
<p class="card-text">{{$session.Description}}</p> <p class="card-text">{{$session.Description}}</p>
<a href="/sessions/{{$session.ID}}/exams/{{$session.Token}}" class="btn btn-primary">Inizia!</a> <a href="/sessions/{{$session.ID}}/exams/{{$session.ParticipantID}}" class="btn btn-primary">Inizia!</a>
</div> </div>
</div> </div>
</div> </div>

View file

@ -14,8 +14,9 @@ type ParticipantAnswer struct {
type Response struct { type Response struct {
Meta Meta
SessionID string `json:"session_id"` SessionTitle string `json:"session_title"`
Answers []*ParticipantAnswer `json:"answers"` Participant *Participant `json:"participant"`
Answers []*ParticipantAnswer `json:"answers"`
} }
func (r *Response) String() string { func (r *Response) String() string {

View file

@ -9,11 +9,13 @@ import (
type Session struct { type Session struct {
Meta Meta
Title string `json:"title"` Title string `json:"title"`
Description string `json:"description"` Description string `json:"description"`
Quizzes map[string]*Quiz `json:"quizzes"`
Answers map[string]*Answer `json:"answers"` Participants map[string]*Participant `json:"participants"`
Exams map[string]*Exam `json:"exams"` Quizzes map[string]*Quiz `json:"quizzes"`
Answers map[string]*Answer `json:"answers"`
Exams map[string]*Exam `json:"exams"`
} }
func (s *Session) String() string { func (s *Session) String() string {

View file

@ -8,7 +8,7 @@ import (
type ResponseFileStore = FileStore[*models.Response, *store.Store[*models.Response]] type ResponseFileStore = FileStore[*models.Response, *store.Store[*models.Response]]
func NewResponseFileStore(config *FileStoreConfig[*models.Response, *store.ResponseStore]) (*ResponseFileStore, error) { func NewResponseFileStore(config *FileStoreConfig[*models.Response, *store.ResponseStore]) (*ResponseFileStore, error) {
return NewFileStore[*models.Response](config, store.NewStore[*models.Response]()) return NewFileStore(config, store.NewStore[*models.Response]())
} }
func NewDefaultResponseFileStore() (*ResponseFileStore, error) { func NewDefaultResponseFileStore() (*ResponseFileStore, error) {

View file

@ -33,10 +33,14 @@ func (s *SessionStore) Create(session *models.Session) (*models.Session, error)
} }
} }
session.Participants = make(map[string]*models.Participant, 0)
session.Quizzes = make(map[string]*models.Quiz, 0) session.Quizzes = make(map[string]*models.Quiz, 0)
session.Answers = make(map[string]*models.Answer, 0) session.Answers = make(map[string]*models.Answer, 0)
for _, exam := range session.Exams { for _, exam := range session.Exams {
session.Participants[exam.Participant.ID] = exam.Participant
for _, quiz := range exam.Quizzes { for _, quiz := range exam.Quizzes {
session.Quizzes[quiz.ID] = quiz session.Quizzes[quiz.ID] = quiz