Skip to content

Commit

Permalink
project preferences refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
mjy committed Jan 15, 2019
1 parent 377df0d commit d2fccd3
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 73 deletions.
2 changes: 1 addition & 1 deletion app/controllers/projects_controller.rb
Expand Up @@ -131,7 +131,7 @@ def set_project

# Never trust parameters from the scary internet, only allow the white list through.
def project_params
params.require(:project).permit(:name)
params.require(:project).permit(:name, Project.key_value_preferences, Project.array_preferences, Project.hash_preferences)
end

def go_to
Expand Down
63 changes: 24 additions & 39 deletions app/models/project.rb
Expand Up @@ -14,42 +14,14 @@ class Project < ApplicationRecord
include Housekeeping::Users
include Housekeeping::Timestamps
include Housekeeping::AssociationHelpers
include Project::Preferences

PREFERENCES = [
:workbench_starting_path, # like '/hub'
:is_api_accessible # Boolean, whether the read-only api is open
]

DEFAULT_WORKBENCH_STARTING_PATH = '/hub'.freeze
DEFAULT_WORKBENCH_SETTINGS = {
'workbench_starting_path' => DEFAULT_WORKBENCH_STARTING_PATH
}.freeze

store :preferences, accessors: PREFERENCES, coder: JSON
attr_accessor :without_root_taxon_name

has_many :project_members, dependent: :restrict_with_error
has_many :users, through: :project_members
has_many :project_sources, dependent: :restrict_with_error
has_many :sources, through: :project_sources

after_initialize :set_default_preferences
after_create :create_root_taxon_name, unless: -> {self.without_root_taxon_name == true}

validates_presence_of :name
validates_uniqueness_of :name

def clear_preferences
update_column(:preferences, DEFAULT_WORKBENCH_SETTINGS)
end

# !! This is not production ready.
# @return [Boolean]
# based on whether the project has successfully been deleted. Can also raise on detected problems with configuration.
def nuke
known = ApplicationRecord.subclasses.select {|a| a.column_names.include?('project_id')}.map(&:name)

