alchemy_cms 3.1.0.beta5 → 3.1.0.beta6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +23 -0
  3. data/app/assets/stylesheets/alchemy/frame.scss +4 -0
  4. data/app/assets/stylesheets/alchemy/icons.scss +2 -0
  5. data/app/controllers/alchemy/admin/languages_controller.rb +5 -6
  6. data/app/controllers/alchemy/api/base_controller.rb +1 -1
  7. data/app/controllers/alchemy/api/contents_controller.rb +1 -1
  8. data/app/controllers/alchemy/api/elements_controller.rb +1 -1
  9. data/app/controllers/alchemy/api/pages_controller.rb +1 -1
  10. data/app/models/alchemy/page.rb +1 -0
  11. data/app/models/alchemy/page/page_natures.rb +3 -3
  12. data/app/views/alchemy/admin/layoutpages/_layoutpage.html.erb +4 -0
  13. data/app/views/alchemy/admin/layoutpages/edit.html.erb +5 -1
  14. data/app/views/alchemy/admin/pages/_form.html.erb +5 -1
  15. data/app/views/alchemy/admin/pages/_locked_page.html.erb +3 -0
  16. data/app/views/alchemy/admin/pages/_page.html.erb +5 -1
  17. data/app/views/alchemy/admin/pages/_page_status.html.erb +3 -0
  18. data/app/views/alchemy/admin/pages/info.html.erb +6 -1
  19. data/app/views/alchemy/admin/resources/_form.html.erb +1 -1
  20. data/config/locales/alchemy.de.yml +1 -0
  21. data/config/locales/alchemy.en.yml +2 -1
  22. data/config/routes.rb +1 -4
  23. data/lib/alchemy/capistrano.rb +3 -4
  24. data/lib/alchemy/errors.rb +0 -4
  25. data/lib/alchemy/mount_point.rb +30 -30
  26. data/lib/alchemy/resource.rb +18 -2
  27. data/lib/alchemy/test_support/factories.rb +2 -2
  28. data/lib/alchemy/version.rb +1 -1
  29. data/lib/rails/generators/alchemy/deploy_script/deploy_script_generator.rb +25 -9
  30. data/lib/rails/generators/alchemy/deploy_script/templates/deploy.rb.tt +0 -1
  31. data/spec/controllers/admin/languages_controller_spec.rb +35 -11
  32. data/spec/controllers/alchemy/api/contents_controller_spec.rb +1 -1
  33. data/spec/controllers/alchemy/api/elements_controller_spec.rb +1 -1
  34. data/spec/controllers/alchemy/api/pages_controller_spec.rb +1 -1
  35. data/spec/dummy/config/alchemy/page_layouts.yml +1 -1
  36. data/spec/dummy/config/application.rb +0 -2
  37. data/spec/dummy/config/environments/test.rb +1 -1
  38. data/spec/libraries/mount_point_spec.rb +41 -26
  39. data/spec/libraries/page_layout_spec.rb +9 -3
  40. data/spec/libraries/resource_spec.rb +24 -0
  41. data/spec/models/page_spec.rb +25 -26
  42. metadata +3 -4
  43. data/app/views/layouts/alchemy/login.html.erb +0 -2
  44. data/config/initializers/inflections.rb +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d78b3cd4366f28718898767bfd2212e69395d267
4
- data.tar.gz: 140a0432a7d56ebf61bea01496a2a595dc4d01d2
3
+ metadata.gz: ee349e3c1603a85fa273cfbb168e88190db26c8f
4
+ data.tar.gz: c3288e7a9f128291320f6646dd41ab78f65f23ea
5
5
  SHA512:
6
- metadata.gz: 27f13644e9cb1b682087d700fc8bc8832bc631eec3050afceb6de0c208b2529240bf4c305e6834d6be3a0108cd5e0450c4a2760711fcc1280db8e100b12aaa39
7
- data.tar.gz: cf7ea49cb254531558138aa382e3cdba384e318dcadf7545abc467bb04393308a6fa71c5713faf3747ef6d38a4d2a92156d9217a1cfa4d3bfe7a509c352cc93c
6
+ metadata.gz: a4b86afe18307827a65c0ecff2894ac39df62a39430d8c9da38d455a49ace528caf9a94b0b91b7e93477a2188ea407c21c700f161ac067e11b26411481f6e5f1
7
+ data.tar.gz: 52dcf130529e8494da6e49babc0ab1bed1ce6e752aea27aaadce37081dee615892f62c4f5ff4cccd3ae00bf32de1ea4e7b001beb848ca08f6d022428a91a1d44
@@ -0,0 +1,23 @@
1
+ # EditorConfig is awesome: http://EditorConfig.org
2
+
3
+ # top-most EditorConfig file
4
+ root = true
5
+
6
+ # Unix-style newlines with a newline ending every file
7
+ [*]
8
+ charset = utf-8
9
+ end_of_line = lf
10
+ indent_size = 2
11
+ indent_style = space
12
+ insert_final_newline = true
13
+ trim_trailing_whitespace = true
14
+ tab_width = 2
15
+
16
+ [**.rb]
17
+ max_line_length = 80
18
+
19
+ [**.js, **.coffee]
20
+ max_line_length = 120
21
+
22
+ [*.md]
23
+ trim_trailing_whitespace = false
@@ -275,6 +275,10 @@ div#user_info {
275
275
  > a {
276
276
  padding: 0px 8px;
277
277
  }
