- POST /api/v1/auth/register with mandatory consents
- POST /api/v1/auth/login
- GET /api/v1/me (protected)
- GET /api/v1/legal/{terms,privacy,disclaimer}
- Migrations for users, consent_log, audit_log
- bcrypt + JWT (access + refresh)
- Docker Compose stack
57 lines
1.2 KiB
Go
57 lines
1.2 KiB
Go
package consent
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
type DocType string
|
|
|
|
const (
|
|
DocTerms DocType = "terms"
|
|
DocPrivacy DocType = "privacy"
|
|
DocDisclaimer DocType = "disclaimer"
|
|
DocAdult DocType = "adult"
|
|
)
|
|
|
|
type Consent struct {
|
|
ID int64
|
|
UserID uuid.UUID
|
|
DocType DocType
|
|
DocVersion string
|
|
IP string
|
|
UserAgent string
|
|
AcceptedAt time.Time
|
|
}
|
|
|
|
type Repo struct {
|
|
pool *pgxpool.Pool
|
|
}
|
|
|
|
func NewRepo(pool *pgxpool.Pool) *Repo {
|
|
return &Repo{pool: pool}
|
|
}
|
|
|
|
func (r *Repo) Record(ctx context.Context, c *Consent) error {
|
|
return r.pool.QueryRow(ctx, `
|
|
INSERT INTO consent_log (user_id, doc_type, doc_version, ip, user_agent)
|
|
VALUES ($1, $2, $3, NULLIF($4, '')::inet, $5)
|
|
RETURNING id, accepted_at`,
|
|
c.UserID, c.DocType, c.DocVersion, c.IP, c.UserAgent,
|
|
).Scan(&c.ID, &c.AcceptedAt)
|
|
}
|
|
|
|
func (r *Repo) HasAccepted(ctx context.Context, userID uuid.UUID, docType DocType, version string) (bool, error) {
|
|
var exists bool
|
|
err := r.pool.QueryRow(ctx, `
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM consent_log
|
|
WHERE user_id=$1 AND doc_type=$2 AND doc_version=$3
|
|
)`, userID, docType, version,
|
|
).Scan(&exists)
|
|
return exists, err
|
|
}
|