Skip to content

feat(newsletter): mute/unmute channel notifications - #757

Merged
jlucaso1 merged 1 commit into
mainfrom
feat/newsletter-mute
Jun 8, 2026
Merged

feat(newsletter): mute/unmute channel notifications#757
jlucaso1 merged 1 commit into
mainfrom
feat/newsletter-mute

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

Closes the features-04 gap.

There was no way to mute a newsletter/channel — WA Web supports silencing follower-activity (and, for owners/admins, admin-activity) notifications, but the library exposed nothing.

Adds Newsletter::set_follower_mute(jid, muted) and Newsletter::set_admin_mute(jid, muted), both going through the vendored update_newsletter_user_setting MEX mutation. The wire shape matches WA Web exactly: { input: { newsletter_id, type, value } } where type is MUTE_FOLLOWER_ACTIVITY / MUTE_ADMIN_ACTIVITY and value is ON/OFF. WA Web's mute-expiration is local DB state (never on the wire), so the public API is a simple bool.

The generated op's input is an opaque string (relay-compiled, the input object type isn't expanded), so the structured object is passed via mex_request!'s raw-variables form rather than the typed Variables { input: String }.

Test: mute_variables_match_wa_web_shape locks the variables shape (newsletter_id / type / ON-OFF) so a wire-format regression is caught without a live server.

Verified against docs/captured-js/WAWeb/Newsletter/UpdateUserSettingJob.js (the { newsletter_id, type, value } call) and Mex/UpdateNewsletterUserSetting.js + UpdateNewsletterUserSettingJobMutation.graphql.js (doc_id 31938993655691868, matches the vendored op).

Adds Newsletter::set_follower_mute and set_admin_mute, mirroring WA Web's
WAWebNewsletterUpdateUserSettingJob. Both go through the vendored
update_newsletter_user_setting MEX mutation with the wire shape
{ input: { newsletter_id, type, value } }, where type is
MUTE_FOLLOWER_ACTIVITY / MUTE_ADMIN_ACTIVITY and value is ON/OFF. The
mute-expiration WA Web tracks is local DB state, not on the wire, so the
public API is a simple bool.

The generated op's input type is an opaque string, so the structured input
object is passed via mex_request!'s raw-variables form. Verified against
docs/captured-js/WAWeb/Newsletter/UpdateUserSettingJob.js and
Mex/UpdateNewsletterUserSetting*.
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8650dde8-24dd-4bb5-b236-c132ae050008

📥 Commits

Reviewing files that changed from the base of the PR and between 0cb4ca5 and bb341cc.

📒 Files selected for processing (1)
  • src/features/newsletter.rs

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added ability to mute and unmute follower-activity notifications in newsletters.
    • Added ability to mute and unmute admin-activity notifications in newsletters.

Walkthrough

This PR extends the Newsletter feature with mute/unmute operations for follower-activity and admin-activity notifications. Two public methods execute the update_newsletter_user_setting MEX mutation with payload validation, supported by a variables builder and test to ensure wire format correctness.

Changes

Newsletter notification mute

Layer / File(s) Summary
Notification mute API and MEX integration
src/features/newsletter.rs
MEX operation import extended to update_newsletter_user_setting. Public set_follower_mute and set_admin_mute methods delegate to internal set_user_setting_mute, which executes the mutation and validates payload, returning MexError::PayloadParsing if result is null.
Mute variables builder and validation test
src/features/newsletter.rs
Helper mute_user_setting_variables constructs exact JSON shape (newsletter_id, type, value as "ON"/"OFF" string). Test mute_variables_match_wa_web_shape validates both mute and unmute cases match WA Web wire format.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • oxidezap/whatsapp-rust#390: Main PR that introduced the initial Newsletter feature; this PR extends it with notification mute/unmute methods.

Suggested labels

api-design

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: adding mute/unmute functionality for newsletter channel notifications.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the feature gap, implementation details, wire format verification, and testing approach.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/newsletter-mute

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

Benchmark Results

