Skip to content

Commit

Permalink
Merge pull request #76 from alphagov/add-manuals
Browse files Browse the repository at this point in the history
Add manuals
  • Loading branch information
evilstreak committed May 8, 2014
2 parents 9a73010 + bf0b95c commit 7a1cc81
Show file tree
Hide file tree
Showing 25 changed files with 580 additions and 6 deletions.
65 changes: 65 additions & 0 deletions app/controllers/manuals_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
class ManualsController < ApplicationController
def index
render_with(manuals: all_manuals)
end

def show
render_with(manual: current_manual)
end

def new
render_with(manual: manual_form)
end

def create
save_manual
end

def edit
render_with(manual: manual_form(current_manual))
end

def update
save_manual(current_manual)
end

private
def all_manuals
manual_repository.all
end

def current_manual
manual_repository.fetch(params[:id])
end

def manual_form(manual = nil)
ManualForm.new(manual)
end

def form_params
params.fetch(:manual, {})
end

def store(manual)
manual_repository.store(manual)
end

def manual_repository
ManualRepository.new
end

def save_manual(manual = nil)
manual = manual_form(manual)
manual.update(form_params)

if manual.valid? && store(manual)
redirect_to manual_path(manual)
else
if manual.persisted?
render(:edit, locals: {manual: manual})
else
render(:new, locals: {manual: manual})
end
end
end
end
44 changes: 44 additions & 0 deletions app/forms/manual_form.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
class ManualForm
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Validations

attr_accessor :title, :summary

validates :title, presence: true

def initialize(manual = nil)
@manual = manual

if manual
@id = manual.id
@title = manual.title
@summary = manual.summary
end
end

def self.model_name
ActiveModel::Name.new(self, nil, "Manual")
end

def id
@id ||= SecureRandom.uuid
end

def update(attributes)
attributes.each do |name, value|
send("#{name}=", value)
end
end

def persisted?
manual.present?
end

def to_param
id
end

private
attr_reader :manual
end
4 changes: 4 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ def document_state(document)

state
end

def nav_link_to(text, href)
link_to(text, href)
end
end
1 change: 1 addition & 0 deletions app/lib/specialist_publisher_wiring.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'dependency_container'
require 'securerandom'
require "specialist_document_repository"
require 'builders/specialist_document_builder'
require 'gds_api/panopticon'
require 'panopticon_registerer'
Expand Down
14 changes: 14 additions & 0 deletions app/models/manual.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class Manual
attr_reader :id, :title, :summary, :updated_at

def initialize(attributes)
@id = attributes.fetch(:id)
@title = attributes.fetch(:title)
@summary = attributes.fetch(:summary)
@updated_at = attributes.fetch(:updated_at)
end

def to_param
id
end
end
52 changes: 52 additions & 0 deletions app/models/manual_record.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
class ManualRecord
include ::Mongoid::Document
include ::Mongoid::Timestamps

field :manual_id, type: String

embeds_many :editions,
class_name: 'ManualRecord::Edition',
cascade_callbacks: true

def self.find_by(attributes)
first(conditions: attributes)
end

def new_or_existing_draft_edition
editions
.where(state: 'draft')
.order(:version_number)
.last || build_draft_edition
end

def latest_edition
editions.last
end

private
def build_draft_edition
editions.build(state: 'draft', version_number: next_version_number)
end

def next_version_number
current_version_number + 1
end

def current_version_number
latest_edition && latest_edition.version_number || 0
end

class Edition
include ::Mongoid::Document
include ::Mongoid::Timestamps

field :title, type: String
field :summary, type: String
field :state, type: String
field :version_number, type: Integer

# We don't make use of the relationship but Mongiod can't save the
# timestamps properly without it.
embedded_in 'ManualRecord'
end
end
46 changes: 46 additions & 0 deletions app/repositories/manual_repository.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
class ManualRepository
def initialize(dependencies = {})
@collection = dependencies.fetch(:collection) { ManualRecord }
@factory = dependencies.fetch(:factory) { Manual.method(:new) }
end

def store(manual)
manual_record = collection.find_or_initialize_by(manual_id: manual.id)
edition = manual_record.new_or_existing_draft_edition
edition.attributes = attributes_for(manual)

manual_record.save!
end

def fetch(manual_id)
manual_record = collection.find_by(manual_id: manual_id)
build_manual_for(manual_record)
end

def all
collection.all.lazy.map { |manual_record|
build_manual_for(manual_record)
}
end

