Add Device Token Support for Customer and User Entities

- Introduced a new DeviceToken field in both Customer and User entities to store device tokens for authentication and notifications.
- Updated LoginForm structures for both Customer and User to include an optional DeviceToken field, allowing clients to send device tokens during login.
- Enhanced the Login methods in the customer and user services to append the device token to the respective entities if it does not already exist, improving user session management and notification capabilities.
- Ensured proper validation and structured responses for the new DeviceToken field in the forms, maintaining compliance with best practices for API design.
This commit is contained in:
n.nakhostin
2025-09-20 10:11:36 +03:30
parent 00ad7e136d
commit dfcdef60d6
9 changed files with 48 additions and 7 deletions
+10 -1
View File
@@ -2057,7 +2057,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"Admin Flags"
"Admin-Flags"
],
"summary": "Get flag by country code (Admin)",
"parameters": [
@@ -7051,6 +7051,10 @@ const docTemplate = `{
"customer.LoginForm": {
"type": "object",
"properties": {
"device_token": {
"type": "string",
"example": "device_token"
},
"password": {
"type": "string",
"example": "App!1234"
@@ -8077,6 +8081,11 @@ const docTemplate = `{
"user.LoginForm": {
"type": "object",
"properties": {
"device_token": {
"description": "Device token",
"type": "string",
"example": "device_token"
},
"password": {
"description": "User password",
"type": "string",
+10 -1
View File
@@ -2051,7 +2051,7 @@
"application/json"
],
"tags": [
"Admin Flags"
"Admin-Flags"
],
"summary": "Get flag by country code (Admin)",
"parameters": [
@@ -7045,6 +7045,10 @@
"customer.LoginForm": {
"type": "object",
"properties": {
"device_token": {
"type": "string",
"example": "device_token"
},
"password": {
"type": "string",
"example": "App!1234"
@@ -8071,6 +8075,11 @@
"user.LoginForm": {
"type": "object",
"properties": {
"device_token": {
"description": "Device token",
"type": "string",
"example": "device_token"
},
"password": {
"description": "User password",
"type": "string",
+8 -1
View File
@@ -406,6 +406,9 @@ definitions:
type: object
customer.LoginForm:
properties:
device_token:
example: device_token
type: string
password:
example: App!1234
type: string
@@ -1110,6 +1113,10 @@ definitions:
type: object
user.LoginForm:
properties:
device_token:
description: Device token
example: device_token
type: string
password:
description: User password
example: Admin!1234
@@ -2509,7 +2516,7 @@ paths:
- BearerAuth: []
summary: Get flag by country code (Admin)
tags:
- Admin Flags
- Admin-Flags
/admin/v1/health:
get:
consumes:
+1
View File
@@ -45,6 +45,7 @@ type Customer struct {
Role CustomerRole `bson:"role"`
Phone *string `bson:"phone"`
CompanyIDs []string `bson:"company_ids"`
DeviceToken []string `bson:"device_token"`
LastLoginAt *int64 `bson:"last_login_at"`
UpdatedAt int64 `bson:"updated_at"`
CreatedAt int64 `bson:"created_at"`
+1
View File
@@ -91,6 +91,7 @@ type CustomerListResponse struct {
type LoginForm struct {
Username string `json:"username" valid:"required" example:"app"`
Password string `json:"password" valid:"required" example:"App!1234"`
DeviceToken string `json:"device_token" valid:"optional" example:"device_token"`
}
type RefreshTokenForm struct {
+6
View File
@@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"math/big"
"slices"
"strings"
"time"
@@ -529,6 +530,11 @@ func (s *customerService) Login(ctx context.Context, form *LoginForm) (*AuthResp
return nil, errors.New("failed to generate authentication tokens")
}
// append device token to customer if not exists
if !slices.Contains(customer.DeviceToken, form.DeviceToken) {
customer.DeviceToken = append(customer.DeviceToken, form.DeviceToken)
}
err = s.repository.Login(ctx, customer.ID.Hex())
if err != nil {
s.logger.Error("Failed to update customer last login", map[string]interface{}{
+1
View File
@@ -38,6 +38,7 @@ type User struct {
Position *string `bson:"position"`
Phone *string `bson:"phone"`
ProfileImage *string `bson:"profile_image"`
DeviceToken []string `bson:"device_token"`
IsVerified bool `bson:"is_verified"`
LastLoginAt *int64 `bson:"last_login_at"`
}
+1
View File
@@ -35,6 +35,7 @@ type UpdateUserForm struct {
type LoginForm struct {
Username string `json:"username" valid:"required" example:"admin"` // Username or email address
Password string `json:"password" valid:"required" example:"Admin!1234"` // User password
DeviceToken string `json:"device_token" valid:"optional" example:"device_token"` // Device token
}
// RefreshTokenForm represents the refresh token required to generate new access tokens
+6
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"slices"
"strings"
"time"
"tm/pkg/authorization"
@@ -311,6 +312,11 @@ func (s *userService) Login(ctx context.Context, form *LoginForm) (*AuthResponse
return nil, errors.New("invalid credentials")
}
// append device token to user if not exists
if !slices.Contains(user.DeviceToken, form.DeviceToken) {
user.DeviceToken = append(user.DeviceToken, form.DeviceToken)
}
// Update last login
err = s.repository.Login(ctx, user.ID.Hex())
if err != nil {