Restructure the monorepo into clear top-level directories: - backend/: Go module root (cmd, internal, pkg, configs, migrations, docs/swagger, scripts, tests, go.mod, Makefile, .air.toml) - deploy/: Docker (Dockerfile, docker-compose*), quickstart, fluentd - docs/: project documentation + reports/ (moved from repo root) - AGENTS.md: new AI coding-agent guide at repo root Update all references to the new layout: - Dockerfile: COPY backend/go.mod, COPY backend/ (context = repo root) - docker-compose files: context ../.., dockerfile deploy/docker/Dockerfile, env_file ../../.env, volume mounts ../../backend:/app - deploy/quickstart/compose.yaml: dockerfile deploy/docker/Dockerfile - CI: working-directory: backend for go commands, file deploy/docker/Dockerfile, coverage path backend/coverage.out, health_check backend/scripts/ - backend/Makefile: docker target uses -f ../deploy/docker/Dockerfile ../ - README: architecture tree, quickstart, config paths updated Move root stray scripts (rename_models.*, run_m11_tests.sh, verify_build.sh, gorm_bool_main.go) to backend/scripts/legacy/. All moves via git mv to preserve history. Build, vet, SQLite tests, and docker compose config verified.
130 lines
4.5 KiB
Go
130 lines
4.5 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/gochat/gochat/internal/model"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// ReportingEventRepo provides data access for ReportingEvent.
|
|
type ReportingEventRepo struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
type ReportingEventListFilter struct {
|
|
Since *time.Time
|
|
Until *time.Time
|
|
InboxID uint
|
|
UserID uint
|
|
Name string
|
|
Offset int
|
|
Limit int
|
|
}
|
|
|
|
func NewReportingEventRepo(db *gorm.DB) *ReportingEventRepo {
|
|
return &ReportingEventRepo{db: db}
|
|
}
|
|
|
|
func (r *ReportingEventRepo) DB() *gorm.DB {
|
|
if r == nil {
|
|
return nil
|
|
}
|
|
return r.db
|
|
}
|
|
|
|
func (r *ReportingEventRepo) Create(ctx context.Context, event *model.ReportingEvent) error {
|
|
return r.db.WithContext(ctx).Create(event).Error
|
|
}
|
|
|
|
func (r *ReportingEventRepo) FindByAccountID(ctx context.Context, accountID uint, since, until time.Time) ([]model.ReportingEvent, error) {
|
|
var events []model.ReportingEvent
|
|
err := r.db.WithContext(ctx).
|
|
Where("account_id = ? AND created_at >= ? AND created_at <= ?", accountID, since, until).
|
|
Find(&events).Error
|
|
return events, err
|
|
}
|
|
|
|
func (r *ReportingEventRepo) FindByDateRange(ctx context.Context, accountID uint, since, until time.Time) ([]model.ReportingEvent, error) {
|
|
var events []model.ReportingEvent
|
|
err := r.db.WithContext(ctx).
|
|
Where("account_id = ? AND event_start_time >= ? AND event_end_time <= ?", accountID, since, until).
|
|
Find(&events).Error
|
|
return events, err
|
|
}
|
|
|
|
func (r *ReportingEventRepo) FindByMetric(ctx context.Context, accountID uint, metricName string, since, until time.Time) ([]model.ReportingEvent, error) {
|
|
var events []model.ReportingEvent
|
|
err := r.db.WithContext(ctx).
|
|
Where("account_id = ? AND name = ? AND created_at >= ? AND created_at <= ?", accountID, metricName, since, until).
|
|
Find(&events).Error
|
|
return events, err
|
|
}
|
|
|
|
func (r *ReportingEventRepo) FindByInboxID(ctx context.Context, accountID, inboxID uint, since, until time.Time) ([]model.ReportingEvent, error) {
|
|
var events []model.ReportingEvent
|
|
err := r.db.WithContext(ctx).
|
|
Where("account_id = ? AND inbox_id = ? AND created_at >= ? AND created_at <= ?", accountID, inboxID, since, until).
|
|
Find(&events).Error
|
|
return events, err
|
|
}
|
|
|
|
func (r *ReportingEventRepo) FindByConversationID(ctx context.Context, accountID, conversationID uint) ([]model.ReportingEvent, error) {
|
|
var events []model.ReportingEvent
|
|
err := r.db.WithContext(ctx).
|
|
Where("account_id = ? AND conversation_id = ?", accountID, conversationID).
|
|
Order("created_at ASC").
|
|
Find(&events).Error
|
|
return events, err
|
|
}
|
|
|
|
func (r *ReportingEventRepo) FindByAccountFiltered(ctx context.Context, accountID uint, filter ReportingEventListFilter) ([]model.ReportingEvent, int64, error) {
|
|
query := r.db.WithContext(ctx).Model(&model.ReportingEvent{}).Where("account_id = ?", accountID)
|
|
if filter.Since != nil && filter.Until != nil {
|
|
query = query.Where("created_at >= ? AND created_at < ?", *filter.Since, *filter.Until)
|
|
}
|
|
if filter.InboxID != 0 {
|
|
query = query.Where("inbox_id = ?", filter.InboxID)
|
|
}
|
|
if filter.UserID != 0 {
|
|
query = query.Where("user_id = ?", filter.UserID)
|
|
}
|
|
if filter.Name != "" {
|
|
query = query.Where("name = ?", filter.Name)
|
|
}
|
|
|
|
var total int64
|
|
if err := query.Count(&total).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
var events []model.ReportingEvent
|
|
err := query.Order("created_at DESC").Offset(filter.Offset).Limit(filter.Limit).Find(&events).Error
|
|
return events, total, err
|
|
}
|
|
|
|
// AggregateByMetric returns aggregated values (average, count) for a given metric name.
|
|
func (r *ReportingEventRepo) AggregateByMetric(ctx context.Context, accountID uint, metricName string, since, until time.Time) (float64, int64, error) {
|
|
var result struct {
|
|
SumValue float64
|
|
Count int64
|
|
}
|
|
err := r.db.WithContext(ctx).
|
|
Model(&model.ReportingEvent{}).
|
|
Where("account_id = ? AND name = ? AND created_at >= ? AND created_at <= ?", accountID, metricName, since, until).
|
|
Select("COALESCE(SUM(value), 0) as sum_value, COUNT(*) as count").
|
|
Take(&result).Error
|
|
return result.SumValue, result.Count, err
|
|
}
|
|
|
|
// FindByAccountIDAndTimeRange retrieves all events created in [since, until).
|
|
// Chatwoot rollup/backfill uses reporting_events.created_at for local-date boundaries.
|
|
func (r *ReportingEventRepo) FindByAccountIDAndTimeRange(ctx context.Context, accountID uint, since, until time.Time) ([]model.ReportingEvent, error) {
|
|
var events []model.ReportingEvent
|
|
err := r.db.WithContext(ctx).
|
|
Where("account_id = ? AND created_at >= ? AND created_at < ?", accountID, since, until).
|
|
Find(&events).Error
|
|
return events, err
|
|
}
|