refactor the way the middlewares are loaded (both app and engine) + tweaks some back-office texts + improve the UI by adding icons on addind a picture links + fix an annoying bug with carrierwave
This commit is contained in:
commit
5e8eac53d4
9
Gemfile
9
Gemfile
@ -4,7 +4,7 @@ source :rubygems
|
||||
|
||||
gem 'rake', '0.8.7'
|
||||
|
||||
gem 'rails', '>= 3.0.8'
|
||||
gem 'rails', '3.0.9'
|
||||
|
||||
gem 'warden'
|
||||
gem 'devise', '1.3.4'
|
||||
@ -21,9 +21,12 @@ gem 'formtastic', '~> 1.2.3'
|
||||
gem 'inherited_resources', '~> 1.1.2'
|
||||
|
||||
gem 'rmagick', '2.12.2'
|
||||
gem 'locomotive_carrierwave', '0.5.4.beta2'
|
||||
gem 'locomotive_carrierwave', '0.5.4.beta3'
|
||||
gem 'dragonfly', '~> 0.9.1'
|
||||
gem 'rack-cache', :require => 'rack/cache'
|
||||
|
||||
gem 'custom_fields', '1.0.0.beta.18'
|
||||
gem 'custom_fields', '1.0.0.beta.19'
|
||||
gem 'cancan'
|
||||
gem 'fog', '0.8.2'
|
||||
gem 'mimetype-fu'
|
||||
gem 'actionmailer-with-request', :require => 'actionmailer_with_request'
|
||||
|
28
Gemfile.lock
28
Gemfile.lock
@ -62,6 +62,7 @@ GEM
|
||||
highline (>= 1.6.1)
|
||||
json (>= 1.4.6)
|
||||
rest-client (>= 1.6.1)
|
||||
cancan (1.6.5)
|
||||
capybara (0.4.1.2)
|
||||
celerity (>= 0.7.9)
|
||||
culerity (>= 0.2.4)
|
||||
@ -86,7 +87,7 @@ GEM
|
||||
cucumber-rails (0.3.2)
|
||||
cucumber (>= 0.8.0)
|
||||
culerity (0.2.15)
|
||||
custom_fields (1.0.0.beta.18)
|
||||
custom_fields (1.0.0.beta.19)
|
||||
activesupport (>= 3.0.7)
|
||||
mongoid (= 2.0.2)
|
||||
daemons (1.1.4)
|
||||
@ -102,6 +103,8 @@ GEM
|
||||
orm_adapter (~> 0.0.3)
|
||||
warden (~> 1.0.3)
|
||||
diff-lcs (1.1.2)
|
||||
dragonfly (0.9.4)
|
||||
rack
|
||||
erubis (2.6.6)
|
||||
abstract (>= 1.0.0)
|
||||
excon (0.6.3)
|
||||
@ -132,7 +135,7 @@ GEM
|
||||
heroku (1.19.1)
|
||||
activesupport (>= 2.1.0)
|
||||
launchy (~> 0.3.2)
|
||||
rest-client (>= 1.4.0, < 1.7.0)
|
||||
rest-client (< 1.7.0, >= 1.4.0)
|
||||
highline (1.6.2)
|
||||
httparty (0.7.8)
|
||||
crack (= 0.1.8)
|
||||
@ -151,7 +154,7 @@ GEM
|
||||
linecache (0.43)
|
||||
linecache19 (0.5.12)
|
||||
ruby_core_source (>= 0.1.4)
|
||||
locomotive_carrierwave (0.5.4.beta2)
|
||||
locomotive_carrierwave (0.5.4.beta3)
|
||||
activesupport (~> 3.0)
|
||||
locomotive_jammit-s3 (0.5.4.4)
|
||||
jammit (>= 0.5.4)
|
||||
@ -176,7 +179,7 @@ GEM
|
||||
tzinfo (~> 0.3.22)
|
||||
net-ssh (2.1.4)
|
||||
nokogiri (1.4.6)
|
||||
open4 (1.0.1)
|
||||
open4 (1.1.0)
|
||||
orm_adapter (0.0.5)
|
||||
pickle (0.4.7)
|
||||
cucumber (>= 0.8)
|
||||
@ -184,6 +187,8 @@ GEM
|
||||
polyglot (0.3.1)
|
||||
proxies (0.2.1)
|
||||
rack (1.2.3)
|
||||
rack-cache (1.0.2)
|
||||
rack (>= 0.4)
|
||||
rack-mount (0.6.14)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (0.5.7)
|
||||
@ -202,6 +207,7 @@ GEM
|
||||
rake (>= 0.8.7)
|
||||
rdoc (~> 3.4)
|
||||
thor (~> 0.14.4)
|
||||
raindrops (0.7.0)
|
||||
rake (0.8.7)
|
||||
rdoc (3.6.1)
|
||||
responders (0.6.4)
|
||||
@ -253,9 +259,10 @@ GEM
|
||||
polyglot (>= 0.3.1)
|
||||
trollop (1.16.2)
|
||||
tzinfo (0.3.28)
|
||||
unicorn (3.7.0)
|
||||
kgio (~> 2.3)
|
||||
unicorn (4.0.0)
|
||||
kgio (~> 2.4)
|
||||
rack
|
||||
raindrops (~> 0.6)
|
||||
warden (1.0.4)
|
||||
rack (>= 1.0)
|
||||
will_paginate (2.3.15)
|
||||
@ -276,14 +283,16 @@ DEPENDENCIES
|
||||
bson_ext (~> 1.3.0)
|
||||
bushido
|
||||
bushido_stub!
|
||||
cancan
|
||||
capybara
|
||||
cucumber (= 0.8.5)
|
||||
cucumber-rails
|
||||
custom_fields (= 1.0.0.beta.18)
|
||||
custom_fields (= 1.0.0.beta.19)
|
||||
database_cleaner
|
||||
delayed_job (= 2.1.4)
|
||||
delayed_job_mongoid (= 1.0.2)
|
||||
devise (= 1.3.4)
|
||||
dragonfly (~> 0.9.1)
|
||||
factory_girl_rails
|
||||
fog (= 0.8.2)
|
||||
formtastic (~> 1.2.3)
|
||||
@ -294,7 +303,7 @@ DEPENDENCIES
|
||||
inherited_resources (~> 1.1.2)
|
||||
launchy
|
||||
linecache (= 0.43)
|
||||
locomotive_carrierwave (= 0.5.4.beta2)
|
||||
locomotive_carrierwave (= 0.5.4.beta3)
|
||||
locomotive_jammit-s3
|
||||
locomotive_liquid (= 2.2.2)
|
||||
locomotive_mongoid_acts_as_tree (= 0.1.5.7)
|
||||
@ -302,7 +311,8 @@ DEPENDENCIES
|
||||
mocha!
|
||||
mongoid (~> 2.0.2)
|
||||
pickle
|
||||
rails (>= 3.0.8)
|
||||
rack-cache
|
||||
rails (= 3.0.9)
|
||||
rake (= 0.8.7)
|
||||
rmagick (= 2.12.2)
|
||||
rspec-rails (= 2.3.1)
|
||||
|
@ -19,7 +19,7 @@ h2. Gems
|
||||
|
||||
Here is a short list of main gems used in the application.
|
||||
|
||||
* Rails 3.0.8
|
||||
* Rails 3.0.9
|
||||
* Mongoid 2.0.2 (with MongoDB 1.6)
|
||||
* Liquid
|
||||
* Devise
|
||||
|
@ -1,25 +0,0 @@
|
||||
module Admin
|
||||
class AssetCollectionsController < BaseController
|
||||
|
||||
sections 'assets'
|
||||
|
||||
before_filter :set_collections
|
||||
|
||||
def index
|
||||
if not @asset_collections.empty?
|
||||
redirect_to(edit_admin_asset_collection_url(@asset_collections.first)) and return
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@asset_collection = current_site.asset_collections.find(params[:id])
|
||||
render :action => 'edit'
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def set_collections
|
||||
@asset_collections = current_site.asset_collections.not_internal.order_by([[:name, :asc]])
|
||||
end
|
||||
end
|
||||
end
|
@ -1,29 +1,55 @@
|
||||
module Admin
|
||||
class AssetsController < BaseController
|
||||
|
||||
sections 'assets'
|
||||
include ActionView::Helpers::SanitizeHelper
|
||||
include ActionView::Helpers::TextHelper
|
||||
|
||||
before_filter :set_collections_and_current_collection
|
||||
respond_to :json, :only => [:index, :create, :destroy]
|
||||
|
||||
respond_to :json, :only => :update
|
||||
|
||||
def create
|
||||
create! { edit_admin_asset_collection_url(@asset_collection) }
|
||||
def index
|
||||
index! do |response|
|
||||
response.json do
|
||||
render :json => { :assets => @assets.collect { |asset| asset_to_json(asset) } }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
update! { edit_admin_asset_collection_url(@asset_collection) }
|
||||
def create
|
||||
@asset = current_site.assets.build(:name => params[:name], :source => params[:file])
|
||||
|
||||
create! do |success, failure|
|
||||
success.json do
|
||||
render :json => asset_to_json(@asset)
|
||||
end
|
||||
failure.json do
|
||||
render :json => { :status => 'error' }
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
render :json => { :status => 'error', :message => e.message }
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def begin_of_association_chain
|
||||
@asset_collection
|
||||
def collection
|
||||
if params[:image]
|
||||
@assets ||= begin_of_association_chain.assets.only_image
|
||||
else
|
||||
@assets ||= begin_of_association_chain.assets
|
||||
end
|
||||
end
|
||||
|
||||
def set_collections_and_current_collection
|
||||
@asset_collections = current_site.asset_collections.not_internal.order_by([[:name, :asc]])
|
||||
@asset_collection = current_site.asset_collections.find(params[:collection_id])
|
||||
def asset_to_json(asset)
|
||||
{
|
||||
:status => 'success',
|
||||
:filename => asset.source_filename,
|
||||
:short_name => truncate(asset.name, :length => 15),
|
||||
:extname => truncate(asset.extname, :length => 3),
|
||||
:content_type => asset.content_type,
|
||||
:url => asset.source.url,
|
||||
:vignette_url => asset.vignette_url,
|
||||
:destroy_url => admin_asset_url(asset, :json)
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -9,11 +9,13 @@ module Admin
|
||||
|
||||
before_filter :require_site
|
||||
|
||||
load_and_authorize_resource
|
||||
|
||||
before_filter :validate_site_membership
|
||||
|
||||
before_filter :set_locale
|
||||
|
||||
helper_method :sections, :current_site_url, :site_url, :page_url
|
||||
helper_method :sections, :current_site_url, :site_url, :page_url, :current_ability
|
||||
|
||||
# https://rails.lighthouseapp.com/projects/8994/tickets/1905-apphelpers-within-plugin-not-being-mixed-in
|
||||
Dir[File.dirname(__FILE__) + "/../../helpers/**/*_helper.rb"].each do |file|
|
||||
@ -26,8 +28,24 @@ module Admin
|
||||
|
||||
respond_to :html
|
||||
|
||||
rescue_from CanCan::AccessDenied do |exception|
|
||||
::Locomotive::Logger.info "[CanCan::AccessDenied] #{exception.inspect}"
|
||||
|
||||
if request.xhr?
|
||||
render :json => { :error => exception.message }
|
||||
else
|
||||
flash[:alert] = exception.message
|
||||
|
||||
redirect_to admin_pages_url
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def current_ability
|
||||
@current_ability ||= Ability.new(current_admin, current_site)
|
||||
end
|
||||
|
||||
def require_admin
|
||||
authenticate_admin!
|
||||
end
|
||||
|
@ -5,7 +5,11 @@ module Admin
|
||||
|
||||
before_filter :set_content_type
|
||||
|
||||
respond_to :json, :only => :update
|
||||
respond_to :json, :only => [:update, :sort]
|
||||
|
||||
skip_load_and_authorize_resource
|
||||
|
||||
before_filter :authorize_content
|
||||
|
||||
def index
|
||||
@contents = @content_type.list_or_group_contents
|
||||
@ -20,7 +24,7 @@ module Admin
|
||||
end
|
||||
|
||||
def sort
|
||||
@content_type.sort_contents!(params[:order])
|
||||
@content_type.sort_contents!(params[:children])
|
||||
|
||||
respond_with(@content_type, :location => admin_contents_url(@content_type.slug))
|
||||
end
|
||||
@ -39,5 +43,9 @@ module Admin
|
||||
set_content_type
|
||||
end
|
||||
|
||||
def authorize_content
|
||||
authorize! params[:action].to_sym, ContentInstance
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -9,6 +9,8 @@ module Admin
|
||||
|
||||
before_filter :require_admin, :only => :new
|
||||
|
||||
skip_load_and_authorize_resource
|
||||
|
||||
def new
|
||||
if site = current_admin.sites.detect { |s| s._id.to_s == params[:target_id] }
|
||||
if Rails.env == 'development'
|
||||
|
@ -7,6 +7,10 @@ module Admin
|
||||
|
||||
actions :edit, :update
|
||||
|
||||
skip_load_and_authorize_resource
|
||||
|
||||
load_and_authorize_resource :class => 'Site'
|
||||
|
||||
respond_to :json, :only => :update
|
||||
|
||||
def update
|
||||
|
@ -5,6 +5,8 @@ module Admin
|
||||
|
||||
before_filter :set_parent_and_fields
|
||||
|
||||
skip_load_and_authorize_resource
|
||||
|
||||
def edit
|
||||
@field = @fields.find(params[:id])
|
||||
render :action => "edit_#{@field.kind.downcase}"
|
||||
@ -23,14 +25,9 @@ module Admin
|
||||
protected
|
||||
|
||||
def set_parent_and_fields
|
||||
if params[:parent] == 'asset_collection'
|
||||
@parent = current_site.asset_collections.where(:slug => params[:slug]).first
|
||||
@fields = @parent.asset_custom_fields
|
||||
else
|
||||
@parent = current_site.content_types.where(:slug => params[:slug]).first
|
||||
@fields = @parent.content_custom_fields
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -1,55 +0,0 @@
|
||||
module Admin
|
||||
class ImagesController < BaseController
|
||||
|
||||
include ActionView::Helpers::SanitizeHelper
|
||||
include ActionView::Helpers::TextHelper
|
||||
|
||||
defaults :collection_name => 'assets', :instance_name => 'asset'
|
||||
|
||||
respond_to :json, :only => [:index, :create, :destroy]
|
||||
|
||||
def index
|
||||
index! do |response|
|
||||
response.json do
|
||||
render :json => { :images => @assets.collect { |image| image_to_json(image) } }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
params[:asset] = { :name => params[:name], :source => params[:file] } if params[:file]
|
||||
|
||||
create! do |success, failure|
|
||||
success.json do
|
||||
render :json => image_to_json(@asset)
|
||||
end
|
||||
failure.json do
|
||||
render :json => { :status => 'error' }
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
render :json => { :status => 'error', :message => e.message }
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def collection
|
||||
@assets ||= begin_of_association_chain.assets
|
||||
end
|
||||
|
||||
def begin_of_association_chain
|
||||
@asset_collection ||= AssetCollection.find_or_create_internal(current_site)
|
||||
end
|
||||
|
||||
def image_to_json(image)
|
||||
{
|
||||
:status => 'success',
|
||||
:name => truncate(image.name, :length => 15),
|
||||
:url => image.source.url,
|
||||
:vignette_url => image.vignette_url,
|
||||
:destroy_url => admin_image_url(image, :json)
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -5,6 +5,10 @@ module Admin
|
||||
|
||||
actions :show, :new, :create
|
||||
|
||||
skip_load_and_authorize_resource
|
||||
|
||||
before_filter :authorize_import
|
||||
|
||||
def show
|
||||
@job = Delayed::Job.where({ :job_type => 'import', :site_id => current_site.id }).last
|
||||
|
||||
@ -41,5 +45,11 @@ module Admin
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def authorize_import
|
||||
authorize! :import, Site
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -15,6 +15,8 @@ module Admin
|
||||
|
||||
before_filter :allow_installation?
|
||||
|
||||
skip_load_and_authorize_resource
|
||||
|
||||
def show
|
||||
request.get? ? self.handle_get : self.handle_post
|
||||
end
|
||||
|
@ -7,6 +7,8 @@ module Admin
|
||||
|
||||
respond_to :json, :only => :update
|
||||
|
||||
skip_load_and_authorize_resource
|
||||
|
||||
def update
|
||||
update! { edit_admin_my_account_url }
|
||||
end
|
||||
|
@ -33,7 +33,7 @@ module Admin
|
||||
end
|
||||
|
||||
def get_path
|
||||
page = current_site.pages.build(:parent => current_site.pages.find(params[:parent_id]), :slug => params[:slug].slugify)
|
||||
page = current_site.pages.build(:parent => current_site.pages.find(params[:parent_id]), :slug => params[:slug].permalink)
|
||||
|
||||
render :json => { :url => page_url(page), :slug => page.slug }
|
||||
end
|
||||
|
@ -7,6 +7,8 @@ module Admin
|
||||
|
||||
respond_to :xml
|
||||
|
||||
skip_load_and_authorize_resource
|
||||
|
||||
def show
|
||||
@pages = current_site.pages.published
|
||||
end
|
||||
|
@ -49,8 +49,8 @@ module Admin
|
||||
def sanitize_params
|
||||
params[:theme_asset] = { :source => params[:file] } if params[:file]
|
||||
|
||||
performing_plain_text = params[:theme_asset][:performing_plain_text]
|
||||
params[:theme_asset].delete(:content_type) if performing_plain_text.blank? || performing_plain_text == 'false'
|
||||
# performing_plain_text = params[:theme_asset][:performing_plain_text]
|
||||
# params[:theme_asset].delete(:content_type) if performing_plain_text.blank? || performing_plain_text == 'false'
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
module Admin::AccountsHelper
|
||||
|
||||
def admin_on?(site = current_site)
|
||||
site.memberships.detect { |a| a.admin? && a.account == current_admin }
|
||||
site.memberships.detect { |m| m.admin? && m.account == current_admin }
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -45,15 +45,43 @@ module Admin::CustomFieldsHelper
|
||||
end.compact
|
||||
end
|
||||
|
||||
def options_for_has_one(field)
|
||||
target_contents_from_field(field).collect { |c| [c._label, c._id] }
|
||||
def options_for_has_one(field, value)
|
||||
self.options_for_has_one_or_has_many(field) do |groups|
|
||||
grouped_options_for_select(groups.collect do |g|
|
||||
if g[:items].empty?
|
||||
nil
|
||||
else
|
||||
[g[:name], g[:items].collect { |c| [c._label, c._id] }]
|
||||
end
|
||||
end.compact, value)
|
||||
end
|
||||
end
|
||||
|
||||
alias :options_for_has_many :options_for_has_one
|
||||
def options_for_has_many(field)
|
||||
self.options_for_has_one_or_has_many(field)
|
||||
end
|
||||
|
||||
def target_contents_from_field(field)
|
||||
def options_for_has_one_or_has_many(field, &block)
|
||||
content_type = field.target.constantize._parent
|
||||
content_type.ordered_contents
|
||||
|
||||
if content_type.groupable?
|
||||
grouped_contents = content_type.list_or_group_contents
|
||||
|
||||
if block_given?
|
||||
block.call(grouped_contents)
|
||||
else
|
||||
grouped_contents.collect do |g|
|
||||
if g[:items].empty?
|
||||
nil
|
||||
else
|
||||
{ :name => g[:name], :items => g[:items].collect { |c| [c._label, c._id] } }
|
||||
end
|
||||
end.compact
|
||||
end
|
||||
else
|
||||
contents = content_type.ordered_contents
|
||||
contents.collect { |c| [c._label, c._id] }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
66
app/models/ability.rb
Normal file
66
app/models/ability.rb
Normal file
@ -0,0 +1,66 @@
|
||||
class Ability
|
||||
include CanCan::Ability
|
||||
|
||||
ROLES = %w(admin designer author)
|
||||
|
||||
def initialize(account, site)
|
||||
@account, @site = account, site
|
||||
|
||||
alias_action :index, :show, :edit, :update, :to => :touch
|
||||
|
||||
@membership = @site.memberships.where(:account_id => @account.id).first
|
||||
|
||||
return false if @membership.blank?
|
||||
|
||||
if @membership.admin?
|
||||
setup_admin_permissions!
|
||||
else
|
||||
setup_default_permissions!
|
||||
|
||||
setup_designer_permissions! if @membership.designer?
|
||||
|
||||
setup_author_permissions! if @membership.author?
|
||||
end
|
||||
end
|
||||
|
||||
def setup_default_permissions!
|
||||
cannot :manage, :all
|
||||
end
|
||||
|
||||
def setup_author_permissions!
|
||||
can :touch, [Page, ThemeAsset]
|
||||
can :sort, Page
|
||||
|
||||
can :manage, [ContentInstance, Asset]
|
||||
|
||||
can :touch, Site do |site|
|
||||
site == @site
|
||||
end
|
||||
end
|
||||
|
||||
def setup_designer_permissions!
|
||||
can :manage, Page
|
||||
|
||||
can :manage, ContentInstance
|
||||
|
||||
can :manage, ContentType
|
||||
|
||||
can :manage, Snippet
|
||||
|
||||
can :manage, ThemeAsset
|
||||
|
||||
can :manage, Site do |site|
|
||||
site == @site
|
||||
end
|
||||
|
||||
can :import, Site
|
||||
|
||||
can :point, Site
|
||||
|
||||
can :manage, Membership
|
||||
end
|
||||
|
||||
def setup_admin_permissions!
|
||||
can :manage, :all
|
||||
end
|
||||
end
|
@ -3,12 +3,11 @@ class Asset
|
||||
include Mongoid::Document
|
||||
include Mongoid::Timestamps
|
||||
|
||||
## Extensions ##
|
||||
## extensions ##
|
||||
include Extensions::Asset::Types
|
||||
include Extensions::Asset::Vignette
|
||||
include CustomFields::ProxyClassEnabler
|
||||
|
||||
## fields ##
|
||||
field :name, :type => String
|
||||
field :content_type, :type => String
|
||||
field :width, :type => Integer
|
||||
field :height, :type => Integer
|
||||
@ -17,32 +16,24 @@ class Asset
|
||||
mount_uploader :source, AssetUploader
|
||||
|
||||
## associations ##
|
||||
embedded_in :collection, :class_name => 'AssetCollection', :inverse_of => :assets
|
||||
referenced_in :site
|
||||
|
||||
## validations ##
|
||||
validates_presence_of :name, :source
|
||||
validates_presence_of :source
|
||||
|
||||
## behaviours ##
|
||||
|
||||
## methods ##
|
||||
|
||||
%w{image stylesheet javascript pdf media}.each do |type|
|
||||
define_method("#{type}?") do
|
||||
self.content_type.to_s == type
|
||||
end
|
||||
end
|
||||
alias :name :source_filename
|
||||
|
||||
def extname
|
||||
return nil unless self.source?
|
||||
File.extname(self.source_filename).gsub(/^\./, '')
|
||||
end
|
||||
|
||||
def site_id # needed by the uploader of custom fields
|
||||
self.collection.site_id
|
||||
end
|
||||
|
||||
def to_liquid
|
||||
Locomotive::Liquid::Drops::Asset.new(self)
|
||||
{ :url => self.source.url }.merge(self.attributes).stringify_keys
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,81 +0,0 @@
|
||||
class AssetCollection
|
||||
|
||||
include Locomotive::Mongoid::Document
|
||||
|
||||
## fields ##
|
||||
field :name
|
||||
field :slug
|
||||
field :internal, :type => Boolean, :default => false
|
||||
|
||||
## associations ##
|
||||
referenced_in :site
|
||||
embeds_many :assets, :validate => false
|
||||
|
||||
## behaviours ##
|
||||
custom_fields_for :assets
|
||||
liquid_methods :name, :ordered_assets
|
||||
|
||||
## callbacks ##
|
||||
before_validation :normalize_slug
|
||||
before_save :store_asset_positions!
|
||||
after_destroy :remove_uploaded_files
|
||||
|
||||
## validations ##
|
||||
validates_presence_of :site, :name, :slug
|
||||
validates_uniqueness_of :slug, :scope => :site_id
|
||||
|
||||
## named scopes ##
|
||||
scope :internal, :where => { :internal => true }
|
||||
scope :not_internal, :where => { :internal => false }
|
||||
|
||||
## methods ##
|
||||
|
||||
def ordered_assets
|
||||
self.assets.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
|
||||
end
|
||||
|
||||
def assets_order
|
||||
self.ordered_assets.collect(&:id).join(',')
|
||||
end
|
||||
|
||||
def assets_order=(order)
|
||||
@assets_order = order
|
||||
end
|
||||
|
||||
def self.find_or_create_internal(site)
|
||||
site.asset_collections.internal.first || site.asset_collections.create(:name => 'system', :slug => 'system', :internal => true)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def normalize_slug
|
||||
self.slug = self.name.clone if self.slug.blank? && self.name.present?
|
||||
self.slug.slugify! if self.slug.present?
|
||||
end
|
||||
|
||||
def store_asset_positions!
|
||||
return if @assets_order.nil?
|
||||
|
||||
ids = @assets_order.split(',').collect { |id| BSON::ObjectId(id) }
|
||||
|
||||
ids.each_with_index do |asset_id, index|
|
||||
self.assets.find(asset_id).position = index
|
||||
end
|
||||
|
||||
self.assets.clone.each do |asset|
|
||||
if !ids.include?(asset._id)
|
||||
self.assets.delete(asset)
|
||||
asset.send(:delete)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def remove_uploaded_files # callbacks are not called on each asset so we do it manually
|
||||
self.assets.each do |asset|
|
||||
self.asset_custom_fields.each do |field|
|
||||
asset.send(:"remove_#{field._name}!") if field.kind == 'file'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -14,12 +14,14 @@ class ContentInstance
|
||||
|
||||
## validations ##
|
||||
validate :require_highlighted_field
|
||||
validate :validate_uniqueness_of_slug
|
||||
validates_presence_of :_slug
|
||||
|
||||
## associations ##
|
||||
embedded_in :content_type, :inverse_of => :contents
|
||||
|
||||
## callbacks ##
|
||||
before_save :set_slug
|
||||
before_validation :set_slug
|
||||
before_save :set_visibility
|
||||
before_create :add_to_list_bottom
|
||||
after_create :send_notifications
|
||||
@ -67,8 +69,8 @@ class ContentInstance
|
||||
protected
|
||||
|
||||
def set_slug
|
||||
_alias = self.highlighted_field_alias
|
||||
self._slug = self.send(_alias).parameterize('_')
|
||||
self._slug = self.highlighted_field_value.clone if self._slug.blank? && self.highlighted_field_value.present?
|
||||
self._slug.permalink! if self._slug.present?
|
||||
end
|
||||
|
||||
def set_visibility
|
||||
@ -77,7 +79,6 @@ class ContentInstance
|
||||
end
|
||||
|
||||
def add_to_list_bottom
|
||||
Rails.logger.debug "add_to_list_bottom"
|
||||
self._position_in_list = self.content_type.contents.size
|
||||
end
|
||||
|
||||
@ -88,6 +89,12 @@ class ContentInstance
|
||||
end
|
||||
end
|
||||
|
||||
def validate_uniqueness_of_slug
|
||||
if self._parent.contents.any? { |c| c._id != self._id && c._slug == self._slug }
|
||||
self.errors.add(:_slug, :taken)
|
||||
end
|
||||
end
|
||||
|
||||
def highlighted_field_alias
|
||||
self.content_type.highlighted_field._alias.to_sym
|
||||
end
|
||||
|
@ -107,8 +107,8 @@ class ContentType
|
||||
self.asc_order? ? list : list.reverse
|
||||
end
|
||||
|
||||
def sort_contents!(order)
|
||||
order.split(',').each_with_index do |id, position|
|
||||
def sort_contents!(ids)
|
||||
ids.each_with_index do |id, position|
|
||||
self.contents.find(BSON::ObjectId(id))._position_in_list = position
|
||||
end
|
||||
self.save
|
||||
@ -131,7 +131,7 @@ class ContentType
|
||||
|
||||
def normalize_slug
|
||||
self.slug = self.name.clone if self.slug.blank? && self.name.present?
|
||||
self.slug.slugify! if self.slug.present?
|
||||
self.slug.permalink! if self.slug.present?
|
||||
end
|
||||
|
||||
def remove_uploaded_files # callbacks are not called on each content so we do it manually
|
||||
|
19
app/models/extensions/asset/types.rb
Normal file
19
app/models/extensions/asset/types.rb
Normal file
@ -0,0 +1,19 @@
|
||||
module Extensions
|
||||
module Asset
|
||||
module Types
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
%w{media image stylesheet javascript font pdf}.each do |type|
|
||||
scope :"only_#{type}", where(:content_type => type)
|
||||
|
||||
define_method("#{type}?") do
|
||||
self.content_type.to_s == type
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -7,7 +7,7 @@ module Extensions
|
||||
if self.width < 80 && self.height < 80
|
||||
self.source.url
|
||||
else
|
||||
self.source.url(:medium)
|
||||
Locomotive::Dragonfly.resize_url(self.source, '80x80#')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -42,14 +42,6 @@ module Extensions
|
||||
@item_parsing_errors.try(:each) { |msg| self.errors.add :item_template, msg }
|
||||
end
|
||||
|
||||
# def item_template
|
||||
# self.read_attribute(:default_item_template) || self.default_item_template
|
||||
# end
|
||||
#
|
||||
# def default_item_template
|
||||
# '{{ content.highlighted_field_value }}'
|
||||
# end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -4,6 +4,7 @@ module Extensions
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
field :seo_title, :type => String
|
||||
field :meta_keywords, :type => String
|
||||
field :meta_description, :type => String
|
||||
end
|
||||
|
@ -6,7 +6,7 @@ module Extensions
|
||||
def create_first_one(attributes)
|
||||
site = self.new(attributes)
|
||||
|
||||
site.memberships.build :account => Account.first, :admin => true
|
||||
site.memberships.build :account => Account.first, :role => 'admin'
|
||||
|
||||
site.save
|
||||
|
||||
|
@ -3,7 +3,8 @@ class Membership
|
||||
include Locomotive::Mongoid::Document
|
||||
|
||||
## fields ##
|
||||
field :admin, :type => Boolean, :default => false
|
||||
# field :admin, :type => Boolean, :default => false
|
||||
field :role, :default => 'author'
|
||||
|
||||
## associations ##
|
||||
referenced_in :account, :validate => false
|
||||
@ -12,8 +13,17 @@ class Membership
|
||||
## validations ##
|
||||
validates_presence_of :account
|
||||
|
||||
## callbacks ##
|
||||
before_save :define_role
|
||||
|
||||
## methods ##
|
||||
|
||||
Ability::ROLES.each do |_role|
|
||||
define_method("#{_role}?") do
|
||||
self.role == _role
|
||||
end
|
||||
end
|
||||
|
||||
def email; @email; end
|
||||
|
||||
def email=(email)
|
||||
@ -36,4 +46,14 @@ class Membership
|
||||
end
|
||||
end
|
||||
|
||||
def ability
|
||||
@ability ||= Ability.new(self.account, self.site)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def define_role
|
||||
self.role = Ability::ROLES.include?(role.downcase) ? role.downcase : Ability::ROLES.first
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -97,7 +97,7 @@ class Page
|
||||
|
||||
def normalize_slug
|
||||
self.slug = self.title.clone if self.slug.blank? && self.title.present?
|
||||
self.slug.slugify!(:without_extension => true) if self.slug.present?
|
||||
self.slug.permalink! if self.slug.present?
|
||||
end
|
||||
|
||||
def set_default_raw_template
|
||||
|
@ -5,17 +5,17 @@ class Site
|
||||
## Extensions ##
|
||||
extend Extensions::Site::SubdomainDomains
|
||||
extend Extensions::Site::FirstInstallation
|
||||
extend Extensions::Site::FirstInstallation
|
||||
include Extensions::Shared::Seo
|
||||
|
||||
## fields ##
|
||||
field :name
|
||||
field :meta_keywords
|
||||
field :meta_description
|
||||
|
||||
## associations ##
|
||||
references_many :pages, :validate => false
|
||||
references_many :snippets, :dependent => :destroy, :validate => false
|
||||
references_many :theme_assets, :dependent => :destroy, :validate => false
|
||||
references_many :asset_collections, :dependent => :destroy, :validate => false
|
||||
references_many :assets, :dependent => :destroy, :validate => false
|
||||
references_many :content_types, :dependent => :destroy, :validate => false
|
||||
embeds_many :memberships
|
||||
|
||||
@ -28,6 +28,7 @@ class Site
|
||||
|
||||
## behaviours ##
|
||||
enable_subdomain_n_domains_if_multi_sites
|
||||
accepts_nested_attributes_for :memberships
|
||||
|
||||
## methods ##
|
||||
|
||||
|
@ -26,7 +26,7 @@ class Snippet
|
||||
def normalize_slug
|
||||
# TODO: refactor it
|
||||
self.slug = self.name.clone if self.slug.blank? && self.name.present?
|
||||
self.slug.slugify!(:without_extension => true, :downcase => true) if self.slug.present?
|
||||
self.slug.permalink! if self.slug.present?
|
||||
end
|
||||
|
||||
def update_templates
|
||||
|
@ -2,6 +2,9 @@ class ThemeAsset
|
||||
|
||||
include Locomotive::Mongoid::Document
|
||||
|
||||
## extensions ##
|
||||
include Extensions::Asset::Types
|
||||
|
||||
## fields ##
|
||||
field :local_path
|
||||
field :content_type
|
||||
@ -35,16 +38,10 @@ class ThemeAsset
|
||||
scope :visible, lambda { |all| all ? {} : { :where => { :hidden => false } } }
|
||||
|
||||
## accessors ##
|
||||
attr_accessor :plain_text_name, :plain_text, :performing_plain_text
|
||||
attr_accessor :plain_text_name, :plain_text, :plain_text_type, :performing_plain_text
|
||||
|
||||
## methods ##
|
||||
|
||||
%w{media image stylesheet javascript font}.each do |type|
|
||||
define_method("#{type}?") do
|
||||
self.content_type.to_s == type
|
||||
end
|
||||
end
|
||||
|
||||
def stylesheet_or_javascript?
|
||||
self.stylesheet? || self.javascript?
|
||||
end
|
||||
@ -77,11 +74,17 @@ class ThemeAsset
|
||||
end
|
||||
end
|
||||
|
||||
def plain_text_type
|
||||
@plain_text_type || (stylesheet_or_javascript? ? self.content_type : nil)
|
||||
end
|
||||
|
||||
def performing_plain_text?
|
||||
Boolean.set(self.performing_plain_text) || false
|
||||
end
|
||||
|
||||
def store_plain_text
|
||||
self.content_type ||= @plain_text_type if self.performing_plain_text?
|
||||
|
||||
data = self.performing_plain_text? ? self.plain_text : self.source.read
|
||||
|
||||
return if !self.stylesheet_or_javascript? || self.plain_text_name.blank? || data.blank?
|
||||
@ -95,7 +98,7 @@ class ThemeAsset
|
||||
end
|
||||
|
||||
def to_liquid
|
||||
{ :url => self.source.url }.merge(self.attributes)
|
||||
{ :url => self.source.url }.merge(self.attributes).stringify_keys
|
||||
end
|
||||
|
||||
def self.all_grouped_by_folder(site, include_all = true)
|
||||
|
@ -2,26 +2,10 @@
|
||||
|
||||
class AssetUploader < CarrierWave::Uploader::Base
|
||||
|
||||
include CarrierWave::RMagick
|
||||
include Locomotive::CarrierWave::Uploader::Asset
|
||||
|
||||
version :thumb, :if => :image? do
|
||||
process :resize_to_fill => [50, 50]
|
||||
process :convert => 'png'
|
||||
end
|
||||
|
||||
version :medium, :if => :image? do
|
||||
process :resize_to_fill => [80, 80]
|
||||
process :convert => 'png'
|
||||
end
|
||||
|
||||
version :preview, :if => :image? do
|
||||
process :resize_to_fit => [880, 1100]
|
||||
process :convert => 'png'
|
||||
end
|
||||
|
||||
def store_dir
|
||||
self.build_store_dir('sites', model.collection.site_id, 'assets', model.id)
|
||||
self.build_store_dir('sites', model.site_id, 'assets', model.id)
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,36 +0,0 @@
|
||||
- title link_to(@asset_collection.name.blank? ? @asset_collection.name_was : @asset_collection.name, '#', :rel => 'asset_collection_name', :title => t('.ask_for_name'), :class => 'editable')
|
||||
|
||||
- content_for :head do
|
||||
= include_javascripts :asset_collections
|
||||
= include_stylesheets :fancybox
|
||||
|
||||
- content_for :submenu do
|
||||
= render 'admin/shared/menu/assets'
|
||||
|
||||
- content_for :actions do
|
||||
= render 'admin/shared/actions/assets'
|
||||
|
||||
%p!= t('.help')
|
||||
|
||||
- content_for :buttons do
|
||||
= admin_button_tag :add_asset, new_admin_asset_url(@asset_collection), :class => 'new'
|
||||
|
||||
%p.no-items{ :style => "#{'display: none' unless @asset_collection.assets.empty? }" }
|
||||
!= t('.no_items', :url => new_admin_asset_url(@asset_collection))
|
||||
|
||||
%ul#assets.assets.sortable
|
||||
= render :partial => 'asset', :collection => @asset_collection.ordered_assets
|
||||
%li.clear
|
||||
|
||||
= semantic_form_for @asset_collection, :url => admin_asset_collection_url(@asset_collection), :html => { :multipart => true } do |f|
|
||||
= f.hidden_field :assets_order
|
||||
|
||||
= f.foldable_inputs :name => :options do
|
||||
= f.input :name
|
||||
= f.input :slug, :required => false
|
||||
|
||||
= render 'admin/custom_fields/index', :form => f, :collection_name => 'assets'
|
||||
|
||||
= render 'admin/shared/form_actions', :delete_button => link_to(content_tag(:em, escape_once(' ')) + t('.destroy'), admin_asset_collection_url(@asset_collection), :confirm => t('admin.messages.confirm'), :method => :delete, :class => 'button small remove'), :button_label => :update
|
||||
|
||||
= render 'admin/custom_fields/edit_field'
|
@ -1,11 +0,0 @@
|
||||
- title t('.title')
|
||||
|
||||
- content_for :submenu do
|
||||
= render 'admin/shared/menu/assets'
|
||||
|
||||
- content_for :actions do
|
||||
= render 'admin/shared/actions/assets'
|
||||
|
||||
%p!= t('.help')
|
||||
|
||||
%p.no-items!= t('.no_items', :url => new_admin_asset_collection_url)
|
@ -1,20 +0,0 @@
|
||||
- title t('.title')
|
||||
|
||||
- content_for :head do
|
||||
= include_javascripts :asset_collections
|
||||
|
||||
- content_for :submenu do
|
||||
= render 'admin/shared/menu/assets'
|
||||
|
||||
- content_for :actions do
|
||||
= render 'admin/shared/actions/assets'
|
||||
|
||||
%p!= t('.help')
|
||||
|
||||
= semantic_form_for @asset_collection, :url => admin_asset_collections_url do |f|
|
||||
|
||||
= f.inputs :name => :information do
|
||||
= f.input :name
|
||||
= f.input :slug, :required => false
|
||||
|
||||
= render 'admin/shared/form_actions', :back_url => admin_asset_collections_url, :button_label => :create
|
@ -1,5 +1,5 @@
|
||||
%li{ :id => "asset-#{asset.id}", :class => "asset #{'last' if (asset_counter + 1) % 6 == 0}"}
|
||||
%h4= link_to truncate(asset.name, :length => 17), edit_admin_asset_path(@asset_collection, asset)
|
||||
%h4= link_to truncate(asset.name, :length => 17), edit_admin_asset_path(asset)
|
||||
= vignette_tag(asset)
|
||||
.actions
|
||||
= link_to image_tag('admin/list/icons/cross.png'), '#', :class => 'remove', :confirm => t('admin.messages.confirm')
|
@ -1,17 +0,0 @@
|
||||
- content_for :head do
|
||||
= include_javascripts :edit_custom_fields, :assets
|
||||
= include_stylesheets :fancybox
|
||||
|
||||
= f.inputs :name => :information do
|
||||
= f.input :name
|
||||
= f.input :source, :hint_options => @asset.persisted? ? { :url => link_to(@asset.source_filename, @asset.source.url), :escaping => false } : {}
|
||||
|
||||
- unless @asset.custom_fields.blank?
|
||||
= render 'admin/custom_fields/custom_form', :form => f, :title => :other_fields, :parent => @asset_collection
|
||||
|
||||
- if @asset.image? && @asset.valid?
|
||||
= f.foldable_inputs :name => "#{t('formtastic.titles.preview')} #{image_dimensions_and_size(@asset)}", :class => 'preview' do
|
||||
%li
|
||||
.image
|
||||
.inside
|
||||
= image_tag(@asset.source.url(:preview))
|
@ -1,18 +0,0 @@
|
||||
- title t('.title')
|
||||
|
||||
- content_for :submenu do
|
||||
= render 'admin/shared/menu/assets'
|
||||
|
||||
- content_for :actions do
|
||||
= render 'admin/shared/actions/assets'
|
||||
|
||||
- content_for :buttons do
|
||||
= admin_button_tag t('admin.asset_collections.edit.add_asset'), new_admin_asset_url(@asset_collection), :class => 'new'
|
||||
|
||||
%p!= t('.help')
|
||||
|
||||
= semantic_form_for @asset, :url => admin_asset_url(@asset_collection, @asset), :html => { :multipart => true, :class => 'save-with-shortcut' } do |form|
|
||||
|
||||
= render 'form', :f => form
|
||||
|
||||
= render 'admin/shared/form_actions', :back_url => edit_admin_asset_collection_url(@asset_collection), :button_label => :update
|
@ -1,15 +0,0 @@
|
||||
- title t('.title')
|
||||
|
||||
- content_for :submenu do
|
||||
= render 'admin/shared/menu/assets'
|
||||
|
||||
- content_for :actions do
|
||||
= render 'admin/shared/actions/assets'
|
||||
|
||||
%p!= t('.help')
|
||||
|
||||
= semantic_form_for @asset, :url => admin_assets_url(@asset_collection), :html => { :multipart => true } do |form|
|
||||
|
||||
= render 'form', :f => form
|
||||
|
||||
= render 'admin/shared/form_actions', :back_url => edit_admin_asset_collection_url(@asset_collection), :button_label => :create
|
@ -2,9 +2,11 @@
|
||||
= include_javascripts :edit_custom_fields, :contents
|
||||
= include_stylesheets :fancybox
|
||||
|
||||
= f.foldable_inputs :name => :meta do
|
||||
= render 'admin/custom_fields/custom_form', :form => f, :title => :attributes, :parent => @content_type
|
||||
|
||||
= f.foldable_inputs :name => :advanced_options do
|
||||
|
||||
= f.input :_slug
|
||||
= f.input :seo_title
|
||||
= f.input :meta_keywords
|
||||
= f.input :meta_description
|
||||
|
||||
= render 'admin/custom_fields/custom_form', :form => f, :title => :attributes, :parent => @content_type
|
@ -1,7 +1,7 @@
|
||||
- if contents.empty?
|
||||
%p.no-items!= t('.no_items', :url => new_admin_content_url(@content_type.slug))
|
||||
- else
|
||||
%ul{ :id => 'contents-list', :class => "list #{'sortable' if @content_type.order_by == '_position_in_list'}" }
|
||||
%ul{ :id => 'contents-list', :class => "list #{'sortable' if @content_type.order_by == '_position_in_list'}", :'data-url' => sort_admin_contents_path(@content_type.slug, :json) }
|
||||
- contents.each do |content|
|
||||
%li.content{ :id => "content-#{content._id}" }
|
||||
%em
|
||||
|
@ -7,7 +7,9 @@
|
||||
= render 'admin/shared/actions/contents'
|
||||
|
||||
- content_for :buttons do
|
||||
- if can?(:manage, ContentType)
|
||||
= admin_button_tag t('admin.contents.index.edit'), edit_admin_content_type_url(@content_type), :class => 'edit'
|
||||
|
||||
= admin_button_tag t('admin.contents.index.new'), new_admin_content_url(@content_type.slug), :class => 'new'
|
||||
|
||||
%p= @content_type.description
|
||||
|
@ -10,7 +10,9 @@
|
||||
= include_javascripts :contents
|
||||
|
||||
- content_for :buttons do
|
||||
- if can?(:manage, ContentType)
|
||||
= admin_button_tag :edit, edit_admin_content_type_url(@content_type), :class => 'edit'
|
||||
|
||||
= admin_button_tag :new, new_admin_content_url(@content_type.slug), :class => 'new'
|
||||
|
||||
- if @content_type.description.present?
|
||||
@ -24,7 +26,7 @@
|
||||
- else
|
||||
= render 'list', :contents => @contents
|
||||
|
||||
= form_tag sort_admin_contents_path(@content_type.slug), :method => :put, :class => 'formtastic' do
|
||||
= hidden_field_tag :order
|
||||
|
||||
= render 'admin/shared/form_actions', :delete_button => link_to(content_tag(:em, escape_once(' ')) + t('.destroy'), admin_content_type_url(@content_type), :confirm => t('admin.messages.confirm'), :method => :delete, :class => 'button small remove'), :button_label => :update
|
||||
- if can?(:manage, ContentType)
|
||||
#local-actions-bottom-bar
|
||||
%p.tleft
|
||||
= link_to(content_tag(:em, escape_once(' ')) + t('.destroy'), admin_content_type_url(@content_type), :confirm => t('admin.messages.confirm'), :method => :delete, :class => 'button small remove')
|
||||
|
@ -6,6 +6,7 @@
|
||||
- content_for :actions do
|
||||
= render 'admin/shared/actions/contents'
|
||||
|
||||
- if can?(:manage, ContentType)
|
||||
- content_for :buttons do
|
||||
= admin_button_tag t('admin.contents.index.edit'), edit_admin_content_type_url(@content_type), :class => 'edit'
|
||||
|
||||
|
@ -4,11 +4,12 @@
|
||||
= f.foldable_inputs :name => :information, :style => "#{'display: none' unless @site.new_record?}" do
|
||||
= f.input :name, :required => false
|
||||
|
||||
= f.foldable_inputs :name => :meta do
|
||||
|
||||
= f.foldable_inputs :name => :seo do
|
||||
= f.input :seo_title
|
||||
= f.input :meta_keywords
|
||||
= f.input :meta_description
|
||||
|
||||
- if can?(:point, Site)
|
||||
- if manage_subdomain_or_domains?
|
||||
= f.foldable_inputs :name => :access_points, :class => 'editable-list off' do
|
||||
|
||||
@ -41,12 +42,27 @@
|
||||
%button{ :class => 'button light add', :type => 'button' }
|
||||
%span!= t('admin.buttons.new_item')
|
||||
|
||||
= f.foldable_inputs :name => :memberships, :class => 'memberships' do
|
||||
- @site.memberships.each_with_index do |membership, index|
|
||||
- account = membership.account
|
||||
%li{ :class => "item #{'last' if index == @site.memberships.size - 1}" }
|
||||
- if can?(:manage, Membership)
|
||||
|
||||
= f.foldable_inputs :name => :memberships, :class => 'memberships off' do
|
||||
= f.semantic_fields_for :memberships do |fm|
|
||||
|
||||
- membership, account = fm.object, fm.object.account
|
||||
|
||||
%li.item.membership{ :'data-role' => membership.role }
|
||||
%strong= account.name
|
||||
%em= account.email
|
||||
- if account != current_admin
|
||||
|
||||
%em.email= account.email
|
||||
|
||||
- if current_admin != account
|
||||
.role
|
||||
%em.editable= t("admin.memberships.roles.#{membership.role}")
|
||||
|
||||
= fm.select :role, Ability::ROLES.collect { |r| [t("admin.memberships.roles.#{r}"), r] }, :include_blank => false
|
||||
|
||||
%span.actions
|
||||
= link_to image_tag('admin/form/icons/trash.png'), admin_membership_url(membership), :class => 'remove first', :confirm =>t('admin.messages.confirm'), :method => :delete
|
||||
|
||||
- else
|
||||
.role
|
||||
%em.locked= t("admin.memberships.roles.#{membership.role}")
|
||||
|
@ -3,6 +3,7 @@
|
||||
- content_for :submenu do
|
||||
= render 'admin/shared/menu/settings'
|
||||
|
||||
- if can?(:manage, @site)
|
||||
- content_for :buttons do
|
||||
= admin_button_tag :import, new_admin_import_url, :class => 'new'
|
||||
= admin_button_tag t('.new_membership'), new_admin_membership_url, :class => 'new'
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
—
|
||||
|
||||
%em {{kind_name}}
|
||||
%em.editable {{kind_name}}
|
||||
|
||||
= select_tag '{{base_name}}[kind]', options_for_select(options_for_field_kind), :'data-field' => 'kind'
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
- field.target.constantize.reload_parent! # to make sure all the contents from the parent are loaded
|
||||
|
||||
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :input_html => { :class => 'has_one' }, :as => :select, :collection => options_for_has_one(field), :selected => form.object.send(field._alias.to_sym).try(:_id)
|
||||
- selected_id = form.object.send(field._alias.to_sym).try(:_id)
|
||||
|
||||
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :input_html => { :class => 'has_one' }, :as => :select, :collection => options_for_has_one(field, selected_id), :selected => selected_id
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
%p!= t('.help')
|
||||
|
||||
%ul{ :id => 'import-steps', :class => 'list', :'data-url' => admin_import_url(:json), :'data-success-message' => t('.messages.success'), :'data-failure-message' => t('.messages.failure') }
|
||||
- %w(site content_types assets asset_collections snippets pages).each do |step|
|
||||
- %w(site content_types assets snippets pages).each do |step|
|
||||
%li{ :id => "#{step}-step" }
|
||||
%em
|
||||
%strong
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
- if multi_sites?
|
||||
- content_for :buttons do
|
||||
= admin_button_tag t('.new_site'), new_admin_site_url, :class => 'new'
|
||||
= admin_button_tag t('.new_site'), new_admin_site_url, :class => 'new' if can?(:manage, Site)
|
||||
|
||||
%p= t('.help')
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
= include_javascripts :image_picker, :edit_page
|
||||
= include_stylesheets :editable_elements, :fancybox
|
||||
|
||||
- if can?(:manage, @page)
|
||||
|
||||
= f.foldable_inputs :name => :information do
|
||||
|
||||
= f.input :title
|
||||
@ -9,13 +11,18 @@
|
||||
- if not @page.index? and not @page.not_found?
|
||||
= f.input :parent_id, :as => :select, :collection => parent_pages_options, :include_blank => false
|
||||
|
||||
= f.input :slug, :required => false, :hint => @page.slug.blank? ? ' ' : page_url(@page), :input_html => { :data_url => get_path_admin_pages_url, :disabled => @page.index? || @page.not_found? }, :wrapper_html => { :style => "#{'display: none' if @page.templatized?}; height: 50px" }
|
||||
= f.input :slug, :required => false, :hint => @page.slug.blank? ? ' ' : page_url(@page), :input_html => { :'data-url' => get_path_admin_pages_url, :disabled => @page.index? || @page.not_found? }, :wrapper_html => { :style => "#{'display: none' if @page.templatized?}; height: 50px" }
|
||||
|
||||
= f.foldable_inputs :name => :meta do
|
||||
= render 'editable_elements', :page => @page
|
||||
|
||||
= f.foldable_inputs :name => :seo do
|
||||
|
||||
= f.input :seo_title
|
||||
= f.input :meta_keywords
|
||||
= f.input :meta_description
|
||||
|
||||
- if can?(:manage, @page)
|
||||
|
||||
= f.foldable_inputs :name => :advanced_options do
|
||||
|
||||
= f.input :content_type_id, :as => :select, :collection => current_site.content_types.all.to_a, :include_blank => false, :wrapper_html => { :style => "#{'display: none' unless @page.templatized?}; height: 50px" }
|
||||
@ -36,7 +43,6 @@
|
||||
|
||||
= f.input :redirect_url, :required => true, :wrapper_html => { :style => "#{'display: none' unless @page.redirect?}" }
|
||||
|
||||
= render 'editable_elements', :page => @page
|
||||
|
||||
= f.foldable_inputs :name => :raw_template do
|
||||
= f.custom_input :value, :css => 'code full', :with_label => false do
|
||||
@ -45,4 +51,4 @@
|
||||
= f.text_area :raw_template
|
||||
= f.errors_on :template
|
||||
.more
|
||||
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link'
|
||||
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link', :class => 'picture'
|
@ -1,5 +1,8 @@
|
||||
%li{ :id => "item-#{page.id}", :class => "#{'not-found' if page.not_found? } #{'templatized' if page.templatized?}"}
|
||||
- with_children = !page.children.empty?
|
||||
|
||||
- children = can?(:manage, page) ? page.children : page.children.find_all { |p| !p.templatized? }
|
||||
|
||||
- with_children = !children.empty?
|
||||
|
||||
- if not page.index? and with_children
|
||||
= image_tag 'admin/list/icons/node_closed.png', :class => 'toggler'
|
||||
@ -10,9 +13,10 @@
|
||||
%span!= t('.updated_at')
|
||||
= l page.updated_at, :format => :short
|
||||
|
||||
- if not page.index? and not page.not_found?
|
||||
- if !page.index_or_not_found? && can?(:manage, page)
|
||||
= link_to image_tag('admin/list/icons/trash.png'), admin_page_url(page), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete
|
||||
|
||||
- if with_children
|
||||
%ul{ :id => "folder-#{page._id}", :class => "folder depth-#{(page.depth || 0) + 1}", :data_url => sort_admin_page_url(page), :style => "display: #{cookies["folder-#{page._id}"] || 'block'}" }
|
||||
= render page.children
|
||||
%ul{ :id => "folder-#{page._id}", :class => "folder depth-#{(page.depth || 0) + 1}", :'data-url' => sort_admin_page_url(page), :style => "display: #{cookies["folder-#{page._id}"] || 'block'}" }
|
||||
|
||||
= render children
|
@ -9,6 +9,7 @@
|
||||
- content_for :actions do
|
||||
= render 'admin/shared/actions/contents'
|
||||
|
||||
- if can? :create, Page
|
||||
- content_for :buttons do
|
||||
= admin_button_tag :new, new_admin_page_url, :class => 'new'
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
.actions
|
||||
#local-actions-bottom-bar
|
||||
.span-12
|
||||
%p
|
||||
- if defined?(back_url)
|
||||
|
@ -1,5 +1,4 @@
|
||||
%ul#menu
|
||||
= admin_menu_item('contents', admin_pages_url)
|
||||
= admin_menu_item('assets', admin_asset_collections_url)
|
||||
= admin_menu_item('settings', edit_admin_current_site_url)
|
||||
%li.clear
|
||||
|
@ -1 +0,0 @@
|
||||
= link_to content_tag(:span, t('admin.asset_collections.index.new')), new_admin_asset_collection_url
|
@ -1 +1,2 @@
|
||||
- if can? :manage, ContentType
|
||||
= link_to content_tag(:em) + content_tag(:span, t('admin.content_types.index.new')), new_admin_content_type_url
|
@ -1,3 +0,0 @@
|
||||
- @asset_collections.each do |c|
|
||||
%li
|
||||
= link_to content_tag(:span, truncate(c.name, :length => 20)), edit_admin_asset_collection_url(c), :class => "#{'on' if @asset_collection.id == c.id}"
|
@ -1,4 +1,5 @@
|
||||
= admin_submenu_item 'pages', admin_pages_url do
|
||||
- if can? :manage, @page
|
||||
.header
|
||||
%p= link_to t('admin.pages.index.new'), new_admin_page_url
|
||||
.inner
|
||||
@ -12,6 +13,10 @@
|
||||
- each_content_type_menu_item do |content_type|
|
||||
.header
|
||||
%p= link_to t('admin.contents.index.new'), new_admin_content_url(content_type.slug)
|
||||
|
||||
- if can? :manage, content_type
|
||||
%p.edit= link_to t('admin.contents.index.edit'), edit_admin_content_type_url(content_type)
|
||||
|
||||
.inner
|
||||
%h2!= t('admin.contents.index.lastest_items')
|
||||
%ul
|
||||
|
@ -11,4 +11,4 @@
|
||||
%code{ :class => 'html' }
|
||||
= f.text_area :template
|
||||
.more
|
||||
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link'
|
||||
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link', :class => 'picture'
|
@ -6,7 +6,7 @@
|
||||
- content_for :buttons do
|
||||
= admin_button_tag t('admin.snippets.index.new'), new_admin_snippet_url, :class => 'new'
|
||||
|
||||
%p!= t('.help')
|
||||
%p!= t('.help', :slug => @snippet.slug)
|
||||
|
||||
= semantic_form_for @snippet, :url => admin_snippet_url(@snippet), :html => { :class => 'save-with-shortcut' } do |form|
|
||||
|
||||
|
@ -19,14 +19,14 @@
|
||||
- if @theme_asset.new_record?
|
||||
= f.input :plain_text_name
|
||||
|
||||
= f.custom_input :content_type do
|
||||
= f.select :content_type, %w(stylesheet javascript)
|
||||
= f.custom_input :plain_text_type do
|
||||
= f.select :plain_text_type, %w(stylesheet javascript)
|
||||
|
||||
= f.custom_input :plain_text, :css => 'full', :with_label => false do
|
||||
%code{ :class => (@theme_asset.size && @theme_asset.size > 40000 ? 'nude' : (@theme_asset.content_type || 'stylesheet')) }
|
||||
= f.text_area :plain_text
|
||||
.more
|
||||
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link'
|
||||
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link', :class => 'picture'
|
||||
|
||||
%span.alt
|
||||
!= t('admin.theme_assets.form.choose_file')
|
||||
|
@ -3,10 +3,16 @@
|
||||
- content_for :submenu do
|
||||
= render 'admin/shared/menu/settings'
|
||||
|
||||
- if can?(:manage, ThemeAsset)
|
||||
- content_for :buttons do
|
||||
= admin_button_tag t('admin.theme_assets.index.new'), new_admin_theme_asset_url, :class => 'new'
|
||||
|
||||
%p!= t('.help', :url => @theme_asset.source.url)
|
||||
%p
|
||||
- if %w(image javascript stylesheet).include?(@theme_asset.content_type.to_s)
|
||||
!= t(".help_#{@theme_asset.content_type}", :path => @theme_asset.local_path(true), :width => @theme_asset.width, :height => @theme_asset.height)
|
||||
|
||||
!= t('.help', :url => @theme_asset.source.url)
|
||||
|
||||
|
||||
= semantic_form_for @theme_asset, :url => admin_theme_asset_url(@theme_asset), :html => { :multipart => true, :class => 'save-with-shortcut' } do |form|
|
||||
|
||||
|
@ -4,12 +4,13 @@
|
||||
= render 'admin/shared/menu/settings'
|
||||
|
||||
- content_for :buttons do
|
||||
= admin_button_tag t('admin.theme_assets.index.all'), all_admin_theme_assets_url, :class => 'show'
|
||||
= admin_button_tag t('admin.snippets.index.new'), new_admin_snippet_url, :class => 'new'
|
||||
= admin_button_tag :new, new_admin_theme_asset_url, :class => 'new'
|
||||
= admin_button_tag t('admin.theme_assets.index.all'), all_admin_theme_assets_url, :class => 'show' if can?(:manage, ThemeAsset)
|
||||
= admin_button_tag t('admin.snippets.index.new'), new_admin_snippet_url, :class => 'new' if can?(:manage, Snippet)
|
||||
= admin_button_tag :new, new_admin_theme_asset_url, :class => 'new' if can?(:manage, ThemeAsset)
|
||||
|
||||
%p!= t('.help')
|
||||
|
||||
- if can?(:manage, Snippet)
|
||||
%h3!= t('.snippets')
|
||||
- if @snippets.empty?
|
||||
%p.no-items!= t('admin.snippets.index.no_items', :url => new_admin_snippet_url)
|
||||
@ -19,6 +20,7 @@
|
||||
|
||||
%br
|
||||
|
||||
- if can?(:manage, ThemeAsset)
|
||||
%h3!= t('.css_and_js')
|
||||
- if @js_and_css_assets.empty?
|
||||
%p.no-items!= t('.no_items', :url => new_admin_theme_asset_url)
|
||||
@ -35,6 +37,7 @@
|
||||
%ul.list.theme-assets
|
||||
= render :partial => 'asset', :collection => @assets[:images]
|
||||
|
||||
- if can?(:manage, ThemeAsset)
|
||||
- if @assets[:fonts]
|
||||
%br
|
||||
|
||||
|
@ -45,7 +45,5 @@ module Locomotive
|
||||
|
||||
# Configure sensitive parameters which will be filtered from the log file.
|
||||
config.filter_parameters << :password
|
||||
|
||||
config.middleware.insert_after Rack::Lock, '::Locomotive::Middlewares::Fonts', :path => %r{^/fonts}
|
||||
end
|
||||
end
|
@ -38,13 +38,6 @@ javascripts:
|
||||
- public/javascripts/admin/plugins/mustache.js
|
||||
- public/javascripts/admin/custom_fields/category.js
|
||||
- public/javascripts/admin/custom_fields/has_many.js
|
||||
asset_collections:
|
||||
- public/javascripts/admin/plugins/fancybox.js
|
||||
- public/javascripts/admin/plugins/mustache.js
|
||||
- public/javascripts/admin/custom_fields.js
|
||||
- public/javascripts/admin/asset_collections.js
|
||||
assets:
|
||||
- public/javascripts/admin/assets.js
|
||||
contents:
|
||||
- public/javascripts/admin/plugins/tiny_mce/tinymce.js
|
||||
- public/javascripts/admin/contents.js
|
||||
|
31
config/initializers/dragonfly.rb
Normal file
31
config/initializers/dragonfly.rb
Normal file
@ -0,0 +1,31 @@
|
||||
require 'locomotive'
|
||||
|
||||
unless Locomotive.engine?
|
||||
|
||||
require 'dragonfly'
|
||||
|
||||
## initialize Dragonfly ##
|
||||
|
||||
app = Dragonfly[:images]
|
||||
app.configure_with(:rails)
|
||||
app.configure_with(:imagemagick)
|
||||
|
||||
## configure it ##
|
||||
|
||||
Dragonfly[:images].configure do |c|
|
||||
# Convert absolute location needs to be specified
|
||||
# to avoid issues with Phusion Passenger not using $PATH
|
||||
convert = `which convert`.strip.presence || "/usr/local/bin/convert"
|
||||
c.convert_command = convert
|
||||
c.identify_command = convert
|
||||
|
||||
c.allow_fetch_url = true
|
||||
c.allow_fetch_file = true
|
||||
|
||||
c.url_format = '/images/dynamic/:job/:basename.:format'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
@ -62,4 +62,18 @@ Locomotive.configure do |config|
|
||||
# config.mailer_sender = 'support'
|
||||
# # => 'support@heroku.com' (Heroku), 'support@bushi.do' (Bushido), 'support@example.com' (Dev) or 'support@<your_hosting_platform>' (Multi-sites)
|
||||
config.mailer_sender = 'support'
|
||||
|
||||
# Rack-cache settings, mainly used for the inline resizing image module. Default options:
|
||||
# config.rack_cache = {
|
||||
# :verbose => true,
|
||||
# :metastore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/meta"), # URI encoded in case of spaces
|
||||
# :entitystore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/body")
|
||||
# }
|
||||
# If you do want to disable it for good, just use the following syntax
|
||||
# config.rack_cache = false
|
||||
#
|
||||
# Note: by default, rack/cache is disabled in the Heroku platform
|
||||
|
||||
end unless Locomotive.engine? || Rails.env.test?
|
||||
|
||||
# Rails.application.middleware.use '::Locomotive::Middlewares::SeoTrailingSlash'
|
||||
|
@ -61,8 +61,10 @@ de:
|
||||
title: Optionen
|
||||
help: Organisiere alle Optionen für die Auswahlbox.
|
||||
collection_label: Liste der Optionen
|
||||
custom_form:
|
||||
types:
|
||||
category:
|
||||
edit_categories: Optionen
|
||||
file:
|
||||
delete_file: Datei löschen
|
||||
index:
|
||||
is_required: ist erforderlich
|
||||
@ -190,22 +192,6 @@ de:
|
||||
title: Bilder anzeigen
|
||||
no_items: "Momentan gibt es keine Bilder."
|
||||
|
||||
asset_collections:
|
||||
index:
|
||||
title: Galerie
|
||||
help: "Der Name der Galerie kann durch darauf klicken bearbeitet werden. Du kannst die Bilder in einer Galerie bearbeiten, indem du neue Felder hinzufügst."
|
||||
new: neue Galerie
|
||||
no_items: "Momentan gibt es keine Galerien. Klicke einfach <a href='%{url}'>hier</a>, um eine neue Galerie zu erstellen."
|
||||
new:
|
||||
title: Neue Galerie
|
||||
help: "Gib erst mal einen Namen ein. Alle anderen Einstellungen kannst du vornehmen, sobald das Formular abgesendet ist."
|
||||
edit:
|
||||
help: "Der Name der Galerie kann durch darauf klicken bearbeitet werden. Du kannst Bilder in einer Galerie bearbeiten, indem du neue Felder hinzufügst."
|
||||
add_asset: Bild hinzufügen
|
||||
destroy: Galerie löschen
|
||||
no_items: "Momentan gibt es keine Bilder. Klicke einfach <a href='%{url}'>hier</a>, um das erste Bild zu erstellen."
|
||||
ask_for_name: "Gib den neuen Namen ein"
|
||||
|
||||
assets:
|
||||
new:
|
||||
title: Neues Bild
|
||||
@ -287,7 +273,6 @@ de:
|
||||
site: Webseiten-Informationen
|
||||
content_types: Benutzerdefinierte Inhalts-Typen
|
||||
assets: Template-Dateien
|
||||
asset_collections: Galerien
|
||||
snippets: Snippets
|
||||
pages: Seiten
|
||||
messages:
|
||||
|
@ -60,8 +60,10 @@ en:
|
||||
title: Edit options
|
||||
help: Manage the list of options for your select box.
|
||||
collection_label: List of options
|
||||
custom_form:
|
||||
types:
|
||||
category:
|
||||
edit_categories: Edit options
|
||||
file:
|
||||
delete_file: Delete file
|
||||
index:
|
||||
is_required: is required
|
||||
@ -99,7 +101,7 @@ en:
|
||||
updated_at: updated at
|
||||
edit:
|
||||
show: show
|
||||
help: "The page title can be updated by clicking it."
|
||||
help: "The page title can be updated by clicking it. To apply your changes, click on the \"Update\" button."
|
||||
ask_for_title: "Please type the new page title"
|
||||
form:
|
||||
delete_file: Delete file
|
||||
@ -123,7 +125,7 @@ en:
|
||||
help: "Fill in the form below to update your snippet."
|
||||
edit:
|
||||
title: Editing snippet
|
||||
help: "Fill in the form below to update your snippet."
|
||||
help: "Include your snippet in your page templates with the following liquid code : <span class='code'>{% include '%{slug}' %}</span>."
|
||||
snippet:
|
||||
updated_at: Updated at
|
||||
|
||||
@ -136,10 +138,14 @@ en:
|
||||
edit:
|
||||
import: import
|
||||
new_membership: add account
|
||||
help: "The site name can be updated by clicking it."
|
||||
help: "The site name can be updated by clicking it. To apply your changes, click on the \"Update\" button."
|
||||
ask_for_name: "Please type the new site name"
|
||||
|
||||
memberships:
|
||||
roles:
|
||||
admin: Administrator
|
||||
designer: Designer
|
||||
author: Author
|
||||
new:
|
||||
title: New membership
|
||||
help: "Please give the account email to add. If it does not exist, you will be redirected to the account creation form."
|
||||
@ -151,7 +157,7 @@ en:
|
||||
|
||||
my_accounts:
|
||||
edit:
|
||||
help: "Your name can be updated by clicking it."
|
||||
help: "Your name can be updated by clicking it. To apply your changes, click on the \"Update\" button."
|
||||
new_site: new site
|
||||
en: English
|
||||
de: German
|
||||
@ -163,7 +169,7 @@ en:
|
||||
theme_assets:
|
||||
index:
|
||||
title: Listing theme files
|
||||
help: "The theme files section is the place where you manage the files needed by your layout, ...etc. If you need to manage an image gallery, go to the Assets section instead."
|
||||
help: "The theme files section is the place where you manage the files needed by your layout, snippets...etc. If you need to manage an image gallery, create a new content type instead.<br/><b>Warning:</b> you may not see all the assets depending on your rights."
|
||||
all: all assets
|
||||
new: new file
|
||||
snippets: Snippets
|
||||
@ -171,7 +177,7 @@ en:
|
||||
fonts: Fonts
|
||||
images: Images
|
||||
medias: Medias
|
||||
no_items: "There are no files for now. Just click <a href=\"%{url}\">here</a> to create the first one."
|
||||
no_items: "There are no files for now."
|
||||
asset:
|
||||
updated_at: Updated at
|
||||
new:
|
||||
@ -179,7 +185,10 @@ en:
|
||||
help: "You have the choice to either upload any file or to copy/paste a stylesheet or a javascript in plain text."
|
||||
edit:
|
||||
title: "Editing %{file}"
|
||||
help: "This asset is accessible from the following url: <a href='%{url}'>%{url}</a>"
|
||||
help: "This asset is accessible directly from the following url: <a href='%{url}'>%{url}</a>"
|
||||
help_image: "Include your image in your page templates or snippets with the following liquid code : <span class='code'>{{ '%{path}' | theme_image_tag }}</span>.<br/>Your current image dimensions : <b>%{width}px x %{height}px</b>.<br/>"
|
||||
help_javascript: "Include your javascript file in your page templates or snippets with the following code : <span class='code'>{{ '%{path}' | javascript_tag }}</span>.<br/>"
|
||||
help_stylesheet: "Include your stylesheet file in your page templates or snippets with the following code : <span class='code'>{{ '%{path}' | stylesheet_tag }}</span>.<br/>"
|
||||
form:
|
||||
picker_link: Insert a file into the code
|
||||
choose_file: Choose file
|
||||
@ -188,22 +197,6 @@ en:
|
||||
title: Listing images
|
||||
no_items: "There are no files for now."
|
||||
|
||||
asset_collections:
|
||||
index:
|
||||
title: Asset collections
|
||||
help: "The collection name can be updated by clicking it. You can customize assets in a collection by adding new fields."
|
||||
new: new collection
|
||||
no_items: "There are no collections for now. Just click <a href=\"%{url}\">here</a> to create the first one."
|
||||
new:
|
||||
title: New collection
|
||||
help: "For now, just type a name. Other settings will come once the form is sent."
|
||||
edit:
|
||||
help: "The collection name can be updated by clicking it. You can customize assets in a collection by adding new fields."
|
||||
add_asset: add asset
|
||||
destroy: remove collection
|
||||
no_items: "There are no assets for now. Just click <a href=\"%{url}\">here</a> to create the first one."
|
||||
ask_for_name: "Please type the new name"
|
||||
|
||||
assets:
|
||||
new:
|
||||
title: New asset
|
||||
@ -225,8 +218,8 @@ en:
|
||||
new_item: new item
|
||||
form:
|
||||
order_by:
|
||||
created_at: 'By "created at" date'
|
||||
updated_at: 'By "updated at" date'
|
||||
created_at: 'By creation date'
|
||||
updated_at: 'By updating date'
|
||||
position_in_list: Manually
|
||||
order_direction:
|
||||
asc: Ascending
|
||||
@ -268,7 +261,6 @@ en:
|
||||
site: Site information
|
||||
content_types: Custom content types
|
||||
assets: Theme files
|
||||
asset_collections: Asset collections
|
||||
snippets: Snippets
|
||||
pages: Pages
|
||||
messages:
|
||||
|
@ -60,8 +60,10 @@ fr:
|
||||
title: Editer options
|
||||
help: Gèrer la liste des options de votre liste déroulante
|
||||
collection_label: Liste des options
|
||||
custom_form:
|
||||
types:
|
||||
category:
|
||||
edit_categories: Editer options
|
||||
file:
|
||||
delete_file: Supprimer fichier
|
||||
index:
|
||||
is_required: est obligatoire
|
||||
@ -99,7 +101,7 @@ fr:
|
||||
updated_at: Mise à jour le
|
||||
edit:
|
||||
show: voir
|
||||
help: "Le titre de la page est modifiable en cliquant dessus."
|
||||
help: "Le titre de la page est modifiable en cliquant dessus. Pour appliquer votre modification, cliquez après sur le bouton \"Modifier\""
|
||||
ask_for_title: "Veuillez entrer le nouveau titre"
|
||||
form:
|
||||
delete_file: Supprimer fichier
|
||||
@ -124,6 +126,7 @@ fr:
|
||||
edit:
|
||||
title: Edition snippet
|
||||
help: "Remplissez le formulaire ci-dessous pour mettre à jour votre snippet."
|
||||
help: "Utilisez votre snippet dans le template d'une page avec le code Liquid suivant : <span class='code'>{% include '%{slug}' %}</span>."
|
||||
snippet:
|
||||
updated_at: Mis à jour le
|
||||
|
||||
@ -136,7 +139,7 @@ fr:
|
||||
edit:
|
||||
import: importer
|
||||
new_membership: ajouter compte
|
||||
help: "Le nom du site est modifiable en cliquant dessus."
|
||||
help: "Le nom du site est modifiable en cliquant dessus. Pour appliquer votre modification, cliquez après sur le bouton \"Modifier\""
|
||||
ask_for_name: "Veuillez entrer le nouveau nom"
|
||||
|
||||
memberships:
|
||||
@ -151,7 +154,7 @@ fr:
|
||||
|
||||
my_accounts:
|
||||
edit:
|
||||
help: "Votre nom est modifiable en cliquant dessus."
|
||||
help: "Votre nom est modifiable en cliquant dessus. Pour appliquer votre modification, cliquez après sur le bouton \"Modifier\""
|
||||
new_site: nouveau site
|
||||
en: en Anglais
|
||||
de: en Allemand
|
||||
@ -163,7 +166,7 @@ fr:
|
||||
theme_assets:
|
||||
index:
|
||||
title: Liste des fichiers du thème
|
||||
help: "Les fichiers du thème sont utilisés pour construire le gabarit de vos pages. Si vous avez besoin d'une galerie d'images, la section Média est plus adéquate."
|
||||
help: "Les fichiers du thème sont utilisés pour construire le gabarit de vos pages. Si vous avez besoin d'une galerie d'images, créer un modèle sera plus adéquate.<br/><b>Attention : </b> Suivant les droits que vous avez, il se peut que vous ne puissiez pas voir tous les fichiers."
|
||||
all: tous les fichiers
|
||||
new: nouveau fichier
|
||||
snippets: Snippets
|
||||
@ -171,7 +174,7 @@ fr:
|
||||
images: Images
|
||||
medias: Médias
|
||||
fonts: Polices
|
||||
no_items: "Il n'existe pas de fichiers. Vous pouvez commencer par créer un <a href='%{url}'>ici</a>."
|
||||
no_items: "Il n'existe pas de fichiers."
|
||||
asset:
|
||||
updated_at: Mis à jour le
|
||||
new:
|
||||
@ -180,6 +183,11 @@ fr:
|
||||
edit:
|
||||
title: "Edition %{file}"
|
||||
help: "L'url du fichier est <a href='%{url}'>%{url}</a>"
|
||||
help: "L'url du fichier est directement disponible : <a href='%{url}'>%{url}</a>"
|
||||
help_image: "Utilisez votre image dans le template de vos pages ou snippets avec le code Liquid suivant : <span class='code'>{{ '%{path}' | theme_image_tag }}</span>.<br/>. Votre image a comme dimensions : <b>%{width}px x %{height}px</b>.<br/>"
|
||||
help_javascript: "Utilisez votre javascript dans le template de vos pages avec le code Liquid suivant : <span class='code'>{{ '%{path}' | javascript_tag }}</span>.<br/>"
|
||||
help_stylesheet: "Utilisez votre stylesheet dans le template de vos pages avec le code Liquid suivant : <span class='code'>{{ '%{path}' | stylesheet_tag }}</span>.<br/>"
|
||||
|
||||
form:
|
||||
choose_file: Choisir fichier
|
||||
choose_plain_text: Passer en mode texte
|
||||
@ -187,22 +195,6 @@ fr:
|
||||
title: Liste des images
|
||||
no_items: "Il n'y a pas d'images."
|
||||
|
||||
asset_collections:
|
||||
index:
|
||||
title: Collections
|
||||
help: "Le nom de la collection est modifiable en cliquant dessus. Vous pouvez personnaliser une collection en ajoutant d'autres champs à vos médias."
|
||||
new: nouvelle collection
|
||||
no_items: "Il n'existe pas de collections. Vous pouvez commencer par créer une <a href='%{url}'>ici</a>."
|
||||
new:
|
||||
title: Nouvelle collection
|
||||
help: "Pour le moment, veuillez rentrer le nom. Les autres options viendront dans le formulaire suivant."
|
||||
edit:
|
||||
help: "Le nom de la collection est modifiable en cliquant dessus. Vous pouvez personnaliser une collection en ajoutant d'autres champs à vos médias."
|
||||
add_asset: ajouter média
|
||||
destroy: supprimer collection
|
||||
no_items: "Il n'existe pas de médias. Vous pouvez commencer par créer un <a href='%{url}'>ici</a>."
|
||||
ask_for_name: "Veuillez entrer le nouveau nom"
|
||||
|
||||
assets:
|
||||
new:
|
||||
title: "Nouveau média"
|
||||
@ -224,7 +216,7 @@ fr:
|
||||
new_item: nouvel élément
|
||||
form:
|
||||
order_by:
|
||||
created_at: 'Par date création'
|
||||
created_at: 'Par date de création'
|
||||
updated_at: 'Par date de mise à jour'
|
||||
position_in_list: Manuellement
|
||||
order_direction:
|
||||
@ -267,7 +259,6 @@ fr:
|
||||
site: Informations sur le site
|
||||
content_types: Modèles de données personnalisés
|
||||
assets: Fichiers du thème
|
||||
asset_collections: Collections de média
|
||||
snippets: Snippets
|
||||
pages: Pages
|
||||
messages:
|
||||
|
@ -60,8 +60,10 @@ it:
|
||||
title: Modifica opzioni
|
||||
help: Amministra la lista opzioni del select box.
|
||||
collection_label: Lista delle opzioni
|
||||
custom_form:
|
||||
types:
|
||||
category:
|
||||
edit_categories: Modifica opzioni
|
||||
file:
|
||||
delete_file: Elimina file
|
||||
index:
|
||||
is_required: è richiesto
|
||||
@ -188,22 +190,6 @@ it:
|
||||
title: Lista immagini
|
||||
no_items: "Per ora non ci sono file."
|
||||
|
||||
asset_collections:
|
||||
index:
|
||||
title: Collezioni di risorse
|
||||
help: "Puoi cambiare il nome della collezione cliccandoci sopra. Puoi personalizzare le risorse in una collezione aggiugendo nuovi campi."
|
||||
new: nuov collezione
|
||||
no_items: "Per ora non ci sono collezioni. Clicca <a href=\"%{url}\">qui</a> per creare la prima."
|
||||
new:
|
||||
title: Nuova collezione
|
||||
help: "Per ora inserisci solo in nome. Altre opzioni appariranno dopo aver inviato il modulo."
|
||||
edit:
|
||||
help: "Puoi cambiare il nome della collezione cliccandoci sopra. Puoi personalizzare le risorse in una collezione aggiugendo nuovi campi."
|
||||
add_asset: aggiungi risorsa
|
||||
destroy: elimina collezione
|
||||
no_items: "Per ora non ci sono risorse. Clicca <a href=\"%{url}\">qui</a> per creare la prima."
|
||||
ask_for_name: "Prego, digita il nuovo nome"
|
||||
|
||||
assets:
|
||||
new:
|
||||
title: Nuova risorsa
|
||||
@ -268,7 +254,6 @@ it:
|
||||
site: Informazioni sito
|
||||
content_types: Tipi di contenuti personalizzati
|
||||
assets: File del tema
|
||||
asset_collections: Collezioni di risorse
|
||||
snippets: Frammenti
|
||||
pages: Pagine
|
||||
messages:
|
||||
|
@ -60,8 +60,10 @@ pt-BR:
|
||||
title: Editar opções
|
||||
help: Gerenciar a lista de opções da sua caixa de seleçõa.
|
||||
collection_label: Lista de opções
|
||||
custom_form:
|
||||
types:
|
||||
category:
|
||||
edit_categories: Editar opções
|
||||
file:
|
||||
delete_file: Excluir arquivo
|
||||
|
||||
sessions:
|
||||
@ -185,22 +187,6 @@ pt-BR:
|
||||
title: Listando imagens
|
||||
no_items: "Não existem imagens ainda."
|
||||
|
||||
asset_collections:
|
||||
index:
|
||||
title: Coleções de arquivos
|
||||
help: "O nome da coleção pode ser alterado clicando nele. Você pode customizar os arquivos nas coleções adicionando campos."
|
||||
new: nova coleção
|
||||
no_items: "Não existem coleções ainda. Clique <a href=\"%{url}\">aqui</a> para criar a primeira."
|
||||
new:
|
||||
title: Nova Coleção
|
||||
help: "Por enquanto, apenas insira o nome. Outras opções irão aparecer após o formulário ser enviado."
|
||||
edit:
|
||||
help: "O nome da coleção pode ser alterado clicando nele. Você pode customizar os arquivos nas coleções adicionando campos."
|
||||
add_asset: adicionar arquivo
|
||||
destroy: excluir coleção
|
||||
no_items: "Não existem coleções ainda. Clique <a href=\"%{url}\">aqui</a> para criar a primeira."
|
||||
ask_for_name: Por favor preencha o novo nome"
|
||||
|
||||
assets:
|
||||
new:
|
||||
title: Novo arquivo
|
||||
@ -262,7 +248,6 @@ pt-BR:
|
||||
site: Informações do site
|
||||
content_types: Tipos de Conteúdo customizados
|
||||
assets: Arquivos do Tema
|
||||
asset_collections: Coleções de Arquivos
|
||||
snippets: Blocos
|
||||
pages: Páginas
|
||||
messages:
|
||||
|
@ -72,11 +72,7 @@ de:
|
||||
highlighted_field_name: Hervorgehobener Feld-Name
|
||||
group_by_field_name: Gruppierung nach Feld-Name
|
||||
api_enabled: API aktiviert
|
||||
asset_collection:
|
||||
name: Name
|
||||
slug: Slug
|
||||
asset:
|
||||
name: Name
|
||||
source: Quelle
|
||||
account:
|
||||
email: Email
|
||||
|
@ -63,6 +63,7 @@ fr:
|
||||
redirect: Redirection
|
||||
redirect_url: Url de redirection
|
||||
cache_strategy: Cache
|
||||
seo_title: Titre SEO
|
||||
content_type:
|
||||
name: Nom
|
||||
description: Description
|
||||
@ -71,11 +72,7 @@ fr:
|
||||
highlighted_field_name: Champ mis en avant
|
||||
group_by_field_name: Champ pour grouper
|
||||
api_enabled: Activation API
|
||||
asset_collection:
|
||||
name: Nom
|
||||
slug: Raccourci
|
||||
asset:
|
||||
name: Nom
|
||||
source: Fichier
|
||||
account:
|
||||
email: E-mail
|
||||
|
@ -77,11 +77,7 @@ it:
|
||||
highlighted_field_name: Campo evidenziato
|
||||
group_by_field_name: Raggruppa per nome campo
|
||||
api_enabled: API Attiva
|
||||
asset_collection:
|
||||
name: Nome
|
||||
slug: Slug
|
||||
asset:
|
||||
name: Nome
|
||||
source: Sorgente
|
||||
account:
|
||||
email: Email
|
||||
|
@ -71,11 +71,7 @@ pt-BR:
|
||||
highlighted_field_name: Nome do Campo em destaque
|
||||
group_by_field_name: Agrupar por name do campo
|
||||
api_enabled: Activation API
|
||||
asset_collection:
|
||||
name: Nome
|
||||
slug: Slug
|
||||
asset:
|
||||
name: Nome
|
||||
source: Arquivo
|
||||
account:
|
||||
email: Email
|
||||
|
@ -73,16 +73,6 @@ de:
|
||||
alert: "Account wurde nicht erstellt."
|
||||
already_created: "Account wurde bereits zu dieser Webseite hinzugefügt."
|
||||
|
||||
asset_collections:
|
||||
create:
|
||||
notice: "Sammlung wurde erfolgreich erstellt."
|
||||
alert: "Sammlung wurde nicht erstellt."
|
||||
update:
|
||||
notice: "Sammlung wurde erfolreich aktualisiert."
|
||||
alert: "Sammlung wurde nicht aktualisiert."
|
||||
destroy:
|
||||
notice: "Sammlung wurde erfolgreich gelöscht."
|
||||
|
||||
assets:
|
||||
create:
|
||||
notice: "Asset wurde erfolgreich erstellt."
|
||||
|
@ -73,16 +73,6 @@ en:
|
||||
alert: "Membership was not created."
|
||||
already_created: "Account was already added the current site."
|
||||
|
||||
asset_collections:
|
||||
create:
|
||||
notice: "Collection was successfully created."
|
||||
alert: "Collection was not created."
|
||||
update:
|
||||
notice: "Collection was successfully updated."
|
||||
alert: "Collection was not updated."
|
||||
destroy:
|
||||
notice: "Collection was successfully deleted."
|
||||
|
||||
assets:
|
||||
create:
|
||||
notice: "Asset was successfully created."
|
||||
|
@ -73,16 +73,6 @@ fr:
|
||||
alert: "Le compte n'a pas été ajouté."
|
||||
already_created: "Le compte a déjà été ajouté pour ce site."
|
||||
|
||||
asset_collections:
|
||||
create:
|
||||
notice: "La collection a été créée avec succès."
|
||||
alert: "La collection n'a pas été créée."
|
||||
update:
|
||||
notice: "La collection a été mise à jour avec succès."
|
||||
alert: "La collection n'a pas été mise à jour."
|
||||
destroy:
|
||||
notice: "La collection a été supprimée avec succès."
|
||||
|
||||
assets:
|
||||
create:
|
||||
notice: "Le média a été crée avec succès."
|
||||
|
@ -73,16 +73,6 @@ it:
|
||||
alert: "La partecipazione non è stata creata."
|
||||
already_created: "L'account è già stato aggiunto al corrente sito."
|
||||
|
||||
asset_collections:
|
||||
create:
|
||||
notice: "La collezione è stata creata con successo."
|
||||
alert: "La collezione non è stata creata."
|
||||
update:
|
||||
notice: "La collezione è stata modificata con successo."
|
||||
alert: "La collezione non è stata modificata."
|
||||
destroy:
|
||||
notice: "La collezione è stata eliminata con successo."
|
||||
|
||||
assets:
|
||||
create:
|
||||
notice: "La risorsa è stata creata con successo."
|
||||
|
@ -73,16 +73,6 @@ pt-BR:
|
||||
alert: "Adesão não foi criada."
|
||||
already_created: "Conta já foi adicionada ao site atual."
|
||||
|
||||
asset_collections:
|
||||
create:
|
||||
notice: "Coleção criada com sucesso."
|
||||
alert: "Coleção não foi criada."
|
||||
update:
|
||||
notice: "Coleção foi atualizada com sucesso."
|
||||
alert: "Coleção não foi atualizada."
|
||||
destroy:
|
||||
notice: "Coleção foi apagada com sucesso."
|
||||
|
||||
assets:
|
||||
create:
|
||||
notice: "Asset foi criada com sucesso."
|
||||
|
@ -4,6 +4,7 @@ en:
|
||||
information: General information
|
||||
advanced_options: Advanced options
|
||||
meta: SEO Metadata
|
||||
seo: SEO settings
|
||||
code: Code
|
||||
raw_template: Template
|
||||
credentials: Credentials
|
||||
@ -40,10 +41,14 @@ en:
|
||||
content_type:
|
||||
raw_item_template: Item template
|
||||
api_accounts: Notified Accounts
|
||||
content_instance:
|
||||
_slug: Permalink
|
||||
account:
|
||||
edit:
|
||||
password: New password
|
||||
password_confirmation: New password confirmation
|
||||
page:
|
||||
seo_title: Title
|
||||
|
||||
hints:
|
||||
page:
|
||||
@ -52,11 +57,13 @@ en:
|
||||
templatized: "Use the page as a template for a model you defined."
|
||||
listed: "Control whether to show the page from generated menus."
|
||||
content_type_id: "The type of content this page will be a template for."
|
||||
seo_title: "Define a page title which should be used as the value for the title tag in the head section. Leave it empty if you want to use the default value from the site settings."
|
||||
meta_keywords: "Overrides the site's meta keywords used within the head tag of the page. They are separated by a comma."
|
||||
meta_description: "Overrides the site's meta description used within the head tag of the page."
|
||||
snippet:
|
||||
slug: "You need to know it in order to insert the snippet inside a page"
|
||||
site:
|
||||
seo_title: "Define a global value here which should be used as the value for the title tag in the head section."
|
||||
meta_keywords: "Meta keywords used within the head tag of the page. They are separated by a comma. Required for SEO."
|
||||
meta_description: "Meta description used within the head tag of the page. Required for SEO."
|
||||
domain_name: "ex: locomotiveapp.org"
|
||||
@ -74,6 +81,11 @@ en:
|
||||
field:
|
||||
_alias: "Property available in liquid templates"
|
||||
hint: "Text displayed in the model form just below the field"
|
||||
content_instance:
|
||||
_slug: "Property used to generate the url of a page working as a template for this content type (ex: \"template_page/{{ your_object._permalink }})\"."
|
||||
seo_title: "The value you fill in will replace the SEO title of the templatized page related to your model."
|
||||
meta_keywords: "Overrides the site's meta keywords used within the head tag of the page. They are separated by a comma."
|
||||
meta_description: "Overrides the site's meta description used within the head tag of the page."
|
||||
import:
|
||||
source: "A zipfile containing a database.yml along with assets and templates"
|
||||
samples: "If enabled, the import process will also copy contents and assets"
|
||||
|
@ -4,6 +4,7 @@ fr:
|
||||
information: Informations générales
|
||||
advanced_options: Options avancées
|
||||
meta: SEO Metadata
|
||||
seo: Paramètres SEO
|
||||
code: Code
|
||||
raw_template: Gabarit
|
||||
credentials: Informations de connexion
|
||||
@ -42,10 +43,14 @@ fr:
|
||||
content_type:
|
||||
raw_item_template: Template d'affichage
|
||||
api_accounts: Comptes à notifier
|
||||
content_instance:
|
||||
_slug: Permalink
|
||||
account:
|
||||
edit:
|
||||
password: Nouveau mot de passe
|
||||
password_confirmation: Confirmation nouveau mot de passe
|
||||
page:
|
||||
seo_title: Titre
|
||||
|
||||
hints:
|
||||
page:
|
||||
@ -54,6 +59,7 @@ fr:
|
||||
templatized: "Utilise la page comme un template pour un modèle défini."
|
||||
listed: "Controle si la page doit être visible depuis les menus automatiquement générés."
|
||||
content_type_id: "Le type du contenu pour lequel cette page est un template."
|
||||
seo_title: "Définit un titre de page à mettre dans la balise TITLE de la page. Laissez le blanc pour utiliser la valeur par défaut (voir configuration du site)."
|
||||
meta_keywords: "Redéfinit les mots-clés du site. Utilisés à l'intérieur de la balise HEAD. Ils sont séparés par une virgule."
|
||||
meta_description: "Redéfinit la description du site. Utilisée à l'intérieur de la balise HEAD."
|
||||
snippet:
|
||||
@ -76,6 +82,11 @@ fr:
|
||||
field:
|
||||
_alias: "Champ utilisable dans les templates liquid"
|
||||
hint: "Texte affiché dans le formulaire de l'élément juste en dessous du champ."
|
||||
content_instance:
|
||||
_slug: "Propriété utilisée pour générer l'url d'une page faisant office de template pour ce modèle (ex: \"template_de_la_page/{{ votre_object._permalink }})\"."
|
||||
seo_title: "La valeur que vous rentrez sera utilisée comme titre SEO pour la page faisant office de template pour ce modèle."
|
||||
meta_keywords: "Redéfinit les mots-clés du site. Utilisés à l'intérieur de la balise HEAD. Ils sont séparés par une virgule."
|
||||
meta_description: "Redéfinit la description du site. Utilisée à l'intérieur de la balise HEAD."
|
||||
import:
|
||||
source: "Un fichier zip contenant database.yml, les fichiers du thème et les templates de page"
|
||||
samples: "Si activé, les contenus et les média seront aussi copiés lors de l'import"
|
||||
|
@ -33,11 +33,9 @@ Rails.application.routes.draw do
|
||||
get :all, :action => 'index', :on => :collection, :defaults => { :all => true }
|
||||
end
|
||||
|
||||
resources :asset_collections
|
||||
resources :assets
|
||||
|
||||
resources :assets, :path => 'asset_collections/:collection_id/assets'
|
||||
|
||||
resources :images
|
||||
resources :images, :controller => 'assets', :defaults => { :image => true }
|
||||
|
||||
resources :content_types
|
||||
|
||||
|
62
doc/TODO
62
doc/TODO
@ -1,8 +1,59 @@
|
||||
BOARD:
|
||||
|
||||
x bushido version
|
||||
x default template
|
||||
~ editable_elements: inheritable: false (Mattias) => seems to be fixed by Dirk's last pull request (#44) => content tag
|
||||
- bushido version
|
||||
- default template
|
||||
x locomedia tinyMCE plugin (Bernd)
|
||||
x remove asset_collections
|
||||
x site templates
|
||||
x tinyMCE plugin
|
||||
x vignette.rb
|
||||
x code
|
||||
x helpers
|
||||
x ui
|
||||
x rake task
|
||||
x internal collection
|
||||
x assign same _id
|
||||
x pick up a theme_asset
|
||||
x pull request locomedia
|
||||
x refactor slugify method (use parameterize + create a module)
|
||||
x contents permalink (UI)
|
||||
x BUG: has_one / has_many. Delete an author
|
||||
x bushido changes in the master
|
||||
? edit sidebar (inline editor). Unable to reset it
|
||||
x SEO: support and support/ should be 2 different pages. Remove trailing slash
|
||||
x issue #91: httparty
|
||||
x issue #90: seo metadata
|
||||
x issue #57: seo page title
|
||||
x issue #56
|
||||
x tweak ui: form, quick link to edit a model in the popup menu
|
||||
x Has_one => group by in the select
|
||||
x better hints:
|
||||
x notify the user that after changing the page title, they still have to click "update" for the change to be saved
|
||||
x created_by ASC => "Creation date ascending"
|
||||
x cancan: (authors / designers / admin)
|
||||
x model
|
||||
x ui
|
||||
x controllers / views:
|
||||
x page
|
||||
x content / content type
|
||||
x asset
|
||||
x site
|
||||
x account
|
||||
x snippet
|
||||
x theme asset
|
||||
x features / specs
|
||||
x enable rack-cache only for a specific url
|
||||
- convert existing templates (the 2 of the themes section)
|
||||
|
||||
=> MERGE
|
||||
|
||||
- bugs
|
||||
- heroku: unable to upload a new file
|
||||
- import
|
||||
- delete an item
|
||||
- liquid tag: Date.today (now), add a test to compare 2 dates
|
||||
- better ui: increase text field length + refactor error message
|
||||
|
||||
BACKLOG:
|
||||
|
||||
@ -19,11 +70,16 @@ BACKLOG:
|
||||
- icon for redirection page in the pages section (back-office)
|
||||
- write my first tutorial about locomotive
|
||||
- upgrade warning if new version of locomotive (maybe based on the commit id)
|
||||
- deploying workflow:
|
||||
- roll back a bad update
|
||||
- conflicts with content types
|
||||
- dev -> staging -> production
|
||||
- sync data
|
||||
- import only theme assets
|
||||
|
||||
|
||||
REFACTORING:
|
||||
|
||||
- refactor slugify method (use parameterize + create a module)
|
||||
- move content_type and content_instances in the CustomFields plugin (much more appropriate)
|
||||
|
||||
BUGS:
|
||||
|
32
features/admin/authorization/content_type.feature
Normal file
32
features/admin/authorization/content_type.feature
Normal file
@ -0,0 +1,32 @@
|
||||
Feature: Editing a content type
|
||||
In order to edit a content type
|
||||
As an admin, designer, or author
|
||||
I will be restricted based on my role
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And I have a custom project model
|
||||
And I have a designer and an author
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I go to the "Projects" model edition page
|
||||
Then I should see "Log in"
|
||||
|
||||
Scenario: Accessing edition functionality as an Admin
|
||||
Given I am an authenticated "admin"
|
||||
When I go to the "Projects" model edition page
|
||||
Then I should see "Editing model"
|
||||
And I should see "Custom fields"
|
||||
|
||||
Scenario: Accessing edition functionality as a Designer
|
||||
Given I am an authenticated "designer"
|
||||
When I go to the "Projects" model edition page
|
||||
Then I should see "Editing model"
|
||||
And I should see "Custom fields"
|
||||
|
||||
Scenario: Accessing edition functionality as an Author
|
||||
Given I am an authenticated "author"
|
||||
When I go to the "Projects" model edition page
|
||||
Then I should be on the pages list
|
||||
And I should see the access denied message
|
53
features/admin/authorization/current_site.feature
Normal file
53
features/admin/authorization/current_site.feature
Normal file
@ -0,0 +1,53 @@
|
||||
Feature: Site Settings
|
||||
In order to ensure site settings are not tampered with
|
||||
As an admin, designer or author
|
||||
I will be restricted based on my role
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And I have a designer and an author
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I go to site settings
|
||||
Then I should see "Log in"
|
||||
|
||||
Scenario: Accessing site settings as an Admin
|
||||
Given I am an authenticated "admin"
|
||||
When I go to site settings
|
||||
Then I should see "import"
|
||||
And I should see "add account"
|
||||
And I should see "SEO settings"
|
||||
And I should see "Access points"
|
||||
And I should not see the role dropdown on myself
|
||||
And I should see the role dropdown on the "designer"
|
||||
And I should see the role dropdown on the "author"
|
||||
And I should not see delete on myself
|
||||
And I should see delete on the "designer"
|
||||
And I should see delete on the "author"
|
||||
|
||||
Scenario: Accessing site settings as a Designer
|
||||
Given I am an authenticated "designer"
|
||||
When I go to site settings
|
||||
Then I should see "import"
|
||||
And I should see "add account"
|
||||
And I should see "SEO settings"
|
||||
And I should see "Access points"
|
||||
And I should not see the role dropdown on myself
|
||||
And I should see the role dropdown on the "admin"
|
||||
And I should see the role dropdown on the "author"
|
||||
And I should see delete on the "admin"
|
||||
And I should not see delete on myself
|
||||
And I should see delete on the "author"
|
||||
|
||||
Scenario: Accessing site settings as an Author
|
||||
Given I am an authenticated "author"
|
||||
When I go to site settings
|
||||
Then I should not see "import"
|
||||
And I should not see "add account"
|
||||
And I should see "SEO settings"
|
||||
And I should not see "Access points"
|
||||
And I should not see "Accounts"
|
||||
# Paranoid Checks
|
||||
And I should not see any role dropdowns
|
||||
And I should not see any delete buttons
|
31
features/admin/authorization/importing.feature
Normal file
31
features/admin/authorization/importing.feature
Normal file
@ -0,0 +1,31 @@
|
||||
Feature: Importing a Site
|
||||
In order to populate the site with data and assets
|
||||
As an admin, designer, or author
|
||||
I will be restricted based on my role
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And I have a designer and an author
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I go to import page
|
||||
Then I should see "Log in"
|
||||
|
||||
Scenario: Accessing importing functionality as an Admin
|
||||
Given I am an authenticated "admin"
|
||||
When I go to the import page
|
||||
Then I should see "Import"
|
||||
And I should see "Upload"
|
||||
|
||||
Scenario: Accessing importing functionality as a Designer
|
||||
Given I am an authenticated "designer"
|
||||
When I go to the import page
|
||||
Then I should see "Import"
|
||||
And I should see "Upload"
|
||||
|
||||
Scenario: Accessing importing functionality as an Author
|
||||
Given I am an authenticated "author"
|
||||
When I go to the import page
|
||||
Then I should be on the pages list
|
||||
And I should see the access denied message
|
95
features/admin/authorization/pages.feature
Normal file
95
features/admin/authorization/pages.feature
Normal file
@ -0,0 +1,95 @@
|
||||
Feature: Pages
|
||||
In order to ensure pages are not tampered with
|
||||
As an admin, designer or author
|
||||
I will be restricted based on my role
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And I have a custom project model
|
||||
And I have a designer and an author
|
||||
And a page named "hello-world" with the template:
|
||||
"""
|
||||
Hello World
|
||||
"""
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I go to pages
|
||||
Then I should see "Log in"
|
||||
|
||||
# listing pages
|
||||
|
||||
Scenario: Accessing pages as an Admin
|
||||
Given I am an authenticated "admin"
|
||||
When I go to pages
|
||||
Then I should see "new page"
|
||||
And I should see "new model"
|
||||
And I should see "Projects"
|
||||
And I should see "edit model"
|
||||
And I should see delete page buttons
|
||||
|
||||
Scenario: Accessing pages as a Designer
|
||||
Given I am an authenticated "designer"
|
||||
When I go to pages
|
||||
Then I should see "new page"
|
||||
And I should see "new model"
|
||||
And I should see "Projects"
|
||||
And I should see "edit model"
|
||||
And I should see delete page buttons
|
||||
|
||||
Scenario: Accessing pages as an Author
|
||||
Given I am an authenticated "author"
|
||||
When I go to pages
|
||||
Then I should not see "new page"
|
||||
And I should not see "new model"
|
||||
And I should see "Projects"
|
||||
And I should not see "edit model"
|
||||
And I should not see delete page buttons
|
||||
|
||||
# new page
|
||||
|
||||
Scenario: Accessing new page as an Admin
|
||||
Given I am an authenticated "admin"
|
||||
When I go to the new page
|
||||
Then I should see "New page"
|
||||
|
||||
Scenario: Accessing new page as a Designer
|
||||
Given I am an authenticated "designer"
|
||||
When I go to the new page
|
||||
Then I should see "New page"
|
||||
|
||||
Scenario: Accessing new page as an Author
|
||||
Given I am an authenticated "author"
|
||||
When I go to the new page
|
||||
Then I should be on the pages list
|
||||
And I should see the access denied message
|
||||
|
||||
# edit page
|
||||
|
||||
Scenario: Accessing edit page as an Admin
|
||||
Given I am an authenticated "admin"
|
||||
When I go to the "hello-world" edition page
|
||||
Then I should see "some title"
|
||||
And I should see "General information"
|
||||
And I should see "SEO settings"
|
||||
And I should see "Advanced options"
|
||||
And I should see "Template"
|
||||
|
||||
Scenario: Accessing edit page as a Designer
|
||||
Given I am an authenticated "designer"
|
||||
When I go to the "hello-world" edition page
|
||||
Then I should see "some title"
|
||||
And I should see "General information"
|
||||
And I should see "SEO settings"
|
||||
And I should see "Advanced options"
|
||||
And I should see "Template"
|
||||
|
||||
Scenario: Accessing edit page as an Author
|
||||
Given I am an authenticated "author"
|
||||
When I go to the "hello-world" edition page
|
||||
Then I should see "some title"
|
||||
And I should not see "General Information"
|
||||
And I should see "SEO settings"
|
||||
And I should not see "Advanced options"
|
||||
And I should not see "Template"
|
||||
|
43
features/admin/authorization/theme_assets.feature
Normal file
43
features/admin/authorization/theme_assets.feature
Normal file
@ -0,0 +1,43 @@
|
||||
Feature: Theme Assets
|
||||
In order to ensure theme assets are not tampered with
|
||||
As an admin, designer or author
|
||||
I will be restricted based on my role
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And I have a designer and an author
|
||||
|
||||
Scenario: As an unauthenticated user
|
||||
Given I am not authenticated
|
||||
When I go to theme assets
|
||||
Then I should see "Log in"
|
||||
|
||||
Scenario: Accessing theme assets as an Admin
|
||||
Given I am an authenticated "admin"
|
||||
When I go to theme assets
|
||||
Then I should see "all assets"
|
||||
And I should see "new snippet"
|
||||
And I should see "new file"
|
||||
And I should see "Snippets"
|
||||
And I should see "Style and javascript"
|
||||
And I should see "Images"
|
||||
|
||||
Scenario: Accessing theme assets as a Designer
|
||||
Given I am an authenticated "designer"
|
||||
When I go to theme assets
|
||||
Then I should see "all assets"
|
||||
And I should see "new snippet"
|
||||
And I should see "new file"
|
||||
And I should see "Snippets"
|
||||
And I should see "Style and javascript"
|
||||
And I should see "Images"
|
||||
|
||||
Scenario: Accessing theme assets as an Author
|
||||
Given I am an authenticated "author"
|
||||
When I go to theme assets
|
||||
Then I should not see "all assets"
|
||||
And I should not see "new snippet"
|
||||
And I should not see "new file"
|
||||
And I should not see "Snippets"
|
||||
And I should not see "Style and javascript"
|
||||
And I should see "Images"
|
@ -15,7 +15,7 @@ Scenario: Pages list is not accessible for non authenticated accounts
|
||||
Scenario: Creating a valid page
|
||||
When I go to pages
|
||||
And I follow "new page"
|
||||
And I fill in "Title" with "Test"
|
||||
And I fill in "page_title" with "Test"
|
||||
And I fill in "Slug" with "test"
|
||||
And I select "Home page" from "Parent"
|
||||
And I fill in "Raw template" with "Lorem ipsum...."
|
||||
@ -26,7 +26,7 @@ Scenario: Creating a valid page
|
||||
Scenario: Updating a valid page
|
||||
When I go to pages
|
||||
And I follow "Home page"
|
||||
And I fill in "Title" with "Home page !"
|
||||
And I fill in "page_title" with "Home page !"
|
||||
And I fill in "Raw template" with "My new content is here"
|
||||
And I press "Update"
|
||||
Then I should see "Page was successfully updated."
|
||||
|
@ -30,6 +30,17 @@ Scenario: Uploading a stylesheet
|
||||
And I should see "Code"
|
||||
And I should see "stylesheets/main.css"
|
||||
|
||||
Scenario: Updating a stylesheet
|
||||
Given a stylesheet asset named "application"
|
||||
When I go to theme assets
|
||||
And I follow "stylesheets/application.css"
|
||||
And I fill in "theme_asset[plain_text]" with "Lorem ipsum (updated)"
|
||||
And I press "Update"
|
||||
Then I should see "File was successfully updated."
|
||||
And I should see "Editing application.css"
|
||||
And I should see "application.css"
|
||||
And I should see "Lorem ipsum (updated)" as theme asset code
|
||||
|
||||
Scenario: Uploading a javascript
|
||||
When I go to theme assets
|
||||
And I follow "new file"
|
||||
@ -40,6 +51,14 @@ Scenario: Uploading a javascript
|
||||
And I should see "Code"
|
||||
And I should see "javascripts/test/application.js"
|
||||
|
||||
Scenario: Updating a javascript
|
||||
Given a javascript asset named "application"
|
||||
When I go to theme assets
|
||||
And I follow "javascripts/application.js"
|
||||
And I fill in "theme_asset[plain_text]" with "Lorem ipsum (updated)"
|
||||
And I press "Update"
|
||||
Then I should see "File was successfully updated."
|
||||
|
||||
Scenario: Uploading an image which already exists
|
||||
When I go to theme assets
|
||||
And I follow "new file"
|
||||
|
@ -4,13 +4,23 @@ Given /^I am not authenticated$/ do
|
||||
visit('/admin/sign_out')
|
||||
end
|
||||
|
||||
Given /^I am an authenticated user$/ do
|
||||
Given /^I am an authenticated "([^"]*)"$/ do |role|
|
||||
@member = Site.first.memberships.where(:role => role.downcase).first || Factory(role.downcase.to_sym, :site => Site.first)
|
||||
|
||||
Given %{I go to login}
|
||||
And %{I fill in "Email" with "admin@locomotiveapp.org"}
|
||||
And %{I fill in "Email" with "#{@member.account.email}"}
|
||||
And %{I fill in "Password" with "easyone"}
|
||||
And %{I press "Log in"}
|
||||
end
|
||||
|
||||
Given /^I am an authenticated user$/ do
|
||||
Given %{I am an authenticated "admin"}
|
||||
end
|
||||
|
||||
Then /^I should see the access denied message$/ do
|
||||
Then %{I should see "You are not authorized to access this page"}
|
||||
end
|
||||
|
||||
Then /^I am redirected to "([^\"]*)"$/ do |url|
|
||||
assert [301, 302].include?(@integration_session.status), "Expected status to be 301 or 302, got #{@integration_session.status}"
|
||||
location = @integration_session.headers["Location"]
|
||||
@ -27,3 +37,7 @@ end
|
||||
|
||||
### Common
|
||||
|
||||
Then /^I debug$/ do
|
||||
debugger
|
||||
0
|
||||
end
|
||||
|
7
features/step_definitions/content_types_steps.rb
Normal file
7
features/step_definitions/content_types_steps.rb
Normal file
@ -0,0 +1,7 @@
|
||||
Given /^I have a custom project model/ do
|
||||
site = Site.first
|
||||
@content_type = Factory.build(:content_type, :site => site, :name => 'Projects')
|
||||
@content_type.content_custom_fields.build :label => 'Name', :kind => 'string'
|
||||
@content_type.content_custom_fields.build :label => 'Description', :kind => 'text'
|
||||
@content_type.save.should be_true
|
||||
end
|
35
features/step_definitions/current_site_steps.rb
Normal file
35
features/step_definitions/current_site_steps.rb
Normal file
@ -0,0 +1,35 @@
|
||||
Then /^I should see the role dropdown on the "([^"]*)"$/ do |user|
|
||||
find(:css, "li.membership[data-role=#{user}] select").text.should == 'AdministratorDesignerAuthor'
|
||||
end
|
||||
|
||||
Then /^I should see the role dropdown on myself$/ do
|
||||
Then %{I should see the role dropdown on the "#{@member.role}"}
|
||||
end
|
||||
|
||||
Then /^I should not see the role dropdown on the "([^"]*)"$/ do |user|
|
||||
page.has_css?("li.membership[data-role=#{user}] select").should be_false
|
||||
end
|
||||
|
||||
Then /^I should not see the role dropdown on myself$/ do
|
||||
Then %{I should not see the role dropdown on the "#{@member.role}"}
|
||||
end
|
||||
|
||||
Then /^I should not see any role dropdowns$/ do
|
||||
page.has_css?('li.membership select').should be_false
|
||||
end
|
||||
|
||||
Then /^I should see delete on the "([^"]*)"$/ do |role|
|
||||
page.has_css?("li.membership[data-role=#{role}] .actions a.remove").should be_true
|
||||
end
|
||||
|
||||
Then /^I should not see delete on the "([^"]*)"$/ do |role|
|
||||
page.has_css?("li.membership[data-role=#{role}] .actions a.remove").should be_false
|
||||
end
|
||||
|
||||
Then /^I should not see delete on myself$/ do
|
||||
Then %{I should not see delete on the "#{@member.role}"}
|
||||
end
|
||||
|
||||
Then /^I should not see any delete buttons$/ do
|
||||
page.has_css?('li.membership .actions a.remove').should be_false
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user