Files
imap-copier/internal/store/accounts.go
T
vasyansk b88f88c1a3 feat: delete task/account, edit endpoint, richer event log
- store: DeleteAccount, DeleteTask, UpdateEndpoint (+ cascade/update tests)
- httpapi: DELETE /tasks/{id}, DELETE /tasks/{id}/accounts/{accountId},
  PUT /endpoints/{id}; delete guarded with 409 while task running
- orchestrator: enrich WS events with login/host/port/error (test + run + errors)
- web: delete buttons (task, account) with confirm, endpoint edit form,
  human-readable event log (source/dest, host:port, error text)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
2026-07-02 09:23:14 +07:00

81 lines
2.4 KiB
Go

package store
import (
"context"
"fmt"
)
type Account struct {
ID int64
TaskID int64
SrcLogin string
SrcPassEnc string
DstLogin string
DstPassEnc string
TestSrcStatus string
TestDstStatus string
Status string
Copied int64
Skipped int64
Errors int64
}
func (s *Store) CreateAccount(ctx context.Context, a Account) (int64, error) {
var id int64
err := s.Pool.QueryRow(ctx,
`INSERT INTO accounts (task_id, src_login, src_pass_enc, dst_login, dst_pass_enc)
VALUES ($1,$2,$3,$4,$5) RETURNING id`,
a.TaskID, a.SrcLogin, a.SrcPassEnc, a.DstLogin, a.DstPassEnc).Scan(&id)
return id, err
}
// DeleteAccount removes one account (and its migrated_messages via ON DELETE CASCADE).
func (s *Store) DeleteAccount(ctx context.Context, id int64) error {
_, err := s.Pool.Exec(ctx, `DELETE FROM accounts WHERE id=$1`, id)
return err
}
func (s *Store) ListAccountsByTask(ctx context.Context, taskID int64) ([]Account, error) {
rows, err := s.Pool.Query(ctx,
`SELECT id, task_id, src_login, src_pass_enc, dst_login, dst_pass_enc,
test_src_status, test_dst_status, status, copied_count, skipped_count, error_count
FROM accounts WHERE task_id=$1 ORDER BY id`, taskID)
if err != nil {
return nil, err
}
defer rows.Close()
out := []Account{}
for rows.Next() {
var a Account
if err := rows.Scan(&a.ID, &a.TaskID, &a.SrcLogin, &a.SrcPassEnc, &a.DstLogin, &a.DstPassEnc,
&a.TestSrcStatus, &a.TestDstStatus, &a.Status, &a.Copied, &a.Skipped, &a.Errors); err != nil {
return nil, err
}
out = append(out, a)
}
return out, rows.Err()
}
// side = "src" | "dst"
func (s *Store) SetAccountTestStatus(ctx context.Context, id int64, side, status string) error {
col := "test_src_status"
if side == "dst" {
col = "test_dst_status"
}
_, err := s.Pool.Exec(ctx, fmt.Sprintf(`UPDATE accounts SET %s=$2 WHERE id=$1`, col), id, status)
return err
}
func (s *Store) SetAccountStatus(ctx context.Context, id int64, status string) error {
_, err := s.Pool.Exec(ctx, `UPDATE accounts SET status=$2 WHERE id=$1`, id, status)
return err
}
func (s *Store) IncAccountCounters(ctx context.Context, id, copied, skipped, errs int64) error {
_, err := s.Pool.Exec(ctx,
`UPDATE accounts SET copied_count=copied_count+$2,
skipped_count=skipped_count+$3, error_count=error_count+$4 WHERE id=$1`,
id, copied, skipped, errs)
return err
}