diff --git a/Gemfile b/Gemfile index 8402738bf..f576edd4a 100644 --- a/Gemfile +++ b/Gemfile @@ -68,6 +68,7 @@ group :development do gem "web-console" gem "rubocop", require: false gem "solargraph" + gem "letter_opener" # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] # gem "rack-mini-profiler" diff --git a/Gemfile.lock b/Gemfile.lock index 06d31102c..e03d8c735 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -128,6 +128,10 @@ GEM rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) + launchy (2.5.0) + addressable (~> 2.7) + letter_opener (1.8.1) + launchy (>= 2.2, < 3) loofah (2.18.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) @@ -311,6 +315,7 @@ DEPENDENCIES importmap-rails jbuilder jquery-rails + letter_opener mysql2 (~> 0.5) pay (~> 6.0.3) puma (~> 5.0) diff --git a/app/models/user.rb b/app/models/user.rb index 9dcdc9761..7972798d4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,7 +2,8 @@ class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, - :recoverable, :rememberable, :validatable + :recoverable, :rememberable, :validatable, + :confirmable, :lockable, :trackable # Set up paying customer pay_customer default_payment_processor: :stripe diff --git a/config/environments/development.rb b/config/environments/development.rb index 1f4660fc6..aa7ca0c7a 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -33,6 +33,10 @@ config.cache_store = :null_store end + # letter opener + config.action_mailer.delivery_method = :letter_opener + config.action_mailer.perform_deliveries = true + # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local diff --git a/db/migrate/20221209021828_add_mailer_to_devise.rb b/db/migrate/20221209021828_add_mailer_to_devise.rb new file mode 100644 index 000000000..ce707da06 --- /dev/null +++ b/db/migrate/20221209021828_add_mailer_to_devise.rb @@ -0,0 +1,23 @@ +class AddMailerToDevise < ActiveRecord::Migration[7.0] + def change + change_table :users do |t| + # Trackable + t.integer :sign_in_count, default: 0, null: false + t.datetime :current_sign_in_at + t.datetime :last_sign_in_at + t.string :current_sign_in_ip + t.string :last_sign_in_ip + + # Confirmable + t.string :confirmation_token + t.datetime :confirmed_at + t.datetime :confirmation_sent_at + t.string :unconfirmed_email # Only if using reconfirmable + + # Lockable + t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts + t.string :unlock_token # Only if unlock strategy is :email or :both + t.datetime :locked_at + end + end +end diff --git a/db/schema.rb b/db/schema.rb index ca9b6f472..226122169 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,8 +10,8 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2022_11_20_175058) do - create_table "bikes", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| +ActiveRecord::Schema[7.0].define(version: 2022_12_09_021828) do + create_table "bikes", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "identifier" t.string "current_station_id" t.datetime "created_at", null: false @@ -21,7 +21,7 @@ t.index ["identifier"], name: "index_bikes_on_identifier", unique: true end - create_table "pay_charges", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + create_table "pay_charges", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "identifier", null: false t.bigint "customer_id", null: false t.bigint "subscription_id" @@ -30,64 +30,59 @@ t.string "currency" t.integer "application_fee_amount" t.integer "amount_refunded" - t.text "metadata", size: :long, collation: "utf8mb4_bin" - t.text "data", size: :long, collation: "utf8mb4_bin" + t.json "metadata" + t.json "data" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["customer_id", "processor_id"], name: "index_pay_charges_on_customer_id_and_processor_id", unique: true t.index ["identifier"], name: "index_pay_charges_on_identifier" t.index ["subscription_id"], name: "index_pay_charges_on_subscription_id" - t.check_constraint "json_valid(`data`)", name: "data" - t.check_constraint "json_valid(`metadata`)", name: "metadata" end - create_table "pay_customers", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + create_table "pay_customers", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "identifier", null: false t.string "owner_type" t.bigint "owner_id" t.string "processor", null: false t.string "processor_id" t.boolean "default" - t.text "data", size: :long, collation: "utf8mb4_bin" + t.json "data" t.datetime "deleted_at", precision: nil t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["identifier"], name: "index_pay_customers_on_identifier" t.index ["owner_type", "owner_id", "deleted_at", "default"], name: "pay_customer_owner_index" t.index ["processor", "processor_id"], name: "index_pay_customers_on_processor_and_processor_id", unique: true - t.check_constraint "json_valid(`data`)", name: "data" end - create_table "pay_merchants", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + create_table "pay_merchants", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "identifier", null: false t.string "owner_type" t.bigint "owner_id" t.string "processor", null: false t.string "processor_id" t.boolean "default" - t.text "data", size: :long, collation: "utf8mb4_bin" + t.json "data" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["identifier"], name: "index_pay_merchants_on_identifier" t.index ["owner_type", "owner_id", "processor"], name: "index_pay_merchants_on_owner_type_and_owner_id_and_processor" - t.check_constraint "json_valid(`data`)", name: "data" end - create_table "pay_payment_methods", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + create_table "pay_payment_methods", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "identifier", null: false t.bigint "customer_id", null: false t.string "processor_id", null: false t.boolean "default" t.string "type" - t.text "data", size: :long, collation: "utf8mb4_bin" + t.json "data" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["customer_id", "processor_id"], name: "index_pay_payment_methods_on_customer_id_and_processor_id", unique: true t.index ["identifier"], name: "index_pay_payment_methods_on_identifier" - t.check_constraint "json_valid(`data`)", name: "data" end - create_table "pay_subscriptions", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + create_table "pay_subscriptions", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "identifier", null: false t.bigint "customer_id", null: false t.string "name", null: false @@ -98,28 +93,25 @@ t.datetime "trial_ends_at", precision: nil t.datetime "ends_at", precision: nil t.decimal "application_fee_percent", precision: 8, scale: 2 - t.text "metadata", size: :long, collation: "utf8mb4_bin" - t.text "data", size: :long, collation: "utf8mb4_bin" + t.json "metadata" + t.json "data" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["customer_id", "processor_id"], name: "index_pay_subscriptions_on_customer_id_and_processor_id", unique: true t.index ["identifier"], name: "index_pay_subscriptions_on_identifier" - t.check_constraint "json_valid(`data`)", name: "data" - t.check_constraint "json_valid(`metadata`)", name: "metadata" end - create_table "pay_webhooks", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + create_table "pay_webhooks", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "identifier", null: false t.string "processor" t.string "event_type" - t.text "event", size: :long, collation: "utf8mb4_bin" + t.json "event" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["identifier"], name: "index_pay_webhooks_on_identifier" - t.check_constraint "json_valid(`event`)", name: "event" end - create_table "stations", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + create_table "stations", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "identifier" t.string "name" t.string "address" @@ -131,7 +123,7 @@ t.index ["identifier"], name: "index_stations_on_identifier", unique: true end - create_table "users", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + create_table "users", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false t.string "identifier", null: false @@ -142,6 +134,18 @@ t.datetime "remember_created_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.integer "sign_in_count", default: 0, null: false + t.datetime "current_sign_in_at" + t.datetime "last_sign_in_at" + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.string "confirmation_token" + t.datetime "confirmed_at" + t.datetime "confirmation_sent_at" + t.string "unconfirmed_email" + t.integer "failed_attempts", default: 0, null: false + t.string "unlock_token" + t.datetime "locked_at" t.index ["email"], name: "index_users_on_email", unique: true t.index ["identifier"], name: "index_users_on_identifier", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true