Skip to content

Commit d8f9864

Browse files
committed
[settings] introduce settings module
1 parent dfe1341 commit d8f9864

File tree

24 files changed

+1351
-20
lines changed

24 files changed

+1351
-20
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ toolchain go1.23.2
66

77
require (
88
firebase.google.com/go/v4 v4.12.1
9-
github.com/android-sms-gateway/client-go v1.5.8
9+
github.com/android-sms-gateway/client-go v1.6.0
1010
github.com/ansrivas/fiberprometheus/v2 v2.6.1
1111
github.com/capcom6/go-helpers v0.2.0
1212
github.com/capcom6/go-infra-fx v0.2.1

go.sum

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc
2626
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
2727
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
2828
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
29-
github.com/android-sms-gateway/client-go v1.5.7 h1:1L9Ot3yc+5DtGaDOCUj4/8DEECWyfo4IoPyL+oXnzyE=
30-
github.com/android-sms-gateway/client-go v1.5.7/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4=
31-
github.com/android-sms-gateway/client-go v1.5.8-0.20250516025314-5876d8deb355 h1:fctR5OH1c7g1zWEfp4K+fCZkY4+tZwTiKr/rN5N2yS8=
32-
github.com/android-sms-gateway/client-go v1.5.8-0.20250516025314-5876d8deb355/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4=
33-
github.com/android-sms-gateway/client-go v1.5.8 h1:t9630c1Hv8u/MjwQ8epJ0iDpt3VXurSNFC91CFEjM/M=
34-
github.com/android-sms-gateway/client-go v1.5.8/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4=
29+
github.com/android-sms-gateway/client-go v1.5.9-0.20250522134006-6e8b4dd3057a h1:TSmfm+KOsR1Ie10nZEjCVDepa1bEPin0NAgEUOSJiqw=
30+
github.com/android-sms-gateway/client-go v1.5.9-0.20250522134006-6e8b4dd3057a/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4=
31+
github.com/android-sms-gateway/client-go v1.5.9-0.20250522231449-9e0855eff19f h1:VYrL6YbkQ49pcyiXTYcR5LN1WpNy1Tc684XjeE1UCvw=
32+
github.com/android-sms-gateway/client-go v1.5.9-0.20250522231449-9e0855eff19f/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4=
33+
github.com/android-sms-gateway/client-go v1.5.9-0.20250524095300-2e41cae07049 h1:kdyVkqrgKDSI13JOKXVFz1al3IxfJPcbUaJvSXF6z+0=
34+
github.com/android-sms-gateway/client-go v1.5.9-0.20250524095300-2e41cae07049/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4=
35+
github.com/android-sms-gateway/client-go v1.6.0 h1:3hN0XEUnNrweBl5Xx3IfE5zyq5ihm7fB0dhuTZBKlns=
36+
github.com/android-sms-gateway/client-go v1.6.0/go.mod h1:DQsReciU1xcaVW3T5Z2bqslNdsAwCFCtghawmA6g6L4=
3537
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
3638
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
3739
github.com/ansrivas/fiberprometheus/v2 v2.6.1 h1:wac3pXaE6BYYTF04AC6K0ktk6vCD+MnDOJZ3SK66kXM=

internal/sms-gateway/app.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/messages"
1515
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/metrics"
1616
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/push"
17+
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/settings"
1718
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/webhooks"
1819
"github.com/capcom6/go-infra-fx/cli"
1920
"github.com/capcom6/go-infra-fx/db"
@@ -40,6 +41,7 @@ var Module = fx.Module(
4041
messages.Module,
4142
health.Module,
4243
webhooks.Module,
44+
settings.Module,
4345
devices.Module,
4446
metrics.Module,
4547
cleaner.Module,

internal/sms-gateway/handlers/3rdparty.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/logs"
77
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/messages"
88
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/middlewares/userauth"
9+
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/settings"
910
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/webhooks"
1011
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/auth"
1112
"github.com/go-playground/validator/v10"
@@ -21,6 +22,7 @@ type ThirdPartyHandlerParams struct {
2122
MessagesHandler *messages.ThirdPartyController
2223
WebhooksHandler *webhooks.ThirdPartyController
2324
DevicesHandler *devices.ThirdPartyController
25+
SettingsHandler *settings.ThirdPartyController
2426
LogsHandler *logs.ThirdPartyController
2527

2628
AuthSvc *auth.Service
@@ -36,6 +38,7 @@ type thirdPartyHandler struct {
3638
messagesHandler *messages.ThirdPartyController
3739
webhooksHandler *webhooks.ThirdPartyController
3840
devicesHandler *devices.ThirdPartyController
41+
settingsHandler *settings.ThirdPartyController
3942
logsHandler *logs.ThirdPartyController
4043

4144
authSvc *auth.Service
@@ -57,6 +60,8 @@ func (h *thirdPartyHandler) Register(router fiber.Router) {
5760
h.devicesHandler.Register(router.Group("/device")) // TODO: remove after 2025-07-11
5861
h.devicesHandler.Register(router.Group("/devices"))
5962

63+
h.settingsHandler.Register(router.Group("/settings"))
64+
6065
h.webhooksHandler.Register(router.Group("/webhooks"))
6166

6267
h.logsHandler.Register(router.Group("/logs"))
@@ -69,6 +74,7 @@ func newThirdPartyHandler(params ThirdPartyHandlerParams) *thirdPartyHandler {
6974
messagesHandler: params.MessagesHandler,
7075
webhooksHandler: params.WebhooksHandler,
7176
devicesHandler: params.DevicesHandler,
77+
settingsHandler: params.SettingsHandler,
7278
logsHandler: params.LogsHandler,
7379
authSvc: params.AuthSvc,
7480
}

internal/sms-gateway/handlers/converters/devices_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ func TestDeviceToDTO(t *testing.T) {
3232
ID: "test-id",
3333
Name: anys.AsPointer("test-name"),
3434
LastSeen: lastSeenAt,
35-
TimedModel: models.TimedModel{
36-
CreatedAt: createdAt,
37-
UpdatedAt: updatedAt,
35+
SoftDeletableModel: models.SoftDeletableModel{
36+
TimedModel: models.TimedModel{
37+
CreatedAt: createdAt,
38+
UpdatedAt: updatedAt,
39+
},
3840
},
3941
},
4042
expected: smsgateway.Device{

internal/sms-gateway/handlers/mobile.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/converters"
1111
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/middlewares/deviceauth"
1212
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/middlewares/userauth"
13+
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/settings"
1314
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/webhooks"
1415
"github.com/android-sms-gateway/server/internal/sms-gateway/models"
1516
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/auth"
@@ -33,6 +34,7 @@ type mobileHandler struct {
3334
messagesSvc *messages.Service
3435

3536
webhooksCtrl *webhooks.MobileController
37+
settingsCtrl *settings.MobileController
3638

3739
idGen func() string
3840
}
@@ -303,6 +305,8 @@ func (h *mobileHandler) Register(router fiber.Router) {
303305
router.Patch("/user/password", deviceauth.WithDevice(h.changePassword))
304306

305307
h.webhooksCtrl.Register(router.Group("/webhooks"))
308+
309+
h.settingsCtrl.Register(router.Group("/settings"))
306310
}
307311

308312
type mobileHandlerParams struct {
@@ -316,6 +320,7 @@ type mobileHandlerParams struct {
316320
MessagesSvc *messages.Service
317321

318322
WebhooksCtrl *webhooks.MobileController
323+
SettingsCtrl *settings.MobileController
319324
}
320325

321326
func newMobileHandler(params mobileHandlerParams) *mobileHandler {
@@ -327,6 +332,7 @@ func newMobileHandler(params mobileHandlerParams) *mobileHandler {
327332
devicesSvc: params.DevicesSvc,
328333
messagesSvc: params.MessagesSvc,
329334
webhooksCtrl: params.WebhooksCtrl,
335+
settingsCtrl: params.SettingsCtrl,
330336
idGen: idGen,
331337
}
332338
}

internal/sms-gateway/handlers/module.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/devices"
55
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/logs"
66
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/messages"
7+
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/settings"
78
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/webhooks"
89
"github.com/capcom6/go-infra-fx/http"
910
"go.uber.org/fx"
@@ -27,6 +28,8 @@ var Module = fx.Module(
2728
webhooks.NewThirdPartyController,
2829
webhooks.NewMobileController,
2930
devices.NewThirdPartyController,
31+
settings.NewThirdPartyController,
32+
settings.NewMobileController,
3033
logs.NewThirdPartyController,
3134
fx.Private,
3235
),
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package settings
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/android-sms-gateway/client-go/smsgateway"
7+
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/base"
8+
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/middlewares/userauth"
9+
"github.com/android-sms-gateway/server/internal/sms-gateway/models"
10+
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/devices"
11+
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/settings"
12+
"github.com/go-playground/validator/v10"
13+
"github.com/gofiber/fiber/v2"
14+
"go.uber.org/fx"
15+
"go.uber.org/zap"
16+
)
17+
18+
type thirdPartyControllerParams struct {
19+
fx.In
20+
21+
DevicesSvc *devices.Service
22+
SettingsSvc *settings.Service
23+
24+
Validator *validator.Validate
25+
Logger *zap.Logger
26+
}
27+
28+
type ThirdPartyController struct {
29+
base.Handler
30+
31+
devicesSvc *devices.Service
32+
settingsSvc *settings.Service
33+
}
34+
35+
// @Summary Get settings
36+
// @Description Returns settings for a specific user
37+
// @Security ApiAuth
38+
// @Tags User, Settings
39+
// @Produce json
40+
// @Success 200 {object} smsgateway.DeviceSettings "Settings"
41+
// @Failure 401 {object} smsgateway.ErrorResponse "Unauthorized"
42+
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
43+
// @Router /3rdparty/v1/settings [get]
44+
//
45+
// Get settings
46+
func (h *ThirdPartyController) get(user models.User, c *fiber.Ctx) error {
47+
settings, err := h.settingsSvc.GetSettings(user.ID, true)
48+
if err != nil {
49+
return fmt.Errorf("can't get settings: %w", err)
50+
}
51+
52+
return c.JSON(settings)
53+
}
54+
55+
// @Summary Update settings
56+
// @Description Updates settings for a specific user
57+
// @Security ApiAuth
58+
// @Tags User, Settings
59+
// @Accept json
60+
// @Produce json
61+
// @Param request body smsgateway.DeviceSettings true "Settings"
62+
// @Success 200 {object} object "Settings updated"
63+
// @Failure 400 {object} smsgateway.ErrorResponse "Invalid request"
64+
// @Failure 401 {object} smsgateway.ErrorResponse "Unauthorized"
65+
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
66+
// @Router /3rdparty/v1/settings [put]
67+
//
68+
// Update settings
69+
func (h *ThirdPartyController) put(user models.User, c *fiber.Ctx) error {
70+
if err := h.BodyParserValidator(c, &smsgateway.DeviceSettings{}); err != nil {
71+
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid settings format: %v", err))
72+
}
73+
74+
settings := make(map[string]any, 8)
75+
76+
if err := c.BodyParser(&settings); err != nil {
77+
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Failed to parse request body: %v", err))
78+
}
79+
80+
updated, err := h.settingsSvc.ReplaceSettings(user.ID, settings)
81+
82+
if err != nil {
83+
return fmt.Errorf("can't update settings: %w", err)
84+
}
85+
86+
return c.JSON(updated)
87+
}
88+
89+
// @Summary Partially update settings
90+
// @Description Partially updates settings for a specific user
91+
// @Security ApiAuth
92+
// @Tags User, Settings
93+
// @Accept json
94+
// @Produce json
95+
// @Param request body smsgateway.DeviceSettings true "Settings"
96+
// @Success 200 {object} object "Settings updated"
97+
// @Failure 400 {object} smsgateway.ErrorResponse "Invalid request"
98+
// @Failure 401 {object} smsgateway.ErrorResponse "Unauthorized"
99+
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
100+
// @Router /3rdparty/v1/settings [patch]
101+
//
102+
// Partially update settings
103+
func (h *ThirdPartyController) patch(user models.User, c *fiber.Ctx) error {
104+
if err := h.BodyParserValidator(c, &smsgateway.DeviceSettings{}); err != nil {
105+
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid settings format: %v", err))
106+
}
107+
108+
settings := make(map[string]any, 8)
109+
110+
if err := c.BodyParser(&settings); err != nil {
111+
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Failed to parse request body: %v", err))
112+
}
113+
114+
updated, err := h.settingsSvc.UpdateSettings(user.ID, settings)
115+
if err != nil {
116+
return fmt.Errorf("can't update settings: %w", err)
117+
}
118+
119+
return c.JSON(updated)
120+
}
121+
122+
func (h *ThirdPartyController) Register(app fiber.Router) {
123+
app.Get("", userauth.WithUser(h.get))
124+
app.Patch("", userauth.WithUser(h.patch))
125+
app.Put("", userauth.WithUser(h.put))
126+
}
127+
128+
func NewThirdPartyController(params thirdPartyControllerParams) *ThirdPartyController {
129+
return &ThirdPartyController{
130+
Handler: base.Handler{
131+
Logger: params.Logger.Named("settings"),
132+
Validator: params.Validator,
133+
},
134+
devicesSvc: params.DevicesSvc,
135+
settingsSvc: params.SettingsSvc,
136+
}
137+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package settings
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/base"
7+
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/middlewares/deviceauth"
8+
"github.com/android-sms-gateway/server/internal/sms-gateway/models"
9+
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/devices"
10+
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/settings"
11+
"github.com/gofiber/fiber/v2"
12+
"go.uber.org/fx"
13+
"go.uber.org/zap"
14+
)
15+
16+
type mobileControllerParams struct {
17+
fx.In
18+
19+
DevicesSvc *devices.Service
20+
SettingsSvc *settings.Service
21+
22+
Logger *zap.Logger
23+
}
24+
25+
type MobileController struct {
26+
base.Handler
27+
28+
devicesSvc *devices.Service
29+
settingsSvc *settings.Service
30+
}
31+
32+
// @Summary Get settings
33+
// @Description Returns settings for a device
34+
// @Security MobileToken
35+
// @Tags Device, Settings
36+
// @Produce json
37+
// @Success 200 {object} smsgateway.DeviceSettings "Settings"
38+
// @Failure 401 {object} smsgateway.ErrorResponse "Unauthorized"
39+
// @Failure 500 {object} smsgateway.ErrorResponse "Internal server error"
40+
// @Router /mobile/v1/settings [get]
41+
//
42+
// Get settings
43+
func (h *MobileController) get(device models.Device, c *fiber.Ctx) error {
44+
settings, err := h.settingsSvc.GetSettings(device.UserID, false)
45+
if err != nil {
46+
return fmt.Errorf("can't get settings for device %s (user ID: %s): %w", device.ID, device.UserID, err)
47+
}
48+
49+
return c.JSON(settings)
50+
}
51+
52+
func (h *MobileController) Register(router fiber.Router) {
53+
router.Get("", deviceauth.WithDevice(h.get))
54+
}
55+
56+
func NewMobileController(params mobileControllerParams) *MobileController {
57+
return &MobileController{
58+
Handler: base.Handler{
59+
Logger: params.Logger.Named("settings"),
60+
},
61+
devicesSvc: params.DevicesSvc,
62+
settingsSvc: params.SettingsSvc,
63+
}
64+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-- +goose Up
2+
-- +goose StatementBegin
3+
CREATE TABLE `device_settings` (
4+
`user_id` varchar(32) NOT NULL,
5+
`settings` json NOT NULL,
6+
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
7+
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
8+
PRIMARY KEY (`user_id`),
9+
CONSTRAINT `fk_device_settings_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE
10+
);
11+
-- +goose StatementEnd
12+
---
13+
-- +goose Down
14+
-- +goose StatementBegin
15+
DROP TABLE `device_settings`;
16+
-- +goose StatementEnd

0 commit comments

Comments
 (0)