locomotive_cms 2.0.0.rc11 → 2.0.0.rc12
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/app/assets/javascripts/locomotive/utils/tinymce_settings.js.coffee +3 -3
- data/app/assets/javascripts/locomotive/views/content_entries/_popup_form_view.js.coffee +1 -1
- data/app/assets/javascripts/locomotive/views/editable_elements/long_text_view.js.coffee +2 -2
- data/app/controllers/locomotive/api/base_controller.rb +4 -4
- data/app/controllers/locomotive/api/memberships_controller.rb +2 -2
- data/app/controllers/locomotive/api/my_account_controller.rb +18 -0
- data/app/controllers/locomotive/api/sites_controller.rb +1 -1
- data/app/controllers/locomotive/current_site_controller.rb +2 -0
- data/app/controllers/locomotive/passwords_controller.rb +6 -0
- data/app/mailers/locomotive/notifications.rb +2 -2
- data/app/models/locomotive/content_entry.rb +13 -1
- data/app/models/locomotive/editable_element.rb +4 -0
- data/app/models/locomotive/extensions/page/editable_elements.rb +7 -4
- data/app/models/locomotive/extensions/page/templatized.rb +14 -0
- data/app/models/locomotive/extensions/page/tree.rb +9 -0
- data/app/models/locomotive/extensions/site/locales.rb +7 -1
- data/app/models/locomotive/page.rb +8 -4
- data/app/presenters/locomotive/content_entry_presenter.rb +4 -4
- data/app/presenters/locomotive/page_presenter.rb +2 -2
- data/app/views/locomotive/current_site/edit.html.haml +3 -0
- data/app/views/locomotive/devise_mailer/reset_password_instructions.html.haml +2 -2
- data/app/views/locomotive/notifications/new_content_entry.html.haml +2 -4
- data/app/views/locomotive/pages/_form.html.haml +4 -0
- data/app/views/locomotive/passwords/edit.html.haml +1 -1
- data/config/locales/admin_ui.de.yml +1 -1
- data/config/locales/admin_ui.en.yml +2 -2
- data/config/locales/admin_ui.es.yml +1 -1
- data/config/locales/admin_ui.et.yml +1 -1
- data/config/locales/admin_ui.fr.yml +3 -3
- data/config/locales/admin_ui.it.yml +1 -1
- data/config/locales/admin_ui.nb.yml +1 -1
- data/config/locales/admin_ui.nl.yml +1 -1
- data/config/locales/admin_ui.pt-BR.yml +1 -1
- data/config/locales/admin_ui.ru.yml +1 -1
- data/config/locales/default.de.yml +2 -1
- data/config/locales/default.fr.yml +6 -3
- data/config/locales/devise.de.yml +11 -11
- data/config/locales/devise.en.yml +1 -1
- data/config/locales/devise.es.yml +9 -9
- data/config/locales/devise.et.yml +1 -1
- data/config/locales/devise.fr.yml +12 -12
- data/config/locales/devise.it.yml +11 -11
- data/config/locales/devise.nb.yml +3 -3
- data/config/locales/devise.nl.yml +10 -10
- data/config/locales/devise.pt-BR.yml +11 -11
- data/config/locales/devise.ru.yml +1 -1
- data/config/locales/flash.fr.yml +1 -1
- data/config/routes.rb +4 -2
- data/lib/generators/locomotive/install/templates/carrierwave.rb +1 -1
- data/lib/locomotive/liquid/tags/editable/base.rb +17 -9
- data/lib/locomotive/middlewares/inline_editor.rb +2 -2
- data/lib/locomotive/routing/site_dispatcher.rb +1 -1
- data/lib/locomotive/version.rb +1 -1
- data/vendor/assets/javascripts/locomotive/datepicker_i18n.js.erb +28 -0
- metadata +9 -11
- data/app/views/locomotive/mailer/confirmation_instructions.html.haml +0 -8
- data/app/views/locomotive/mailer/reset_password_instructions.html.haml +0 -12
- data/app/views/locomotive/mailer/unlock_instructions.html.haml +0 -10
- data/vendor/assets/javascripts/locomotive/datepicker_fr.js +0 -16
data/Gemfile
CHANGED
@@ -12,6 +12,7 @@ group :development do
|
|
12
12
|
# gem 'custom_fields', :git => 'git://github.com/locomotivecms/custom_fields.git', :branch => '2.0.0.rc' # Branch on Github
|
13
13
|
|
14
14
|
# gem 'locomotive-aloha-rails', :path => '../gems/aloha-rails' # for Developers
|
15
|
+
# gem 'locomotive-tinymce-rails', '~> 3.4.7.3', :path => '../gems/tinymce-rails' # for Developers
|
15
16
|
# gem 'locomotive_liquid', :path => '../gems/liquid' # for Developers
|
16
17
|
|
17
18
|
gem 'rspec-rails', '~> 2.8.0' # In order to have rspec tasks and generators
|
@@ -3,9 +3,9 @@ window.Locomotive.tinyMCE =
|
|
3
3
|
defaultSettings:
|
4
4
|
theme: 'advanced'
|
5
5
|
skin: 'locomotive'
|
6
|
-
plugins: 'safari,jqueryinlinepopups,locomotive_media,fullscreen'
|
6
|
+
plugins: 'safari,jqueryinlinepopups,table,locomotive_media,fullscreen'
|
7
7
|
extended_valid_elements: 'iframe[width|height|frameborder|allowfullscreen|src|title]'
|
8
|
-
theme_advanced_buttons1: 'fullscreen,code,|,bold,italic,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,outdent,indent,blockquote,|,link,unlink,|,locomotive_media'
|
8
|
+
theme_advanced_buttons1: 'fullscreen,code,|,bold,italic,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,outdent,indent,blockquote,|,link,unlink,|,table,|,locomotive_media'
|
9
9
|
theme_advanced_buttons2: 'formatselect,fontselect,fontsizeselect'
|
10
10
|
theme_advanced_buttons3: ''
|
11
11
|
theme_advanced_toolbar_location: 'top'
|
@@ -33,7 +33,7 @@ window.Locomotive.tinyMCE =
|
|
33
33
|
popupSettings:
|
34
34
|
theme: 'advanced'
|
35
35
|
skin: 'locomotive'
|
36
|
-
plugins: 'safari,jqueryinlinepopups,locomotive_media,fullscreen'
|
36
|
+
plugins: 'safari,jqueryinlinepopups,locomotive_media,fullscreen'
|
37
37
|
extended_valid_elements: 'iframe[width|height|frameborder|allowfullscreen|src|title]'
|
38
38
|
theme_advanced_buttons1: 'fullscreen,code,|,bold,italic,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,outdent,indent,blockquote,|,link,unlink,|,locomotive_media'
|
39
39
|
theme_advanced_buttons2: 'formatselect,fontselect,fontsizeselect'
|
@@ -14,7 +14,7 @@ class Locomotive.Views.EditableElements.LongTextView extends Backbone.View
|
|
14
14
|
return @
|
15
15
|
|
16
16
|
after_render: ->
|
17
|
-
settings = _.extend {}, @tinymce_settings(),
|
17
|
+
settings = _.extend {}, @tinymce_settings(),
|
18
18
|
oninit: ((editor) =>
|
19
19
|
$.cmd 'S', (() =>
|
20
20
|
@model.set(content: editor.getBody().innerHTML)
|
@@ -26,7 +26,7 @@ class Locomotive.Views.EditableElements.LongTextView extends Backbone.View
|
|
26
26
|
@$('textarea').tinymce(settings)
|
27
27
|
|
28
28
|
tinymce_settings: ->
|
29
|
-
window.Locomotive.tinyMCE.defaultSettings
|
29
|
+
_.extend { language: window.locale }, window.Locomotive.tinyMCE.defaultSettings
|
30
30
|
|
31
31
|
refresh: ->
|
32
32
|
# do nothing
|
@@ -21,10 +21,10 @@ module Locomotive
|
|
21
21
|
|
22
22
|
protected
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
def set_current_thread_variables
|
25
|
+
Thread.current[:account] = current_locomotive_account
|
26
|
+
Thread.current[:site] = current_site
|
27
|
+
end
|
28
28
|
|
29
29
|
def current_ability
|
30
30
|
@current_ability ||= Ability.new(current_locomotive_account, current_site)
|
@@ -3,8 +3,8 @@ module Locomotive
|
|
3
3
|
class MembershipsController < BaseController
|
4
4
|
|
5
5
|
# It's an embedded document, so we'll just load manually
|
6
|
-
before_filter :load_membership, :only => [
|
7
|
-
before_filter :load_memberships, :only => [
|
6
|
+
before_filter :load_membership, :only => [:show, :update, :destroy]
|
7
|
+
before_filter :load_memberships, :only => [:index]
|
8
8
|
|
9
9
|
authorize_resource :class => Locomotive::Membership
|
10
10
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Api
|
3
|
+
class MyAccountController < BaseController
|
4
|
+
|
5
|
+
skip_load_and_authorize_resource
|
6
|
+
|
7
|
+
# FIXME: the auto-loaded site won't pass authorization for show, update, or destroy
|
8
|
+
# skip_load_and_authorize_resource :only => [ :show, :update, :destroy ]
|
9
|
+
|
10
|
+
def show
|
11
|
+
respond_with(current_locomotive_account)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -5,7 +5,7 @@ module Locomotive
|
|
5
5
|
load_and_authorize_resource :class => Locomotive::Site
|
6
6
|
|
7
7
|
# FIXME: the auto-loaded site won't pass authorization for show, update, or destroy
|
8
|
-
skip_load_and_authorize_resource :only => [
|
8
|
+
skip_load_and_authorize_resource :only => [:show, :update, :destroy]
|
9
9
|
|
10
10
|
def index
|
11
11
|
@sites = Locomotive::Site.all
|
@@ -4,9 +4,9 @@ module Locomotive
|
|
4
4
|
default :from => Locomotive.config.mailer_sender
|
5
5
|
|
6
6
|
def new_content_entry(account, entry)
|
7
|
-
@account, @entry, @type = account, entry, entry.content_type
|
7
|
+
@account, @entry, @type, @domain = account, entry, entry.content_type, entry.site.domains.first
|
8
8
|
|
9
|
-
subject = t('locomotive.notifications.new_content_entry.subject', :type => @type.name, :locale => account.locale)
|
9
|
+
subject = t('locomotive.notifications.new_content_entry.subject', :domain => @domain, :type => @type.name, :locale => account.locale)
|
10
10
|
|
11
11
|
mail :subject => subject, :to => account.email
|
12
12
|
end
|
@@ -57,7 +57,7 @@ module Locomotive
|
|
57
57
|
|
58
58
|
alias :to_label :_label
|
59
59
|
|
60
|
-
#
|
60
|
+
# Tell if the content entry has been translated or not.
|
61
61
|
# It just checks if the field used for the label has been translated.
|
62
62
|
#
|
63
63
|
# @return [ Boolean ] True if translated, false otherwise
|
@@ -70,6 +70,18 @@ module Locomotive
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
+
# Return the locales the content entry has been translated to.
|
74
|
+
#
|
75
|
+
# @return [ Array ] The list of locales. Nil if not localized
|
76
|
+
#
|
77
|
+
def translated_in
|
78
|
+
if self.respond_to?(:"#{self._label_field_name}_translations")
|
79
|
+
self.send(:"#{self._label_field_name}_translations").keys
|
80
|
+
else
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
73
85
|
# Return the next content entry based on the order defined in the parent content type.
|
74
86
|
#
|
75
87
|
# @param [ Object ] The next content entry or nil if not found
|
@@ -31,6 +31,10 @@ module Locomotive
|
|
31
31
|
!!self.disabled # the original method does not work quite well with the localization
|
32
32
|
end
|
33
33
|
|
34
|
+
def disabled_in_all_translations?
|
35
|
+
self.disabled_translations.all? { |_, v| v == true }
|
36
|
+
end
|
37
|
+
|
34
38
|
# Determines if the current element can be edited in the back-office
|
35
39
|
#
|
36
40
|
def editable?
|
@@ -72,8 +72,8 @@ module Locomotive
|
|
72
72
|
else
|
73
73
|
existing_el.disabled = false
|
74
74
|
|
75
|
-
# only the type and
|
76
|
-
%w(_type hint).each do |attr|
|
75
|
+
# only the type, hint and fixed properties can be modified from the parent element
|
76
|
+
%w(_type hint fixed).each do |attr|
|
77
77
|
existing_el.send(:"#{attr}=", el.send(attr.to_sym))
|
78
78
|
end
|
79
79
|
end
|
@@ -81,10 +81,13 @@ module Locomotive
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def remove_disabled_editable_elements
|
84
|
-
|
84
|
+
# get only those which are fully disabled, meaning in ALL the locales
|
85
|
+
ids = self.editable_elements.find_all { |el| el.disabled_in_all_translations? }.map(&:_id)
|
86
|
+
|
87
|
+
return if ids.empty?
|
85
88
|
|
86
89
|
# super fast way to remove useless elements all in once
|
87
|
-
self.collection.update(self.atomic_selector, '$pull' => { 'editable_elements' => {
|
90
|
+
self.collection.update(self.atomic_selector, '$pull' => { 'editable_elements' => { '_id' => { '$in' => ids } } })
|
88
91
|
end
|
89
92
|
|
90
93
|
end
|
@@ -42,6 +42,20 @@ module Locomotive
|
|
42
42
|
target_klass_name.constantize
|
43
43
|
end
|
44
44
|
|
45
|
+
# Returns the slug related to the target_klass.
|
46
|
+
# In other words, it returns the slug of the target content type.
|
47
|
+
#
|
48
|
+
# @return [ String ] The slug of the target class / content type. Nil if no target klass.
|
49
|
+
#
|
50
|
+
def target_klass_slug
|
51
|
+
if self.target_klass_name =~ /^Locomotive::Entry([a-z0-9]+)$/
|
52
|
+
@content_type ||= self.site.content_types.find($1)
|
53
|
+
@content_type.slug
|
54
|
+
else
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
45
59
|
# Gives the name which can be used in a liquid template in order
|
46
60
|
# to reference an entry. It uses the slug property if the target klass
|
47
61
|
# is a Locomotive content type or the class name itself for the other classes.
|
@@ -22,6 +22,7 @@ module Locomotive
|
|
22
22
|
|
23
23
|
alias_method_chain :rearrange, :identity_map
|
24
24
|
alias_method_chain :rearrange_children, :identity_map
|
25
|
+
alias_method_chain :siblings_and_self, :scoping
|
25
26
|
end
|
26
27
|
|
27
28
|
module ClassMethods
|
@@ -98,6 +99,14 @@ module Locomotive
|
|
98
99
|
end
|
99
100
|
end
|
100
101
|
|
102
|
+
##
|
103
|
+
# Returns this document's siblings and itself, all scoped by the site
|
104
|
+
#
|
105
|
+
# @return [Mongoid::Criteria] Mongoid criteria to retrieve the document's siblings and itself
|
106
|
+
def siblings_and_self_with_scoping
|
107
|
+
base_class.where(:parent_id => self.parent_id, :site_id => self.site_id)
|
108
|
+
end
|
109
|
+
|
101
110
|
def depth
|
102
111
|
self.parent_ids.count
|
103
112
|
end
|
@@ -41,7 +41,13 @@ module Locomotive
|
|
41
41
|
locale = (locale || I18n.locale).to_s
|
42
42
|
fullpath = page.fullpath_translations[locale] || page.fullpath_translations[self.default_locale]
|
43
43
|
|
44
|
-
locale == self.default_locale
|
44
|
+
if locale == self.default_locale.to_s # no need to specify the locale
|
45
|
+
page.index? ? '' : fullpath
|
46
|
+
elsif page.index? # avoid /en/index or /fr/index, prefer /en or /fr instead
|
47
|
+
locale
|
48
|
+
else
|
49
|
+
File.join(locale, fullpath)
|
50
|
+
end
|
45
51
|
end
|
46
52
|
|
47
53
|
def locales=(array)
|
@@ -40,10 +40,10 @@ module Locomotive
|
|
40
40
|
before_destroy :do_not_remove_index_and_404_pages
|
41
41
|
|
42
42
|
## validations ##
|
43
|
-
validates_presence_of :site,
|
44
|
-
validates_uniqueness_of :slug,
|
45
|
-
validates_uniqueness_of :handle, :allow_blank => true
|
46
|
-
validates_exclusion_of :slug,
|
43
|
+
validates_presence_of :site, :title, :slug
|
44
|
+
validates_uniqueness_of :slug, :scope => [:site_id, :parent_id]
|
45
|
+
validates_uniqueness_of :handle, :scope => :site_id, :allow_blank => true
|
46
|
+
validates_exclusion_of :slug, :in => Locomotive.config.reserved_slugs, :if => Proc.new { |p| p.depth <= 1 }
|
47
47
|
|
48
48
|
## named scopes ##
|
49
49
|
scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.ui[:latest_entries_nb]
|
@@ -81,6 +81,10 @@ module Locomotive
|
|
81
81
|
self.title_translations.key?(::Mongoid::Fields::I18n.locale.to_s) rescue false
|
82
82
|
end
|
83
83
|
|
84
|
+
def translated_in
|
85
|
+
self.title_translations.keys
|
86
|
+
end
|
87
|
+
|
84
88
|
def to_liquid
|
85
89
|
Locomotive::Liquid::Drops::Page.new(self)
|
86
90
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Locomotive
|
2
2
|
class ContentEntryPresenter < BasePresenter
|
3
3
|
|
4
|
-
delegate
|
5
|
-
|
6
|
-
|
4
|
+
delegate :_label, :_slug, :_position, :translated_in, :seo_title,
|
5
|
+
:meta_keywords, :meta_description, :select_custom_fields,
|
6
|
+
:file_custom_fields, :has_many_custom_fields, :many_to_many_custom_fields, :to => :source
|
7
7
|
|
8
8
|
# Lists of all the attributes editable thru the html form for instance
|
9
9
|
#
|
@@ -33,7 +33,7 @@ module Locomotive
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def included_methods
|
36
|
-
default_list = %w(_label _slug _position content_type_slug select_custom_fields file_custom_fields has_many_custom_fields many_to_many_custom_fields safe_attributes)
|
36
|
+
default_list = %w(_label _slug _position content_type_slug select_custom_fields file_custom_fields has_many_custom_fields many_to_many_custom_fields translated_in safe_attributes)
|
37
37
|
default_list << 'errors' if !!self.options[:include_errors]
|
38
38
|
super + self.filtered_custom_fields_methods + default_list
|
39
39
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Locomotive
|
2
2
|
class PagePresenter < BasePresenter
|
3
3
|
|
4
|
-
delegate :title, :slug, :fullpath, :handle, :raw_template, :published, :listed, :templatized, :templatized_from_parent, :redirect, :redirect_url, :template_changed, :cache_strategy, :response_type, :to => :source
|
4
|
+
delegate :title, :slug, :fullpath, :handle, :position, :raw_template, :published, :listed, :templatized, :templatized_from_parent, :target_klass_slug, :redirect, :redirect_url, :template_changed, :cache_strategy, :response_type, :translated_in, :to => :source
|
5
5
|
|
6
6
|
def escaped_raw_template
|
7
7
|
h(self.source.raw_template)
|
@@ -12,7 +12,7 @@ module Locomotive
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def included_methods
|
15
|
-
super + %w(title slug fullpath handle raw_template published listed templatized templatized_from_parent redirect redirect_url cache_strategy response_type template_changed editable_elements localized_fullpaths)
|
15
|
+
super + %w(title slug fullpath handle position raw_template published listed templatized templatized_from_parent target_klass_slug redirect redirect_url cache_strategy response_type template_changed editable_elements localized_fullpaths translated_in)
|
16
16
|
end
|
17
17
|
|
18
18
|
def localized_fullpaths
|
@@ -3,6 +3,9 @@
|
|
3
3
|
- content_for :submenu do
|
4
4
|
= render_cell 'locomotive/settings_menu', :show
|
5
5
|
|
6
|
+
- content_for :actions do
|
7
|
+
= locale_picker_link
|
8
|
+
|
6
9
|
- content_for :buttons do
|
7
10
|
- if can?(:create, Locomotive::Account)
|
8
11
|
= local_action_button t('.new_membership'), new_membership_url, :class => 'new'
|
@@ -1,11 +1,11 @@
|
|
1
1
|
%p
|
2
|
-
!= t('locomotive.
|
2
|
+
!= t('locomotive.devise_mailer.common.hello')
|
3
3
|
= @resource.email
|
4
4
|
\!
|
5
5
|
%p
|
6
6
|
!= t('.reset_password_instruction')
|
7
7
|
%p
|
8
|
-
= link_to t('.change_my_password'),
|
8
|
+
= link_to t('.change_my_password'), edit_locomotive_account_password_url(:reset_password_token => @resource.reset_password_token)
|
9
9
|
%p
|
10
10
|
!= t('.wrong_request_instruction')
|
11
11
|
%p
|
@@ -1,6 +1,4 @@
|
|
1
|
-
%p= t('.title', :name => @account.name, :date => I18n.l(Time.now), :locale => @account.locale)
|
2
|
-
|
3
|
-
%hr
|
1
|
+
%p= t('.title', :name => @account.name, :domain => @domain, :date => I18n.l(Time.now), :locale => @account.locale).html_safe
|
4
2
|
|
5
3
|
%p
|
6
4
|
%b= t('.type', :type => @type.name, :locale => @account.locale)
|
@@ -21,7 +19,7 @@
|
|
21
19
|
= value
|
22
20
|
- when 'file'
|
23
21
|
- url = value.guess_url
|
24
|
-
- url = url =~ /^http/ ? url : URI.join("http://#{@
|
22
|
+
- url = url =~ /^http/ ? url : URI.join("http://#{@domain}", url).to_s # Amazon S3 (http/https) or local files ?
|
25
23
|
= link_to File.basename(url), url
|
26
24
|
- when 'select'
|
27
25
|
= value
|
@@ -18,6 +18,10 @@
|
|
18
18
|
|
19
19
|
= f.input :slug, :required => false, :hint => @page.slug.blank? ? t('.empty_slug') : public_page_url(@page), :input_html => { :'data-url' => get_path_pages_url, :disabled => @page.index? || @page.not_found? }, :wrapper_html => { :style => "#{'display: none' if @page.templatized? && !@page.templatized_from_parent?};", :class => 'em-inline-hints' }
|
20
20
|
|
21
|
+
- else
|
22
|
+
= f.inputs :name => :information, :style => 'display: none' do
|
23
|
+
= f.text_field :title
|
24
|
+
|
21
25
|
= f.inputs :name => :seo, :class => "inputs foldable #{'folded' if inputs_folded?(@page)}" do
|
22
26
|
|
23
27
|
= f.input :seo_title
|
@@ -1,6 +1,6 @@
|
|
1
1
|
- title t('.title')
|
2
2
|
|
3
|
-
= semantic_form_for(resource, :as => resource_name, :url =>
|
3
|
+
= semantic_form_for(resource, :as => resource_name, :url => locomotive_account_password_url, :html => { :method => :put }) do |f|
|
4
4
|
|
5
5
|
= f.hidden_field :reset_password_token
|
6
6
|
|
@@ -68,8 +68,8 @@ en:
|
|
68
68
|
|
69
69
|
notifications:
|
70
70
|
new_content_entry:
|
71
|
-
subject: "[%{type}] new"
|
72
|
-
title: "Hi %{name}, just to let you know that a new instance has been created on %{date}"
|
71
|
+
subject: "[%{domain}][%{type}] new entry"
|
72
|
+
title: "Hi %{name}, just to let you know that a new instance has been created on %{date} for the site <b>%{domain}</b>"
|
73
73
|
type: "Model: %{type}"
|
74
74
|
|
75
75
|
sites_picker:
|