278
+
279
+ .inline.icon {
280
+ vertical-align: text-bottom;
281
+ }
278
282
  }
279
283
  }
280
284
 
@@ -302,6 +302,8 @@
302
302
 
303
303
  &.warning, &.warn, &.alert {
304
304
  background-position: 0 -168px;
305
+
306
+ &.inline { vertical-align: baseline; }
305
307
  }
306
308
 
307
309
  &.word {
@@ -1,18 +1,17 @@
1
1
  module Alchemy
2
2
  module Admin
3
- class LanguagesController < Alchemy::Admin::ResourcesController
3
+ class LanguagesController < ResourcesController
4
4
 
5
5
  def new
6
- @language = Alchemy::Language.new
7
- @language.page_layout = (configured_page_layout or @language.page_layout)
6
+ @language = Language.new
7
+ @language.page_layout = configured_page_layout || @language.page_layout
8
8
  end
9
9
 
10
- protected
10
+ private
11
11
 
12
12
  def configured_page_layout
13
- Alchemy::Config.get(:default_language).try('[]', 'page_layout')
13
+ Config.get(:default_language).try('[]', 'page_layout')
14
14
  end
15
-
16
15
  end
17
16
  end
18
17
  end
@@ -1,5 +1,5 @@
1
1
  module Alchemy
2
- class API::BaseController < Alchemy::BaseController
2
+ class Api::BaseController < Alchemy::BaseController
3
3
  layout false
4
4
  respond_to :json
5
5
 
@@ -1,5 +1,5 @@
1
1
  module Alchemy
2
- class API::ContentsController < API::BaseController
2
+ class Api::ContentsController < Api::BaseController
3
3
 
4
4
  # Returns all contents as json object
5
5
  #
@@ -1,5 +1,5 @@
1
1
  module Alchemy
2
- class API::ElementsController < API::BaseController
2
+ class Api::ElementsController < Api::BaseController
3
3
 
4
4
  # Returns all elements as json object
5
5
  #
@@ -1,5 +1,5 @@
1
1
  module Alchemy
2
- class API::PagesController < API::BaseController
2
+ class Api::PagesController < Api::BaseController
3
3
  before_action :load_page, only: [:show]
4
4
 
5
5
  # Returns all pages as json object
@@ -36,6 +36,7 @@
36
36
  module Alchemy
37
37
  class Page < ActiveRecord::Base
38
38
  include Alchemy::Hints
39
+ include Alchemy::Logger
39
40
  include Alchemy::Touching
40
41
 
41
42
  DEFAULT_ATTRIBUTES_FOR_COPY = {
@@ -67,10 +67,10 @@ module Alchemy
67
67
  return {} if self.systempage?
68
68
  description = PageLayout.get(self.page_layout)
69
69
  if description.nil?
70
- raise PageLayoutDefinitionError, "Description could not be found for page layout named #{self.page_layout}. Please check page_layouts.yml file."
71
- else
72
- description
70
+ log_warning "Page layout description for `#{self.page_layout}` not found. Please check `page_layouts.yml` file."
71
+ return {}
73
72
  end
73
+ description
74
74
  end
75
75
  alias_method :definition, :layout_description
76
76
 
@@ -1,7 +1,11 @@
1
1
  <li class="page_level_<%= layoutpage.level %>" id="page_<%= layoutpage.id %>">
2
2
  <div class="sitemap_page<%= layoutpage.locked ? ' locked' : '' %>">
3
3
  <div class="sitemap_left_images">
4
+ <% if layoutpage.layout_description.blank? %>
5
+ <span class="inline warning icon" title="<%= _t(:page_layout_description_missing) %>"></span>
6
+ <% else %>
4
7
  <%= render_icon(:page) %>
8
+ <% end %>
5
9
  </div>
6
10
  <div class="sitemap_right_tools">
7
11
  <%- if can?(:configure, layoutpage) -%>
@@ -1,5 +1,9 @@
1
1
  <%= alchemy_form_for [:admin, @page], class: 'edit_page' do |f| %>
2
- <%= f.input :page_layout, collection: @page_layouts, label: _t(:page_type), include_blank: false, input_html: {class: 'alchemy_selectbox'} %>
2
+ <%= f.input :page_layout,
3
+ collection: @page_layouts,
4
+ label: @page.layout_description.blank? ? (%(<span class="inline warning icon" title="#{ _t(:page_layout_description_missing) }"></span>&nbsp;) + _t(:page_type)).html_safe : _t(:page_type),
5
+ include_blank: false,
6
+ input_html: {class: 'alchemy_selectbox'} %>
3
7
  <%= f.input :name, autofocus: true %>
4
8
  <% if @page.taggable? %>
5
9
  <div class="input string">
@@ -1,5 +1,9 @@
1
1
  <%= alchemy_form_for [:admin, @page], class: 'edit_page' do |f| %>
2
- <%= f.input :page_layout, collection: @page_layouts, label: _t(:page_type), include_blank: false, input_html: {class: 'alchemy_selectbox'} %>
2
+ <%= f.input :page_layout,
3
+ collection: @page_layouts,
4
+ label: @page.layout_description.blank? ? (%(<span class="inline warning icon" title="#{ _t(:page_layout_description_missing) }"></span>&nbsp;) + _t(:page_type)).html_safe : _t(:page_type),
5
+ include_blank: false,
6
+ input_html: {class: 'alchemy_selectbox'} %>
3
7
  <div class="input check_boxes">
4
8
  <label class="control-label"><%= _t(:page_status) %></label>
5
9
  <div class="control_group">
@@ -3,6 +3,9 @@
3
3
  <% else %>
4
4
  <div class="subnavi_tab wide" id="locked_page_<%= locked_page.id %>">
5
5
  <%= link_to alchemy.edit_admin_page_path(locked_page) do %>
6
+ <% if locked_page.layout_description.blank? %>
7
+ <span class="inline warning icon" title="<%= _t(:page_layout_description_missing) %>"></span>
8
+ <% end %>
6
9
  <span class="page_name" title="<%= locked_page.name %>">
7
10
  <%= truncate locked_page.name, length: 15 %>
8
11
  </span>
@@ -2,7 +2,11 @@
2
2
  <div class="sitemap_page<%= page.locked ? ' locked' : '' %>" name="<%= page.name %>">
3
3
  <div class="sitemap_left_images">
4
4
  <%= sitemap_folder_link(page) unless page.level == 1 || page.children.blank? || @sorting %>
5
- <div class="page icon <%= @sorting && page.level > 1 ? 'handle' : nil %>"></div>
5
+ <% if page.layout_description.blank? %>
6
+ <span class="inline warning icon" title="<%= _t(:page_layout_description_missing) %>"></span>
7
+ <% else %>
8
+ <div class="page icon <%= @sorting && page.level > 1 ? 'handle' : nil %>"></div>
9
+ <% end %>
6
10
  </div>
7
11
  <div class="sitemap_right_tools">
8
12
  <%- unless @sorting -%>
@@ -1,4 +1,7 @@
1
1
  <div class="page_status_and_name" id="page_<%= @page.id %>_status">
2
+ <% if @page.layout_description.blank? %>
3
+ <span class="inline warning icon" title="<%= _t(:page_layout_description_missing) %>"></span>
4
+ <% end %>
2
5
  <span class="page_name"><%= @page.name %></span>
3
6
  <%- if multi_language? -%>
4
7
  <span class="page_language" title="<%= @page.language.name %>">
@@ -5,7 +5,12 @@
5
5
  <% end %>
6
6
  <% end %>
7
7
  <div class="value">
8
- <label><%= Alchemy::Page.human_attribute_name(:page_layout) %></label>
8
+ <label>
9
+ <% if @page.layout_description.blank? %>
10
+ <span class="inline warning icon" title="<%= _t(:page_layout_description_missing) %>"></span>
11
+ <% end %>
12
+ <%= Alchemy::Page.human_attribute_name(:page_layout) %>
13
+ </label>
9
14
  <p><%= @page.layout_display_name %></p>
10
15
  </div>
11
16
  <div class="value">
@@ -1,5 +1,5 @@
1
1
  <%= alchemy_form_for resource_instance_variable, url: resource_path(resource_instance_variable) do |f| %>
2
- <% resource_handler.attributes.each do |attribute| %>
2
+ <% resource_handler.editable_attributes.each do |attribute| %>
3
3
  <% if relation = attribute[:relation] %>
4
4
  <%= f.association relation[:name].to_sym,
5
5
  label_method: relation[:attr_method],
@@ -287,6 +287,7 @@ de:
287
287
  "Warning!": "Achtung!"
288
288
  content_description_missing: "Warnung: Für diesen Content konnte die Vorlage nicht gefunden werden. Bitte überprüfen Sie die elements.yml Datei."
289
289
  element_description_missing: "Warnung! Für dieses Element konnte die Vorlage nicht gefunden werden. Bitte überprüfen Sie die elements.yml Datei."
290
+ page_layout_description_missing: "Warnung! Für diese Seite konnte die Vorlage nicht gefunden werden. Bitte überprüfen Sie die page_layouts.yml Datei."
290
291
  "Welcome to Alchemy": "Willkommen in Alchemy"
291
292
  "Who else is online": "Wer ist noch online"
292
293
  "Yes": "Ja"
@@ -286,7 +286,8 @@ en:
286
286
  "Visit page": "Visit page"
287
287
  "Warning!": "Warning!"
288
288
  content_description_missing: "Warning: Content is missing its description. Please check the elements.yml"
289
- element_description_missing: "WARNING! Missing description. Please check your elements.yml file."
289
+ element_description_missing: "WARNING! Missing element description. Please check your elements.yml file."
290
+ page_layout_description_missing: "WARNING! Missing page layout description. Please check your page_layouts.yml file."
290
291
  "Welcome to Alchemy": "Welcome to Alchemy"
291
292
  "Who else is online": "Who else is online"
292
293
  "Yes": "Yes"
@@ -4,10 +4,7 @@ Alchemy::Engine.routes.draw do
4
4
 
5
5
  get '/sitemap.xml' => 'pages#sitemap', format: 'xml'
6
6
 
7
- get '/admin' => redirect(
8
- "#{Alchemy::MountPoint.get}/admin/dashboard"
9
- )
10
-
7
+ get '/admin' => redirect('admin/dashboard')
11
8
  get '/admin/dashboard' => 'admin/dashboard#index',
12
9
  :as => :admin_dashboard
13
10
  get '/admin/dashboard/info' => 'admin/dashboard#info',
@@ -1,9 +1,8 @@
1
- # This recipe contains Capistrano recipes for handling the uploads and picture cache files while deploying your application.
2
- #
1
+ # This recipe contains Capistrano recipes for handling the uploads
2
+ # and picture cache files while deploying your application.
3
+
3
4
  require 'fileutils'
4
5
  require 'alchemy/tasks/helpers'
5
- # Loading the current Rails app's env, so we can get the Alchemy mount point.
6
- require './config/environment.rb'
7
6
  require 'alchemy/mount_point'
8
7
 
9
8
  include Alchemy::Tasks::Helpers
@@ -32,10 +32,6 @@ module Alchemy
32
32
  # Raised if calling +image_file+ on a Picture object returns nil.
33
33
  end
34
34
 
35
- class PageLayoutDefinitionError < StandardError
36
- # Raised if page_layout definition can not be found.
37
- end
38
-
39
35
  class PictureInUseError < StandardError
40
36
  # Raised if the picture is still in use and can not be deleted.
41
37
  end
@@ -1,41 +1,41 @@
1
1
  module Alchemy
2
- # Utitlities for Alchemy's mount point in the host rails app.
2
+
3
+ # Utilities for Alchemy's mount point in the host rails app.
3
4
  #
4
5
  class MountPoint
6
+ MOUNT_POINT_REGEXP = /mount\sAlchemy::Engine\s=>\s['|"](\/\w*)['|"]/
7
+
8
+ class << self
5
9
 
6
- # Returns the path of Alchemy's mount point in current rails app.
7
- #
8
- # @param [Boolean] remove_leading_slash_if_blank
9
- # Pass false to not return a leading slash on empty mount point.
10
- #
11
- def self.get(remove_leading_slash_if_blank = true)
12
- if self.mount_point == "/" && remove_leading_slash_if_blank
13
- self.mount_point.gsub(/\A\/\z/, '')
14
- else
15
- self.mount_point
10
+ # Returns the path of Alchemy's mount point in current rails app.
11
+ #
12
+ # @param [Boolean] remove_leading_slash_if_blank
13
+ # Pass false to not return a leading slash on empty mount point.
14
+ #
15
+ def get(remove_leading_slash_if_blank = true)
16
+ if path == "/" && remove_leading_slash_if_blank
17
+ path.gsub(/\A\/\z/, '')
18
+ else
19
+ path
20
+ end
16
21
  end
17
- end
18
22
 
19
- # Returns the routes object from Alchemy in the host app.
20
- #
21
- def self.routes
22
- ::Rails.application.routes.named_routes[:alchemy]
23
- end
23
+ # Returns the mount point path from the Rails app routes.
24
+ #
25
+ def path
26
+ match = File.read(routes_file_path).match(MOUNT_POINT_REGEXP)
27
+ if match.nil?
28
+ raise "Alchemy mount point not found! Please run `bin/rake alchemy:mount'"
29
+ else
30
+ match[1]
31
+ end
32
+ end
33
+
34
+ private
24
35
 
25
- # Returns the raw mount point path from the Rails app routes.
26
- #
27
- # If Alchemy is not mounted in the main app, it falls back to root path.
28
- #
29
- def self.mount_point
30
- if self.routes.nil?
31
- ::Rails.logger.warn <<-WARN
32
- Alchemy is not mounted! Falling back to root path (/).
33
- If you want to change Alchemy's mount point, please mount Alchemy::Engine in your config/routes.rb file.
34
- WARN
35
- return '/'
36
+ def routes_file_path
37
+ Rails.root.join('config/routes.rb')
36
38
  end
37
- routes.path.spec.to_s
38
39
  end
39
-
40
40
  end
41
41
  end
@@ -20,7 +20,7 @@ module Alchemy
20
20
  #
21
21
  # == Skip attributes
22
22
  #
23
- # Usually you don't want your users to edit all attributes provided by a model. Hence some default attributes,
23
+ # Usually you don't want your users to see and edit all attributes provided by a model. Hence some default attributes,
24
24
  # namely id, updated_at, created_at, creator_id and updater_id are not returned by Resource#attributes.
25
25
  #
26
26
  # If you want to skip a different set of attributes just define a +skipped_alchemy_resource_attributes+ class method in your model class
@@ -32,6 +32,17 @@ module Alchemy
32
32
  # %w(id updated_at secret_token remote_ip)
33
33
  # end
34
34
  #
35
+ # == Restrict attributes
36
+ #
37
+ # Beside skipping certain attributes you can also restrict them. Restricted attributes can not be edited by the user but still be seen in the index view.
38
+ # No attributes are restricted by default.
39
+ #
40
+ # === Example
41
+ #
42
+ # def self.restricted_alchemy_resource_attributes
43
+ # %w(synced_at remote_record_id)
44
+ # end
45
+ #
35
46
  # == Resource relations
36
47
  #
37
48
  # Alchemy::Resource can take care of ActiveRecord relations.
@@ -73,7 +84,7 @@ module Alchemy
73
84
  # resource = Resource.new('/admin/tags', {"engine_name"=>"alchemy"}, ActsAsTaggableOn::Tag)
74
85
  #
75
86
  class Resource
76
- attr_accessor :skipped_attributes, :resource_relations, :model_associations
87
+ attr_accessor :skipped_attributes, :restricted_attributes, :resource_relations, :model_associations
77
88
  attr_reader :model
78
89
 
79
90
  DEFAULT_SKIPPED_ATTRIBUTES = %w(id updated_at created_at creator_id updater_id)
@@ -84,6 +95,7 @@ module Alchemy
84
95
  @module_definition = module_definition
85
96
  @model = (custom_model or guess_model_from_controller_path)
86
97
  self.skipped_attributes = model.respond_to?(:skipped_alchemy_resource_attributes) ? model.skipped_alchemy_resource_attributes : DEFAULT_SKIPPED_ATTRIBUTES
98
+ self.restricted_attributes = model.respond_to?(:restricted_alchemy_resource_attributes) ? model.restricted_alchemy_resource_attributes : []
87
99
  if model.respond_to?(:alchemy_resource_relations)
88
100
  if not model.respond_to?(:reflect_on_all_associations)
89
101
  raise MissingActiveRecordAssociation
@@ -139,6 +151,10 @@ module Alchemy
139
151
  end.compact
140
152
  end
141
153
 
154
+ def editable_attributes
155
+ attributes.reject { |h| self.restricted_attributes.map(&:to_s).include?(h[:name].to_s) }
156
+ end
157
+
142
158
  # Returns all columns that are searchable
143
159
  #
144
160
  # For now it only uses string type columns
@@ -28,7 +28,7 @@ FactoryGirl.define do
28
28
  code 'de'
29
29
  default true
30
30
  frontpage_name 'Intro'
31
- page_layout 'intro'
31
+ page_layout { Alchemy::Config.get(:default_language)['page_layout'] }
32
32
  public true
33
33
  site { Alchemy::Site.first }
34
34
 
@@ -59,7 +59,7 @@ FactoryGirl.define do
59
59
 
60
60
  factory :language_root_page do
61
61
  name 'Startseite'
62
- page_layout 'intro'
62
+ page_layout { language.page_layout }
63
63
  language_root true
64
64
  public true
65
65
  parent_id { Alchemy::Page.root.id }
@@ -1,5 +1,5 @@
1
1
  module Alchemy
2
- VERSION = "3.1.0.beta5"
2
+ VERSION = "3.1.0.beta6"
3
3
 
4
4
  def self.version
5
5
  VERSION
@@ -5,13 +5,31 @@ module Alchemy
5
5
  class DeployScriptGenerator < ::Rails::Generators::Base
6
6
 
7
7
  desc "This generator generates a Capistrano receipt for deploying Alchemy CMS."
8
- class_option :scm, :type => :string, :desc => "Set the type of scm you use for deployment.", :default => 'git'
9
- class_option :db, :type => :string, :desc => "Set the type of database you use on your server.", :default => 'mysql'
8
+
9
+ class_option :scm,
10
+ type: 'string',
11
+ desc: "Set the type of scm you use for deployment.",
12
+ default: 'git'
13
+
14
+ class_option :db,
15
+ type: 'string',
16
+ desc: "Set the type of database you use on your server.",
17
+ default: 'mysql'
18
+
10
19
  source_root File.expand_path('templates', File.dirname(__FILE__))
11
20
 
12
21
  def copy_script
13
22
  @scm = options[:scm]
14
23
  @database_type = options[:db]
24
+ ask_questions
25
+ template "deploy.rb.tt", Rails.root.join('config', 'deploy.rb')
26
+ setup_capistrano
27
+ show_read_me
28
+ end
29
+
30
+ private
31
+
32
+ def ask_questions
15
33
  @app_name = ask('Please enter a name for your application:')
16
34
  @server = ask('Please enter server ip or domain:')
17
35
  if @store_credentials = yes?('Do want to store the ssh credentials? (PLEASE DO NOT STORE THEM IF THE REPOSITORY IS PUBLIC) (y/N)')
@@ -27,13 +45,8 @@ module Alchemy
27
45
  if @scm == "svn" && yes?('Is your repository private? (y/N)')
28
46
  ask_for_repo_credentials
29
47
  end
30
- template "deploy.rb.tt", Rails.root.join('config', 'deploy.rb')
31
- setup_capistrano
32
- show_read_me
33
48
  end
34
49
 
35
- private
36
-
37
50
  def ask_for_credentials
38
51
  @ssh_user = ask('Please enter ssh username:')
39
52
  port = ask('Please enter ssh port (22):')
@@ -59,7 +72,11 @@ module Alchemy
59
72
 
60
73
  def setup_capistrano
61
74
  puts "\nSetting up Capistrano"
62
- `capify .`
75
+ if system 'capify .'
76
+ gsub_file 'Capfile',
77
+ /\s{4}#\sload\s'deploy\/assets'/,
78
+ "load 'deploy/assets'"
79
+ end
63
80
  end
64
81
 
65
82
  def show_read_me
@@ -68,7 +85,6 @@ module Alchemy
68
85
  puts "\nIf you want to deploy Alchemy the first time type:\ncap deploy:cold"
69
86
  puts "\nAfter the first deploy you just need to type:\ncap deploy"
70
87
  end
71
-
72
88
  end
73
89
  end
74
90
  end
@@ -1,6 +1,5 @@
1
1
  require 'bundler/capistrano'
2
2
  require 'alchemy/capistrano'
3
- load 'deploy/assets'
4
3
 
5
4
  # application name
6
5
  set :application, "<%= @app_name %>"
@@ -1,19 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
- class Alchemy::Config;
4
- end
5
-
6
3
  describe Alchemy::Admin::LanguagesController do
7
4
 
8
5
  before do
9
6
  sign_in(admin_user)
10
7
  end
11
8
 
12
- describe "new" do
13
-
9
+ describe "#new" do
14
10
  context "when default_language.page_layout is set" do
15
- it "should use it as page_layout-default for the new language" do
16
- # FML :/
11
+ before do
17
12
  allow(Alchemy::Config).to receive(:get) do |arg|
18
13
  if arg == :default_language
19
14
  {'page_layout' => "new_standard"}
@@ -21,17 +16,46 @@ describe Alchemy::Admin::LanguagesController do
21
16
  Alchemy::Config.show[arg.to_s]
22
17
  end
23
18
  end
19
+ end
20
+
21
+ it "uses it as page_layout-default for the new language" do
24
22
  get :new
25
- expect(assigns(:language).page_layout).to eql("new_standard")
23
+ expect(assigns(:language).page_layout).to eq("new_standard")
26
24
  end
27
25
  end
28
26
 
29
- context "when default_language or page_layout aren't configured" do
30
- it "should fallback to one configured in config.yml" do
27
+ context "when default_language is not configured" do
28
+ before do
29
+ allow(Alchemy::Config).to receive(:get) do |arg|
30
+ if arg == :default_language
31
+ nil
32
+ else
33
+ Alchemy::Config.show[arg.to_s]
34
+ end
35
+ end
36
+ end
37
+
38
+ it "falls back to default database value." do
31
39
  get :new
32
- expect(assigns(:language).page_layout).to eql("index")
40
+ expect(assigns(:language).page_layout).to eq("intro")
33
41
  end
34
42
  end
35
43
 
44
+ context "when default language page_layout is not configured" do
45
+ before do
46
+ allow(Alchemy::Config).to receive(:get) do |arg|
47
+ if arg == :default_language
48
+ {}
49
+ else
50
+ Alchemy::Config.show[arg.to_s]
51
+ end
52
+ end
53
+ end
54
+
55
+ it "falls back to default database value." do
56
+ get :new
57
+ expect(assigns(:language).page_layout).to eq("intro")
58
+ end
59
+ end
36
60
  end
37
61
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module Alchemy
4
- describe API::ContentsController do
4
+ describe Api::ContentsController do
5
5
  describe '#index' do
6
6
  let!(:page) { create(:page) }
7
7
  let!(:element) { create(:element, page: page) }
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module Alchemy
4
- describe API::ElementsController do
4
+ describe Api::ElementsController do
5
5
  describe '#index' do
6
6
  let!(:page) { create(:public_page) }
7
7
  let!(:element) { create(:element, page: page) }
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module Alchemy
4
- describe API::PagesController do
4
+ describe Api::PagesController do
5
5
 
6
6
  describe '#index' do
7
7
  let!(:page) { create(:public_page) }
@@ -1,4 +1,4 @@
1
- - name: intro
1
+ - name: index
2
2
  unique: true
3
3
 
4
4
  - name: standard
@@ -18,7 +18,5 @@ module Dummy
18
18
  # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
19
19
  # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
20
20
  # config.i18n.default_locale = :de
21
-
22
- I18n.enforce_available_locales = true
23
21
  end
24
22
  end
@@ -34,5 +34,5 @@ Dummy::Application.configure do
34
34
  # Print deprecation notices to the stderr.
35
35
  config.active_support.deprecation = :stderr
36
36
 
37
- I18n.enforce_available_locales = false
37
+ config.i18n.enforce_available_locales = false
38
38
  end
@@ -1,33 +1,34 @@
1
1
  require 'spec_helper'
2
- require 'ostruct'
3
2
 
4
3
  describe Alchemy::MountPoint do
5
-
6
4
  describe '.get' do
7
-
8
5
  it "returns the path of alchemy's mount point" do
9
- allow(Alchemy::MountPoint).to receive(:mount_point).and_return('/cms')
6
+ allow(Alchemy::MountPoint).to receive(:path).and_return('/cms')
10
7
  expect(Alchemy::MountPoint.get).to eq('/cms')
11
8
  end
12
9
 
13
10
  it "removes the leading slash if root mount point" do
14
- allow(Alchemy::MountPoint).to receive(:mount_point).and_return('/')
11
+ allow(Alchemy::MountPoint).to receive(:path).and_return('/')
15
12
  expect(Alchemy::MountPoint.get).to eq('')
16
13
  end
17
14
 
18
15
  context "with remove_leading_slash_if_blank set to false" do
19
- before {
20
- allow(Alchemy::MountPoint).to receive(:mount_point).and_return('/')
21
- }
16
+ before do
17
+ allow(Alchemy::MountPoint)
18
+ .to receive(:path)
19
+ .and_return('/')
20
+ end
22
21
 
23
22
  it "does not remove the leading white slash of path" do
24
23
  expect(Alchemy::MountPoint.get(false)).to eq('/')
25
24
  end
26
25
 
27
26
  context "and with mount point not root" do
28
- before {
29
- allow(Alchemy::MountPoint).to receive(:mount_point).and_return('/cms')
30
- }
27
+ before do
28
+ allow(Alchemy::MountPoint)
29
+ .to receive(:path)
30
+ .and_return('/cms')
31
+ end
31
32
 
32
33
  it "does not remove the leading white slash of path" do
33
34
  expect(Alchemy::MountPoint.get(false)).to eq('/cms')
@@ -36,27 +37,41 @@ describe Alchemy::MountPoint do
36
37
  end
37
38
  end
38
39
 
39
- describe '.routes' do
40
- it "returns the routes object from alchemy engine" do
41
- expect(Alchemy::MountPoint.routes).to be_instance_of(ActionDispatch::Journey::Route)
40
+ describe '.path' do
41
+ before do
42
+ allow(File)
43
+ .to receive(:read)
44
+ .and_return("mount Alchemy::Engine => '/cms'")
42
45
  end
43
- end
44
46
 
45
- describe '.mount_point' do
46
- it 'returns the raw mount point path from routes' do
47
- allow(Alchemy::MountPoint).to receive(:routes).and_return(OpenStruct.new(path: OpenStruct.new(spec: '/cms')))
48
- expect(Alchemy::MountPoint.mount_point).to eq('/cms')
47
+ it 'returns the mount point path from routes.' do
48
+ expect(Alchemy::MountPoint.path).to eq('/cms')
49
+ end
50
+
51
+ context "Alchemy mount point could not be found" do
52
+ before do
53
+ allow(File)
54
+ .to receive(:read)
55
+ .and_return("")
56
+ end
57
+
58
+ it "raises an exception" do
59
+ expect {
60
+ Alchemy::MountPoint.path
61
+ }.to raise_error
62
+ end
49
63
  end
50
64
 
51
- context "Alchemy routes could not be found" do
52
- before {
53
- allow(Alchemy::MountPoint).to receive(:routes).and_return(nil)
54
- }
65
+ context 'Mount point using double quotes string' do
66
+ before do
67
+ allow(File)
68
+ .to receive(:read)
69
+ .and_return('mount Alchemy::Engine => "/cms"')
70
+ end
55
71
 
56
- it "falls back to root path" do
57
- expect(Alchemy::MountPoint.mount_point).to eq('/')
72
+ it 'returns the mount point path from routes.' do
73
+ expect(Alchemy::MountPoint.path).to eq('/cms')
58
74
  end
59
75
  end
60
76
  end
61
-
62
77
  end
@@ -81,12 +81,18 @@ module Alchemy
81
81
 
82
82
  context "with sites layouts present" do
83
83
  let(:site) { Site.new }
84
- let(:definitions) { [{'name' => 'default_site', 'page_layouts' => %w(intro)}] }
85
- before { allow(Site).to receive(:layout_definitions).and_return(definitions) }
84
+
85
+ let(:definitions) do
86
+ [{'name' => 'default_site', 'page_layouts' => %w(index)}]
87
+ end
88
+
89
+ before do
90
+ allow(Site).to receive(:layout_definitions).and_return(definitions)
91
+ end
86
92
 
87
93
  it "should only return layouts for site" do
88
94
  expect(subject.length).to eq(1)
89
- expect(subject.first['name']).to eq('intro')
95
+ expect(subject.first['name']).to eq('index')
90
96
  end
91
97
  end
92
98
  end
@@ -63,6 +63,11 @@ module Alchemy
63
63
  expect(resource.skipped_attributes).to eq(%w(id updated_at created_at creator_id updater_id))
64
64
  end
65
65
 
66
+ it "sets the restricted attributes accessor to an empty array by default" do
67
+ resource = Resource.new("admin/parties")
68
+ expect(resource.restricted_attributes).to eq([])
69
+ end
70
+
66
71
  it "sets an instance variable that holds the controller path" do
67
72
  resource = Resource.new("admin/parties")
68
73
  expect(resource.instance_variable_get(:@controller_path)).to eq("admin/parties")
@@ -269,6 +274,25 @@ module Alchemy
269
274
  end
270
275
  end
271
276
 
277
+ describe "#editable_attributes" do
278
+ subject { resource.editable_attributes }
279
+
280
+ let(:columns) do
281
+ [
282
+ double(:column, {name: 'name', type: :string}),
283
+ double(:column, {name: 'title', type: :string}),
284
+ double(:column, {name: 'synced_at', type: :datetime}),
285
+ double(:column, {name: 'remote_record_id', type: :string})
286
+ ]
287
+ end
288
+
289
+ before { resource.restricted_attributes = [:synced_at, :remote_record_id] }
290
+
291
+ it "does not contain restricted attributes" do
292
+ is_expected.to eq([{name: "name", type: :string}, {name: "title", type: :string}])
293
+ end
294
+ end
295
+
272
296
  context "when alchemy_resource_relations defined as class method in the model" do
273
297
  let(:resource) { Resource.new("admin/events") }
274
298
 
@@ -567,22 +567,6 @@ module Alchemy
567
567
  end
568
568
  end
569
569
 
570
- describe '.layout_description' do
571
- it "should raise Exception if the page_layout could not be found in the definition file" do
572
- expect { page.layout_description }.to raise_error
573
- end
574
-
575
- context "for a language root page" do
576
- it "should return the page layout description as hash" do
577
- expect(language_root.layout_description['name']).to eq('intro')
578
- end
579
-
580
- it "should return an empty hash for root page" do
581
- expect(rootpage.layout_description).to eq({})
582
- end
583
- end
584
- end
585
-
586
570
  describe '.layoutpages' do
587
571
  it "should return 1 layoutpage" do
588
572
  FactoryGirl.create(:public_page, :layoutpage => true, :name => 'Layoutpage', :parent_id => rootpage.id, :language => language)
@@ -659,16 +643,6 @@ module Alchemy
659
643
  end
660
644
  end
661
645
 
662
- context "for page_layout not existing" do
663
- let(:page) { FactoryGirl.build_stubbed(:page, page_layout: 'not_existing_one') }
664
-
665
- it "should raise error" do
666
- expect {
667
- page.available_element_definitions
668
- }.to raise_error(Alchemy::PageLayoutDefinitionError)
669
- end
670
- end
671
-
672
646
  context 'limited amount' do
673
647
  let(:page) { FactoryGirl.build_stubbed(:page, page_layout: 'columns') }
674
648
  let(:unique_element) { FactoryGirl.build_stubbed(:unique_element, name: 'unique_headline') }
@@ -1026,6 +1000,31 @@ module Alchemy
1026
1000
  end
1027
1001
  end
1028
1002
 
1003
+ describe '#layout_description' do
1004
+ context 'if the page layout could not be found in the definition file' do
1005
+ let(:page) { build_stubbed(:page, page_layout: 'notexisting') }
1006
+
1007
+ it "it loggs a warning." do
1008
+ expect(Alchemy::Logger).to receive(:warn)
1009
+ page.layout_description
1010
+ end
1011
+
1012
+ it "it returns empty hash." do
1013
+ expect(page.layout_description).to eq({})
1014
+ end
1015
+ end
1016
+
1017
+ context "for a language root page" do
1018
+ it "it returns the page layout description as hash." do
1019
+ expect(language_root.layout_description['name']).to eq('index')
1020
+ end
1021
+
1022
+ it "it returns an empty hash for root page." do
1023
+ expect(rootpage.layout_description).to eq({})
1024
+ end
1025
+ end
1026
+ end
1027
+
1029
1028
  describe '#lock_to!' do
1030
1029
  let(:page) { create(:page) }
1031
1030
  let(:user) { mock_model('DummyUser') }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alchemy_cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0.beta5
4
+ version: 3.1.0.beta6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas von Deyen
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2015-01-02 00:00:00.000000000 Z
15
+ date: 2015-01-08 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: actionpack-page_caching
@@ -446,6 +446,7 @@ executables:
446
446
  extensions: []
447
447
  extra_rdoc_files: []
448
448
  files:
449
+ - ".editorconfig"
449
450
  - ".gitignore"
450
451
  - ".rspec"
451
452
  - ".travis.yml"
@@ -842,14 +843,12 @@ files:
842
843
  - app/views/kaminari/alchemy/_paginator.html.erb
843
844
  - app/views/kaminari/alchemy/_prev_page.html.erb
844
845
  - app/views/layouts/alchemy/admin.html.erb
845
- - app/views/layouts/alchemy/login.html.erb
846
846
  - app/views/layouts/alchemy/sitemap.xml.erb
847
847
  - bin/alchemy
848
848
  - bin/rails
849
849
  - config/alchemy/config.yml
850
850
  - config/alchemy/modules.yml
851
851
  - config/initializers/dragonfly.rb
852
- - config/initializers/inflections.rb
853
852
  - config/initializers/simple_form.rb
854
853
  - config/locales/alchemy.de.yml
855
854
  - config/locales/alchemy.en.yml
@@ -1,2 +0,0 @@
1
- <%# This file only exist for cases where one want to override the login view %>
2
- <%= render :template => 'layouts/alchemy/admin' %>
@@ -1,3 +0,0 @@
1
- ActiveSupport::Inflector.inflections(:en) do |inflect|
2
- inflect.acronym 'API'
3
- end