Skip to content

Commit aa43d15

Browse files
committed
Merge branch 'feat-foi'
2 parents eb814fa + dd1e545 commit aa43d15

40 files changed

Lines changed: 2247 additions & 314 deletions

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,15 @@ golib: golib-clean
8989
USER_EMAIL ?= a@pollex.nl
9090
USER_SCHEMA ?= default
9191
usercreate:
92-
echo '{"schema_id":"$(USER_SCHEMA)", "traits": {"email":"$(USER_EMAIL)"}}' | http post 127.0.0.1:4434/admin/identities | jq -r .id
92+
@echo '{"schema_id":"$(USER_SCHEMA)", "traits": {"email":"$(USER_EMAIL)"}}' | http post 127.0.0.1:4434/admin/identities | jq -r .id
9393

9494
userfind:
95-
http get 127.0.0.1:4434/admin/identities\?credentials_identifier=$(USER_EMAIL) | jq -r .[0].id
95+
@http get 127.0.0.1:4434/admin/identities\?credentials_identifier=$(USER_EMAIL) | jq -r .[0].id
9696

9797
USER_ID =
9898
EXPIRES_IN ?= 5m
9999
userrecover:
100-
echo '{"identity_id":"$(USER_ID)","expires_in":"$(EXPIRES_IN)"}' | http post 127.0.0.1:4434/admin/recovery/code
100+
@echo '{"identity_id":"$(USER_ID)","expires_in":"$(EXPIRES_IN)"}' | http post 127.0.0.1:4434/admin/recovery/code
101101

102102

103103
oathkeeper:

architecture.drawio

