Skip to content

Commit 58db57f

Browse files
committed
added report endpoints with report dat a column and custom type, currently broken :D
1 parent aff0630 commit 58db57f

File tree

11 files changed

+318
-91
lines changed

11 files changed

+318
-91
lines changed

cmd/api.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ func runAPI(cmd *cobra.Command, args []string) {
7575
entities.IncidentComment{},
7676
entities.Changelog{},
7777
entities.ChangelogEntry{},
78+
entities.Report{},
7879
)
7980

8081
ch_db, err := clickhouse.NewClient(ctx, conf.Clickhouse)
@@ -125,7 +126,8 @@ func runAPI(cmd *cobra.Command, args []string) {
125126
incidentRepository := incident.NewRepository(db)
126127
incidentService := incident.NewService(incidentRepository)
127128

128-
reportsService := report.NewService(db)
129+
reportRepository := report.NewRepository(db)
130+
reportsService := report.NewService(reportRepository)
129131

130132
srv, err := rest.NewServer(
131133
conf.REST,

go.mod

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ require (
1717
github.com/go-playground/validator/v10 v10.11.1
1818
github.com/gofrs/uuid v4.0.0+incompatible
1919
github.com/golang-jwt/jwt v3.2.2+incompatible
20-
github.com/google/uuid v1.3.0
20+
github.com/google/uuid v1.6.0
2121
github.com/jackc/pgconn v1.13.0
2222
github.com/json-iterator/go v1.1.12
2323
github.com/labstack/echo/v4 v4.9.1
@@ -38,16 +38,18 @@ require (
3838
github.com/vmihailenco/msgpack v4.0.4+incompatible
3939
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0
4040
go.uber.org/automaxprocs v1.5.2
41-
golang.org/x/crypto v0.4.0
41+
golang.org/x/crypto v0.23.0
42+
gorm.io/datatypes v1.2.6
4243
gorm.io/driver/clickhouse v0.5.0
43-
gorm.io/driver/postgres v1.4.5
44-
gorm.io/gorm v1.24.2
44+
gorm.io/driver/postgres v1.5.0
45+
gorm.io/gorm v1.30.0
4546
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448
4647
)
4748

4849
require (
4950
cloud.google.com/go/compute v1.12.1 // indirect
5051
cloud.google.com/go/compute/metadata v0.2.1 // indirect
52+
filippo.io/edwards25519 v1.1.0 // indirect
5153
github.com/ClickHouse/ch-go v0.48.0 // indirect
5254
github.com/ClickHouse/clickhouse-go/v2 v2.3.0 // indirect
5355
github.com/Rican7/retry v0.3.1 // indirect
@@ -70,6 +72,7 @@ require (
7072
github.com/go-faster/errors v0.6.1 // indirect
7173
github.com/go-playground/locales v0.14.0 // indirect
7274
github.com/go-playground/universal-translator v0.18.0 // indirect
75+
github.com/go-sql-driver/mysql v1.8.1 // indirect
7376
github.com/golang/protobuf v1.5.2 // indirect
7477
github.com/gorilla/context v1.1.1 // indirect
7578
github.com/gorilla/mux v1.6.2 // indirect
@@ -82,9 +85,9 @@ require (
8285
github.com/jackc/pgio v1.0.0 // indirect
8386
github.com/jackc/pgpassfile v1.0.0 // indirect
8487
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
85-
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
86-
github.com/jackc/pgtype v1.12.0 // indirect
87-
github.com/jackc/pgx/v4 v4.17.2 // indirect
88+
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
89+
github.com/jackc/pgx/v5 v5.5.5 // indirect
90+
github.com/jackc/puddle/v2 v2.2.1 // indirect
8891
github.com/jinzhu/inflection v1.0.0 // indirect
8992
github.com/jinzhu/now v1.1.5 // indirect
9093
github.com/jmespath/go-jmespath v0.4.0 // indirect
@@ -116,15 +119,17 @@ require (
116119
github.com/valyala/fasttemplate v1.2.1 // indirect
117120
go.opentelemetry.io/otel v1.10.0 // indirect
118121
go.opentelemetry.io/otel/trace v1.10.0 // indirect
119-
golang.org/x/net v0.5.0 // indirect
122+
golang.org/x/net v0.21.0 // indirect
120123
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect
121-
golang.org/x/sys v0.4.0 // indirect
122-
golang.org/x/text v0.6.0 // indirect
124+
golang.org/x/sync v0.9.0 // indirect
125+
golang.org/x/sys v0.20.0 // indirect
126+
golang.org/x/text v0.20.0 // indirect
123127
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
124128
google.golang.org/appengine v1.6.7 // indirect
125129
google.golang.org/protobuf v1.28.1 // indirect
126130
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
127131
gopkg.in/ini.v1 v1.67.0 // indirect
128132
gopkg.in/yaml.v2 v2.4.0 // indirect
129133
gopkg.in/yaml.v3 v3.0.1 // indirect
134+
gorm.io/driver/mysql v1.5.6 // indirect
130135
)

go.sum

Lines changed: 48 additions & 43 deletions
Large diffs are not rendered by default.

internal/check/repository.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type Repository interface {
2020
GetMonitorStatsByMonitorID(ctx context.Context, monitorID uint) (*MonitorStats, error)
2121
GetMonitorOverviewStatsByTeamID(ctx context.Context, teamID uint) (*[]MonitorOverviewStats, error)
2222
GetMonitorIDAndAssertions(ctx context.Context, monitorID uint, assertions []string) (*[]Check, error)
23+
GetByTeamIDMonitorsUptime(ctx context.Context, teamID uint, start, end string) (*[]MonitorUptime, error)
2324
}
2425

2526
type RepositoryImpl struct {
@@ -213,3 +214,33 @@ func (r *RepositoryImpl) GetMonitorIDAndAssertions(ctx context.Context, monitorI
213214

214215
return &checks, nil
215216
}
217+
218+
type MonitorUptime struct {
219+
MonitorID uint
220+
Url string
221+
UptimePercentage float32
222+
Date string
223+
}
224+
225+
func (r *RepositoryImpl) GetByTeamIDMonitorsUptime(ctx context.Context, teamID uint, start, end string) (*[]MonitorUptime, error) {
226+
var uptime []MonitorUptime
227+
err := r.db.WithContext(
228+
ctx,
229+
).Table("checks").Select(`
230+
monitor_id,
231+
url,
232+
count(status_code <= 400) / count(status_code) * 100 as uptime_percentage,
233+
avg(timing_total/1000000) as average_response_time,
234+
toMonth(created_at) as date`).
235+
Where("team_id = ?", teamID).
236+
// Where("created_at BETWEEN ? AND ?", start, end).
237+
Group("monitor_id, url, date").
238+
Order("date ASC").
239+
Find(&uptime).Error
240+
241+
if err != nil {
242+
return nil, err
243+
}
244+
245+
return &uptime, nil
246+
}

internal/check/service.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type Service interface {
1818
GetMonitorOverviewsByTeamID(ctx context.Context, teamID uint) (*[]MonitorOverviews, error)
1919

2020
GetMonitorIDAndAssertions(ctx context.Context, monitorID uint, assertions []string) (*[]Check, error)
21+
GetByTeamIDMonitorsUptime(ctx context.Context, teamID uint, start, end string) (*[]MonitorUptime, error)
2122
}
2223

2324
type ServiceImpl struct {
@@ -74,3 +75,6 @@ func (s *ServiceImpl) GetMonitorOverviewsByTeamID(ctx context.Context, teamID ui
7475
func (s *ServiceImpl) GetMonitorIDAndAssertions(ctx context.Context, monitorID uint, assertions []string) (*[]Check, error) {
7576
return s.repository.GetMonitorIDAndAssertions(ctx, monitorID, assertions)
7677
}
78+
func (s *ServiceImpl) GetByTeamIDMonitorsUptime(ctx context.Context, teamID uint, start, end string) (*[]MonitorUptime, error) {
79+
return s.repository.GetByTeamIDMonitorsUptime(ctx, teamID, start, end)
80+
}

internal/entities/report.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package entities
2+
3+
import (
4+
"errors"
5+
"time"
6+
7+
"github.com/opsway-io/backend/internal/check"
8+
"gorm.io/datatypes"
9+
)
10+
11+
type ReportType string
12+
13+
const (
14+
ReportTypeUptime ReportType = "UPTIME"
15+
ReportTypePerformance ReportType = "PERFORMANCE"
16+
ReportTypeIncident ReportType = "INCIDENT"
17+
ReportTypeAll ReportType = "ALL"
18+
ReportTypeCustom ReportType = "CUSTOM"
19+
)
20+
21+
type Report struct {
22+
ID uint
23+
TeamID uint `gorm:"index;not null"`
24+
Type ReportType `gorm:"index;not null"`
25+
Report datatypes.JSONType[ReportData] `gorm:"not null"`
26+
27+
CreatedAt time.Time `gorm:"index"`
28+
UpdatedAt time.Time `gorm:"index"`
29+
}
30+
31+
func (Report) TableName() string {
32+
return "reports"
33+
}
34+
35+
type ReportData struct {
36+
Uptime *[]check.MonitorUptime `json:"uptime"`
37+
Performance *string `json:"performance"`
38+
Incident *string `json:"incident"`
39+
All *string `json:"all"`
40+
Custom *string `json:"custom"`
41+
}
42+
43+
func ReportFrom(source any) (ReportType, error) {
44+
s, ok := source.(string)
45+
if !ok {
46+
return "", errors.New("invalid report type, must be string")
47+
}
48+
49+
switch s {
50+
case "UPTIME":
51+
return ReportTypeUptime, nil
52+
case "PERFORMANCE":
53+
return ReportTypePerformance, nil
54+
case "INCIDENT":
55+
return ReportTypeIncident, nil
56+
case "ALL":
57+
return ReportTypeAll, nil
58+
case "CUSTOM":
59+
return ReportTypeCustom, nil
60+
default:
61+
return "", errors.New("invalid report type")
62+
}
63+
}

internal/report/repository.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package report
2+
3+
import (
4+
"context"
5+
"errors"
6+
7+
"github.com/opsway-io/backend/internal/entities"
8+
"gorm.io/gorm"
9+
)
10+
11+
var ErrNotFound = errors.New("monitor not found")
12+
13+
type Repository interface {
14+
GetReportsByTeamID(ctx context.Context, teamID uint) (*[]entities.Report, error)
15+
Create(ctx context.Context, rep *entities.Report) error
16+
Delete(ctx context.Context, teamID, reportID uint) error
17+
}
18+
19+
type RepositoryImpl struct {
20+
db *gorm.DB
21+
}
22+
23+
func NewRepository(db *gorm.DB) Repository {
24+
return &RepositoryImpl{
25+
db: db,
26+
}
27+
}
28+
29+
func (r *RepositoryImpl) GetReportsByTeamID(ctx context.Context, teamID uint) (*[]entities.Report, error) {
30+
var reports []entities.Report
31+
err := r.db.WithContext(
32+
ctx,
33+
).Where(entities.Report{
34+
TeamID: teamID,
35+
}).Find(&reports).Error
36+
if err != nil {
37+
if errors.Is(err, gorm.ErrRecordNotFound) {
38+
return nil, nil
39+
}
40+
41+
return nil, err
42+
}
43+
44+
return &reports, err
45+
}
46+
47+
func (r *RepositoryImpl) Create(ctx context.Context, rep *entities.Report) error {
48+
return r.db.WithContext(ctx).Create(rep).Error
49+
}
50+
51+
func (r *RepositoryImpl) Delete(ctx context.Context, teamID, reportID uint) error {
52+
err := r.db.WithContext(ctx).
53+
Where(entities.Report{
54+
ID: reportID,
55+
TeamID: teamID,
56+
}).Delete(&entities.Report{}).Error
57+
if errors.Is(err, gorm.ErrRecordNotFound) {
58+
return ErrNotFound
59+
}
60+
61+
return err
62+
}

internal/report/service.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,37 @@ package report
33
import (
44
"context"
55

6-
"gorm.io/gorm"
6+
"github.com/opsway-io/backend/internal/entities"
7+
"gorm.io/datatypes"
78
)
89

910
type Service interface {
10-
GetResportsByTeam(ctx context.Context, teamID uint) (string, error)
11+
GetResportsByTeam(ctx context.Context, teamID uint) (*[]entities.Report, error)
12+
CreateReport(ctx context.Context, teamID uint, reportType string, reportData entities.ReportData) error
1113
}
1214

1315
type ServiceImpl struct {
16+
repository Repository
1417
}
1518

16-
func NewService(db *gorm.DB) Service {
17-
return &ServiceImpl{}
19+
func NewService(repository Repository) Service {
20+
return &ServiceImpl{
21+
repository: repository,
22+
}
1823
}
1924

20-
func (s *ServiceImpl) GetResportsByTeam(ctx context.Context, teamID uint) (string, error) {
21-
return "", nil
25+
func (s *ServiceImpl) GetResportsByTeam(ctx context.Context, teamID uint) (*[]entities.Report, error) {
26+
return s.repository.GetReportsByTeamID(ctx, teamID)
27+
}
28+
func (s *ServiceImpl) CreateReport(ctx context.Context, teamID uint, reportType string, reportData entities.ReportData) error {
29+
reportTypeEnum, err := entities.ReportFrom(reportType)
30+
if err != nil {
31+
return err
32+
}
33+
34+
return s.repository.Create(ctx, &entities.Report{
35+
TeamID: teamID,
36+
Type: reportTypeEnum,
37+
Report: datatypes.NewJSONType(reportData),
38+
})
2239
}

0 commit comments

Comments
 (0)