Merge pull request #769 from Ducz0r/lm-sci-1475

Refactor user settings into a jsonb field [SCI-1475]
This commit is contained in:
Luka Murn 2017-08-23 08:43:23 +02:00 committed by GitHub
commit 647c879c76
13 changed files with 132 additions and 33 deletions

View file

@ -87,6 +87,6 @@ class ApplicationController < ActionController::Base
end end
def set_time_zone(&block) def set_time_zone(&block)
Time.use_zone(current_user.time_zone, &block) Time.use_zone(current_user.settings[:time_zone], &block)
end end
end end

View file

@ -180,7 +180,7 @@ module Users
message: sanitize_input(message) message: sanitize_input(message)
) )
if target_user.assignments_notification if target_user.settings[:notifications][:assignments]
UserNotification.create(notification: notification, user: target_user) UserNotification.create(notification: notification, user: target_user)
end end
end end

View file

@ -77,15 +77,15 @@ module Users
end end
def notifications_settings def notifications_settings
@user.assignments_notification = @user.settings[:notifications][:assignments] =
params[:assignments_notification] ? true : false params[:assignments_notification] ? true : false
@user.recent_notification = @user.settings[:notifications][:recent] =
params[:recent_notification] ? true : false params[:recent_notification] ? true : false
@user.recent_notification_email = @user.settings[:notifications][:recent_email] =
params[:recent_notification_email] ? true : false params[:recent_notification_email] ? true : false
@user.assignments_notification_email = @user.settings[:notifications][:assignments_email] =
params[:assignments_notification_email] ? true : false params[:assignments_notification_email] ? true : false
@user.system_message_notification_email = @user.settings[:notifications][:system_message_email] =
params[:system_message_notification_email] ? true : false params[:system_message_notification_email] ? true : false
if @user.save if @user.save

View file

@ -100,7 +100,7 @@ module ApplicationHelper
title: sanitize_input(title), title: sanitize_input(title),
message: sanitize_input(message) message: sanitize_input(message)
) )
if target_user.assignments_notification if target_user.settings[:notifications][:assignments]
UserNotification.create(notification: notification, user: target_user) UserNotification.create(notification: notification, user: target_user)
end end
end end

View file

@ -44,7 +44,7 @@ module NotificationsHelper
message: sanitize_input(message) message: sanitize_input(message)
) )
if target_user.assignments_notification if target_user.settings[:notifications][:assignments]
UserNotification.create(notification: notification, user: target_user) UserNotification.create(notification: notification, user: target_user)
end end
end end

View file

@ -118,9 +118,9 @@ class Activity < ApplicationRecord
project.users.each do |project_user| project.users.each do |project_user|
next if project_user == user next if project_user == user
next if !project_user.assignments_notification && next if !project_user.settings[:notifications][:assignments] &&
notification.type_of == 'assignment' notification.type_of == 'assignment'
next if !project_user.recent_notification && next if !project_user.settings[:notifications][:recent] &&
notification.type_of == 'recent_changes' notification.type_of == 'recent_changes'
UserNotification.create(notification: notification, user: project_user) UserNotification.create(notification: notification, user: project_user)
end end

View file

@ -0,0 +1,22 @@
module SettingsModel
extend ActiveSupport::Concern
@@default_settings = HashWithIndifferentAccess.new
included do
serialize :settings, JsonbHashSerializer
after_initialize :init_default_settings, if: :new_record?
end
class_methods do
def default_settings(dfs)
@@default_settings.merge!(dfs)
end
end
protected
def init_default_settings
self.settings = @@default_settings
end
end

View file

@ -1,5 +1,6 @@
class User < ApplicationRecord class User < ApplicationRecord
include SearchableModel include SearchableModel
include SettingsModel
acts_as_token_authenticatable acts_as_token_authenticatable
devise :invitable, :confirmable, :database_authenticatable, :registerable, devise :invitable, :confirmable, :database_authenticatable, :registerable,
@ -33,9 +34,21 @@ class User < ApplicationRecord
validates_attachment :avatar, validates_attachment :avatar,
:content_type => { :content_type => ["image/jpeg", "image/png"] }, :content_type => { :content_type => ["image/jpeg", "image/png"] },
size: { less_than: Constants::AVATAR_MAX_SIZE_MB.megabytes } size: { less_than: Constants::AVATAR_MAX_SIZE_MB.megabytes }
validates :time_zone, presence: true
validate :time_zone_check validate :time_zone_check
store_accessor :settings, :time_zone
default_settings(
time_zone: 'UTC',
notifications: {
assignments: true,
assignments_email: false,
recent: true,
recent_email: false,
system_message_email: false
}
)
# Relations # Relations
has_many :user_teams, inverse_of: :user has_many :user_teams, inverse_of: :user
has_many :teams, through: :user_teams has_many :teams, through: :user_teams
@ -384,7 +397,8 @@ class User < ApplicationRecord
end end
def time_zone_check def time_zone_check
if time_zone.nil? or ActiveSupport::TimeZone.new(time_zone).nil? if time_zone.nil? ||
ActiveSupport::TimeZone.new(time_zone).nil?
errors.add(:time_zone) errors.add(:time_zone)
end end
end end