Lines changed: 572 additions & 0 deletions
Large diffs are not rendered by default.

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ require (
1919
github.com/gorilla/websocket v1.5.1
2020
github.com/jackc/pgx/v5 v5.7.2
2121
github.com/jmoiron/sqlx v1.3.5
22+
github.com/lmittmann/tint v1.0.7
2223
github.com/mochi-mqtt/server/v2 v2.6.6
2324
github.com/ory/client-go v1.5.1
2425
github.com/ory/nosurf v1.2.7
@@ -30,6 +31,7 @@ require (
3031
github.com/stretchr/testify v1.9.0
3132
github.com/testcontainers/testcontainers-go v0.29.1
3233
github.com/twpayne/go-geom v1.5.7
34+
github.com/urfave/cli/v2 v2.27.5
3335
github.com/valyala/quicktemplate v1.7.0
3436
go.opentelemetry.io/otel v1.32.0
3537
go.opentelemetry.io/otel/exporters/prometheus v0.54.0
@@ -128,7 +130,6 @@ require (
128130
github.com/tklauser/go-sysconf v0.3.13 // indirect
129131
github.com/tklauser/numcpus v0.7.0 // indirect
130132
github.com/ulikunitz/xz v0.5.9 // indirect
131-
github.com/urfave/cli/v2 v2.27.5 // indirect
132133
github.com/valyala/bytebufferpool v1.0.0 // indirect
133134
github.com/x448/float16 v0.8.4 // indirect
134135
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect

go.sum

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6Fm
191191
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
192192
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
193193
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
194+
github.com/lmittmann/tint v1.0.7 h1:D/0OqWZ0YOGZ6AyC+5Y2kD8PBEzBk6rFHVSfOqCkF9Y=
195+
github.com/lmittmann/tint v1.0.7/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
194196
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
195197
github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a h1:3Bm7EwfUQUvhNeKIkUct/gl9eod1TcXuj8stxvi/GoI=
196198
github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
@@ -268,7 +270,6 @@ github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
268270
github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
269271
github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
270272
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
271-
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
272273
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
273274
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
274275
github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA=

internal/httpfilter/filter.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
var d = schema.NewDecoder()
1414

1515
func init() {
16+
d.SetAliasTag("url")
1617
d.IgnoreUnknownKeys(true)
1718
d.RegisterConverter(json.RawMessage{}, convertJSON)
1819
d.RegisterConverter(uuid.UUID{}, convertUUID)

pkg/auth/permissions.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ const (
4848
// User worker permissions
4949
READ_USER_WORKERS Permission = "READ_USER_WORKERS"
5050
WRITE_USER_WORKERS Permission = "WRITE_USER_WORKERS"
51+
52+
READ_PROJECTS Permission = "READ_PROJECTS"
53+
WRITE_PROJECTS Permission = "WRITE_PROJECTS"
5154
)
5255

5356
var allPermissions = Permissions{
@@ -64,6 +67,8 @@ var allPermissions = Permissions{
6467
READ_TRACING,
6568
READ_USER_WORKERS,
6669
WRITE_USER_WORKERS,
70+
READ_PROJECTS,
71+
WRITE_PROJECTS,
6772
}
6873

6974
func AllPermissions() Permissions {

pkg/auth/utils.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,11 @@ type pqts[T queryBuilders] interface {
7373
Where(pred any, args ...any) T
7474
}
7575

76-
func ProtectedQuery[T queryBuilders](ctx context.Context, query pqts[T]) T {
76+
func ProtectedQuery[T queryBuilders](ctx context.Context, tenantIDColumn string, query pqts[T]) T {
7777
tenantID, err := GetTenant(ctx)
7878
if err != nil {
7979
log.Println("WARN: in pkg/auth/utils.go. Called ProtectedQuery without a tenant being set in the context")
8080
return query.Where("false")
8181
}
82-
return query.Where(squirrel.Eq{"tenant_id": tenantID})
82+
return query.Where(squirrel.Eq{tenantIDColumn: tenantID})
8383
}

services/core/devices/application.go

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"sensorbucket.nl/sensorbucket/internal/pagination"
1111
"sensorbucket.nl/sensorbucket/pkg/auth"
12+
"sensorbucket.nl/sensorbucket/services/core/featuresofinterest"
1213
)
1314

1415
type DeviceStore interface {
@@ -30,14 +31,16 @@ type SensorGroupStore interface {
3031
}
3132

3233
type Service struct {
33-
store DeviceStore
34-
sensorGroupStore SensorGroupStore
34+
store DeviceStore
35+
sensorGroupStore SensorGroupStore
36+
featureOfInterestService *featuresofinterest.Service
3537
}
3638

37-
func New(store DeviceStore, sensorGroupStore SensorGroupStore) *Service {
39+
func New(store DeviceStore, sensorGroupStore SensorGroupStore, featureOfInterestService *featuresofinterest.Service) *Service {
3840
return &Service{
39-
store: store,
40-
sensorGroupStore: sensorGroupStore,
41+
store: store,
42+
sensorGroupStore: sensorGroupStore,
43+
featureOfInterestService: featureOfInterestService,
4144
}
4245
}
4346

@@ -116,15 +119,14 @@ func (s *Service) GetDevice(ctx context.Context, id int64) (*Device, error) {
116119
}
117120

118121
type NewSensorDTO struct {
119-
Code string `json:"code"`
120-
Brand string `json:"brand"`
121-
GoalID int64 `json:"goal_id"`
122-
TypeID int64 `json:"type_id"`
123-
Description string `json:"description"`
124-
ExternalID string `json:"external_id"`
125-
Properties json.RawMessage `json:"properties"`
126-
ArchiveTime *int `json:"archive_time"`
127-
IsFallback bool `json:"is_fallback"`
122+
Code string `json:"code"`
123+
Brand string `json:"brand"`
124+
Description string `json:"description"`
125+
ExternalID string `json:"external_id"`
126+
FeatureOfInterestID int64 `json:"feature_of_interest_id"`
127+
Properties json.RawMessage `json:"properties"`
128+
ArchiveTime *int `json:"archive_time"`
129+
IsFallback bool `json:"is_fallback"`
128130
}
129131

130132
func (s *Service) AddSensor(ctx context.Context, dev *Device, dto NewSensorDTO) error {
@@ -141,6 +143,14 @@ func (s *Service) AddSensor(ctx context.Context, dev *Device, dto NewSensorDTO)
141143
ArchiveTime: dto.ArchiveTime,
142144
IsFallback: dto.IsFallback,
143145
}
146+
if dto.FeatureOfInterestID > 0 {
147+
feature, err := s.featureOfInterestService.GetFeatureOfInterest(ctx, dto.FeatureOfInterestID)
148+
if err != nil {
149+
return fmt.Errorf("in AddSensor: could not get feature of interest: %w", err)
150+
}
151+
opts.FeatureOfInterest = feature
152+
}
153+
144154
if err := dev.AddSensor(opts); err != nil {
145155
return err
146156
}
@@ -235,12 +245,13 @@ func (s *Service) GetSensor(ctx context.Context, id int64) (*Sensor, error) {
235245
}
236246

237247
type UpdateSensorOpts struct {
238-
Description *string `json:"description"`
239-
Brand *string `json:"brand"`
240-
ArchiveTime *int `json:"archive_time"`
241-
ExternalID *string `json:"external_id"`
242-
IsFallback *bool `json:"is_fallback"`
243-
Properties json.RawMessage `json:"properties"`
248+
Description *string `json:"description"`
249+
Brand *string `json:"brand"`
250+
ArchiveTime *int `json:"archive_time"`
251+
ExternalID *string `json:"external_id"`
252+
IsFallback *bool `json:"is_fallback"`
253+
Properties json.RawMessage `json:"properties"`
254+
FeatureOfInterestID *int64 `json:"feature_of_interest_id"`
244255
}
245256

246257
func (s *Service) UpdateSensor(ctx context.Context, device *Device, sensor *Sensor, opt UpdateSensorOpts) error {
@@ -270,6 +281,17 @@ func (s *Service) UpdateSensor(ctx context.Context, device *Device, sensor *Sens
270281
if opt.Properties != nil {
271282
sensor.Properties = opt.Properties
272283
}
284+
if opt.FeatureOfInterestID != nil {
285+
if *opt.FeatureOfInterestID == 0 {
286+
sensor.FeatureOfInterest = nil
287+
} else {
288+
feature, err := s.featureOfInterestService.GetFeatureOfInterest(ctx, *opt.FeatureOfInterestID)
289+
if err != nil {
290+
return fmt.Errorf("in UpdateSensor: could not get feature of interest: %w", err)
291+
}
292+
sensor.FeatureOfInterest = feature
293+
}
294+
}
273295

274296
if err := device.UpdateSensor(sensor); err != nil {
275297
return err

services/core/devices/application_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func TestServiceDeviceUpdates(t *testing.T) {
4444
return nil
4545
}}
4646

47-
svc := devices.New(store, nil)
47+
svc := devices.New(store, nil, nil)
4848

4949
err := svc.UpdateDevice(authtest.GodContext(), &originalDevice, updateDTO)
5050
assert.NoError(t, err)
@@ -73,7 +73,7 @@ func TestServiceCreateDevice(t *testing.T) {
7373
storedDev = dev
7474
return nil
7575
}}
76-
svc := devices.New(store, nil)
76+
svc := devices.New(store, nil, nil)
7777

7878
_, err := svc.CreateDevice(authtest.GodContext(), newDTO)
7979
assert.NoError(t, err)
@@ -113,7 +113,7 @@ func TestServiceShouldAddSensor(t *testing.T) {
113113
return nil
114114
},
115115
}
116-
svc := devices.New(store, nil)
116+
svc := devices.New(store, nil, nil)
117117

118118
// Act
119119
err := svc.AddSensor(authtest.GodContext(), &dev, sensorDTO)
@@ -161,7 +161,7 @@ func TestServiceShouldAddSensorToSensorGroup(t *testing.T) {
161161
return nil
162162
},
163163
}
164-
svc := devices.New(deviceStore, sensorGroupStore)
164+
svc := devices.New(deviceStore, sensorGroupStore, nil)
165165

166166
// Act
167167
err := svc.AddSensorToSensorGroup(authtest.GodContext(), sensorGroupID, sensorID)
@@ -202,7 +202,7 @@ func TestServiceShouldDeleteSensorFromSensorGroup(t *testing.T) {
202202
return nil
203203
},
204204
}
205-
svc := devices.New(deviceStore, sensorGroupStore)
205+
svc := devices.New(deviceStore, sensorGroupStore, nil)
206206

207207
// Act
208208
err := svc.DeleteSensorFromSensorGroup(authtest.GodContext(), sensorGroupID, sensorID)
@@ -236,7 +236,7 @@ func TestServiceShouldDeleteSensorGroup(t *testing.T) {
236236
return nil
237237
},
238238
}
239-
svc := devices.New(deviceStore, sensorGroupStore)
239+
svc := devices.New(deviceStore, sensorGroupStore, nil)
240240

241241
// Act
242242
err := svc.DeleteSensorGroup(authtest.GodContext(), sensorGroup)
@@ -266,7 +266,7 @@ func TestServiceShouldUpdateSensorGroup(t *testing.T) {
266266
return nil
267267
},
268268
}
269-
svc := devices.New(deviceStore, sensorGroupStore)
269+
svc := devices.New(deviceStore, sensorGroupStore, nil)
270270
dto := devices.UpdateSensorGroupOpts{
271271
Name: &updatedName,
272272
}

services/core/devices/devices.go

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"time"
1010

1111
"sensorbucket.nl/sensorbucket/internal/web"
12+
"sensorbucket.nl/sensorbucket/services/core/featuresofinterest"
1213
)
1314

1415
var (
@@ -50,6 +51,11 @@ var (
5051
"Invalid coordinates supplied",
5152
"ERR_LOCATION_INVALID_COORDINATES",
5253
)
54+
ErrFeatureOfInterestNotFound = web.NewError(
55+
http.StatusNotFound,
56+
"feature_of_interest not found",
57+
"FEATURE_OF_INTEREST_NOT_FOUND",
58+
)
5359
)
5460

5561
type DeviceState uint8
@@ -76,17 +82,18 @@ type Device struct {
7682
}
7783

7884
type Sensor struct {
79-
ID int64 `json:"id"`
80-
Code string `json:"code"`
81-
Description string `json:"description"`
82-
DeviceID int64 `json:"device_id" db:"device_id"`
83-
Brand string `json:"brand"`
84-
ArchiveTime *int `json:"archive_time" db:"archive_time"`
85-
ExternalID string `json:"external_id" db:"external_id"`
86-
IsFallback bool `json:"is_fallback" db:"is_fallback"`
87-
Properties json.RawMessage `json:"properties"`
88-
TenantID int64 `json:"tenant_id"`
89-
CreatedAt time.Time `json:"created_at" db:"created_at"`
85+
ID int64 `json:"id"`
86+
Code string `json:"code"`
87+
Description string `json:"description"`
88+
DeviceID int64 `json:"device_id" db:"device_id"`
89+
Brand string `json:"brand"`
90+
ArchiveTime *int `json:"archive_time" db:"archive_time"`
91+
ExternalID string `json:"external_id" db:"external_id"`
92+
IsFallback bool `json:"is_fallback" db:"is_fallback"`
93+
Properties json.RawMessage `json:"properties"`
94+
FeatureOfInterest *featuresofinterest.FeatureOfInterest `json:"feature_of_interest"`
95+
TenantID int64 `json:"tenant_id"`
96+
CreatedAt time.Time `json:"created_at" db:"created_at"`
9097
}
9198

9299
type NewDeviceOpts struct {
@@ -134,24 +141,26 @@ func NewDevice(tenantID int64, opts NewDeviceOpts) (*Device, error) {
134141
}
135142

136143
type NewSensorOpts struct {
137-
Code string `json:"code"`
138-
Brand string `json:"brand"`
139-
Description string `json:"description"`
140-
ExternalID string `json:"external_id"`
141-
ArchiveTime *int `json:"archive_time"`
142-
Properties json.RawMessage `json:"properties"`
143-
IsFallback bool `json:"is_fallback"`
144+
Code string
145+
Brand string
146+
Description string
147+
ExternalID string
148+
ArchiveTime *int
149+
FeatureOfInterest *featuresofinterest.FeatureOfInterest
150+
Properties json.RawMessage
151+
IsFallback bool
144152
}
145153

146154
func NewSensor(opts NewSensorOpts) (*Sensor, error) {
147155
sensor := Sensor{
148-
Brand: opts.Brand,
149-
Description: opts.Description,
150-
ExternalID: opts.ExternalID,
151-
Properties: []byte("{}"),
152-
ArchiveTime: opts.ArchiveTime,
153-
CreatedAt: time.Now(),
154-
IsFallback: opts.IsFallback,
156+
Brand: opts.Brand,
157+
Description: opts.Description,
158+
ExternalID: opts.ExternalID,
159+
Properties: []byte("{}"),
160+
ArchiveTime: opts.ArchiveTime,
161+
CreatedAt: time.Now(),
162+
FeatureOfInterest: opts.FeatureOfInterest,
163+
IsFallback: opts.IsFallback,
155164
}
156165

157166
if !R_CODE.MatchString(opts.Code) {

0 commit comments

Comments
 (0)