368 lines
11 KiB
Go
368 lines
11 KiB
Go
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
)
|
|
|
|
type Question struct {
|
|
ID int
|
|
QuestionText string
|
|
QuestionType string
|
|
Options []string
|
|
}
|
|
|
|
type Match struct {
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
Classes []string `json:"classes"`
|
|
}
|
|
|
|
var db *sql.DB
|
|
|
|
func renderForm(w http.ResponseWriter, r *http.Request) {
|
|
log.Println("[DEBUG] Entering renderForm handler")
|
|
tmpl := template.Must(template.ParseFiles("index.html"))
|
|
log.Println("[DEBUG] Rendering template with questions")
|
|
err := tmpl.Execute(w, nil)
|
|
if err != nil {
|
|
log.Println("[ERROR] Error rendering template:", err)
|
|
}
|
|
}
|
|
|
|
func handleFormSubmit(w http.ResponseWriter, r *http.Request) {
|
|
log.Println("[DEBUG] Entering handleFormSubmit handler")
|
|
|
|
// Parse the form data
|
|
if err := r.ParseForm(); err != nil {
|
|
http.Error(w, "Invalid form data", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
name := r.FormValue("name")
|
|
email := r.FormValue("email")
|
|
phone := r.FormValue("phone")
|
|
dorm := r.FormValue("dorm")
|
|
classes := r.FormValue("classes")
|
|
|
|
// Insert the user data into the database
|
|
tx, err := db.Begin()
|
|
if err != nil {
|
|
log.Fatalf("[ERROR] Failed to begin transaction: %v\n", err)
|
|
return
|
|
}
|
|
|
|
result, err := tx.Exec(`INSERT INTO users (name, email, phone, dorm) VALUES (?, ?, ?, ?)`, name, email, phone, dorm)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
log.Fatalf("[ERROR] Failed to insert user: %v\n", err)
|
|
return
|
|
}
|
|
|
|
userID, err := result.LastInsertId()
|
|
if err != nil {
|
|
tx.Rollback()
|
|
log.Fatalf("[ERROR] Failed to get last insert ID: %v\n", err)
|
|
return
|
|
}
|
|
|
|
// Insert the classes associated with this user
|
|
classList := strings.Split(classes, ",")
|
|
for _, class := range classList {
|
|
_, err := tx.Exec(`INSERT INTO classes (user_id, class_name) VALUES (?, ?)`, userID, strings.TrimSpace(class))
|
|
if err != nil {
|
|
tx.Rollback()
|
|
log.Fatalf("[ERROR] Failed to insert class: %v\n", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
log.Fatalf("[ERROR] Failed to commit transaction: %v\n", err)
|
|
return
|
|
}
|
|
|
|
log.Println("[DEBUG] User and classes inserted successfully")
|
|
fmt.Fprintf(w, "Thank you for your submission!")
|
|
log.Println("[DEBUG] Exiting handleFormSubmit handler")
|
|
}
|
|
|
|
// func handleAdmin(w http.ResponseWriter, r *http.Request) {
|
|
// log.Println("[DEBUG] Entering handleAdmin handler")
|
|
// rows, err := db.Query(`
|
|
// SELECT q.question_text, a.answer, GROUP_CONCAT(t.tag, ', ') as tags
|
|
// FROM answers a
|
|
// JOIN questions q ON a.question_id = q.id
|
|
// LEFT JOIN tags t ON a.id = t.answer_id
|
|
// GROUP BY a.id
|
|
// ORDER BY q.question_order
|
|
// `)
|
|
// if err != nil {
|
|
// log.Printf("[ERROR] Error fetching submissions: %v\n", err)
|
|
// http.Error(w, "Failed to fetch submissions", http.StatusInternalServerError)
|
|
// return
|
|
// }
|
|
// defer rows.Close()
|
|
//
|
|
// var submissions []struct {
|
|
// QuestionText string
|
|
// Answer string
|
|
// Tags string
|
|
// }
|
|
// log.Println("[DEBUG] Fetching submissions")
|
|
//
|
|
// for rows.Next() {
|
|
// var submission struct {
|
|
// QuestionText string
|
|
// Answer string
|
|
// Tags string
|
|
// }
|
|
// err := rows.Scan(&submission.QuestionText, &submission.Answer, &submission.Tags)
|
|
// if err != nil {
|
|
// log.Printf("[ERROR] Error scanning submission: %v\n", err)
|
|
// continue
|
|
// }
|
|
// submissions = append(submissions, submission)
|
|
// log.Printf("[DEBUG] Fetched submission: %v\n", submission)
|
|
// }
|
|
//
|
|
// tmpl := template.Must(template.ParseFiles("admin.html"))
|
|
// log.Println("[DEBUG] Rendering admin template with submissions")
|
|
// tmpl.Execute(w, submissions)
|
|
// }
|
|
//
|
|
// func handleAddQuestion(w http.ResponseWriter, r *http.Request) {
|
|
// log.Println("[DEBUG] Entering handleAddQuestion handler")
|
|
// if r.Method != http.MethodPost {
|
|
// log.Printf("[ERROR] Invalid request method: %v\n", r.Method)
|
|
// http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
|
|
// return
|
|
// }
|
|
//
|
|
// r.ParseForm()
|
|
// questionText := r.FormValue("question_text")
|
|
// questionType := r.FormValue("question_type")
|
|
// options := r.FormValue("options")
|
|
//
|
|
// log.Printf("[DEBUG] Adding new question: %s, Type: %s\n", questionText, questionType)
|
|
//
|
|
// insertQuery := `INSERT INTO questions (question_text, question_type, question_order) VALUES (?, ?, (SELECT IFNULL(MAX(question_order), 0) + 1 FROM questions));`
|
|
// res, err := db.Exec(insertQuery, questionText, questionType)
|
|
// if err != nil {
|
|
// log.Printf("[ERROR] Error adding new question: %v\n", err)
|
|
// http.Error(w, "Failed to add question", http.StatusInternalServerError)
|
|
// return
|
|
// }
|
|
//
|
|
// if questionType == "multiple_choice" || questionType == "single_choice" || questionType == "dropdown" || questionType == "tags" {
|
|
// questionID, err := res.LastInsertId()
|
|
// if err != nil {
|
|
// log.Printf("[ERROR] Error getting question ID: %v\n", err)
|
|
// http.Error(w, "Failed to add question", http.StatusInternalServerError)
|
|
// return
|
|
// }
|
|
// log.Printf("[DEBUG] Inserted question ID: %d\n", questionID)
|
|
//
|
|
// optionsList := strings.Split(options, ",")
|
|
// for _, option := range optionsList {
|
|
// option = strings.TrimSpace(option)
|
|
// log.Printf("[DEBUG] Adding option: %s to question ID: %d\n", option, questionID)
|
|
// _, err = db.Exec("INSERT INTO question_options (question_id, option_text) VALUES (?, ?)", questionID, option)
|
|
// if err != nil {
|
|
// log.Printf("[ERROR] Error adding options: %v\n", err)
|
|
// http.Error(w, "Failed to add options", http.StatusInternalServerError)
|
|
// return
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// log.Println("[DEBUG] Redirecting to manage page")
|
|
// http.Redirect(w, r, "/manage", http.StatusSeeOther)
|
|
// }
|
|
//
|
|
// func handleManage(w http.ResponseWriter, r *http.Request) {
|
|
// log.Println("[DEBUG] Entering handleManage handler")
|
|
// rows, err := db.Query("SELECT id, question_text, question_type FROM questions ORDER BY question_order")
|
|
// if err != nil {
|
|
// log.Printf("[ERROR] Error fetching questions: %v\n", err)
|
|
// http.Error(w, "Failed to fetch questions", http.StatusInternalServerError)
|
|
// return
|
|
// }
|
|
// defer rows.Close()
|
|
//
|
|
// var questions []Question
|
|
// log.Println("[DEBUG] Fetching questions for management")
|
|
//
|
|
// for rows.Next() {
|
|
// var question Question
|
|
// err := rows.Scan(&question.ID, &question.QuestionText, &question.QuestionType)
|
|
// if err != nil {
|
|
// log.Printf("[ERROR] Error scanning question: %v\n", err)
|
|
// continue
|
|
// }
|
|
// log.Printf("[DEBUG] Found question: %v\n", question)
|
|
//
|
|
// if question.QuestionType == "multiple_choice" || question.QuestionType == "single_choice" || question.QuestionType == "dropdown" {
|
|
// optionRows, err := db.Query("SELECT option_text FROM question_options WHERE question_id = ?", question.ID)
|
|
// if err != nil {
|
|
// log.Printf("[ERROR] Error fetching options: %v\n", err)
|
|
// continue
|
|
// }
|
|
// defer optionRows.Close()
|
|
//
|
|
// for optionRows.Next() {
|
|
// var optionText string
|
|
// err = optionRows.Scan(&optionText)
|
|
// if err != nil {
|
|
// log.Printf("[ERROR] Error scanning option: %v\n", err)
|
|
// continue
|
|
// }
|
|
// question.Options = append(question.Options, optionText)
|
|
// log.Printf("[DEBUG] Found option: %s\n", optionText)
|
|
// }
|
|
// }
|
|
//
|
|
// questions = append(questions, question)
|
|
// }
|
|
//
|
|
// tmpl := template.Must(template.ParseFiles("manage.html"))
|
|
// log.Println("[DEBUG] Rendering manage template with questions")
|
|
// tmpl.Execute(w, questions)
|
|
// }
|
|
//
|
|
// func handleRemoveQuestion(w http.ResponseWriter, r *http.Request) {
|
|
// log.Println("[DEBUG] Entering handleRemoveQuestion handler")
|
|
// questionID := r.URL.Query().Get("id")
|
|
// log.Printf("[DEBUG] Removing question with ID: %s\n", questionID)
|
|
//
|
|
// deleteQuery := `DELETE FROM questions WHERE id = ?`
|
|
// _, err := db.Exec(deleteQuery, questionID)
|
|
// if err != nil {
|
|
// log.Printf("[ERROR] Error removing question: %v\n", err)
|
|
// http.Error(w, "Failed to remove question", http.StatusInternalServerError)
|
|
// return
|
|
// }
|
|
//
|
|
// log.Println("[DEBUG] Redirecting to manage page after deletion")
|
|
// http.Redirect(w, r, "/manage", http.StatusSeeOther)
|
|
// }
|
|
|
|
func handleFetchMatches(w http.ResponseWriter, r *http.Request) {
|
|
log.Println("[DEBUG] Entering handleFetchMatches handler")
|
|
|
|
// Parse the request body
|
|
var requestData struct {
|
|
Classes []string `json:"classes"`
|
|
}
|
|
err := json.NewDecoder(r.Body).Decode(&requestData)
|
|
if err != nil {
|
|
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
classes := requestData.Classes
|
|
|
|
// Prepare the SQL query to find matching users based on classes
|
|
query := `
|
|
SELECT u.name, u.email, GROUP_CONCAT(c.class_name, ', ') AS classes
|
|
FROM users u
|
|
JOIN classes c ON u.id = c.user_id
|
|
WHERE c.class_name IN (` + strings.Repeat("?,", len(classes)-1) + `?)
|
|
GROUP BY u.id
|
|
`
|
|
|
|
args := make([]interface{}, len(classes))
|
|
for i, class := range classes {
|
|
args[i] = class
|
|
}
|
|
|
|
rows, err := db.Query(query, args...)
|
|
if err != nil {
|
|
http.Error(w, "Database query failed", http.StatusInternalServerError)
|
|
log.Fatalf("[ERROR] Query failed: %v\n", err)
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
|
|
var people []map[string]interface{}
|
|
for rows.Next() {
|
|
var name, email, classList string
|
|
if err := rows.Scan(&name, &email, &classList); err != nil {
|
|
log.Fatalf("[ERROR] Row scan failed: %v\n", err)
|
|
return
|
|
}
|
|
|
|
person := map[string]interface{}{
|
|
"name": name,
|
|
"email": email,
|
|
"classes": strings.Split(classList, ", "),
|
|
}
|
|
people = append(people, person)
|
|
}
|
|
|
|
// Send the matching people as JSON response
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(people)
|
|
|
|
log.Println("[DEBUG] Exiting handleFetchMatches handler")
|
|
}
|
|
|
|
func main() {
|
|
var err error
|
|
|
|
log.Println("[DEBUG] Opening database connection")
|
|
db, err = sql.Open("sqlite3", "./formdata.db")
|
|
// db, err = sql.Open("sqlite3", ":memory:")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
createTableQueries := `
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
email TEXT,
|
|
phone TEXT,
|
|
dorm TEXT
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS classes (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER,
|
|
class_name TEXT NOT NULL,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
`
|
|
|
|
log.Println("[DEBUG] Creating database tables")
|
|
_, err = db.Exec(createTableQueries)
|
|
if err != nil {
|
|
log.Fatalf("[ERROR] Error creating tables: %v\n", err)
|
|
return
|
|
}
|
|
log.Println("[DEBUG] Database tables created successfully")
|
|
|
|
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
|
|
|
http.HandleFunc("/", renderForm)
|
|
http.HandleFunc("/submit", handleFormSubmit)
|
|
// http.HandleFunc("/admin", handleAdmin)
|
|
// http.HandleFunc("/manage", handleManage)
|
|
// http.HandleFunc("/manage/add", handleAddQuestion)
|
|
// http.HandleFunc("/manage/remove", handleRemoveQuestion)
|
|
http.HandleFunc("/fetch-matches", handleFetchMatches)
|
|
|
|
log.Println("[DEBUG] Server starting at :8080")
|
|
fmt.Println("Server started at :8080")
|
|
|
|
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
}
|