adicionado comentários
This commit is contained in:
parent
e8ca410b94
commit
e796b29e1d
8 changed files with 875 additions and 13 deletions
|
|
@ -22,6 +22,192 @@ func NewStore(pool *pgxpool.Pool) *Store { return &Store{pool: pool} }
|
|||
|
||||
func (s *Store) poolRef() *pgxpool.Pool { return s.pool }
|
||||
|
||||
// ------------------------------
|
||||
// Painel: comentários e status de análise
|
||||
// ------------------------------
|
||||
|
||||
type StatusAnalisePainel = contratos.StatusAnalisePainel
|
||||
|
||||
const (
|
||||
StatusAnalisePendente = contratos.StatusAnalisePendente
|
||||
StatusAnaliseConcluida = contratos.StatusAnaliseConcluida
|
||||
)
|
||||
|
||||
type ComentarioPainel = contratos.ComentarioPainel
|
||||
|
||||
// GetStatusAnalise retorna o status do painel para uma resposta.
|
||||
// Se não existir registro, considera "pendente".
|
||||
func (s *Store) GetStatusAnalise(ctx context.Context, produto, respostaID string) (StatusAnalisePainel, error) {
|
||||
var status string
|
||||
err := s.pool.QueryRow(ctx, `
|
||||
SELECT status
|
||||
FROM painel_resposta_status
|
||||
WHERE produto=$1 AND resposta_id=$2
|
||||
`, produto, respostaID).Scan(&status)
|
||||
if err == pgx.ErrNoRows {
|
||||
return StatusAnalisePendente, nil
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
switch status {
|
||||
case string(StatusAnalisePendente):
|
||||
return StatusAnalisePendente, nil
|
||||
case string(StatusAnaliseConcluida):
|
||||
return StatusAnaliseConcluida, nil
|
||||
default:
|
||||
// fallback defensivo
|
||||
return StatusAnalisePendente, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) SetStatusAnalise(ctx context.Context, produto, respostaID string, status StatusAnalisePainel) error {
|
||||
if status != StatusAnalisePendente && status != StatusAnaliseConcluida {
|
||||
return fmt.Errorf("status invalido")
|
||||
}
|
||||
concluidaEm := (*time.Time)(nil)
|
||||
if status == StatusAnaliseConcluida {
|
||||
agora := time.Now()
|
||||
concluidaEm = &agora
|
||||
}
|
||||
|
||||
_, err := s.pool.Exec(ctx, `
|
||||
INSERT INTO painel_resposta_status (produto, resposta_id, status, concluida_em, atualizado_em)
|
||||
VALUES ($1,$2,$3,$4, now())
|
||||
ON CONFLICT (produto, resposta_id)
|
||||
DO UPDATE SET
|
||||
status=EXCLUDED.status,
|
||||
concluida_em=EXCLUDED.concluida_em,
|
||||
atualizado_em=now()
|
||||
`, produto, respostaID, string(status), concluidaEmOrNil(concluidaEm))
|
||||
return err
|
||||
}
|
||||
|
||||
func concluidaEmOrNil(t *time.Time) any {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return *t
|
||||
}
|
||||
|
||||
func (s *Store) ListarComentariosPainel(ctx context.Context, produto, respostaID string) ([]ComentarioPainel, error) {
|
||||
rows, err := s.pool.Query(ctx, `
|
||||
SELECT id::text, pessoa_nome, sessao_id::text, comentario, criado_em, atualizado_em
|
||||
FROM painel_resposta_comentario
|
||||
WHERE produto=$1 AND resposta_id=$2
|
||||
ORDER BY criado_em ASC
|
||||
`, produto, respostaID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
out := []ComentarioPainel{}
|
||||
for rows.Next() {
|
||||
var c ComentarioPainel
|
||||
if err := rows.Scan(&c.ID, &c.PessoaNome, &c.SessaoID, &c.Comentario, &c.CriadoEm, &c.AtualizadoEm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, c)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func (s *Store) CriarComentarioPainel(ctx context.Context, produto, respostaID, pessoaNome, sessaoID, comentario string) error {
|
||||
_, err := s.pool.Exec(ctx, `
|
||||
INSERT INTO painel_resposta_comentario (produto, resposta_id, pessoa_nome, sessao_id, comentario, criado_em, atualizado_em)
|
||||
VALUES ($1,$2,$3,$4::uuid,$5, now(), now())
|
||||
`, produto, respostaID, pessoaNome, sessaoID, comentario)
|
||||
return err
|
||||
}
|
||||
|
||||
// EditarComentarioPainel edita um comentário, mas somente se pertencer à mesma sessão.
|
||||
func (s *Store) EditarComentarioPainel(ctx context.Context, comentarioID, sessaoID, comentario string) (bool, error) {
|
||||
tag, err := s.pool.Exec(ctx, `
|
||||
UPDATE painel_resposta_comentario
|
||||
SET comentario=$3, atualizado_em=now()
|
||||
WHERE id=$1::uuid AND sessao_id=$2::uuid
|
||||
`, comentarioID, sessaoID, comentario)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return tag.RowsAffected() > 0, nil
|
||||
}
|
||||
|
||||
// DeletarComentarioPainel remove um comentário, mas somente se pertencer à mesma sessão.
|
||||
func (s *Store) DeletarComentarioPainel(ctx context.Context, comentarioID, sessaoID string) (bool, error) {
|
||||
tag, err := s.pool.Exec(ctx, `
|
||||
DELETE FROM painel_resposta_comentario
|
||||
WHERE id=$1::uuid AND sessao_id=$2::uuid
|
||||
`, comentarioID, sessaoID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return tag.RowsAffected() > 0, nil
|
||||
}
|
||||
|
||||
// GetStatusAnaliseBatch retorna um mapa resposta_id -> status.
|
||||
// Se não existir registro para um id, ele simplesmente não aparece no mapa.
|
||||
func (s *Store) GetStatusAnaliseBatch(ctx context.Context, produto string, respostaIDs []string) (map[string]StatusAnalisePainel, error) {
|
||||
out := map[string]StatusAnalisePainel{}
|
||||
if len(respostaIDs) == 0 {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
rows, err := s.pool.Query(ctx, `
|
||||
SELECT resposta_id, status
|
||||
FROM painel_resposta_status
|
||||
WHERE produto=$1 AND resposta_id = ANY($2::text[])
|
||||
`, produto, respostaIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var id, st string
|
||||
if err := rows.Scan(&id, &st); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch st {
|
||||
case string(StatusAnaliseConcluida):
|
||||
out[id] = StatusAnaliseConcluida
|
||||
default:
|
||||
out[id] = StatusAnalisePendente
|
||||
}
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
// ListarComentariosPainelBatch retorna um mapa resposta_id -> comentários.
|
||||
func (s *Store) ListarComentariosPainelBatch(ctx context.Context, produto string, respostaIDs []string) (map[string][]ComentarioPainel, error) {
|
||||
out := map[string][]ComentarioPainel{}
|
||||
if len(respostaIDs) == 0 {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
rows, err := s.pool.Query(ctx, `
|
||||
SELECT resposta_id, id::text, pessoa_nome, sessao_id::text, comentario, criado_em, atualizado_em
|
||||
FROM painel_resposta_comentario
|
||||
WHERE produto=$1 AND resposta_id = ANY($2::text[])
|
||||
ORDER BY resposta_id ASC, criado_em ASC
|
||||
`, produto, respostaIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var respostaID string
|
||||
var c ComentarioPainel
|
||||
if err := rows.Scan(&respostaID, &c.ID, &c.PessoaNome, &c.SessaoID, &c.Comentario, &c.CriadoEm, &c.AtualizadoEm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out[respostaID] = append(out[respostaID], c)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func ipReal(r *http.Request) string {
|
||||
// IP real do cliente.
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue