mr_common 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +30 -9
- data/app/controllers/mr_common/dashboard_controller.rb +1 -0
- data/app/controllers/mr_common/pre_registrations/import_controller.rb +26 -0
- data/app/controllers/mr_common/pre_registrations/pre_registrations_controller.rb +48 -0
- data/app/controllers/mr_common/registrations/confirmations_controller.rb +54 -0
- data/app/controllers/mr_common/registrations/export_controller.rb +35 -4
- data/app/controllers/mr_common/registrations/public_controller.rb +24 -1
- data/app/controllers/mr_common/registrations/registrations_controller.rb +2 -0
- data/app/controllers/mr_common/registrations/resend_notifications_controller.rb +27 -0
- data/app/controllers/mr_common/registrations/success_controller.rb +1 -0
- data/app/mailers/mr_common/registration_mailer.rb +13 -3
- data/app/models/concerns/mr_common/csv_exportable.rb +6 -2
- data/app/models/mr_common/country.rb +9 -0
- data/app/models/mr_common/csv_renderer.rb +38 -0
- data/app/models/mr_common/pattern.rb +10 -0
- data/app/models/mr_common/pre_registration.rb +52 -0
- data/app/models/mr_common/pre_registration_importer.rb +91 -0
- data/app/models/mr_common/registration.rb +11 -2
- data/app/models/mr_common/registration_decorator.rb +20 -0
- data/app/models/mr_common/reminder.rb +6 -0
- data/app/models/mr_common/timezone.rb +5 -0
- data/app/views/layouts/mr_common/_navigation.html.erb +7 -0
- data/app/views/mr_common/pre_registrations/import/new.html.erb +27 -0
- data/app/views/mr_common/pre_registrations/pre_registrations/_form.html.erb +29 -0
- data/app/views/mr_common/pre_registrations/pre_registrations/index.html.erb +32 -0
- data/{lib/generators/mr_common/views/templates/mr_common/registrations/public → app/views/mr_common/pre_registrations/pre_registrations}/new.html.erb +2 -1
- data/{lib/generators/mr_common/views/templates/mr_common/registration_mailer/confirmation.html.erb → app/views/mr_common/registration_mailer/confirmed_registration.html.erb} +3 -0
- data/app/views/mr_common/registration_mailer/{confirmation.text.erb → confirmed_registration.text.erb} +2 -0
- data/app/views/mr_common/registration_mailer/revoked_registration.html.erb +5 -0
- data/app/views/mr_common/registration_mailer/revoked_registration.text.erb +6 -0
- data/app/views/mr_common/registration_mailer/unconfirmed_registration.html.erb +3 -0
- data/app/views/mr_common/registration_mailer/unconfirmed_registration.text.erb +4 -0
- data/app/views/mr_common/registrations/registrations/_form.html.erb +6 -0
- data/app/views/mr_common/registrations/registrations/index.html.erb +4 -0
- data/app/views/mr_common/registrations/registrations/show.html.erb +34 -3
- data/config/routes.rb +13 -1
- data/db/migrate/20190522151523_create_pre_registrations.rb +12 -0
- data/db/migrate/20190530220614_add_confirmed_to_registrations.rb +5 -0
- data/lib/generators/mr_common/controllers/USAGE +9 -0
- data/lib/generators/mr_common/controllers/controllers_generator.rb +24 -0
- data/lib/generators/mr_common/mailers/USAGE +16 -0
- data/lib/generators/mr_common/mailers/mailers_generator.rb +31 -0
- data/lib/generators/mr_common/models/USAGE +8 -0
- data/lib/generators/mr_common/models/models_generator.rb +23 -0
- data/lib/generators/mr_common/views/USAGE +1 -4
- data/lib/generators/mr_common/views/views_generator.rb +7 -8
- data/lib/mr_common.rb +14 -2
- data/lib/mr_common/version.rb +1 -1
- data/spec/dummy/config/initializers/mr_common.rb +10 -0
- data/spec/dummy/db/schema.rb +14 -4
- data/spec/dummy/log/development.log +1969 -50958
- data/spec/dummy/log/test.log +647 -14437
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-G/-gyHBJNssgJVEwk7sD1F9nK_dT1D1R5NjlAvcESJxME.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3d/3DI5adLgOKj6Q76fFxrLy_hKYkrlht0MEWksNkYgoXk.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3n/3NK03OBfUwDPKVYV6_11AOo3IGNUQPed4dqB-Ddv6-Q.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/7d/7DbSMErmkAd0cL6q_WyLMfx7gLYQB0h9smKZ0xGjOjY.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/9m/9MK1AG2zx0HVFVRULpQQnQQY0HiNroKnYEz2FUBzw6k.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/CO/cojbSP1f9tYoCyycggqXgW3OYb3atOkOpf-h-Axn36o.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/H6/h6GO-mL-rzWHmoiFw-uuwdny5zj_zSb1Xzun5jkza5k.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/LG/LG2fyButWQgZoNvH4qD2dBMQhl35dSysUbxsvw_2PA0.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/LZ/lZ_yNthdvXeWexZW9TZuMWs6lZBLMEF5rp7aA5Bl9uU.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Lh/LhBzrZLgp6fzHcgWFt_B-TqHzHaPyKv9Uk67brUycZE.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/N-/N-7bXt4Ck0q2VWzHHuRPKL0a0CH_1W_eyAU59tZraxE.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Pi/PI3-Xhs-TBYEqgGeCf3hWGn6vj1qCdqBqgYRY2jNr4Q.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QQ/qqtvJX4CrLCTv4jjIg0LwoNxJUyDpLus0RIbg6D6muk.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Se/setx2SgK-JX4zwjgbekiVnvWJnbp0-2XnO0TQJfCOHU.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ue/UecY7KKAHkP6oiqpx1zkXAL9WWGqWdhgqhixQyJ82is.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/VF/VfH7y0fTeHy8aLBK_bu5OKprS0c1-GCHUzrMzp-O0_I.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/WC/WCV-7lpbJsFHZueodYuN5542p56UPNtby1LVPUjvuJU.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/WV/wvfl97Gci1mpw00EFHWc0Q9x0DLBar03PTd9BrZ7MF0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/eP/ePjuIgA1bwfnJWATz7q6EjGfNnpvYEaKW_2aozCJFBQ.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ge/GegLYwRNBYKvfYR1-WWnx3ssHerCO6M94VPxwUTYHtM.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/h9/H95rpLdUakuAt6lpkUhlZvxsYlSb-VrfpiznZYmWnGo.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/p_/P_kWJKPROj6qDVkyzNQgx8wZmba8YaTqtWMQyGHFtuY.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/w3/w34qFl6hbbodwCEAr9Px_jzso7svjewL5BaOf6QMIN4.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/wi/wi_OyVKzMxj9CcM3e2Bhab5PQSg4wh0nD-7QJQ3SVPw.cache +1 -0
- data/spec/dummy/tmp/pids/server.pid +1 -1
- data/spec/factories/registrations.rb +5 -5
- data/spec/models/registration_spec.rb +40 -0
- metadata +80 -11
- data/app/helpers/mr_common/form_helper.rb +0 -11
- data/app/models/mr_common/csv_exporter.rb +0 -35
- data/app/models/mr_common/default_csv_export_adapter.rb +0 -23
- data/app/views/mr_common/registration_mailer/confirmation.html.erb +0 -4
- data/lib/generators/mr_common/views/templates/mr_common/registration_mailer/confirmation.text.erb +0 -6
- data/lib/generators/mr_common/views/templates/mr_common/registrations/success/index.html.erb +0 -2
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "csv"
|
|
4
|
+
|
|
5
|
+
module MrCommon
|
|
6
|
+
# Renders collections of objects to a CSV string.
|
|
7
|
+
#
|
|
8
|
+
# @param collection [Enumerable<Object>] a collection of objects.
|
|
9
|
+
# @param fields [Array<String, Symbol>] fields to use as columns in the CSV.
|
|
10
|
+
# It is expected that each item responds to each field if sent as a message.
|
|
11
|
+
# @param decorator [SimpleDelegator, nil] optional wrapper class used to
|
|
12
|
+
# generate values for CSV rows when items in the collection don't respond to
|
|
13
|
+
# every field provided.
|
|
14
|
+
class CSVRenderer
|
|
15
|
+
attr_reader :collection, :decorator, :fields
|
|
16
|
+
|
|
17
|
+
def initialize(collection: [], fields: [], decorator: nil)
|
|
18
|
+
@collection = collection
|
|
19
|
+
@decorator = decorator
|
|
20
|
+
@fields = fields.map(&:to_sym)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Renders the provided collection to a CSV string.
|
|
24
|
+
#
|
|
25
|
+
# @return [String] the CSV file contents
|
|
26
|
+
def render
|
|
27
|
+
CSV.generate do |csv|
|
|
28
|
+
csv << fields
|
|
29
|
+
|
|
30
|
+
collection.each do |item|
|
|
31
|
+
item = decorator ? decorator.new(item) : item
|
|
32
|
+
row = fields.map { |field_name| item.try(field_name) }
|
|
33
|
+
csv << row
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module MrCommon
|
|
4
|
+
# Common regex patterns
|
|
4
5
|
class Pattern
|
|
5
6
|
class << self
|
|
7
|
+
# Matches valid email addresses. Ensures that the @ symbol is
|
|
8
|
+
# preceded by something resembling a username and followed by something
|
|
9
|
+
# resembling a domain name.
|
|
6
10
|
def email
|
|
7
11
|
/\A\S+@\S+\.\S+\z/
|
|
8
12
|
end
|
|
13
|
+
|
|
14
|
+
# Matches most phone numbers a person could enter. Tests for at least 7 of
|
|
15
|
+
# the characters that can appear in a phone number.
|
|
16
|
+
def phone_number
|
|
17
|
+
/[\d()\\x+\- ]{7,}/
|
|
18
|
+
end
|
|
9
19
|
end
|
|
10
20
|
end
|
|
11
21
|
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MrCommon
|
|
4
|
+
# When MrCommon.enable_pre_registration is true newly created Registrations
|
|
5
|
+
# will be checked against existing PreRegistrations. If a PreRegistration is
|
|
6
|
+
# found the Registration will be confirmed automatically.
|
|
7
|
+
#
|
|
8
|
+
# A PreRegistration requires a first+last name OR an email to be valid.
|
|
9
|
+
class PreRegistration < ApplicationRecord
|
|
10
|
+
validates :email, presence: true, format: MrCommon::Pattern.email, if: :should_validate_email?
|
|
11
|
+
validates :first_name, presence: true, if: :should_validate_name?
|
|
12
|
+
validates :last_name, presence: true, if: :should_validate_name?
|
|
13
|
+
validates :normalized_name, presence: true, if: :should_validate_name?
|
|
14
|
+
|
|
15
|
+
before_validation :normalize_email
|
|
16
|
+
before_validation :set_normalized_name
|
|
17
|
+
|
|
18
|
+
def self.exists_for?(registration)
|
|
19
|
+
email = registration.email&.downcase
|
|
20
|
+
name = normalized_name_from(registration).presence
|
|
21
|
+
|
|
22
|
+
exists_for_email = email.present? ? exists?(email: email) : false
|
|
23
|
+
exists_for_name = name.present? ? exists?(normalized_name: name) : false
|
|
24
|
+
exists_for_email || exists_for_name
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def self.normalized_name_from(registration_or_self)
|
|
30
|
+
first = registration_or_self.first_name.downcase.gsub(/\W+/, "-")
|
|
31
|
+
last = registration_or_self.last_name.downcase.gsub(/\W+/, "-")
|
|
32
|
+
spacer = first.present? && last.present? ? "-" : ""
|
|
33
|
+
"#{first}#{spacer}#{last}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def should_validate_email?
|
|
37
|
+
first_name.blank? && last_name.blank?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def should_validate_name?
|
|
41
|
+
email.blank?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def set_normalized_name
|
|
45
|
+
self.normalized_name = PreRegistration.normalized_name_from(self)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def normalize_email
|
|
49
|
+
self.email = email.downcase
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MrCommon
|
|
4
|
+
# Imports PreRegistration records from a CSV file that looks like:
|
|
5
|
+
#
|
|
6
|
+
# first_name, last_name, email
|
|
7
|
+
# John, Smith, jsmith@example.com
|
|
8
|
+
# Jane, Doe, jdoe@example.com
|
|
9
|
+
# ,,unknown@example.com
|
|
10
|
+
# Name,Only,
|
|
11
|
+
#
|
|
12
|
+
# @author Corey Smedstad <csmedstad@mreach.com>
|
|
13
|
+
class PreRegistrationImporter
|
|
14
|
+
RowStruct = Struct.new(:first_name, :last_name, :email) do
|
|
15
|
+
# Returns true if the row does not represent a duplicate PreRegistration
|
|
16
|
+
# @return [Boolean]
|
|
17
|
+
def new?
|
|
18
|
+
!PreRegistration.exists_for?(self)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
ResultStruct = Struct.new(:created, :skipped)
|
|
23
|
+
|
|
24
|
+
attr_reader :csv, :current_row, :result
|
|
25
|
+
|
|
26
|
+
# @param csv [String] a the contents of a CSV file
|
|
27
|
+
def initialize(csv)
|
|
28
|
+
@csv = csv
|
|
29
|
+
@created = 0
|
|
30
|
+
@skipped = 0
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Attempts to create PreRegistration records for each row in the CSV
|
|
34
|
+
# recording the number of created and skipped records in the process.
|
|
35
|
+
#
|
|
36
|
+
# The result is memoized to prevent double imports.
|
|
37
|
+
#
|
|
38
|
+
# @returns [ResultStruct] the result of the import
|
|
39
|
+
def import
|
|
40
|
+
@result ||= perform_import
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def perform_import
|
|
46
|
+
PreRegistration.transaction do
|
|
47
|
+
rows.each do |data|
|
|
48
|
+
load_row(data)
|
|
49
|
+
|
|
50
|
+
if current_row.new?
|
|
51
|
+
make_pre_registration
|
|
52
|
+
else
|
|
53
|
+
skip_pre_registration
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
ResultStruct.new(@created, @skipped)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def rows
|
|
62
|
+
CSV.parse(csv, headers: true)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def load_row(data)
|
|
66
|
+
first_name = data[0] || ""
|
|
67
|
+
last_name = data[1] || ""
|
|
68
|
+
email = data[2] || ""
|
|
69
|
+
|
|
70
|
+
@current_row = RowStruct.new(first_name, last_name, email)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def make_pre_registration
|
|
74
|
+
pre_registration = PreRegistration.new(
|
|
75
|
+
first_name: current_row.first_name,
|
|
76
|
+
last_name: current_row.last_name,
|
|
77
|
+
email: current_row.email
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if pre_registration.save
|
|
81
|
+
@created += 1
|
|
82
|
+
else
|
|
83
|
+
skip_pre_registration
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def skip_pre_registration
|
|
88
|
+
@skipped += 1
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -8,11 +8,20 @@ module MrCommon
|
|
|
8
8
|
|
|
9
9
|
validates :first_name, presence: true
|
|
10
10
|
validates :last_name, presence: true
|
|
11
|
-
validates :email, presence: true
|
|
11
|
+
validates :email, presence: true, format: Pattern.email
|
|
12
12
|
validates :company_name, presence: true
|
|
13
|
-
validates :telephone, presence: true
|
|
13
|
+
validates :telephone, presence: true, format: Pattern.phone_number
|
|
14
14
|
validates :job_title, presence: true
|
|
15
15
|
validates :contact_via_email, inclusion: [true, false]
|
|
16
16
|
validates :contact_via_phone, inclusion: [true, false]
|
|
17
|
+
|
|
18
|
+
validate :telephone_length
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def telephone_length
|
|
23
|
+
digits = telephone.gsub(/\D+/, "")
|
|
24
|
+
errors.add(:telephone, "must be longer") if digits.length < 7
|
|
25
|
+
end
|
|
17
26
|
end
|
|
18
27
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MrCommon
|
|
4
|
+
# Implements custom field values when exporting Registration records as CSV.
|
|
5
|
+
class RegistrationDecorator < SimpleDelegator
|
|
6
|
+
def preregistered?
|
|
7
|
+
__getobj__.preregistered? ? "YES" : "NO"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def confirmed?
|
|
11
|
+
__getobj__.confirmed? ? "YES" : "NO"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
if MrCommon.registration_confirmation_strategy == :pre_register
|
|
15
|
+
def pre_registered?
|
|
16
|
+
PreRegistration.exists_for?(__getobj__) ? "YES" : "NO"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
require_dependency "mr_common/application_record"
|
|
4
4
|
|
|
5
5
|
module MrCommon
|
|
6
|
+
# Stores information for generating downloadable calendar reminders that
|
|
7
|
+
# appear in some emails.
|
|
8
|
+
#
|
|
9
|
+
# When
|
|
6
10
|
class Reminder < ApplicationRecord
|
|
7
11
|
validates :start_time, presence: true
|
|
8
12
|
validates :end_time, presence: true
|
|
@@ -15,6 +19,8 @@ module MrCommon
|
|
|
15
19
|
|
|
16
20
|
before_validation :parameterize_slug
|
|
17
21
|
|
|
22
|
+
scope :for_confirmed_notice, -> { where(include_in_confirmation_mailer: true) }
|
|
23
|
+
|
|
18
24
|
def to_ical
|
|
19
25
|
cal = Icalendar::Calendar.new
|
|
20
26
|
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module MrCommon
|
|
4
|
+
# Helper class for building time zone select options. Pares down the list by
|
|
5
|
+
# grouping locations that share ones or offsets.
|
|
4
6
|
class Timezone
|
|
5
7
|
class << self
|
|
8
|
+
# @return [Array<String>] list of time zone names ordered by offset
|
|
6
9
|
def time_zone_options
|
|
7
10
|
filtered_time_zones.collect(&:name)
|
|
8
11
|
end
|
|
9
12
|
|
|
13
|
+
# @return [Array<Array<String, String>>] list of label value pairs for
|
|
14
|
+
# building time zone select options ordered by offset.
|
|
10
15
|
def time_zone_select_options
|
|
11
16
|
filtered_time_zones.collect do |tz|
|
|
12
17
|
["(UTC#{tz_utc_offset(tz)}) #{tz_friendly_name(tz)}", tz.name]
|
|
@@ -13,6 +13,13 @@
|
|
|
13
13
|
<li>
|
|
14
14
|
<%= link_to 'Reminders', reminders_path %>
|
|
15
15
|
</li>
|
|
16
|
+
|
|
17
|
+
<% if MrCommon.registration_confirmation_strategy == :pre_register %>
|
|
18
|
+
<li>
|
|
19
|
+
<%= link_to 'PreRegistrations', pre_registrations_path %>
|
|
20
|
+
</li>
|
|
21
|
+
<% end %>
|
|
22
|
+
|
|
16
23
|
<% if MrCommon.authentication_method_name.present? %>
|
|
17
24
|
<li>
|
|
18
25
|
<%= link_to 'Log Out', main_app.send(MrCommon.logout_path_helper), method: MrCommon.logout_path_method %>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<div class="row">
|
|
2
|
+
<div class="col">
|
|
3
|
+
<h1>Import Pre Registrations</h1>
|
|
4
|
+
<%= form_with scope: :import, url: pre_registrations_import_index_url, local: true do |f| %>
|
|
5
|
+
<fieldset>
|
|
6
|
+
<legend>Import</legend>
|
|
7
|
+
<div class="form-group">
|
|
8
|
+
<%= f.label :csv_file, "CSV File" %>
|
|
9
|
+
<%= f.file_field :csv_file, required: true, accept: "text/csv" %>
|
|
10
|
+
</div>
|
|
11
|
+
<p>The CSV file should be formatted like this example:</p>
|
|
12
|
+
<pre>
|
|
13
|
+
first_name, last_name, email
|
|
14
|
+
John, Smith, jsmith@example.com
|
|
15
|
+
Jane, Doe, jdoe@example.com
|
|
16
|
+
,,unknown@example.com
|
|
17
|
+
Name,Only,
|
|
18
|
+
</pre>
|
|
19
|
+
<p>If you have a spreadsheet with these columns, "Save as..." and choose the CSV as the file type.</p>
|
|
20
|
+
<p>It is assumed that your CSV has column headings. The first non-empty row will be ignored.</p>
|
|
21
|
+
</fieldset>
|
|
22
|
+
|
|
23
|
+
<%= f.submit "Import" %>
|
|
24
|
+
<%= link_to "Cancel", pre_registrations_path, class: 'button-secondary' %>
|
|
25
|
+
<% end %>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<%= form_with model: @pre_registration, local: true do |f| %>
|
|
2
|
+
<fieldset>
|
|
3
|
+
<legend>Pre-registration details</legend>
|
|
4
|
+
<%= f.form_group :email do %>
|
|
5
|
+
<%= f.label :email %>
|
|
6
|
+
<%= f.text_field :email %>
|
|
7
|
+
<%= f.errors :email %>
|
|
8
|
+
<% end %>
|
|
9
|
+
|
|
10
|
+
<%= f.form_group :first_name do %>
|
|
11
|
+
<%= f.label :first_name %>
|
|
12
|
+
<%= f.text_field :first_name %>
|
|
13
|
+
<%= f.errors :first_name %>
|
|
14
|
+
<% end %>
|
|
15
|
+
|
|
16
|
+
<%= f.form_group :last_name do %>
|
|
17
|
+
<%= f.label :last_name %>
|
|
18
|
+
<%= f.text_field :last_name %>
|
|
19
|
+
<%= f.errors :last_name %>
|
|
20
|
+
<% end %>
|
|
21
|
+
</fieldset>
|
|
22
|
+
|
|
23
|
+
<%= f.submit "Save" %>
|
|
24
|
+
<% if @pre_registration.new_record? %>
|
|
25
|
+
<%= link_to "Cancel", pre_registrations_path, class: 'button-secondary' %>
|
|
26
|
+
<% else %>
|
|
27
|
+
<%= link_to "Cancel", pre_registration_path(@pre_registration), class: 'button-secondary' %>
|
|
28
|
+
<% end %>
|
|
29
|
+
<% end %>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<div class="row">
|
|
2
|
+
<div class="col">
|
|
3
|
+
<h1>PreRegistrations</h1>
|
|
4
|
+
<p>
|
|
5
|
+
<%= link_to 'New', new_pre_registration_path, class: 'button' %>
|
|
6
|
+
</p>
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="row">
|
|
10
|
+
<div class="col">
|
|
11
|
+
<table>
|
|
12
|
+
<thead>
|
|
13
|
+
<tr>
|
|
14
|
+
<th>Email</th>
|
|
15
|
+
<th>First</th>
|
|
16
|
+
<th>Last</th>
|
|
17
|
+
<th>Actions</th>
|
|
18
|
+
</tr>
|
|
19
|
+
</thead>
|
|
20
|
+
<tbody>
|
|
21
|
+
<% @pre_registration.each do |r| %>
|
|
22
|
+
<tr>
|
|
23
|
+
<td><%= r.email %></td>
|
|
24
|
+
<td><%= r.first_name %></td>
|
|
25
|
+
<td><%= r.last_name %></td>
|
|
26
|
+
<td><%= link_to 'Delete', r, method: :delete, data: { confirm: 'Are you sure?' } %></td>
|
|
27
|
+
</tr>
|
|
28
|
+
<% end %>
|
|
29
|
+
</tbody>
|
|
30
|
+
</table>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<h1>Your registration is no longer confirmed</h1>
|
|
2
|
+
|
|
3
|
+
<p>Thank you for your interest in our invitation-only event.</p>
|
|
4
|
+
|
|
5
|
+
<p>Unfortunately, we aren’t able to accommodate your registration at this time. If we are able to confirm a spot for you, we will notify you before the event.</p>
|