| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 93d8ac9 commit 2b9a45f
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1117,6 +1117,7 @@ func (container *Container) PhoneHandler() (handler *handlers.PhoneHandler) { | |||
| 1117 | 1117 | container.Logger(), | |
| 1118 | 1118 | container.Tracer(), | |
| 1119 | 1119 | container.PhoneService(), | |
| 1120 | + container.MessageSendScheduleService(), | ||
| 1120 | 1121 | container.PhoneHandlerValidator(), | |
| 1121 | 1122 | ) | |
| 1122 | 1123 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -27,9 +27,14 @@ type MessageSendSchedule struct { | |||
| 27 | 27 | ||
| 28 | 28 | // ResolveScheduledAt returns the next allowed send time based on the schedule. | |
| 29 | 29 | // If the schedule is inactive, has no windows, or has an invalid timezone, | |
| 30 | - // the current time is returned in UTC. | ||
| 30 | + // the current time is returned in UTC. An active schedule with no windows | ||
| 31 | + // is treated as inactive (messages are sent immediately). | ||
| 31 | 32 | func (schedule *MessageSendSchedule) ResolveScheduledAt(current time.Time) time.Time { | |
| 32 | - if schedule == nil || !schedule.IsActive || len(schedule.Windows) == 0 { | ||
| 33 | + if schedule == nil || !schedule.IsActive { | ||
| 34 | + return current.UTC() | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + if len(schedule.Windows) == 0 { | ||
| 33 | 38 | return current.UTC() | |
| 34 | 39 | } | |
| 35 | 40 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -56,7 +56,7 @@ func (h *MessageSendScheduleHandler) RegisterRoutes(router fiber.Router, middlew | |||
| 56 | 56 | // @Security ApiKeyAuth | |
| 57 | 57 | // @Tags Send Schedules | |
| 58 | 58 | // @Produce json | |
| 59 | - // @Success 200 {array} entities.MessageSendSchedule | ||
| 59 | + // @Success 200 {object} responses.MessageSendSchedulesResponse | ||
| 60 | 60 | // @Failure 401 {object} responses.Unauthorized | |
| 61 | 61 | // @Failure 500 {object} responses.InternalServerError | |
| 62 | 62 | // @Router /send-schedules [get] | |
@@ -85,7 +85,7 @@ func (h *MessageSendScheduleHandler) Index(c *fiber.Ctx) error { | |||
| 85 | 85 | // @Success 201 {object} responses.MessageSendScheduleResponse | |
| 86 | 86 | // @Failure 400 {object} responses.BadRequest | |
| 87 | 87 | // @Failure 401 {object} responses.Unauthorized | |
| 88 | - // @Failure 402 {object} responses.BadRequest | ||
| 88 | + // @Failure 402 {object} responses.PaymentRequired | ||
| 89 | 89 | // @Failure 422 {object} responses.UnprocessableEntity | |
| 90 | 90 | // @Failure 500 {object} responses.InternalServerError | |
| 91 | 91 | // @Router /send-schedules [post] | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,10 +2,13 @@ package handlers | |||
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "fmt" | |
| 5 | + "net/url" | ||
| 6 | + "strings" | ||
| 5 | 7 | ||
| 6 | 8 | "github.com/NdoleStudio/httpsms/pkg/requests" | |
| 7 | 9 | "github.com/NdoleStudio/httpsms/pkg/validators" | |
| 8 | 10 | "github.com/davecgh/go-spew/spew" | |
| 11 | + "github.com/google/uuid" | ||
| 9 | 12 | ||
| 10 | 13 | "github.com/NdoleStudio/httpsms/pkg/services" | |
| 11 | 14 | "github.com/NdoleStudio/httpsms/pkg/telemetry" | |
@@ -16,24 +19,27 @@ import ( | |||
| 16 | 19 | // PhoneHandler handles phone http requests. | |
| 17 | 20 | type PhoneHandler struct { | |
| 18 | 21 | handler | |
| 19 | - logger telemetry.Logger | ||
| 20 | - tracer telemetry.Tracer | ||
| 21 | - service *services.PhoneService | ||
| 22 | - validator *validators.PhoneHandlerValidator | ||
| 22 | + logger telemetry.Logger | ||
| 23 | + tracer telemetry.Tracer | ||
| 24 | + service *services.PhoneService | ||
| 25 | + scheduleService *services.MessageSendScheduleService | ||
| 26 | + validator *validators.PhoneHandlerValidator | ||
| 23 | 27 | } | |
| 24 | 28 | ||
| 25 | 29 | // NewPhoneHandler creates a new PhoneHandler | |
| 26 | 30 | func NewPhoneHandler( | |
| 27 | 31 | logger telemetry.Logger, | |
| 28 | 32 | tracer telemetry.Tracer, | |
| 29 | 33 | service *services.PhoneService, | |
| 34 | + scheduleService *services.MessageSendScheduleService, | ||
| 30 | 35 | validator *validators.PhoneHandlerValidator, | |
| 31 | 36 | ) (h *PhoneHandler) { | |
| 32 | 37 | return &PhoneHandler{ | |
| 33 | - logger: logger.WithService(fmt.Sprintf("%T", h)), | ||
| 34 | - tracer: tracer, | ||
| 35 | - validator: validator, | ||
| 36 | - service: service, | ||
| 38 | + logger: logger.WithService(fmt.Sprintf("%T", h)), | ||
| 39 | + tracer: tracer, | ||
| 40 | + validator: validator, | ||
| 41 | + service: service, | ||
| 42 | + scheduleService: scheduleService, | ||
| 37 | 43 | } | |
| 38 | 44 | } | |
| 39 | 45 | ||
@@ -127,6 +133,15 @@ func (h *PhoneHandler) Upsert(c *fiber.Ctx) error { | |||
| 127 | 133 | return h.responseUnprocessableEntity(c, errors, "validation errors while updating phones") | |
| 128 | 134 | } | |
| 129 | 135 | ||
| 136 | + if request.ScheduleID != nil && strings.TrimSpace(*request.ScheduleID) != "" { | ||
| 137 | + scheduleID, _ := uuid.Parse(strings.TrimSpace(*request.ScheduleID)) | ||
| 138 | + if _, err := h.scheduleService.Load(ctx, h.userFromContext(c).ID, scheduleID); err != nil { | ||
| 139 | + validationErrors := url.Values{} | ||
| 140 | + validationErrors.Add("schedule_id", "schedule_id does not belong to the authenticated user or does not exist") | ||
| 141 | + return h.responseUnprocessableEntity(c, validationErrors, "validation errors while updating phones") | ||
| 142 | + } | ||
| 143 | + } | ||
| 144 | + | ||
| 130 | 145 | phone, err := h.service.Upsert(ctx, request.ToUpsertParams(h.userFromContext(c), c.OriginalURL())) | |
| 131 | 146 | if err != nil { | |
| 132 | 147 | msg := fmt.Sprintf("cannot update phones with params [%+#v]", request) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -31,7 +31,7 @@ type PhoneUpsert struct { | |||
| 31 | 31 | // SIM is the SIM slot of the phone in case the phone has more than 1 SIM slot | |
| 32 | 32 | SIM string `json:"sim" example:"SIM1"` | |
| 33 | 33 | ||
| 34 | - ScheduleID *string `json:"schedule_id" example:"32343a19-da5e-4b1b-a767-3298a73703cb"` | ||
| 34 | + ScheduleID *string `json:"schedule_id,omitempty" example:"32343a19-da5e-4b1b-a767-3298a73703cb" validate:"optional"` | ||
| 35 | 35 | } | |
| 36 | 36 | ||
| 37 | 37 | // Sanitize sets defaults to MessageOutstanding | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -38,6 +38,12 @@ type Unauthorized struct { | |||
| 38 | 38 | Data string `json:"data" example:"Make sure your API key is set in the [X-API-Key] header in the request"` | |
| 39 | 39 | } | |
| 40 | 40 | ||
| 41 | + // PaymentRequired is the response with status code is 402 | ||
| 42 | + type PaymentRequired struct { | ||
| 43 | + Status string `json:"status" example:"error"` | ||
| 44 | + Message string `json:"message" example:"You have reached the maximum number of allowed resources. Please upgrade your plan."` | ||
| 45 | + } | ||
| 46 | + | ||
| 41 | 47 | // NoContent is the response when status code is 204 | |
| 42 | 48 | type NoContent struct { | |
| 43 | 49 | Status string `json:"status" example:"success"` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1779,10 +1779,10 @@ export default Vue.extend({ | |||
| 1779 | 1779 | } | |
| 1780 | 1780 | ||
| 1781 | 1781 | const message = messages.find((x: string) => | |
| 1782 | - x.includes(`Day of week ${index}`), | ||
| 1782 | + x.includes(`day_of_week ${index}`), | ||
| 1783 | 1783 | ) | |
| 1784 | 1784 | return message | |
| 1785 | - ? message.replace(`Day of week ${index}`, this.getWeekday(index)) | ||
| 1785 | + ? message.replace(`day_of_week ${index}`, this.getWeekday(index)) | ||
| 1786 | 1786 | : null | |
| 1787 | 1787 | }, | |
| 1788 | 1788 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1111,23 +1111,17 @@ export const actions = { | |||
| 1111 | 1111 | getSendSchedules(context: ActionContext<State, State>) { | |
| 1112 | 1112 | return new Promise<Array<EntitiesSendSchedule>>((resolve, reject) => { | |
| 1113 | 1113 | axios | |
| 1114 | - .get<ResponsesSendSchedulesResponse>(`/v1/send-schedules`, { | ||
| 1115 | - params: { | ||
| 1116 | - limit: 100, | ||
| 1117 | - }, | ||
| 1118 | - }) | ||
| 1114 | + .get<ResponsesSendSchedulesResponse>(`/v1/send-schedules`) | ||
| 1119 | 1115 | .then((response: AxiosResponse<ResponsesSendSchedulesResponse>) => { | |
| 1120 | 1116 | resolve(response.data.data) | |
| 1121 | 1117 | }) | |
| 1122 | 1118 | .catch(async (error: AxiosError) => { | |
| 1123 | - await Promise.all([ | ||
| 1124 | - context.dispatch('addNotification', { | ||
| 1125 | - message: | ||
| 1126 | - (error.response?.data as any)?.message ?? | ||
| 1127 | - 'Error while fetching send schedules', | ||
| 1128 | - type: 'error', | ||
| 1129 | - }), | ||
| 1130 | - ]) | ||
| 1119 | + await context.dispatch('addNotification', { | ||
| 1120 | + message: | ||
| 1121 | + (error.response?.data as any)?.message ?? | ||
| 1122 | + 'Error while fetching send schedules', | ||
| 1123 | + type: 'error', | ||
| 1124 | + }) | ||
| 1131 | 1125 | reject(getErrorMessages(error)) | |
| 1132 | 1126 | }) | |
| 1133 | 1127 | }) | |
@@ -1144,14 +1138,12 @@ export const actions = { | |||
| 1144 | 1138 | resolve(response.data.data) | |
| 1145 | 1139 | }) | |
| 1146 | 1140 | .catch(async (error: AxiosError) => { | |
| 1147 | - await Promise.all([ | ||
| 1148 | - context.dispatch('addNotification', { | ||
| 1149 | - message: | ||
| 1150 | - (error.response?.data as any)?.message ?? | ||
| 1151 | - 'Error while creating send schedule', | ||
| 1152 | - type: 'error', | ||
| 1153 | - }), | ||
| 1154 | - ]) | ||
| 1141 | + await context.dispatch('addNotification', { | ||
| 1142 | + message: | ||
| 1143 | + (error.response?.data as any)?.message ?? | ||
| 1144 | + 'Error while creating send schedule', | ||
| 1145 | + type: 'error', | ||
| 1146 | + }) | ||
| 1155 | 1147 | reject(getErrorMessages(error)) | |
| 1156 | 1148 | }) | |
| 1157 | 1149 | }) | |
@@ -1171,38 +1163,31 @@ export const actions = { | |||
| 1171 | 1163 | resolve(response.data.data) | |
| 1172 | 1164 | }) | |
| 1173 | 1165 | .catch(async (error: AxiosError) => { | |
| 1174 | - await Promise.all([ | ||
| 1175 | - context.dispatch('addNotification', { | ||
| 1176 | - message: | ||
| 1177 | - (error.response?.data as any)?.message ?? | ||
| 1178 | - 'Error while updating send schedule', | ||
| 1179 | - type: 'error', | ||
| 1180 | - }), | ||
| 1181 | - ]) | ||
| 1166 | + await context.dispatch('addNotification', { | ||
| 1167 | + message: | ||
| 1168 | + (error.response?.data as any)?.message ?? | ||
| 1169 | + 'Error while updating send schedule', | ||
| 1170 | + type: 'error', | ||
| 1171 | + }) | ||
| 1182 | 1172 | reject(getErrorMessages(error)) | |
| 1183 | 1173 | }) | |
| 1184 | 1174 | }) | |
| 1185 | 1175 | }, | |
| 1186 | 1176 | ||
| 1187 | - deleteSendSchedule( | ||
| 1188 | - context: ActionContext<State, State>, | ||
| 1189 | - payload: string, | ||
| 1190 | - ) { | ||
| 1177 | + deleteSendSchedule(context: ActionContext<State, State>, payload: string) { | ||
| 1191 | 1178 | return new Promise<void>((resolve, reject) => { | |
| 1192 | 1179 | axios | |
| 1193 | 1180 | .delete<ResponsesNoContent>(`/v1/send-schedules/${payload}`) | |
| 1194 | 1181 | .then(() => { | |
| 1195 | 1182 | resolve() | |
| 1196 | 1183 | }) | |
| 1197 | 1184 | .catch(async (error: AxiosError) => { | |
| 1198 | - await Promise.all([ | ||
| 1199 | - context.dispatch('addNotification', { | ||
| 1200 | - message: | ||
| 1201 | - (error.response?.data as any)?.message ?? | ||
| 1202 | - 'Error while deleting send schedule', | ||
| 1203 | - type: 'error', | ||
| 1204 | - }), | ||
| 1205 | - ]) | ||
| 1185 | + await context.dispatch('addNotification', { | ||
| 1186 | + message: | ||
| 1187 | + (error.response?.data as any)?.message ?? | ||
| 1188 | + 'Error while deleting send schedule', | ||
| 1189 | + type: 'error', | ||
| 1190 | + }) | ||
| 1206 | 1191 | reject(getErrorMessages(error)) | |
| 1207 | 1192 | }) | |
| 1208 | 1193 | }) | |
| Back | FazBrowse Home | New Git URL |
0 commit comments