Skip to content

Commit 942348b

Browse files
committed
feat: add public found item contact page
1 parent 89d4a9b commit 942348b

18 files changed

Lines changed: 1465 additions & 413 deletions

File tree

backend/app/api/app.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type app struct {
2020
services *services.AllServices
2121
bus *eventbus.EventBus
2222
authLimiter *authRateLimiter
23+
foundLabelLimiter *simpleRateLimiter
2324
notifierTestLimiter *simpleRateLimiter
2425
otel *otel.Provider
2526
}
@@ -38,6 +39,7 @@ func new(conf *config.Config) *app {
3839
}
3940

4041
s.authLimiter = newAuthRateLimiter(s.conf.Auth.RateLimit)
42+
s.foundLabelLimiter = newSimpleRateLimiter(60, time.Minute, s.conf.Options.TrustProxy) // 60 requests per minute
4143
s.notifierTestLimiter = newSimpleRateLimiter(10, time.Minute, s.conf.Options.TrustProxy) // 10 requests per minute
4244

4345
return s
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package v1
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/go-chi/chi/v5"
7+
"github.com/google/uuid"
8+
"github.com/hay-kot/httpkit/errchain"
9+
"github.com/hay-kot/httpkit/server"
10+
"github.com/sysadminsmedia/homebox/backend/internal/data/repo"
11+
"github.com/sysadminsmedia/homebox/backend/internal/sys/validate"
12+
"github.com/sysadminsmedia/homebox/backend/internal/web/adapters"
13+
)
14+
15+
// HandleFoundEntityContact godoc
16+
//
17+
// @Summary Get found item contact
18+
// @Tags Entities
19+
// @Produce json
20+
// @Param id path string true "Entity ID"
21+
// @Success 200 {object} repo.FoundEntityContact
22+
// @Router /v1/found/entities/{id} [GET]
23+
func (ctrl *V1Controller) HandleFoundEntityContact() errchain.HandlerFunc {
24+
fn := func(r *http.Request, ID uuid.UUID) (repo.FoundEntityContact, error) {
25+
return ctrl.repo.Entities.GetFoundEntityContact(r.Context(), ID)
26+
}
27+
28+
return adapters.CommandID("id", fn, http.StatusOK)
29+
}
30+
31+
// HandleFoundAssetContact godoc
32+
//
33+
// @Summary Get found asset contact
34+
// @Tags Entities
35+
// @Produce json
36+
// @Param id path string true "Asset ID"
37+
// @Success 200 {object} repo.FoundEntityContact
38+
// @Router /v1/found/assets/{id} [GET]
39+
func (ctrl *V1Controller) HandleFoundAssetContact() errchain.HandlerFunc {
40+
return func(rw http.ResponseWriter, r *http.Request) error {
41+
assetID, ok := repo.ParseAssetID(chi.URLParam(r, "id"))
42+
if !ok || assetID.Nil() {
43+
return validate.NewRouteKeyError("id")
44+
}
45+
46+
contact, err := ctrl.repo.Entities.GetFoundEntityContactByAssetID(r.Context(), assetID)
47+
if err != nil {
48+
return err
49+
}
50+
51+
return server.JSON(rw, http.StatusOK, contact)
52+
}
53+
}

backend/app/api/routes.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
8888

8989
r.Post("/users/register", chain.ToHandlerFunc(v1Ctrl.HandleUserRegistration()))
9090
r.Post("/users/login", chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin(providers...), a.mwAuthRateLimit))
91+
r.Get("/found/entities/{id}", chain.ToHandlerFunc(v1Ctrl.HandleFoundEntityContact(), a.foundLabelLimiter.middleware))
92+
r.Get("/found/assets/{id}", chain.ToHandlerFunc(v1Ctrl.HandleFoundAssetContact(), a.foundLabelLimiter.middleware))
9193

