114 lines
3.7 KiB
Go
114 lines
3.7 KiB
Go
package jitsi
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"log/slog"
|
|
"time"
|
|
)
|
|
|
|
type Queriable interface {
|
|
ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
|
|
PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
|
|
QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
|
|
QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
|
|
}
|
|
|
|
type Repository struct {
|
|
Db *sql.DB
|
|
q Queriable
|
|
}
|
|
|
|
func NewRepository(db *sql.DB) (*Repository, error) {
|
|
return &Repository{Db: db, q: db}, nil
|
|
}
|
|
|
|
func (r *Repository) WithTx(tx *sql.Tx) *Repository {
|
|
return &Repository{Db: r.Db, q: tx}
|
|
}
|
|
|
|
func (r *Repository) RecordJoin(ctx context.Context, userId int64, room string, at time.Time) error {
|
|
query := "INSERT INTO jitsi_room_history(user_id, room_name, last_joined_at) VALUES(?, ?, ?) ON CONFLICT(user_id, room_name) DO UPDATE SET last_joined_at = excluded.last_joined_at"
|
|
_, err := r.q.ExecContext(ctx, query, userId, room, at.UTC().Format(time.RFC3339))
|
|
if err != nil {
|
|
slog.Error("record room join", slog.String("op", "repo.RecordJoin"), slog.Int64("user_id", userId), slog.String("room", room), slog.Any("error", err))
|
|
return ErrInternal
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *Repository) List(ctx context.Context, userId int64, limit, offset int64) ([]*RoomHistory, error) {
|
|
query := "SELECT user_id, room_name, last_joined_at FROM jitsi_room_history WHERE user_id = ? ORDER BY last_joined_at DESC"
|
|
args := []any{userId}
|
|
|
|
if limit > 0 {
|
|
query += " LIMIT ? OFFSET ?"
|
|
args = append(args, limit, offset)
|
|
}
|
|
|
|
rows, err := r.q.QueryContext(ctx, query, args...)
|
|
if err != nil {
|
|
slog.Error("list room history", slog.String("op", "repo.List"), slog.Int64("user_id", userId), slog.Any("error", err))
|
|
return nil, ErrInternal
|
|
}
|
|
defer rows.Close()
|
|
|
|
var history []*RoomHistory
|
|
for rows.Next() {
|
|
entry := &RoomHistory{}
|
|
var lastJoinedAt string
|
|
err := rows.Scan(&entry.UserId, &entry.RoomName, &lastJoinedAt)
|
|
if err != nil {
|
|
slog.Error("scan room history", slog.String("op", "repo.List"), slog.Int64("user_id", userId), slog.Any("error", err))
|
|
return nil, ErrInternal
|
|
}
|
|
|
|
parsed, err := time.Parse(time.RFC3339, lastJoinedAt)
|
|
if err != nil {
|
|
slog.Error("parse last_joined_at", slog.String("op", "repo.List"), slog.Int64("user_id", userId), slog.String("room", entry.RoomName), slog.Any("error", err))
|
|
return nil, ErrInternal
|
|
}
|
|
entry.LastJoinedAt = parsed
|
|
|
|
history = append(history, entry)
|
|
}
|
|
|
|
err = rows.Err()
|
|
if err != nil {
|
|
slog.Error("iterate room history", slog.String("op", "repo.List"), slog.Int64("user_id", userId), slog.Any("error", err))
|
|
return nil, ErrInternal
|
|
}
|
|
|
|
return history, nil
|
|
}
|
|
|
|
func (r *Repository) DeleteRoom(ctx context.Context, userId int64, room string) error {
|
|
query := "DELETE FROM jitsi_room_history WHERE user_id = ? AND room_name = ?"
|
|
res, err := r.q.ExecContext(ctx, query, userId, room)
|
|
if err != nil {
|
|
slog.Error("delete room", slog.String("op", "repo.DeleteRoom"), slog.Int64("user_id", userId), slog.String("room", room), slog.Any("error", err))
|
|
return ErrInternal
|
|
}
|
|
|
|
affected, err := res.RowsAffected()
|
|
if err != nil {
|
|
slog.Error("rows affected", slog.String("op", "repo.DeleteRoom"), slog.Int64("user_id", userId), slog.String("room", room), slog.Any("error", err))
|
|
return ErrInternal
|
|
}
|
|
if affected == 0 {
|
|
return ErrNotFound
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *Repository) DeleteAll(ctx context.Context, userId int64) error {
|
|
query := "DELETE FROM jitsi_room_history WHERE user_id = ?"
|
|
_, err := r.q.ExecContext(ctx, query, userId)
|
|
if err != nil {
|
|
slog.Error("delete all rooms", slog.String("op", "repo.DeleteAll"), slog.Int64("user_id", userId), slog.Any("error", err))
|
|
return ErrInternal
|
|
}
|
|
return nil
|
|
}
|