Skip to content

Commit ab04eb8

Browse files
committed
Add code to update messages per minute
1 parent 05c9e92 commit ab04eb8

File tree

5 files changed

+174
-28
lines changed

5 files changed

+174
-28
lines changed

api/pkg/requests/phone_update_request.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import (
1212
// PhoneUpsert is the payload for updating a phone
1313
type PhoneUpsert struct {
1414
request
15-
PhoneNumber string `json:"phone_number" example:"+18005550199"`
16-
FcmToken string `json:"fcm_token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzd....."`
15+
MessagesPerMinute uint `json:"messages_per_minute" example:"1"`
16+
PhoneNumber string `json:"phone_number" example:"+18005550199"`
17+
FcmToken string `json:"fcm_token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzd....."`
1718
}
1819

1920
// Sanitize sets defaults to MessageOutstanding
@@ -26,9 +27,23 @@ func (input *PhoneUpsert) Sanitize() PhoneUpsert {
2627
// ToUpsertParams converts PhoneUpsert to services.PhoneUpsertParams
2728
func (input *PhoneUpsert) ToUpsertParams(user entities.AuthUser) services.PhoneUpsertParams {
2829
phone, _ := phonenumbers.Parse(input.PhoneNumber, phonenumbers.UNKNOWN_REGION)
30+
31+
// ignore value if it's default
32+
var messagesPerMinute *uint
33+
if input.MessagesPerMinute != 0 {
34+
messagesPerMinute = &input.MessagesPerMinute
35+
}
36+
37+
// ignore default
38+
var fcmToken *string
39+
if input.FcmToken != "" {
40+
fcmToken = &input.FcmToken
41+
}
42+
2943
return services.PhoneUpsertParams{
30-
PhoneNumber: *phone,
31-
FcmToken: input.FcmToken,
32-
UserID: user.ID,
44+
PhoneNumber: *phone,
45+
MessagesPerMinute: messagesPerMinute,
46+
FcmToken: fcmToken,
47+
UserID: user.ID,
3348
}
3449
}

api/pkg/services/phone_service.go

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,10 @@ func (service *PhoneService) Index(ctx context.Context, authUser entities.AuthUs
5454

5555
// PhoneUpsertParams are parameters for creating a new entities.Phone
5656
type PhoneUpsertParams struct {
57-
PhoneNumber phonenumbers.PhoneNumber
58-
FcmToken string
59-
UserID entities.UserID
57+
PhoneNumber phonenumbers.PhoneNumber
58+
FcmToken *string
59+
MessagesPerMinute *uint
60+
UserID entities.UserID
6061
}
6162

6263
// Upsert a new entities.Phone
@@ -76,8 +77,7 @@ func (service *PhoneService) Upsert(ctx context.Context, params PhoneUpsertParam
7677
return nil, service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
7778
}
7879

79-
phone.FcmToken = &params.FcmToken
80-
if err = service.repository.Save(ctx, phone); err != nil {
80+
if err = service.repository.Save(ctx, service.update(phone, params)); err != nil {
8181
msg := fmt.Sprintf("cannot update phone with id [%s] and number [%s]", phone.ID, phone.PhoneNumber)
8282
return nil, service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
8383
}
@@ -86,6 +86,16 @@ func (service *PhoneService) Upsert(ctx context.Context, params PhoneUpsertParam
8686
return phone, nil
8787
}
8888

89+
func (service *PhoneService) update(phone *entities.Phone, params PhoneUpsertParams) *entities.Phone {
90+
if phone.FcmToken != nil {
91+
phone.FcmToken = params.FcmToken
92+
}
93+
if params.MessagesPerMinute != nil {
94+
phone.MessagesPerMinute = *params.MessagesPerMinute
95+
}
96+
return phone
97+
}
98+
8999
// Delete an entities.Phone
90100
func (service *PhoneService) Delete(ctx context.Context, userID entities.UserID, phoneID uuid.UUID) error {
91101
ctx, span := service.tracer.Start(ctx)
@@ -109,12 +119,13 @@ func (service *PhoneService) createPhone(ctx context.Context, params PhoneUpsert
109119
defer span.End()
110120

111121
phone := &entities.Phone{
112-
ID: uuid.New(),
113-
UserID: params.UserID,
114-
FcmToken: &params.FcmToken,
115-
PhoneNumber: phonenumbers.Format(&params.PhoneNumber, phonenumbers.E164),
116-
CreatedAt: time.Now().UTC(),
117-
UpdatedAt: time.Now().UTC(),
122+
ID: uuid.New(),
123+
UserID: params.UserID,
124+
FcmToken: params.FcmToken,
125+
MessagesPerMinute: 0,
126+
PhoneNumber: phonenumbers.Format(&params.PhoneNumber, phonenumbers.E164),
127+
CreatedAt: time.Now().UTC(),
128+
UpdatedAt: time.Now().UTC(),
118129
}
119130

120131
if err := service.repository.Save(ctx, phone); err != nil {

api/pkg/validators/phone_handler_validator.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ func (validator *PhoneHandlerValidator) ValidateUpsert(_ context.Context, reques
6666
"min:1",
6767
"max:1000",
6868
},
69+
"messages_per_minute": []string{
70+
"required",
71+
"min:1",
72+
"max:60",
73+
},
6974
},
7075
})
7176

web/pages/settings/index.vue

Lines changed: 118 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,28 @@
1010
<v-container>
1111
<v-row>
1212
<v-col cols="12" md="9" offset-md="1" xl="8" offset-xl="2">
13+
<div v-if="$fire.auth.currentUser" class="text-center">
14+
<v-avatar size="100" color="indigo" class="mx-auto">
15+
<img
16+
v-if="$fire.auth.currentUser.photoURL"
17+
:src="$fire.auth.currentUser.photoURL"
18+
:alt="$fire.auth.currentUser.displayName"
19+
/>
20+
<v-icon v-else dark size="70"> mdi-account-circle </v-icon>
21+
</v-avatar>
22+
<h3 v-if="$fire.auth.currentUser.displayName">
23+
{{ $fire.auth.currentUser.displayName }}
24+
</h3>
25+
<h4 class="text--secondary">
26+
{{ $fire.auth.currentUser.email }}
27+
<v-icon
28+
v-if="$fire.auth.currentUser.emailVerified"
29+
small
30+
color="primary"
31+
>mdi-shield-check</v-icon
32+
>
33+
</h4>
34+
</div>
1335
<h5 class="text-h4 mb-3 mt-3">API Key</h5>
1436
<p>
1537
Use your API Key in the <code>x-api-key</code> HTTP Header when
@@ -92,13 +114,13 @@
92114
<v-btn
93115
:icon="$vuetify.breakpoint.mdAndDown"
94116
small
95-
color="error"
96-
:disabled="deletingPhone"
97-
@click.prevent="deletePhone(phone.id)"
117+
color="info"
118+
:disabled="updatingPhone"
119+
@click.prevent="showEditPhone(phone.id)"
98120
>
99-
<v-icon small>mdi-delete</v-icon>
121+
<v-icon small>mdi-square-edit-outline</v-icon>
100122
<span v-if="!$vuetify.breakpoint.mdAndDown">
101-
Delete
123+
Edit
102124
</span>
103125
</v-btn>
104126
</td>
@@ -110,17 +132,79 @@
110132
</v-row>
111133
</v-container>
112134
</div>
135+
<v-dialog v-model="showPhoneEdit" max-width="500px">
136+
<v-card>
137+
<v-card-text v-if="activePhone" class="mt-6">
138+
<v-container>
139+
<v-row>
140+
<v-col>
141+
<v-text-field
142+
outlined
143+
dense
144+
disabled
145+
label="ID"
146+
:value="activePhone.id"
147+
>
148+
</v-text-field>
149+
<v-text-field
150+
outlined
151+
disabled
152+
dense
153+
label="Phone Number"
154+
:value="activePhone.phone_number"
155+
>
156+
</v-text-field>
157+
<v-textarea
158+
outlined
159+
disabled
160+
dense
161+
label="FCM Token"
162+
:value="activePhone.fcm_token"
163+
>
164+
</v-textarea>
165+
<v-text-field
166+
v-model="activePhone.messages_per_minute"
167+
outlined
168+
type="number"
169+
dense
170+
label="Messages Per Minute"
171+
>
172+
</v-text-field>
173+
</v-col>
174+
</v-row>
175+
</v-container>
176+
</v-card-text>
177+
<v-card-actions class="mt-n8">
178+
<v-btn small color="info" @click="updatePhone">
179+
<v-icon v-if="$vuetify.breakpoint.lgAndUp" small
180+
>mdi-content-save</v-icon
181+
>
182+
Update
183+
</v-btn>
184+
<v-spacer></v-spacer>
185+
<v-btn small color="error" text @click="deletePhone(activePhone.id)">
186+
<v-icon v-if="$vuetify.breakpoint.lgAndUp" small>mdi-delete</v-icon>
187+
Delete
188+
</v-btn>
189+
</v-card-actions>
190+
</v-card>
191+
</v-dialog>
113192
</v-container>
114193
</template>
115194

116-
<script>
117-
export default {
195+
<script lang="ts">
196+
import Vue from 'vue'
197+
import { Phone } from '~/models/phone'
198+
199+
export default Vue.extend({
118200
name: 'SettingsIndex',
119201
middleware: ['auth'],
120202
data() {
121203
return {
122204
apiKeyShow: false,
123-
deletingPhone: false,
205+
showPhoneEdit: false,
206+
activePhone: null,
207+
updatingPhone: false,
124208
}
125209
},
126210
computed: {
@@ -141,12 +225,34 @@ export default {
141225
},
142226
143227
methods: {
144-
deletePhone(phoneId) {
145-
this.deletingPhone = true
228+
showEditPhone(phoneId: string) {
229+
const phone = this.$store.getters.getPhones.find(
230+
(x: Phone) => x.id === phoneId
231+
)
232+
if (!phone) {
233+
return
234+
}
235+
this.activePhone = { ...phone }
236+
this.showPhoneEdit = true
237+
},
238+
239+
updatePhone() {
240+
this.updatingPhone = true
241+
this.$store.dispatch('updatePhone', this.activePhone).finally(() => {
242+
this.updatingPhone = false
243+
this.showPhoneEdit = false
244+
this.activePhone = null
245+
})
246+
},
247+
248+
deletePhone(phoneId: string) {
249+
this.updatingPhone = true
146250
this.$store.dispatch('deletePhone', phoneId).finally(() => {
147-
this.deletingPhone = false
251+
this.updatingPhone = false
252+
this.showPhoneEdit = false
253+
this.activePhone = null
148254
})
149255
},
150256
},
151-
}
257+
})
152258
</script>

web/store/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,15 @@ export const actions = {
285285
context.commit('resetState', false)
286286
},
287287

288+
async updatePhone(context: ActionContext<State, State>, phone: Phone) {
289+
await axios.put(`/v1/phones`, {
290+
fcm_token: phone.fcm_token,
291+
phone_number: phone.phone_number,
292+
messages_per_minute: parseInt(phone.messages_per_minute.toString()),
293+
})
294+
await context.dispatch('loadPhones', true)
295+
},
296+
288297
async getHeartbeat(context: ActionContext<State, State>) {
289298
const response = await axios.get('/v1/heartbeats', {
290299
params: {

0 commit comments

Comments
 (0)