9294
if a.conf.OIDC.Enabled {
9395
r.Get("/users/login/oidc", chain.ToHandlerFunc(v1Ctrl.HandleOIDCLogin(), a.mwAuthRateLimit))

backend/app/api/static/docs/docs.go

Lines changed: 132 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,62 @@ const docTemplate = `{
11551155
}
11561156
}
11571157
},
1158+
"/v1/found/assets/{id}": {
1159+
"get": {
1160+
"produces": [
1161+
"application/json"
1162+
],
1163+
"tags": [
1164+
"Entities"
1165+
],
1166+
"summary": "Get found asset contact",
1167+
"parameters": [
1168+
{
1169+
"type": "string",
1170+
"description": "Asset ID",
1171+
"name": "id",
1172+
"in": "path",
1173+
"required": true
1174+
}
1175+
],
1176+
"responses": {
1177+
"200": {
1178+
"description": "OK",
1179+
"schema": {
1180+
"$ref": "#/definitions/repo.FoundEntityContact"
1181+
}
1182+
}
1183+
}
1184+
}
1185+
},
1186+
"/v1/found/entities/{id}": {
1187+
"get": {
1188+
"produces": [
1189+
"application/json"
1190+
],
1191+
"tags": [
1192+
"Entities"
1193+
],
1194+
"summary": "Get found item contact",
1195+
"parameters": [
1196+
{
1197+
"type": "string",
1198+
"description": "Entity ID",
1199+
"name": "id",
1200+
"in": "path",
1201+
"required": true
1202+
}
1203+
],
1204+
"responses": {
1205+
"200": {
1206+
"description": "OK",
1207+
"schema": {
1208+
"$ref": "#/definitions/repo.FoundEntityContact"
1209+
}
1210+
}
1211+
}
1212+
}
1213+
},
11581214
"/v1/groups": {
11591215
"get": {
11601216
"security": [
@@ -1439,36 +1495,6 @@ const docTemplate = `{
14391495
}
14401496
}
14411497
}
1442-
},
1443-
"post": {
1444-
"security": [
1445-
{
1446-
"Bearer": []
1447-
}
1448-
],
1449-
"produces": [
1450-
"application/json"
1451-
],
1452-
"tags": [
1453-
"Group"
1454-
],
1455-
"summary": "Add User to Group",
1456-
"parameters": [
1457-
{
1458-
"description": "User ID",
1459-
"name": "payload",
1460-
"in": "body",
1461-
"required": true,
1462-
"schema": {
1463-
"$ref": "#/definitions/v1.GroupMemberAdd"
1464-
}
1465-
}
1466-
],
1467-
"responses": {
1468-
"204": {
1469-
"description": "No Content"
1470-
}
1471-
}
14721498
}
14731499
},
14741500
"/v1/groups/members/{user_id}": {
@@ -3718,6 +3744,13 @@ const docTemplate = `{
37183744
"$ref": "#/definitions/ent.Tag"
37193745
}
37203746
},
3747+
"user_groups": {
3748+
"description": "UserGroups holds the value of the user_groups edge.",
3749+
"type": "array",
3750+
"items": {
3751+
"$ref": "#/definitions/ent.UserGroup"
3752+
}
3753+
},
37213754
"users": {
37223755
"description": "Users holds the value of the users edge.",
37233756
"type": "array",
@@ -4097,14 +4130,6 @@ const docTemplate = `{
40974130
"description": "OidcSubject holds the value of the \"oidc_subject\" field.",
40984131
"type": "string"
40994132
},
4100-
"role": {
4101-
"description": "Role holds the value of the \"role\" field.",
4102-
"allOf": [
4103-
{
4104-
"$ref": "#/definitions/user.Role"
4105-
}
4106-
]
4107-
},
41084133
"settings": {
41094134
"description": "Settings holds the value of the \"settings\" field.",
41104135
"type": "object",
@@ -4150,6 +4175,63 @@ const docTemplate = `{
41504175
"items": {
41514176
"$ref": "#/definitions/ent.Notifier"
41524177
}
4178+
},
4179+
"user_groups": {
4180+
"description": "UserGroups holds the value of the user_groups edge.",
4181+
"type": "array",
4182+
"items": {
4183+
"$ref": "#/definitions/ent.UserGroup"
4184+
}
4185+
}
4186+
}
4187+
},
4188+
"ent.UserGroup": {
4189+
"type": "object",
4190+
"properties": {
4191+
"edges": {
4192+
"description": "Edges holds the relations/edges for other nodes in the graph.\nThe values are being populated by the UserGroupQuery when eager-loading is set.",
4193+
"allOf": [
4194+
{
4195+
"$ref": "#/definitions/ent.UserGroupEdges"
4196+
}
4197+
]
4198+
},
4199+
"group_id": {
4200+
"description": "GroupID holds the value of the \"group_id\" field.",
4201+
"type": "string"
4202+
},
4203+
"role": {
4204+
"description": "Role holds the value of the \"role\" field.",
4205+
"allOf": [
4206+
{
4207+
"$ref": "#/definitions/usergroup.Role"
4208+
}
4209+
]
4210+
},
4211+
"user_id": {
4212+
"description": "UserID holds the value of the \"user_id\" field.",
4213+
"type": "string"
4214+
}
4215+
}
4216+
},
4217+
"ent.UserGroupEdges": {
4218+
"type": "object",
4219+
"properties": {
4220+
"group": {
4221+
"description": "Group holds the value of the group edge.",
4222+
"allOf": [
4223+
{
4224+
"$ref": "#/definitions/ent.Group"
4225+
}
4226+
]
4227+
},
4228+
"user": {
4229+
"description": "User holds the value of the user edge.",
4230+
"allOf": [
4231+
{
4232+
"$ref": "#/definitions/ent.User"
4233+
}
4234+
]
41534235
}
41544236
}
41554237
},
@@ -5096,6 +5178,17 @@ const docTemplate = `{
50965178
}
50975179
}
50985180
},
5181+
"repo.FoundEntityContact": {
5182+
"type": "object",
5183+
"properties": {
5184+
"itemId": {
5185+
"type": "string"
5186+
},
5187+
"ownerEmail": {
5188+
"type": "string"
5189+
}
5190+
}
5191+
},
50995192
"repo.Group": {
51005193
"type": "object",
51015194
"properties": {
@@ -5647,9 +5740,6 @@ const docTemplate = `{
56475740
"id": {
56485741
"type": "string"
56495742
},
5650-
"isOwner": {
5651-
"type": "boolean"
5652-
},
56535743
"isSuperuser": {
56545744
"type": "boolean"
56555745
},
@@ -5673,9 +5763,6 @@ const docTemplate = `{
56735763
"id": {
56745764
"type": "string"
56755765
},
5676-
"isOwner": {
5677-
"type": "boolean"
5678-
},
56795766
"name": {
56805767
"type": "string"
56815768
}
@@ -5772,7 +5859,7 @@ const docTemplate = `{
57725859
"TypeTime"
57735860
]
57745861
},
5775-
"user.Role": {
5862+
"usergroup.Role": {
57765863
"type": "string",
57775864
"enum": [
57785865
"user",
@@ -5944,17 +6031,6 @@ const docTemplate = `{
59446031
}
59456032
}
59466033
},
5947-
"v1.GroupMemberAdd": {
5948-
"type": "object",
5949-
"required": [
5950-
"userId"
5951-
],
5952-
"properties": {
5953-
"userId": {
5954-
"type": "string"
5955-
}
5956-
}
5957-
},
59586034
"v1.LoginForm": {
59596035
"type": "object",
59606036
"properties": {

0 commit comments

Comments
 (0)