entry submission has been implemented

did committed Jan 08, 2013
commit ff3d5245705336ba7bdad6eb79cde544506c0a93
Showing 10 changed files with 424 additions and 37 deletions
TODO +9 -3
@@ @@ -6,9 +6,15 @@ x dragonfly
- listen:
x content types and content entries / site
- make it work for other platforms (linux, windows)
- - post content entry (WIP)
+ x post content entry
+ x liquid assigns: sessions (rack)
- I18n keys
- - liquid assigns: sessions (rack)
+ x fr/en
+ - other locales
+ - static js/css assets (non coffeescript or sass files) are not reloaded if got changed.
+ - content types / liquid
+ - group_contents_by
+ - select_names
- nice error page (replace the default exception middleware) to display:
- liquid errors
- other exceptions
@@ @@ -17,7 +23,7 @@ x dragonfly
- push:
- option to select to push only some parts (pages, ...etc)
- --force option
- - static js/css assets (non coffeescript or sass files) are not reloaded if got changed.
+
- translations
locomotive/builder/liquid/drops/content_entry.rb b/lib/locomotive/builder/liquid/drops/content_entry.rb +7 -0
@@ @@ -22,6 +22,13 @@ module Locomotive
self
end
+ def errors
+ (@_source.errors || []).inject({}) do |memo, name|
+ memo[name] = ::I18n.t('errors.messages.blank')
+ memo
+ end
+ end
+
def before_method(meth)
return '' if self._source.nil?
locomotive/builder/misc.rb b/lib/locomotive/builder/misc.rb +2 -1
@@ @@ -1,3 +1,4 @@
require 'locomotive/builder/misc/will_paginate.rb'
require 'locomotive/builder/misc/httparty.rb'
- require 'locomotive/builder/misc/dragonfly.rb'
\ No newline at end of file
+ require 'locomotive/builder/misc/dragonfly.rb'
+ require 'locomotive/builder/misc/i18n.rb'
\ No newline at end of file
locomotive/builder/misc/i18n.rb b/lib/locomotive/builder/misc/i18n.rb +4 -0
@@ @@ -0,0 +1,4 @@
+ Dir[File.join(File.dirname(__FILE__), "/../../../../locales/*.yml")].each do |locale|
+ puts "[Builder|I18n] register #{locale}"
+ ::I18n.config.load_path << locale
+ end
\ No newline at end of file
locomotive/builder/server.rb b/lib/locomotive/builder/server.rb +10 -2
@@ @@ -40,6 +40,14 @@ module Locomotive::Builder
use Rack::ShowExceptions
use Rack::Lint
+ use Rack::Session::Cookie, {
+ key: 'rack.session',
+ domain: '0.0.0.0',
+ path: '/',
+ expire_after: 2592000,
+ secret: 'uselessinlocal'
+ }
+
use ::Dragonfly::Middleware, :images
use Rack::Static, {
@@ @@ -50,11 +58,11 @@ module Locomotive::Builder
use Favicon
use DynamicAssets
+ use EntrySubmission
+
use Path
use Locale
- use EntrySubmission
-
use Page
use TemplatizedPage
use NotFound
locomotive/builder/server/entry_submission.rb b/lib/locomotive/builder/server/entry_submission.rb +77 -20
@@ @@ -3,54 +3,111 @@ module Locomotive::Builder
# Mimic the submission of a content entry
#
- #
class EntrySubmission < Middleware
def call(env)
self.set_accessors(env)
- if self.request.post? && self.path =~ /^entry_submissions\/(.*)/
+ if self.request.post? && env['PATH_INFO'] =~ /^\/entry_submissions\/(.*)/
self.process_form($1)
- # TODO
- [200, { 'Content-Type' => 'text/html' }, ["POST !!! #{$1}"]]
+ if @entry.valid?
+ if self.html?
+ self.record_submitted_entry
+ self.redirect_to self.callback_url
+ elsif self.json?
+ self.json_response
+ end
+ else
+ if self.html?
+ if self.callback_url =~ /^http:\/\//
+ self.redirect_to self.callback_url
+ else
+ env['PATH_INFO'] = self.callback_url
+ self.liquid_assigns[@content_type.slug.singularize] = @entry
+ app.call(env)
+ end
+ elsif self.json?
+ self.json_response(422)
+ end
+ end
else
+ self.fetch_submitted_entry
+
app.call(env)
end
end
protected
+ def record_submitted_entry
+ self.request.session[:now] ||= {}
+ self.request.session[:now][:submitted_entry] = [@content_type.slug, @entry._slug]
+ end
+
+ def fetch_submitted_entry
+ if data = self.request.session[:now].try(:delete, :submitted_entry)
+ content_type = self.mounting_point.content_types[data.first.to_s]
+
+ entry = (content_type.entries || []).detect { |e| e._slug == data.last }
+
+ # do not keep track of the entry
+ content_type.entries.delete(entry) if entry
+
+ # add it to the additional liquid assigns for the next liquid rendering
+ if entry
+ self.liquid_assigns[content_type.slug.singularize] = entry
+ end
+ end
+ end
+
# Mimic the creation of a content entry with a minimal validation.
#
# @param [ String ] permalink The permalink (or slug) of the content type
#
- # @return [ Array ] The rack response depending on the validation status and the requested format
#
def process_form(permalink)
- content_type = self.mounting_point.content_types[permalink]
+ permalink = permalink.split('.').first
- raise "Unknown content type '#{content_type.inspect}'" if content_type.nil?
+ @content_type = self.mounting_point.content_types[permalink]
- puts "params = #{self.params.inspect}"
+ raise "Unknown content type '#{@content_type.inspect}'" if @content_type.nil?
- content_entry = self.build_entry(content_type, self.params[:entry] || self.params[:content])
+ @entry = @content_type.build_entry(self.params[:entry] || self.params[:content])
- if content_entry.valid?
- puts "valid content entry!"
- else
- puts "invalid content entry!"
- end
+ # if not valid, we do not need to keep track of the entry
+ @content_type.entries.delete(@entry) if !@entry.valid?
end
- def build_entry(content_type, attributes)
- Locomotive::Mounter::Models::ContentEntry.new(content_type: content_type).tap do |entry|
- # do not forget that we are manipulating dynamic fields
- attributes.each { |k, v| entry.send(:"#{k}=", v) }
+ def callback_url
+ (@entry.valid? ? params[:success_callback] : params[:error_callback]) || '/'
+ end
- # force the slug to be defined from its label and in all the locales
- entry.send :set_slug
+ # Build the JSON response
+ #
+ # @param [ Integer ] status The HTTP return code
+ #
+ # @return [ Array ] The rack response depending on the validation status and the requested format
+ #
+ def json_response(status = 200)
+ locale = self.mounting_point.default_locale
+
+ if self.request.path =~ /^\/(#{self.mounting_point.locales.join('|')})+(\/|$)/
+ locale = $1
end
+
+ hash = @entry.to_hash(false).tap do |_hash|
+ if !@entry.valid?
+ _hash['errors'] = @entry.errors.inject({}) do |memo, name|
+ memo[name] = ::I18n.t('errors.messages.blank', locale: locale)
+ memo
+ end
+ end
+ end
+
+ [status, { 'Content-Type' => 'application/json' }, [
+ { @content_type.slug.singularize => hash }.to_json
+ ]]
end
end
locomotive/builder/server/middleware.rb b/lib/locomotive/builder/server/middleware.rb +16 -1
@@ @@ -3,7 +3,7 @@ module Locomotive::Builder
class Middleware
- attr_accessor :app, :request, :path
+ attr_accessor :app, :request, :path, :liquid_assigns
attr_accessor :mounting_point, :page, :content_entry
@@ @@ -23,6 +23,9 @@ module Locomotive::Builder
self.mounting_point = env['builder.mounting_point']
self.page = env['builder.page']
self.content_entry = env['builder.content_entry']
+
+ env['builder.liquid_assigns'] ||= {}
+ self.liquid_assigns = env['builder.liquid_assigns']
end
def site
@@ @@ -33,6 +36,18 @@ module Locomotive::Builder
self.request.params.deep_symbolize_keys
end
+ def html?
+ self.request.media_type == 'text/html' || !self.request.xhr?
+ end
+
+ def json?
+ self.request.content_type == 'application/json' || File.extname(self.request.path) == '.json'
+ end
+
+ def redirect_to(location)
+ [301, { 'Content-Type' => 'text/html', 'Location' => location }, []]
+ end
+
end
end
locomotive/builder/server/renderer.rb b/lib/locomotive/builder/server/renderer.rb +2 -10
@@ @@ -18,7 +18,6 @@ module Locomotive::Builder
[200, { 'Content-Type' => type }, [html]]
end
else
- puts "argggg"
# no page at all, even not the 404 page
[404, { 'Content-Type' => 'text/html' }, ['Page not found']]
end
@@ @@ -47,8 +46,8 @@ module Locomotive::Builder
def locomotive_context(other_assigns = {})
assigns = self.locomotive_default_assigns
- # TODO: process data from the session
- # assigns.merge!(self.locomotive_flash_assigns)
+ # assigns from other middlewares
+ assigns.merge!(self.liquid_assigns)
assigns.merge!(other_assigns)
@@ @@ -59,13 +58,6 @@ module Locomotive::Builder
end
end
- # if defined?(self.page) && self.page.templatized? # add instance from content type
- # content_entry = self.page.content_entry.to_liquid
- # ['content_entry', 'entry', @page.target_entry_name].each do |key|
- # assigns[key] = content_entry
- # end
- # end
-
# Tip: switch from false to true to enable the re-thrown exception flag
::Liquid::Context.new({}, assigns, self.locomotive_default_registers, true)
end
locales/en.yml +164 -0
@@ @@ -0,0 +1,164 @@
+ en:
+ errors:
+ messages:
+ blank: "can't not blank"
+
+ pagination:
+ previous: "&laquo; Previous"
+ next: "Next &raquo;"
+
+ date:
+ abbr_day_names:
+ - Sun
+ - Mon
+ - Tue
+ - Wed
+ - Thu
+ - Fri
+ - Sat
+ abbr_month_names:
+ -
+ - Jan
+ - Feb
+ - Mar
+ - Apr
+ - May
+ - Jun
+ - Jul
+ - Aug
+ - Sep
+ - Oct
+ - Nov
+ - Dec
+ day_names:
+ - Sunday
+ - Monday
+ - Tuesday
+ - Wednesday
+ - Thursday
+ - Friday
+ - Saturday
+ formats:
+ default: ! '%Y-%m-%d'
+ long: ! '%B %d, %Y'
+ short: ! '%b %d'
+ month_names:
+ -
+ - January
+ - February
+ - March
+ - April
+ - May
+ - June
+ - July
+ - August
+ - September
+ - October
+ - November
+ - December
+ order:
+ - :year
+ - :month
+ - :day
+ datetime:
+ distance_in_words:
+ about_x_hours:
+ one: about 1 hour
+ other: about %{count} hours
+ about_x_months:
+ one: about 1 month
+ other: about %{count} months
+ about_x_years:
+ one: about 1 year
+ other: about %{count} years
+ almost_x_years:
+ one: almost 1 year
+ other: almost %{count} years
+ half_a_minute: half a minute
+ less_than_x_minutes:
+ one: less than a minute
+ other: less than %{count} minutes
+ less_than_x_seconds:
+ one: less than 1 second
+ other: less than %{count} seconds
+ over_x_years:
+ one: over 1 year
+ other: over %{count} years
+ x_days:
+ one: 1 day
+ other: ! '%{count} days'
+ x_minutes:
+ one: 1 minute
+ other: ! '%{count} minutes'
+ x_months:
+ one: 1 month
+ other: ! '%{count} months'
+ x_seconds:
+ one: 1 second
+ other: ! '%{count} seconds'
+ prompts:
+ day: Day
+ hour: Hour
+ minute: Minute
+ month: Month
+ second: Seconds
+ year: Year
+ number:
+ currency:
+ format:
+ delimiter: ! ','
+ format: ! '%u%n'
+ precision: 2
+ separator: .
+ significant: false
+ strip_insignificant_zeros: false
+ unit: $
+ format:
+ delimiter: ! ','
+ precision: 3
+ separator: .
+ significant: false
+ strip_insignificant_zeros: false
+ human:
+ decimal_units:
+ format: ! '%n %u'
+ units:
+ billion: Billion
+ million: Million
+ quadrillion: Quadrillion
+ thousand: Thousand
+ trillion: Trillion
+ unit: ''
+ format:
+ delimiter: ''
+ precision: 3
+ significant: true
+ strip_insignificant_zeros: true
+ storage_units:
+ format: ! '%n %u'
+ units:
+ byte:
+ one: Byte
+ other: Bytes
+ gb: GB
+ kb: KB
+ mb: MB
+ tb: TB
+ percentage:
+ format:
+ delimiter: ''
+ precision:
+ format:
+ delimiter: ''
+ support:
+ array:
+ last_word_connector: ! ', and '
+ two_words_connector: ! ' and '
+ words_connector: ! ', '
+ time:
+ am: am
+ formats:
+ default: ! '%a, %d %b %Y %H:%M:%S %z'
+ long: ! '%B %d, %Y %H:%M'
+ short: ! '%d %b %H:%M'
+ pm: pm
\ No newline at end of file
locales/fr.yml +133 -0
@@ @@ -0,0 +1,133 @@
+ fr:
+ errors:
+ messages:
+ blank: "doit être rempli(e)"
+
+ pagination:
+ previous: "&laquo; Précédent"
+ next: "Suivant &raquo;"
+ date:
+ formats:
+ default: "%d/%m/%Y"
+ short: "%e %b"
+ long: "%e %B %Y"
+ long_ordinal: "%e %B %Y"
+ only_day: "%e"
+
+ day_names: [dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi]
+ abbr_day_names: [dim, lun, mar, mer, jeu, ven, sam]
+ # month_names: [~, janvier, février, mars, avril, mai, juin, juillet, août, septembre, octobre, novembre, décembre]
+ # abbr_month_names: [~, jan., fév., mar., avr., mai, juin, juil., août, sept., oct., nov., déc.]
+ month_names:
+ - ~
+ - janvier
+ - février
+ - mars
+ - avril
+ - mai
+ - juin
+ - juillet
+ - août
+ - septembre
+ - octobre
+ - novembre
+ - décembre
+ abbr_month_names:
+ - ~
+ - jan.
+ - fév.
+ - mar.
+ - avr.
+ - mai
+ - juin
+ - juil.
+ - août
+ - sept.
+ - oct.
+ - nov.
+ - déc.
+ order: [day, month, year]
+
+ time:
+ formats:
+ default: "%d %B %Y %H:%M"
+ time: "%H:%M"
+ short: "%d %b %H:%M"
+ long: "%A %d %B %Y %H:%M:%S %Z"
+ long_ordinal: "%A %d %B %Y %H:%M:%S %Z"
+ only_second: "%S"
+ am: 'am'
+ pm: 'pm'
+
+ datetime:
+ distance_in_words:
+ half_a_minute: "une demi-minute"
+ less_than_x_seconds:
+ zero: "moins d'une seconde"
+ one: "moins de 1 seconde"
+ other: "moins de %{count} secondes"
+ x_seconds:
+ one: "1 seconde"
+ other: "%{count} secondes"
+ less_than_x_minutes:
+ zero: "moins d'une minute"
+ one: "moins de 1 minute"
+ other: "moins de %{count} minutes"
+ x_minutes:
+ one: "1 minute"
+ other: "%{count} minutes"
+ about_x_hours:
+ one: "environ une heure"
+ other: "environ %{count} heures"
+ x_days:
+ one: "1 jour"
+ other: "%{count} jours"
+ about_x_months:
+ one: "environ un mois"
+ other: "environ %{count} mois"
+ x_months:
+ one: "1 mois"
+ other: "%{count} mois"
+ about_x_years:
+ one: "environ un an"
+ other: "environ %{count} ans"
+ over_x_years:
+ one: "plus d'un an"
+ other: "plus de %{count} ans"
+ prompts:
+ year: "Année"
+ month: "Mois"
+ day: "Jour"
+ hour: "Heure"
+ minute: "Minute"
+ second: "Seconde"
+
+ number:
+ format:
+ precision: 3
+ separator: ','
+ delimiter: ' '
+ currency:
+ format:
+ unit: '€'
+ precision: 2
+ format: '%n %u'
+ human:
+ format:
+ precision: 2
+ storage_units:
+ format: '%n %u'
+ units:
+ byte: 'Octet'
+ kb: 'ko'
+ mb: 'Mo'
+ gb: 'Go'
+ tb: 'To'
+
+ support:
+ array:
+ sentence_connector: 'et'
+ skip_last_comma: true
+ words_connector: ", "
+ two_words_connector: " et "
+ last_word_connector: " et "
\ No newline at end of file