| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 909dc4a commit f2e2d76
15 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -41,11 +41,55 @@ func NewPhoneAPIKeyHandler( | |||
| 41 | 41 | // RegisterRoutes registers the routes for the PhoneAPIKeyHandler | |
| 42 | 42 | func (h *PhoneAPIKeyHandler) RegisterRoutes(app *fiber.App, middlewares ...fiber.Handler) { | |
| 43 | 43 | router := app.Group("/v1/api-keys/") | |
| 44 | + router.Get("/", h.computeRoute(middlewares, h.Index)...) | ||
| 44 | 45 | router.Post("/", h.computeRoute(middlewares, h.Store)...) | |
| 45 | 46 | router.Delete("/:phoneAPIKeyID", h.computeRoute(middlewares, h.Delete)...) | |
| 46 | 47 | router.Delete("/:phoneAPIKeyID/phones/:phoneID", h.computeRoute(middlewares, h.DeletePhone)...) | |
| 47 | 48 | } | |
| 48 | 49 | ||
| 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 | + | ||
| 49 | 93 | // Store a new Phone API key | |
| 50 | 94 | // @Summary Store phone API key | |
| 51 | 95 | // @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 | |||
| 54 | 98 | // @Accept json | |
| 55 | 99 | // @Produce json | |
| 56 | 100 | // @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 | ||
| 58 | 102 | // @Failure 400 {object} responses.BadRequest | |
| 59 | 103 | // @Failure 401 {object} responses.Unauthorized | |
| 60 | 104 | // @Failure 422 {object} responses.UnprocessableEntity | |
| 61 | 105 | // @Failure 500 {object} responses.InternalServerError | |
| 62 | 106 | // @Router /api-keys [post] | |
| 63 | 107 | 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) | ||
| 65 | 109 | defer span.End() | |
| 66 | 110 | ||
| 67 | - ctxLogger := h.tracer.CtxLogger(h.logger, span) | ||
| 68 | - | ||
| 69 | 111 | var request requests.PhoneAPIKeyStoreRequest | |
| 70 | 112 | if err := c.BodyParser(&request); err != nil { | |
| 71 | 113 | msg := fmt.Sprintf("cannot marshall params [%s] into %T", c.OriginalURL(), request) | |
| Original file line number | Diff line number | Diff 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 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,7 +17,7 @@ type PhoneIndex struct { | |||
| 17 | 17 | // Sanitize sets defaults to MessageOutstanding | |
| 18 | 18 | func (input *PhoneIndex) Sanitize() PhoneIndex { | |
| 19 | 19 | if strings.TrimSpace(input.Limit) == "" { | |
| 20 | - input.Limit = "1" | ||
| 20 | + input.Limit = "10" | ||
| 21 | 21 | } | |
| 22 | 22 | input.Query = strings.TrimSpace(input.Query) | |
| 23 | 23 | input.Skip = strings.TrimSpace(input.Skip) | |
| Original file line number | Diff line number | Diff 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 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -38,6 +38,21 @@ func NewPhoneAPIKeyService( | |||
| 38 | 38 | } | |
| 39 | 39 | } | |
| 40 | 40 | ||
| 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 | + | ||
| 41 | 56 | // Create a new entities.PhoneAPIKey | |
| 42 | 57 | func (service *PhoneAPIKeyService) Create(ctx context.Context, authContext entities.AuthContext, name string) (*entities.PhoneAPIKey, error) { | |
| 43 | 58 | ctx, span, ctxLogger := service.tracer.StartWithLogger(ctx, service.logger) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -34,6 +34,7 @@ func (validator *PhoneAPIKeyHandlerValidator) ValidateStore(_ context.Context, r | |||
| 34 | 34 | Data: &request, | |
| 35 | 35 | Rules: govalidator.MapData{ | |
| 36 | 36 | "name": []string{ | |
| 37 | + "required", | ||
| 37 | 38 | "min:1", | |
| 38 | 39 | "max:60", | |
| 39 | 40 | }, | |
@@ -42,3 +43,27 @@ func (validator *PhoneAPIKeyHandlerValidator) ValidateStore(_ context.Context, r | |||
| 42 | 43 | ||
| 43 | 44 | return v.ValidateStruct() | |
| 44 | 45 | } | |
| 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 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -163,6 +163,18 @@ | |||
| 163 | 163 | </v-list-item-title> | |
| 164 | 164 | </v-list-item-content> | |
| 165 | 165 | </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> | ||
| 166 | 178 | <v-list-item | |
| 167 | 179 | v-if="$store.getters.getOwner" | |
| 168 | 180 | :href="$store.getters.getAppData.appDownloadUrl" | |
@@ -221,6 +233,7 @@ import { | |||
| 221 | 233 | mdiPlus, | |
| 222 | 234 | mdiAccountCog, | |
| 223 | 235 | mdiLogout, | |
| 236 | + mdiCellphoneKey, | ||
| 224 | 237 | mdiDownload, | |
| 225 | 238 | mdiFinance, | |
| 226 | 239 | mdiBatteryChargingHigh, | |
@@ -241,6 +254,7 @@ export default class MessageThreadHeader extends Vue { | |||
| 241 | 254 | mdiAccountCog = mdiAccountCog | |
| 242 | 255 | mdiLogout = mdiLogout | |
| 243 | 256 | mdiDownload = mdiDownload | |
| 257 | + mdiCellphoneKey = mdiCellphoneKey | ||
| 244 | 258 | mdiPackageUp = mdiPackageUp | |
| 245 | 259 | mdiCommentTextMultipleOutline = mdiCommentTextMultipleOutline | |
| 246 | 260 | mdiFinance = mdiFinance | |
| Back | FazBrowse Home | New Git URL |
0 commit comments