private
attr_reader :collection, :factory

def attributes_for(manual)
{
title: manual.title,
summary: manual.summary,
}
end

def build_manual_for(record)
edition = record.latest_edition

factory.call(
id: record.manual_id,
title: edition.title,
summary: edition.summary,
updated_at: edition.updated_at,
)
end
end
4 changes: 2 additions & 2 deletions app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="/">All documents</a></li>
<%# <li><a href="#about">About</a></li> %>
<li><%= nav_link_to 'Documents', '/specialist-documents' %></li>
<li><%= nav_link_to 'Manuals', '/manuals' %></li>
</ul>
</div><!--/.nav-collapse -->
</div>
Expand Down
14 changes: 14 additions & 0 deletions app/views/manuals/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<div class="row">
<div class="col-md-8">
<%= form_for manual do |f| %>
<%= f.text_field :title %>
<%= f.text_area :summary, class: 'short-textarea' %>

<button name="draft" class="btn btn-primary">Save as draft</button>
<% end %>
</div>

<div class="col-md-4">
<%= render partial: 'shared/govspeak-help' %>
</div>
</div>
3 changes: 3 additions & 0 deletions app/views/manuals/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<h1 class="page-header">Edit a manual</h1>

<%= render 'form', manual: manual %>
18 changes: 18 additions & 0 deletions app/views/manuals/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<h1 class="page-header">Your manuals</h1>

<div class="row">
<div class="sidebar col-md-3">
<%= link_to "Create new manual", new_manual_path, class: 'btn btn-default' %>
</div>

<div class="col-md-9">
<ul class="document-list">
<% manuals.each do |manual| %>
<li class="document">
<%= link_to manual.title, manual_path(manual), class: 'document-title' %>
- Last updated: <%= manual.updated_at.strftime('%e/%m/%y %R') %>
</li>
<% end %>
</ul>
</div>
</div>
3 changes: 3 additions & 0 deletions app/views/manuals/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<h1 class="page-header">Create new manual</h1>

<%= render 'form', manual: manual %>
9 changes: 9 additions & 0 deletions app/views/manuals/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<h1 class="page-header"><%= manual.title %></h1>

<%= link_to 'Edit', edit_manual_path(manual), class: 'btn btn-default' %>

<div class="row">
<div class="sidebar col-md-8">
<%= manual.summary %>
</div>
</div>
File renamed without changes.
2 changes: 1 addition & 1 deletion app/views/specialist_documents/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
</div>

<div class="col-md-4">
<%= render partial: 'govspeak-help' %>
<%= render partial: 'shared/govspeak-help' %>

<h2>Attachments</h2>

Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@
post :withdraw, on: :member
end

resources :manuals, except: :destroy

root to: redirect('/specialist-documents')
end
20 changes: 20 additions & 0 deletions features/creating-and-editing-a-manual.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Feature: Creating and editing a manual
As a CMA editor
I want to create and edit a manual and see it in the publisher
So that I can start moving my content to gov.uk

Background:
Given I am logged in as a CMA editor

Scenario: Create a new manual
When I create a manual
Then the manual should exist

Scenario: Edit a draft manual
Given a draft manual exists
When I edit a manual
Then the manual should have been updated

Scenario: Try to create an invalid manual
When I create a manual with an empty title
Then I see errors for the title field
43 changes: 43 additions & 0 deletions features/step_definitions/manual_steps.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
When(/^I create a manual$/) do
@fields = {
title: 'Example Manual Title',
summary: 'Nullam quis risus eget urna mollis ornare vel eu leo.',
}

create_manual(@fields)
end

Then(/^the manual should exist$/) do
check_manual_exists_with(@fields)
end

Given(/^a draft manual exists$/) do
@fields = {
title: 'Example Manual Title',
summary: 'Nullam quis risus eget urna mollis ornare vel eu leo.',
}

create_manual(@fields)
end

When(/^I edit a manual$/) do
@new_title = 'Edited Example Manual'
edit_manual(@fields[:title], title: @new_title)
end

Then(/^the manual should have been updated$/) do
check_manual_exists_with(@fields.merge(title: @new_title))
end

When(/^I create a manual with an empty title$/) do
@fields = {
title: '',
summary: 'Nullam quis risus eget urna mollis ornare vel eu leo.',
}

create_manual(@fields)
end

Then(/^I see errors for the title field$/) do
check_for_errors_for_fields('title')
end
Loading

0 comments on commit 7a1cc81

Please sign in to comment.