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