go-crm improvements
This commit is contained in:
Binary file not shown.
10
AGENTS.md
10
AGENTS.md
@@ -59,6 +59,16 @@ npm run test:coverage # Jest with coverage
|
|||||||
```bash
|
```bash
|
||||||
cd apps/whatsapp-reader
|
cd apps/whatsapp-reader
|
||||||
# No test script defined
|
# No test script defined
|
||||||
|
node index.js # Run main script
|
||||||
|
node sync.js # Run sync script
|
||||||
|
```
|
||||||
|
|
||||||
|
### timesfm-forecast (Python/uv)
|
||||||
|
```bash
|
||||||
|
cd apps/timesfm-forecast
|
||||||
|
uv venv && source .venv/bin/activate # Create & activate venv
|
||||||
|
uv pip install -e . # Install package
|
||||||
|
timesfm-app # Run Streamlit app
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
Binary file not shown.
BIN
apps/go-crm/data/go-crm.db.bak
Normal file
BIN
apps/go-crm/data/go-crm.db.bak
Normal file
Binary file not shown.
BIN
apps/go-crm/go-crm
Executable file
BIN
apps/go-crm/go-crm
Executable file
Binary file not shown.
@@ -5,13 +5,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
ClientID int64 `json:"client_id"`
|
ClientID int64 `json:"client_id"`
|
||||||
Name string `json:"name"`
|
AccountID int64 `json:"account_id"`
|
||||||
Phone string `json:"phone,omitempty"`
|
Name string `json:"name"`
|
||||||
Email string `json:"email,omitempty"`
|
Phone string `json:"phone,omitempty"`
|
||||||
Address string `json:"address,omitempty"`
|
Email string `json:"email,omitempty"`
|
||||||
Notes string `json:"notes,omitempty"`
|
Address string `json:"address,omitempty"`
|
||||||
CreatedAt int64 `json:"created_at"`
|
Notes string `json:"notes,omitempty"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Customer struct {
|
type Customer struct {
|
||||||
@@ -59,8 +60,8 @@ type Payment struct {
|
|||||||
|
|
||||||
func (c *Client) Create(db *sql.DB) error {
|
func (c *Client) Create(db *sql.DB) error {
|
||||||
result, err := db.Exec(
|
result, err := db.Exec(
|
||||||
"INSERT INTO clients (name, phone, email, address, notes, created_at) VALUES (?, ?, ?, ?, ?, ?)",
|
"INSERT INTO clients (account_id, name, phone, email, address, notes, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||||
c.Name, c.Phone, c.Email, c.Address, c.Notes, c.CreatedAt,
|
c.AccountID, c.Name, c.Phone, c.Email, c.Address, c.Notes, c.CreatedAt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -75,29 +76,35 @@ func (c *Client) Create(db *sql.DB) error {
|
|||||||
|
|
||||||
func (c *Client) Read(db *sql.DB, id int64) error {
|
func (c *Client) Read(db *sql.DB, id int64) error {
|
||||||
return db.QueryRow(
|
return db.QueryRow(
|
||||||
"SELECT client_id, name, phone, email, address, notes, created_at FROM clients WHERE client_id = ?",
|
"SELECT client_id, account_id, name, COALESCE(phone,''), COALESCE(email,''), COALESCE(address,''), COALESCE(notes,''), created_at FROM clients WHERE client_id = ?",
|
||||||
id,
|
id,
|
||||||
).Scan(&c.ClientID, &c.Name, &c.Phone, &c.Email, &c.Address, &c.Notes, &c.CreatedAt)
|
).Scan(&c.ClientID, &c.AccountID, &c.Name, &c.Phone, &c.Email, &c.Address, &c.Notes, &c.CreatedAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Update(db *sql.DB) error {
|
func (c *Client) Update(db *sql.DB) error {
|
||||||
_, err := db.Exec(
|
_, err := db.Exec(
|
||||||
"UPDATE clients SET name = ?, phone = ?, email = ?, address = ?, notes = ? WHERE client_id = ?",
|
"UPDATE clients SET name = ?, phone = ?, email = ?, address = ?, notes = ? WHERE client_id = ? AND account_id = ?",
|
||||||
c.Name, c.Phone, c.Email, c.Address, c.Notes, c.ClientID,
|
c.Name, c.Phone, c.Email, c.Address, c.Notes, c.ClientID, c.AccountID,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Delete(db *sql.DB, id int64) error {
|
func (c *Client) Delete(db *sql.DB) error {
|
||||||
_, err := db.Exec("DELETE FROM clients WHERE client_id = ?", id)
|
_, err := db.Exec("DELETE FROM clients WHERE client_id = ? AND account_id = ?", c.ClientID, c.AccountID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListClients(db *sql.DB, limit, offset int) ([]Client, error) {
|
func ListClients(db *sql.DB, accountID int64, limit, offset int) ([]Client, error) {
|
||||||
rows, err := db.Query(
|
query := "SELECT client_id, account_id, name, COALESCE(phone,''), COALESCE(email,''), COALESCE(address,''), COALESCE(notes,''), created_at FROM clients"
|
||||||
"SELECT client_id, name, phone, email, address, notes, created_at FROM clients ORDER BY created_at DESC LIMIT ? OFFSET ?",
|
args := []interface{}{}
|
||||||
limit, offset,
|
if accountID > 0 {
|
||||||
)
|
query += " WHERE account_id = ?"
|
||||||
|
args = append(args, accountID)
|
||||||
|
}
|
||||||
|
query += " ORDER BY created_at DESC LIMIT ? OFFSET ?"
|
||||||
|
args = append(args, limit, offset)
|
||||||
|
|
||||||
|
rows, err := db.Query(query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -106,7 +113,7 @@ func ListClients(db *sql.DB, limit, offset int) ([]Client, error) {
|
|||||||
var clients []Client
|
var clients []Client
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var c Client
|
var c Client
|
||||||
if err := rows.Scan(&c.ClientID, &c.Name, &c.Phone, &c.Email, &c.Address, &c.Notes, &c.CreatedAt); err != nil {
|
if err := rows.Scan(&c.ClientID, &c.AccountID, &c.Name, &c.Phone, &c.Email, &c.Address, &c.Notes, &c.CreatedAt); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
clients = append(clients, c)
|
clients = append(clients, c)
|
||||||
@@ -114,12 +121,12 @@ func ListClients(db *sql.DB, limit, offset int) ([]Client, error) {
|
|||||||
return clients, rows.Err()
|
return clients, rows.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetClientByID(db *sql.DB, id int64) (*Client, error) {
|
func GetClientByID(db *sql.DB, accountID, id int64) (*Client, error) {
|
||||||
var c Client
|
var c Client
|
||||||
err := db.QueryRow(
|
err := db.QueryRow(
|
||||||
"SELECT client_id, name, phone, email, address, notes, created_at FROM clients WHERE client_id = ?",
|
"SELECT client_id, account_id, name, COALESCE(phone,''), COALESCE(email,''), COALESCE(address,''), COALESCE(notes,''), created_at FROM clients WHERE client_id = ? AND account_id = ?",
|
||||||
id,
|
id, accountID,
|
||||||
).Scan(&c.ClientID, &c.Name, &c.Phone, &c.Email, &c.Address, &c.Notes, &c.CreatedAt)
|
).Scan(&c.ClientID, &c.AccountID, &c.Name, &c.Phone, &c.Email, &c.Address, &c.Notes, &c.CreatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -142,13 +149,24 @@ func (cu *Customer) Create(db *sql.DB) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListCustomers(db *sql.DB, clientID int64, limit, offset int) ([]Customer, error) {
|
func ListCustomers(db *sql.DB, accountID, clientID int64, limit, offset int) ([]Customer, error) {
|
||||||
|
args := []interface{}{}
|
||||||
query := "SELECT customer_id, client_id, name, phone, birth_date, instagram, created_at FROM customers"
|
query := "SELECT customer_id, client_id, name, phone, birth_date, instagram, created_at FROM customers"
|
||||||
var args []interface{}
|
cond := ""
|
||||||
if clientID > 0 {
|
if clientID > 0 {
|
||||||
query += " WHERE client_id = ?"
|
cond = "client_id = ?"
|
||||||
args = append(args, clientID)
|
args = append(args, clientID)
|
||||||
}
|
}
|
||||||
|
if accountID > 0 {
|
||||||
|
if cond != "" {
|
||||||
|
cond += " AND "
|
||||||
|
}
|
||||||
|
cond += "client_id IN (SELECT client_id FROM clients WHERE account_id = ?)"
|
||||||
|
args = append(args, accountID)
|
||||||
|
}
|
||||||
|
if cond != "" {
|
||||||
|
query += " WHERE " + cond
|
||||||
|
}
|
||||||
query += " ORDER BY created_at DESC LIMIT ? OFFSET ?"
|
query += " ORDER BY created_at DESC LIMIT ? OFFSET ?"
|
||||||
args = append(args, limit, offset)
|
args = append(args, limit, offset)
|
||||||
|
|
||||||
@@ -185,13 +203,24 @@ func (s *Service) Create(db *sql.DB) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListServices(db *sql.DB, clientID int64, limit, offset int) ([]Service, error) {
|
func ListServices(db *sql.DB, accountID, clientID int64, limit, offset int) ([]Service, error) {
|
||||||
|
args := []interface{}{}
|
||||||
query := "SELECT service_id, client_id, name, price, description, duration, created_at FROM services"
|
query := "SELECT service_id, client_id, name, price, description, duration, created_at FROM services"
|
||||||
var args []interface{}
|
cond := ""
|
||||||
if clientID > 0 {
|
if clientID > 0 {
|
||||||
query += " WHERE client_id = ?"
|
cond = "client_id = ?"
|
||||||
args = append(args, clientID)
|
args = append(args, clientID)
|
||||||
}
|
}
|
||||||
|
if accountID > 0 {
|
||||||
|
if cond != "" {
|
||||||
|
cond += " AND "
|
||||||
|
}
|
||||||
|
cond += "client_id IN (SELECT client_id FROM clients WHERE account_id = ?)"
|
||||||
|
args = append(args, accountID)
|
||||||
|
}
|
||||||
|
if cond != "" {
|
||||||
|
query += " WHERE " + cond
|
||||||
|
}
|
||||||
query += " ORDER BY created_at DESC LIMIT ? OFFSET ?"
|
query += " ORDER BY created_at DESC LIMIT ? OFFSET ?"
|
||||||
args = append(args, limit, offset)
|
args = append(args, limit, offset)
|
||||||
|
|
||||||
@@ -430,7 +459,8 @@ type AnswerWithDetails struct {
|
|||||||
QuestionText string `json:"question_text"`
|
QuestionText string `json:"question_text"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListAnswersWithDetails(db *sql.DB, questionID int64, limit, offset int) ([]AnswerWithDetails, error) {
|
func ListAnswersWithDetails(db *sql.DB, accountID, questionID int64, limit, offset int) ([]AnswerWithDetails, error) {
|
||||||
|
args := []interface{}{accountID}
|
||||||
query := `
|
query := `
|
||||||
SELECT
|
SELECT
|
||||||
a.answer_id, a.client_id, a.question_id, a.answer, a.timestamp, a.status, a.created_at,
|
a.answer_id, a.client_id, a.question_id, a.answer, a.timestamp, a.status, a.created_at,
|
||||||
@@ -441,8 +471,7 @@ func ListAnswersWithDetails(db *sql.DB, questionID int64, limit, offset int) ([]
|
|||||||
JOIN questions q ON a.question_id = q.question_id
|
JOIN questions q ON a.question_id = q.question_id
|
||||||
JOIN customers cu ON q.customer_id = cu.customer_id
|
JOIN customers cu ON q.customer_id = cu.customer_id
|
||||||
JOIN clients c ON q.client_id = c.client_id
|
JOIN clients c ON q.client_id = c.client_id
|
||||||
WHERE 1=1`
|
WHERE c.account_id = ?`
|
||||||
var args []interface{}
|
|
||||||
if questionID > 0 {
|
if questionID > 0 {
|
||||||
query += " AND a.question_id = ?"
|
query += " AND a.question_id = ?"
|
||||||
args = append(args, questionID)
|
args = append(args, questionID)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
_ "github.com/glebarez/sqlite"
|
_ "github.com/glebarez/sqlite"
|
||||||
)
|
)
|
||||||
@@ -27,12 +28,14 @@ CREATE TABLE IF NOT EXISTS sessions (
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS clients (
|
CREATE TABLE IF NOT EXISTS clients (
|
||||||
client_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
client_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
account_id INTEGER NOT NULL,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
phone TEXT,
|
phone TEXT,
|
||||||
email TEXT,
|
email TEXT,
|
||||||
address TEXT,
|
address TEXT,
|
||||||
notes TEXT,
|
notes TEXT,
|
||||||
created_at INTEGER NOT NULL
|
created_at INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY (account_id) REFERENCES accounts(account_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS customers (
|
CREATE TABLE IF NOT EXISTS customers (
|
||||||
@@ -138,5 +141,20 @@ func Init(path string) (*sql.DB, error) {
|
|||||||
return nil, fmt.Errorf("failed to create schema: %w", err)
|
return nil, fmt.Errorf("failed to create schema: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := migrate(database); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to migrate: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return database, nil
|
return database, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func migrate(db *sql.DB) error {
|
||||||
|
_, err := db.Exec("ALTER TABLE clients ADD COLUMN account_id INTEGER")
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "duplicate column name") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,42 @@ func Signup(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Redirect(w, r, "/auth/login", http.StatusFound)
|
var accountID int64
|
||||||
|
err = DB.QueryRow("SELECT account_id FROM accounts WHERE email = ?", email).Scan(&accountID)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Failed to create account", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client := struct {
|
||||||
|
AccountID int64
|
||||||
|
Name string
|
||||||
|
CreatedAt int64
|
||||||
|
}{
|
||||||
|
AccountID: accountID,
|
||||||
|
Name: name,
|
||||||
|
CreatedAt: time.Now().Unix(),
|
||||||
|
}
|
||||||
|
_, err = DB.Exec(
|
||||||
|
"INSERT INTO clients (account_id, name, created_at) VALUES (?, ?, ?)",
|
||||||
|
client.AccountID, client.Name, client.CreatedAt,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Failed to create client", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionID := generateSessionID()
|
||||||
|
expires := time.Now().Add(24 * time.Hour).Unix()
|
||||||
|
|
||||||
|
_, err = DB.Exec("INSERT INTO sessions (session_id, account_id, expires) VALUES (?, ?, ?)", sessionID, accountID, expires)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Failed to create session", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
http.SetCookie(w, &http.Cookie{Name: "session", Value: sessionID, Path: "/"})
|
||||||
|
http.Redirect(w, r, "/", http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoginPage(w http.ResponseWriter, r *http.Request) {
|
func LoginPage(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -121,7 +156,7 @@ func Login(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
http.SetCookie(w, &http.Cookie{Name: "session", Value: sessionID, Path: "/"})
|
http.SetCookie(w, &http.Cookie{Name: "session", Value: sessionID, Path: "/"})
|
||||||
http.Redirect(w, r, "/clients", http.StatusFound)
|
http.Redirect(w, r, "/", http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Logout(w http.ResponseWriter, r *http.Request) {
|
func Logout(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -158,7 +193,67 @@ func getSession(r *http.Request) (int64, error) {
|
|||||||
return accountID, err
|
return accountID, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetAccountID(r *http.Request) (int64, error) {
|
||||||
|
return getSession(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requireAuth(w http.ResponseWriter, r *http.Request) (int64, bool) {
|
||||||
|
accountID, err := getSession(r)
|
||||||
|
if err != nil {
|
||||||
|
http.Redirect(w, r, "/auth/login", http.StatusFound)
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
return accountID, true
|
||||||
|
}
|
||||||
|
|
||||||
func SetupAuthHandlers(db *sql.DB) {
|
func SetupAuthHandlers(db *sql.DB) {
|
||||||
DB = db
|
DB = db
|
||||||
chi.RegisterMethod("GET")
|
chi.RegisterMethod("GET")
|
||||||
|
}
|
||||||
|
|
||||||
|
func AccountPage(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var name, email string
|
||||||
|
err := DB.QueryRow("SELECT name, email FROM accounts WHERE account_id = ?", accountID).Scan(&name, &email)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Account not found", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "text/html")
|
||||||
|
w.Write([]byte(`<!DOCTYPE html><html><head><title>Account</title></head><body><h1>Account Settings</h1><form method="POST" action="/auth/account">
|
||||||
|
<p>Name: <input type="text" name="name" value="` + name + `"></p>
|
||||||
|
<p>Email: <input type="email" value="` + email + `" disabled></p>
|
||||||
|
<p>New Password: <input type="password" name="password" placeholder="Leave blank to keep current"></p>
|
||||||
|
<button type="submit">Update</button>
|
||||||
|
</form>
|
||||||
|
<a href="/">Back to Dashboard</a></body></html>`))
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateAccount(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.ParseForm()
|
||||||
|
name := r.FormValue("name")
|
||||||
|
password := r.FormValue("password")
|
||||||
|
|
||||||
|
if name != "" {
|
||||||
|
DB.Exec("UPDATE accounts SET name = ? WHERE account_id = ?", name, accountID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if password != "" {
|
||||||
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
|
if err == nil {
|
||||||
|
DB.Exec("UPDATE accounts SET password = ? WHERE account_id = ?", string(hashedPassword), accountID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
http.Redirect(w, r, "/auth/account", http.StatusFound)
|
||||||
}
|
}
|
||||||
@@ -11,13 +11,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ListClients(w http.ResponseWriter, r *http.Request) {
|
func ListClients(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
if limit == 0 {
|
if limit == 0 {
|
||||||
limit = 20
|
limit = 20
|
||||||
}
|
}
|
||||||
|
|
||||||
clients, err := db.ListClients(DB, limit, offset)
|
clients, err := db.ListClients(DB, accountID, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@@ -81,8 +86,14 @@ func ListClients(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateClient(w http.ResponseWriter, r *http.Request) {
|
func CreateClient(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
client := db.Client{
|
client := db.Client{
|
||||||
|
AccountID: accountID,
|
||||||
Name: r.FormValue("name"),
|
Name: r.FormValue("name"),
|
||||||
Phone: r.FormValue("phone"),
|
Phone: r.FormValue("phone"),
|
||||||
Email: r.FormValue("email"),
|
Email: r.FormValue("email"),
|
||||||
@@ -101,8 +112,13 @@ func CreateClient(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ViewClient(w http.ResponseWriter, r *http.Request) {
|
func ViewClient(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
client, err := db.GetClientByID(DB, id)
|
client, err := db.GetClientByID(DB, accountID, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Client not found", http.StatusNotFound)
|
http.Error(w, "Client not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
@@ -124,10 +140,16 @@ func ViewClient(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UpdateClient(w http.ResponseWriter, r *http.Request) {
|
func UpdateClient(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
client := db.Client{
|
client := db.Client{
|
||||||
ClientID: id,
|
ClientID: id,
|
||||||
|
AccountID: accountID,
|
||||||
Name: r.FormValue("name"),
|
Name: r.FormValue("name"),
|
||||||
Phone: r.FormValue("phone"),
|
Phone: r.FormValue("phone"),
|
||||||
Email: r.FormValue("email"),
|
Email: r.FormValue("email"),
|
||||||
@@ -144,8 +166,14 @@ func UpdateClient(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DeleteClient(w http.ResponseWriter, r *http.Request) {
|
func DeleteClient(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
if err := (&db.Client{}).Delete(DB, id); err != nil {
|
client := &db.Client{ClientID: id, AccountID: accountID}
|
||||||
|
if err := client.Delete(DB); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ListCustomers(w http.ResponseWriter, r *http.Request) {
|
func ListCustomers(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
clientID, _ := strconv.ParseInt(r.URL.Query().Get("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.URL.Query().Get("client_id"), 10, 64)
|
||||||
@@ -18,13 +23,13 @@ func ListCustomers(w http.ResponseWriter, r *http.Request) {
|
|||||||
limit = 20
|
limit = 20
|
||||||
}
|
}
|
||||||
|
|
||||||
customers, err := db.ListCustomers(DB, clientID, limit, offset)
|
customers, err := db.ListCustomers(DB, accountID, clientID, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
clients, err := db.ListClients(DB, limit, offset)
|
clients, err := db.ListClients(DB, accountID, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@@ -44,8 +49,21 @@ func ListCustomers(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateCustomer(w http.ResponseWriter, r *http.Request) {
|
func CreateCustomer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
||||||
|
|
||||||
|
var checkID int64
|
||||||
|
err := DB.QueryRow("SELECT client_id FROM clients WHERE client_id = ? AND account_id = ?", clientID, accountID).Scan(&checkID)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Invalid client", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
customer := db.Customer{
|
customer := db.Customer{
|
||||||
ClientID: clientID,
|
ClientID: clientID,
|
||||||
Name: r.FormValue("name"),
|
Name: r.FormValue("name"),
|
||||||
@@ -64,6 +82,11 @@ func CreateCustomer(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ViewCustomer(w http.ResponseWriter, r *http.Request) {
|
func ViewCustomer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
var c db.Customer
|
var c db.Customer
|
||||||
err := DB.QueryRow("SELECT customer_id, client_id, name, phone, birth_date, instagram, created_at FROM customers WHERE customer_id = ?", id).Scan(&c.CustomerID, &c.ClientID, &c.Name, &c.Phone, &c.BirthDate, &c.Instagram, &c.CreatedAt)
|
err := DB.QueryRow("SELECT customer_id, client_id, name, phone, birth_date, instagram, created_at FROM customers WHERE customer_id = ?", id).Scan(&c.CustomerID, &c.ClientID, &c.Name, &c.Phone, &c.BirthDate, &c.Instagram, &c.CreatedAt)
|
||||||
@@ -77,6 +100,11 @@ func ViewCustomer(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UpdateCustomer(w http.ResponseWriter, r *http.Request) {
|
func UpdateCustomer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
||||||
@@ -89,6 +117,11 @@ func UpdateCustomer(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DeleteCustomer(w http.ResponseWriter, r *http.Request) {
|
func DeleteCustomer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
DB.Exec("DELETE FROM customers WHERE customer_id = ?", id)
|
DB.Exec("DELETE FROM customers WHERE customer_id = ?", id)
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ListPayments(w http.ResponseWriter, r *http.Request) {
|
func ListPayments(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
clientID, _ := strconv.ParseInt(r.URL.Query().Get("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.URL.Query().Get("client_id"), 10, 64)
|
||||||
@@ -24,13 +29,13 @@ func ListPayments(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
clients, err := db.ListClients(DB, limit, offset)
|
clients, err := db.ListClients(DB, accountID, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
customers, err := db.ListCustomers(DB, clientID, limit, offset)
|
customers, err := db.ListCustomers(DB, accountID, clientID, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@@ -69,6 +74,11 @@ func ListPayments(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreatePayment(w http.ResponseWriter, r *http.Request) {
|
func CreatePayment(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
||||||
customerID, _ := strconv.ParseInt(r.FormValue("customer_id"), 10, 64)
|
customerID, _ := strconv.ParseInt(r.FormValue("customer_id"), 10, 64)
|
||||||
@@ -96,6 +106,11 @@ func CreatePayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ViewPayment(w http.ResponseWriter, r *http.Request) {
|
func ViewPayment(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(r.URL.Query().Get("id"), 10, 64)
|
id, _ := strconv.ParseInt(r.URL.Query().Get("id"), 10, 64)
|
||||||
var p db.Payment
|
var p db.Payment
|
||||||
var hasPaid int
|
var hasPaid int
|
||||||
@@ -111,6 +126,11 @@ func ViewPayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UpdatePayment(w http.ResponseWriter, r *http.Request) {
|
func UpdatePayment(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
||||||
@@ -126,6 +146,11 @@ func UpdatePayment(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DeletePayment(w http.ResponseWriter, r *http.Request) {
|
func DeletePayment(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(r.URL.Query().Get("id"), 10, 64)
|
id, _ := strconv.ParseInt(r.URL.Query().Get("id"), 10, 64)
|
||||||
DB.Exec("DELETE FROM payments WHERE payment_id = ?", id)
|
DB.Exec("DELETE FROM payments WHERE payment_id = ?", id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ListQuestions(w http.ResponseWriter, r *http.Request) {
|
func ListQuestions(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
clientID, _ := strconv.ParseInt(r.URL.Query().Get("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.URL.Query().Get("client_id"), 10, 64)
|
||||||
@@ -24,13 +29,13 @@ func ListQuestions(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
clients, err := db.ListClients(DB, limit, offset)
|
clients, err := db.ListClients(DB, accountID, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
customers, err := db.ListCustomers(DB, clientID, limit, offset)
|
customers, err := db.ListCustomers(DB, accountID, clientID, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@@ -65,6 +70,11 @@ func ListQuestions(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateQuestion(w http.ResponseWriter, r *http.Request) {
|
func CreateQuestion(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
||||||
customerID, _ := strconv.ParseInt(r.FormValue("customer_id"), 10, 64)
|
customerID, _ := strconv.ParseInt(r.FormValue("customer_id"), 10, 64)
|
||||||
@@ -86,6 +96,11 @@ func CreateQuestion(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ViewQuestion(w http.ResponseWriter, r *http.Request) {
|
func ViewQuestion(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
var q db.Question
|
var q db.Question
|
||||||
err := DB.QueryRow("SELECT question_id, client_id, customer_id, question, timestamp, status, created_at FROM questions WHERE question_id = ?", id).Scan(&q.QuestionID, &q.ClientID, &q.CustomerID, &q.Question, &q.Timestamp, &q.Status, &q.CreatedAt)
|
err := DB.QueryRow("SELECT question_id, client_id, customer_id, question, timestamp, status, created_at FROM questions WHERE question_id = ?", id).Scan(&q.QuestionID, &q.ClientID, &q.CustomerID, &q.Question, &q.Timestamp, &q.Status, &q.CreatedAt)
|
||||||
@@ -99,6 +114,11 @@ func ViewQuestion(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UpdateQuestion(w http.ResponseWriter, r *http.Request) {
|
func UpdateQuestion(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
||||||
@@ -112,11 +132,21 @@ func UpdateQuestion(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DeleteQuestion(w http.ResponseWriter, r *http.Request) {
|
func DeleteQuestion(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
DB.Exec("DELETE FROM questions WHERE question_id = ?", id)
|
DB.Exec("DELETE FROM questions WHERE question_id = ?", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListAnswers(w http.ResponseWriter, r *http.Request) {
|
func ListAnswers(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
questionID, _ := strconv.ParseInt(r.URL.Query().Get("question_id"), 10, 64)
|
questionID, _ := strconv.ParseInt(r.URL.Query().Get("question_id"), 10, 64)
|
||||||
@@ -124,7 +154,7 @@ func ListAnswers(w http.ResponseWriter, r *http.Request) {
|
|||||||
limit = 20
|
limit = 20
|
||||||
}
|
}
|
||||||
|
|
||||||
answers, err := db.ListAnswersWithDetails(DB, questionID, limit, offset)
|
answers, err := db.ListAnswersWithDetails(DB, accountID, questionID, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@@ -224,6 +254,11 @@ func ListAnswers(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateAnswer(w http.ResponseWriter, r *http.Request) {
|
func CreateAnswer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
questionID, _ := strconv.ParseInt(r.FormValue("question_id"), 10, 64)
|
questionID, _ := strconv.ParseInt(r.FormValue("question_id"), 10, 64)
|
||||||
|
|
||||||
@@ -234,6 +269,13 @@ func CreateAnswer(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var checkID int64
|
||||||
|
err = DB.QueryRow("SELECT client_id FROM clients WHERE client_id = ? AND account_id = ?", clientID, accountID).Scan(&checkID)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Invalid question", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
answer := db.Answer{
|
answer := db.Answer{
|
||||||
ClientID: clientID,
|
ClientID: clientID,
|
||||||
QuestionID: questionID,
|
QuestionID: questionID,
|
||||||
@@ -252,6 +294,11 @@ func CreateAnswer(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ViewAnswer(w http.ResponseWriter, r *http.Request) {
|
func ViewAnswer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
var a db.Answer
|
var a db.Answer
|
||||||
err := DB.QueryRow("SELECT answer_id, client_id, question_id, answer, timestamp, status, created_at FROM answers WHERE answer_id = ?", id).Scan(&a.AnswerID, &a.ClientID, &a.QuestionID, &a.Answer, &a.Timestamp, &a.Status, &a.CreatedAt)
|
err := DB.QueryRow("SELECT answer_id, client_id, question_id, answer, timestamp, status, created_at FROM answers WHERE answer_id = ?", id).Scan(&a.AnswerID, &a.ClientID, &a.QuestionID, &a.Answer, &a.Timestamp, &a.Status, &a.CreatedAt)
|
||||||
@@ -265,6 +312,11 @@ func ViewAnswer(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UpdateAnswer(w http.ResponseWriter, r *http.Request) {
|
func UpdateAnswer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
questionID, _ := strconv.ParseInt(r.FormValue("question_id"), 10, 64)
|
questionID, _ := strconv.ParseInt(r.FormValue("question_id"), 10, 64)
|
||||||
@@ -277,6 +329,11 @@ func UpdateAnswer(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DeleteAnswer(w http.ResponseWriter, r *http.Request) {
|
func DeleteAnswer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
DB.Exec("DELETE FROM answers WHERE answer_id = ?", id)
|
DB.Exec("DELETE FROM answers WHERE answer_id = ?", id)
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ListSchedules(w http.ResponseWriter, r *http.Request) {
|
func ListSchedules(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
clientID, _ := strconv.ParseInt(r.URL.Query().Get("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.URL.Query().Get("client_id"), 10, 64)
|
||||||
@@ -25,19 +30,19 @@ func ListSchedules(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
clients, err := db.ListClients(DB, limit, offset)
|
clients, err := db.ListClients(DB, accountID, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
customers, err := db.ListCustomers(DB, clientID, limit, offset)
|
customers, err := db.ListCustomers(DB, accountID, clientID, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
services, err := db.ListServices(DB, clientID, limit, offset)
|
services, err := db.ListServices(DB, accountID, clientID, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@@ -81,6 +86,11 @@ func ListSchedules(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateSchedule(w http.ResponseWriter, r *http.Request) {
|
func CreateSchedule(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
||||||
customerID, _ := strconv.ParseInt(r.FormValue("customer_id"), 10, 64)
|
customerID, _ := strconv.ParseInt(r.FormValue("customer_id"), 10, 64)
|
||||||
@@ -104,6 +114,11 @@ func CreateSchedule(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ViewSchedule(w http.ResponseWriter, r *http.Request) {
|
func ViewSchedule(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
var sch db.Schedule
|
var sch db.Schedule
|
||||||
err := DB.QueryRow("SELECT schedule_id, client_id, customer_id, service_id, plan_date, time, status, created_at FROM scheduling WHERE schedule_id = ?", id).Scan(&sch.ScheduleID, &sch.ClientID, &sch.CustomerID, &sch.ServiceID, &sch.PlanDate, &sch.Time, &sch.Status, &sch.CreatedAt)
|
err := DB.QueryRow("SELECT schedule_id, client_id, customer_id, service_id, plan_date, time, status, created_at FROM scheduling WHERE schedule_id = ?", id).Scan(&sch.ScheduleID, &sch.ClientID, &sch.CustomerID, &sch.ServiceID, &sch.PlanDate, &sch.Time, &sch.Status, &sch.CreatedAt)
|
||||||
@@ -117,6 +132,11 @@ func ViewSchedule(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UpdateSchedule(w http.ResponseWriter, r *http.Request) {
|
func UpdateSchedule(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
||||||
@@ -131,6 +151,11 @@ func UpdateSchedule(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DeleteSchedule(w http.ResponseWriter, r *http.Request) {
|
func DeleteSchedule(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
DB.Exec("DELETE FROM scheduling WHERE schedule_id = ?", id)
|
DB.Exec("DELETE FROM scheduling WHERE schedule_id = ?", id)
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ListServices(w http.ResponseWriter, r *http.Request) {
|
func ListServices(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||||
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||||
clientID, _ := strconv.ParseInt(r.URL.Query().Get("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.URL.Query().Get("client_id"), 10, 64)
|
||||||
@@ -18,13 +23,13 @@ func ListServices(w http.ResponseWriter, r *http.Request) {
|
|||||||
limit = 20
|
limit = 20
|
||||||
}
|
}
|
||||||
|
|
||||||
services, err := db.ListServices(DB, clientID, limit, offset)
|
services, err := db.ListServices(DB, accountID, clientID, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
clients, err := db.ListClients(DB, limit, offset)
|
clients, err := db.ListClients(DB, accountID, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@@ -44,8 +49,21 @@ func ListServices(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateService(w http.ResponseWriter, r *http.Request) {
|
func CreateService(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accountID, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
||||||
|
|
||||||
|
var checkID int64
|
||||||
|
err := DB.QueryRow("SELECT client_id FROM clients WHERE client_id = ? AND account_id = ?", clientID, accountID).Scan(&checkID)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Invalid client", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
price, _ := strconv.ParseFloat(r.FormValue("price"), 64)
|
price, _ := strconv.ParseFloat(r.FormValue("price"), 64)
|
||||||
service := db.Service{
|
service := db.Service{
|
||||||
ClientID: clientID,
|
ClientID: clientID,
|
||||||
@@ -65,6 +83,11 @@ func CreateService(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ViewService(w http.ResponseWriter, r *http.Request) {
|
func ViewService(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
var s db.Service
|
var s db.Service
|
||||||
err := DB.QueryRow("SELECT service_id, client_id, name, price, description, duration, created_at FROM services WHERE service_id = ?", id).Scan(&s.ServiceID, &s.ClientID, &s.Name, &s.Price, &s.Description, &s.Duration, &s.CreatedAt)
|
err := DB.QueryRow("SELECT service_id, client_id, name, price, description, duration, created_at FROM services WHERE service_id = ?", id).Scan(&s.ServiceID, &s.ClientID, &s.Name, &s.Price, &s.Description, &s.Duration, &s.CreatedAt)
|
||||||
@@ -78,6 +101,11 @@ func ViewService(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UpdateService(w http.ResponseWriter, r *http.Request) {
|
func UpdateService(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
clientID, _ := strconv.ParseInt(r.FormValue("client_id"), 10, 64)
|
||||||
@@ -91,6 +119,11 @@ func UpdateService(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DeleteService(w http.ResponseWriter, r *http.Request) {
|
func DeleteService(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, ok := requireAuth(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
id, _ := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||||
DB.Exec("DELETE FROM services WHERE service_id = ?", id)
|
DB.Exec("DELETE FROM services WHERE service_id = ?", id)
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"go-crm/internal/db"
|
"go-crm/internal/db"
|
||||||
"go-crm/internal/handlers"
|
"go-crm/internal/handlers"
|
||||||
@@ -32,15 +31,14 @@ func main() {
|
|||||||
templates.Init()
|
templates.Init()
|
||||||
|
|
||||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
homeTmpl := templates.Get("home.html")
|
_, err := handlers.GetAccountID(r)
|
||||||
layoutTmpl := templates.Layout("Home", "")
|
if err != nil {
|
||||||
if homeTmpl != nil && layoutTmpl != nil {
|
http.Redirect(w, r, "/auth/login", http.StatusFound)
|
||||||
buf := &strings.Builder{}
|
return
|
||||||
homeTmpl.Execute(buf, map[string]string{"Title": "Home"})
|
|
||||||
layoutTmpl.Execute(w, map[string]string{"Title": "Home", "Content": buf.String()})
|
|
||||||
} else {
|
|
||||||
w.Write([]byte(`<!DOCTYPE html><html><head><title>Home</title></head><body><h1>Welcome to CRM</h1><nav><a href="/clients">Clients</a> | <a href="/customers">Customers</a> | <a href="/services">Services</a> | <a href="/questions">Questions</a> | <a href="/answers">Answers</a></nav></body></html>`))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "text/html")
|
||||||
|
w.Write([]byte(`<!DOCTYPE html><html><head><title>Dashboard</title></head><body><h1>Welcome to CRM</h1><nav><a href="/clients">Clients</a> | <a href="/customers">Customers</a> | <a href="/services">Services</a> | <a href="/scheduling">Scheduling</a> | <a href="/payments">Payments</a> | <a href="/questions">Questions</a> | <a href="/answers">Answers</a> | <a href="/auth/account">Account</a> | <form method="POST" action="/auth/logout" style="display:inline"><button type="submit">Logout</button></form></nav></body></html>`))
|
||||||
})
|
})
|
||||||
|
|
||||||
r.Route("/auth", func(r chi.Router) {
|
r.Route("/auth", func(r chi.Router) {
|
||||||
@@ -49,6 +47,8 @@ func main() {
|
|||||||
r.Get("/login", handlers.LoginPage)
|
r.Get("/login", handlers.LoginPage)
|
||||||
r.Post("/login", handlers.Login)
|
r.Post("/login", handlers.Login)
|
||||||
r.Post("/logout", handlers.Logout)
|
r.Post("/logout", handlers.Logout)
|
||||||
|
r.Get("/account", handlers.AccountPage)
|
||||||
|
r.Post("/account", handlers.UpdateAccount)
|
||||||
})
|
})
|
||||||
|
|
||||||
r.Route("/clients", func(r chi.Router) {
|
r.Route("/clients", func(r chi.Router) {
|
||||||
|
|||||||
@@ -1 +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 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 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
|
||||||
Binary file not shown.
Reference in New Issue
Block a user