order = %w{
# ORDER MATTERS
# Used in nuke order (not available in production UI), but
# ultimately also for dumping records
MANIFEST = %w{
Label
Attribution
DwcOccurrence
Expand Down Expand Up @@ -117,16 +89,33 @@ def nuke
Descriptor
ProjectMember
}

has_many :project_members, dependent: :restrict_with_error
has_many :users, through: :project_members
has_many :project_sources, dependent: :restrict_with_error
has_many :sources, through: :project_sources


after_create :create_root_taxon_name, unless: -> {self.without_root_taxon_name == true}

validates_presence_of :name
validates_uniqueness_of :name

# !! This is not production ready.
# @return [Boolean]
# based on whether the project has successfully been deleted. Can also raise on detected problems with configuration.
def nuke
known = ApplicationRecord.subclasses.select {|a| a.column_names.include?('project_id')}.map(&:name)

known.each do |k|
next if k.constantize.table_name == 'test_classes' # TODO: a kludge to ignore stubbed classes in testing
if !order.include?(k)
if !MANIFEST.include?(k)
raise "#{k} has not been added to #nuke order."
end
end

begin
order.each do |o|
MANIFEST.each do |o|
klass = o.constantize
klass.where(project_id: id).delete_all
end
Expand Down Expand Up @@ -158,10 +147,6 @@ def self.find_for_autocomplete(params)

protected

def set_default_preferences
write_attribute(:preferences, DEFAULT_WORKBENCH_SETTINGS.merge(preferences ||= {}) )
end

def create_root_taxon_name
p = Protonym.stub_root(project_id: id, by: creator)
p.save!
Expand Down
62 changes: 62 additions & 0 deletions app/models/project/preferences.rb
@@ -0,0 +1,62 @@
class Project
module Preferences

# DEFAULT_WORKBENCH_STARTING_PATH = '/hub'.freeze
# DEFAULT_WORKBENCH_SETTINGS = {
# 'workbench_starting_path' => DEFAULT_WORKBENCH_STARTING_PATH
# }.freeze

BASE_PREFERENCES = YAML.load_file(Rails.root + 'config/preferences/project.yml')

Project.class_eval do
store :preferences, accessors: BASE_PREFERENCES.symbolize_keys.keys, coder: JSON
before_save :fill_preferences

# after_initialize :set_default_preferences

def self.hash_preferences
Project::BASE_PREFERENCES.select{|k, v| Project::BASE_PREFERENCES[k].kind_of?(Hash)}.keys.inject({}){|hsh,k| hsh.merge!(k.to_sym => {})}
end

def self.array_preferences
Project::BASE_PREFERENCES.select{|k, v| Project::BASE_PREFERENCES[k].kind_of?(Array)}.keys.inject({}){|hsh,k| hsh.merge!(k.to_sym => [])}
end

def self.key_value_preferences
Project::BASE_PREFERENCES.symbolize_keys.keys.select{|k| Project::BASE_PREFERENCES[k] != {} && Project::BASE_PREFERENCES[k] != []}
end
end



def fill_preferences
if preferences.empty?
reset_preferences
else
BASE_PREFERENCES.keys.each do |k|
preferences[k] = BASE_PREFERENCES[k] if send(k).nil?
end
end
true
end

def reset_preferences
write_attribute(:preferences, BASE_PREFERENCES)
end

def layout=(values)
l = layout.nil? ? {} : layout
super(l.merge(values))
end

# def set_default_preferences
# write_attribute(:preferences, DEFAULT_WORKBENCH_SETTINGS.merge(preferences ||= {}) )
# end

# def clear_preferences
# update_column(:preferences, DEFAULT_WORKBENCH_SETTINGS)
# end


end
end
20 changes: 20 additions & 0 deletions config/preferences/project.yml
@@ -0,0 +1,20 @@
# !! YOU MUST RESTART THE SERVER FOR CHANGES HERE TO TAKE AFFECT !!
#
# This is the default project preference set.
#
# * Values of `nil` should be avoided!
#
---

workbench_starting_path: '/hub'
is_api_accessible: false
layout: { } # element_set_id: { element_id: position }
model_predicate_sets:
- Otu: []
- AssertedDistribution: []
- CollectionObject: []
- CollectingEvent: []
default_hub_tab_order: # not ported
- tasks
- data
- favorite
71 changes: 71 additions & 0 deletions spec/models/project/preferences_spec.rb
@@ -0,0 +1,71 @@
require 'rails_helper'

describe Project, type: :model, group: [:project] do

let(:project) { Project.new(name: 'I prefer this project') }

context 'project.yml' do
context 'accessors exist for' do
Project::BASE_PREFERENCES.keys.each do |k|
specify "#{k}" do
expect(project.respond_to?(k)).to be_truthy
end
end
end
end

context 'hashed keys' do
specify '.hash_preferences' do
expect(Project.hash_preferences).to include(layout: {})
end

specify '.array_preferences' do
expect(Project.array_preferences).to include(default_hub_tab_order: [])
end

specify '.key_value_preferences' do
expect(Project.key_value_preferences).to include(:model_predicate_sets) # etc.
end
end

specify 'filled preferences are not over-written' do
project.is_api_accessible = true
project.save!
expect(project.is_api_accessible).to eq(true)
end

specify 'unfilled preferences are filled' do
project.save!
expect(project.is_api_accessible).to eq(false)
end

specify '#reset_preferences' do
project.reset_preferences
expect(project.preferences).to eq(Project::BASE_PREFERENCES)
end

context 'with one layout set' do
before do
project.layout = { foo: {'firstid' => 1, 'secondid' => 2}}
project.save!
end

specify 'updating another layout' do
project.layout = {bar: {'second_id' => 1}}
expect(project.layout.keys).to contain_exactly('foo', 'bar')
end
end

specify '#workbench_starting_path 1' do
project.save!
expect(project.workbench_starting_path).to eq('/hub')
end

specify '#workbench_starting_path 1' do
project.workbench_starting_path = '/dashboard'
project.save!
expect(project.workbench_starting_path).to eq('/dashboard')
end


end
33 changes: 0 additions & 33 deletions spec/models/project_spec.rb
Expand Up @@ -113,39 +113,6 @@
end
end

context 'preferences' do
before(:each) {
project.name = 'Preferences'
project.save!
}

specify 'are set to default' do
expect(project.preferences).to eq(Project::DEFAULT_WORKBENCH_SETTINGS)
end

specify 'can be cleared with #clear_preferences' do
project.clear_preferences
expect(project.preferences).to eq(Project::DEFAULT_WORKBENCH_SETTINGS)
end

specify 'default_path defaults to DEFAULT_WORKBENCH_STARTING_PATH 1' do
expect(project.workbench_starting_path).to eq(Project::DEFAULT_WORKBENCH_STARTING_PATH)
end

specify 'default_path defaults to DEFAULT_WORKBENCH_STARTING_PATH 2' do
expect(project.preferences['workbench_starting_path']).to eq(Project::DEFAULT_WORKBENCH_STARTING_PATH)
end

specify 'updating an attribute is a little tricky, use _will_change!' do
expect(project.workbench_starting_path).to eq(Project::DEFAULT_WORKBENCH_STARTING_PATH)
expect(project.preferences).to eq({'workbench_starting_path' => '/hub'}) # was changed from nil

expect(project.workbench_starting_path = '/dashboard').to be_truthy
expect(project.save!).to be_truthy
expect(project.workbench_starting_path).to eq('/dashboard')
end
end

context 'root taxon name' do
before(:each) {
project.name = 'Root taxon name'
Expand Down

0 comments on commit d2fccd3

Please sign in to comment.