Files
api_tmpl/internal/worker/task_send_verify_email.go
FernandoJVideira c4ee0ce4dc chore: rename simple_bank to api_tmpl and clean up for template use
Rename the module, proto service, and all identifiers from simple_bank/
SimpleBank to api_tmpl/ApiTmpl, and regenerate the gRPC/gateway/swagger/
mock code accordingly.

- Scrub real secrets (SMTP password, auth token secret) from api.env/
  api_test.env, untrack them, and add api.env.example/api_test.env.example
- Remove committed build artifacts (tmp/main, tmp/build-errors.log,
  dbml-error.log) and gitignore them going forward
- Fix Dockerfile paths (build target, migrations copy) that referenced a
  stale project layout
- Rewrite README to match the actual cmd/ + internal/ structure and add a
  "using this as a template" section
2026-08-25 03:02:37 +01:00

82 lines
2.5 KiB
Go

package worker
import (
"context"
"encoding/json"
"errors"
"fmt"
db "github.com/FernandoJVideira/api_tmpl/internal/db/sqlc"
"github.com/FernandoJVideira/api_tmpl/internal/mailer"
"github.com/FernandoJVideira/api_tmpl/pkg/testutil"
"github.com/hibiken/asynq"
"github.com/rs/zerolog/log"
)
const TaskSendVerifyEmail = "task:send_verify_email"
type SendVerifyEmailPayload struct {
Username string `json:"username"`
}
func (r *RedisTaskDistributor) DestributeTaskSendVerifyEmail(ctx context.Context, payload *SendVerifyEmailPayload, opts ...asynq.Option) error {
jsonPayload, err := json.Marshal(payload)
if err != nil {
return fmt.Errorf("failed to marshal SendVerifyEmailPayload: %w", err)
}
task := asynq.NewTask(TaskSendVerifyEmail, jsonPayload, opts...)
info, err := r.client.EnqueueContext(ctx, task)
if err != nil {
return fmt.Errorf("failed to enqueue task %s: %w", TaskSendVerifyEmail, err)
}
log.Info().Str("type", task.Type()).Bytes("payload", task.Payload()).Str("queue", info.Queue).Int("max_retries", info.MaxRetry).Msgf("enqueued task")
return nil
}
func (r *RedisTaskProcessor) ProcessTaskSendVerifyEmail(ctx context.Context, task *asynq.Task) error {
var payload SendVerifyEmailPayload
if err := json.Unmarshal(task.Payload(), &payload); err != nil {
return fmt.Errorf("failed to unmarshal payload: %w", asynq.SkipRetry)
}
usr, err := r.store.GetUser(ctx, payload.Username)
if err != nil {
if errors.Is(err, db.ErrRecordNotFound) {
return fmt.Errorf("user %s not found: %w", payload.Username, asynq.SkipRetry)
}
return fmt.Errorf("failed to get user %s: %w", payload.Username, err)
}
verifyEmail, err := r.store.CreateVerifyEmail(ctx, db.CreateVerifyEmailParams{
Username: usr.Username,
Email: usr.Email,
SecretCode: testutil.RandomString(32),
})
if err != nil {
return fmt.Errorf("failed to create verify email for user %s: %w", usr.Username, err)
}
vars := struct {
ServiceName string
Username string
ActivationURL string
}{
ServiceName: r.config.ServiceName,
Username: usr.Username,
ActivationURL: fmt.Sprintf("%s/verify_email?id=%d&code=%s", r.config.FrontendURL, verifyEmail.ID, verifyEmail.SecretCode),
}
to := []string{usr.Email}
err = r.mailer.Send(mailer.UserWelcomeTemplate, vars, to, nil, nil, nil)
if err != nil {
return fmt.Errorf("failed to send verify email to user %s: %w", usr.Username, err)
}
log.Info().Str("type", task.Type()).Bytes("payload", task.Payload()).Str("email", usr.Email).Msg("sent verify email to user")
return nil
}