67 unchanged benchmark(s)
Benchmark Current Baseline Change
reporting_token_benchmark::content_extraction_group::bench_content_extraction simple:setup_simple_message() 2,925 2,925 +0.0%
reporting_token_benchmark::content_extraction_group::bench_content_extraction extended:setup_extended_message() 8,446 8,446 +0.0%
reporting_token_benchmark::key_derivation_group::bench_key_derivation 31,317 31,317 +0.0%
reporting_token_benchmark::token_calculation_group::bench_token_calculation 13,827 13,827 +0.0%
reporting_token_benchmark::full_generation_group::bench_full_token_generation simple:setup_full_gen_simple() 49,485 49,485 +0.0%
reporting_token_benchmark::full_generation_group::bench_full_token_generation extended:setup_full_gen_extended() 55,001 55,001 +0.0%
reporting_token_benchmark::message_encoding_group::bench_message_encoding simple:setup_simple_message() 1,679 1,679 +0.0%
reporting_token_benchmark::message_encoding_group::bench_message_encoding extended:setup_extended_message() 4,393 4,393 +0.0%
send_receive_benchmark::dm_send::bench_dm_send text:setup_dm_send() 113,212 113,074 +0.1%
send_receive_benchmark::dm_recv::bench_dm_recv text:setup_dm_recv() 1,656,624 1,656,731 -0.0%
send_receive_benchmark::group_send::bench_group_send group_10:setup_group_send_10() 651,788 651,824 -0.0%
send_receive_benchmark::group_send::bench_group_send group_50:setup_group_send_50() 875,821 875,836 -0.0%
send_receive_benchmark::group_send::bench_group_send group_256:setup_group_send_256() 2,083,613 2,083,449 +0.0%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_10:setup_group_skdm_10() 748,899 748,298 +0.1%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_50:setup_group_skdm_50() 1,325,951 1,325,870 +0.0%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_256:setup_group_skdm_256() 4,378,939 4,359,859 +0.4%
send_receive_benchmark::group_recv::bench_group_recv text:setup_group_recv() 520,931 515,683 +1.0%
binary_benchmark::marshal_group::bench_marshal_allocating 45,381 45,381 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_allocating 45,431 45,431 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_allocating 66,334 66,334 +0.0%
binary_benchmark::marshal_group::bench_marshal_reusing_buffer 43,492 43,492 +0.0%
binary_benchmark::marshal_group::bench_marshal_reusing_buffer_vec_writer 45,487 45,487 +0.0%
binary_benchmark::marshal_group::bench_marshal_long_string 4,945 4,945 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_long_string 4,976 4,976 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_long_string 6,747 6,747 +0.0%
binary_benchmark::marshal_group::bench_marshal_huge_bytes_allocating 528,544 528,544 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_huge_bytes_allocating 528,165 528,165 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_huge_bytes_allocating 529,411 529,411 +0.0%
binary_benchmark::marshal_group::bench_marshal_many_children_allocating 5,417,732 5,417,732 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_many_children_allocating 5,362,047 5,362,047 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_many_children_allocating 13,276,365 13,276,365 +0.0%
binary_benchmark::unmarshal_group::bench_unmarshal small:setup_small_marshaled() 1,850 1,850 +0.0%
binary_benchmark::unmarshal_group::bench_unmarshal large:setup_large_marshaled() 29,217 29,217 +0.0%
binary_benchmark::unpack_group::bench_unpack_uncompressed 618 618 +0.0%
binary_benchmark::unpack_group::bench_unpack_compressed 672,890 672,890 +0.0%
binary_benchmark::attr_parser_group::bench_attr_parser attr_lookup:setup_attr_marshaled() 3,736 3,736 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip small:setup_small_marshaled() 3,840 3,840 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip large:setup_large_marshaled() 48,274 48,274 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_auto small:setup_small_marshaled() 3,866 3,866 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_auto large:setup_large_marshaled() 48,335 48,335 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_exact small:setup_small_marshaled() 5,206 5,206 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_exact large:setup_large_marshaled() 66,659 66,659 +0.0%
binary_benchmark::child_iteration_group::bench_get_children_by_tag 310,312 310,312 +0.0%
binary_benchmark::jid_optimization_group::bench_jid_to_owned_access jid_access:setup_jid_heavy_marshaled() 8,291 8,291 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_u32 254 254 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_u32 91 91 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_u64 292 292 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_u64 137 137 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_i64 317 317 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_i64 145 145 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_loop_100_u64 27,425 27,425 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_loop_100_u64 10,725 10,725 +0.0%
libsignal_benchmark::dm_group::bench_dm_session_establishment setup:setup_dm_users() 4,139,524 4,140,179 -0.0%
libsignal_benchmark::dm_group::bench_dm_encrypt_first_message first_msg:setup_dm_session() 100,131 100,131 +0.0%
libsignal_benchmark::dm_group::bench_dm_decrypt_first_message decrypt_prekey:setup_dm_with_first_message() 4,264,189 4,264,189 +0.0%
libsignal_benchmark::dm_group::bench_dm_encrypt_subsequent_message subsequent:setup_established_dm_session() 100,399 100,399 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_create_distribution_message create:setup_group_sender() 210,262 210,262 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_encrypt_message encrypt:setup_group_with_distribution() 496,921 496,908 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_decrypt_message decrypt:setup_group_with_encrypted_message() 509,854 509,489 +0.1%
libsignal_benchmark::conversation_group::bench_full_dm_conversation full:setup_conversation_data() 11,977,221 11,980,619 -0.0%
libsignal_benchmark::signature_group::bench_signature_creation sign:setup_keypair_with_message() 2,466,138 2,466,138 +0.0%
libsignal_benchmark::signature_group::bench_signature_verification verify:setup_keypair_with_message() 4,918,392 4,913,032 +0.1%
libsignal_benchmark::signature_group::bench_key_generation keygen 2,043,397 2,043,397 +0.0%
libsignal_benchmark::session_optimization_group::bench_decrypt_with_previous_session previous_session:setup_with_archived_sessions() 37,414 37,404 +0.0%
libsignal_benchmark::session_optimization_group::bench_out_of_order_decryption out_of_order:setup_out_of_order_messages() 3,617,967 3,617,967 +0.0%
libsignal_benchmark::session_optimization_group::bench_promote_matching_session promote:setup_promote_matching_session() 230,658 230,638 +0.0%
libsignal_benchmark::session_optimization_group::bench_message_key_eviction eviction:setup_message_key_eviction() 9,980,959 9,980,959 +0.0%
No significant changes detected.

@jlucaso1
jlucaso1 merged commit 0df74ff into main Jun 8, 2026
11 checks passed
@jlucaso1
jlucaso1 deleted the feat/newsletter-mute branch June 8, 2026 10:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant