Skip to content

Commit f2e2d76

Browse files
committed
Add page for managing phone API keys
1 parent 909dc4a commit f2e2d76

File tree

15 files changed

+2137
-32
lines changed

15 files changed

+2137
-32
lines changed

api/docs/docs.go

Lines changed: 505 additions & 1 deletion
Large diffs are not rendered by default.

api/docs/swagger.json

Lines changed: 458 additions & 1 deletion
Large diffs are not rendered by default.

api/docs/swagger.yaml

Lines changed: 353 additions & 1 deletion
Large diffs are not rendered by default.

api/pkg/handlers/phone_api_key_handler.go

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,55 @@ func NewPhoneAPIKeyHandler(
4141
// RegisterRoutes registers the routes for the PhoneAPIKeyHandler
4242
func (h *PhoneAPIKeyHandler) RegisterRoutes(app *fiber.App, middlewares ...fiber.Handler) {
4343
router := app.Group("/v1/api-keys/")
44+
router.Get("/", h.computeRoute(middlewares, h.Index)...)
4445
router.Post("/", h.computeRoute(middlewares, h.Store)...)
4546
router.Delete("/:phoneAPIKeyID", h.computeRoute(middlewares, h.Delete)...)
4647
router.Delete("/:phoneAPIKeyID/phones/:phoneID", h.computeRoute(middlewares, h.DeletePhone)...)
4748
}
4849

50+
// Index returns the phone API Keys of a user
51+
// @Summary Get the phone API keys of a user
52+
// @Description Get list phone API keys which a user has registered on the httpSMS application
53+
// @Security ApiKeyAuth
54+
// @Tags PhoneAPIKeys
55+
// @Accept json
56+
// @Produce json
57+
// @Param skip query int false "number of heartbeats to skip" minimum(0)
58+
// @Param query query string false "filter api keys with name containing query"
59+
// @Param limit query int false "number of phone api keys to return" minimum(1) maximum(100)
60+
// @Success 200 {object} responses.PhoneAPIKeysResponse
61+
// @Failure 400 {object} responses.BadRequest
62+
// @Failure 401 {object} responses.Unauthorized
63+
// @Failure 422 {object} responses.UnprocessableEntity
64+
// @Failure 500 {object} responses.InternalServerError
65+
// @Router /api-keys [get]
66+
func (h *PhoneAPIKeyHandler) Index(c *fiber.Ctx) error {
67+
ctx, span, ctxLogger := h.tracer.StartFromFiberCtxWithLogger(c, h.logger)
68+
defer span.End()
69+
70+
var request requests.PhoneAPIKeyIndex
71+
if err := c.QueryParser(&request); err != nil {
72+
msg := fmt.Sprintf("cannot marshall params [%s] into %T", c.OriginalURL(), request)
73+
ctxLogger.Warn(stacktrace.Propagate(err, msg))
74+
return h.responseBadRequest(c, err)
75+
}
76+
77+
if errors := h.validator.ValidateIndex(ctx, request.Sanitize()); len(errors) != 0 {
78+
msg := fmt.Sprintf("validation errors [%s], while fetching phone API keys [%+#v]", spew.Sdump(errors), request)
79+
ctxLogger.Warn(stacktrace.NewError(msg))
80+
return h.responseUnprocessableEntity(c, errors, "validation errors while fetching phone API keys")
81+
}
82+
83+
apiKeys, err := h.service.Index(ctx, h.userIDFomContext(c), request.ToIndexParams())
84+
if err != nil {
85+
msg := fmt.Sprintf("cannot index phone API keys with params [%+#v]", request)
86+
ctxLogger.Error(stacktrace.Propagate(err, msg))
87+
return h.responseInternalServerError(c)
88+
}
89+
90+
return h.responseOK(c, fmt.Sprintf("fetched %d phone API %s", len(apiKeys), h.pluralize("key", len(apiKeys))), apiKeys)
91+
}
92+
4993
// Store a new Phone API key
5094
// @Summary Store phone API key
5195
// @Description Creates a new phone API key which can be used to log in to the httpSMS app on your Android phone
@@ -54,18 +98,16 @@ func (h *PhoneAPIKeyHandler) RegisterRoutes(app *fiber.App, middlewares ...fiber
5498
// @Accept json
5599
// @Produce json
56100
// @Param payload body requests.PhoneAPIKeyStoreRequest true "Payload of new phone API key."
57-
// @Success 200 {object} responses.Ok[*entities.PhoneAPIKey]
101+
// @Success 200 {object} responses.PhoneAPIKeyResponse
58102
// @Failure 400 {object} responses.BadRequest
59103
// @Failure 401 {object} responses.Unauthorized
60104
// @Failure 422 {object} responses.UnprocessableEntity
61105
// @Failure 500 {object} responses.InternalServerError
62106
// @Router /api-keys [post]
63107
func (h *PhoneAPIKeyHandler) Store(c *fiber.Ctx) error {
64-
ctx, span := h.tracer.StartFromFiberCtx(c)
108+
ctx, span, ctxLogger := h.tracer.StartFromFiberCtxWithLogger(c, h.logger)
65109
defer span.End()
66110

67-
ctxLogger := h.tracer.CtxLogger(h.logger, span)
68-
69111
var request requests.PhoneAPIKeyStoreRequest
70112
if err := c.BodyParser(&request); err != nil {
71113
msg := fmt.Sprintf("cannot marshall params [%s] into %T", c.OriginalURL(), request)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package requests
2+
3+
import (
4+
"strings"
5+
6+
"github.com/NdoleStudio/httpsms/pkg/repositories"
7+
)
8+
9+
// PhoneAPIKeyIndex is the payload for fetching entities.PhoneAPIKey of a user
10+
type PhoneAPIKeyIndex struct {
11+
request
12+
Skip string `json:"skip" query:"skip"`
13+
Query string `json:"query" query:"query"`
14+
Limit string `json:"limit" query:"limit"`
15+
}
16+
17+
// Sanitize sets defaults to MessageOutstanding
18+
func (input *PhoneAPIKeyIndex) Sanitize() PhoneAPIKeyIndex {
19+
if strings.TrimSpace(input.Limit) == "" {
20+
input.Limit = "1"
21+
}
22+
input.Query = strings.TrimSpace(input.Query)
23+
input.Skip = strings.TrimSpace(input.Skip)
24+
if input.Skip == "" {
25+
input.Skip = "0"
26+
}
27+
return *input
28+
}
29+
30+
// ToIndexParams converts HeartbeatIndex to repositories.IndexParams
31+
func (input *PhoneAPIKeyIndex) ToIndexParams() repositories.IndexParams {
32+
return repositories.IndexParams{
33+
Skip: input.getInt(input.Skip),
34+
Query: input.Query,
35+
Limit: input.getInt(input.Limit),
36+
}
37+
}

api/pkg/requests/phone_index_request.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type PhoneIndex struct {
1717
// Sanitize sets defaults to MessageOutstanding
1818
func (input *PhoneIndex) Sanitize() PhoneIndex {
1919
if strings.TrimSpace(input.Limit) == "" {
20-
input.Limit = "1"
20+
input.Limit = "10"
2121
}
2222
input.Query = strings.TrimSpace(input.Query)
2323
input.Skip = strings.TrimSpace(input.Skip)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package responses
2+
3+
import "github.com/NdoleStudio/httpsms/pkg/entities"
4+
5+
// PhoneAPIKeyResponse is the payload containing an entities.PhoneAPIKey
6+
type PhoneAPIKeyResponse struct {
7+
response
8+
Data entities.PhoneAPIKey `json:"data"`
9+
}
10+
11+
// PhoneAPIKeysResponse is the payload containing []entities.PhoneAPIKey
12+
type PhoneAPIKeysResponse struct {
13+
response
14+
Data []entities.PhoneAPIKey `json:"data"`
15+
}

api/pkg/services/phone_api_key_service.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,21 @@ func NewPhoneAPIKeyService(
3838
}
3939
}
4040

41+
// Index fetches the entities.Webhook for an entities.UserID
42+
func (service *PhoneAPIKeyService) Index(ctx context.Context, userID entities.UserID, params repositories.IndexParams) ([]*entities.PhoneAPIKey, error) {
43+
ctx, span, ctxLogger := service.tracer.StartWithLogger(ctx, service.logger)
44+
defer span.End()
45+
46+
phoneAPIKeys, err := service.repository.Index(ctx, userID, params)
47+
if err != nil {
48+
msg := fmt.Sprintf("could not fetch phone API Keys with params [%+#v]", params)
49+
return nil, service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
50+
}
51+
52+
ctxLogger.Info(fmt.Sprintf("fetched [%d] phone API Keys with prams [%+#v]", len(phoneAPIKeys), params))
53+
return phoneAPIKeys, nil
54+
}
55+
4156
// Create a new entities.PhoneAPIKey
4257
func (service *PhoneAPIKeyService) Create(ctx context.Context, authContext entities.AuthContext, name string) (*entities.PhoneAPIKey, error) {
4358
ctx, span, ctxLogger := service.tracer.StartWithLogger(ctx, service.logger)

api/pkg/validators/phone_api_key_handler_validator.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ func (validator *PhoneAPIKeyHandlerValidator) ValidateStore(_ context.Context, r
3434
Data: &request,
3535
Rules: govalidator.MapData{
3636
"name": []string{
37+
"required",
3738
"min:1",
3839
"max:60",
3940
},
@@ -42,3 +43,27 @@ func (validator *PhoneAPIKeyHandlerValidator) ValidateStore(_ context.Context, r
4243

4344
return v.ValidateStruct()
4445
}
46+
47+
// ValidateIndex validates the requests.HeartbeatIndex request
48+
func (validator *PhoneAPIKeyHandlerValidator) ValidateIndex(_ context.Context, request requests.PhoneAPIKeyIndex) url.Values {
49+
v := govalidator.New(govalidator.Options{
50+
Data: &request,
51+
Rules: govalidator.MapData{
52+
"limit": []string{
53+
"required",
54+
"numeric",
55+
"min:1",
56+
"max:100",
57+
},
58+
"skip": []string{
59+
"required",
60+
"numeric",
61+
"min:0",
62+
},
63+
"query": []string{
64+
"max:100",
65+
},
66+
},
67+
})
68+
return v.ValidateStruct()
69+
}

web/components/MessageThreadHeader.vue

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,18 @@
163163
</v-list-item-title>
164164
</v-list-item-content>
165165
</v-list-item>
166+
<v-list-item :to="{ name: 'phone-api-keys' }" exact>
167+
<v-list-item-icon class="pl-2">
168+
<v-icon dense>{{ mdiCellphoneKey }}</v-icon>
169+
</v-list-item-icon>
170+
<v-list-item-content class="ml-n3">
171+
<v-list-item-title class="pr-16 py-1">
172+
<span :class="{ 'pr-16': $vuetify.breakpoint.mdAndUp }">
173+
Phone API Keys
174+
</span>
175+
</v-list-item-title>
176+
</v-list-item-content>
177+
</v-list-item>
166178
<v-list-item
167179
v-if="$store.getters.getOwner"
168180
:href="$store.getters.getAppData.appDownloadUrl"
@@ -221,6 +233,7 @@ import {
221233
mdiPlus,
222234
mdiAccountCog,
223235
mdiLogout,
236+
mdiCellphoneKey,
224237
mdiDownload,
225238
mdiFinance,
226239
mdiBatteryChargingHigh,
@@ -241,6 +254,7 @@ export default class MessageThreadHeader extends Vue {
241254
mdiAccountCog = mdiAccountCog
242255
mdiLogout = mdiLogout
243256
mdiDownload = mdiDownload
257+
mdiCellphoneKey = mdiCellphoneKey
244258
mdiPackageUp = mdiPackageUp
245259
mdiCommentTextMultipleOutline = mdiCommentTextMultipleOutline
246260
mdiFinance = mdiFinance

0 commit comments

Comments
 (0)