Skip to content

Commit 53ecaed

Browse files
committed
Fix messages
1 parent c37e484 commit 53ecaed

File tree

12 files changed

+325
-46
lines changed

12 files changed

+325
-46
lines changed

android/app/src/main/java/com/httpsms/FirebaseMessagingService.kt

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.httpsms
33
import android.app.PendingIntent
44
import android.content.Context
55
import android.content.Intent
6-
import android.content.IntentFilter
76
import androidx.work.OneTimeWorkRequest
87
import androidx.work.WorkManager
98
import androidx.work.Worker
@@ -75,8 +74,6 @@ class MyFirebaseMessagingService : FirebaseMessagingService() {
7574
val owner = Settings.getOwner(applicationContext) ?: return Result.failure()
7675
val message = getMessage(applicationContext, owner) ?: return Result.failure()
7776

78-
registerReceivers()
79-
8077
sendMessage(
8178
message,
8279
createPendingIntent(message, SmsManagerService.ACTION_SMS_SENT),
@@ -105,19 +102,6 @@ class MyFirebaseMessagingService : FirebaseMessagingService() {
105102
Timber.d("sent SMS for message with ID [${message.id}]")
106103
}
107104

108-
109-
private fun registerReceivers() {
110-
this.applicationContext.registerReceiver(
111-
SentReceiver(),
112-
IntentFilter(SmsManagerService.ACTION_SMS_SENT)
113-
)
114-
115-
this.applicationContext.registerReceiver(
116-
DeliveredReceiver(),
117-
IntentFilter(SmsManagerService.ACTION_SMS_DELIVERED)
118-
)
119-
}
120-
121105
private fun createPendingIntent(message: Message, action: String): PendingIntent {
122106
val intent = Intent(action)
123107
intent.putExtra(Constants.KEY_MESSAGE_ID, message.id)

android/app/src/main/java/com/httpsms/MainActivity.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import android.app.NotificationChannel
77
import android.app.NotificationManager
88
import android.content.Context
99
import android.content.Intent
10+
import android.content.IntentFilter
1011
import android.content.pm.PackageManager
1112
import android.os.Bundle
1213
import android.telephony.PhoneNumberUtils
@@ -40,6 +41,7 @@ class MainActivity : AppCompatActivity() {
4041
setActiveStatus(this)
4142
registerListeners()
4243
refreshToken(this)
44+
registerReceivers()
4345
}
4446

4547
override fun onResume() {
@@ -49,6 +51,18 @@ class MainActivity : AppCompatActivity() {
4951
refreshToken(this)
5052
}
5153

54+
private fun registerReceivers() {
55+
this.registerReceiver(
56+
SentReceiver(),
57+
IntentFilter(SmsManagerService.ACTION_SMS_SENT)
58+
)
59+
60+
this.registerReceiver(
61+
DeliveredReceiver(),
62+
IntentFilter(SmsManagerService.ACTION_SMS_DELIVERED)
63+
)
64+
}
65+
5266
private fun refreshToken(context: Context) {
5367
if(!Settings.isLoggedIn(context)) {
5468
Timber.w("cannot refresh token because owner is not logged in")

api/pkg/di/container.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,15 @@ func (container *Container) PhoneHandlerValidator() (validator *validators.Phone
258258
)
259259
}
260260

261+
// UserHandlerValidator creates a new instance of validators.UserHandlerValidator
262+
func (container *Container) UserHandlerValidator() (validator *validators.UserHandlerValidator) {
263+
container.logger.Debug(fmt.Sprintf("creating %T", validator))
264+
return validators.NewUserHandlerValidator(
265+
container.Logger(),
266+
container.Tracer(),
267+
)
268+
}
269+
261270
// EventDispatcher creates a new instance of services.EventDispatcher
262271
func (container *Container) EventDispatcher() (dispatcher *services.EventDispatcher) {
263272
if container.eventDispatcher != nil {
@@ -382,6 +391,7 @@ func (container *Container) UserHandler() (handler *handlers.UserHandler) {
382391
return handlers.NewUserHandler(
383392
container.Logger(),
384393
container.Tracer(),
394+
container.UserHandlerValidator(),
385395
container.UserService(),
386396
)
387397
}

api/pkg/handlers/user_handler.go

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ package handlers
33
import (
44
"fmt"
55

6+
"github.com/NdoleStudio/http-sms-manager/pkg/requests"
7+
"github.com/NdoleStudio/http-sms-manager/pkg/validators"
8+
"github.com/davecgh/go-spew/spew"
9+
610
"github.com/NdoleStudio/http-sms-manager/pkg/services"
711
"github.com/NdoleStudio/http-sms-manager/pkg/telemetry"
812
"github.com/gofiber/fiber/v2"
@@ -12,27 +16,31 @@ import (
1216
// UserHandler handles user http requests.
1317
type UserHandler struct {
1418
handler
15-
logger telemetry.Logger
16-
tracer telemetry.Tracer
17-
service *services.UserService
19+
logger telemetry.Logger
20+
tracer telemetry.Tracer
21+
validator *validators.UserHandlerValidator
22+
service *services.UserService
1823
}
1924

2025
// NewUserHandler creates a new UserHandler
2126
func NewUserHandler(
2227
logger telemetry.Logger,
2328
tracer telemetry.Tracer,
29+
validator *validators.UserHandlerValidator,
2430
service *services.UserService,
2531
) (h *UserHandler) {
2632
return &UserHandler{
27-
logger: logger.WithService(fmt.Sprintf("%T", h)),
28-
tracer: tracer,
29-
service: service,
33+
logger: logger.WithService(fmt.Sprintf("%T", h)),
34+
tracer: tracer,
35+
validator: validator,
36+
service: service,
3037
}
3138
}
3239

3340
// RegisterRoutes registers the routes for the MessageHandler
3441
func (h *UserHandler) RegisterRoutes(router fiber.Router) {
3542
router.Get("/users/me", h.Show)
43+
router.Put("/users/me", h.Update)
3644
}
3745

3846
// Show returns an entities.User
@@ -65,3 +73,46 @@ func (h *UserHandler) Show(c *fiber.Ctx) error {
6573

6674
return h.responseOK(c, "user fetched successfully", user)
6775
}
76+
77+
// Update an entities.User
78+
// @Summary Update a user
79+
// @Description Updates the details of the currently authenticated user
80+
// @Security ApiKeyAuth
81+
// @Tags Phones
82+
// @Accept json
83+
// @Produce json
84+
// @Param payload body requests.UserUpdate true "Payload of user details to update"
85+
// @Success 200 {object} responses.PhoneResponse
86+
// @Failure 400 {object} responses.BadRequest
87+
// @Failure 401 {object} responses.Unauthorized
88+
// @Failure 422 {object} responses.UnprocessableEntity
89+
// @Failure 500 {object} responses.InternalServerError
90+
// @Router /users/me [put]
91+
func (h *UserHandler) Update(c *fiber.Ctx) error {
92+
ctx, span := h.tracer.StartFromFiberCtx(c)
93+
defer span.End()
94+
95+
ctxLogger := h.tracer.CtxLogger(h.logger, span)
96+
97+
var request requests.UserUpdate
98+
if err := c.BodyParser(&request); err != nil {
99+
msg := fmt.Sprintf("cannot marshall params [%s] into %T", c.OriginalURL(), request)
100+
ctxLogger.Warn(stacktrace.Propagate(err, msg))
101+
return h.responseBadRequest(c, err)
102+
}
103+
104+
if errors := h.validator.ValidateUpdate(ctx, request.Sanitize()); len(errors) != 0 {
105+
msg := fmt.Sprintf("validation errors [%s], while updating user [%+#v]", spew.Sdump(errors), request)
106+
ctxLogger.Warn(stacktrace.NewError(msg))
107+
return h.responseUnprocessableEntity(c, errors, "validation errors while fetching phones")
108+
}
109+
110+
user, err := h.service.Update(ctx, h.userFromContext(c), request.ToUpdateParams())
111+
if err != nil {
112+
msg := fmt.Sprintf("cannot update user with params [%+#v]", request)
113+
ctxLogger.Error(stacktrace.Propagate(err, msg))
114+
return h.responseInternalServerError(c)
115+
}
116+
117+
return h.responseOK(c, "user updated successfully", user)
118+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package requests
2+
3+
import (
4+
"strings"
5+
6+
"github.com/google/uuid"
7+
8+
"github.com/NdoleStudio/http-sms-manager/pkg/services"
9+
)
10+
11+
// UserUpdate is the payload for updating a phone
12+
type UserUpdate struct {
13+
request
14+
ActivePhoneID string `json:"active_phone_id" example:"32343a19-da5e-4b1b-a767-3298a73703cb"`
15+
}
16+
17+
// Sanitize sets defaults to MessageOutstanding
18+
func (input *UserUpdate) Sanitize() UserUpdate {
19+
input.ActivePhoneID = strings.TrimSpace(input.ActivePhoneID)
20+
return *input
21+
}
22+
23+
// ToUpdateParams converts UserUpdate to services.UserUpdateParams
24+
func (input *UserUpdate) ToUpdateParams() services.UserUpdateParams {
25+
return services.UserUpdateParams{
26+
ActivePhoneID: uuid.MustParse(input.ActivePhoneID),
27+
}
28+
}

api/pkg/services/user_service.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66

77
"github.com/NdoleStudio/http-sms-manager/pkg/repositories"
8+
"github.com/google/uuid"
89
"github.com/palantir/stacktrace"
910

1011
"github.com/NdoleStudio/http-sms-manager/pkg/entities"
@@ -44,3 +45,32 @@ func (service *UserService) Get(ctx context.Context, authUser entities.AuthUser)
4445

4546
return user, nil
4647
}
48+
49+
// UserUpdateParams are parameters for updating an entities.User
50+
type UserUpdateParams struct {
51+
ActivePhoneID uuid.UUID
52+
}
53+
54+
// Update an entities.User
55+
func (service *UserService) Update(ctx context.Context, authUser entities.AuthUser, params UserUpdateParams) (*entities.User, error) {
56+
ctx, span := service.tracer.Start(ctx)
57+
defer span.End()
58+
59+
ctxLogger := service.tracer.CtxLogger(service.logger, span)
60+
61+
user, err := service.repository.LoadOrStore(ctx, authUser)
62+
if err != nil {
63+
msg := fmt.Sprintf("could not get [%T] with from [%+#v]", user, authUser)
64+
return nil, service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
65+
}
66+
67+
user.ActivePhoneID = &params.ActivePhoneID
68+
69+
if err = service.repository.Update(ctx, user); err != nil {
70+
msg := fmt.Sprintf("cannot save user with id [%s]", user.ID)
71+
return nil, service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
72+
}
73+
74+
ctxLogger.Info(fmt.Sprintf("user saved with id [%s] in the repository", user.ID))
75+
return user, nil
76+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package validators
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/url"
7+
8+
"github.com/NdoleStudio/http-sms-manager/pkg/requests"
9+
"github.com/NdoleStudio/http-sms-manager/pkg/telemetry"
10+
"github.com/thedevsaddam/govalidator"
11+
)
12+
13+
// UserHandlerValidator validates models used in handlers.UserHandler
14+
type UserHandlerValidator struct {
15+
logger telemetry.Logger
16+
tracer telemetry.Tracer
17+
}
18+
19+
// NewUserHandlerValidator creates a new handlers.UserHandler validator
20+
func NewUserHandlerValidator(
21+
logger telemetry.Logger,
22+
tracer telemetry.Tracer,
23+
) (v *UserHandlerValidator) {
24+
return &UserHandlerValidator{
25+
logger: logger.WithService(fmt.Sprintf("%T", v)),
26+
tracer: tracer,
27+
}
28+
}
29+
30+
// ValidateUpdate validates requests.UserUpdate
31+
func (validator *UserHandlerValidator) ValidateUpdate(_ context.Context, request requests.UserUpdate) url.Values {
32+
v := govalidator.New(govalidator.Options{
33+
Data: &request,
34+
Rules: govalidator.MapData{
35+
"active_phone_id": []string{
36+
"required",
37+
"uuid",
38+
},
39+
},
40+
})
41+
42+
return v.ValidateStruct()
43+
}

web/components/MessageThread.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
<template>
22
<v-list two-line class="px-0 py-0" subheader>
3+
<v-progress-linear
4+
v-if="$store.getters.getLoadingThreads"
5+
color="primary"
6+
indeterminate
7+
></v-progress-linear>
38
<v-list-item-group>
49
<template v-for="thread in threads">
510
<v-list-item

web/components/MessageThreadHeader.vue

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,29 @@
55
:color="$vuetify.breakpoint.lgAndUp ? 'grey darken-4' : 'primary'"
66
>
77
<div>
8-
<nuxt-link to="/" class="text-decoration-none text--primary">
9-
<v-toolbar-title>
10-
{{ $store.getters.getOwner | phoneNumber }}
11-
<v-progress-circular
12-
v-if="$store.getters.getPolling"
13-
indeterminate
14-
:size="14"
15-
:width="1"
16-
class="mt-n1"
17-
color="success"
18-
></v-progress-circular>
19-
</v-toolbar-title>
20-
</nuxt-link>
21-
<div class="d-flex">
8+
<v-toolbar-title>
9+
<div class="d-flex" style="width: 225px">
10+
<v-select
11+
outlined
12+
dense
13+
:items="owners"
14+
:value="$store.getters.getOwner"
15+
@change="onOwnerChanged"
16+
>
17+
</v-select>
18+
<div style="width: 50px">
19+
<v-progress-circular
20+
v-if="$store.getters.getPolling"
21+
indeterminate
22+
:size="20"
23+
:width="1"
24+
class="mt-3 ml-2"
25+
color="success"
26+
></v-progress-circular>
27+
</div>
28+
</div>
29+
</v-toolbar-title>
30+
<div class="d-flex mt-n4">
2231
<p class="text--secondary mb-n1">
2332
{{ $store.getters.getOwner | phoneCountry }}
2433
</p>
@@ -87,9 +96,32 @@
8796

8897
<script lang="ts">
8998
import { Vue, Component } from 'vue-property-decorator'
99+
import { SelectItem } from '~/types'
100+
import { Phone } from '~/models/phone'
90101
91102
@Component
92103
export default class MessageThreadHeader extends Vue {
104+
get owners(): Array<SelectItem> {
105+
return this.$store.getters.getPhones.map((phone: Phone): SelectItem => {
106+
return {
107+
text: this.$options.filters?.phoneNumber(phone.phone_number),
108+
value: phone.phone_number,
109+
}
110+
})
111+
}
112+
113+
async onOwnerChanged(owner: string) {
114+
console.log('owner changed')
115+
await this.$store.dispatch('setOwner', owner)
116+
if (this.$route.name !== 'threads') {
117+
await this.$store.dispatch('setThreadId', null)
118+
await this.$router.push({ name: 'threads' })
119+
return
120+
}
121+
122+
await this.$store.dispatch('loadThreads')
123+
}
124+
93125
logout(): void {
94126
this.$fire.auth.signOut().then(() => {
95127
this.$store.dispatch('setAuthUser', null)

0 commit comments

Comments
 (0)