Skip to content

Commit

Permalink
Add canonical email to users (#4367)
Browse files Browse the repository at this point in the history
* add canonical_email to users

* fix bug preventing users from earning organizer privilege
  • Loading branch information
pleary authored Jan 30, 2025
1 parent f891f33 commit 5c1e5d6
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 2 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ gem "elasticsearch", "~> 8"
gem "elasticsearch-api", "~> 8"
gem "elasticsearch-model", "~> 8"
gem "elasticsearch-rails", "8.0.0.pre"
gem "email_address"
gem "exifr", require: ["exifr", "exifr/jpeg", "exifr/tiff"]
gem "exiftool_vendored" # Vendored version includes exiftool and exiftool gem
gem "fastimage"
Expand Down
6 changes: 6 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ GEM
aws-sigv4 (~> 1.1)
aws-sigv4 (1.4.0)
aws-eventstream (~> 1, >= 1.0.2)
base64 (0.2.0)
bcrypt (3.1.16)
bcrypt_pbkdf (1.1.0)
better_errors (2.9.1)
Expand Down Expand Up @@ -327,6 +328,9 @@ GEM
elasticsearch (~> 8)
hashie
elasticsearch-rails (8.0.0.pre)
email_address (0.2.5)
base64
simpleidn
erubi (1.13.0)
execjs (2.8.1)
exifr (1.3.9)
Expand Down Expand Up @@ -653,6 +657,7 @@ GEM
simplecov_json_formatter (~> 0.1)
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.3)
simpleidn (0.2.3)
snaky_hash (2.0.1)
hashie
version_gem (~> 1.1, >= 1.1.1)
Expand Down Expand Up @@ -766,6 +771,7 @@ DEPENDENCIES
elasticsearch-api (~> 8)
elasticsearch-model (~> 8)
elasticsearch-rails (= 8.0.0.pre)
email_address
exifr
exiftool_vendored
factory_bot_rails
Expand Down
14 changes: 14 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ def followers
before_validation :download_remote_icon, :if => :icon_url_provided?
before_validation :strip_name, :strip_login
before_validation :set_time_zone
before_validation :set_canonical_email
before_create :skip_confirmation_if_child
before_save :allow_some_licenses
before_save :get_lat_lon_from_ip_if_last_ip_changed
Expand All @@ -293,6 +294,7 @@ def followers
after_save :update_taxon_name_priorities
after_update :set_observations_taxa_if_pref_changed
after_update :send_welcome_email
after_update :check_privileges_if_confirmed
after_create :set_uri
after_destroy :remove_oauth_access_tokens
after_destroy :destroy_project_rules
Expand Down Expand Up @@ -776,6 +778,12 @@ def set_time_zone
true
end

def set_canonical_email
return unless new_record? || email_changed?

self.canonical_email = EmailAddress.canonical( email )
end

def set_uri
if uri.blank?
User.where( id: id ).update_all( uri: UrlHelper.user_url( id ) )
Expand Down Expand Up @@ -1356,6 +1364,12 @@ def send_welcome_email
end
end

def check_privileges_if_confirmed
return unless saved_change_to_confirmed_at?

UserPrivilege.check( id, UserPrivilege::ORGANIZER )
end

def revoke_authorizations_after_password_change
return unless encrypted_password_previously_changed?
Doorkeeper::AccessToken.where( resource_owner_id: id, revoked_at: nil ).each( &:revoke )
Expand Down
9 changes: 9 additions & 0 deletions db/migrate/20241217203007_add_canonical_email_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class AddCanonicalEmailToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :canonical_email, :string, limit: 100
add_index :users, :canonical_email
end
end

13 changes: 11 additions & 2 deletions db/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5706,7 +5706,8 @@ CREATE TABLE public.users (
data_transfer_consent_at timestamp without time zone,
unconfirmed_email character varying,
annotated_observations_count integer DEFAULT 0,
icon_path_version smallint DEFAULT 0 NOT NULL
icon_path_version smallint DEFAULT 0 NOT NULL,
canonical_email character varying(100)
);


Expand Down Expand Up @@ -10608,6 +10609,13 @@ CREATE INDEX index_user_signups_on_ip_and_browser_id ON public.user_signups USIN
CREATE UNIQUE INDEX index_user_signups_on_user_id ON public.user_signups USING btree (user_id);


--
-- Name: index_users_on_canonical_email; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX index_users_on_canonical_email ON public.users USING btree (canonical_email);


--
-- Name: index_users_on_confirmation_token; Type: INDEX; Schema: public; Owner: -
--
Expand Down Expand Up @@ -11399,6 +11407,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20241202092831'),
('20241218164832'),
('20250124155306'),
('20250127200519');
('20250127200519'),
('20241217203007');


11 changes: 11 additions & 0 deletions spec/models/user_privilege_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@
user.update( confirmed_at: nil )
expect( UserPrivilege.earned_organizer?( user ) ).to be false
end

it "organizer is earned after email is confirmed" do
user = User.make!( confirmed_at: nil )
expect( UserPrivilege.earned_organizer?( user ) ).to be false
stub_verifiable_obs = double( "verifiable" )
expect( stub_verifiable_obs ).to receive( :limit ).and_return( ( 1..50 ).to_a )
expect( user.observations ).to receive( :verifiable ).and_return( stub_verifiable_obs )
expect( UserPrivilege.earned_organizer?( user ) ).to be false
user.update( confirmed_at: Time.now )
expect( UserPrivilege.earned_organizer?( user ) ).to be true
end
end
describe "for identification" do
it "should earn speech after 3 identifications for others" do
Expand Down
13 changes: 13 additions & 0 deletions spec/models/user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,19 @@
expect(u).to be_valid
end

it "generates a canonical email" do
emails_with_shared_canonical = [
"test@gmail.com",
"T.e.sT@gmail.com",
"test+1@gmail.com",
"T.est+2@gmail.com",
"t..est+test2@gmail.com"
]
emails_with_shared_canonical.each do | email |
expect( User.make!( email: email ).canonical_email ).to eq "test@gmail.com"
end
end

it "should not allow time_zone to be a blank string" do
expect( User.make!( time_zone: "" ).time_zone ).to be_nil
end
Expand Down

0 comments on commit 5c1e5d6

Please sign in to comment.