From 91fbf6f609cc16c80a8b5902c39fbd339057bbaa Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 10 Sep 2024 15:09:08 +0300 Subject: [PATCH] legacymigrate: fix things --- .gitignore | 2 +- cmd/mautrix-whatsapp/legacymigrate.go | 38 +++++- cmd/mautrix-whatsapp/legacymigrate.sql | 129 +++++++++++++++--- cmd/mautrix-whatsapp/main.go | 8 +- go.mod | 2 +- go.sum | 4 +- pkg/connector/config.go | 10 +- pkg/connector/connector.go | 9 +- pkg/connector/dbmeta.go | 16 ++- pkg/connector/events.go | 15 +- pkg/connector/example-config.yaml | 2 +- pkg/connector/handlematrix.go | 13 +- pkg/connector/wadb/database.go | 18 ++- .../wadb/upgrades/00-latest-schema.sql | 67 +++++++++ pkg/connector/wadb/upgrades/upgrades.go | 16 +++ 15 files changed, 311 insertions(+), 38 deletions(-) create mode 100644 pkg/connector/wadb/upgrades/00-latest-schema.sql create mode 100644 pkg/connector/wadb/upgrades/upgrades.go diff --git a/.gitignore b/.gitignore index 4f2b27b..58688b4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,10 +4,10 @@ !.pre-commit-config.yaml !example-config.yaml -*.session *.json *.db *.log +*.bak /mautrix-whatsapp /start diff --git a/cmd/mautrix-whatsapp/legacymigrate.go b/cmd/mautrix-whatsapp/legacymigrate.go index 7e8de58..16e478b 100644 --- a/cmd/mautrix-whatsapp/legacymigrate.go +++ b/cmd/mautrix-whatsapp/legacymigrate.go @@ -2,8 +2,10 @@ package main import ( _ "embed" + "strings" up "go.mau.fi/util/configupgrade" + "go.mau.fi/util/dbutil/litestream" "maunium.net/go/mautrix/bridgev2/bridgeconfig" ) @@ -26,9 +28,41 @@ ALTER TABLE "user" RENAME TO user_old; //go:embed legacymigrate.sql var legacyMigrateCopyData string -//lint:ignore U1000 - TODO use this function +func init() { + litestream.Functions["split_part"] = func(input, delimiter string, partNum int) string { + // split_part is 1-indexed + partNum++ + parts := strings.Split(input, delimiter) + if len(parts) <= partNum { + return "" + } + return parts[partNum] + } +} + func migrateLegacyConfig(helper up.Helper) { helper.Set(up.Str, "maunium.net/go/mautrix-whatsapp", "encryption", "pickle_key") + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"whatsapp", "os_name"}, []string{"network", "os_name"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"whatsapp", "browser_name"}, []string{"network", "browser_name"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"whatsapp", "proxy"}, []string{"network", "proxy"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"whatsapp", "get_proxy_url"}, []string{"network", "get_proxy_url"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"whatsapp", "proxy_only_login"}, []string{"network", "proxy_only_login"}) bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "displayname_template"}, []string{"network", "displayname_template"}) - // TODO other fields + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "call_start_notices"}, []string{"network", "call_start_notices"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "send_presence_on_typing"}, []string{"network", "send_presence_on_typing"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "enable_status_broadcast"}, []string{"network", "enable_status_broadcast"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "disable_status_broadcast_send"}, []string{"network", "disable_status_broadcast_send"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "mute_status_broadcast"}, []string{"network", "mute_status_broadcast"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "status_broadcast_tag"}, []string{"network", "status_broadcast_tag"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "whatsapp_thumbnail"}, []string{"network", "whatsapp_thumbnail"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "url_previews"}, []string{"network", "url_previews"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "force_active_delivery_receipts"}, []string{"network", "force_active_delivery_receipts"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "history_sync", "request_full_sync"}, []string{"network", "history_sync", "request_full_sync"}) + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "history_sync", "full_sync_config", "days_limit"}, []string{"network", "history_sync", "full_sync_config", "days_limit"}) + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "history_sync", "full_sync_config", "size_limit_mb"}, []string{"network", "history_sync", "full_sync_config", "size_limit_mb"}) + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "history_sync", "full_sync_config", "storage_quota_mb"}, []string{"network", "history_sync", "full_sync_config", "storage_quota_mb"}) + bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "history_sync", "media_requests", "auto_request_media"}, []string{"network", "history_sync", "media_requests", "auto_request_media"}) + bridgeconfig.CopyToOtherLocation(helper, up.Str, []string{"bridge", "history_sync", "media_requests", "request_method"}, []string{"network", "history_sync", "media_requests", "request_method"}) + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "history_sync", "media_requests", "request_local_time"}, []string{"network", "history_sync", "media_requests", "request_local_time"}) + bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "history_sync", "media_requests", "max_async_handle"}, []string{"network", "history_sync", "media_requests", "max_async_handle"}) } diff --git a/cmd/mautrix-whatsapp/legacymigrate.sql b/cmd/mautrix-whatsapp/legacymigrate.sql index 7a20e50..8fd0afa 100644 --- a/cmd/mautrix-whatsapp/legacymigrate.sql +++ b/cmd/mautrix-whatsapp/legacymigrate.sql @@ -20,7 +20,8 @@ SELECT 'phone_last_seen', phone_last_seen, 'phone_last_pinged', phone_last_pinged, 'timezone', timezone - ) -- metadata + ), -- metadata + '{}' -- remote_profile FROM user_old WHERE username<>'' AND device<>0; @@ -51,6 +52,9 @@ SELECT ) -- metadata FROM puppet_old; +INSERT INTO ghost (bridge_id, id, name, avatar_id, avatar_hash, avatar_mxc, name_set, avatar_set, contact_info_set, is_bot, identifiers, metadata) +VALUES ('', '', '', '', '', '', false, false, false, false, '[]', '{}'); + INSERT INTO portal ( bridge_id, id, receiver, mxid, parent_id, parent_receiver, relay_bridge_id, relay_login_id, other_user_id, name, topic, avatar_id, avatar_hash, avatar_mxc, name_set, avatar_set, topic_set, @@ -98,21 +102,35 @@ SELECT last_read_ts * 1000000000 -- last_read TODO check multiplier FROM user_portal_old; +ALTER TABLE message_old ADD COLUMN combined_id TEXT; +UPDATE message_old SET combined_id = chat_jid || ':' || ( + CASE WHEN sender LIKE '%:%@s.whatsapp.net' + THEN (split_part(replace(sender, '@s.whatsapp.net', ''), ':', 1) || '@s.whatsapp.net') + ELSE sender + END +) || ':' || jid; + INSERT INTO message ( bridge_id, id, part_id, mxid, room_id, room_receiver, sender_id, sender_mxid, timestamp, edit_count, metadata ) SELECT '', -- bridge_id - jid, -- id FIXME requires prefix + combined_id, -- id '', -- part_id mxid, chat_jid, -- room_id CASE WHEN chat_receiver LIKE '%@s.whatsapp.net' THEN chat_receiver ELSE '' END, -- room_receiver - sender, -- sender_id + CASE WHEN sender=chat_jid THEN '' ELSE split_part(replace(sender, '@s.whatsapp.net', ''), ':', 1) END, -- sender_id sender_mxid, -- sender_mxid timestamp * 1000000000, -- timestamp TODO check multiplier 0, -- edit_count - '{}' -- metadata + -- only: postgres + jsonb_build_object + -- only: sqlite (line commented) +-- json_object + ( + 'sender_device_id', CAST(nullif(split_part(replace(sender, '@s.whatsapp.net', ''), ':', 2), '') AS INTEGER) + ) -- metadata FROM message_old; INSERT INTO reaction ( @@ -120,17 +138,27 @@ INSERT INTO reaction ( ) SELECT '', -- bridge_id - target_jid, -- message_id FIXME requires prefix + message_old.combined_id, -- message_id '', -- message_part_id - sender, -- sender_id + replace(reaction_old.sender, '@s.whatsapp.net', ''), -- sender_id '', -- emoji_id - chat_jid, -- room_id - CASE WHEN chat_receiver LIKE '%@s.whatsapp.net' THEN chat_receiver ELSE '' END, -- room_receiver - mxid, + reaction_old.chat_jid, -- room_id + CASE WHEN reaction_old.chat_receiver LIKE '%@s.whatsapp.net' THEN reaction_old.chat_receiver ELSE '' END, -- room_receiver + reaction_old.mxid, 0, -- timestamp '', -- emoji - '{}' -- metadata -FROM reaction_old; + -- only: postgres + jsonb_build_object + -- only: sqlite (line commented) +-- json_object + ( + 'sender_device_id', CAST(nullif(split_part(replace(reaction_old.sender, '@s.whatsapp.net', ''), ':', 2), '') AS INTEGER) + ) -- metadata +FROM reaction_old +LEFT JOIN message_old + ON reaction_old.chat_jid = message_old.chat_jid + AND reaction_old.chat_receiver = message_old.chat_receiver + AND reaction_old.target_jid = message_old.jid; INSERT INTO disappearing_message (bridge_id, mx_room, mxid, type, timer, disappear_at) SELECT @@ -152,7 +180,7 @@ SELECT CASE WHEN portal_receiver LIKE '%@s.whatsapp.net' THEN portal_receiver ELSE '' END, -- portal_receiver (SELECT id FROM user_login WHERE user_login.user_mxid=backfill_queue_old.user_mxid), -- user_login_id COUNT(*), -- batch_count - COUNT(*) == COUNT(completed_at), -- is_done + COUNT(*) = COUNT(completed_at), -- is_done '', -- cursor '', -- oldest_message_id -- only: postgres @@ -165,14 +193,81 @@ FROM backfill_queue_old WHERE type IN (0, 200) GROUP BY user_mxid, portal_jid, portal_receiver; +INSERT INTO whatsapp_poll_option_id (bridge_id, msg_mxid, opt_id, opt_hash) +SELECT '', msg_mxid, opt_id, opt_hash +FROM poll_option_id_old; + +INSERT INTO whatsapp_history_sync_conversation ( + bridge_id, user_login_id, chat_jid, last_message_timestamp, archived, pinned, mute_end_time, + end_of_history_transfer_type, ephemeral_expiration, ephemeral_setting_timestamp, marked_as_unread, unread_count +) +SELECT + '', + user_login.id, + portal_jid, + -- only: postgres + CAST(EXTRACT(EPOCH FROM last_message_timestamp) AS BIGINT), + -- only: sqlite (line commented) +-- unixepoch(last_message_timestamp), + archived, + CASE WHEN pinned > 0 THEN true ELSE false END, + -- only: postgres + CAST(EXTRACT(EPOCH FROM mute_end_time) AS BIGINT), + -- only: sqlite (line commented) +-- unixepoch(mute_end_time), + end_of_history_transfer_type, + ephemeral_expiration, + 0, + marked_as_unread, + unread_count +FROM history_sync_conversation_old +LEFT JOIN user_login ON user_login.user_mxid = history_sync_conversation_old.user_mxid +WHERE user_login.id IS NOT NULL; + +INSERT INTO whatsapp_history_sync_message ( + bridge_id, user_login_id, chat_jid, message_id, timestamp, data, inserted_time +) +SELECT + '', + user_login.id, + conversation_id, + message_id, + -- only: postgres + CAST(EXTRACT(EPOCH FROM timestamp) AS BIGINT), + -- only: sqlite (line commented) +-- unixepoch(timestamp), + data, + -- only: postgres + CAST(EXTRACT(EPOCH FROM inserted_time) AS BIGINT) + -- only: sqlite (line commented) +-- unixepoch(inserted_time) +FROM history_sync_message_old +LEFT JOIN user_login ON user_login.user_mxid = history_sync_message_old.user_mxid +WHERE user_login.id IS NOT NULL; + +INSERT INTO whatsapp_media_backfill_request ( + bridge_id, user_login_id, portal_id, portal_receiver, event_id, media_key, status, error +) +SELECT + '', + user_login.id, + portal_jid, + CASE WHEN portal_receiver LIKE '%@s.whatsapp.net' THEN portal_receiver ELSE '' END, + event_id, + media_key, + status, + error +FROM media_backfill_requests_old +LEFT JOIN user_login ON user_login.user_mxid = media_backfill_requests_old.user_mxid +WHERE user_login.id IS NOT NULL; + DROP TABLE backfill_queue_old; DROP TABLE backfill_state_old; DROP TABLE disappearing_message_old; --- TODO migrate these tables --- DROP TABLE history_sync_message_old; --- DROP TABLE history_sync_conversation_old; --- DROP TABLE media_backfill_requests_old; --- DROP TABLE poll_option_id_old; +DROP TABLE history_sync_message_old; +DROP TABLE history_sync_conversation_old; +DROP TABLE media_backfill_requests_old; +DROP TABLE poll_option_id_old; DROP TABLE user_portal_old; DROP TABLE reaction_old; DROP TABLE message_old; diff --git a/cmd/mautrix-whatsapp/main.go b/cmd/mautrix-whatsapp/main.go index 826b881..a50a6da 100644 --- a/cmd/mautrix-whatsapp/main.go +++ b/cmd/mautrix-whatsapp/main.go @@ -1,9 +1,11 @@ package main import ( + "maunium.net/go/mautrix/bridgev2/bridgeconfig" "maunium.net/go/mautrix/bridgev2/matrix/mxmain" "maunium.net/go/mautrix-whatsapp/pkg/connector" + "maunium.net/go/mautrix-whatsapp/pkg/connector/wadb/upgrades" ) // Information to find out exactly which commit the bridge was built from. @@ -24,12 +26,16 @@ var m = mxmain.BridgeMain{ } func main() { + bridgeconfig.HackyMigrateLegacyNetworkConfig = migrateLegacyConfig m.PostInit = func() { m.CheckLegacyDB( 57, "v0.8.6", "v0.11.0", - m.LegacyMigrateSimple(legacyMigrateRenameTables, legacyMigrateCopyData, 16), + m.LegacyMigrateWithAnotherUpgrader( + legacyMigrateRenameTables, legacyMigrateCopyData, 17, + upgrades.Table, "whatsapp_version", 1, + ), true, ) } diff --git a/go.mod b/go.mod index f823037..da42de5 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/sync v0.8.0 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.20.1-0.20240906145130-6b055b1475bd + maunium.net/go/mautrix v0.20.1-0.20240910112932-ffdb1d575e5f ) require ( diff --git a/go.sum b/go.sum index 19faa24..0b8f227 100644 --- a/go.sum +++ b/go.sum @@ -114,5 +114,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.20.1-0.20240906145130-6b055b1475bd h1:gfiJD2cPS9iUek1UI+DOUn08zogF4kmu7XYfBqSrAU4= -maunium.net/go/mautrix v0.20.1-0.20240906145130-6b055b1475bd/go.mod h1:l6nYvD5/FMSrAZ/IP1AqJV0b47SRl/0uQNRiy4CcSVk= +maunium.net/go/mautrix v0.20.1-0.20240910112932-ffdb1d575e5f h1:T4K6V2Ige2mshH7FW69xLep23GBrW7xS1sxomaKe1Hg= +maunium.net/go/mautrix v0.20.1-0.20240910112932-ffdb1d575e5f/go.mod h1:l6nYvD5/FMSrAZ/IP1AqJV0b47SRl/0uQNRiy4CcSVk= diff --git a/pkg/connector/config.go b/pkg/connector/config.go index f212144..072d922 100644 --- a/pkg/connector/config.go +++ b/pkg/connector/config.go @@ -79,8 +79,8 @@ func upgradeConfig(helper up.Helper) { helper.Copy(up.Str, "os_name") helper.Copy(up.Str, "browser_name") - helper.Copy(up.Str, "proxy") - helper.Copy(up.Str, "get_proxy_url") + helper.Copy(up.Str|up.Null, "proxy") + helper.Copy(up.Str|up.Null, "get_proxy_url") helper.Copy(up.Bool, "proxy_only_login") helper.Copy(up.Str, "displayname_template") @@ -95,9 +95,9 @@ func upgradeConfig(helper up.Helper) { helper.Copy(up.Bool, "url_previews") helper.Copy(up.Bool, "history_sync", "request_full_sync") - helper.Copy(up.Int, "history_sync", "full_sync_config", "days_limit") - helper.Copy(up.Int, "history_sync", "full_sync_config", "size_mb_limit") - helper.Copy(up.Int, "history_sync", "full_sync_config", "storage_quota_mb") + helper.Copy(up.Int|up.Null, "history_sync", "full_sync_config", "days_limit") + helper.Copy(up.Int|up.Null, "history_sync", "full_sync_config", "size_mb_limit") + helper.Copy(up.Int|up.Null, "history_sync", "full_sync_config", "storage_quota_mb") helper.Copy(up.Bool, "history_sync", "media_requests", "auto_request_media") helper.Copy(up.Str, "history_sync", "media_requests", "request_method") helper.Copy(up.Int, "history_sync", "media_requests", "request_local_time") diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 3d9f3ba..2f90ff6 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -12,6 +12,7 @@ import ( "google.golang.org/protobuf/proto" "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix-whatsapp/pkg/connector/wadb" "maunium.net/go/mautrix-whatsapp/pkg/msgconv" "maunium.net/go/mautrix-whatsapp/pkg/waid" ) @@ -21,6 +22,7 @@ type WhatsAppConnector struct { Config Config DeviceStore *sqlstore.Container MsgConv *msgconv.MessageConverter + DB *wadb.Database } var _ bridgev2.NetworkConnector = (*WhatsAppConnector)(nil) @@ -44,6 +46,7 @@ func (wa *WhatsAppConnector) GetName() bridgev2.BridgeName { func (wa *WhatsAppConnector) Init(bridge *bridgev2.Bridge) { wa.Bridge = bridge wa.MsgConv = msgconv.New(bridge) + wa.DB = wadb.New(bridge.DB.Database, bridge.Log.With().Str("db_section", "whatsapp").Logger()) wa.DeviceStore = sqlstore.NewWithDB( bridge.DB.RawDB, @@ -66,11 +69,15 @@ func (wa *WhatsAppConnector) Init(bridge *bridgev2.Bridge) { } } -func (wa *WhatsAppConnector) Start(_ context.Context) error { +func (wa *WhatsAppConnector) Start(ctx context.Context) error { err := wa.DeviceStore.Upgrade() if err != nil { return bridgev2.DBUpgradeError{Err: err, Section: "whatsmeow"} } + err = wa.DB.Upgrade(ctx) + if err != nil { + return bridgev2.DBUpgradeError{Err: err, Section: "whatsapp"} + } ver, err := whatsmeow.GetLatestVersion(nil) if err != nil { diff --git a/pkg/connector/dbmeta.go b/pkg/connector/dbmeta.go index e546891..026f46e 100644 --- a/pkg/connector/dbmeta.go +++ b/pkg/connector/dbmeta.go @@ -10,8 +10,12 @@ func (wa *WhatsAppConnector) GetDBMetaTypes() database.MetaTypes { Ghost: func() any { return &GhostMetadata{} }, - Message: nil, - Reaction: nil, + Message: func() any { + return &MessageMetadata{} + }, + Reaction: func() any { + return &ReactionMetadata{} + }, Portal: func() any { return &PortalMetadata{} }, @@ -26,6 +30,14 @@ type UserLoginMetadata struct { //TODO: Add phone last ping/seen } +type MessageMetadata struct { + SenderDeviceID uint16 `json:"sender_device_id,omitempty"` +} + +type ReactionMetadata struct { + SenderDeviceID uint16 `json:"sender_device_id,omitempty"` +} + type PortalMetadata struct { DisappearingTimerSetAt int64 `json:"disappearing_timer_set_at,omitempty"` } diff --git a/pkg/connector/events.go b/pkg/connector/events.go index 4717b66..f131158 100644 --- a/pkg/connector/events.go +++ b/pkg/connector/events.go @@ -27,6 +27,7 @@ var ( _ bridgev2.RemoteEventThatMayCreatePortal = (*WAMessageEvent)(nil) _ bridgev2.RemoteReaction = (*WAMessageEvent)(nil) _ bridgev2.RemoteReactionRemove = (*WAMessageEvent)(nil) + _ bridgev2.RemoteReactionWithMeta = (*WAMessageEvent)(nil) _ bridgev2.RemoteEdit = (*WAMessageEvent)(nil) _ bridgev2.RemoteMessageRemove = (*WAMessageEvent)(nil) ) @@ -77,6 +78,12 @@ func (evt *WAMessageEvent) GetReactionEmoji() (string, networkid.EmojiID) { return evt.Message.Message.GetReactionMessage().GetText(), "" } +func (evt *WAMessageEvent) GetReactionDBMetadata() any { + return &ReactionMetadata{ + SenderDeviceID: evt.Info.Sender.Device, + } +} + func (evt *WAMessageEvent) GetRemovedEmojiID() networkid.EmojiID { return "" } @@ -129,5 +136,11 @@ func (evt *WAMessageEvent) GetTransactionID() networkid.TransactionID { } func (evt *WAMessageEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI) (*bridgev2.ConvertedMessage, error) { - return evt.wa.Main.MsgConv.ToMatrix(ctx, portal, evt.wa.Client, intent, evt.Message.Message), nil + converted := evt.wa.Main.MsgConv.ToMatrix(ctx, portal, evt.wa.Client, intent, evt.Message.Message) + for _, part := range converted.Parts { + part.DBMetadata = &MessageMetadata{ + SenderDeviceID: evt.Info.Sender.Device, + } + } + return converted, nil } diff --git a/pkg/connector/example-config.yaml b/pkg/connector/example-config.yaml index 6502121..1ff6c89 100644 --- a/pkg/connector/example-config.yaml +++ b/pkg/connector/example-config.yaml @@ -16,7 +16,7 @@ proxy_only_login: false # {{.PushName}} - nickname set by the WhatsApp user # {{.BusinessName}} - validated WhatsApp business name # {{.Phone}} - phone number (international format) -# {{.FullName}} - Name you set in the contacts list +# {{.FullName}} - Name you set in the contacts list displayname_template: "{{or .FullName .BusinessName .PushName .Phone}} (WA)" # Should incoming calls send a message to the Matrix room? diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index d045fe4..b05fb68 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -47,8 +47,11 @@ func (wa *WhatsAppClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2 return &bridgev2.MatrixMessageResponse{ DB: &database.Message{ ID: wrappedMsgID, - SenderID: networkid.UserID(wa.UserLogin.ID), + SenderID: waid.MakeUserID(wa.JID), Timestamp: resp.Timestamp, + Metadata: &MessageMetadata{ + SenderDeviceID: wa.JID.Device, + }, }, RemovePending: networkid.TransactionID(wrappedMsgID), }, nil @@ -56,7 +59,7 @@ func (wa *WhatsAppClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2 func (wa *WhatsAppClient) PreHandleMatrixReaction(_ context.Context, msg *bridgev2.MatrixReaction) (bridgev2.MatrixReactionPreResponse, error) { return bridgev2.MatrixReactionPreResponse{ - SenderID: networkid.UserID(wa.UserLogin.ID), + SenderID: waid.MakeUserID(wa.JID), Emoji: variationselector.Remove(msg.Content.RelatesTo.Key), MaxReactions: 1, }, nil @@ -82,7 +85,11 @@ func (wa *WhatsAppClient) HandleMatrixReaction(ctx context.Context, msg *bridgev resp, err := wa.Client.SendMessage(ctx, portalJID, reactionMsg) zerolog.Ctx(ctx).Trace().Any("response", resp).Msg("WhatsApp reaction response") - return nil, err + return &database.Reaction{ + Metadata: &ReactionMetadata{ + SenderDeviceID: wa.JID.Device, + }, + }, err } func (wa *WhatsAppClient) HandleMatrixReactionRemove(ctx context.Context, msg *bridgev2.MatrixReactionRemove) error { diff --git a/pkg/connector/wadb/database.go b/pkg/connector/wadb/database.go index 18739ea..59d9c05 100644 --- a/pkg/connector/wadb/database.go +++ b/pkg/connector/wadb/database.go @@ -1,3 +1,19 @@ package wadb -// TODO: ADD POLL AND HISTORYSYNC AND MEDIABACKFILLREQUEST DBs +import ( + "github.com/rs/zerolog" + "go.mau.fi/util/dbutil" + + "maunium.net/go/mautrix-whatsapp/pkg/connector/wadb/upgrades" +) + +type Database struct { + *dbutil.Database +} + +func New(db *dbutil.Database, log zerolog.Logger) *Database { + db = db.Child("whatsapp_version", upgrades.Table, dbutil.ZeroLogger(log)) + return &Database{ + Database: db, + } +} diff --git a/pkg/connector/wadb/upgrades/00-latest-schema.sql b/pkg/connector/wadb/upgrades/00-latest-schema.sql new file mode 100644 index 0000000..608eaa4 --- /dev/null +++ b/pkg/connector/wadb/upgrades/00-latest-schema.sql @@ -0,0 +1,67 @@ +-- v0 -> v1 (compatible with v1+): Latest revision + +CREATE TABLE whatsapp_poll_option_id ( + bridge_id TEXT, + msg_mxid TEXT, + opt_id TEXT, + opt_hash bytea CHECK ( length(opt_hash) = 32 ), + + PRIMARY KEY (bridge_id, msg_mxid, opt_id), + CONSTRAINT whatsapp_poll_option_unique_hash UNIQUE (bridge_id, msg_mxid, opt_hash), + CONSTRAINT message_mxid_fkey FOREIGN KEY (bridge_id, msg_mxid) + REFERENCES message(bridge_id, mxid) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE TABLE whatsapp_history_sync_conversation ( + bridge_id TEXT, + user_login_id TEXT, + chat_jid TEXT, + + last_message_timestamp BIGINT, + archived BOOLEAN, + pinned BOOLEAN, + mute_end_time BIGINT, + end_of_history_transfer_type INTEGER, + ephemeral_expiration INTEGER, + ephemeral_setting_timestamp BIGINT, + marked_as_unread BOOLEAN, + unread_count INTEGER, + + PRIMARY KEY (bridge_id, user_login_id, chat_jid), + CONSTRAINT whatsapp_history_sync_conversation_user_login_fkey FOREIGN KEY (bridge_id, user_login_id) + REFERENCES user_login(bridge_id, id) ON UPDATE CASCADE ON DELETE CASCADE +); + +CREATE TABLE whatsapp_history_sync_message ( + bridge_id TEXT, + user_login_id TEXT, + chat_jid TEXT, + message_id TEXT, + timestamp BIGINT, + data bytea, + inserted_time BIGINT, + + PRIMARY KEY (bridge_id, user_login_id, chat_jid, message_id), + CONSTRAINT whatsapp_history_sync_message_user_login_fkey FOREIGN KEY (bridge_id, user_login_id) + REFERENCES user_login(bridge_id, id) ON UPDATE CASCADE ON DELETE CASCADE, + CONSTRAINT whatsapp_history_sync_message_conversation_fkey FOREIGN KEY (bridge_id, user_login_id, chat_jid) + REFERENCES whatsapp_history_sync_conversation(bridge_id, user_login_id, chat_jid) ON UPDATE CASCADE ON DELETE CASCADE +); + +CREATE TABLE whatsapp_media_backfill_request ( + bridge_id TEXT, + user_login_id TEXT, + portal_id TEXT, + portal_receiver TEXT, + + event_id TEXT, + media_key bytea, + status INTEGER, + error TEXT, + + PRIMARY KEY (bridge_id, user_login_id, portal_id, portal_receiver, event_id), + CONSTRAINT whatsapp_media_backfill_request_user_login_fkey FOREIGN KEY (bridge_id, user_login_id) + REFERENCES user_login(bridge_id, id) ON UPDATE CASCADE ON DELETE CASCADE, + CONSTRAINT whatsapp_media_backfill_request_portal_fkey FOREIGN KEY (bridge_id, portal_id, portal_receiver) + REFERENCES portal(bridge_id, id, receiver) ON UPDATE CASCADE ON DELETE CASCADE +); diff --git a/pkg/connector/wadb/upgrades/upgrades.go b/pkg/connector/wadb/upgrades/upgrades.go new file mode 100644 index 0000000..22c5414 --- /dev/null +++ b/pkg/connector/wadb/upgrades/upgrades.go @@ -0,0 +1,16 @@ +package upgrades + +import ( + "embed" + + "go.mau.fi/util/dbutil" +) + +var Table dbutil.UpgradeTable + +//go:embed *.sql +var rawUpgrades embed.FS + +func init() { + Table.RegisterFS(rawUpgrades) +}