lib/locomotive/steam/middlewares/entry_submission.rb in locomotivecms_steam-0.1.2.pre.beta vs lib/locomotive/steam/middlewares/entry_submission.rb in locomotivecms_steam-1.0.0.pre.alpha
- old
+ new
@@ -1,120 +1,158 @@
module Locomotive::Steam
module Middlewares
- # Mimic the submission of a content entry
+ # Submit a content entry and persist it
#
- class EntrySubmission < Base
+ class EntrySubmission < ThreadSafe
- def _call(env)
- super
+ include Helpers
- if self.request.post? && env['PATH_INFO'] =~ /^\/entry_submissions\/(.*)/
- self.process_form($1)
+ HTTP_REGEXP = /^https?:\/\//o
+ ENTRY_SUBMISSION_REGEXP = /^\/entry_submissions\/(\w+)/o
+ SUBMITTED_TYPE_PARAM = 'submitted_type_slug'
+ SUBMITTED_PARAM = 'submitted_entry_slug'
- # puts "html? #{html?} / json? #{json?} / #{self.callback_url} / #{params.inspect}"
-
- if @entry.valid?
- if self.html?
- self.record_submitted_entry
- self.redirect_to self.callback_url
- elsif self.json?
- self.json_response
- end
+ def _call
+ # we didn't go through the locale middleware yet,
+ # so set the locale manually. Needed to build a localized
+ # version of the entry + error messages (if present).
+ with_locale do
+ if slug = get_content_type_slug
+ entry = create_entry(slug)
+ navigation_behavior(entry)
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
+ fetch_entry
end
+ end
+ end
+
+ # Render or redirect depending on:
+ # - the status of the content entry (valid or not)
+ # - the presence of a callback or not
+ # - the type of response asked by the browser (html or json)
+ #
+ def navigation_behavior(entry)
+ if entry.errors.empty?
+ navigation_success(entry)
else
- self.fetch_submitted_entry
+ navigation_error(entry)
+ end
+ end
- app.call(env)
+ def navigation_success(entry)
+ if html?
+ redirect_to success_location(entry_to_query_string(entry))
+ elsif json?
+ json_response(entry)
end
end
- protected
+ def navigation_error(entry)
+ if html?
+ navigation_html_error(entry)
+ elsif json?
+ json_response(entry, 422)
+ end
+ end
- def record_submitted_entry
- self.request.session[:now] ||= {}
- self.request.session[:now][:submitted_entry] = [@content_type.slug, @entry._slug]
+ def navigation_html_error(entry)
+ if error_location =~ HTTP_REGEXP
+ redirect_to error_location
+ else
+ env['PATH_INFO'] = error_location
+ store_in_liquid(entry)
+ self.next
+ end
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]
+ private
- entry = (content_type.entries || []).detect { |e| e._slug == data.last }
+ def store_in_liquid(entry)
+ liquid_assigns[entry.content_type_slug.singularize] = entry
+ end
- # do not keep track of the entry
- content_type.entries.delete(entry) if entry
+ def entry_to_query_string(entry)
+ type, slug = entry.content_type_slug, entry._slug
+ "#{SUBMITTED_TYPE_PARAM}=#{type}&#{SUBMITTED_PARAM}=#{slug}"
+ end
- # add it to the additional liquid assigns for the next liquid rendering
- if entry
- self.liquid_assigns[content_type.slug.singularize] = entry
- end
+ def with_locale(&block)
+ locale = default_locale || params[:locale]
+
+ if request.path_info =~ /^\/(#{site.locales.join('|')})+(\/|$)/
+ locale = $1
end
- end
- # Mimic the creation of a content entry with a minimal validation.
- #
- # @param [ String ] permalink The permalink (or slug) of the content type
- #
- #
- def process_form(permalink)
- permalink = permalink.split('.').first
+ services.locale = locale
- @content_type = self.mounting_point.content_types[permalink]
+ I18n.with_locale(locale, &block)
+ end
- raise "Unknown content type '#{@content_type.inspect}'" if @content_type.nil?
+ def success_location(query); location(:success, query); end
+ def error_location; location(:error); end
- attributes = self.params[:entry] || self.params[:content] || {}
+ def location(state, query = '')
+ location = params[:"#{state}_callback"] || (entry_submissions_path? ? '/' : request.path_info)
- @entry = @content_type.build_entry(attributes)
+ if query.blank?
+ location
+ else
+ location += (location.include?('?') ? '&' : '?') + query
+ end
+ end
- # if not valid, we do not need to keep track of the entry
- @content_type.entries.delete(@entry) if !@entry.valid?
+ def entry_submissions_path?
+ !(request.path_info =~ ENTRY_SUBMISSION_REGEXP).nil?
end
- def callback_url
- (@entry.valid? ? params[:success_callback] : params[:error_callback]) || '/'
+ # Get the slug (or permalink) of the content type either from the PATH_INFO variable (old way)
+ # or from the presence of the content_type_slug param (model_form tag).
+ #
+ def get_content_type_slug
+ if request.post? && (request.path_info =~ ENTRY_SUBMISSION_REGEXP || params[:content_type_slug])
+ $1 || params[:content_type_slug]
+ end
end
- # Build the JSON response
+ # Create a content entry with a minimal validation.
#
- # @param [ Integer ] status The HTTP return code
+ # @param [ String ] slug The slug (or permalink) of the content type
#
- # @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
+ def create_entry(slug)
+ if entry = services.entry_submission.submit(slug, entry_attributes)
+ entry
+ else
+ raise %{Unknown content type "#{slug}"}
end
+ 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
+ # Get the content entry from the params.
+ #
+ def fetch_entry
+ if (type_slug = params[SUBMITTED_TYPE_PARAM]) && (slug = params[SUBMITTED_PARAM])
+ if entry = services.entry_submission.find(type_slug, slug)
+ store_in_liquid(entry)
end
end
+ end
- [status, { 'Content-Type' => 'application/json' }, [
- { @content_type.slug.singularize => hash }.to_json
- ]]
+ # 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(entry, status = 200)
+ json = services.entry_submission.to_json(entry)
+ render_response(json, status, 'application/json')
end
+ def entry_attributes
+ HashConverter.to_sym(params[:entry] || params[:content] || {})
+ end
+
end
end
-end
\ No newline at end of file
+end