mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-26 21:47:20 +00:00
a224a1a195
Record successful response writes, scheduled generation, file saves and SMTP outcomes in a durable content-free tally. Distinct active days include manual exports, while saved-schedule periods deduplicate retries and monthly reuse. Publish bounded scalars through the existing opt-out-controlled heartbeat and report missing coverage explicitly. Preserve pricing and customer entitlements.
81 lines
2.8 KiB
Go
81 lines
2.8 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/config"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/mock"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
type reportingActivityRecorder interface {
|
|
RecordReportingActivity(config.ReportingActivityEvent) error
|
|
}
|
|
|
|
func (h *ReportingHandlers) recordReportingActivity(event config.ReportingActivityEvent) {
|
|
if h == nil || mock.IsMockEnabled() {
|
|
return
|
|
}
|
|
recorder, ok := h.settingsStore.(reportingActivityRecorder)
|
|
if !ok {
|
|
return
|
|
}
|
|
if err := recorder.RecordReportingActivity(event); err != nil {
|
|
// No report, scope, recipient, schedule or error content enters this log.
|
|
log.Debug().Msg("Unable to retain aggregate reporting activity")
|
|
}
|
|
}
|
|
|
|
func (h *ReportingHandlers) recordReportingDownload(r *http.Request, kind string, count int, err error, expected int) {
|
|
if r == nil || r.Method == http.MethodHead || r.Context().Err() != nil || err != nil || count != expected {
|
|
return
|
|
}
|
|
h.recordReportingActivity(config.ReportingActivityEvent{At: time.Now().UTC(), Kind: kind, Event: "generated"})
|
|
}
|
|
|
|
func reportingActivityDigest(value string) string {
|
|
sum := sha256.Sum256([]byte(value))
|
|
return hex.EncodeToString(sum[:])
|
|
}
|
|
|
|
func reportingActivityPeriod(schedule config.ReportSchedule, start, end time.Time, now time.Time) string {
|
|
if start.IsZero() || end.IsZero() {
|
|
anchor := now
|
|
if schedule.RunWindowEnd != nil {
|
|
anchor = *schedule.RunWindowEnd
|
|
}
|
|
var err error
|
|
start, end, err = reportScheduleWindow(schedule, anchor, schedule.RunManual)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
}
|
|
location, err := reportScheduleLocation(schedule.Cadence.Timezone)
|
|
if err != nil || !end.After(start) {
|
|
return ""
|
|
}
|
|
// Day boundaries describe the reporting window. A retry or same-day rerun
|
|
// cannot become repeat use merely because its clock time changed.
|
|
return reportingActivityDigest(start.In(location).Format(time.DateOnly) + "\x00" + end.In(location).Format(time.DateOnly))
|
|
}
|
|
|
|
func (h *ReportingHandlers) recordReportingSuccessfulPeriod(ctx context.Context, schedule config.ReportSchedule, period string, at time.Time) {
|
|
if schedule.ID == "" || period == "" || schedule.LastRunStatus != config.ReportScheduleLastRunOK {
|
|
return
|
|
}
|
|
key := reportingActivityDigest(GetOrgID(ctx) + "\x00" + schedule.Kind + "\x00" + schedule.ID)
|
|
h.recordReportingActivity(config.ReportingActivityEvent{At: at, Kind: schedule.Kind, Event: "successful_period", ScheduleKey: key, PeriodKey: period})
|
|
}
|
|
|
|
func (h *ReportingHandlers) recordReportingDeliveryFailure(kind string, status string, at time.Time) {
|
|
event := "delivery_failed"
|
|
if status == "unconfirmed" {
|
|
event = "delivery_unconfirmed"
|
|
}
|
|
h.recordReportingActivity(config.ReportingActivityEvent{At: at, Kind: kind, Event: event})
|
|
}
|