diff --git a/resources/db/migration/V1.3.0.2__add_partner_to_report_stats.sql b/resources/db/migration/V1.3.0.2__add_partner_to_report_stats.sql new file mode 100644 index 0000000..aa1d5bc --- /dev/null +++ b/resources/db/migration/V1.3.0.2__add_partner_to_report_stats.sql @@ -0,0 +1,15 @@ +delete from report_statistics; + +alter table report_statistics + add operator_uuid varchar(36) not null; + +alter table report_statistics + add constraint report_statistics_operators_uuid_fk + foreign key (operator_uuid) references operators + on update cascade on delete cascade; + +alter table report_statistics drop constraint report_statistics_pk; + +alter table report_statistics + add constraint report_statistics_pk + primary key (operator_uuid, subject); diff --git a/src/api/model/statistics.go b/src/api/model/statistics.go index 231576a..6679b16 100644 --- a/src/api/model/statistics.go +++ b/src/api/model/statistics.go @@ -24,12 +24,14 @@ package model import "com.t-systems-mms.cwa/repositories" type ReportStatisticsDTO struct { - Subject string `json:"subject"` - ReportCount uint `json:"report_count"` + Operator *string `json:"operator"` + Subject string `json:"subject"` + ReportCount uint `json:"report_count"` } func (dto ReportStatisticsDTO) FromModel(model repositories.ReportStatistics) *ReportStatisticsDTO { return &ReportStatisticsDTO{ + Operator: model.Operator.OperatorNumber, Subject: model.Subject, ReportCount: model.Count, } diff --git a/src/api/statistics.go b/src/api/statistics.go index d47cc40..829bc8f 100644 --- a/src/api/statistics.go +++ b/src/api/statistics.go @@ -22,13 +22,17 @@ package api import ( - "com.t-systems-mms.cwa/api/model" "com.t-systems-mms.cwa/core/api" "com.t-systems-mms.cwa/core/security" + "com.t-systems-mms.cwa/core/util" + "com.t-systems-mms.cwa/domain" "com.t-systems-mms.cwa/repositories" + "encoding/csv" "github.com/go-chi/chi" "github.com/go-chi/jwtauth" + "github.com/sirupsen/logrus" "net/http" + "strconv" ) type Statistics struct { @@ -47,20 +51,70 @@ func NewStatisticsAPI(reportsRepository repositories.BugReports, auth *jwtauth.J r.Use(jwtauth.Authenticator) r.Use(api.RequireRole(security.RoleAdmin)) - r.Get("/reports", api.Handle(statistics.getReportStatistics)) + r.Get("/reports", statistics.getReportStatistics) }) return statistics } -func (c *Statistics) getReportStatistics(_ http.ResponseWriter, r *http.Request) (interface{}, error) { +func (c *Statistics) getReportStatistics(w http.ResponseWriter, r *http.Request) { stats, err := c.reportsRepository.GetStatistics(r.Context()) if err != nil { - return nil, err + logrus.WithError(err).Error("Error getting report statistics") + w.WriteHeader(http.StatusInternalServerError) + return } - result := make([]model.ReportStatisticsDTO, len(stats)) - for i, stat := range stats { - result[i] = *model.ReportStatisticsDTO{}.FromModel(stat) + subjects := make([]string, 0) + operators := make(map[string]domain.Operator) + data := make(map[string]map[string]uint) + for _, value := range stats { + knownSubject := false + for _, s := range subjects { + if s == value.Subject { + knownSubject = true + break + } + } + + if !knownSubject { + subjects = append(subjects, value.Subject) + } + + if _, ok := data[value.OperatorUUID]; !ok { + data[value.OperatorUUID] = make(map[string]uint) + operators[value.OperatorUUID] = *value.Operator + } + + data[value.OperatorUUID][value.Subject] = value.Count + } + + w.Header().Set("Content-Type", "text/csv") + if _, err := w.Write([]byte{0xEF, 0xBB, 0xBF}); err != nil { + logrus.WithError(err).Error("Error writing BOM") + return + } + + csvWriter := csv.NewWriter(w) + csvWriter.Comma = ';' + + headers := []string{"partner_uuid", "partner_name", "partner_number"} + headers = append(headers, subjects...) + if err := csvWriter.Write(headers); err != nil { + logrus.WithError(err).Error("Error writing response") + return + } + + for operator, entry := range data { + columns := []string{operator, util.PtrToString(operators[operator].OperatorNumber, ""), operators[operator].Name} + for _, subject := range subjects { + columns = append(columns, strconv.Itoa(int(entry[subject]))) + } + + if err := csvWriter.Write(columns); err != nil { + logrus.WithError(err).Error("Error writing response") + return + } } - return result, nil + + csvWriter.Flush() } diff --git a/src/repositories/bugreports.go b/src/repositories/bugreports.go index 320498f..d69cbf0 100644 --- a/src/repositories/bugreports.go +++ b/src/repositories/bugreports.go @@ -31,8 +31,10 @@ import ( ) type ReportStatistics struct { - Subject string - Count uint + Subject string + OperatorUUID string + Operator *domain.Operator `gorm:"foreignKey:OperatorUUID"` + Count uint } type BugReports interface { @@ -45,7 +47,7 @@ type BugReports interface { FindAllByLeader(ctx context.Context, leader string) ([]domain.BugReport, error) ResetLeader(ctx context.Context, leader string) error - IncrementReportCount(ctx context.Context, subject string) error + IncrementReportCount(ctx context.Context, operatorUUID, subject string) error GetStatistics(ctx context.Context) ([]ReportStatistics, error) } @@ -98,22 +100,25 @@ func (b *bugReportsRepository) ResetLeader(ctx context.Context, leader string) e func (b *bugReportsRepository) FindAll(ctx context.Context) ([]domain.BugReport, error) { var reports []domain.BugReport - err := b.GetTX(ctx).Find(&reports).Error + err := b.GetTX(ctx). + Find(&reports).Error return reports, err } -func (b *bugReportsRepository) IncrementReportCount(ctx context.Context, subject string) error { - return b.GetTX(ctx).Exec("insert into report_statistics (subject, count)"+ - "VALUES (?, 1)"+ - "on conflict (subject) "+ - "do update set count = report_statistics.count + 1", subject).Error +func (b *bugReportsRepository) IncrementReportCount(ctx context.Context, operatorUUID, subject string) error { + return b.GetTX(ctx).Exec("insert into report_statistics (operator_uuid, subject, count)"+ + "VALUES (?, ?, 1)"+ + "on conflict on constraint report_statistics_pk "+ + "do update set count = report_statistics.count + 1", operatorUUID, subject).Error } func (b *bugReportsRepository) GetStatistics(ctx context.Context) ([]ReportStatistics, error) { var statistics []ReportStatistics err := b.GetTX(ctx). - Raw("select * from report_statistics"). - Scan(&statistics).Error + Preload("Operator"). + Order("operator_uuid"). + Find(&statistics). + Error return statistics, err } diff --git a/src/services/bugreports.go b/src/services/bugreports.go index 24a27a2..6e5c10b 100644 --- a/src/services/bugreports.go +++ b/src/services/bugreports.go @@ -132,7 +132,7 @@ func (s *bugReportsService) CreateBugReport(ctx context.Context, centerUUID, sub return report, err } - if err := s.bugReportsRepository.IncrementReportCount(ctx, report.Subject); err != nil { + if err := s.bugReportsRepository.IncrementReportCount(ctx, center.OperatorUUID, report.Subject); err != nil { logrus.WithError(err).Error("Error updating report statistics") }