added crud functionality
This commit is contained in:
		
							parent
							
								
									2131f370ee
								
							
						
					
					
						commit
						cb8d779a57
					
				
							
								
								
									
										178
									
								
								main.go
								
								
								
								
							
							
						
						
									
										178
									
								
								main.go
								
								
								
								
							| 
						 | 
				
			
			@ -37,17 +37,38 @@ const (
 | 
			
		|||
	dbName = "gomatic"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// type Agent struct {
 | 
			
		||||
// 	agentId int
 | 
			
		||||
// 	agentName string
 | 
			
		||||
// 	initialContact string
 | 
			
		||||
// 	lastContact string
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
type Agent struct {
 | 
			
		||||
	agentId int
 | 
			
		||||
	agentName string
 | 
			
		||||
	initialContact string
 | 
			
		||||
	lastContact string
 | 
			
		||||
	AgentID        int    `json:"agentId"`
 | 
			
		||||
	AgentName      string `json:"agentName"`
 | 
			
		||||
	InitialContact string `json:"initialContact"`
 | 
			
		||||
	LastContact    string `json:"lastContact"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	tmpl, _ = template.ParseGlob("templates/*.html")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func renderTemplate(w http.ResponseWriter, tmpl string, data interface{}) {
 | 
			
		||||
	t, err := template.ParseFiles(tmpl)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
		log.Printf("Failed to load template %s: %v", tmpl, err)
 | 
			
		||||
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if err := t.Execute(w, data); err != nil {
 | 
			
		||||
		log.Printf("Failed to render template %s: %v", tmpl, err)
 | 
			
		||||
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func initDB () {
 | 
			
		||||
	var err  error
 | 
			
		||||
	dbOpen := fmt.Sprintf("%s:%s@(%s:%d)/%s?parseTime=true", dbUser,dbPassword, dbHost, dbPort, dbName)
 | 
			
		||||
| 
						 | 
				
			
			@ -82,7 +103,7 @@ func getAgents(dbPointer *sql.DB) ([]Agent, error) {
 | 
			
		|||
	for rows.Next() {
 | 
			
		||||
		var agent Agent
 | 
			
		||||
 | 
			
		||||
		rowErr := rows.Scan(&agent.agentId, &agent.agentName, &agent.initialContact, &agent.lastContact)
 | 
			
		||||
		rowErr := rows.Scan(&agent.AgentID, &agent.AgentName, &agent.InitialContact, &agent.LastContact)
 | 
			
		||||
		if rowErr != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -141,6 +162,140 @@ func getHomepage(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	tmpl.ExecuteTemplate(w, "index.html", nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func agentsHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	// if r.URL.Path == "/agents" {
 | 
			
		||||
	// 	if r.Method == http.MethodGet{
 | 
			
		||||
	// 		agents, err := getAgentsFromDB()
 | 
			
		||||
	// 		if err != nil {
 | 
			
		||||
	// 			http.Error(w, "Failed to fetch agents", http.StatusInternalServerError)
 | 
			
		||||
	// 			return
 | 
			
		||||
	// 		}
 | 
			
		||||
	// 		renderTemplate(w, "templates/partials/agent_list.html", agents)
 | 
			
		||||
	// 	} else {
 | 
			
		||||
	// 		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
 | 
			
		||||
	// 	}
 | 
			
		||||
	// 	return
 | 
			
		||||
	// }
 | 
			
		||||
 | 
			
		||||
	parts := strings.Split(strings.TrimPrefix(r.URL.Path, "/agents/"), "/")
 | 
			
		||||
	agentId := ""
 | 
			
		||||
	if len(parts) > 0 && parts[0] != "" {
 | 
			
		||||
		agentId = parts[0]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if len (parts) < 1 || parts[0] == "" {
 | 
			
		||||
	// 	http.Error(w, "Agent ID required", http.StatusBadRequest)
 | 
			
		||||
	// 	return
 | 
			
		||||
	// }
 | 
			
		||||
 | 
			
		||||
	// agentId := parts[0]
 | 
			
		||||
 | 
			
		||||
	switch r.Method {
 | 
			
		||||
	case http.MethodDelete:
 | 
			
		||||
		deleteAgent(w, r, agentId)
 | 
			
		||||
	case http.MethodGet:
 | 
			
		||||
		if agentId == "" {
 | 
			
		||||
			listAgents(w, r)
 | 
			
		||||
		} else {
 | 
			
		||||
			getAgent(w, r, agentId)
 | 
			
		||||
		}
 | 
			
		||||
	case http.MethodPost:
 | 
			
		||||
		createAgent(w, r)
 | 
			
		||||
	case http.MethodPut:
 | 
			
		||||
		updateAgent(w, r, agentId)
 | 
			
		||||
	default:
 | 
			
		||||
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func listAgents(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	agents, err := getAgentsFromDB()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		http.Error(w, "Failed to fetch agents", http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	renderTemplate(w, "templates/partials/agent_list.html", agents)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func deleteAgent(w http.ResponseWriter, r *http.Request, agentID string) {
 | 
			
		||||
	query := "DELETE FROM agents WHERE agentId = ?"
 | 
			
		||||
	_, err := db.Exec(query, agentID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		http.Error(w, "Failed to delete agent", http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	agents, err := getAgentsFromDB()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		http.Error(w, "Failed to fetch agents", http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	renderTemplate(w, "templates/partials/agent_list.html", agents)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createAgent(w http.ResponseWriter, r * http.Request) {
 | 
			
		||||
	err := r.ParseForm()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		http.Error(w, "Invalid form data", http.StatusBadRequest)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	agentName := r.FormValue("agentName")
 | 
			
		||||
	agentId := 42
 | 
			
		||||
	// initalContact := r.FormValue("initialContact")
 | 
			
		||||
	// lastContact := r.FormValue("lastContact")
 | 
			
		||||
 | 
			
		||||
	query := "INSERT INTO agents (agentId, agentName, initialContact, lastContact) VALUES (?, ?, NOW(), NOW())"
 | 
			
		||||
	_, err = db.Exec(query, agentId, agentName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		http.Error(w, "Failed to create agent", http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	listAgents(w, r)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func updateAgent(w http.ResponseWriter, r *http.Request, agentId string) {
 | 
			
		||||
	err := r.ParseForm()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		http.Error(w, "Invalid form data", http.StatusBadRequest)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	agentName := r.FormValue("agentName")
 | 
			
		||||
	lastContact := r.FormValue("lastContact")
 | 
			
		||||
 | 
			
		||||
	query := "UPDATE agents SET agentName = ?, lastContact = ? where agentId = ?"
 | 
			
		||||
	_, err = db.Exec(query, agentName, lastContact, agentId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		http.Error(w, "Failed to update agent", http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	listAgents(w, r,)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getAgentsFromDB() ([]Agent, error) {
 | 
			
		||||
	query := "SELECT agentId, agentName, initialContact, lastContact FROM agents"
 | 
			
		||||
	rows, err := db.Query(query)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	var agents []Agent
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		var agent Agent
 | 
			
		||||
		err := rows.Scan(&agent.AgentID, &agent.AgentName, &agent.InitialContact, &agent.LastContact)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		agents = append(agents, agent)
 | 
			
		||||
	}
 | 
			
		||||
	return agents, rows.Err()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func agentHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	parts := strings.Split(strings.TrimPrefix(r.URL.Path, "/agents/"), "/")
 | 
			
		||||
	if len (parts) < 1 || parts[0] == "" {
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +326,7 @@ type webSocketHandler struct {
 | 
			
		|||
func getAgent(w http.ResponseWriter, r *http.Request, agentId string) {
 | 
			
		||||
	query := "Select agentId, agentName, initialContact, lastContact from agents where agentId = ?"
 | 
			
		||||
	var agent Agent
 | 
			
		||||
	err := db.QueryRow(query, agentId).Scan(&agentId, &agent.agentName, &agent.initialContact, &agent.lastContact)
 | 
			
		||||
	err := db.QueryRow(query, agentId).Scan(&agent.AgentID, &agent.AgentName, &agent.InitialContact, &agent.LastContact)
 | 
			
		||||
	if err == sql.ErrNoRows {
 | 
			
		||||
		http.Error(w, "Agent not found", http.StatusNotFound)
 | 
			
		||||
		return
 | 
			
		||||
| 
						 | 
				
			
			@ -181,6 +336,8 @@ func getAgent(w http.ResponseWriter, r *http.Request, agentId string) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// return agent, nil
 | 
			
		||||
	// TODO: Add agent_detail.html
 | 
			
		||||
	renderTemplate(w, "templates/partials/agent_detail.html", agent)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -226,12 +383,13 @@ func main() {
 | 
			
		|||
 | 
			
		||||
	webMux := http.NewServeMux()
 | 
			
		||||
	webMux.HandleFunc("/", getHomepage)
 | 
			
		||||
	webMux.HandleFunc("/index", getRoot)
 | 
			
		||||
	webMux.HandleFunc("/hello", getHello)
 | 
			
		||||
	webMux.HandleFunc("/agents", fetchAgents)
 | 
			
		||||
	// webMux.HandleFunc("/index", getRoot)
 | 
			
		||||
	// webMux.HandleFunc("/hello", getHello)
 | 
			
		||||
	// webMux.HandleFunc("/agents", fetchAgents)
 | 
			
		||||
	webMux.HandleFunc("/agents", agentsHandler)
 | 
			
		||||
	// webMux.HandleFunc("/newagentform", getAgentForm)
 | 
			
		||||
	// webMux.HandleFunc("/getagentupdateform/{agentId}", getAgentUpdateForm)
 | 
			
		||||
	webMux.HandleFunc("/agents/{agentId}", agentHandler)
 | 
			
		||||
	webMux.HandleFunc("/agents/{agentId}", agentsHandler)
 | 
			
		||||
	// webMux.HandleFunc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,14 +1,21 @@
 | 
			
		|||
{{define "agentList"}}
 | 
			
		||||
<ul>
 | 
			
		||||
    {{range .}}
 | 
			
		||||
        <li>
 | 
			
		||||
            <span {{if .Done}} style="text-decoration:line-through" {{end}}>{{.Agents}}</span>
 | 
			
		||||
            <!-- [<a href="#" hx-get="/gettaskupdateform/{{.Id}}" hx-target="#addTaskForm" hx-swap="innerHTML">Edit</a>] | -->
 | 
			
		||||
            <a href="#" hx-delete="/agents/{{.agentId}}"
 | 
			
		||||
                        hx-confirm="Are you sure you want to Delete this Task?"
 | 
			
		||||
                        hx-target="#agentList">[Delete]</a>
 | 
			
		||||
        </li>
 | 
			
		||||
    {{end}}
 | 
			
		||||
</ul>
 | 
			
		||||
 | 
			
		||||
{{end}}
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
    <title>Agent List</title>
 | 
			
		||||
    <script src="https://unpkg.com/htmx.org"></script>
 | 
			
		||||
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css">
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<div class="container mt-5">
 | 
			
		||||
    <h1>Agent List</h1>
 | 
			
		||||
    <div id="agent-list">
 | 
			
		||||
        <!-- Agents will be dynamically loaded here -->
 | 
			
		||||
        <button class="btn btn-primary mb-3" hx-get="/agents" hx-target="#agent-list" hx-swap="innerHTML">
 | 
			
		||||
            Load Agents
 | 
			
		||||
        </button>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,23 +5,55 @@
 | 
			
		|||
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
 | 
			
		||||
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
 | 
			
		||||
    <script src="https://unpkg.com/htmx.org@1.9.12"></script>
 | 
			
		||||
    <title>To Do App</title>
 | 
			
		||||
    <!-- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> -->
 | 
			
		||||
    <title>g2: gommand & gontrol</title>
 | 
			
		||||
    <script>
 | 
			
		||||
        document.body.addEventListener('htmx:afterRequest', (evt) => {
 | 
			
		||||
            console.log(evt.detail.xhr.responseText);
 | 
			
		||||
        });
 | 
			
		||||
        document.body.addEventListener('htmx:responseError', (evt) => {
 | 
			
		||||
            console.error(evt.detail.xhr.responseText);
 | 
			
		||||
        });
 | 
			
		||||
    </script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <div class="container">
 | 
			
		||||
        <div class="row">
 | 
			
		||||
            <div class="col">
 | 
			
		||||
                <h2>Agents</h2>
 | 
			
		||||
 | 
			
		||||
    <div class="row">
 | 
			
		||||
 | 
			
		||||
        <div class="col">
 | 
			
		||||
            <h2>Tasks</h2>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            <div id="agentList" hx-get="/agents" hx-trigger="load" hx-swap="innerHTML">
 | 
			
		||||
                <!-- Agent List -->
 | 
			
		||||
                <div id="agentList" hx-get="/agents" hx-trigger="load" hx-swap="innerHTML"></div>
 | 
			
		||||
 | 
			
		||||
                <!-- Add Agent Form -->
 | 
			
		||||
                <button class="btn btn-primary mt-3" data-bs-toggle="collapse" data-bs-target="#addAgentForm">Add Agent</button>
 | 
			
		||||
                <div id="addAgentForm" class="collapse mt-2">
 | 
			
		||||
                    <form hx-post="/agents" hx-target="#agentList" hx-swap="innerHTML">
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="agentName" class="form-label">Agent Name</label>
 | 
			
		||||
                            <input type="text" class="form-control" id="agentName" name="agentName" required>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="initialContact" class="form-label">Initial Contact</label>
 | 
			
		||||
                            <input type="datetime-local" class="form-control" id="initialContact" name="initialContact" required>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="lastContact" class="form-label">Last Contact</label>
 | 
			
		||||
                            <input type="datetime-local" class="form-control" id="lastContact" name="lastContact" required>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <button type="submit" class="btn btn-success">Add Agent</button>
 | 
			
		||||
                    </form>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            <!-- Agent Details -->
 | 
			
		||||
            <div class="col" id="agentDetails">
 | 
			
		||||
                <h3>Details</h3>
 | 
			
		||||
                <p>Select an agent to view details.</p>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
<div id="agent-detail">
 | 
			
		||||
    <h2>Agent Details</h2>
 | 
			
		||||
    <p>ID: {{.AgentID}}</p>
 | 
			
		||||
    <p>Name: {{.AgentName}}</p>
 | 
			
		||||
    <p>Initial Contact: {{.InitialContact}}</p>
 | 
			
		||||
    <p>Last Contact: {{.LastContact}}</p>
 | 
			
		||||
    <button hx-get="/agents" hx-target="#agentList" hx-swap="innerHTML">Back to List</button>
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
<table class="table table-bordered">
 | 
			
		||||
    <thead>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <th>ID</th>
 | 
			
		||||
            <th>Name</th>
 | 
			
		||||
            <th>Initial Contact</th>
 | 
			
		||||
            <th>Last Contact</th>
 | 
			
		||||
            <th>Actions</th>
 | 
			
		||||
        </tr>
 | 
			
		||||
    </thead>
 | 
			
		||||
    <tbody>
 | 
			
		||||
        {{range .}}
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td>{{.AgentID}}</td>
 | 
			
		||||
            <td>{{.AgentName}}</td>
 | 
			
		||||
            <td>{{.InitialContact}}</td>
 | 
			
		||||
            <td>{{.LastContact}}</td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <button hx-get="/agents/{{.AgentID}}" hx-target="#agentDetails" hx-swap="innerHTML">View</button>
 | 
			
		||||
 | 
			
		||||
                <button class="btn btn-danger" hx-delete="/agents/{{.AgentID}}" hx-target="#agentList" hx-swap="innerHTML">Delete</button>
 | 
			
		||||
            </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        {{end}}
 | 
			
		||||
    </tbody>
 | 
			
		||||
</table>
 | 
			
		||||
		Loading…
	
		Reference in New Issue