View file

@ -40,17 +40,17 @@ class UserNotification < ApplicationRecord
send_email_notification( send_email_notification(
user, user,
notification notification
) if user.system_message_notification_email ) if user.settings[:notifications][:system_message_email]
when 'assignment' when 'assignment'
send_email_notification( send_email_notification(
user, user,
notification notification
) if user.assignments_notification_email ) if user.settings[:notifications][:assignments_email]
when 'recent_changes' when 'recent_changes'
send_email_notification( send_email_notification(
user, user,
notification notification
) if user.recent_notification_email ) if user.settings[:notifications][:recent_email]
when 'deliver' when 'deliver'
send_email_notification( send_email_notification(
user, user,

View file

@ -0,0 +1,11 @@
class JsonbHashSerializer
def self.dump(hash)
hash.to_json
end
def self.load(hash)
hash ||= {}
hash = JSON.parse(hash) if hash.instance_of? String
hash.with_indifferent_access
end
end

View file

@ -12,7 +12,11 @@
<%= form_for(@user, <%= form_for(@user,
url: update_preferences_path(format: :json), url: update_preferences_path(format: :json),
remote: true, remote: true,
html: { method: :put, 'data-for' => 'time_zone' }) do |f| %> html: {
method: :put,
'data-for' => 'settings[time_zone]',
'data-turbolinks' => false
}) do |f| %>
<div data-part="view"> <div data-part="view">
<div class="form-group"> <div class="form-group">
<%= f.label t("users.settings.account.preferences.edit.time_zone_label") %> <%= f.label t("users.settings.account.preferences.edit.time_zone_label") %>
@ -21,9 +25,9 @@
disabled="disabled" disabled="disabled"
autocomplete="off" autocomplete="off"
type="text" type="text"
value="<%= @user.time_zone %>" value="<%= @user.settings[:time_zone] %>"
name="fake_user[time_zone]" name="fake_user[settings][time_zone]"
id="fake_user_time_zone"> id="fake_user_settings_time_zone">
<span class="input-group-btn"> <span class="input-group-btn">
<a href="#" class="btn btn-default" data-action="edit"><%=t "general.edit" %></a> <a href="#" class="btn btn-default" data-action="edit"><%=t "general.edit" %></a>
</span> </span>
@ -35,7 +39,7 @@
<div class="well"> <div class="well">
<h4><%=t "users.settings.account.preferences.edit.time_zone_title" %></h4> <h4><%=t "users.settings.account.preferences.edit.time_zone_title" %></h4>
<div class="form-group" style="max-width: 500px;"> <div class="form-group" style="max-width: 500px;">
<%= f.select :time_zone, ActiveSupport::TimeZone.all.collect { |tz| <%= f.select :time_zone , ActiveSupport::TimeZone.all.collect { |tz|
[tz.formatted_offset + " " + tz.name, tz.name] [tz.formatted_offset + " " + tz.name, tz.name]
}, {}, {class: 'form-control selectpicker', 'ata-role' => 'clear'} %> }, {}, {class: 'form-control selectpicker', 'ata-role' => 'clear'} %>
<small><%= t("users.settings.account.preferences.edit.time_zone_sublabel") %></small> <small><%= t("users.settings.account.preferences.edit.time_zone_sublabel") %></small>
@ -75,7 +79,7 @@
<%=t 'notifications.form.notification_scinote' %> <%=t 'notifications.form.notification_scinote' %>
</div> </div>
<div class="col-sm-8"> <div class="col-sm-8">
<%= check_box_tag :assignments_notification, @user.assignments_notification %> <%= check_box_tag :assignments_notification, @user.settings[:notifications][:assignments] %>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -83,7 +87,7 @@
<%=t 'notifications.form.notification_email' %> <%=t 'notifications.form.notification_email' %>
</div> </div>
<div class="col-sm-8"> <div class="col-sm-8">
<%= check_box_tag :assignments_notification_email, @user.assignments_notification_email %> <%= check_box_tag :assignments_notification_email, @user.settings[:notifications][:assignments_email] %>
</div> </div>
</div> </div>
</div> </div>
@ -100,7 +104,7 @@
<%=t 'notifications.form.notification_scinote' %> <%=t 'notifications.form.notification_scinote' %>
</div> </div>
<div class="col-sm-8"> <div class="col-sm-8">
<%= check_box_tag :recent_notification, @user.recent_notification %> <%= check_box_tag :recent_notification, @user.settings[:notifications][:recent] %>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -108,7 +112,7 @@
<%=t 'notifications.form.notification_email' %> <%=t 'notifications.form.notification_email' %>
</div> </div>
<div class="col-sm-8"> <div class="col-sm-8">
<%= check_box_tag :recent_notification_email, @user.recent_notification_email %> <%= check_box_tag :recent_notification_email, @user.settings[:notifications][:recent_email] %>
</div> </div>
</div> </div>
</div> </div>
@ -133,7 +137,7 @@
<%=t 'notifications.form.notification_email' %> <%=t 'notifications.form.notification_email' %>
</div> </div>
<div class="col-sm-8"> <div class="col-sm-8">
<%= check_box_tag :system_message_notification_email, @user.system_message_notification_email %> <%= check_box_tag :system_message_notification_email, @user.settings[:notifications][:system_message_email] %>
</div> </div>
</div> </div>
</div> </div>

View file

@ -0,0 +1,53 @@
class RefactorUserSettings < ActiveRecord::Migration[5.1]
def up
add_column :users, :settings, :jsonb, default: {}, null: false
User.find_each do |user|
settings = {
time_zone: user['time_zone'],
notifications: {
assignments: user['assignments_notification'],
assignments_email: user['assignments_notification_email'],
recent: user['recent_notification'],
recent_email: user['recent_notification_email'],
system_message_email: user['system_message_notification_email']
}
}
user.update(settings: settings)
end
remove_column :users, :time_zone, :string
remove_column :users, :assignments_notification, :boolean
remove_column :users, :assignments_notification_email, :boolean
remove_column :users, :recent_notification, :boolean
remove_column :users, :recent_notification_email, :boolean
remove_column :users, :system_message_notification_email, :boolean
end
def down
add_column :users, :time_zone, :string, default: false
add_column :users, :assignments_notification, :boolean, default: false
add_column :users, :assignments_notification_email, :boolean, default: false
add_column :users, :recent_notification, :boolean, default: false
add_column :users, :recent_notification_email, :boolean, default: false
add_column :users,
:system_message_notification_email, :boolean, default: false
User.find_each do |user|
user.time_zone = user.settings[:time_zone]
user.assignments_notification =
user.settings[:notifications][:assignments]
user.assignments_notification_email =
user.settings[:notifications][:assignments_email]
user.recent_notification =
user.settings[:notifications][:recent]
user.recent_notification_email =
user.settings[:notifications][:recent_email]
user.system_message_notification_email =
user.settings[:notifications][:system_message_email]
user.save
end
remove_column :users, :settings, :jsonb
end
end

View file

@ -28,7 +28,6 @@ describe User, type: :model do
it { should have_db_column :confirmed_at } it { should have_db_column :confirmed_at }
it { should have_db_column :confirmation_sent_at } it { should have_db_column :confirmation_sent_at }
it { should have_db_column :unconfirmed_email } it { should have_db_column :unconfirmed_email }
it { should have_db_column :time_zone }
it { should have_db_column :invitation_token } it { should have_db_column :invitation_token }
it { should have_db_column :invitation_created_at } it { should have_db_column :invitation_created_at }
it { should have_db_column :invitation_sent_at } it { should have_db_column :invitation_sent_at }
@ -38,12 +37,8 @@ describe User, type: :model do
it { should have_db_column :invited_by_type } it { should have_db_column :invited_by_type }
it { should have_db_column :invitations_count } it { should have_db_column :invitations_count }
it { should have_db_column :tutorial_status } it { should have_db_column :tutorial_status }
it { should have_db_column :assignments_notification } it { should have_db_column :settings }
it { should have_db_column :recent_notification }
it { should have_db_column :assignments_notification_email }
it { should have_db_column :recent_notification_email }
it { should have_db_column :current_team_id } it { should have_db_column :current_team_id }
it { should have_db_column :system_message_notification_email }
it { should have_db_column :authentication_token } it { should have_db_column :authentication_token }
end end
@ -115,7 +110,7 @@ describe User, type: :model do
it { should validate_presence_of :full_name } it { should validate_presence_of :full_name }
it { should validate_presence_of :initials } it { should validate_presence_of :initials }
it { should validate_presence_of :email } it { should validate_presence_of :email }
it { should validate_presence_of :time_zone } it { should validate_presence_of :settings }
it do it do
should validate_length_of(:full_name).is_at_most( should validate_length_of(:full_name).is_at_most(