From 1618051a126c4828ac78f1119398ee19ad013450 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 30 Aug 2023 20:45:14 +0300 Subject: [PATCH] Store phone settings for users --- database/upgrades/00-latest-revision.sql | 3 +- database/upgrades/06-phone-settings.sql | 2 ++ database/user.go | 35 +++++++++++++++++------ libgm/gmproto/settings.pb.go | 6 ++-- libgm/gmproto/settings.pb.raw | Bin 1734 -> 1754 bytes libgm/gmproto/settings.proto | 2 +- user.go | 17 ++++++++++- 7 files changed, 50 insertions(+), 15 deletions(-) create mode 100644 database/upgrades/06-phone-settings.sql diff --git a/database/upgrades/00-latest-revision.sql b/database/upgrades/00-latest-revision.sql index 2ecea0e..fb682d9 100644 --- a/database/upgrades/00-latest-revision.sql +++ b/database/upgrades/00-latest-revision.sql @@ -1,4 +1,4 @@ --- v0 -> v5: Latest revision +-- v0 -> v6: Latest revision CREATE TABLE "user" ( -- only: postgres @@ -12,6 +12,7 @@ CREATE TABLE "user" ( self_participant_ids jsonb NOT NULL DEFAULT '[]', sim_metadata jsonb NOT NULL DEFAULT '{}', + settings jsonb NOT NULL DEFAULT '{}', management_room TEXT, space_room TEXT, diff --git a/database/upgrades/06-phone-settings.sql b/database/upgrades/06-phone-settings.sql new file mode 100644 index 0000000..aec2514 --- /dev/null +++ b/database/upgrades/06-phone-settings.sql @@ -0,0 +1,2 @@ +-- v6: Store phone settings for users +ALTER TABLE "user" ADD COLUMN settings jsonb NOT NULL DEFAULT '{}'; diff --git a/database/user.go b/database/user.go index 3000e7d..0a32ba1 100644 --- a/database/user.go +++ b/database/user.go @@ -47,19 +47,26 @@ func (uq *UserQuery) getDB() *Database { } func (uq *UserQuery) GetAllWithSession(ctx context.Context) ([]*User, error) { - return getAll[*User](uq, ctx, `SELECT rowid, mxid, phone_id, session, self_participant_ids, sim_metadata, management_room, space_room, access_token FROM "user" WHERE session IS NOT NULL`) + return getAll[*User](uq, ctx, `SELECT rowid, mxid, phone_id, session, self_participant_ids, sim_metadata, settings, management_room, space_room, access_token FROM "user" WHERE session IS NOT NULL`) } func (uq *UserQuery) GetAllWithDoublePuppet(ctx context.Context) ([]*User, error) { - return getAll[*User](uq, ctx, `SELECT rowid, mxid, phone_id, session, self_participant_ids, sim_metadata, management_room, space_room, access_token FROM "user" WHERE access_token<>''`) + return getAll[*User](uq, ctx, `SELECT rowid, mxid, phone_id, session, self_participant_ids, sim_metadata, settings, management_room, space_room, access_token FROM "user" WHERE access_token<>''`) } func (uq *UserQuery) GetByRowID(ctx context.Context, rowID int) (*User, error) { - return get[*User](uq, ctx, `SELECT rowid, mxid, phone_id, session, self_participant_ids, sim_metadata, management_room, space_room, access_token FROM "user" WHERE rowid=$1`, rowID) + return get[*User](uq, ctx, `SELECT rowid, mxid, phone_id, session, self_participant_ids, sim_metadata, settings, management_room, space_room, access_token FROM "user" WHERE rowid=$1`, rowID) } func (uq *UserQuery) GetByMXID(ctx context.Context, userID id.UserID) (*User, error) { - return get[*User](uq, ctx, `SELECT rowid, mxid, phone_id, session, self_participant_ids, sim_metadata, management_room, space_room, access_token FROM "user" WHERE mxid=$1`, userID) + return get[*User](uq, ctx, `SELECT rowid, mxid, phone_id, session, self_participant_ids, sim_metadata, settings, management_room, space_room, access_token FROM "user" WHERE mxid=$1`, userID) +} + +type Settings struct { + RCSEnabled bool `json:"rcs_enabled"` + ReadReceipts bool `json:"read_receipts"` + TypingNotifications bool `json:"typing_notifications"` + IsDefaultSMSApp bool `json:"is_default_sms_app"` } type User struct { @@ -79,13 +86,15 @@ type User struct { simMetadata map[string]*gmproto.SIMCard simMetadataLock sync.RWMutex + Settings Settings + AccessToken string } func (user *User) Scan(row dbutil.Scannable) (*User, error) { var phoneID, session, managementRoom, spaceRoom, accessToken sql.NullString - var selfParticipantIDs, simMetadata string - err := row.Scan(&user.RowID, &user.MXID, &phoneID, &session, &selfParticipantIDs, &simMetadata, &managementRoom, &spaceRoom, &accessToken) + var selfParticipantIDs, simMetadata, settings string + err := row.Scan(&user.RowID, &user.MXID, &phoneID, &session, &selfParticipantIDs, &simMetadata, &settings, &managementRoom, &spaceRoom, &accessToken) if errors.Is(err, sql.ErrNoRows) { return nil, nil } else if err != nil { @@ -111,6 +120,10 @@ func (user *User) Scan(row dbutil.Scannable) (*User, error) { if err != nil { return nil, fmt.Errorf("failed to parse SIM metadata: %w", err) } + err = json.Unmarshal([]byte(settings), &user.Settings) + if err != nil { + return nil, fmt.Errorf("failed to parse settings: %w", err) + } user.PhoneID = phoneID.String user.AccessToken = accessToken.String user.ManagementRoom = id.RoomID(managementRoom.String) @@ -146,7 +159,11 @@ func (user *User) sqlVariables() []any { panic(err) } user.simMetadataLock.RUnlock() - return []any{user.MXID, phoneID, session, string(selfParticipantIDs), string(simMetadata), managementRoom, spaceRoom, accessToken} + settings, err := json.Marshal(&user.Settings) + if err != nil { + panic(err) + } + return []any{user.MXID, phoneID, session, string(selfParticipantIDs), string(simMetadata), string(settings), managementRoom, spaceRoom, accessToken} } func (user *User) IsSelfParticipantID(id string) bool { @@ -233,12 +250,12 @@ func (user *User) AddSelfParticipantID(ctx context.Context, id string) error { func (user *User) Insert(ctx context.Context) error { err := user.db.Conn(ctx). - QueryRowContext(ctx, `INSERT INTO "user" (mxid, phone_id, session, self_participant_ids, sim_metadata, management_room, space_room, access_token) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING rowid`, user.sqlVariables()...). + QueryRowContext(ctx, `INSERT INTO "user" (mxid, phone_id, session, self_participant_ids, sim_metadata, settings, management_room, space_room, access_token) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING rowid`, user.sqlVariables()...). Scan(&user.RowID) return err } func (user *User) Update(ctx context.Context) error { - _, err := user.db.Conn(ctx).ExecContext(ctx, `UPDATE "user" SET phone_id=$2, session=$3, self_participant_ids=$4, sim_metadata=$5, management_room=$6, space_room=$7, access_token=$8 WHERE mxid=$1`, user.sqlVariables()...) + _, err := user.db.Conn(ctx).ExecContext(ctx, `UPDATE "user" SET phone_id=$2, session=$3, self_participant_ids=$4, sim_metadata=$5, settings=$6, management_room=$7, space_room=$8, access_token=$9 WHERE mxid=$1`, user.sqlVariables()...) return err } diff --git a/libgm/gmproto/settings.pb.go b/libgm/gmproto/settings.pb.go index 51a990b..888f228 100644 --- a/libgm/gmproto/settings.pb.go +++ b/libgm/gmproto/settings.pb.go @@ -613,7 +613,7 @@ type RCSSettings struct { IsEnabled bool `protobuf:"varint,1,opt,name=isEnabled,proto3" json:"isEnabled,omitempty"` SendReadReceipts bool `protobuf:"varint,2,opt,name=sendReadReceipts,proto3" json:"sendReadReceipts,omitempty"` ShowTypingIndicators bool `protobuf:"varint,3,opt,name=showTypingIndicators,proto3" json:"showTypingIndicators,omitempty"` - Bool4 bool `protobuf:"varint,4,opt,name=bool4,proto3" json:"bool4,omitempty"` + IsDefaultSMSApp bool `protobuf:"varint,4,opt,name=isDefaultSMSApp,proto3" json:"isDefaultSMSApp,omitempty"` // uncertain, but this field seems to disappear when gmessages is un-defaulted } func (x *RCSSettings) Reset() { @@ -669,9 +669,9 @@ func (x *RCSSettings) GetShowTypingIndicators() bool { return false } -func (x *RCSSettings) GetBool4() bool { +func (x *RCSSettings) GetIsDefaultSMSApp() bool { if x != nil { - return x.Bool4 + return x.IsDefaultSMSApp } return false } diff --git a/libgm/gmproto/settings.pb.raw b/libgm/gmproto/settings.pb.raw index d0f4b66edcb849380bcc87fd3d2fd1ed947960c3..aac3c7b0276a6be4a85452e3cae8c765455492d9 100644 GIT binary patch delta 60 zcmX@cdy99&bQZ>~lV`B>YHD!tXBNAprX`l delta 22 ecmcb`dyIF(bQZ>ilV`B>PIhDy-R#HO!w3Ln)d%JP diff --git a/libgm/gmproto/settings.proto b/libgm/gmproto/settings.proto index e180b0b..4c7679e 100644 --- a/libgm/gmproto/settings.proto +++ b/libgm/gmproto/settings.proto @@ -64,7 +64,7 @@ message RCSSettings { bool isEnabled = 1; bool sendReadReceipts = 2; bool showTypingIndicators = 3; - bool bool4 = 4; + bool isDefaultSMSApp = 4; // uncertain, but this field seems to disappear when gmessages is un-defaulted } message BooleanFields2 { diff --git a/user.go b/user.go index 5c0eec7..465ceff 100644 --- a/user.go +++ b/user.go @@ -742,7 +742,21 @@ func (user *User) handleSettings(settings *gmproto.Settings) { return } ctx := context.TODO() - if user.SetSIMs(settings.SIMCards) { + changed := user.SetSIMs(settings.SIMCards) + newRCSSettings := settings.GetRCSSettings() + if user.Settings.RCSEnabled != newRCSSettings.GetIsEnabled() || + user.Settings.ReadReceipts != newRCSSettings.GetSendReadReceipts() || + user.Settings.TypingNotifications != newRCSSettings.GetShowTypingIndicators() || + user.Settings.IsDefaultSMSApp != newRCSSettings.GetIsDefaultSMSApp() { + user.Settings = database.Settings{ + RCSEnabled: newRCSSettings.GetIsEnabled(), + ReadReceipts: newRCSSettings.GetSendReadReceipts(), + TypingNotifications: newRCSSettings.GetShowTypingIndicators(), + IsDefaultSMSApp: newRCSSettings.GetIsDefaultSMSApp(), + } + changed = true + } + if changed { err := user.Update(ctx) if err != nil { user.zlog.Err(err).Msg("Failed to save SIM details") @@ -757,6 +771,7 @@ func (user *User) FillBridgeState(state status.BridgeState) status.BridgeState { } if state.StateEvent == status.StateConnected { state.Info["sims"] = user.GetSIMsForBridgeState() + state.Info["settings"] = user.Settings state.Info["battery_low"] = user.batteryLow state.Info["mobile_data"] = user.mobileData state.Info["browser_active"] = user.browserInactiveType == ""