diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000..5e3c8109da
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,13 @@
+# Keep GitHub Actions up to date with GitHub's Dependabot...
+# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
+# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem
+version: 2
+updates:
+ - package-ecosystem: github-actions
+ directory: /
+ groups:
+ github-actions:
+ patterns:
+ - "*" # Group all Actions updates into a single larger pull request
+ schedule:
+ interval: weekly
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
index 4b264a6be2..ab509ebad7 100644
--- a/Gemfile
+++ b/Gemfile
@@ -26,13 +26,12 @@ gem 'puma_worker_killer'
gem 'knockoutjs-rails'
# Using this branch in pattern library due to multiselect (until it's merged to master)
-gem 'pattern-library', git: 'https://github.com/openstax/pattern-library.git', ref: 'c3dd0b2c8ed987f9089b7da302fb02d2fc4cd840'
+gem 'pattern-library', github: 'openstax/pattern-library', ref: 'c3dd0b2c8ed987f9089b7da302fb02d2fc4cd840'
-# Lev framework
-# - introduces two new concepts: Routines and Handlers
-gem 'lev', github: 'lml/lev', ref: 'a33c93c83afea63c80b5da6317efec4bfd357df5'
-gem 'openstax_transaction_retry', github: 'openstax/transaction_retry', ref: '36e26d0a068756c334b9d1c671d40773bbfc9300'
-gem 'openstax_transaction_isolation', github: 'openstax/transaction_isolation', ref: '7387fa091462118704967a7c4b2821cd0f5d9e01'
+# Lev framework - introduces two new concepts: Routines and Handlers
+gem 'lev'
+gem 'openstax_transaction_retry'
+gem 'openstax_transaction_isolation'
# SCSS stylesheets
gem 'sass-rails'
@@ -123,7 +122,7 @@ gem 'representable'
gem 'keyword_search'
# ToS/PP management
-gem 'fine_print', github: 'lml/fine_print', ref: '636023f68e95196dffaf295bfad3ad8051c23542'
+gem 'fine_print'
# Send users back to the correct page after login
gem 'action_interceptor'
@@ -170,7 +169,7 @@ gem 'openstax_path_prefixer', github: 'openstax/path_prefixer', ref: 'e3edfc7058
gem 'json-jwt'
# international country codes javascript plugin
-gem 'intl-tel-input-rails', git: 'https://github.com/openstax/intl-tel-input-rails.git', branch: 'master'
+gem 'intl-tel-input-rails', github: 'openstax/intl-tel-input-rails', branch: 'master'
# internationalization based on the `HTTP_ACCEPT_LANGUAGE` header sent by browsers
gem 'http_accept_language'
@@ -225,10 +224,6 @@ group :development, :test do
# Codecov integration
gem 'codecov', require: false
- # Speedup Rails boot time
- gem 'spring'
- gem 'spring-commands-rspec'
-
# Run specs when files change
gem 'guard-rspec'
gem 'guard-livereload', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index a1fc2c2227..a2bac63920 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,29 +1,3 @@
-GIT
- remote: https://github.com/lml/fine_print.git
- revision: 636023f68e95196dffaf295bfad3ad8051c23542
- ref: 636023f68e95196dffaf295bfad3ad8051c23542
- specs:
- fine_print (6.0.1)
- action_interceptor
- jquery-rails
- rails (< 7)
- responders
-
-GIT
- remote: https://github.com/lml/lev.git
- revision: a33c93c83afea63c80b5da6317efec4bfd357df5
- ref: a33c93c83afea63c80b5da6317efec4bfd357df5
- specs:
- lev (13.0.0)
- actionpack (>= 4.2)
- active_attr
- activejob
- activemodel (>= 6.1)
- activerecord (>= 4.2)
- hashie
- openstax_transaction_isolation
- openstax_transaction_retry
-
GIT
remote: https://github.com/openstax/intl-tel-input-rails.git
revision: 3a63a495822d90bc9ca93e9541ef252fd7a0b50b
@@ -49,23 +23,6 @@ GIT
specs:
pattern-library (1.1.18)
-GIT
- remote: https://github.com/openstax/transaction_isolation.git
- revision: 7387fa091462118704967a7c4b2821cd0f5d9e01
- ref: 7387fa091462118704967a7c4b2821cd0f5d9e01
- specs:
- openstax_transaction_isolation (2.0.0)
- activerecord (>= 6)
-
-GIT
- remote: https://github.com/openstax/transaction_retry.git
- revision: 36e26d0a068756c334b9d1c671d40773bbfc9300
- ref: 36e26d0a068756c334b9d1c671d40773bbfc9300
- specs:
- openstax_transaction_retry (2.0.0)
- activerecord (>= 6)
- openstax_transaction_isolation (>= 2)
-
GEM
remote: https://rubygems.org/
specs:
@@ -269,7 +226,7 @@ GEM
activerecord (>= 5.a)
database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1)
- date (3.3.4)
+ date (3.4.1)
db-query-matchers (0.13.0)
activesupport (>= 4.0, < 7.3)
rspec (>= 3.0)
@@ -297,7 +254,7 @@ GEM
eventmachine (>= 0.12.9)
http_parser.rb (~> 0)
error_page_assets (0.4)
- erubi (1.13.0)
+ erubi (1.13.1)
eventmachine (1.2.7)
exception_notification (4.5.0)
actionmailer (>= 5.2, < 8)
@@ -342,6 +299,11 @@ GEM
faraday_middleware (1.2.1)
faraday (~> 1.0)
ffi (1.16.3)
+ fine_print (6.0.3)
+ action_interceptor
+ jquery-rails
+ rails (< 7)
+ responders
font-awesome-rails (4.7.0.8)
railties (>= 3.2, < 8.0)
formatador (1.1.0)
@@ -417,6 +379,15 @@ GEM
launchy (3.0.1)
addressable (~> 2.8)
childprocess (~> 5.0)
+ lev (13.0.0)
+ actionpack (>= 4.2)
+ active_attr
+ activejob
+ activemodel (>= 6.1)
+ activerecord (>= 4.2)
+ hashie
+ openstax_transaction_isolation
+ openstax_transaction_retry
libv8-node (18.19.0.0)
libv8-node (18.19.0.0-x86_64-darwin)
libv8-node (18.19.0.0-x86_64-linux)
@@ -429,7 +400,7 @@ GEM
activesupport (>= 4)
railties (>= 4)
request_store (~> 1.0)
- loofah (2.23.0)
+ loofah (2.24.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
lumberjack (1.2.10)
@@ -446,16 +417,16 @@ GEM
railties (>= 3.0.0, < 8)
method_source (1.1.0)
mini_mime (1.1.5)
- mini_portile2 (2.8.7)
+ mini_portile2 (2.8.8)
mini_racer (0.16.0)
libv8-node (~> 18.19.0.0)
- minitest (5.25.1)
+ minitest (5.25.4)
msgpack (1.7.3)
multi_json (1.15.0)
multi_xml (0.6.0)
multipart-post (2.4.1)
nenv (0.3.0)
- net-imap (0.5.0)
+ net-imap (0.5.5)
date
net-protocol
net-pop (0.1.2)
@@ -464,13 +435,13 @@ GEM
timeout
net-smtp (0.5.0)
net-protocol
- nio4r (2.7.3)
- nokogiri (1.16.7)
+ nio4r (2.7.4)
+ nokogiri (1.18.1)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
- nokogiri (1.16.7-x86_64-darwin)
+ nokogiri (1.18.1-x86_64-darwin)
racc (~> 1.4)
- nokogiri (1.16.7-x86_64-linux)
+ nokogiri (1.18.1-x86_64-linux-gnu)
racc (~> 1.4)
notiffany (0.1.3)
nenv (~> 0.1)
@@ -539,6 +510,11 @@ GEM
openstax_active_force
rails (>= 5.0, < 7.0)
restforce
+ openstax_transaction_isolation (2.0.0)
+ activerecord (>= 6)
+ openstax_transaction_retry (2.0.0)
+ activerecord (>= 6)
+ openstax_transaction_isolation (>= 2)
openstax_utilities (5.1.2)
aws-sdk-autoscaling
faraday
@@ -584,7 +560,7 @@ GEM
rack (>= 2.0.0)
rack-session (1.0.2)
rack (< 3)
- rack-test (2.1.0)
+ rack-test (2.2.0)
rack (>= 1.3)
rails (6.1.7.8)
actioncable (= 6.1.7.8)
@@ -614,9 +590,9 @@ GEM
activesupport (>= 4.2)
choice (~> 0.2.0)
ruby-graphviz (~> 1.2)
- rails-html-sanitizer (1.6.0)
+ rails-html-sanitizer (1.6.2)
loofah (~> 2.21)
- nokogiri (~> 1.14)
+ nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
rails-i18n (7.0.9)
i18n (>= 0.7, < 2)
railties (>= 6.0.0, < 8)
@@ -761,9 +737,6 @@ GEM
snaky_hash (2.0.1)
hashie
version_gem (~> 1.1, >= 1.1.1)
- spring (4.2.1)
- spring-commands-rspec (1.0.4)
- spring (>= 0.9.1)
sprockets (3.7.5)
base64
concurrent-ruby (~> 1.0)
@@ -780,7 +753,7 @@ GEM
thor (1.3.2)
tilt (2.4.0)
timecop (0.9.10)
- timeout (0.4.1)
+ timeout (0.4.3)
trailblazer-option (0.1.2)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
@@ -805,7 +778,8 @@ GEM
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
websocket (1.2.11)
- websocket-driver (0.7.6)
+ websocket-driver (0.7.7)
+ base64
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
whenever (1.0.0)
@@ -858,7 +832,7 @@ DEPENDENCIES
faraday
faraday_middleware
ffi (< 1.17)
- fine_print!
+ fine_print
font-awesome-rails
guard-livereload
guard-rspec
@@ -872,7 +846,7 @@ DEPENDENCIES
keyword_search
knockoutjs-rails
launchy
- lev!
+ lev
listen
lograge
maruku
@@ -890,8 +864,8 @@ DEPENDENCIES
openstax_path_prefixer!
openstax_rescue_from
openstax_salesforce
- openstax_transaction_isolation!
- openstax_transaction_retry!
+ openstax_transaction_isolation
+ openstax_transaction_retry
openstax_utilities
p3p
parallel_tests
@@ -923,8 +897,6 @@ DEPENDENCIES
sentry-ruby
shoulda-matchers
smarter_csv
- spring
- spring-commands-rspec
timecop
uglifier
vcr
diff --git a/app/handlers/create_external_user_credentials.rb b/app/handlers/create_external_user_credentials.rb
index 1394662e61..4e12e4b719 100644
--- a/app/handlers/create_external_user_credentials.rb
+++ b/app/handlers/create_external_user_credentials.rb
@@ -53,7 +53,7 @@ def handle
password_confirmation: signup_params.password
)
- run Newflow::CreateEmailForUser, email: signup_params.email, user: outputs.user
+ run Newflow::CreateEmailForUser, email: signup_params.email, user: outputs.user, show_pin: false
agree_to_terms if signup_params.terms_accepted
end
diff --git a/app/mailers/newflow_mailer.rb b/app/mailers/newflow_mailer.rb
index 75e327e8ed..47afe9c9be 100644
--- a/app/mailers/newflow_mailer.rb
+++ b/app/mailers/newflow_mailer.rb
@@ -15,8 +15,9 @@ def reset_password_email(user:, email_address:)
subject: "Reset your OpenStax password"
end
- def signup_email_confirmation(email_address:)
- @should_show_pin = ConfirmByPin.sequential_failure_for(email_address).attempts_remaining?
+ def signup_email_confirmation(email_address:, show_pin: true)
+ @should_show_pin = show_pin != false &&
+ ConfirmByPin.sequential_failure_for(email_address).attempts_remaining?
@email_value = email_address.value
@confirmation_pin = email_address.confirmation_pin
@confirmation_code = email_address.confirmation_code
diff --git a/app/models/user.rb b/app/models/user.rb
index d32591a2bd..32bef11f4c 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -80,10 +80,7 @@ class User < ApplicationRecord
before_validation(:strip_fields)
before_validation(:remove_special_chars)
- before_validation(
- :generate_uuid, :generate_support_identifier,
- on: :create
- )
+ before_validation(:generate_uuid, on: :create)
validate(:ensure_names_continue_to_be_present)
validate(
@@ -125,7 +122,7 @@ class User < ApplicationRecord
validates(:login_token, uniqueness: { allow_nil: true })
- validates(:uuid, :support_identifier, presence: true, uniqueness: true)
+ validates(:uuid, presence: true, uniqueness: true)
validate :books_used_details_valid
@@ -160,7 +157,7 @@ class User < ApplicationRecord
delegate_to_routine :destroy
- attr_readonly :uuid, :support_identifier
+ attr_readonly :uuid
attribute :is_not_gdpr_location, :boolean, default: nil
@@ -450,10 +447,6 @@ def generate_uuid
self.uuid ||= SecureRandom.uuid
end
- def generate_support_identifier(length: 4)
- self.support_identifier ||= "cs_#{SecureRandom.hex(length)}"
- end
-
protected
def make_first_user_an_admin
diff --git a/app/representers/api/v1/find_or_create_user_representer.rb b/app/representers/api/v1/find_or_create_user_representer.rb
index 008e1d4cda..3f946ecece 100644
--- a/app/representers/api/v1/find_or_create_user_representer.rb
+++ b/app/representers/api/v1/find_or_create_user_representer.rb
@@ -12,11 +12,6 @@ class FindOrCreateUserRepresenter < Roar::Decorator
readable: true,
writeable: false
- property :support_identifier,
- type: String,
- readable: true,
- writeable: false
-
property :external_id,
type: String,
readable: false,
diff --git a/app/representers/api/v1/find_user_representer.rb b/app/representers/api/v1/find_user_representer.rb
index a73208017f..c68cd4287c 100644
--- a/app/representers/api/v1/find_user_representer.rb
+++ b/app/representers/api/v1/find_user_representer.rb
@@ -12,11 +12,6 @@ class FindUserRepresenter < Roar::Decorator
readable: true,
writeable: true
- property :support_identifier,
- type: String,
- readable: true,
- writeable: false
-
property :external_id,
type: String,
readable: false,
diff --git a/app/representers/api/v1/user_representer.rb b/app/representers/api/v1/user_representer.rb
index ece0f265c4..3031e2bdc7 100644
--- a/app/representers/api/v1/user_representer.rb
+++ b/app/representers/api/v1/user_representer.rb
@@ -50,11 +50,6 @@ class UserRepresenter < Roar::Decorator
readable: true,
writeable: false
- property :support_identifier,
- type: String,
- readable: true,
- writeable: false
-
property :consent_preferences,
type: JSON,
readable: true,
diff --git a/app/routines/confirm_by_pin.rb b/app/routines/confirm_by_pin.rb
index 9aecfa5a16..456697c914 100644
--- a/app/routines/confirm_by_pin.rb
+++ b/app/routines/confirm_by_pin.rb
@@ -9,6 +9,8 @@ def self.sequential_failure_for(contact_info)
:value
when PreAuthState
:contact_info_value
+ else
+ :value
end
SequentialFailure.confirm_by_pin
diff --git a/app/routines/newflow/create_email_for_user.rb b/app/routines/newflow/create_email_for_user.rb
index 05014c85f3..e6ef5d37d4 100644
--- a/app/routines/newflow/create_email_for_user.rb
+++ b/app/routines/newflow/create_email_for_user.rb
@@ -5,7 +5,7 @@ class CreateEmailForUser
protected ###############
- def exec(email:, user:, is_school_issued: nil)
+ def exec(email:, user:, is_school_issued: nil, show_pin: true)
@email = EmailAddress.find_or_create_by(value: email&.downcase, user_id: user.id)
@email.is_school_issued = is_school_issued
@@ -17,7 +17,9 @@ def exec(email:, user:, is_school_issued: nil)
event_type: :email_added_to_user,
event_data: { email: @email }
)
- NewflowMailer.signup_email_confirmation(email_address: @email).deliver_later
+ NewflowMailer.signup_email_confirmation(
+ email_address: @email, show_pin: show_pin
+ ).deliver_later
end
@email.save
diff --git a/app/routines/newflow/create_or_update_salesforce_lead.rb b/app/routines/newflow/create_or_update_salesforce_lead.rb
index d186fc30a4..4302aa9510 100644
--- a/app/routines/newflow/create_or_update_salesforce_lead.rb
+++ b/app/routines/newflow/create_or_update_salesforce_lead.rb
@@ -146,11 +146,23 @@ def build_book_adoption_json_for_salesforce(user)
return nil unless user.books_used_details
user.books_used_details.each do |book|
- books_json << {
- name: book[0],
+ book_value = book[0]
+ if book_value.match(/\[.*\]/)
+ book_name = book_value.gsub(/\[.*\]/, '').strip # Calculus Volume 1
+ book_language = book_value[/\[(.*?)\]/, 1] # Spanish (no brackets)
+ books_json << {
+ name: book_name,
+ students: book[1]["num_students_using_book"],
+ howUsing: book[1]["how_using_book"],
+ language: book_language,
+ }
+ else
+ books_json << {
+ name: book_value,
students: book[1]["num_students_using_book"],
howUsing: book[1]["how_using_book"]
}
+ end
end
adoption_json['Books'] = books_json
diff --git a/app/routines/search_users.rb b/app/routines/search_users.rb
index 49061c24cc..73e219c199 100644
--- a/app/routines/search_users.rb
+++ b/app/routines/search_users.rb
@@ -96,16 +96,6 @@ def exec(query, options={})
users = users.where(uuid: uuids_queries)
end
- if options[:admin]
- with.keyword :support_identifier do |identifiers|
- sanitized_identifiers = sanitize_strings(
- identifiers, append_wildcard: true, prepend_wildcard: true
- )
-
- users = users.where( table[:support_identifier].matches_any(sanitized_identifiers) )
- end
- end
-
with.keyword :id do |ids|
users = users.where(id: ids)
end
@@ -160,7 +150,6 @@ def exec(query, options={})
matches_last_name = table[:last_name].matches_any(sanitized_names)
matches_full_name = full_name.matches_any(sanitized_names)
matches_id = table[:id].in(terms)
- matches_support_identifier = table[:support_identifier].matches_any(sanitized_names)
users = User.where(matches_first_name)
.or(
@@ -169,8 +158,6 @@ def exec(query, options={})
User.where(matches_full_name)
).or(
User.where(matches_id)
- ).or(
- User.where(matches_support_identifier)
)
end
end
diff --git a/app/views/newflow_mailer/signup_email_confirmation.html.erb b/app/views/newflow_mailer/signup_email_confirmation.html.erb
index 3afbd76129..2ccd542acd 100644
--- a/app/views/newflow_mailer/signup_email_confirmation.html.erb
+++ b/app/views/newflow_mailer/signup_email_confirmation.html.erb
@@ -89,7 +89,7 @@
- Verify your email by clicking the button below or use your pin: <%= @confirmation_pin %>
+ Verify your email by clicking the button below<% if @should_show_pin %> or use your pin: <%= @confirmation_pin %><% end %>
|
diff --git a/config/initializers/active_job.rb b/config/initializers/active_job.rb
index 6627277b2d..c508b387de 100644
--- a/config/initializers/active_job.rb
+++ b/config/initializers/active_job.rb
@@ -1,2 +1,2 @@
# Use delayed_job for background jobs
-Rails.application.config.active_job.queue_adapter = :delayed_job
+ActiveSupport.on_load(:active_job) { ActiveJob::Base.queue_adapter = :delayed_job }
diff --git a/config/initializers/delayed_job.rb b/config/initializers/delayed_job.rb
index 114db75540..d3126d4b4f 100644
--- a/config/initializers/delayed_job.rb
+++ b/config/initializers/delayed_job.rb
@@ -65,7 +65,7 @@ def handle_failed_job(job, exception)
job.fail! if fail_proc.present? && fail_proc.call(exception) ||
exception.try(:instantly_fail_if_in_background_job?)
- super(job, exception)
+ super(job, exception)
end
end
diff --git a/db/migrate/20241107193019_remove_support_identifier_from_users.rb b/db/migrate/20241107193019_remove_support_identifier_from_users.rb
new file mode 100644
index 0000000000..6802f6ecbd
--- /dev/null
+++ b/db/migrate/20241107193019_remove_support_identifier_from_users.rb
@@ -0,0 +1,17 @@
+class RemoveSupportIdentifierFromUsers < ActiveRecord::Migration[6.1]
+ def up
+ remove_column :users, :support_identifier
+ end
+
+ def down
+ add_column :users, :support_identifier, :citext
+
+ add_index :users, :support_identifier, unique: true
+
+ User.find_each do |user|
+ User.where(id: user.id).update_all(support_identifier: user.generate_support_identifier)
+ end
+
+ change_column_null :users, :support_identifier, false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index e9fe3357f4..ae95da60cc 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2024_10_24_162218) do
+ActiveRecord::Schema.define(version: 2024_11_07_193019) do
# These are extensions that must be enabled in order to support this database
enable_extension "citext"
@@ -437,7 +437,6 @@
t.datetime "login_token_expires_at"
t.integer "role", default: 0, null: false
t.jsonb "signed_external_data"
- t.citext "support_identifier", null: false
t.boolean "is_test"
t.integer "school_type", default: 0, null: false
t.boolean "using_openstax", default: false
@@ -484,7 +483,6 @@
t.index ["school_id"], name: "index_users_on_school_id"
t.index ["school_type"], name: "index_users_on_school_type"
t.index ["source_application_id"], name: "index_users_on_source_application_id"
- t.index ["support_identifier"], name: "index_users_on_support_identifier", unique: true
t.index ["username"], name: "index_users_on_username", unique: true
t.index ["uuid"], name: "index_users_on_uuid", unique: true
end
diff --git a/lib/fetch_book_data.rb b/lib/fetch_book_data.rb
index b297ed95a0..3381798bef 100644
--- a/lib/fetch_book_data.rb
+++ b/lib/fetch_book_data.rb
@@ -19,7 +19,7 @@ def fetch_titles
items = results.fetch('items', [])
# See https://github.com/openstax/openstax-cms/blob/main/books/constants.py#L7 for book states
- books = items.reject{ %w[retired unlisted].include?(i['book_state']) }
+ books = items.reject { |i| %w[retired unlisted].include?(i['book_state']) }
books_with_subject = []
diff --git a/lib/import_users.rb b/lib/import_users.rb
index c039fa81d6..11c5d11911 100644
--- a/lib/import_users.rb
+++ b/lib/import_users.rb
@@ -72,7 +72,6 @@ def create_user(username, password_digest, title, first_name, last_name, email_a
@user.first_name = first_name
@user.last_name = last_name
@user.generate_uuid
- @user.generate_support_identifier
@user.save(validate: false)
identity = @user.build_identity
diff --git a/spec/controllers/api/v1/users_controller_spec.rb b/spec/controllers/api/v1/users_controller_spec.rb
index 75880e7cb1..bd0a9abcfc 100644
--- a/spec/controllers/api/v1/users_controller_spec.rb
+++ b/spec/controllers/api/v1/users_controller_spec.rb
@@ -302,7 +302,6 @@
external_ids: [ external_id.external_id ],
id: user.id,
sso: kind_of(String),
- support_identifier: user.support_identifier,
uuid: user.uuid
)
end
@@ -315,7 +314,6 @@
expect(response.body_as_hash).to match(
external_ids: [ external_id.external_id ],
id: user.id,
- support_identifier: user.support_identifier,
uuid: user.uuid
)
end
@@ -360,7 +358,7 @@
expect(response.code).to eq('201')
new_user = User.order(:id).last
expect(response.body_as_hash).to eq(
- id: new_user.id, uuid: new_user.uuid, external_ids: [], support_identifier: new_user.support_identifier
+ id: new_user.id, uuid: new_user.uuid, external_ids: []
)
end
@@ -448,8 +446,7 @@
expect(response.body_as_hash).to eq(
id: unclaimed_user.id,
uuid: unclaimed_user.uuid,
- external_ids: [],
- support_identifier: unclaimed_user.support_identifier
+ external_ids: []
)
end
@@ -459,7 +456,7 @@
body: { email: user_2.contact_infos.first.value }
expect(response.code).to eq('201')
expect(response.body_as_hash).to eq(
- id: user_2.id, uuid: user_2.uuid, external_ids: [], support_identifier: user_2.support_identifier
+ id: user_2.id, uuid: user_2.uuid, external_ids: []
)
end
end
diff --git a/spec/fixtures/users.json b/spec/fixtures/users.json
index c01cce385f..1c2abf70f4 100644
--- a/spec/fixtures/users.json
+++ b/spec/fixtures/users.json
@@ -1 +1 @@
-[{"username":"jstrav","created_at":"2018-05-17T19:49:42.469Z","updated_at":"2018-05-17T19:49:42.469Z","is_administrator":false,"first_name":"John","last_name":"Stravinsky","title":null,"uuid":"f1f96deb-919b-4183-9367-0cb713672172","suffix":null,"state":"activated","salesforce_contact_id":null,"faculty_status":0,"self_reported_school":null,"login_token":null,"login_token_expires_at":null,"role":0,"signed_external_data":null,"support_identifier":"cs_5d1edbb0","is_test":null,"school_type":0,"identity":{"password_digest":"$2a$04$s48G.v95rrx3vQ9Hvld2fus2fuNBRBhel99Io30.mTJOivtSgSxRu","created_at":"2018-05-17T19:49:42.524Z","updated_at":"2018-05-17T19:49:42.524Z","password_expires_at":null},"authentications":[{"provider":"identity","created_at":"2018-05-17T19:49:42.538Z","updated_at":"2018-05-17T19:49:42.538Z","login_hint":null}],"contact_infos":[{"type":"EmailAddress","value":"8f30b4@7cc1fa.223256","verified":false,"confirmation_code":null,"created_at":"2018-05-17T19:49:42.477Z","updated_at":"2018-05-17T19:49:42.477Z","confirmation_sent_at":null,"is_searchable":true,"confirmation_pin":null},{"type":"EmailAddress","value":"a467a2@4634bc.981344","verified":false,"confirmation_code":null,"created_at":"2018-05-17T19:49:42.485Z","updated_at":"2018-05-17T19:49:42.485Z","confirmation_sent_at":null,"is_searchable":true,"confirmation_pin":null}]},{"username":"mary","created_at":"2018-05-17T19:49:42.497Z","updated_at":"2018-05-17T19:49:42.497Z","is_administrator":false,"first_name":"Mary","last_name":"Mighty","title":null,"uuid":"f3145396-9b36-4080-a66d-ff3d4c0c1393","suffix":null,"state":"activated","salesforce_contact_id":null,"faculty_status":0,"self_reported_school":null,"login_token":null,"login_token_expires_at":null,"role":0,"signed_external_data":null,"support_identifier":"cs_6cf1cf5e","is_test":null,"school_type":0,"identity":{"password_digest":"$2a$04$nghthHpquanPYYJRfUk6n.TwkNtoP6h.aFFWJl9DHblRze9F1teMa","created_at":"2018-05-17T19:49:42.545Z","updated_at":"2018-05-17T19:49:42.545Z","password_expires_at":null},"authentications":[{"provider":"identity","created_at":"2018-05-17T19:49:42.551Z","updated_at":"2018-05-17T19:49:42.551Z","login_hint":null}],"contact_infos":[]},{"username":"jstead","created_at":"2018-05-17T19:49:42.507Z","updated_at":"2018-05-17T19:49:42.507Z","is_administrator":false,"first_name":"John","last_name":"Stead","title":null,"uuid":"1ced2cd8-4bb5-4bc6-a034-29410bb6e86d","suffix":null,"state":"activated","salesforce_contact_id":null,"faculty_status":0,"self_reported_school":null,"login_token":null,"login_token_expires_at":null,"role":0,"signed_external_data":null,"support_identifier":"cs_fa68f2a5","is_test":null,"school_type":0,"identity":null,"authentications":[],"contact_infos":[]}]
\ No newline at end of file
+[{"username":"jstrav","created_at":"2018-05-17T19:49:42.469Z","updated_at":"2018-05-17T19:49:42.469Z","is_administrator":false,"first_name":"John","last_name":"Stravinsky","title":null,"uuid":"f1f96deb-919b-4183-9367-0cb713672172","suffix":null,"state":"activated","salesforce_contact_id":null,"faculty_status":0,"self_reported_school":null,"login_token":null,"login_token_expires_at":null,"role":0,"signed_external_data":null,"is_test":null,"school_type":0,"identity":{"password_digest":"$2a$04$s48G.v95rrx3vQ9Hvld2fus2fuNBRBhel99Io30.mTJOivtSgSxRu","created_at":"2018-05-17T19:49:42.524Z","updated_at":"2018-05-17T19:49:42.524Z","password_expires_at":null},"authentications":[{"provider":"identity","created_at":"2018-05-17T19:49:42.538Z","updated_at":"2018-05-17T19:49:42.538Z","login_hint":null}],"contact_infos":[{"type":"EmailAddress","value":"8f30b4@7cc1fa.223256","verified":false,"confirmation_code":null,"created_at":"2018-05-17T19:49:42.477Z","updated_at":"2018-05-17T19:49:42.477Z","confirmation_sent_at":null,"is_searchable":true,"confirmation_pin":null},{"type":"EmailAddress","value":"a467a2@4634bc.981344","verified":false,"confirmation_code":null,"created_at":"2018-05-17T19:49:42.485Z","updated_at":"2018-05-17T19:49:42.485Z","confirmation_sent_at":null,"is_searchable":true,"confirmation_pin":null}]},{"username":"mary","created_at":"2018-05-17T19:49:42.497Z","updated_at":"2018-05-17T19:49:42.497Z","is_administrator":false,"first_name":"Mary","last_name":"Mighty","title":null,"uuid":"f3145396-9b36-4080-a66d-ff3d4c0c1393","suffix":null,"state":"activated","salesforce_contact_id":null,"faculty_status":0,"self_reported_school":null,"login_token":null,"login_token_expires_at":null,"role":0,"signed_external_data":null,"is_test":null,"school_type":0,"identity":{"password_digest":"$2a$04$nghthHpquanPYYJRfUk6n.TwkNtoP6h.aFFWJl9DHblRze9F1teMa","created_at":"2018-05-17T19:49:42.545Z","updated_at":"2018-05-17T19:49:42.545Z","password_expires_at":null},"authentications":[{"provider":"identity","created_at":"2018-05-17T19:49:42.551Z","updated_at":"2018-05-17T19:49:42.551Z","login_hint":null}],"contact_infos":[]},{"username":"jstead","created_at":"2018-05-17T19:49:42.507Z","updated_at":"2018-05-17T19:49:42.507Z","is_administrator":false,"first_name":"John","last_name":"Stead","title":null,"uuid":"1ced2cd8-4bb5-4bc6-a034-29410bb6e86d","suffix":null,"state":"activated","salesforce_contact_id":null,"faculty_status":0,"self_reported_school":null,"login_token":null,"login_token_expires_at":null,"role":0,"signed_external_data":null,"is_test":null,"school_type":0,"identity":null,"authentications":[],"contact_infos":[]}]
diff --git a/spec/handlers/create_external_user_credentials_spec.rb b/spec/handlers/create_external_user_credentials_spec.rb
index 43f82faacf..9eb9da7fde 100644
--- a/spec/handlers/create_external_user_credentials_spec.rb
+++ b/spec/handlers/create_external_user_credentials_spec.rb
@@ -49,7 +49,7 @@
it 'sends a confirmation email' do
expect_any_instance_of(NewflowMailer).to(
receive(:signup_email_confirmation).with(
- hash_including({ email_address: an_instance_of(EmailAddress) })
+ hash_including({ email_address: an_instance_of(EmailAddress), show_pin: false })
)
)
handler_call
diff --git a/spec/mailers/newflow_mailer_spec.rb b/spec/mailers/newflow_mailer_spec.rb
index 681ed8fa13..aabb49abb1 100644
--- a/spec/mailers/newflow_mailer_spec.rb
+++ b/spec/mailers/newflow_mailer_spec.rb
@@ -2,45 +2,56 @@
module Newflow
describe NewflowMailer, type: :mailer do
- # let(:user) { FactoryBot.create :user, first_name: 'John', last_name: 'Doe', suffix: 'Jr.' }
- # let(:email) { FactoryBot.create :email_address, value: 'to@example.org',
- # user_id: user.id, confirmation_code: '1234', confirmation_pin: '123456' }
-
- describe '' do
- # it 'has basic header and from info and greeting' do
- # mail = ConfirmationMailer.instructions email_address: email
-
- # expect(mail.header['to'].to_s).to eq('"John Doe Jr." ')
- # expect(mail.from).to eq(["noreply@openstax.org"])
- # expect(mail.body.encoded).to include("Hi #{user.casual_name}")
- # end
-
- # it 'does not include PIN when directed not to' do
- # mail = ConfirmationMailer.instructions email_address: email, send_pin: false
-
- # expect(mail.subject).to eq("[OpenStax] Confirm your email address")
- # expect(mail.body.encoded).not_to include('Your PIN')
- # end
-
- # it "has PIN info when PIN attempts remain" do
- # allow(ConfirmByPin).to receive(:sequential_failure_for) { Hashie::Mash.new('attempts_remaining?' => true)}
-
- # mail = ConfirmationMailer.instructions email_address: email, send_pin: true
-
- # expect(mail.subject).to eq("[OpenStax] Use PIN 123456 to confirm your email address")
- # expect(mail.body.encoded).to include('Enter your 6-digit')
- # expect(mail.body.encoded).to include('Your PIN: 123456')
- # end
-
- # it "has just link when no PIN attempts remain" do
- # allow(ConfirmByPin).to receive(:sequential_failure_for) { Hashie::Mash.new('attempts_remaining?' => false)}
-
- # mail = ConfirmationMailer.instructions email_address: email, send_pin: true
-
- # expect(mail.subject).to eq("[OpenStax] Confirm your email address")
- # expect(mail.body.encoded).to include('Click on the link below')
- # expect(mail.body.encoded).not_to include('Your PIN')
- # end
+ let(:pin) { '123456' }
+ let(:code) { '1234' }
+ let(:confirm_url) { "http://localhost:2999/i/verify_email_by_code/#{code}" }
+ let(:user) { FactoryBot.create :user, first_name: 'John', last_name: 'Doe', suffix: 'Jr.' }
+ let(:email) {
+ FactoryBot.create :email_address,
+ value: 'to@example.org',
+ user_id: user.id,
+ confirmation_code: code,
+ confirmation_pin: pin
+ }
+
+ describe 'sends email confirmation' do
+ it 'has basic header and from info and greeting' do
+ mail = NewflowMailer.signup_email_confirmation email_address: email
+
+ expect(mail.header['to'].to_s).to eq('to@example.org')
+ expect(mail.from).to eq(["noreply@openstax.org"])
+ expect(mail.body.encoded).to include("Welcome to OpenStax!")
+ end
+
+ context 'when show_pin is not sent' do
+ it 'includes PIN info in the email' do
+ mail = NewflowMailer.signup_email_confirmation(email_address: email)
+
+ expect(mail.subject).to eq("[OpenStax] Your OpenStax account PIN has arrived: #{pin}")
+ expect(mail.body.encoded).to include("#{pin}")
+ end
+ end
+
+ context 'when show_pin is nil' do
+ it 'includes PIN info in the email' do
+ mail = NewflowMailer.signup_email_confirmation(email_address: email, show_pin: nil)
+
+ expect(mail.subject).to eq("[OpenStax] Your OpenStax account PIN has arrived: #{pin}")
+ expect(mail.body.encoded).to include("#{pin}")
+ end
+ end
+
+ context 'when show_pin is false' do
+ it 'excludes the pin code from the email' do
+ mail = NewflowMailer.signup_email_confirmation(email_address: email, show_pin: false)
+
+ expect(mail.subject).to eq("[OpenStax] Confirm your email address")
+ expect(mail.body.encoded).to include("#{pin}")
+ end
+ end
end
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index b570bd38cd..fe9450846e 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -9,8 +9,7 @@
it { is_expected.to validate_presence_of(:role ) }
it { is_expected.to validate_presence_of(:school_type ) }
- it { is_expected.to validate_uniqueness_of(:uuid ).case_insensitive }
- it { is_expected.to validate_uniqueness_of(:support_identifier).case_insensitive }
+ it { is_expected.to validate_uniqueness_of(:uuid).case_insensitive }
context 'when the user is activated' do
let(:user) { User.new.tap {|u| u.state = 'activated'} }
@@ -135,27 +134,6 @@
end
end
- context 'support_identifier' do
- it 'is generated when created' do
- user = FactoryBot.create :user
- expect(user.support_identifier).to start_with('cs')
- expect(user.support_identifier.length).to eq(11)
- end
-
- it 'cannot be updated' do
- user = FactoryBot.create :user
- old_identifier = user.support_identifier
- user.update(first_name: 'New')
- expect(user.reload.first_name).to eq('New')
- expect(user.support_identifier).to eq(old_identifier)
-
- new_identifier = "cs_#{SecureRandom.hex(4)}"
- user.support_identifier = new_identifier
- user.save
- expect(user.reload.support_identifier).to eq(old_identifier)
- end
- end
-
context 'username' do
it 'must be unique (case-insensitive) on creation, if provided' do
user_1 = FactoryBot.create :user, username: "MyUs3Rn4M3"
diff --git a/spec/representers/api/v1/find_user_representer_spec.rb b/spec/representers/api/v1/find_user_representer_spec.rb
index 9e74130e33..773a7d7640 100644
--- a/spec/representers/api/v1/find_user_representer_spec.rb
+++ b/spec/representers/api/v1/find_user_representer_spec.rb
@@ -30,20 +30,6 @@
end
end
- context 'support_identifier' do
- it 'can be read' do
- payload.support_identifier = SecureRandom.uuid
- expect(representer.to_hash['support_identifier']).to eq payload.support_identifier
- end
-
- it 'cannot be written (attempts are silently ignored)' do
- hash = { 'support_identifier' => SecureRandom.uuid }
-
- expect(payload).not_to receive(:support_identifier=)
- expect { representer.from_hash(hash) }.not_to change { payload.support_identifier }
- end
- end
-
context 'external_id' do
it 'cannot be read' do
payload.external_id = SecureRandom.uuid
diff --git a/spec/representers/api/v1/user_representer_spec.rb b/spec/representers/api/v1/user_representer_spec.rb
index 66f3e0f8aa..18232a4ec4 100644
--- a/spec/representers/api/v1/user_representer_spec.rb
+++ b/spec/representers/api/v1/user_representer_spec.rb
@@ -27,11 +27,10 @@
expect(representer.to_hash['consent_preferences']).to eq user.consent_preferences
end
- it 'cannot be written (attempts are silently ignored)' do
- hash = { 'support_identifier' => "cs_#{SecureRandom.hex(4)}" }
-
- expect(user).not_to receive(:support_identifier=)
- expect { representer.from_hash(hash) }.not_to change { user.reload.support_identifier }
+ it 'can be written' do
+ hash = { 'consent_preferences' => {} }
+ expect(user).to receive(:consent_preferences=).with({}).and_call_original
+ expect { representer.from_hash(hash) }.to change { user.consent_preferences }
end
end
diff --git a/spec/routines/admin/import_users_spec.rb b/spec/routines/admin/import_users_spec.rb
index e0aff29814..20d9e907a9 100644
--- a/spec/routines/admin/import_users_spec.rb
+++ b/spec/routines/admin/import_users_spec.rb
@@ -32,7 +32,6 @@
expect(user_1.login_token_expires_at).to be_nil
expect(user_1.role).to eq 'unknown_role'
expect(user_1.signed_external_data).to be_nil
- expect(user_1.support_identifier).to eq 'cs_5d1edbb0'
expect(user_1.is_test).to be_nil
expect(user_1.school_type).to eq 'unknown_school_type'
expect(user_1.identity.password_digest).to(
@@ -78,7 +77,6 @@
expect(user_2.login_token_expires_at).to be_nil
expect(user_2.role).to eq 'unknown_role'
expect(user_2.signed_external_data).to be_nil
- expect(user_2.support_identifier).to eq 'cs_6cf1cf5e'
expect(user_2.is_test).to be_nil
expect(user_2.school_type).to eq 'unknown_school_type'
expect(user_2.identity.password_digest).to(
@@ -111,7 +109,6 @@
expect(user_3.login_token_expires_at).to be_nil
expect(user_3.role).to eq 'unknown_role'
expect(user_3.signed_external_data).to be_nil
- expect(user_3.support_identifier).to eq 'cs_fa68f2a5'
expect(user_3.is_test).to be_nil
expect(user_3.school_type).to eq 'unknown_school_type'
expect(user_3.identity).to be_nil
diff --git a/spec/routines/admin/search_users_spec.rb b/spec/routines/admin/search_users_spec.rb
index 0187c38230..edeb445a2a 100644
--- a/spec/routines/admin/search_users_spec.rb
+++ b/spec/routines/admin/search_users_spec.rb
@@ -56,20 +56,6 @@
expect(outcome).to eq [user_1]
end
- it "should match on full support_identifier" do
- support_identifier = user_1.support_identifier
- outcome = described_class.call("support_identifier:#{support_identifier}").outputs.items.to_a
- expect(outcome).to eq [user_1]
- end
-
- it "should match on partial support_identifier" do
- partial_support_identifier = user_1.support_identifier.first(10).last(9)
- outcome = described_class.call(
- "support_identifier:#{partial_support_identifier}"
- ).outputs.items.to_a
- expect(outcome).to eq [user_1]
- end
-
it "should match based on a partial email address" do
email = user_1.contact_infos.email_addresses.order(:value).first.value.split('@').first
outcome = described_class.call("email:#{email}").outputs.items.to_a
@@ -84,17 +70,11 @@
end
it "should match any fields when no prefix given" do
- [ user_1, user_2, user_3, user_4 ].each_with_index do |user, index|
- User.where(id: user.id).update_all(support_identifier: "cs_#{index}")
- end
outcome = described_class.call("st").outputs.items.to_a
expect(outcome).to eq [user_4, user_3, user_1]
end
it "should match any fields when no prefix given and intersect when prefix given" do
- [ user_1, user_2, user_3, user_4 ].each_with_index do |user, index|
- User.where(id: user.id).update_all(support_identifier: "cs_#{index}")
- end
outcome = described_class.call("John first_name:John").outputs.items.to_a
expect(outcome).to eq [user_3, user_1]
end
@@ -105,9 +85,6 @@
end
it "should gather space-separated unprefixed search terms" do
- [ user_1, user_2, user_3, user_4 ].each_with_index do |user, index|
- User.where(id: user.id).update_all(support_identifier: "cs_#{index}")
- end
outcome = described_class.call("john strav").outputs.items.to_a
expect(outcome).to eq [user_1]
end
diff --git a/spec/routines/search_users_spec.rb b/spec/routines/search_users_spec.rb
index 11b3ffad83..92f587f3f3 100644
--- a/spec/routines/search_users_spec.rb
+++ b/spec/routines/search_users_spec.rb
@@ -145,25 +145,11 @@
expect(outcome).to eq [user_4]
end
- it 'should not match by support_identifier' do
- outcome = described_class.call(
- "support_identifier:#{user_3.support_identifier}"
- ).outputs.items.to_a
- expect(outcome).to eq []
- end
-
it 'should match by external_id' do
outcome = described_class.call("external_id:#{user_4.external_ids.first.external_id}").outputs.items.to_a
expect(outcome).to eq [user_4]
end
- it 'should not match by support_identifier' do
- outcome = described_class.call(
- "support_identifier:#{user_3.support_identifier}"
- ).outputs.items.to_a
- expect(outcome).to eq []
- end
-
context "sorting" do
let!(:bob_brown) do
diff --git a/spec/support/user_hash.rb b/spec/support/user_hash.rb
index 10946035f9..63e9ccb743 100644
--- a/spec/support/user_hash.rb
+++ b/spec/support/user_hash.rb
@@ -11,7 +11,6 @@ def user_matcher(user, include_private_data: false)
title: user.title,
suffix: user.suffix,
uuid: user.uuid,
- support_identifier: user.support_identifier,
consent_preferences: user.consent_preferences,
is_test: user.is_test?,
is_administrator: user.is_administrator?,