User Settings Step 1: Add user_settings and user_notification_settings tables (rfc#32) (#12768)
* feat: add the two new models users_setting and users_notification_setting * feat: add the settings and notification_settings table to the schema * feat: add the user and notification models * feat: add the user_id foreign key to the model * chore: sneaky indent * feat: add some fields from the profile attributes * Revert "feat: add some fields from the profile attributes" This reverts commit 376828746ded063a243505d317140fa5339227cf. * chore: add some profile field attributes * chore: remove language_settings * chore: update indent * chore: remove language_settings * feat: changes to the tables * chore: remove validation in favor of the foreign keys * chore: add default for editor version * Address PR review suggestions * setting_spec.rb needs to be fixed; need help * Working on PR review comments * Continue with addressing PR review comments * Remove normalize_config_values method; pass correct values from forms * Address Travis failures * revert some unnecessary changes in spec file Co-authored-by: Arit Amana <msarit@gmail.com>
This commit is contained in:
parent
d77b21b9b5
commit
4848a8b2e1
12 changed files with 247 additions and 8 deletions
|
|
@ -108,6 +108,8 @@ class User < ApplicationRecord
|
|||
acts_as_follower
|
||||
|
||||
has_one :profile, dependent: :destroy
|
||||
has_one :notification_setting, class_name: "Users::NotificationSetting", dependent: :destroy
|
||||
has_one :setting, class_name: "Users::Setting", dependent: :destroy
|
||||
|
||||
has_many :access_grants, class_name: "Doorkeeper::AccessGrant", foreign_key: :resource_owner_id,
|
||||
inverse_of: :resource_owner, dependent: :delete_all
|
||||
|
|
|
|||
14
app/models/users/notification_setting.rb
Normal file
14
app/models/users/notification_setting.rb
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
module Users
|
||||
class NotificationSetting < ApplicationRecord
|
||||
self.table_name_prefix = "users_"
|
||||
validates :email_digest_periodic, inclusion: { in: [true, false] }
|
||||
|
||||
alias_attribute :subscribed_to_welcome_notifications?, :welcome_notifications
|
||||
alias_attribute :subscribed_to_mod_roundrobin_notifications?, :mod_roundrobin_notifications
|
||||
alias_attribute :subscribed_to_email_follower_notifications?, :email_follower_notifications
|
||||
|
||||
# NOTE: @ridhwana Need to account for
|
||||
# subscribe_to_mailchimp_newsletter in app/models/user.rb
|
||||
# code: return unless saved_changes.key?(:email) || saved_changes.key?(:email_newsletter)
|
||||
end
|
||||
end
|
||||
33
app/models/users/setting.rb
Normal file
33
app/models/users/setting.rb
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
module Users
|
||||
class Setting < ApplicationRecord
|
||||
self.table_name_prefix = "users_"
|
||||
|
||||
belongs_to :user
|
||||
|
||||
enum editor_version: { v2: 0, v1: 1 }, _suffix: :editor
|
||||
enum config_font: { default: 0, comic_sans: 1, monospace: 2, open_dyslexic: 3, sans_serif: 4, serif: 5 }
|
||||
enum inbox_type: { private: 0, open: 1 }, _suffix: :inbox
|
||||
enum config_navbar: { default_navbar: 0, static_navbar: 1 }
|
||||
enum config_theme: { default_theme: 0, minimal_light_theme: 1, night_theme: 2, pink_theme: 3,
|
||||
ten_x_hacker_theme: 4 }
|
||||
|
||||
validates :user_id, presence: true
|
||||
validates :experience_level, numericality: { less_than_or_equal_to: 10 }, allow_blank: true
|
||||
validates :feed_referential_link, inclusion: { in: [true, false] }
|
||||
validates :feed_url, length: { maximum: 500 }, allow_nil: true
|
||||
validates :inbox_guidelines, length: { maximum: 250 }, allow_nil: true
|
||||
validate :validate_feed_url, if: :feed_url_changed?
|
||||
|
||||
private
|
||||
|
||||
def validate_feed_url
|
||||
return if feed_url.blank?
|
||||
|
||||
valid = Feeds::ValidateUrl.call(feed_url)
|
||||
|
||||
errors.add(:feed_url, "is not a valid RSS/Atom feed") unless valid
|
||||
rescue StandardError => e
|
||||
errors.add(:feed_url, e.message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
<fieldset class="crayons-field">
|
||||
<legend class="crayons-field__label">Site Theme</legend>
|
||||
<div class="theme-selector-field grid gap-4 grid-cols-2 l:grid-cols-3">
|
||||
<% ["default", "night theme", "minimal light theme", "pink theme", "ten x hacker theme"].each do |theme| %>
|
||||
<% %w[default night_theme minimal_light_theme pink_theme ten_x_hacker_theme].each do |theme| %>
|
||||
<%= render partial: "theme_selector", locals: { f: f, theme: theme } %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<label class="rich-selector crayons-field crayons-field--radio navbar-selector--<%= navbar.tr(" ", "-") %>">
|
||||
<%= f.radio_button :config_navbar, navbar, checked: @user.config_navbar.tr("_", " ") == navbar, class: "crayons-radio" %>
|
||||
<label class="rich-selector crayons-field crayons-field--radio navbar-selector--<%= navbar %>">
|
||||
<%= f.radio_button :config_navbar, navbar, checked: @user.config_navbar == navbar, class: "crayons-radio" %>
|
||||
<div class="crayons-field__label">
|
||||
<% if navbar == "default" %>
|
||||
Fixed to window
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<label class="rich-selector crayons-field crayons-field--radio p-4 theme-selector theme-selector--<%= theme.tr(" ", "-") %>" title="<%= theme.titlecase %>">
|
||||
<%= f.radio_button :config_theme, theme, checked: @user.config_theme.tr("_", " ") == theme, class: "crayons-radio" %>
|
||||
<label class="rich-selector crayons-field crayons-field--radio p-4 theme-selector theme-selector--<%= theme.tr("_", "-") %>" title="<%= theme.titlecase %>">
|
||||
<%= f.radio_button :config_theme, theme, checked: @user.config_theme == theme, class: "crayons-radio" %>
|
||||
<div class="crayons-field__label">
|
||||
<%= theme.titlecase %>
|
||||
|
||||
|
|
|
|||
29
db/migrate/20210222102503_create_users_settings.rb
Normal file
29
db/migrate/20210222102503_create_users_settings.rb
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
class CreateUsersSettings < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
create_table :users_settings do |t|
|
||||
t.references :user, foreign_key: true, null: false
|
||||
|
||||
t.boolean "display_announcements", default: true, null: false
|
||||
t.boolean "display_sponsors", default: true, null: false
|
||||
|
||||
t.integer "editor_version", default: 0, null: false
|
||||
t.integer "config_font", default: 0, null: false
|
||||
t.integer "inbox_type", default: 0, null: false
|
||||
t.integer "config_navbar", default: 0, null: false
|
||||
t.integer "config_theme", default: 0, null: false
|
||||
|
||||
t.integer "experience_level"
|
||||
t.boolean "feed_mark_canonical", default: false, null: false
|
||||
t.boolean "feed_referential_link", default: true, null: false
|
||||
t.string "feed_url"
|
||||
t.string "inbox_guidelines"
|
||||
|
||||
t.boolean "permit_adjacent_sponsors", default: true
|
||||
t.string "brand_color1", default: "#000000"
|
||||
t.string "brand_color2", default: "#ffffff"
|
||||
t.boolean "display_email_on_profile", default: false, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
class CreateUsersNotificationSettings < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
create_table :users_notification_settings do |t|
|
||||
t.references :user, foreign_key: true, null: false
|
||||
t.boolean "email_badge_notifications", default: true, null: false
|
||||
t.boolean "email_comment_notifications", default: true, null: false
|
||||
t.boolean "email_community_mod_newsletter", default: false, null: false
|
||||
t.boolean "email_connect_messages", default: true, null: false
|
||||
t.boolean "email_digest_periodic", default: false, null: false
|
||||
t.boolean "email_follower_notifications", default: true, null: false
|
||||
t.boolean "email_membership_newsletter", default: false, null: false
|
||||
t.boolean "email_mention_notifications", default: true, null: false
|
||||
t.boolean "email_newsletter", default: false, null: false
|
||||
t.boolean "email_tag_mod_newsletter", default: false, null: false
|
||||
t.boolean "email_unread_notifications", default: true, null: false
|
||||
t.boolean "mobile_comment_notifications", default: true, null: false
|
||||
t.boolean "mod_roundrobin_notifications", default: true, null: false
|
||||
t.boolean "reaction_notifications", default: true, null: false
|
||||
t.boolean "welcome_notifications", default: true, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
53
db/schema.rb
53
db/schema.rb
|
|
@ -432,12 +432,12 @@ ActiveRecord::Schema.define(version: 2021_03_26_172406) do
|
|||
end
|
||||
|
||||
create_table "devices", force: :cascade do |t|
|
||||
t.bigint "user_id", null: false
|
||||
t.string "token", null: false
|
||||
t.string "platform", null: false
|
||||
t.string "app_bundle", null: false
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.string "platform", null: false
|
||||
t.string "token", null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
t.bigint "user_id", null: false
|
||||
t.index ["user_id", "token", "platform", "app_bundle"], name: "index_devices_on_user_id_and_token_and_platform_and_app_bundle", unique: true
|
||||
end
|
||||
|
||||
|
|
@ -1363,12 +1363,57 @@ ActiveRecord::Schema.define(version: 2021_03_26_172406) do
|
|||
t.string "username"
|
||||
end
|
||||
|
||||
create_table "users_notification_settings", force: :cascade do |t|
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.boolean "email_badge_notifications", default: true, null: false
|
||||
t.boolean "email_comment_notifications", default: true, null: false
|
||||
t.boolean "email_community_mod_newsletter", default: false, null: false
|
||||
t.boolean "email_connect_messages", default: true, null: false
|
||||
t.boolean "email_digest_periodic", default: false, null: false
|
||||
t.boolean "email_follower_notifications", default: true, null: false
|
||||
t.boolean "email_membership_newsletter", default: false, null: false
|
||||
t.boolean "email_mention_notifications", default: true, null: false
|
||||
t.boolean "email_newsletter", default: false, null: false
|
||||
t.boolean "email_tag_mod_newsletter", default: false, null: false
|
||||
t.boolean "email_unread_notifications", default: true, null: false
|
||||
t.boolean "mobile_comment_notifications", default: true, null: false
|
||||
t.boolean "mod_roundrobin_notifications", default: true, null: false
|
||||
t.boolean "reaction_notifications", default: true, null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
t.bigint "user_id", null: false
|
||||
t.boolean "welcome_notifications", default: true, null: false
|
||||
t.index ["user_id"], name: "index_users_notification_settings_on_user_id"
|
||||
end
|
||||
|
||||
create_table "users_roles", id: false, force: :cascade do |t|
|
||||
t.bigint "role_id"
|
||||
t.bigint "user_id"
|
||||
t.index ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id"
|
||||
end
|
||||
|
||||
create_table "users_settings", force: :cascade do |t|
|
||||
t.string "brand_color1", default: "#000000"
|
||||
t.string "brand_color2", default: "#ffffff"
|
||||
t.integer "config_font", default: 0, null: false
|
||||
t.integer "config_navbar", default: 0, null: false
|
||||
t.integer "config_theme", default: 0, null: false
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.boolean "display_announcements", default: true, null: false
|
||||
t.boolean "display_email_on_profile", default: false, null: false
|
||||
t.boolean "display_sponsors", default: true, null: false
|
||||
t.integer "editor_version", default: 0, null: false
|
||||
t.integer "experience_level"
|
||||
t.boolean "feed_mark_canonical", default: false, null: false
|
||||
t.boolean "feed_referential_link", default: true, null: false
|
||||
t.string "feed_url"
|
||||
t.string "inbox_guidelines"
|
||||
t.integer "inbox_type", default: 0, null: false
|
||||
t.boolean "permit_adjacent_sponsors", default: true
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
t.bigint "user_id", null: false
|
||||
t.index ["user_id"], name: "index_users_settings_on_user_id"
|
||||
end
|
||||
|
||||
create_table "users_suspended_usernames", primary_key: "username_hash", id: :string, force: :cascade do |t|
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
|
|
@ -1480,8 +1525,10 @@ ActiveRecord::Schema.define(version: 2021_03_26_172406) do
|
|||
add_foreign_key "user_blocks", "users", column: "blocker_id"
|
||||
add_foreign_key "user_subscriptions", "users", column: "author_id"
|
||||
add_foreign_key "user_subscriptions", "users", column: "subscriber_id"
|
||||
add_foreign_key "users_notification_settings", "users"
|
||||
add_foreign_key "users_roles", "roles", on_delete: :cascade
|
||||
add_foreign_key "users_roles", "users", on_delete: :cascade
|
||||
add_foreign_key "users_settings", "users"
|
||||
add_foreign_key "webhook_endpoints", "oauth_applications"
|
||||
add_foreign_key "webhook_endpoints", "users"
|
||||
end
|
||||
|
|
|
|||
15
spec/factories/users_setting.rb
Normal file
15
spec/factories/users_setting.rb
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
FactoryBot.define do
|
||||
factory :users_setting, class: "Users::Setting" do
|
||||
config_font { "sans_serif" }
|
||||
config_navbar { "default_navbar" }
|
||||
config_theme { "night_theme" }
|
||||
display_announcements { true }
|
||||
display_sponsors { true }
|
||||
editor_version { "v1" }
|
||||
experience_level { 1 }
|
||||
feed_mark_canonical { false }
|
||||
feed_referential_link { true }
|
||||
inbox_type { "private" }
|
||||
permit_adjacent_sponsors { true }
|
||||
end
|
||||
end
|
||||
|
|
@ -38,6 +38,8 @@ RSpec.describe User, type: :model do
|
|||
subject { user }
|
||||
|
||||
it { is_expected.to have_one(:profile).dependent(:destroy) }
|
||||
it { is_expected.to have_one(:notification_setting).dependent(:destroy) }
|
||||
it { is_expected.to have_one(:setting).dependent(:destroy) }
|
||||
|
||||
it { is_expected.to have_many(:access_grants).class_name("Doorkeeper::AccessGrant").dependent(:delete_all) }
|
||||
it { is_expected.to have_many(:access_tokens).class_name("Doorkeeper::AccessToken").dependent(:delete_all) }
|
||||
|
|
|
|||
73
spec/models/users/setting_spec.rb
Normal file
73
spec/models/users/setting_spec.rb
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
require "rails_helper"
|
||||
# rubocop:disable Layout/LineLength
|
||||
RSpec.describe Users::Setting, type: :model do
|
||||
describe "validations" do
|
||||
subject { setting }
|
||||
|
||||
let(:setting) { create(:users_setting, user: user) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
it { is_expected.to validate_length_of(:inbox_guidelines).is_at_most(250).allow_nil }
|
||||
it { is_expected.to define_enum_for(:inbox_type).with_values(private: 0, open: 1).with_suffix(:inbox) }
|
||||
it { is_expected.to define_enum_for(:config_font).with_values(default: 0, comic_sans: 1, monospace: 2, open_dyslexic: 3, sans_serif: 4, serif: 5) }
|
||||
it { is_expected.to define_enum_for(:config_navbar).with_values(default_navbar: 0, static_navbar: 1) }
|
||||
it { is_expected.to define_enum_for(:config_theme).with_values(default_theme: 0, minimal_light_theme: 1, night_theme: 2, pink_theme: 3, ten_x_hacker_theme: 4) }
|
||||
|
||||
describe "when validating feed_url", vcr: true do
|
||||
it "is valid with no feed_url" do
|
||||
setting.feed_url = nil
|
||||
|
||||
expect(setting).to be_valid
|
||||
end
|
||||
|
||||
it "is not valid with an invalid feed_url", vcr: { cassette_name: "feeds_validate_url_invalid" } do
|
||||
setting.feed_url = "http://example.com"
|
||||
|
||||
expect(setting).not_to be_valid
|
||||
end
|
||||
|
||||
it "is valid with a valid feed_url", vcr: { cassette_name: "feeds_import_medium_vaidehi" } do
|
||||
setting.feed_url = "https://medium.com/feed/@vaidehijoshi"
|
||||
|
||||
expect(setting).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe "#config_theme" do
|
||||
it "accepts valid theme" do
|
||||
setting.config_theme = 2
|
||||
expect(setting).to be_valid
|
||||
expect(setting.night_theme?).to be true
|
||||
end
|
||||
|
||||
it "does not accept invalid theme" do
|
||||
expect { setting.config_theme = 10 }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#config_font" do
|
||||
it "accepts valid font" do
|
||||
setting.config_font = 4
|
||||
expect(setting).to be_valid
|
||||
expect(setting.sans_serif?).to be true
|
||||
end
|
||||
|
||||
it "does not accept invalid font" do
|
||||
expect { setting.config_font = 10 }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#config_navbar" do
|
||||
it "accepts valid navbar" do
|
||||
setting.config_navbar = 1
|
||||
expect(setting).to be_valid
|
||||
expect(setting.static_navbar?).to be true
|
||||
end
|
||||
|
||||
it "does not accept invalid navbar" do
|
||||
expect { setting.config_navbar = 10 }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop:enable Layout/LineLength
|
||||
Loading…
Add table
Reference in a new issue