Skip to content

Commit

Permalink
Feature/settings (SpinaCMS#288)
Browse files Browse the repository at this point in the history
* WIP plugin settings

* Allow default values

* Add plugin level tests

* Add controller tests

* Merge in latest upstream master

* Add test for default values

* Change find_by_name to more generic find_by

* Clean up a little bit
  • Loading branch information
simmerz authored and Bramjetten committed Aug 2, 2017
1 parent 388cbb5 commit 29638c3
Show file tree
Hide file tree
Showing 19 changed files with 257 additions and 17 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ group :development, :test do
gem 'codeclimate-test-reporter', '~> 1.0.0'
gem 'letter_opener'
gem 'pry-rails'
gem 'mocha'
end
15 changes: 12 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
PATH
remote: .
specs:
spina (0.11.1)
spina (0.12.0)
ancestry
bcrypt
breadcrumbs_on_rails
carrierwave
coffee-rails
globalize (~> 5.1.0.beta1)
globalize (~> 5.1.0.beta2)
haml-rails
jquery-fileupload-rails
jquery-rails
jsonb_accessor (~> 1.0.0.beta.6)
kaminari
mini_magick
rack-rewrite (~> 1.5.0)
Expand Down Expand Up @@ -119,6 +120,10 @@ GEM
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (2.1.0)
jsonb_accessor (1.0.0.beta.6)
activerecord (>= 5.0)
activesupport (>= 5.0)
pg (>= 0.18.1)
kaminari (1.0.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.0.1)
Expand All @@ -139,6 +144,7 @@ GEM
nokogiri (>= 1.5.9)
mail (2.6.6)
mime-types (>= 1.16, < 4)
metaclass (0.0.4)
method_source (0.8.2)
mime-types (3.1)
mime-types-data (~> 3.2015)
Expand All @@ -151,6 +157,8 @@ GEM
builder
minitest (>= 5.0)
ruby-progressbar
mocha (1.2.1)
metaclass (~> 0.0.1)
nio4r (2.1.0)
nokogiri (1.8.0)
mini_portile2 (~> 2.2.0)
Expand Down Expand Up @@ -247,11 +255,12 @@ DEPENDENCIES
factory_girl (~> 4.0)
letter_opener
minitest-reporters
mocha
pg
pry-rails
rails-controller-testing
simplecov
spina!

BUNDLED WITH
1.15.0
1.15.3
56 changes: 56 additions & 0 deletions app/controllers/spina/admin/settings_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
module Spina
module Admin
class SettingsController < AdminController

before_action :find_or_set_settings
before_action :set_breadcrumbs

def edit
add_breadcrumb t("spina.#{plugin.namespace}.title")
end

def update
if @setting.update_attributes(settings_params)
redirect_to spina.admin_edit_settings_path(plugin.namespace)
else
add_breadcrumb t("spina.#{plugin.namespace}.title")
render :edit
end
end

private

def setting_class
"spina/#{plugin.namespace}/setting".classify.constantize
end

def plugin
Spina::Plugin.find_by(namespace: params[:plugin])
end
helper_method :plugin

def find_or_set_settings
@setting = setting_class.first_or_create do |setting|
plugin.settings.each do |attribute, type|
setting.send("#{attribute}=", (type.is_a?(Hash) ? type.first.last : nil))
end
end
plugin.settings.keys.reject do |x|
@setting.preferences.keys.map(&:to_sym).include? x
end.each do |key|
value = plugin.settings[key].is_a?(Hash) ? plugin.settings[key].first.last : nil
@setting.send("#{key}=", value)
end
end

def set_breadcrumbs
add_breadcrumb t('spina.settings.title')
end

def settings_params
params.require(:setting).permit(plugin.settings.keys)
end

end
end
end
7 changes: 7 additions & 0 deletions app/models/spina/setting.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module Spina
class Setting < ApplicationRecord

validates :plugin, presence: true

end
end
4 changes: 4 additions & 0 deletions app/views/spina/admin/settings/_string_field.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.horizontal-form-label
= f.label attribute, t("spina.#{plugin.namespace}.settings.#{attribute}")
.horizontal-form-content
= f.text_field attribute, placeholder: t("spina.#{plugin.namespace}.settings.#{attribute}_placeholder")
4 changes: 4 additions & 0 deletions app/views/spina/admin/settings/_wysiwyg_field.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.horizontal-form-label
= f.label attribute, t("spina.#{plugin.namespace}.settings.#{attribute}")
.horizontal-form-content
= render 'spina/admin/shared/rich_text_field', f: f, field: attribute
13 changes: 13 additions & 0 deletions app/views/spina/admin/settings/edit.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
= form_for @setting, url: admin_settings_path do |f|
%header#header
= render partial: 'spina/admin/shared/breadcrumbs'

#header_actions
%button.button.button-primary{type: 'submit'}
= icon('check')
= t('spina.settings.save')

.well
.horizontal-form
- plugin.settings.each do |key, value|
.horizontal-form-group= render "#{value.is_a?(Hash) ? value.first.first : value}_field", f: f, attribute: key
3 changes: 3 additions & 0 deletions app/views/spina/admin/shared/_primary_navigation.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
- if current_theme.plugins.include? plugin.name
- if lookup_context.exists? "spina/admin/hooks/#{ plugin.namespace }/_settings_secondary_navigation"
= render "spina/admin/hooks/#{ plugin.namespace }/settings_secondary_navigation", plugin: plugin
- if plugin.settings.present?
%li{class: ('active' if controller_name == 'settings' and params[:plugin] == plugin.namespace)}
= link_to t("spina.#{plugin.namespace}.title"), spina.admin_edit_settings_path(plugin.namespace)

%li
= link_to '#', class: 'back-to-main-menu' do
Expand Down
4 changes: 4 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ en:
logout: Logout
main_menu: Main menu

settings:
title: Settings
save: Save Settings

forgot_password:
new: Forgot password
request: Request new password
Expand Down
5 changes: 4 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
end
end

get "/settings/:plugin", to: "settings#edit", as: :edit_settings
patch "/settings/:plugin", to: "settings#update", as: :settings

resources :users

# Sessions
Expand Down Expand Up @@ -44,7 +47,7 @@

resources :photos do
collection do
get 'trix_select/:object_id' => 'photos#trix_select', as: :trix_select
get 'trix_select/:object_id' => 'photos#trix_select', as: :trix_select
post 'trix_insert/:object_id' => 'photos#trix_insert', as: :trix_insert
get 'photo_select/:page_part_id' => 'photos#photo_select', as: :photo_select
get 'photo_collection_select/:page_part_id' => 'photos#photo_collection_select', as: :photo_collection_select
Expand Down
11 changes: 11 additions & 0 deletions db/migrate/7_create_spina_settings.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class CreateSpinaSettings < ActiveRecord::Migration[5.0]
def change
create_table :spina_settings do |t|
t.string :plugin
t.jsonb :preferences, default: {}
t.timestamps
end

add_index :spina_settings, :plugin
end
end
2 changes: 1 addition & 1 deletion lib/spina/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
require 'kaminari'
require 'globalize'
require 'rack-rewrite'
require 'jsonb_accessor'

module Spina
class Engine < ::Rails::Engine
Expand All @@ -29,6 +30,5 @@ class Engine < ::Rails::Engine
# Load helpers from main application
Spina::ApplicationController.helper Rails.application.helpers
end

end
end
51 changes: 48 additions & 3 deletions lib/spina/plugin.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,68 @@
module Spina
class Plugin

attr_accessor :name, :namespace
attr_accessor :name, :namespace, :settings

def create_setting_class!
class_settings = data_mapped_settings_hash
plugin_name = namespace

klass = Class.new(::Spina::Setting) do
jsonb_accessor :preferences, class_settings

default_scope { where(plugin: "#{plugin_name}") }
end
"Spina::#{namespace_class}".constantize.const_set 'Setting', klass
end

private

def map_data_type(type)
type = type.is_a?(Hash) ? type.first.first : type
case type
when :wysiwyg then :text
else type
end
end

def namespace_class
namespace.split('_').map{|part| part.camelize}.join
end

def data_mapped_settings_hash
hash = Hash.new
settings.each do |key, value|
hash[key] = map_data_type(value)
end
hash
end

class << self

def all
::Spina::PLUGINS
end

def find_by_name(name)
all.find { |plugin| plugin.name == name }
def find_by(opts={})
all.find do |plugin|
matches = true
opts.each do |key, value|
matches = false unless plugin.send(key) == value
end
plugin if matches
end
end

def register
plugin = new
yield plugin
raise 'Missing plugin name' if plugin.name.nil?
raise 'Missing plugin namespace' if plugin.namespace.nil?

if plugin.settings.present?
plugin.create_setting_class!
end

all << plugin
plugin
end
Expand Down
1 change: 1 addition & 0 deletions spina.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Gem::Specification.new do |s|
s.add_dependency 'kaminari'
s.add_dependency 'globalize', '~> 5.1.0.beta2'
s.add_dependency 'rack-rewrite', '~> 1.5.0'
s.add_dependency 'jsonb_accessor', '~> 1.0.0.beta.6'

s.add_development_dependency 'factory_girl', '~> 4.0'
end
Empty file added test/dummy/db/migrate/.keep
Empty file.
17 changes: 9 additions & 8 deletions test/dummy/db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20170724115131) do
ActiveRecord::Schema.define(version: 7) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand Down Expand Up @@ -68,7 +68,6 @@
end

