From 1452ecfc5860ea120ef6a8d831a7fd7d21d0413d Mon Sep 17 00:00:00 2001 From: Ken-ichi Ueda Date: Thu, 5 Jun 2025 15:16:07 -0700 Subject: [PATCH 1/3] feat: support activity_email_notification preference --- lib/models/user.js | 2 ++ openapi/schema/request/users_update.js | 1 + openapi/schema/response/private_user.js | 1 + 3 files changed, 4 insertions(+) diff --git a/lib/models/user.js b/lib/models/user.js index 63998d34..53a910da 100644 --- a/lib/models/user.js +++ b/lib/models/user.js @@ -11,6 +11,7 @@ const config = require( "../../config" ); // This is a not-great duplication of logic in the Rails app where this model // really lives, but this saves us an additional HTTP request const PREFS = [ + { name: "activity_email_notification", default: true }, { name: "automatic_taxonomic_changes", default: true }, { name: "comment_email_notification", default: true }, { name: "common_names", default: true }, @@ -41,6 +42,7 @@ const PREFS = [ // prefs that should be present as prefers_name const PREFERS_PREFS = [ + "activity_email_notification", "automatic_taxonomic_changes", "comment_email_notification", "common_names", diff --git a/openapi/schema/request/users_update.js b/openapi/schema/request/users_update.js index cade47eb..0f987526 100644 --- a/openapi/schema/request/users_update.js +++ b/openapi/schema/request/users_update.js @@ -51,6 +51,7 @@ module.exports = Joi.object( ).keys( { preferred_project_addition_by: Joi.string( ), preferred_sound_license: Joi.string( ).valid( null ), prefers_automatic_taxonomic_changes: Joi.boolean( ), + prefers_activity_email_notification: Joi.boolean( ), prefers_comment_email_notification: Joi.boolean( ), prefers_common_names: Joi.boolean( ), prefers_community_taxa: Joi.boolean( ), diff --git a/openapi/schema/response/private_user.js b/openapi/schema/response/private_user.js index 6b5494b4..888c5d04 100644 --- a/openapi/schema/response/private_user.js +++ b/openapi/schema/response/private_user.js @@ -34,6 +34,7 @@ module.exports = user.append( { preferred_photo_license: Joi.string( ).valid( null ), preferred_project_addition_by: Joi.string( ).valid( null ), preferred_sound_license: Joi.string( ).valid( null ), + prefers_activity_email_notification: Joi.boolean( ).valid( null ), prefers_automatic_taxonomic_changes: Joi.boolean( ).valid( null ), prefers_comment_email_notification: Joi.boolean( ).valid( null ), prefers_common_names: Joi.boolean( ).valid( null ), From c3c0d256720b1116f809d4d335d4f4233dea7932 Mon Sep 17 00:00:00 2001 From: Ken-ichi Ueda Date: Wed, 11 Jun 2025 16:25:00 -0700 Subject: [PATCH 2/3] feat: support email_suppressions in user put and get requests --- lib/models/user.js | 14 +++++++++++--- openapi/schema/request/users_update.js | 18 +++++++++++++++++- openapi/schema/response/private_user.js | 2 +- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/lib/models/user.js b/lib/models/user.js index 53a910da..e3070c02 100644 --- a/lib/models/user.js +++ b/lib/models/user.js @@ -11,7 +11,6 @@ const config = require( "../../config" ); // This is a not-great duplication of logic in the Rails app where this model // really lives, but this saves us an additional HTTP request const PREFS = [ - { name: "activity_email_notification", default: true }, { name: "automatic_taxonomic_changes", default: true }, { name: "comment_email_notification", default: true }, { name: "common_names", default: true }, @@ -42,7 +41,6 @@ const PREFS = [ // prefs that should be present as prefers_name const PREFERS_PREFS = [ - "activity_email_notification", "automatic_taxonomic_changes", "comment_email_notification", "common_names", @@ -141,7 +139,7 @@ const User = class User extends Model { .field( "users.confirmed_at" ) .field( "users.confirmation_sent_at" ) .field( "users.time_zone" ) - .field( "email" ) + .field( "users.email" ) .field( "unconfirmed_email" ) .field( "locale" ) .field( "place_id" ) @@ -153,11 +151,13 @@ const User = class User extends Model { .field( "user_blocks.blocked_user_id" ) .field( "pf.project_id", "pf_project_id" ) .field( "pf.position", "pf_position" ) + .field( "es.suppression_type", "es_suppression_type" ) .from( "users" ) .left_join( "user_mutes", null, "users.id = user_mutes.user_id" ) .left_join( "user_blocks", null, "users.id = user_blocks.user_id" ) .left_join( "user_privileges", "up", "users.id = up.user_id" ) .left_join( "project_faves", "pf", "users.id = pf.user_id" ) + .left_join( "email_suppressions", "es", "users.id = es.user_id" ) .where( "login = ?", login ); const { rows } = await pgClient.replica.query( query.toString( ) ); const userObject = _.mapValues( rows[0], v => v || null ); @@ -202,6 +202,14 @@ const User = class User extends Model { ) ) ); + userObject.email_suppression_types = _.compact( + _.uniq( + _.map( + _.sortBy( rows, "es_suppression_type" ), + r => r.es_suppression_type + ) + ) + ); delete userObject.pf_project_id; delete userObject.pf_position; userObject.monthly_supporter = ( diff --git a/openapi/schema/request/users_update.js b/openapi/schema/request/users_update.js index 0f987526..c1c59e22 100644 --- a/openapi/schema/request/users_update.js +++ b/openapi/schema/request/users_update.js @@ -9,6 +9,23 @@ module.exports = Joi.object( ).keys( { is to delete the account. ` ), description: Joi.string( ).valid( null ), + email_suppression_types: Joi + .array( ).items( + Joi.string( ).valid( + "account_emails", + "activity", + "blocks", + "bounces", + "donation_emails", + "invalid_emails", + "messages", + "news_from_inaturalist", + "spam_reports", + "transactional_emails", + "unsubscribes" + ) + ) + .description( "List of email suppression types" ), faved_project_ids: Joi.array( ).items( Joi.number( ) ) .description( ` Ordered list of IDs of projects the user has faved. Order of IDs in @@ -51,7 +68,6 @@ module.exports = Joi.object( ).keys( { preferred_project_addition_by: Joi.string( ), preferred_sound_license: Joi.string( ).valid( null ), prefers_automatic_taxonomic_changes: Joi.boolean( ), - prefers_activity_email_notification: Joi.boolean( ), prefers_comment_email_notification: Joi.boolean( ), prefers_common_names: Joi.boolean( ), prefers_community_taxa: Joi.boolean( ), diff --git a/openapi/schema/response/private_user.js b/openapi/schema/response/private_user.js index 888c5d04..7e5c360b 100644 --- a/openapi/schema/response/private_user.js +++ b/openapi/schema/response/private_user.js @@ -11,6 +11,7 @@ module.exports = user.append( { confirmation_sent_at: Joi.date( ).valid( null ), data_transfer_consent: Joi.boolean( ).valid( true, null ), email: Joi.string( ).valid( null ), + email_suppression_types: Joi.array( ).items( Joi.string( ) ).valid( null ), locale: Joi.string( ).valid( null ), login: Joi.string( ), muted_user_ids: Joi.array( ).items( @@ -34,7 +35,6 @@ module.exports = user.append( { preferred_photo_license: Joi.string( ).valid( null ), preferred_project_addition_by: Joi.string( ).valid( null ), preferred_sound_license: Joi.string( ).valid( null ), - prefers_activity_email_notification: Joi.boolean( ).valid( null ), prefers_automatic_taxonomic_changes: Joi.boolean( ).valid( null ), prefers_comment_email_notification: Joi.boolean( ).valid( null ), prefers_common_names: Joi.boolean( ).valid( null ), From acfe2c221c657a97509dbe8d2841a9e5959639ac Mon Sep 17 00:00:00 2001 From: Ken-ichi Ueda Date: Wed, 11 Jun 2025 16:52:17 -0700 Subject: [PATCH 3/3] fix: support feedback email suppression group --- openapi/schema/request/users_update.js | 1 + 1 file changed, 1 insertion(+) diff --git a/openapi/schema/request/users_update.js b/openapi/schema/request/users_update.js index c1c59e22..3a72369f 100644 --- a/openapi/schema/request/users_update.js +++ b/openapi/schema/request/users_update.js @@ -17,6 +17,7 @@ module.exports = Joi.object( ).keys( { "blocks", "bounces", "donation_emails", + "feedback", "invalid_emails", "messages", "news_from_inaturalist",