alchemy_cms 2.4.1 → 2.5.0.b2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +1 -1
- data/README.md +18 -17
- data/alchemy_cms.gemspec +5 -10
- data/app/assets/images/alchemy/icons.png +0 -0
- data/app/assets/stylesheets/alchemy/archive.scss +27 -0
- data/app/assets/stylesheets/alchemy/base.scss +0 -51
- data/app/assets/stylesheets/alchemy/elements.scss +37 -2
- data/app/assets/stylesheets/alchemy/icons.scss +4 -0
- data/app/assets/stylesheets/alchemy/modules.scss +4 -0
- data/app/assets/stylesheets/alchemy/sitemap.scss +1 -1
- data/app/assets/stylesheets/alchemy/tables.scss +1 -1
- data/app/assets/stylesheets/alchemy/variables.scss +1 -0
- data/app/controllers/alchemy/admin/pages_controller.rb +1 -0
- data/app/controllers/alchemy/admin/pictures_controller.rb +22 -8
- data/app/controllers/alchemy/admin/resources_controller.rb +1 -1
- data/app/controllers/alchemy/admin/sites_controller.rb +6 -0
- data/app/controllers/alchemy/base_controller.rb +8 -0
- data/app/controllers/alchemy/elements_controller.rb +33 -3
- data/app/controllers/alchemy/messages_controller.rb +47 -40
- data/app/controllers/alchemy/pages_controller.rb +8 -31
- data/app/controllers/alchemy/pictures_controller.rb +64 -30
- data/app/helpers/alchemy/admin/base_helper.rb +7 -0
- data/app/helpers/alchemy/admin/pages_helper.rb +12 -0
- data/app/helpers/alchemy/elements_helper.rb +2 -0
- data/app/helpers/alchemy/pages_helper.rb +30 -10
- data/app/helpers/alchemy/url_helper.rb +1 -0
- data/app/models/alchemy/content.rb +1 -2
- data/app/models/alchemy/element.rb +47 -2
- data/app/models/alchemy/language.rb +27 -14
- data/app/models/alchemy/page.rb +1 -1
- data/app/models/alchemy/picture.rb +46 -41
- data/app/models/alchemy/site.rb +44 -0
- data/app/views/alchemy/admin/elements/_element_head.html.erb +1 -0
- data/app/views/alchemy/admin/languages/index.html.erb +23 -0
- data/app/views/alchemy/admin/pages/edit.html.erb +27 -1
- data/app/views/alchemy/admin/pages/fold.js.erb +1 -0
- data/app/views/alchemy/admin/partials/_upload_form.html.erb +2 -0
- data/app/views/alchemy/admin/pictures/_picture.html.erb +24 -2
- data/app/views/alchemy/admin/pictures/_tag_list.html.erb +5 -4
- data/app/views/alchemy/admin/pictures/create.js.erb +1 -9
- data/app/views/alchemy/admin/pictures/info.html.erb +42 -0
- data/app/views/alchemy/admin/resources/_form.html.erb +0 -2
- data/app/views/alchemy/admin/resources/_resource.html.erb +2 -1
- data/app/views/alchemy/admin/resources/index.html.erb +2 -1
- data/app/views/alchemy/elements/show.html.erb +1 -6
- data/app/views/alchemy/elements/show.js.erb +4 -10
- data/app/views/alchemy/essences/_essence_link_view.html.erb +1 -0
- data/app/views/alchemy/search/_form.html.erb +9 -6
- data/app/views/alchemy/search/_result.html.erb +1 -1
- data/bin/alchemy +13 -120
- data/config/alchemy/config.yml +7 -11
- data/config/alchemy/modules.yml +24 -12
- data/config/authorization_rules.rb +6 -2
- data/config/initializers/dragonfly.rb +20 -0
- data/config/locales/alchemy.de.yml +57 -28
- data/config/locales/alchemy.en.yml +18 -4
- data/config/routes.rb +4 -2
- data/db/migrate/20121121162313_switch_from_fleximage_to_dragonfly.rb +21 -0
- data/db/migrate/20121205155004_create_alchemy_sites.rb +14 -0
- data/db/migrate/20121211163003_add_public_to_alchemy_sites.rb +6 -0
- data/lib/alchemy/capistrano.rb +7 -2
- data/lib/alchemy/ferret_search.rb +84 -0
- data/lib/alchemy/picture_attributes.rb +29 -0
- data/lib/alchemy/seeder.rb +10 -16
- data/lib/alchemy/upgrader.rb +59 -8
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy_cms.rb +7 -4
- data/lib/rails/generators/alchemy/deploy_script/templates/deploy.rb.tt +3 -0
- data/lib/rails/generators/alchemy/elements/elements_generator.rb +5 -1
- data/lib/rails/generators/alchemy/page_layouts/page_layouts_generator.rb +1 -0
- data/lib/rails/generators/alchemy/scaffold/files/{pages.html.erb → application.html.erb} +0 -0
- data/lib/rails/generators/alchemy/scaffold/scaffold_generator.rb +11 -20
- data/lib/rails/templates/alchemy.rb +1 -7
- data/lib/tasks/{database.rake → alchemy/db.rake} +1 -1
- data/lib/tasks/{install.rake → alchemy/install.rake} +9 -14
- data/lib/tasks/{upgrade.rake → alchemy/upgrade.rake} +1 -1
- data/spec/controllers/elements_controller_spec.rb +24 -9
- data/spec/controllers/pictures_controller_spec.rb +11 -8
- data/{app → spec/dummy/app}/views/alchemy/elements/_article_editor.html.erb +0 -0
- data/{app → spec/dummy/app}/views/alchemy/elements/_article_view.html.erb +0 -0
- data/{app → spec/dummy/app}/views/alchemy/elements/_headline_view.html.erb +0 -0
- data/{app → spec/dummy/app}/views/alchemy/elements/_news_view.html.erb +0 -0
- data/{app → spec/dummy/app}/views/alchemy/elements/_searchresult_view.html.erb +0 -0
- data/{app → spec/dummy/app}/views/alchemy/page_layouts/_standard.html.erb +0 -0
- data/spec/dummy/config/alchemy/elements.yml +86 -0
- data/spec/dummy/config/alchemy/page_layouts.yml +26 -0
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/db/migrate/20121121162313_switch_from_fleximage_to_dragonfly.rb +21 -0
- data/spec/dummy/db/migrate/20121205155004_create_alchemy_sites.rb +14 -0
- data/spec/dummy/db/migrate/20121211163003_add_public_to_alchemy_sites.rb +6 -0
- data/spec/dummy/db/schema.rb +21 -6
- data/spec/factories.rb +6 -2
- data/spec/integration/translation_integration_spec.rb +4 -18
- data/spec/models/element_spec.rb +4 -4
- data/spec/models/picture_spec.rb +37 -20
- data/spec/models/site_spec.rb +69 -0
- data/spec/routing_spec.rb +115 -115
- data/spec/spec_helper.rb +1 -3
- data/spec/support/alchemy/specs_helpers.rb +4 -4
- data/vendor/assets/javascripts/jquery_plugins/jquery.html5uploader.js +1 -1
- metadata +72 -96
- data/app/assets/stylesheets/alchemy/standard_set.css +0 -440
- data/app/views/alchemy/elements/_bild_editor.html.erb +0 -1
- data/app/views/alchemy/elements/_bild_text_editor.html.erb +0 -7
- data/app/views/alchemy/elements/_bild_text_view.html.erb +0 -9
- data/app/views/alchemy/elements/_bild_view.html.erb +0 -9
- data/app/views/alchemy/elements/_claim_editor.html.erb +0 -1
- data/app/views/alchemy/elements/_claim_view.html.erb +0 -1
- data/app/views/alchemy/elements/_contactform_editor.html.erb +0 -4
- data/app/views/alchemy/elements/_contactform_view.html.erb +0 -78
- data/app/views/alchemy/elements/_download_editor.html.erb +0 -4
- data/app/views/alchemy/elements/_download_view.html.erb +0 -7
- data/app/views/alchemy/elements/_footnote_editor.html.erb +0 -1
- data/app/views/alchemy/elements/_footnote_view.html.erb +0 -5
- data/app/views/alchemy/elements/_header_editor.html.erb +0 -1
- data/app/views/alchemy/elements/_header_view.html.erb +0 -1
- data/app/views/alchemy/elements/_headline_editor.html.erb +0 -1
- data/app/views/alchemy/elements/_image_mosaic_editor.html.erb +0 -3
- data/app/views/alchemy/elements/_image_mosaic_view.html.erb +0 -14
- data/app/views/alchemy/elements/_intro_editor.html.erb +0 -1
- data/app/views/alchemy/elements/_intro_image_text_editor.html.erb +0 -3
- data/app/views/alchemy/elements/_intro_image_text_view.html.erb +0 -16
- data/app/views/alchemy/elements/_intro_view.html.erb +0 -3
- data/app/views/alchemy/elements/_news_editor.html.erb +0 -3
- data/app/views/alchemy/elements/_searchresult_editor.html.erb +0 -4
- data/app/views/alchemy/elements/_sitemap_editor.html.erb +0 -3
- data/app/views/alchemy/elements/_sitemap_view.html.erb +0 -38
- data/app/views/alchemy/elements/_sitename_editor.html.erb +0 -1
- data/app/views/alchemy/elements/_sitename_view.html.erb +0 -1
- data/app/views/alchemy/elements/_subheadline_editor.html.erb +0 -1
- data/app/views/alchemy/elements/_subheadline_view.html.erb +0 -5
- data/app/views/alchemy/elements/_text_editor.html.erb +0 -1
- data/app/views/alchemy/elements/_text_view.html.erb +0 -3
- data/app/views/alchemy/page_layouts/_contact.html.erb +0 -14
- data/app/views/alchemy/page_layouts/_external.html.erb +0 -0
- data/app/views/alchemy/page_layouts/_intro.html.erb +0 -14
- data/app/views/alchemy/page_layouts/_layout_footer.html.erb +0 -14
- data/app/views/alchemy/page_layouts/_layout_header.html.erb +0 -14
- data/app/views/alchemy/page_layouts/_news.html.erb +0 -14
- data/app/views/alchemy/page_layouts/_newsletter_layout.html.erb +0 -1
- data/app/views/alchemy/page_layouts/_search.html.erb +0 -14
- data/app/views/alchemy/pictures/show.gif.flexi +0 -19
- data/app/views/alchemy/pictures/show.jpg.flexi +0 -19
- data/app/views/alchemy/pictures/show.png.flexi +0 -19
- data/app/views/alchemy/pictures/thumbnail.png.flexi +0 -13
- data/app/views/alchemy/pictures/zoom.jpg.flexi +0 -3
- data/app/views/alchemy/pictures/zoom.png.flexi +0 -3
- data/app/views/layouts/alchemy/pages.html.erb +0 -51
- data/config/alchemy/elements.yml +0 -274
- data/config/alchemy/page_layouts.yml +0 -75
- data/config/asset_packages.yml +0 -30
- data/config/initializers/localeapp.rb +0 -9
- data/lib/rails/generators/alchemy/plugin/files/translation.pot +0 -3
- data/lib/rails/generators/alchemy/plugin/files/translation_de.po +0 -3
- data/lib/rails/generators/alchemy/plugin/files/translation_en.po +0 -3
- data/lib/rails/generators/alchemy/plugin/plugin_generator.rb +0 -37
- data/lib/rails/generators/alchemy/plugin/templates/authorization_rules.rb +0 -34
- data/lib/rails/generators/alchemy/plugin/templates/config.yml +0 -30
- data/lib/rails/generators/alchemy/plugin/templates/init.rb +0 -1
- data/lib/rails/generators/alchemy/plugin/templates/plugin.rb +0 -0
- data/lib/rails/generators/alchemy/plugin/templates/routes.rb +0 -10
- data/lib/tasks/fleximage.rake +0 -154
- data/spec/dummy/app/views/layouts/.gitkeep +0 -0
|
@@ -3,8 +3,6 @@ module Alchemy
|
|
|
3
3
|
|
|
4
4
|
include Alchemy::BaseHelper
|
|
5
5
|
include Alchemy::ElementsHelper
|
|
6
|
-
include Alchemy::ElementsBlockHelper
|
|
7
|
-
include Alchemy::UrlHelper
|
|
8
6
|
|
|
9
7
|
def render_classes(classes=[])
|
|
10
8
|
s = classes.uniq.delete_if { |x| x.blank? }.join(" ")
|
|
@@ -445,19 +443,41 @@ module Alchemy
|
|
|
445
443
|
javascript_include_tag("alchemy/preview") if @preview_mode
|
|
446
444
|
end
|
|
447
445
|
|
|
448
|
-
# Renders
|
|
446
|
+
# Renders a search form
|
|
447
|
+
#
|
|
448
|
+
# It queries the controller and then redirects to the search result page.
|
|
449
|
+
#
|
|
450
|
+
# === Example search results page layout
|
|
451
|
+
#
|
|
452
|
+
# Only performs the search if ferret is enabled in your +config/alchemy/config.yml+ and
|
|
453
|
+
# a page is present that is flagged with +searchresults+ true.
|
|
454
|
+
#
|
|
455
|
+
# # config/alchemy/page_layouts.yml
|
|
456
|
+
# - name: search
|
|
457
|
+
# searchresults: true # Flag as search result page
|
|
458
|
+
#
|
|
459
|
+
# === Note
|
|
460
|
+
#
|
|
461
|
+
# The search result page will not be cached.
|
|
462
|
+
#
|
|
463
|
+
# @option options html5 [Boolean] (true) Should the search form be of type search or not?
|
|
464
|
+
# @option options class [String] (fulltext_search) The default css class of the form
|
|
465
|
+
# @option options id [String] (search) The default css id of the form
|
|
466
|
+
#
|
|
449
467
|
def render_search_form(options={})
|
|
450
468
|
default_options = {
|
|
451
|
-
:html5 => false
|
|
469
|
+
:html5 => false,
|
|
470
|
+
:class => 'fulltext_search',
|
|
471
|
+
:id => 'search'
|
|
452
472
|
}
|
|
453
|
-
|
|
454
|
-
warning("No search result page found")
|
|
455
|
-
return
|
|
456
|
-
end
|
|
457
|
-
render :partial => 'alchemy/search/form', :locals => {:options => default_options.merge(options)}
|
|
473
|
+
render :partial => 'alchemy/search/form', :locals => {:options => default_options.merge(options), :search_result_page => find_search_result_page}
|
|
458
474
|
end
|
|
459
475
|
|
|
460
|
-
# Renders the search
|
|
476
|
+
# Renders the search results partial within +app/views/alchemy/search/_results.html+
|
|
477
|
+
#
|
|
478
|
+
# @option options show_result_count [Boolean] (true) Should the count of results be displayed or not?
|
|
479
|
+
# @option options show_heading [Boolean] (true) Should the heading be displayed or not?
|
|
480
|
+
#
|
|
461
481
|
def render_search_results(options={})
|
|
462
482
|
default_options = {
|
|
463
483
|
:show_result_count => true,
|
|
@@ -76,6 +76,7 @@ module Alchemy
|
|
|
76
76
|
|
|
77
77
|
# Returns the correct params-hash for passing to show_page_path
|
|
78
78
|
def show_page_path_params(page, optional_params={})
|
|
79
|
+
raise ArgumentError, 'Page is nil' if page.nil?
|
|
79
80
|
url_params = {:level1 => nil, :level2 => nil, :level3 => nil, :urlname => page.urlname}
|
|
80
81
|
url_params.update(optional_params)
|
|
81
82
|
url_params.update(params_for_nested_url(page)) if configuration(:url_nesting)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Alchemy
|
|
2
2
|
class Element < ActiveRecord::Base
|
|
3
3
|
|
|
4
|
-
FORBIDDEN_DEFINITION_ATTRIBUTES = %w(contents available_contents amount picture_gallery taggable)
|
|
4
|
+
FORBIDDEN_DEFINITION_ATTRIBUTES = %w(contents available_contents amount picture_gallery taggable hint)
|
|
5
5
|
SKIPPED_ATTRIBUTES_ON_COPY = %w(id position folded created_at updated_at creator_id updater_id cached_tag_list)
|
|
6
6
|
|
|
7
7
|
acts_as_taggable
|
|
@@ -12,7 +12,6 @@ module Alchemy
|
|
|
12
12
|
:folded,
|
|
13
13
|
:name,
|
|
14
14
|
:page_id,
|
|
15
|
-
:position,
|
|
16
15
|
:public,
|
|
17
16
|
:tag_list,
|
|
18
17
|
:unique
|
|
@@ -29,6 +28,7 @@ module Alchemy
|
|
|
29
28
|
|
|
30
29
|
validates_uniqueness_of :position, :scope => [:page_id, :cell_id], :if => lambda { |e| e.position != nil }
|
|
31
30
|
validates_presence_of :name, :on => :create
|
|
31
|
+
validates_format_of :name, :on => :create, :with => /\A[a-z0-9_-]+\z/
|
|
32
32
|
|
|
33
33
|
attr_accessor :create_contents_after_create
|
|
34
34
|
|
|
@@ -37,6 +37,7 @@ module Alchemy
|
|
|
37
37
|
scope :trashed, where(:position => nil).order('updated_at DESC')
|
|
38
38
|
scope :not_trashed, where(Element.arel_table[:position].not_eq(nil))
|
|
39
39
|
scope :published, where(:public => true)
|
|
40
|
+
scope :not_restricted, joins(:page).where("alchemy_pages" => {:restricted => false})
|
|
40
41
|
scope :available, published.not_trashed
|
|
41
42
|
scope :named, lambda { |names| where(:name => names) }
|
|
42
43
|
scope :excluded, lambda { |names| where(arel_table[:name].not_in(names)) }
|
|
@@ -510,6 +511,50 @@ module Alchemy
|
|
|
510
511
|
description['taggable'] == true
|
|
511
512
|
end
|
|
512
513
|
|
|
514
|
+
def to_partial_path
|
|
515
|
+
"alchemy/elements/#{name}_view"
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
# Returns the hint for this element
|
|
519
|
+
#
|
|
520
|
+
# To add a hint to an element either pass +hint: true+ to the element definition in its element.yml
|
|
521
|
+
#
|
|
522
|
+
# Then the hint itself is placed in the locale yml files.
|
|
523
|
+
#
|
|
524
|
+
# Alternativly you can pass the hint itself to the hint key.
|
|
525
|
+
#
|
|
526
|
+
# == Locale Example:
|
|
527
|
+
#
|
|
528
|
+
# # elements.yml
|
|
529
|
+
# - name: headline
|
|
530
|
+
# hint: true
|
|
531
|
+
#
|
|
532
|
+
# # config/locales/de.yml
|
|
533
|
+
# de:
|
|
534
|
+
# element_hints:
|
|
535
|
+
# headline: Lorem ipsum
|
|
536
|
+
#
|
|
537
|
+
# == Hint Key Example:
|
|
538
|
+
#
|
|
539
|
+
# - name: headline
|
|
540
|
+
# hint: "Lorem ipsum"
|
|
541
|
+
#
|
|
542
|
+
# @return String
|
|
543
|
+
#
|
|
544
|
+
def hint
|
|
545
|
+
hint = definition['hint']
|
|
546
|
+
if hint == true
|
|
547
|
+
I18n.t(name, scope: :element_hints)
|
|
548
|
+
else
|
|
549
|
+
hint
|
|
550
|
+
end
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
# Returns true if the element has a hint
|
|
554
|
+
def has_hint?
|
|
555
|
+
hint.present?
|
|
556
|
+
end
|
|
557
|
+
|
|
513
558
|
private
|
|
514
559
|
|
|
515
560
|
# creates the contents for this element as described in the elements.yml
|
|
@@ -9,17 +9,19 @@ module Alchemy
|
|
|
9
9
|
:public,
|
|
10
10
|
:default,
|
|
11
11
|
:country_code,
|
|
12
|
-
:code
|
|
12
|
+
:code,
|
|
13
|
+
:site
|
|
13
14
|
)
|
|
14
15
|
|
|
15
16
|
validates_presence_of :name
|
|
16
17
|
validates_presence_of :language_code
|
|
17
18
|
validates_presence_of :page_layout
|
|
18
19
|
validates_presence_of :frontpage_name
|
|
19
|
-
validates_uniqueness_of :language_code, :scope => :country_code
|
|
20
|
+
validates_uniqueness_of :language_code, :scope => [:site_id, :country_code]
|
|
20
21
|
validate :presence_of_default_language
|
|
21
22
|
validate :publicity_of_default_language
|
|
22
23
|
has_many :pages
|
|
24
|
+
belongs_to :site
|
|
23
25
|
after_destroy :delete_language_root_page
|
|
24
26
|
validates_format_of :language_code, :with => /^[a-z]{2}$/, :if => proc { language_code.present? }
|
|
25
27
|
validates_format_of :country_code, :with => /^[a-z]{2}$/, :if => proc { country_code.present? }
|
|
@@ -30,18 +32,29 @@ module Alchemy
|
|
|
30
32
|
|
|
31
33
|
scope :published, where(:public => true)
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
# multi-site support
|
|
36
|
+
scope :on_site, lambda { |s| s.present? ? where(site_id: s) : scoped }
|
|
37
|
+
default_scope { on_site(Site.current) }
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
class << self
|
|
40
|
+
|
|
41
|
+
# Returns all languages for which a language root page exists.
|
|
42
|
+
def all_for_created_language_trees
|
|
43
|
+
# don't use 'find' here as it would clash with our default_scopes
|
|
44
|
+
# in various unholy ways you don't want to find out about.
|
|
45
|
+
where(id: Page.language_roots.collect(&:language_id))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def all_codes_for_published
|
|
49
|
+
published.collect(&:code)
|
|
50
|
+
rescue
|
|
51
|
+
[]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def get_default
|
|
55
|
+
where(default: true).first
|
|
56
|
+
end
|
|
42
57
|
|
|
43
|
-
def self.get_default
|
|
44
|
-
self.find_by_default(true)
|
|
45
58
|
end
|
|
46
59
|
|
|
47
60
|
def label(attrib)
|
|
@@ -54,7 +67,7 @@ module Alchemy
|
|
|
54
67
|
|
|
55
68
|
include Code
|
|
56
69
|
|
|
57
|
-
|
|
70
|
+
private
|
|
58
71
|
|
|
59
72
|
def publicity_of_default_language
|
|
60
73
|
if self.default? && !self.public?
|
|
@@ -75,7 +88,7 @@ module Alchemy
|
|
|
75
88
|
end
|
|
76
89
|
|
|
77
90
|
def remove_old_default
|
|
78
|
-
lang = Language.get_default
|
|
91
|
+
lang = Language.on_site(site).get_default
|
|
79
92
|
return true if lang.nil?
|
|
80
93
|
lang.default = false
|
|
81
94
|
lang.save(:validate => false)
|
data/app/models/alchemy/page.rb
CHANGED
|
@@ -28,7 +28,6 @@ module Alchemy
|
|
|
28
28
|
:name,
|
|
29
29
|
:page_layout,
|
|
30
30
|
:parent_id,
|
|
31
|
-
:position,
|
|
32
31
|
:public,
|
|
33
32
|
:restricted,
|
|
34
33
|
:robot_index,
|
|
@@ -52,6 +51,7 @@ module Alchemy
|
|
|
52
51
|
has_and_belongs_to_many :to_be_sweeped_elements, :class_name => 'Alchemy::Element', :uniq => true, :join_table => 'alchemy_elements_alchemy_pages'
|
|
53
52
|
belongs_to :language
|
|
54
53
|
|
|
54
|
+
validates_presence_of :language, :on => :create, :unless => :root
|
|
55
55
|
validates_presence_of :name
|
|
56
56
|
validates_presence_of :page_layout, :unless => :systempage?
|
|
57
57
|
validates_presence_of :parent_id, :if => proc { Page.count > 1 }
|
|
@@ -6,27 +6,28 @@ module Alchemy
|
|
|
6
6
|
has_many :elements, :through => :contents
|
|
7
7
|
has_many :pages, :through => :elements
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
# Raise error, if picture is in use (aka. assigned to an EssencePicture)
|
|
10
|
+
#
|
|
11
|
+
# === CAUTION:
|
|
12
|
+
# This HAS to be placed for Dragonfly's class methods, to ensure this runs before Dragonfly's before_destroy callback.
|
|
13
|
+
#
|
|
14
|
+
before_destroy :unless => :deletable? do
|
|
15
|
+
raise PictureInUseError, I18n.t(:cannot_delete_picture_notice) % { :name => name }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
image_accessor :image_file do
|
|
19
|
+
if Config.get(:preprocess_image_resize).present?
|
|
20
|
+
after_assign { |a| a.process!(:resize, Config.get(:preprocess_image_resize)) }
|
|
20
21
|
end
|
|
21
22
|
end
|
|
22
23
|
|
|
24
|
+
validates_presence_of :image_file
|
|
25
|
+
validates_property :format, :of => :image_file, :in => Config.get('uploader')['allowed_filetypes']['pictures'].map(&:to_sym), :message => I18n.t("not a valid image")
|
|
26
|
+
|
|
23
27
|
acts_as_taggable
|
|
24
28
|
|
|
25
29
|
attr_accessible(
|
|
26
30
|
:image_file,
|
|
27
|
-
:image_filename,
|
|
28
|
-
:image_height,
|
|
29
|
-
:image_width,
|
|
30
31
|
:name,
|
|
31
32
|
:tag_list,
|
|
32
33
|
:upload_hash
|
|
@@ -35,6 +36,7 @@ module Alchemy
|
|
|
35
36
|
stampable(:stamper_class_name => 'Alchemy::User')
|
|
36
37
|
|
|
37
38
|
scope :recent, where("#{self.table_name}.created_at > ?", Time.now-24.hours).order(:created_at)
|
|
39
|
+
scope :deletable, where("alchemy_pictures.id NOT IN (SELECT picture_id FROM alchemy_essence_pictures)")
|
|
38
40
|
|
|
39
41
|
def self.find_paginated(params, per_page)
|
|
40
42
|
Picture.where("name LIKE ?", "%#{params[:query]}%").page(params[:page] || 1).per(per_page).order(:name)
|
|
@@ -60,32 +62,31 @@ module Alchemy
|
|
|
60
62
|
end
|
|
61
63
|
|
|
62
64
|
def suffix
|
|
63
|
-
|
|
64
|
-
image_filename.split('.').last.downcase
|
|
65
|
-
else
|
|
66
|
-
""
|
|
67
|
-
end
|
|
65
|
+
image_file.ext
|
|
68
66
|
end
|
|
69
67
|
|
|
70
68
|
def humanized_name
|
|
71
|
-
return "" if
|
|
72
|
-
(
|
|
69
|
+
return "" if image_file_name.blank?
|
|
70
|
+
(image_file_name.downcase.gsub(/\.#{::Regexp.quote(suffix)}$/, '')).humanize
|
|
73
71
|
end
|
|
74
72
|
|
|
75
73
|
# Returning true if picture's width is greater than it's height
|
|
76
74
|
def landscape_format?
|
|
77
|
-
|
|
75
|
+
image_file.landscape?
|
|
78
76
|
end
|
|
77
|
+
alias_method :landscape?, :landscape_format?
|
|
79
78
|
|
|
80
79
|
# Returning true if picture's width is smaller than it's height
|
|
81
80
|
def portrait_format?
|
|
82
|
-
|
|
81
|
+
image_file.portrait?
|
|
83
82
|
end
|
|
83
|
+
alias_method :portrait?, :portrait_format?
|
|
84
84
|
|
|
85
85
|
# Returning true if picture's width and height is equal
|
|
86
86
|
def square_format?
|
|
87
|
-
|
|
87
|
+
image_file.aspect_ratio == 1.0
|
|
88
88
|
end
|
|
89
|
+
alias_method :square?, :square_format?
|
|
89
90
|
|
|
90
91
|
# Returns the default centered image mask for a given size
|
|
91
92
|
def default_mask(size)
|
|
@@ -93,24 +94,24 @@ module Alchemy
|
|
|
93
94
|
width = size.split('x')[0].to_i
|
|
94
95
|
height = size.split('x')[1].to_i
|
|
95
96
|
if (width > height)
|
|
96
|
-
zoom_factor =
|
|
97
|
+
zoom_factor = image_file_width.to_f / width
|
|
97
98
|
mask_height = (height * zoom_factor).round
|
|
98
99
|
x1 = 0
|
|
99
|
-
x2 =
|
|
100
|
-
y1 = (
|
|
100
|
+
x2 = image_file_width
|
|
101
|
+
y1 = (image_file_height - mask_height) / 2
|
|
101
102
|
y2 = y1 + mask_height
|
|
102
103
|
elsif (width == 0 && height == 0)
|
|
103
104
|
x1 = 0
|
|
104
|
-
x2 =
|
|
105
|
+
x2 = image_file_width
|
|
105
106
|
y1 = 0
|
|
106
|
-
y2 =
|
|
107
|
+
y2 = image_file_height
|
|
107
108
|
else
|
|
108
|
-
zoom_factor =
|
|
109
|
+
zoom_factor = image_file_height.to_f / height
|
|
109
110
|
mask_width = (width * zoom_factor).round
|
|
110
|
-
x1 = (
|
|
111
|
+
x1 = (image_file_width - mask_width) / 2
|
|
111
112
|
x2 = x1 + mask_width
|
|
112
113
|
y1 = 0
|
|
113
|
-
y2 =
|
|
114
|
+
y2 = image_file_height
|
|
114
115
|
end
|
|
115
116
|
{
|
|
116
117
|
:x1 => x1,
|
|
@@ -141,6 +142,14 @@ module Alchemy
|
|
|
141
142
|
pages.any? && pages.not_restricted.blank?
|
|
142
143
|
end
|
|
143
144
|
|
|
145
|
+
def deletable?
|
|
146
|
+
!essence_pictures.any?
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def image_file_dimensions
|
|
150
|
+
"#{image_file_width} x #{image_file_height}"
|
|
151
|
+
end
|
|
152
|
+
|
|
144
153
|
# Returns a security token for signed picture rendering requests.
|
|
145
154
|
#
|
|
146
155
|
# Pass a params hash containing:
|
|
@@ -149,21 +158,17 @@ module Alchemy
|
|
|
149
158
|
# crop [Boolean] (Optional)
|
|
150
159
|
# crop_from [String] (Optional)
|
|
151
160
|
# crop_size [String] (Optional)
|
|
161
|
+
# quality [Integer] (Optional)
|
|
152
162
|
#
|
|
153
163
|
# to sign them.
|
|
154
164
|
#
|
|
155
165
|
def security_token(params = {})
|
|
156
166
|
@params = params.stringify_keys
|
|
157
|
-
@params.update({'crop' => @params['crop'] ? 'crop' : nil})
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
private
|
|
162
|
-
|
|
163
|
-
def secured_params
|
|
164
|
-
secret = Rails.configuration.secret_token
|
|
165
|
-
[id, @params['size'], @params['crop'], @params['crop_from'], @params['crop_size'], secret].join('-')
|
|
167
|
+
@params.update({'crop' => @params['crop'] ? 'crop' : nil, 'id' => self.id})
|
|
168
|
+
@params.delete_if { |k,v| v.nil? }
|
|
169
|
+
PictureAttributes.secure(@params)
|
|
166
170
|
end
|
|
167
171
|
|
|
168
172
|
end
|
|
173
|
+
class PictureInUseError < StandardError; end
|
|
169
174
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Alchemy
|
|
2
|
+
class Site < ActiveRecord::Base
|
|
3
|
+
cattr_accessor :current
|
|
4
|
+
|
|
5
|
+
attr_accessible :host, :name, :public
|
|
6
|
+
|
|
7
|
+
# validations
|
|
8
|
+
validates_presence_of :host
|
|
9
|
+
validates_uniqueness_of :host
|
|
10
|
+
|
|
11
|
+
# associations
|
|
12
|
+
has_many :languages
|
|
13
|
+
|
|
14
|
+
scope :published, where(public: true)
|
|
15
|
+
|
|
16
|
+
# Returns true if this site is the current site
|
|
17
|
+
def current?
|
|
18
|
+
self.class.current == self
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class << self
|
|
22
|
+
def default
|
|
23
|
+
Site.first
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
before_create do
|
|
28
|
+
# If no languages are present, create a default language based
|
|
29
|
+
# on the host app's Alchemy configuration.
|
|
30
|
+
|
|
31
|
+
if languages.empty?
|
|
32
|
+
default_language = Alchemy::Config.get(:default_language)
|
|
33
|
+
languages.build(
|
|
34
|
+
name: default_language['name'],
|
|
35
|
+
language_code: default_language['code'],
|
|
36
|
+
frontpage_name: default_language['frontpage_name'],
|
|
37
|
+
page_layout: default_language['page_layout'],
|
|
38
|
+
public: true,
|
|
39
|
+
default: true
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|