create_table "spina_lines", force: :cascade do |t|
t.string "content"
t.datetime "created_at"
t.datetime "updated_at"
end
Expand Down Expand Up @@ -124,24 +123,19 @@
end

create_table "spina_pages", force: :cascade do |t|
t.string "title"
t.string "menu_title"
t.string "description"
t.boolean "show_in_menu", default: true
t.string "slug"
t.boolean "deletable", default: true
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
t.string "seo_title"
t.boolean "skip_to_first_child", default: false
t.string "view_template"
t.string "layout_template"
t.boolean "draft", default: false
t.string "link_url"
t.string "ancestry"
t.integer "position"
t.string "materialized_path"
t.boolean "active", default: true
end

Expand Down Expand Up @@ -169,6 +163,14 @@
t.datetime "updated_at"
end

create_table "spina_settings", force: :cascade do |t|
t.string "plugin"
t.jsonb "preferences", default: {}
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["plugin"], name: "index_spina_settings_on_plugin", using: :btree
end

create_table "spina_structure_items", force: :cascade do |t|
t.integer "structure_id"
t.integer "position"
Expand Down Expand Up @@ -205,7 +207,6 @@
end

create_table "spina_texts", force: :cascade do |t|
t.text "content"
t.datetime "created_at"
t.datetime "updated_at"
end
Expand Down
29 changes: 29 additions & 0 deletions test/functional/spina/admin/settings_controller_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require 'test_helper'

module Spina
module Admin
class SettingsControllerTest < ActionController::TestCase
setup do
@routes = ::Spina::Engine.routes
@account = FactoryGirl.create :account
@user = FactoryGirl.create :user
@plugin = ::Spina::Plugin.find_by(namespace: 'spina_test')
@controller.stubs(:current_spina_user).returns(@user)
end

test 'editing produces the correct forms' do
get :edit, params: { plugin: 'spina_test' }
assert_template :edit
assert assigns(:setting).is_a?(Spina::SpinaTest::Setting)
assert assigns(:setting).test_setting == '<div></div>'
end

test 'updating updates the settings' do
patch :update, params: { plugin: 'spina_test', setting: { foobar: 'baz' } }

assert Spina::SpinaTest::Setting.first.foobar == 'baz'
end

end
end
end
Loading

0 comments on commit 29638c3

Please sign in to comment.