diff --git a/app/views/waiting_list_mailer/daily_report.html.erb b/app/views/waiting_list_mailer/daily_report.html.erb
new file mode 100644
index 0000000..609523b
--- /dev/null
+++ b/app/views/waiting_list_mailer/daily_report.html.erb
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
Daily Waiting List Report - Linkarooie
+
+
+
Total subscribers: <%= @total_count %>
+
New subscribers today: <%= @today_count %>
+
+
+
All Subscribers:
+
+ <% @waiting_list.each do |subscriber| %>
+ - <%= subscriber.email %> (joined: <%= subscriber.created_at.strftime('%B %d, %Y') %>)
+ <% end %>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index 911a877..f5ccce9 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -14,6 +14,8 @@
# Health check route
get 'up' => 'rails/health#show', as: :rails_health_check
+ resources :waiting_lists, only: [:create]
+
# Root route
root to: 'pages#home'
diff --git a/config/sidekiq_scheduler.yml b/config/sidekiq_scheduler.yml
index ad94670..ecb05a6 100644
--- a/config/sidekiq_scheduler.yml
+++ b/config/sidekiq_scheduler.yml
@@ -5,3 +5,7 @@ aggregate_metrics:
backup_database:
cron: '0 2 * * *' # Runs daily at 2 AM
class: BackupDatabaseJob
+
+send_waiting_list_report:
+ cron: '0 3 * * *' # Runs daily at 3 AM
+ class: SendWaitingListReportJob
\ No newline at end of file
diff --git a/db/migrate/20240904121238_create_waiting_lists.rb b/db/migrate/20240904121238_create_waiting_lists.rb
new file mode 100644
index 0000000..be3e691
--- /dev/null
+++ b/db/migrate/20240904121238_create_waiting_lists.rb
@@ -0,0 +1,9 @@
+class CreateWaitingLists < ActiveRecord::Migration[7.1]
+ def change
+ create_table :waiting_lists do |t|
+ t.string :email
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 02c5548..b6a6039 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[7.1].define(version: 2024_09_02_002819) do
+ActiveRecord::Schema[7.1].define(version: 2024_09_04_121238) do
create_table "achievement_views", force: :cascade do |t|
t.integer "achievement_id", null: false
t.integer "user_id", null: false
@@ -141,6 +141,12 @@
t.index ["username"], name: "index_users_on_username", unique: true
end
+ create_table "waiting_lists", force: :cascade do |t|
+ t.string "email"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
add_foreign_key "achievement_views", "achievements"
add_foreign_key "achievement_views", "users"
add_foreign_key "achievements", "users"
diff --git a/spec/controllers/waiting_lists_controller_spec.rb b/spec/controllers/waiting_lists_controller_spec.rb
new file mode 100644
index 0000000..8bf6be9
--- /dev/null
+++ b/spec/controllers/waiting_lists_controller_spec.rb
@@ -0,0 +1,50 @@
+# spec/controllers/waiting_lists_controller_spec.rb
+require 'rails_helper'
+
+RSpec.describe WaitingListsController, type: :controller do
+ describe "POST #create" do
+ context "with valid params" do
+ it "creates a new WaitingList" do
+ expect {
+ post :create, params: { waiting_list: attributes_for(:waiting_list) }
+ }.to change(WaitingList, :count).by(1)
+ end
+
+ it "redirects to the root path with a success notice" do
+ post :create, params: { waiting_list: attributes_for(:waiting_list) }
+ expect(response).to redirect_to(root_path)
+ expect(flash[:notice]).to eq("Thanks for joining our waiting list!")
+ end
+ end
+
+ context "with invalid params" do
+ it "does not create a new WaitingList" do
+ expect {
+ post :create, params: { waiting_list: { email: "invalid_email" } }
+ }.to_not change(WaitingList, :count)
+ end
+
+ it "redirects to the root path with an error alert" do
+ post :create, params: { waiting_list: { email: "invalid_email" } }
+ expect(response).to redirect_to(root_path)
+ expect(flash[:alert]).to include("There was an error")
+ end
+ end
+
+ context "with duplicate email" do
+ before { create(:waiting_list, email: "test@example.com") }
+
+ it "does not create a new WaitingList" do
+ expect {
+ post :create, params: { waiting_list: { email: "test@example.com" } }
+ }.to_not change(WaitingList, :count)
+ end
+
+ it "redirects to the root path with an error alert" do
+ post :create, params: { waiting_list: { email: "test@example.com" } }
+ expect(response).to redirect_to(root_path)
+ expect(flash[:alert]).to include("Email has already been taken")
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/spec/factories/waiting_lists.rb b/spec/factories/waiting_lists.rb
new file mode 100644
index 0000000..ed302e2
--- /dev/null
+++ b/spec/factories/waiting_lists.rb
@@ -0,0 +1,6 @@
+# spec/factories/waiting_lists.rb
+FactoryBot.define do
+ factory :waiting_list do
+ sequence(:email) { |n| "user#{n}@example.com" }
+ end
+end
\ No newline at end of file
diff --git a/spec/helpers/waiting_lists_helper_spec.rb b/spec/helpers/waiting_lists_helper_spec.rb
new file mode 100644
index 0000000..4abd8d2
--- /dev/null
+++ b/spec/helpers/waiting_lists_helper_spec.rb
@@ -0,0 +1,6 @@
+# spec/helpers/waiting_lists_helper_spec.rb
+require 'rails_helper'
+
+RSpec.describe WaitingListsHelper, type: :helper do
+ # Add helper specs here if you create any helper methods in the future
+end
\ No newline at end of file
diff --git a/spec/models/waiting_list_spec.rb b/spec/models/waiting_list_spec.rb
new file mode 100644
index 0000000..567942e
--- /dev/null
+++ b/spec/models/waiting_list_spec.rb
@@ -0,0 +1,26 @@
+# spec/models/waiting_list_spec.rb
+require 'rails_helper'
+
+RSpec.describe WaitingList, type: :model do
+ it "has a valid factory" do
+ expect(build(:waiting_list)).to be_valid
+ end
+
+ describe "validations" do
+ it { should validate_presence_of(:email) }
+ it { should validate_uniqueness_of(:email).case_insensitive }
+
+ it "validates email format" do
+ valid_emails = ["user@example.com", "USER@foo.COM", "A_US-ER@foo.bar.org"]
+ invalid_emails = ["user@example,com", "user_at_foo.org", "user.name@example.", "foo@bar_baz.com", "foo@bar+baz.com"]
+
+ valid_emails.each do |email|
+ expect(build(:waiting_list, email: email)).to be_valid
+ end
+
+ invalid_emails.each do |email|
+ expect(build(:waiting_list, email: email)).to be_invalid
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/spec/requests/waiting_lists_spec.rb b/spec/requests/waiting_lists_spec.rb
new file mode 100644
index 0000000..29cd65a
--- /dev/null
+++ b/spec/requests/waiting_lists_spec.rb
@@ -0,0 +1,44 @@
+# spec/requests/waiting_lists_spec.rb
+require 'rails_helper'
+
+RSpec.describe "WaitingLists", type: :request do
+ describe "POST /waiting_lists" do
+ context "with valid parameters" do
+ it "creates a new waiting list entry" do
+ expect {
+ post waiting_lists_path, params: { waiting_list: { email: "test@example.com" } }
+ }.to change(WaitingList, :count).by(1)
+
+ expect(response).to redirect_to(root_path)
+ follow_redirect!
+ expect(response.body).to include("Thanks for joining our waiting list!")
+ end
+ end
+
+ context "with invalid parameters" do
+ it "does not create a new waiting list entry" do
+ expect {
+ post waiting_lists_path, params: { waiting_list: { email: "invalid_email" } }
+ }.not_to change(WaitingList, :count)
+
+ expect(response).to redirect_to(root_path)
+ follow_redirect!
+ expect(response.body).to include("There was an error")
+ end
+ end
+
+ context "with duplicate email" do
+ before { WaitingList.create(email: "test@example.com") }
+
+ it "does not create a new waiting list entry" do
+ expect {
+ post waiting_lists_path, params: { waiting_list: { email: "test@example.com" } }
+ }.not_to change(WaitingList, :count)
+
+ expect(response).to redirect_to(root_path)
+ follow_redirect!
+ expect(response.body).to include("Email has already been taken")
+ end
+ end
+ end
+end
\ No newline at end of file