Compare commits
2 commits
1742f65fcd
...
b5ec4a9f17
| Author | SHA1 | Date | |
|---|---|---|---|
| b5ec4a9f17 | |||
| 097ecd6dfc |
2 changed files with 175 additions and 21 deletions
111
main.go
111
main.go
|
|
@ -241,29 +241,75 @@ func addTrainingAreaHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchTrainings() ([]Training, error) {
|
func fetchTrainings() ([]Training, error) {
|
||||||
log.Println("Fetching trainings from the database")
|
log.Println("Fetching trainings with assigned trainers from the database")
|
||||||
rows, err := db.Query("SELECT id, title, training_type, mode, strftime('%Y-%m-%d %H:%M:%S', start), strftime('%Y-%m-%d %H:%M:%S', end), status FROM trainings")
|
|
||||||
|
query := `
|
||||||
|
SELECT
|
||||||
|
t.id, t.title, t.training_type, t.mode,
|
||||||
|
strftime('%Y-%m-%d %H:%M:%S', t.start), strftime('%Y-%m-%d %H:%M:%S', t.end), t.status,
|
||||||
|
tr.id, tr.name, tr.email
|
||||||
|
FROM trainings t
|
||||||
|
LEFT JOIN training_trainers tt ON t.id = tt.training_id
|
||||||
|
LEFT JOIN trainers tr ON tt.trainer_id = tr.id
|
||||||
|
ORDER BY t.id, tr.name
|
||||||
|
`
|
||||||
|
|
||||||
|
rows, err := db.Query(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error fetching trainings: %v", err)
|
log.Printf("Error fetching trainings: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
var trainings []Training
|
trainingMap := make(map[int]*Training)
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var t Training
|
var trainingID int
|
||||||
var start, end string
|
var title, trainingType, mode, status, startStr, endStr string
|
||||||
err := rows.Scan(&t.ID, &t.Title, &t.TrainingType, &t.Mode, &start, &end, &t.Status)
|
var trainerID sql.NullInt64
|
||||||
|
var trainerName sql.NullString
|
||||||
|
var trainerEmail sql.NullString
|
||||||
|
|
||||||
|
err := rows.Scan(&trainingID, &title, &trainingType, &mode, &startStr, &endStr, &status,
|
||||||
|
&trainerID, &trainerName, &trainerEmail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error scanning row for training: %v", err)
|
log.Printf("Error scanning row for training: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t.Start, _ = time.Parse(time.DateTime, start)
|
|
||||||
t.End, _ = time.Parse(time.DateTime, end)
|
start, _ := time.Parse(time.DateTime, startStr)
|
||||||
trainings = append(trainings, t)
|
end, _ := time.Parse(time.DateTime, endStr)
|
||||||
|
|
||||||
|
training, exists := trainingMap[trainingID]
|
||||||
|
if !exists {
|
||||||
|
training = &Training{
|
||||||
|
ID: trainingID,
|
||||||
|
Title: title,
|
||||||
|
TrainingType: trainingType,
|
||||||
|
Mode: mode,
|
||||||
|
Start: start,
|
||||||
|
End: end,
|
||||||
|
Status: status,
|
||||||
|
Trainers: []Trainer{},
|
||||||
|
}
|
||||||
|
trainingMap[trainingID] = training
|
||||||
|
}
|
||||||
|
|
||||||
|
if trainerID.Valid {
|
||||||
|
training.Trainers = append(training.Trainers, Trainer{
|
||||||
|
ID: int(trainerID.Int64),
|
||||||
|
Name: trainerName.String,
|
||||||
|
Email: trainerEmail.String,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Found %d trainings", len(trainings))
|
var trainings []Training
|
||||||
|
for _, training := range trainingMap {
|
||||||
|
trainings = append(trainings, *training)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Found %d trainings with trainers", len(trainings))
|
||||||
return trainings, nil
|
return trainings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -276,7 +322,22 @@ func trainingListHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tmpl.ExecuteTemplate(w, "training_list.html", trainings)
|
trainers, err := fetchTrainers()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error fetching trainers: %v", err)
|
||||||
|
http.Error(w, "Database error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data := struct {
|
||||||
|
Trainings []Training
|
||||||
|
Trainers []Trainer
|
||||||
|
}{
|
||||||
|
Trainings: trainings,
|
||||||
|
Trainers: trainers,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tmpl.ExecuteTemplate(w, "training_list.html", data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error in templating page training_list.html: %v", err)
|
log.Printf("Error in templating page training_list.html: %v", err)
|
||||||
http.Error(w, fmt.Sprintf("Error in templating page %v", err), http.StatusInternalServerError)
|
http.Error(w, fmt.Sprintf("Error in templating page %v", err), http.StatusInternalServerError)
|
||||||
|
|
@ -562,11 +623,39 @@ func addTrainingHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assignTrainerHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Println("Handling trainer assignment to training")
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
trainingID := r.FormValue("training_id")
|
||||||
|
trainerID := r.FormValue("trainer_id")
|
||||||
|
|
||||||
|
if trainingID == "" || trainerID == "" {
|
||||||
|
log.Println("Missing training ID or trainer ID")
|
||||||
|
http.Error(w, "Training ID and Trainer ID are required", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := db.Exec("INSERT OR IGNORE INTO training_trainers (training_id, trainer_id) VALUES (?, ?)", trainingID, trainerID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error assigning trainer to training: %v", err)
|
||||||
|
http.Error(w, "Database error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Trainer assigned to training successfully")
|
||||||
|
http.Redirect(w, r, "/trainings", http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
||||||
func initServerHandlers() {
|
func initServerHandlers() {
|
||||||
http.Handle("/", redirectIfNoAdmin(http.HandlerFunc(homeHandler)))
|
http.Handle("/", redirectIfNoAdmin(http.HandlerFunc(homeHandler)))
|
||||||
|
|
||||||
http.Handle("/trainings", redirectIfNoAdmin(http.HandlerFunc(trainingListHandler)))
|
http.Handle("/trainings", redirectIfNoAdmin(http.HandlerFunc(trainingListHandler)))
|
||||||
http.Handle("/trainings/add", redirectIfNoAdmin(http.HandlerFunc(addTrainingHandler)))
|
http.Handle("/trainings/add", redirectIfNoAdmin(http.HandlerFunc(addTrainingHandler)))
|
||||||
|
http.Handle("/trainings/assign_trainer", redirectIfNoAdmin(http.HandlerFunc(assignTrainerHandler)))
|
||||||
|
|
||||||
http.Handle("/trainers", redirectIfNoAdmin(http.HandlerFunc(trainerListHandler)))
|
http.Handle("/trainers", redirectIfNoAdmin(http.HandlerFunc(trainerListHandler)))
|
||||||
http.Handle("/trainers/add", redirectIfNoAdmin(http.HandlerFunc(addTrainerHandler)))
|
http.Handle("/trainers/add", redirectIfNoAdmin(http.HandlerFunc(addTrainerHandler)))
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
<p><a href="/trainings/add"><button>Add New Training</button></a></p>
|
<p><a href="/trainings/add"><button>Add New Training</button></a></p>
|
||||||
|
|
||||||
<h1>Trainings</h1>
|
<h1>Trainings</h1>
|
||||||
<table border="1">
|
<table>
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Title</th>
|
<th>Title</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
|
|
@ -10,17 +11,81 @@
|
||||||
<th>Start</th>
|
<th>Start</th>
|
||||||
<th>End</th>
|
<th>End</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
|
<th>Trainers</th>
|
||||||
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
{{ range . }}
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range .Trainings}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ .Title }}</td>
|
<td>{{.Title}}</td>
|
||||||
<td>{{ .TrainingType }}</td>
|
<td>{{.TrainingType}}</td>
|
||||||
<td>{{ .Mode }}</td>
|
<td>{{.Mode}}</td>
|
||||||
<td>{{ .Start }}</td>
|
<td>{{.Start.Format "2006-01-02 15:04"}}</td>
|
||||||
<td>{{ .End }}</td>
|
<td>{{.End.Format "2006-01-02 15:04"}}</td>
|
||||||
<td>{{ .Status }}</td>
|
<td>{{.Status}}</td>
|
||||||
|
<td>
|
||||||
|
{{if .Trainers}}
|
||||||
|
{{range .Trainers}}
|
||||||
|
{{.Name}} ({{.Email}})<br>
|
||||||
|
{{end}}
|
||||||
|
{{else}}
|
||||||
|
No trainers assigned
|
||||||
|
{{end}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button onclick="openAssignTrainerModal({{.ID}})">Assign Trainer</button>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{ end }}
|
{{end}}
|
||||||
</table>
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- Assign Trainer Modal -->
|
||||||
|
<div id="assignTrainerModal" style="display:none; position:fixed; top:50%; left:50%; transform:translate(-50%, -50%); background:white; padding:20px; border:1px solid black;">
|
||||||
|
<h3>Assign Trainer</h3>
|
||||||
|
<form id="assignTrainerForm" >
|
||||||
|
<input type="hidden" id="training_id" name="training_id">
|
||||||
|
<label for="trainer">Select Trainer:</label>
|
||||||
|
<select id="trainer_id" name="trainer_id">
|
||||||
|
{{range .Trainers}}
|
||||||
|
<option value="{{.ID}}">{{.Name}} ({{.Email}})</option>
|
||||||
|
{{end}}
|
||||||
|
</select>
|
||||||
|
<button type="submit">Assign</button>
|
||||||
|
<button type="button" onclick="closeAssignTrainerModal()">Cancel</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function openAssignTrainerModal(trainingId) {
|
||||||
|
document.getElementById('training_id').value = trainingId;
|
||||||
|
document.getElementById('assignTrainerModal').style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeAssignTrainerModal() {
|
||||||
|
document.getElementById('assignTrainerModal').style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('assignTrainerForm').addEventListener('submit', function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const formData = new FormData(this); // Create FormData from the form element
|
||||||
|
console.log(formData);
|
||||||
|
|
||||||
|
fetch('/trainings/assign_trainer', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData // Send as form data
|
||||||
|
}).then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
alert('Failed to assign trainer');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{{template "epilogue.html" }}
|
{{template "epilogue.html" }}
|
||||||
Loading…
Add table
Reference in a new issue