diff --git a/scnserver/.idea/server.iml b/scnserver/.idea/server.iml index 9f75a96..c7bb95a 100644 --- a/scnserver/.idea/server.iml +++ b/scnserver/.idea/server.iml @@ -14,7 +14,6 @@ - diff --git a/scnserver/api/handler/apiChannel.go b/scnserver/api/handler/apiChannel.go index 3e9282a..a6a430c 100644 --- a/scnserver/api/handler/apiChannel.go +++ b/scnserver/api/handler/apiChannel.go @@ -27,7 +27,7 @@ import ( // @ID api-channels-list // @Tags API-v2 // -// @Param uid path int true "UserID" +// @Param uid path string true "UserID" // @Param selector query string false "Filter channels (default: owned)" Enums(owned, subscribed, all, subscribed_any, all_any) // // @Success 200 {object} handler.ListChannels.response @@ -162,7 +162,7 @@ func (h APIHandler) GetChannel(g *gin.Context) ginresp.HTTPResponse { // @ID api-channels-create // @Tags API-v2 // -// @Param uid path int true "UserID" +// @Param uid path string true "UserID" // @Param post_body body handler.CreateChannel.body false " " // // @Success 200 {object} models.ChannelWithSubscriptionJSON @@ -260,8 +260,8 @@ func (h APIHandler) CreateChannel(g *gin.Context) ginresp.HTTPResponse { // @ID api-channels-update // @Tags API-v2 // -// @Param uid path int true "UserID" -// @Param cid path int true "ChannelID" +// @Param uid path string true "UserID" +// @Param cid path string true "ChannelID" // // @Param subscribe_key body string false "Send `true` to create a new subscribe_key" // @Param send_key body string false "Send `true` to create a new send_key" @@ -378,8 +378,8 @@ func (h APIHandler) UpdateChannel(g *gin.Context) ginresp.HTTPResponse { // @Tags API-v2 // // @Param query_data query handler.ListChannelMessages.query false " " -// @Param uid path int true "UserID" -// @Param cid path int true "ChannelID" +// @Param uid path string true "UserID" +// @Param cid path string true "ChannelID" // // @Success 200 {object} handler.ListChannelMessages.response // @Failure 400 {object} ginresp.apiError "supplied values/parameters cannot be parsed / are invalid" diff --git a/scnserver/api/handler/apiClient.go b/scnserver/api/handler/apiClient.go index 05dbdae..59b0f25 100644 --- a/scnserver/api/handler/apiClient.go +++ b/scnserver/api/handler/apiClient.go @@ -103,7 +103,7 @@ func (h APIHandler) GetClient(g *gin.Context) ginresp.HTTPResponse { // @ID api-clients-create // @Tags API-v2 // -// @Param uid path int true "UserID" +// @Param uid path string true "UserID" // // @Param post_body body handler.AddClient.body false " " // @@ -206,3 +206,89 @@ func (h APIHandler) DeleteClient(g *gin.Context) ginresp.HTTPResponse { return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, client.JSON())) } + +// UpdateClient swaggerdoc +// +// @Summary (Partially) update a client +// @Description The body-values are optional, only send the ones you want to update +// @ID api-client-update +// @Tags API-v2 +// +// @Param uid path string true "UserID" +// @Param cid path string true "ClientID" +// +// @Param clientname body string false "Change the clientname (send an empty string to clear it)" +// @Param pro_token body string false "Send a verification of premium purchase" +// +// @Success 200 {object} models.ClientJSON +// @Failure 400 {object} ginresp.apiError "supplied values/parameters cannot be parsed / are invalid" +// @Failure 401 {object} ginresp.apiError "client is not authorized / has missing permissions" +// @Failure 404 {object} ginresp.apiError "client not found" +// @Failure 500 {object} ginresp.apiError "internal server error" +// +// @Router /api/v2/users/{uid}/clients/{cid} [PATCH] +func (h APIHandler) UpdateClient(g *gin.Context) ginresp.HTTPResponse { + type uri struct { + UserID models.UserID `uri:"uid" binding:"entityid"` + ClientID models.ClientID `uri:"cid" binding:"entityid"` + } + type body struct { + FCMToken *string `json:"fcm_token"` + AgentModel *string `json:"agent_model"` + AgentVersion *string `json:"agent_version"` + } + + var u uri + var b body + ctx, errResp := h.app.StartRequest(g, &u, nil, &b, nil) + if errResp != nil { + return *errResp + } + defer ctx.Cancel() + + if permResp := ctx.CheckPermissionUserAdmin(u.UserID); permResp != nil { + return *permResp + } + + client, err := h.database.GetClient(ctx, u.UserID, u.ClientID) + if err == sql.ErrNoRows { + return ginresp.APIError(g, 404, apierr.CLIENT_NOT_FOUND, "Client not found", err) + } + if err != nil { + return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err) + } + + if b.FCMToken != nil && *b.FCMToken != client.FCMToken { + + err = h.database.DeleteClientsByFCM(ctx, *b.FCMToken) + if err != nil { + return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to delete existing clients in db", err) + } + + err = h.database.UpdateClientFCMToken(ctx, u.ClientID, *b.FCMToken) + if err != nil { + return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to update client", err) + } + } + + if b.AgentModel != nil { + err = h.database.UpdateClientAgentModel(ctx, u.ClientID, *b.AgentModel) + if err != nil { + return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to update client", err) + } + } + + if b.AgentVersion != nil { + err = h.database.UpdateClientAgentVersion(ctx, u.ClientID, *b.AgentVersion) + if err != nil { + return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to update client", err) + } + } + + client, err = h.database.GetClient(ctx, u.UserID, u.ClientID) + if err != nil { + return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query (updated) client", err) + } + + return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, client.JSON())) +} diff --git a/scnserver/api/handler/apiKeyToken.go b/scnserver/api/handler/apiKeyToken.go index 69ccc1f..2c81e5d 100644 --- a/scnserver/api/handler/apiKeyToken.go +++ b/scnserver/api/handler/apiKeyToken.go @@ -106,8 +106,8 @@ func (h APIHandler) GetUserKey(g *gin.Context) ginresp.HTTPResponse { // @ID api-tokenkeys-update // @Tags API-v2 // -// @Param uid path int true "UserID" -// @Param kid path int true "TokenKeyID" +// @Param uid path string true "UserID" +// @Param kid path string true "TokenKeyID" // // @Param post_body body handler.UpdateUserKey.body false " " // @@ -204,7 +204,7 @@ func (h APIHandler) UpdateUserKey(g *gin.Context) ginresp.HTTPResponse { // @ID api-tokenkeys-create // @Tags API-v2 // -// @Param uid path int true "UserID" +// @Param uid path string true "UserID" // // @Param post_body body handler.CreateUserKey.body false " " // diff --git a/scnserver/api/handler/apiSubscription.go b/scnserver/api/handler/apiSubscription.go index 084bac1..7a86a99 100644 --- a/scnserver/api/handler/apiSubscription.go +++ b/scnserver/api/handler/apiSubscription.go @@ -25,7 +25,7 @@ import ( // @ID api-user-subscriptions-list // @Tags API-v2 // -// @Param uid path int true "UserID" +// @Param uid path string true "UserID" // @Param selector query string true "Filter subscriptions (default: outgoing_all)" Enums(outgoing_all, outgoing_confirmed, outgoing_unconfirmed, incoming_all, incoming_confirmed, incoming_unconfirmed) // // @Success 200 {object} handler.ListUserSubscriptions.response @@ -275,7 +275,7 @@ func (h APIHandler) CancelSubscription(g *gin.Context) ginresp.HTTPResponse { // @ID api-subscriptions-create // @Tags API-v2 // -// @Param uid path int true "UserID" +// @Param uid path string true "UserID" // @Param query_data query handler.CreateSubscription.query false " " // @Param post_data body handler.CreateSubscription.body false " " // @@ -363,8 +363,8 @@ func (h APIHandler) CreateSubscription(g *gin.Context) ginresp.HTTPResponse { // @ID api-subscriptions-update // @Tags API-v2 // -// @Param uid path int true "UserID" -// @Param sid path int true "SubscriptionID" +// @Param uid path string true "UserID" +// @Param sid path string true "SubscriptionID" // @Param post_data body handler.UpdateSubscription.body false " " // // @Success 200 {object} models.SubscriptionJSON diff --git a/scnserver/api/handler/apiUser.go b/scnserver/api/handler/apiUser.go index 51f054e..7f23c9a 100644 --- a/scnserver/api/handler/apiUser.go +++ b/scnserver/api/handler/apiUser.go @@ -180,7 +180,7 @@ func (h APIHandler) GetUser(g *gin.Context) ginresp.HTTPResponse { // @ID api-user-update // @Tags API-v2 // -// @Param uid path int true "UserID" +// @Param uid path string true "UserID" // // @Param username body string false "Change the username (send an empty string to clear it)" // @Param pro_token body string false "Send a verification of premium purchase" diff --git a/scnserver/api/handler/compat.go b/scnserver/api/handler/compat.go index 6d33567..04382f8 100644 --- a/scnserver/api/handler/compat.go +++ b/scnserver/api/handler/compat.go @@ -325,8 +325,6 @@ func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse { return ginresp.CompatAPIError(0, "Failed to query clients") } - fcmSet := langext.ArrAny(clients, func(c models.Client) bool { return c.FCMToken != nil }) - return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{ Success: true, Message: "ok", @@ -335,7 +333,7 @@ func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse { QuotaUsed: user.QuotaUsedToday(), QuotaMax: user.QuotaPerDay(), IsPro: langext.Conditional(user.IsPro, 1, 0), - FCMSet: fcmSet, + FCMSet: len(clients) > 0, UnackCount: 0, })) } diff --git a/scnserver/api/handler/message.go b/scnserver/api/handler/message.go index 4916969..c22eb33 100644 --- a/scnserver/api/handler/message.go +++ b/scnserver/api/handler/message.go @@ -307,7 +307,7 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to create delivery", err)) } } else { - _, err = h.database.CreateSuccessDelivery(ctx, client, msg, *fcmDelivID) + _, err = h.database.CreateSuccessDelivery(ctx, client, msg, fcmDelivID) if err != nil { return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to create delivery", err)) } diff --git a/scnserver/api/router.go b/scnserver/api/router.go index 436913b..349b4b8 100644 --- a/scnserver/api/router.go +++ b/scnserver/api/router.go @@ -135,6 +135,7 @@ func (r *Router) Init(e *gin.Engine) error { apiv2.GET("/users/:uid/clients", r.Wrap(r.apiHandler.ListClients)) apiv2.GET("/users/:uid/clients/:cid", r.Wrap(r.apiHandler.GetClient)) + apiv2.PATCH("/users/:uid/clients/:cid", r.Wrap(r.apiHandler.UpdateClient)) apiv2.POST("/users/:uid/clients", r.Wrap(r.apiHandler.AddClient)) apiv2.DELETE("/users/:uid/clients/:cid", r.Wrap(r.apiHandler.DeleteClient)) diff --git a/scnserver/db/impl/primary/clients.go b/scnserver/db/impl/primary/clients.go index 20215b9..00f2246 100644 --- a/scnserver/db/impl/primary/clients.go +++ b/scnserver/db/impl/primary/clients.go @@ -2,7 +2,6 @@ package primary import ( "blackforestbytes.com/simplecloudnotifier/models" - "gogs.mikescher.com/BlackForestBytes/goext/langext" "gogs.mikescher.com/BlackForestBytes/goext/sq" "time" ) @@ -17,7 +16,7 @@ func (db *Database) CreateClient(ctx TxContext, userid models.UserID, ctype mode ClientID: models.NewClientID(), UserID: userid, Type: ctype, - FCMToken: langext.Ptr(fcmToken), + FCMToken: fcmToken, TimestampCreated: time2DB(time.Now()), AgentModel: agentModel, AgentVersion: agentVersion, @@ -113,3 +112,54 @@ func (db *Database) DeleteClientsByFCM(ctx TxContext, fcmtoken string) error { return nil } + +func (db *Database) UpdateClientFCMToken(ctx TxContext, clientid models.ClientID, fcmtoken string) error { + tx, err := ctx.GetOrCreateTransaction(db) + if err != nil { + return err + } + + _, err = tx.Exec(ctx, "UPDATE clients SET fcm_token = :vvv WHERE client_id = :cid", sq.PP{ + "vvv": fcmtoken, + "cid": clientid, + }) + if err != nil { + return err + } + + return nil +} + +func (db *Database) UpdateClientAgentModel(ctx TxContext, clientid models.ClientID, agentModel string) error { + tx, err := ctx.GetOrCreateTransaction(db) + if err != nil { + return err + } + + _, err = tx.Exec(ctx, "UPDATE clients SET agent_model = :vvv WHERE client_id = :cid", sq.PP{ + "vvv": agentModel, + "cid": clientid, + }) + if err != nil { + return err + } + + return nil +} + +func (db *Database) UpdateClientAgentVersion(ctx TxContext, clientid models.ClientID, agentVersion string) error { + tx, err := ctx.GetOrCreateTransaction(db) + if err != nil { + return err + } + + _, err = tx.Exec(ctx, "UPDATE clients SET agent_version = :vvv WHERE client_id = :cid", sq.PP{ + "vvv": agentVersion, + "cid": clientid, + }) + if err != nil { + return err + } + + return nil +} diff --git a/scnserver/db/schema/primary_3.ddl b/scnserver/db/schema/primary_3.ddl index 5e5d01b..7f33ae3 100644 --- a/scnserver/db/schema/primary_3.ddl +++ b/scnserver/db/schema/primary_3.ddl @@ -50,7 +50,7 @@ CREATE TABLE clients user_id TEXT NOT NULL, type TEXT CHECK(type IN ('ANDROID', 'IOS')) NOT NULL, - fcm_token TEXT NULL, + fcm_token TEXT NOT NULL, timestamp_created INTEGER NOT NULL, diff --git a/scnserver/go.mod b/scnserver/go.mod index ebdd02d..e07770d 100644 --- a/scnserver/go.mod +++ b/scnserver/go.mod @@ -9,7 +9,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/mattn/go-sqlite3 v1.14.16 github.com/rs/zerolog v1.28.0 - gogs.mikescher.com/BlackForestBytes/goext v0.0.126 + gogs.mikescher.com/BlackForestBytes/goext v0.0.127 gopkg.in/loremipsum.v1 v1.1.0 ) diff --git a/scnserver/go.sum b/scnserver/go.sum index e1b2fb1..78191f7 100644 --- a/scnserver/go.sum +++ b/scnserver/go.sum @@ -81,6 +81,8 @@ gogs.mikescher.com/BlackForestBytes/goext v0.0.125 h1:l4C5/CQS/IVm364oZa8MqiG62+ gogs.mikescher.com/BlackForestBytes/goext v0.0.125/go.mod h1:w8JlyUHpoOJmW5GxsiheZkFh3vn8Mp80ynSVOFLszL0= gogs.mikescher.com/BlackForestBytes/goext v0.0.126 h1:o3u0STRaPkmNBenqzvXAOPALSyRswuDwl3Y/0MVHAx4= gogs.mikescher.com/BlackForestBytes/goext v0.0.126/go.mod h1:w8JlyUHpoOJmW5GxsiheZkFh3vn8Mp80ynSVOFLszL0= +gogs.mikescher.com/BlackForestBytes/goext v0.0.127 h1:NYrSO1kjFWL1yMh0xqIeMZ4hUJiGjILMQwvZMLy4VEg= +gogs.mikescher.com/BlackForestBytes/goext v0.0.127/go.mod h1:w8JlyUHpoOJmW5GxsiheZkFh3vn8Mp80ynSVOFLszL0= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= diff --git a/scnserver/jobs/DeliveryRetryJob.go b/scnserver/jobs/DeliveryRetryJob.go index dcf8d02..0c4e01e 100644 --- a/scnserver/jobs/DeliveryRetryJob.go +++ b/scnserver/jobs/DeliveryRetryJob.go @@ -158,7 +158,7 @@ func (j *DeliveryRetryJob) redeliver(ctx *logic.SimpleContext, delivery models.D fcmDelivID, err := j.app.DeliverMessage(ctx, client, msg, nil) if err == nil { - err = j.app.Database.Primary.SetDeliverySuccess(ctx, delivery, *fcmDelivID) + err = j.app.Database.Primary.SetDeliverySuccess(ctx, delivery, fcmDelivID) if err != nil { log.Err(err).Str("MessageID", delivery.MessageID.String()).Str("DeliveryID", delivery.DeliveryID.String()).Msg("Failed to update delivery") ctx.RollbackTransaction() diff --git a/scnserver/logic/application.go b/scnserver/logic/application.go index 74a6525..ab6026a 100644 --- a/scnserver/logic/application.go +++ b/scnserver/logic/application.go @@ -339,17 +339,13 @@ func (app *Application) NormalizeUsername(v string) string { return strings.TrimSpace(v) } -func (app *Application) DeliverMessage(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string) (*string, error) { - if client.FCMToken != nil { - fcmDelivID, err := app.Pusher.SendNotification(ctx, client, msg, compatTitleOverride) - if err != nil { - log.Warn().Str("MessageID", msg.MessageID.String()).Str("ClientID", client.ClientID.String()).Err(err).Msg("FCM Delivery failed") - return nil, err - } - return langext.Ptr(fcmDelivID), nil - } else { - return langext.Ptr(""), nil +func (app *Application) DeliverMessage(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string) (string, error) { + fcmDelivID, err := app.Pusher.SendNotification(ctx, client, msg, compatTitleOverride) + if err != nil { + log.Warn().Str("MessageID", msg.MessageID.String()).Str("ClientID", client.ClientID.String()).Err(err).Msg("FCM Delivery failed") + return "", err } + return fcmDelivID, nil } func (app *Application) InsertRequestLog(data models.RequestLog) { diff --git a/scnserver/models/client.go b/scnserver/models/client.go index 25def19..59113b0 100644 --- a/scnserver/models/client.go +++ b/scnserver/models/client.go @@ -18,7 +18,7 @@ type Client struct { ClientID ClientID UserID UserID Type ClientType - FCMToken *string + FCMToken string TimestampCreated time.Time AgentModel string AgentVersion string @@ -40,7 +40,7 @@ type ClientJSON struct { ClientID ClientID `json:"client_id"` UserID UserID `json:"user_id"` Type ClientType `json:"type"` - FCMToken *string `json:"fcm_token"` + FCMToken string `json:"fcm_token"` TimestampCreated string `json:"timestamp_created"` AgentModel string `json:"agent_model"` AgentVersion string `json:"agent_version"` @@ -50,7 +50,7 @@ type ClientDB struct { ClientID ClientID `db:"client_id"` UserID UserID `db:"user_id"` Type ClientType `db:"type"` - FCMToken *string `db:"fcm_token"` + FCMToken string `db:"fcm_token"` TimestampCreated int64 `db:"timestamp_created"` AgentModel string `db:"agent_model"` AgentVersion string `db:"agent_version"` diff --git a/scnserver/push/firebase.go b/scnserver/push/firebase.go index 9c83884..6c99fc6 100644 --- a/scnserver/push/firebase.go +++ b/scnserver/push/firebase.go @@ -65,7 +65,7 @@ func (fb FirebaseConnector) SendNotification(ctx context.Context, client models. "title": langext.Coalesce(compatTitleOverride, msg.Title), "body": langext.Coalesce(msg.TrimmedContent(), ""), }, - "token": *client.FCMToken, + "token": client.FCMToken, "android": gin.H{ "priority": "high", }, diff --git a/scnserver/test/client_test.go b/scnserver/test/client_test.go index 378b49f..c87e7bf 100644 --- a/scnserver/test/client_test.go +++ b/scnserver/test/client_test.go @@ -57,7 +57,42 @@ func TestGetClient(t *testing.T) { tt.AssertJsonMapEqual(t, "client", r3, c0) } -func TestCreateAndDeleteClient(t *testing.T) { +func TestCreateClient(t *testing.T) { + _, baseUrl, stop := tt.StartSimpleWebserver(t) + defer stop() + + r0 := tt.RequestPost[gin.H](t, baseUrl, "/api/v2/users", gin.H{ + "agent_model": "DUMMY_PHONE", + "agent_version": "4X", + "client_type": "ANDROID", + "fcm_token": "DUMMY_FCM", + }) + + uid := fmt.Sprintf("%v", r0["user_id"]) + + tt.AssertEqual(t, "len(clients)", 1, len(r0["clients"].([]any))) + + admintok := r0["admin_key"].(string) + + fmt.Printf("uid := %s\n", uid) + fmt.Printf("admin_key := %s\n", admintok) + + tt.RequestAuthPost[gin.H](t, admintok, baseUrl, "/api/v2/users/"+uid+"/clients", gin.H{ + "agent_model": "DUMMY_PHONE_2", + "agent_version": "99X", + "client_type": "IOS", + "fcm_token": "DUMMY_FCM_2", + }) + + type rt3 struct { + Clients []gin.H `json:"clients"` + } + + r3 := tt.RequestAuthGet[rt3](t, admintok, baseUrl, "/api/v2/users/"+uid+"/clients") + tt.AssertEqual(t, "len(clients)", 2, len(r3.Clients)) +} + +func TestDeleteClient(t *testing.T) { _, baseUrl, stop := tt.StartSimpleWebserver(t) defer stop() @@ -191,3 +226,63 @@ func TestListClients(t *testing.T) { tt.RequestAuthGetShouldFail(t, data.User[0].AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/clients", url.QueryEscape(data.User[1].UID)), 401, apierr.USER_AUTH_FAILED) } + +func TestUpdateClient(t *testing.T) { + _, baseUrl, stop := tt.StartSimpleWebserver(t) + defer stop() + + r0 := tt.RequestPost[gin.H](t, baseUrl, "/api/v2/users", gin.H{ + "agent_model": "DUMMY_PHONE", + "agent_version": "4X", + "client_type": "ANDROID", + "fcm_token": "DUMMY_FCM", + }) + + uid := fmt.Sprintf("%v", r0["user_id"]) + + tt.AssertEqual(t, "len(clients)", 1, len(r0["clients"].([]any))) + + admintok := r0["admin_key"].(string) + + fmt.Printf("uid := %s\n", uid) + fmt.Printf("admin_key := %s\n", admintok) + + r2 := tt.RequestAuthPost[gin.H](t, admintok, baseUrl, "/api/v2/users/"+uid+"/clients", gin.H{ + "agent_model": "DUMMY_PHONE_2", + "agent_version": "99X", + "client_type": "IOS", + "fcm_token": "DUMMY_FCM_2", + }) + + cid2 := fmt.Sprintf("%v", r2["client_id"]) + + type rt3 struct { + Clients []gin.H `json:"clients"` + } + + r3 := tt.RequestAuthGet[rt3](t, admintok, baseUrl, "/api/v2/users/"+uid+"/clients") + tt.AssertEqual(t, "len(clients)", 2, len(r3.Clients)) + + r4 := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/v2/users/"+uid+"/clients/"+cid2) + tt.AssertEqual(t, "agent_model", "DUMMY_PHONE_2", r4["agent_model"]) + tt.AssertEqual(t, "agent_version", "99X", r4["agent_version"]) + tt.AssertEqual(t, "client_type", "IOS", r4["type"]) + tt.AssertEqual(t, "fcm_token", "DUMMY_FCM_2", r4["fcm_token"]) + + r5 := tt.RequestAuthPatch[gin.H](t, admintok, baseUrl, "/api/v2/users/"+uid+"/clients/"+cid2, gin.H{ + "agent_model": "PP_DUMMY_PHONE_2", + "agent_version": "PP_99X", + "fcm_token": "PP_DUMMY_FCM_2", + }) + tt.AssertEqual(t, "agent_model", "PP_DUMMY_PHONE_2", r5["agent_model"]) + tt.AssertEqual(t, "agent_version", "PP_99X", r5["agent_version"]) + tt.AssertEqual(t, "client_type", "IOS", r5["type"]) + tt.AssertEqual(t, "fcm_token", "PP_DUMMY_FCM_2", r5["fcm_token"]) + + r6 := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/v2/users/"+uid+"/clients/"+cid2) + tt.AssertEqual(t, "agent_model", "PP_DUMMY_PHONE_2", r6["agent_model"]) + tt.AssertEqual(t, "agent_version", "PP_99X", r6["agent_version"]) + tt.AssertEqual(t, "client_type", "IOS", r6["type"]) + tt.AssertEqual(t, "fcm_token", "PP_DUMMY_FCM_2", r6["fcm_token"]) + +} diff --git a/scnserver/test/compat_test.go b/scnserver/test/compat_test.go index 5f06ebd..ded0e71 100644 --- a/scnserver/test/compat_test.go +++ b/scnserver/test/compat_test.go @@ -477,7 +477,7 @@ func TestCompatUpdateUserKey(t *testing.T) { s0 := tt.RequestPost[gin.H](t, baseUrl, fmt.Sprintf("/send.php?user_id=%d&user_key=%s&title=%s", userid, userkey, url.QueryEscape("msg_1")), nil) tt.AssertEqual(t, "success", true, s0["success"]) - tt.AssertEqual(t, "fcm", "DUMMY_FCM", *pusher.Last().Client.FCMToken) + tt.AssertEqual(t, "fcm", "DUMMY_FCM", pusher.Last().Client.FCMToken) upd := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/update.php?user_id=%d&user_key=%s", userid, userkey)) tt.AssertEqual(t, "success", true, upd["success"]) @@ -497,7 +497,7 @@ func TestCompatUpdateUserKey(t *testing.T) { s1 := tt.RequestPost[gin.H](t, baseUrl, fmt.Sprintf("/send.php?user_id=%d&user_key=%s&title=%s", userid, newkey, url.QueryEscape("msg_2")), nil) tt.AssertEqual(t, "success", true, s1["success"]) - tt.AssertEqual(t, "fcm", "DUMMY_FCM", *pusher.Last().Client.FCMToken) + tt.AssertEqual(t, "fcm", "DUMMY_FCM", pusher.Last().Client.FCMToken) } func TestCompatUpdateFCM(t *testing.T) { @@ -514,7 +514,7 @@ func TestCompatUpdateFCM(t *testing.T) { s0 := tt.RequestPost[gin.H](t, baseUrl, fmt.Sprintf("/send.php?user_id=%d&user_key=%s&title=%s", userid, userkey, url.QueryEscape("msg_1")), nil) tt.AssertEqual(t, "success", true, s0["success"]) - tt.AssertEqual(t, "fcm", "DUMMY_FCM", *pusher.Last().Client.FCMToken) + tt.AssertEqual(t, "fcm", "DUMMY_FCM", pusher.Last().Client.FCMToken) upd := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/update.php?user_id=%d&user_key=%s&fcm_token=%s", userid, userkey, "NEW_FCM")) tt.AssertEqual(t, "success", true, upd["success"]) @@ -534,7 +534,7 @@ func TestCompatUpdateFCM(t *testing.T) { s1 := tt.RequestPost[gin.H](t, baseUrl, fmt.Sprintf("/send.php?user_id=%d&user_key=%s&title=%s", userid, newkey, url.QueryEscape("msg_2")), nil) tt.AssertEqual(t, "success", true, s1["success"]) - tt.AssertEqual(t, "fcm", "NEW_FCM", *pusher.Last().Client.FCMToken) + tt.AssertEqual(t, "fcm", "NEW_FCM", pusher.Last().Client.FCMToken) } func TestCompatUpgrade(t *testing.T) {