132 lines
3.7 KiB
Go
132 lines
3.7 KiB
Go
package database
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"5803025020/w04/internal/auth"
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
// Connect membuat koneksi ke PostgreSQL menggunakan env vars individual
|
|
func Connect() (*pgx.Conn, error) {
|
|
host := getEnvOrDefault("DB_HOST", "localhost")
|
|
port := getEnvOrDefault("DB_PORT", "5432")
|
|
user := os.Getenv("DB_USER")
|
|
password := os.Getenv("DB_PASSWORD")
|
|
dbname := os.Getenv("DB_NAME")
|
|
sslmode := getEnvOrDefault("DB_SSLMODE", "disable")
|
|
|
|
connStr := fmt.Sprintf(
|
|
"host=%s port=%s user=%s password=%s dbname=%s sslmode=%s",
|
|
host, port, user, password, dbname, sslmode,
|
|
)
|
|
|
|
conn, err := pgx.Connect(context.Background(), connStr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("unable to connect to database: %v", err)
|
|
}
|
|
return conn, nil
|
|
}
|
|
|
|
// CreateTables membuat tabel users, sessions, dan snippets jika belum ada
|
|
func CreateTables(conn *pgx.Conn) error {
|
|
queries := []string{
|
|
`CREATE TABLE IF NOT EXISTS users (
|
|
id TEXT PRIMARY KEY,
|
|
username TEXT UNIQUE NOT NULL,
|
|
password_hash TEXT NOT NULL
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS sessions (
|
|
token TEXT PRIMARY KEY,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS snippets (
|
|
id TEXT PRIMARY KEY,
|
|
title TEXT NOT NULL,
|
|
content TEXT NOT NULL,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE
|
|
)`,
|
|
}
|
|
|
|
for _, q := range queries {
|
|
_, err := conn.Exec(context.Background(), q)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create table: %v", err)
|
|
}
|
|
}
|
|
|
|
// Otomatis masukkan data sample 2 user & session
|
|
if err := SeedSampleData(conn); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Warning: failed to seed sample data: %v\n", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SeedSampleData memasukkan data sample 2 user dan session ke database dan mencetak infonya langsung ke konsol VS Code
|
|
func SeedSampleData(conn *pgx.Conn) error {
|
|
ctx := context.Background()
|
|
|
|
samples := []struct {
|
|
username string
|
|
password string
|
|
}{
|
|
{username: "Budianto", password: "password123"},
|
|
{username: "Megalodon", password: "password12345"},
|
|
{username: "Bruh", password: "password12345678"},
|
|
{username: "KiwKiw", password: "password12345678910"},
|
|
}
|
|
|
|
fmt.Println("✅ INSERT DATA SAMPLE KE DATABASE (lebih dari 2 USERS):")
|
|
|
|
for i, s := range samples {
|
|
userID := uuid.New().String()
|
|
hash, err := auth.HashPassword(s.password)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to hash password for %s: %w", s.username, err)
|
|
}
|
|
|
|
err = conn.QueryRow(ctx,
|
|
"INSERT INTO users (id, username, password_hash) VALUES ($1, $2, $3) ON CONFLICT (username) DO UPDATE SET password_hash = EXCLUDED.password_hash RETURNING id",
|
|
userID, s.username, hash,
|
|
).Scan(&userID)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to insert user %s: %w", s.username, err)
|
|
}
|
|
|
|
token, err := auth.GenerateToken()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to generate session token for %s: %w", s.username, err)
|
|
}
|
|
|
|
_, err = conn.Exec(ctx,
|
|
"INSERT INTO sessions (token, user_id, created_at) VALUES ($1, $2, $3)",
|
|
token, userID, time.Now(),
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to insert session for %s: %w", s.username, err)
|
|
}
|
|
|
|
fmt.Printf("\n--- [User %d: %s] ---\n", i+1, s.username)
|
|
fmt.Printf(" User ID : %s\n", userID)
|
|
fmt.Printf(" Username : %s\n", s.username)
|
|
fmt.Printf(" Password Plain: %s\n", s.password)
|
|
fmt.Printf(" Password Hash : %s\n", hash)
|
|
fmt.Printf(" Session Token : %s\n", token)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getEnvOrDefault(key, defaultVal string) string {
|
|
if val := os.Getenv(key); val != "" {
|
|
return val
|
|
}
|
|
return defaultVal
|
|
}
|