Permalink
Browse files

Merge pull request #5 from alphagov/single-registration-point

Single registration point

A simplified way to register new content on GOV.UK. For now this registers things in both panopticon and search in one go, but in future it's intended to be a single place to register new content and have it reflected everywhere in the system that it needs to be.
  • Loading branch information...
2 parents b70e397 + a350c0a commit e647e1ffa0e9cc8ab7eaf2bb691a9d3ecebbad90 @jystewart jystewart committed Jul 2, 2012
View
16 Gemfile
@@ -20,25 +20,27 @@ gem 'null_logger'
gem 'exception_notification'
gem 'gds-api-adapters'
-gem 'aws-ses', :require => 'aws/ses'
+
+gem 'aws-ses', require: 'aws/ses'
gem 'rails', '~> 3.1.1'
gem 'colorize', '~> 0.5.8'
+gem 'rummageable', "~> 0.3.0"
gem "mongoid", "~> 2.4.2"
gem "mongo", "1.5.2"
gem "bson_ext", "1.5.2"
gem "bson", "1.5.2"
if ENV['CONTENT_MODELS_DEV']
- gem "govuk_content_models", :path => '../govuk_content_models'
+ gem "govuk_content_models", path: '../govuk_content_models'
else
gem "govuk_content_models", "0.1.6"
end
if ENV['BUNDLE_DEV']
- gem 'gds-sso', :path => '../gds-sso'
+ gem 'gds-sso', path: '../gds-sso'
else
gem 'gds-sso', '0.7.0'
end
@@ -50,22 +52,22 @@ end
group :test do
# Pretty printed test output
- gem 'turn', :require => false
- gem 'sqlite3-ruby', :require => false
+ gem 'turn', require: false
+ gem 'sqlite3-ruby', require: false
gem 'simplecov', '~> 0.6.4'
gem 'simplecov-rcov'
gem 'ci_reporter'
gem 'test-unit'
- gem 'cucumber-rails', :require => false
+ gem 'cucumber-rails', require: false
gem 'database_cleaner'
gem 'minitest'
gem "shoulda", "~> 2.11.3"
gem 'factory_girl', "3.3.0"
gem 'factory_girl_rails'
gem 'capybara-mechanize', '~> 0.3.0.rc3'
gem 'launchy'
- gem 'fakeweb'
gem 'mocha'
+ gem 'webmock', require: false
end
group :import do
View
@@ -76,6 +76,7 @@ GEM
ci_reporter (1.6.9)
builder (>= 2.1.2)
colorize (0.5.8)
+ crack (0.3.1)
cucumber (1.1.4)
builder (>= 2.1.2)
diff-lcs (>= 1.1.2)
@@ -207,7 +208,13 @@ GEM
rake (0.9.2)
rdoc (3.12)
json (~> 1.4)
+ rest-client (1.6.7)
+ mime-types (>= 1.16)
rubyzip (0.9.5)
+ rummageable (0.3.0)
+ json
+ plek
+ rest-client
selenium-webdriver (2.17.0)
childprocess (>= 0.2.5)
ffi (~> 1.0.9)
@@ -246,6 +253,9 @@ GEM
multi_json (>= 1.0.2)
warden (1.2.1)
rack (>= 1.0)
+ webmock (1.8.7)
+ addressable (>= 2.2.7)
+ crack (>= 0.1.7)
webrobots (0.0.12)
nokogiri (>= 1.4.4)
whenever (0.7.2)
@@ -271,7 +281,6 @@ DEPENDENCIES
exception_notification
factory_girl (= 3.3.0)
factory_girl_rails
- fakeweb
formtastic!
formtastic-bootstrap!
gds-api-adapters
@@ -290,6 +299,7 @@ DEPENDENCIES
rack (= 1.3.5)
rails (~> 3.1.1)
rake (= 0.9.2)
+ rummageable (~> 0.3.0)
shoulda (~> 2.11.3)
simplecov (~> 0.6.4)
simplecov-rcov
@@ -299,4 +309,5 @@ DEPENDENCIES
therubyracer (~> 0.9.4)
turn
uglifier
+ webmock
whenever
@@ -1,5 +1,5 @@
class ArtefactsController < ApplicationController
- before_filter :find_artefact, :only => [:show, :edit, :update]
+ before_filter :find_artefact, :only => [:show, :edit]
before_filter :build_artefact, :only => [:new, :create]
respond_to :html, :json
@@ -33,20 +33,45 @@ def create
respond_with @artefact, location: @artefact.admin_url(params.slice(:return_to))
end
+ # NB: We are departing from usual rails conventions here. PUTing a resource
+ # will create it if it doesn't exist, rather than the usual 404.
def update
+ begin
+ @artefact = Artefact.from_param(params[:id])
+ status_to_use = 200
+ rescue Mongoid::Errors::DocumentNotFound
+ @artefact = Artefact.new(slug: params[:id])
+ status_to_use = 201
+ end
+
parameters_to_use = extract_parameters(params)
+ if attempting_to_change_owning_app?(parameters_to_use)
+ render(
+ text: "This artefact already belongs to the '#{@artefact.owning_app}' app",
+ status: 409
+ )
+ return
+ end
+
saved = @artefact.update_attributes(parameters_to_use)
flash[:notice] = saved ? 'Panopticon item updated' : 'Failed to save item'
if saved && params[:commit] == 'Save and continue editing'
redirect_to edit_artefact_path(@artefact)
else
- respond_with @artefact
+ respond_with @artefact, status: status_to_use
end
end
private
+
+ def attempting_to_change_owning_app?(parameters_to_use)
+ @artefact.persisted? &&
+ parameters_to_use.include?('owning_app') &&
+ parameters_to_use['owning_app'] != @artefact.owning_app
+ end
+
def redirect_to_show_if_need_met
if params[:artefact] && params[:artefact][:need_id]
artefact = Artefact.where(need_id: params[:artefact][:need_id]).first
@@ -64,6 +89,8 @@ def build_artefact
def extract_parameters(params)
fields_to_update = Artefact.fields.keys + ['sections']
+
+ # TODO: Remove this variance
parameters_to_use = params[:artefact] || params.slice(*fields_to_update)
# Strip out the empty submit option for sections
@@ -0,0 +1,7 @@
+require "artefact"
+
+class Artefact
+ # Add a non-field attribute so we can pass indexable content over to Rummager
+ # without persisting it
+ attr_accessor :indexable_content
+end
@@ -0,0 +1,79 @@
+class RummageableArtefact
+
+ def initialize(artefact)
+ @artefact = artefact
+ end
+
+ def logger
+ Rails.logger
+ end
+
+ def submit
+ # API requests, if they know about the single registration API, will be
+ # providing the indexable_content field to update Rummager. UI requests
+ # and requests from apps that don't know about single registration, will
+ # not include this field
+ if should_amend
+ logger.info "Posting amendments to Rummager: #{artefact_link}"
+ Rummageable.amend artefact_link, artefact_hash
+ else
+ logger.info "Posting document to Rummager: #{artefact_link}"
+ Rummageable.index [artefact_hash]
+ end
+ end
+
+ def should_amend
+ @artefact.indexable_content.nil?
+ end
+
+ def artefact_hash
+ # This won't cope with nested values, but we don't have any of those yet
+ # When we want to include additional links, this will become an issue
+ rummageable_keys = Rummageable::VALID_KEYS.map { |full_key| full_key[0] }.uniq
+
+ # When amending an artefact, requests with the "link" parameter will be
+ # refused, because we can't amend the link within Rummager
+ rummageable_keys.delete "link" if should_amend
+
+ rummageable_keys.inject({}) do |hash, rummageable_key|
+ strip_nils = (rummageable_key == "indexable_content")
+
+ # method_name = KEY_MAPPING[rummageable_key].to_sym
+ # return hash unless @artefact.respond_to? method_name
+ #
+ # Use the relevant extraction method from this class if it exists
+ if respond_to? "artefact_#{rummageable_key}"
+ value = __send__ "artefact_#{rummageable_key}"
+ elsif @artefact.respond_to? rummageable_key
+ value = @artefact.__send__ rummageable_key
+ else
+ return hash
+ end
+
+ unless (strip_nils && value.nil?)
+ hash[rummageable_key] = value
+ end
+ hash
+ end
+ end
+
+ def artefact_section
+ @artefact.section.split(":")[0]
+ end
+
+ def artefact_subsection
+ @artefact.section.split(":")[1]
+ end
+
+ def artefact_format
+ @artefact.kind
+ end
+
+ def artefact_title
+ @artefact.name
+ end
+
+ def artefact_link
+ "/#{@artefact.slug}"
+ end
+end
@@ -0,0 +1,8 @@
+class UpdateSearchObserver < Mongoid::Observer
+
+ observe :artefact
+
+ def after_save(artefact)
+ RummageableArtefact.new(artefact).submit if artefact.live?
+ end
+end
@@ -16,7 +16,7 @@
<%= semantic_form_for(artefact, :html => { :class => '', :id => 'edit_artefact'}) do |f| %>
<%= f.inputs do %>
<%= f.input :name, :input_html => { :class => "span6" } %>
- <%= f.input :slug, :input_html => { :class => "span6", :disabled => f.object.any_editions_ever_published? }, :hint => "A valid slug might look like this: i-am-a-good-slug-with-no-spaces" %>
+ <%= f.input :slug, :input_html => { :class => "span6", :disabled => f.object.live? }, :hint => "A valid slug might look like this: i-am-a-good-slug-with-no-spaces" %>
<%= f.input :need_id, :input_html => { :class => "span6", :disabled => f.object.persisted? } %>
<% if ! artefact.new_record? && ! artefact.business_proposition %>
<%= link_to "View in Need-O-Tron", need_url(f.object), :rel => 'external', :class => "btn btn-primary" %>
@@ -0,0 +1,4 @@
+Dir[Rails.root.join("app", "models", "enhancements", "*.rb")].each do |path|
+ name = File.basename(path, ".rb")
+ require "enhancements/#{name}"
+end
@@ -0,0 +1,18 @@
+# In development environments we don't want to depend on Rummager unless
+# explicitly told to do so
+unless Rails.env.development?
+ update_search = true
+else
+ update_search = ENV['UPDATE_SEARCH'].present?
+end
+
+if update_search
+ Rails.logger.info "Registering search observer for artefacts"
+ # Use to_prepare so this gets reloaded with the app when in development
+ # In production, it will only be called once
+ ActionDispatch::Callbacks.to_prepare do
+ Panopticon::Application.config.mongoid.observers << :update_search_observer
+ end
+else
+ Rails.logger.info "In development/test mode: not registering search observer"
+end
View
@@ -1,6 +1,5 @@
Panopticon::Application.routes.draw do
resources :artefacts
-
resources :tags, :defaults => {:format => 'json'}
resources :curated_lists, only: :index
View
@@ -0,0 +1,22 @@
+Feature: Managing contacts
+ In order that citizens know who to talk to if GovUK doesn't answer their question
+ I want to connect contacts and artefacts
+ This feature is not currently in use
+
+ Background:
+ Given I am an admin
+
+# Scenario: Assign a contact
+# Given an artefact exists
+# And a contact exists
+# When I add the contact to the artefact
+# Then I should be redirected to Publisher
+# And the API should say that the artefact has the contact
+
+# Scenario: Unassign a contact
+# Given an artefact exists
+# And a contact exists
+# And the artefact has the contact
+# When I remove the contact from the artefact
+# Then I should be redirected to Publisher
+# And the API should say that the artefact does not have the contact
View
@@ -0,0 +1,23 @@
+Feature: Creating artefacts
+ In order to build GovUK
+ I want to create artefacts in panopticon
+
+ Background:
+ Given I am an admin
+
+ Scenario: Creating artefacts directly in panopticon
+ When I visit the homepage
+ Then I should see a link to create an item
+
+ When I follow the link link to create an item
+ Then I should see the artefact form
+
+ When I fill in the form for a business need
+ And I save, indicating that I want to go to the item
+
+ Then I should be redirected to Publisher
+
+ Scenario: Trying to create an artefact for a need that is already met
+ Given an artefact exists
+ When I try to create a new artefact with the same need
+ Then I should be redirected to Publisher
@@ -1,19 +0,0 @@
-Feature: Creating artefacts directly
- In order to support multiple propositions
- I want to create artefacts directly in panopticon
- So I am not prematurely committed to need-o-tron
-
- Background:
- Given I am an admin
-
- Scenario:
- When I visit the homepage
- Then I should see a link to create an item
-
- When I follow the link link to create an item
- Then I should see the artefact form
-
- When I fill in the form for a business need
- And I save, indicating that I want to go to the item
-
- Then I should be redirected to Publisher
Oops, something went wrong.

0 comments on commit e647e1f

Please sign in to comment.