diff options
48 files changed, 1869 insertions, 148 deletions
diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js index 0b5d56525..4925a65a4 100644 --- a/app/assets/javascripts/admin.js +++ b/app/assets/javascripts/admin.js @@ -1,7 +1,10 @@ // ... //= require jquery //= require jquery.ui.tabs +//= require jquery.ui.sortable +//= require jquery.ui.effect-highlight //= require admin/bootstrap-collapse //= require admin/bootstrap-tab //= require admin/admin +//= require admin/category-order //= require jquery_ujs diff --git a/app/assets/javascripts/admin/category-order.js b/app/assets/javascripts/admin/category-order.js new file mode 100644 index 000000000..3be82e46f --- /dev/null +++ b/app/assets/javascripts/admin/category-order.js @@ -0,0 +1,42 @@ +$(function() { + $('.save-order').each(function(index){ + + // identify the elements that will work together + var save_button = $(this); + var save_notice = save_button.next(); + var save_panel = save_button.parent(); + var list_element = $(save_button.data('list-id')); + var endpoint = save_button.data('endpoint'); + + // on the first list change, show that there are unsaved changes + list_element.sortable({ + update: function (event, ui) { + if (save_button.is('.disabled')){ + save_button.removeClass("disabled"); + save_notice.html(save_notice.data('unsaved-text')); + save_panel.effect('highlight', {}, 2000); + } + } + }); + // on save, POST to endpoint + save_button.click(function(){ + if (!save_button.is('.disabled')){ + var data = list_element.sortable('serialize', {'attribute': 'data-id'}); + var update_call = $.ajax({ data: data, type: 'POST', url: endpoint }); + + // on success, disable the save button again, and show success notice + update_call.done(function(msg) { + save_button.addClass('disabled'); + save_panel.effect('highlight', {}, 2000); + save_notice.html(save_notice.data('success-text')); + }) + // on failure, show error message + update_call.fail(function(jqXHR, msg) { + save_panel.effect('highlight', {'color': '#cc0000'}, 2000); + save_notice.html(save_notice.data('error-text') + jqXHR.responseText); + }); + } + return false; + }) + }); +}); diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index b0de2eb7b..863a6c808 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -27,6 +27,9 @@ body.admin { } .admin { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 20px; @import "compass/css3"; @import "bootstrap"; @@ -47,6 +50,9 @@ body.admin { .accordion-group { border: none; + div { + clear: both; + } } .accordion-heading { .btn { @@ -104,5 +110,14 @@ body.admin { width: 750px; } + .save-notice { + display: inline-block; + padding-left: 1em; + } + + .category-list-item { + padding: 3px 0; + } + } diff --git a/app/controllers/admin_public_body_categories_controller.rb b/app/controllers/admin_public_body_categories_controller.rb new file mode 100644 index 000000000..fda09fa4a --- /dev/null +++ b/app/controllers/admin_public_body_categories_controller.rb @@ -0,0 +1,84 @@ +class AdminPublicBodyCategoriesController < AdminController + def index + @locale = self.locale_from_params + @category_headings = PublicBodyHeading.all + @without_heading = PublicBodyCategory.without_headings + end + + def new + @category = PublicBodyCategory.new + render :formats => [:html] + end + + def edit + @category = PublicBodyCategory.find(params[:id]) + @tagged_public_bodies = PublicBody.find_by_tag(@category.category_tag) + end + + def update + @category = PublicBodyCategory.find(params[:id]) + @tagged_public_bodies = PublicBody.find_by_tag(@category.category_tag) + heading_ids = [] + + I18n.with_locale(I18n.default_locale) do + if params[:public_body_category][:category_tag] && PublicBody.find_by_tag(@category.category_tag).count > 0 && @category.category_tag != params[:public_body_category][:category_tag] + flash[:notice] = 'There are authorities associated with this category, so the tag can\'t be renamed' + else + if params[:headings] + heading_ids = params[:headings].values + removed_headings = @category.public_body_heading_ids - heading_ids + added_headings = heading_ids - @category.public_body_heading_ids + + unless removed_headings.empty? + # remove the link objects + deleted_links = PublicBodyCategoryLink.where( + :public_body_category_id => @category.id, + :public_body_heading_id => [removed_headings] + ) + deleted_links.delete_all + + #fix the category object + @category.public_body_heading_ids = heading_ids + end + + added_headings.each do |heading_id| + PublicBodyHeading.find(heading_id).add_category(@category) + end + end + + if @category.update_attributes(params[:public_body_category]) + flash[:notice] = 'Category was successfully updated.' + end + end + + render :action => 'edit' + end + end + + def create + I18n.with_locale(I18n.default_locale) do + @category = PublicBodyCategory.new(params[:public_body_category]) + if @category.save + if params[:headings] + params[:headings].values.each do |heading_id| + PublicBodyHeading.find(heading_id).add_category(@category) + end + end + flash[:notice] = 'Category was successfully created.' + redirect_to admin_categories_path + else + render :action => 'new' + end + end + end + + def destroy + @locale = self.locale_from_params + I18n.with_locale(@locale) do + category = PublicBodyCategory.find(params[:id]) + category.destroy + flash[:notice] = "Category was successfully destroyed." + redirect_to admin_categories_path + end + end +end diff --git a/app/controllers/admin_public_body_controller.rb b/app/controllers/admin_public_body_controller.rb index 120419a27..f7a80476c 100644 --- a/app/controllers/admin_public_body_controller.rb +++ b/app/controllers/admin_public_body_controller.rb @@ -4,8 +4,6 @@ # Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. # Email: hello@mysociety.org; WWW: http://www.mysociety.org/ -require "public_body_categories" - class AdminPublicBodyController < AdminController def index list diff --git a/app/controllers/admin_public_body_headings_controller.rb b/app/controllers/admin_public_body_headings_controller.rb new file mode 100644 index 000000000..c7c80e802 --- /dev/null +++ b/app/controllers/admin_public_body_headings_controller.rb @@ -0,0 +1,113 @@ +class AdminPublicBodyHeadingsController < AdminController + + def edit + @heading = PublicBodyHeading.find(params[:id]) + render :formats => [:html] + end + + def update + I18n.with_locale(I18n.default_locale) do + @heading = PublicBodyHeading.find(params[:id]) + if @heading.update_attributes(params[:public_body_heading]) + flash[:notice] = 'Category heading was successfully updated.' + end + render :action => 'edit' + end + end + + def reorder + transaction = reorder_headings(params[:headings]) + if transaction[:success] + render :nothing => true, :status => :ok + else + render :text => transaction[:error], :status => :unprocessable_entity + end + end + + def reorder_categories + transaction = reorder_categories_for_heading(params[:id], params[:categories]) + if transaction[:success] + render :nothing => true, :status => :ok and return + else + render :text => transaction[:error], :status => :unprocessable_entity + end + end + + def new + @heading = PublicBodyHeading.new + render :formats => [:html] + end + + def create + I18n.with_locale(I18n.default_locale) do + @heading = PublicBodyHeading.new(params[:public_body_heading]) + if @heading.save + flash[:notice] = 'Category heading was successfully created.' + redirect_to admin_categories_url + else + render :action => 'new' + end + end + end + + def destroy + @locale = self.locale_from_params() + I18n.with_locale(@locale) do + heading = PublicBodyHeading.find(params[:id]) + + if heading.public_body_categories.count > 0 + flash[:notice] = "There are categories associated with this heading, so can't destroy it" + redirect_to edit_admin_heading_url(heading) + return + end + + heading.destroy + flash[:notice] = "Category heading was successfully destroyed." + redirect_to admin_categories_url + end + end + + protected + + def reorder_headings(headings) + error = nil + ActiveRecord::Base.transaction do + headings.each_with_index do |heading_id, index| + begin + heading = PublicBodyHeading.find(heading_id) + rescue ActiveRecord::RecordNotFound => e + error = e.message + raise ActiveRecord::Rollback + end + heading.display_order = index + unless heading.save + error = heading.errors.full_messages.join(",") + raise ActiveRecord::Rollback + end + end + end + { :success => error.nil? ? true : false, :error => error } + end + + def reorder_categories_for_heading(heading_id, categories) + error = nil + ActiveRecord::Base.transaction do + categories.each_with_index do |category_id, index| + conditions = { :public_body_category_id => category_id, + :public_body_heading_id => heading_id } + link = PublicBodyCategoryLink.where(conditions).first + unless link + error = "Couldn't find PublicBodyCategoryLink for category #{category_id}, heading #{heading_id}" + raise ActiveRecord::Rollback + end + link.category_display_order = index + unless link.save + error = link.errors.full_messages.join(",") + raise ActiveRecord::Rollback + end + end + end + { :success => error.nil? ? true : false, :error => error } + end + +end diff --git a/app/controllers/public_body_controller.rb b/app/controllers/public_body_controller.rb index d2c84d820..e64644a1b 100644 --- a/app/controllers/public_body_controller.rb +++ b/app/controllers/public_body_controller.rb @@ -111,7 +111,7 @@ class PublicBodyController < ApplicationController if @tag.nil? || @tag == 'all' @tag = 'all' elsif @tag == 'other' - category_list = PublicBodyCategories.get.tags.map{ |c| %Q('#{ c }') }.join(",") + category_list = PublicBodyCategory.get.tags.map{ |c| %Q('#{ c }') }.join(",") where_condition += base_tag_condition + " AND has_tag_string_tags.name in (#{category_list})) = 0" elsif @tag.scan(/./mu).size == 1 @tag = Unicode.upcase(@tag) @@ -132,7 +132,7 @@ class PublicBodyController < ApplicationController elsif @tag.size == 1 @description = _("beginning with ‘{{first_letter}}’", :first_letter => @tag) else - category_name = PublicBodyCategories.get.by_tag[@tag] + category_name = PublicBodyCategory.get.by_tag[@tag] if category_name.nil? @description = _("matching the tag ‘{{tag_name}}’", :tag_name => @tag) else diff --git a/app/helpers/admin_public_body_category_helper.rb b/app/helpers/admin_public_body_category_helper.rb new file mode 100644 index 000000000..9c5e5cc5e --- /dev/null +++ b/app/helpers/admin_public_body_category_helper.rb @@ -0,0 +1,14 @@ +module AdminPublicBodyCategoryHelper + def heading_is_selected?(heading) + if params[:headings] + if params[:headings]["heading_#{heading.id}"] + return true + else + return false + end + elsif @category.public_body_headings.include?(heading) + return true + end + false + end +end diff --git a/app/models/public_body.rb b/app/models/public_body.rb index 87b5c2227..f61a3f449 100644 --- a/app/models/public_body.rb +++ b/app/models/public_body.rb @@ -132,14 +132,14 @@ class PublicBody < ActiveRecord::Base end def translated_versions=(translation_attrs) - def skip?(attrs) - valueless = attrs.inject({}) { |h, (k, v)| h[k] = v if v != '' and k != 'locale'; h } # because we want to fall back to alternative translations where there are empty values - return valueless.length == 0 + def empty_translation?(attrs) + attrs_with_values = attrs.select{ |key, value| value != '' and key != 'locale' } + attrs_with_values.empty? end if translation_attrs.respond_to? :each_value # Hash => updating translation_attrs.each_value do |attrs| - next if skip?(attrs) + next if empty_translation?(attrs) t = translation_for(attrs[:locale]) || PublicBody::Translation.new t.attributes = attrs calculate_cached_fields(t) @@ -147,7 +147,7 @@ class PublicBody < ActiveRecord::Base end else # Array => creating translation_attrs.each do |attrs| - next if skip?(attrs) + next if empty_translation?(attrs) new_translation = PublicBody::Translation.new(attrs) calculate_cached_fields(new_translation) translations << new_translation @@ -335,8 +335,8 @@ class PublicBody < ActiveRecord::Base types = [] first = true for tag in self.tags - if PublicBodyCategories::get().by_tag().include?(tag.name) - desc = PublicBodyCategories::get().singular_by_tag()[tag.name] + if PublicBodyCategory.get().by_tag().include?(tag.name) + desc = PublicBodyCategory.get().singular_by_tag()[tag.name] if first # terrible that Ruby/Rails doesn't have an equivalent of ucfirst # (capitalize shockingly converts later characters to lowercase) diff --git a/app/models/public_body_category.rb b/app/models/public_body_category.rb new file mode 100644 index 000000000..8eaecd596 --- /dev/null +++ b/app/models/public_body_category.rb @@ -0,0 +1,90 @@ +# == Schema Information +# +# Table name: public_body_categories +# +# id :integer not null, primary key +# title :text not null +# category_tag :text not null +# description :text not null +# display_order :integer +# + +require 'forwardable' + +class PublicBodyCategory < ActiveRecord::Base + attr_accessible :locale, :category_tag, :title, :description, + :translated_versions, :display_order + + has_many :public_body_category_links, :dependent => :destroy + has_many :public_body_headings, :through => :public_body_category_links + + translates :title, :description + validates_uniqueness_of :category_tag, :message => N_('Tag is already taken') + validates_presence_of :title, :message => N_("Title can't be blank") + validates_presence_of :category_tag, :message => N_("Tag can't be blank") + + def self.get + locale = I18n.locale.to_s || default_locale.to_s || "" + categories = CategoryCollection.new + I18n.with_locale(locale) do + headings = PublicBodyHeading.all + headings.each do |heading| + categories << heading.name + heading.public_body_categories.each do |category| + categories << [ + category.category_tag, + category.title, + category.description + ] + end + end + end + categories + end + + def self.without_headings + sql = %Q| SELECT * FROM public_body_categories pbc + WHERE pbc.id NOT IN ( + SELECT public_body_category_id AS id + FROM public_body_category_links + ) | + PublicBodyCategory.find_by_sql(sql) + end + + # Called from the old-style public_body_categories_[locale].rb data files + def self.add(locale, data_list) + CategoryAndHeadingMigrator.add_categories_and_headings_from_list(locale, data_list) + end + + # Convenience methods for creating/editing translations via forms + def find_translation_by_locale(locale) + translations.find_by_locale(locale) + end + + def translated_versions + translations + end + + def translated_versions=(translation_attrs) + def empty_translation?(attrs) + attrs_with_values = attrs.select{ |key, value| value != '' and key != 'locale' } + attrs_with_values.empty? + end + if translation_attrs.respond_to? :each_value # Hash => updating + translation_attrs.each_value do |attrs| + next if empty_translation?(attrs) + t = translation_for(attrs[:locale]) || PublicBodyCategory::Translation.new + t.attributes = attrs + t.save! + end + else # Array => creating + translation_attrs.each do |attrs| + next if empty_translation?(attrs) + new_translation = PublicBodyCategory::Translation.new(attrs) + translations << new_translation + end + end + end +end + + diff --git a/app/models/public_body_category/category_collection.rb b/app/models/public_body_category/category_collection.rb new file mode 100644 index 000000000..8286e2710 --- /dev/null +++ b/app/models/public_body_category/category_collection.rb @@ -0,0 +1,54 @@ +# replicate original file-based PublicBodyCategories functionality +class PublicBodyCategory::CategoryCollection + include Enumerable + extend Forwardable + def_delegators :@categories, :each, :<< + + def initialize + @categories = [] + end + + def with_headings + @categories + end + + def with_description + @categories.select() { |a| a.instance_of?(Array) } + end + + def tags + tags = with_description.map() { |a| a[0] } + end + + def by_tag + Hash[*with_description.map() { |a| a[0..1] }.flatten] + end + + def singular_by_tag + Hash[*with_description.map() { |a| [a[0],a[2]] }.flatten] + end + + def by_heading + output = {} + heading = nil + @categories.each do |row| + if row.is_a?(Array) + output[heading] << row[0] + else + heading = row + output[heading] = [] + end + end + output + end + + def headings + output = [] + @categories.each do |row| + unless row.is_a?(Array) + output << row + end + end + output + end +end diff --git a/app/models/public_body_category_link.rb b/app/models/public_body_category_link.rb new file mode 100644 index 000000000..eb233b56f --- /dev/null +++ b/app/models/public_body_category_link.rb @@ -0,0 +1,34 @@ +# == Schema Information +# +# Table name: public_body_category_link +# +# public_body_category_id :integer not null +# public_body_heading_id :integer not null +# category_display_order :integer +# + +class PublicBodyCategoryLink < ActiveRecord::Base + attr_accessible :public_body_category_id, :public_body_heading_id, :category_display_order + + belongs_to :public_body_category + belongs_to :public_body_heading + validates_presence_of :public_body_category + validates_presence_of :public_body_heading + validates :category_display_order, :numericality => { :only_integer => true, + :message => N_('Display order must be a number') } + + before_validation :on => :create do + unless self.category_display_order + self.category_display_order = PublicBodyCategoryLink.next_display_order(public_body_heading_id) + end + end + + def self.next_display_order(heading_id) + if last = where(:public_body_heading_id => heading_id).order(:category_display_order).last + last.category_display_order + 1 + else + 0 + end + end + +end diff --git a/app/models/public_body_heading.rb b/app/models/public_body_heading.rb new file mode 100644 index 000000000..c38800561 --- /dev/null +++ b/app/models/public_body_heading.rb @@ -0,0 +1,75 @@ +# == Schema Information +# +# Table name: public_body_headings +# +# id :integer not null, primary key +# name :text not null +# display_order :integer +# + +class PublicBodyHeading < ActiveRecord::Base + attr_accessible :name, :display_order, :translated_versions + + has_many :public_body_category_links, :dependent => :destroy + has_many :public_body_categories, :order => :category_display_order, :through => :public_body_category_links + default_scope order('display_order ASC') + + translates :name + + validates_uniqueness_of :name, :message => N_('Name is already taken') + validates_presence_of :name, :message => N_('Name can\'t be blank') + validates :display_order, :numericality => { :only_integer => true, + :message => N_('Display order must be a number') } + + before_validation :on => :create do + unless self.display_order + self.display_order = PublicBodyHeading.next_display_order + end + end + + # Convenience methods for creating/editing translations via forms + def find_translation_by_locale(locale) + translations.find_by_locale(locale) + end + + def translated_versions + translations + end + + def translated_versions=(translation_attrs) + def empty_translation?(attrs) + attrs_with_values = attrs.select{ |key, value| value != '' and key != 'locale' } + attrs_with_values.empty? + end + + if translation_attrs.respond_to? :each_value # Hash => updating + translation_attrs.each_value do |attrs| + next if empty_translation?(attrs) + t = translation_for(attrs[:locale]) || PublicBodyHeading::Translation.new + t.attributes = attrs + t.save! + end + else # Array => creating + translation_attrs.each do |attrs| + next if empty_translation?(attrs) + new_translation = PublicBodyHeading::Translation.new(attrs) + translations << new_translation + end + end + end + + def add_category(category) + unless public_body_categories.include?(category) + public_body_categories << category + end + end + + def self.next_display_order + if max = maximum(:display_order) + max + 1 + else + 0 + end + end + +end diff --git a/app/views/admin_general/_admin_navbar.html.erb b/app/views/admin_general/_admin_navbar.html.erb index 5cc740f70..14fc06092 100644 --- a/app/views/admin_general/_admin_navbar.html.erb +++ b/app/views/admin_general/_admin_navbar.html.erb @@ -10,6 +10,7 @@ <li><%= link_to 'Stats', admin_stats_path %></li> <li><%= link_to 'Debug', admin_debug_path %></li> <li><%= link_to 'Authorities', admin_body_list_path %></li> + <li><%= link_to 'Categories', admin_categories_path %></li> <li><%= link_to 'Requests', admin_request_list_path %></li> <li><%= link_to 'Users', admin_user_list_path %></li> <li><%= link_to 'Tracks', admin_track_list_path %></li> diff --git a/app/views/admin_public_body/_tag_help.html.erb b/app/views/admin_public_body/_tag_help.html.erb index b64e65877..5d6990400 100644 --- a/app/views/admin_public_body/_tag_help.html.erb +++ b/app/views/admin_public_body/_tag_help.html.erb @@ -1,6 +1,6 @@ <h2>List of tags</h2> <% first_row = true %> -<% for row in PublicBodyCategories::get().with_headings() %> +<% for row in PublicBodyCategory.get().with_headings() %> <% if row.instance_of?(Array) %> <% if row[0] != 'other' %> <strong><%= row[0] %></strong>=<%= row[1] %> diff --git a/app/views/admin_public_body/import_csv.html.erb b/app/views/admin_public_body/import_csv.html.erb index c690f0fc2..4b14226d1 100644 --- a/app/views/admin_public_body/import_csv.html.erb +++ b/app/views/admin_public_body/import_csv.html.erb @@ -76,7 +76,7 @@ Another One,another@example.com,Otro organismo,a_tag <hr> <p>Standard tags: - <% for category, description in PublicBodyCategories::get().by_tag() %> + <% for category, description in PublicBodyCategory.get().by_tag() %> <% if category != "other" %> <strong><%= category %></strong>=<%= description %>; <% end %> diff --git a/app/views/admin_public_body_categories/_category_list_item.html.erb b/app/views/admin_public_body_categories/_category_list_item.html.erb new file mode 100644 index 000000000..056ab6148 --- /dev/null +++ b/app/views/admin_public_body_categories/_category_list_item.html.erb @@ -0,0 +1,5 @@ +<div class="category-list-item" <% if heading %> data-id="categories_<%= category.id %>"<% end %>> + <%= link_to(category.title, edit_admin_category_path(category), :title => "view full details") %> +</div> + + diff --git a/app/views/admin_public_body_categories/_form.html.erb b/app/views/admin_public_body_categories/_form.html.erb new file mode 100644 index 000000000..b0778d371 --- /dev/null +++ b/app/views/admin_public_body_categories/_form.html.erb @@ -0,0 +1,66 @@ +<%= error_messages_for 'category' %> + +<!--[form:public_body_category]--> + +<div id="div-locales"> + <ul class="locales nav nav-tabs"> + <% I18n.available_locales.each_with_index do |locale, i| %> + <li><a href="#div-locale-<%=locale.to_s%>" data-toggle="tab" ><%=locale_name(locale.to_s) || "Default locale"%></a></li> + <% end %> + </ul> + <div class="tab-content"> +<% + I18n.available_locales.each do |locale| + if locale==I18n.default_locale # The default locale is submitted as part of the bigger object... + prefix = 'public_body_category' + object = @category + else # ...but additional locales go "on the side" + prefix = "public_body_category[translated_versions][]" + object = @category.new_record? ? + PublicBodyCategory::Translation.new : + @category.find_translation_by_locale(locale.to_s) || PublicBodyCategory::Translation.new + end +%> + <%= fields_for prefix, object do |t| %> + <div class="tab-pane" id="div-locale-<%=locale.to_s%>"> + <div class="control-group"> + <%= t.hidden_field :locale, :value => locale.to_s %> + <label for="<%= form_tag_id(t.object_name, :title, locale) %>" class="control-label">Title</label> + <div class="controls"> + <%= t.text_field :title, :id => form_tag_id(t.object_name, :title, locale), :class => "span4" %> + </div> + </div> + <div class="control-group"> + <label for="<%= form_tag_id(t.object_name, :description, locale) %>" class="control-label">Description</label> + <div class="controls"> + <%= t.text_field :description, :id => form_tag_id(t.object_name, :description, locale), :class => "span4" %> + </div> + </div> + </div> + <% + end +end +%> + </div> +</div> + +<% if PublicBody.find_by_tag(@category.category_tag).count == 0 or @category.errors.messages.keys.include?(:category_tag) %> + <h3>Common Fields</h3> + + <div class="control-group"> + <label for="public_body_category_category_tag" class="control-label">Category tag</label> + <div class="controls"> + <%= f.text_field :category_tag, :class => "span4" %> + </div> + </div> +<% end %> + +<h3>Headings</h3> +<div class="control-group"> + <% PublicBodyHeading.all.each do |heading| %> + <div class="span3"> + <%= check_box_tag "headings[heading_#{heading.id}]", heading.id, heading_is_selected?(heading) %> <label for="headings_heading_<%= heading.id %>" class="control-label"><%= heading.name %></label> + </div> + <% end %> +</div> +<!--[eoform:public_body_category]--> diff --git a/app/views/admin_public_body_categories/_heading_list.html.erb b/app/views/admin_public_body_categories/_heading_list.html.erb new file mode 100644 index 000000000..4bd8bdc90 --- /dev/null +++ b/app/views/admin_public_body_categories/_heading_list.html.erb @@ -0,0 +1,26 @@ +<div class="accordion" id="category_list"> + <% for heading in category_headings %> + <div class="accordion-group" data-id="headings_<%=heading.id%>"> + <div class="accordion-heading accordion-toggle row"> + <span class="item-title span6"> + <a href="#heading_<%=heading.id%>_categories" data-toggle="collapse" data-parent="#categories" ><%= chevron_right %></a> + <strong><%= link_to(heading.name, edit_admin_heading_path(heading), :title => "view full details") %></strong> + </span> + </div> + + <div id="heading_<%= heading.id %>_categories" class="accordion-body collapse row "> + <div class="well"> + <div class="span12" id="heading_<%= heading.id %>_category_list" class="category-list"> + <% heading.public_body_categories.each do |category| %> + <%= render :partial => 'category_list_item', :locals => { :category => category, :heading => heading } %> + <% end %> + </div> + + <div class="form-actions save-panel"> + <%= link_to "Save", '#', :class => "btn btn-primary disabled save-order", "data-heading-id" => heading.id, "data-list-id" => "#heading_#{heading.id}_category_list", 'data-endpoint' => reorder_categories_admin_heading_path(heading) %><p class="save-notice" data-unsaved-text="There are unsaved changes to the order of categories." data-success-text="Changes saved." data-error-text="There was an error saving your changes: ">Drag and drop to change the order of categories.</p> + </div> + </div> + </div> + </div> + <% end %> +</div> diff --git a/app/views/admin_public_body_categories/edit.html.erb b/app/views/admin_public_body_categories/edit.html.erb new file mode 100644 index 000000000..95988d688 --- /dev/null +++ b/app/views/admin_public_body_categories/edit.html.erb @@ -0,0 +1,30 @@ +<h1><%=@title%></h1> + +<div class="row"> + <div class="span8"> + <div id="public_body_category_form"> + <%= form_for @category, :url => admin_category_path(@category), :html => { :class => "form form-horizontal" } do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <div class="form-actions"> + <%= f.submit 'Save', :accesskey => 's', :class => "btn btn-success" %></p> + </div> + <% end %> + </div> +</div> + +<div class="row"> + <div class="span8 well"> + <%= link_to 'List all', admin_categories_path, :class => "btn" %> + </div> +</div> + +<% if @tagged_public_bodies.empty? %> + <div class="row"> + <div class="span8"> + <%= form_tag(admin_category_path(@category), :method => 'delete', :class => "form form-inline") do %> + <%= hidden_field_tag(:public_body_id, { :value => @category.id } ) %> + <%= submit_tag "Destroy #{@category.title}", :title => @category.title, :class => "btn btn-danger" %> (this is permanent!) + <% end %> + </div> + </div> +<% end %> diff --git a/app/views/admin_public_body_categories/index.html.erb b/app/views/admin_public_body_categories/index.html.erb new file mode 100644 index 000000000..62ec4623d --- /dev/null +++ b/app/views/admin_public_body_categories/index.html.erb @@ -0,0 +1,28 @@ +<% @title = 'Listing public authority categories' %> + +<h1><%=@title%></h1> + +<div class="btn-toolbar"> + <div class="btn-group"> + <%= link_to 'New category', new_admin_category_path, :class => "btn btn-primary" %> + </div> + <div class="btn-group"> + <%= link_to 'New category heading', new_admin_heading_path, :class => "btn" %> + </div> +</div> + +<h2>All category headings</h2> +<div> +<%= render :partial => 'heading_list', :locals => { :category_headings => @category_headings, :table_name => 'exact' } %> + +<% if @without_heading.count > 0 %> + + <h3>Categories with no heading</h3> + + <% @without_heading.each do |category| %> + <%= render :partial => 'category_list_item', :locals => { :category => category, :heading => nil } %> + <% end %> +<% end %> +<div class="form-actions save-panel"> +<%= link_to "Save", '#', :class => "btn btn-primary disabled save-order", "data-list-id" => '#category_list', 'data-endpoint' => reorder_admin_headings_path %><p class="save-notice" data-unsaved-text="There are unsaved changes to the order of category headings." data-success-text="Changes saved." data-error-text="There was an error saving your changes: ">Drag and drop to change the order of category headings.</p> +</div> diff --git a/app/views/admin_public_body_categories/new.html.erb b/app/views/admin_public_body_categories/new.html.erb new file mode 100644 index 000000000..8b1b1103f --- /dev/null +++ b/app/views/admin_public_body_categories/new.html.erb @@ -0,0 +1,21 @@ +<% @title = 'New category' %> + +<h1><%=@title%></h1> +<div class="row"> + <div class="span8"> + <div id="public_category_form"> + <%= form_for @category, :url => admin_categories_path, :html => {:class => "form form-horizontal"} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + + <div class="form-actions"> + <%= f.submit "Create", :class => "btn btn-primary" %> + </div> + <% end %> + <div class="row"> + <div class="span8 well"> + <%= link_to 'List all', admin_categories_path, :class => "btn" %> + </div> + </div> + </div> + </div> +</div> diff --git a/app/views/admin_public_body_headings/_form.html.erb b/app/views/admin_public_body_headings/_form.html.erb new file mode 100644 index 000000000..d4e914ca1 --- /dev/null +++ b/app/views/admin_public_body_headings/_form.html.erb @@ -0,0 +1,41 @@ +<%= error_messages_for 'heading' %> + +<!--[form:public_body_heading]--> + +<div id="div-locales"> + <ul class="locales nav nav-tabs"> + <% I18n.available_locales.each_with_index do |locale, i| %> + <li><a href="#div-locale-<%=locale.to_s%>" data-toggle="tab" ><%=locale_name(locale.to_s) || "Default locale"%></a></li> + <% end %> + </ul> + <div class="tab-content"> +<% + for locale in I18n.available_locales do + if locale==I18n.default_locale # The default locale is submitted as part of the bigger object... + prefix = 'public_body_heading' + object = @heading + else # ...but additional locales go "on the side" + prefix = "public_body_heading[translated_versions][]" + object = @heading.new_record? ? + PublicBodyHeading::Translation.new : + @heading.find_translation_by_locale(locale.to_s) || PublicBodyHeading::Translation.new + end +%> + <%= fields_for prefix, object do |t| %> + <div class="tab-pane" id="div-locale-<%=locale.to_s%>"> + <div class="control-group"> + <%= t.hidden_field :locale, :value => locale.to_s %> + <label for="<%= form_tag_id(t.object_name, :name, locale) %>" class="control-label">Name</label> + <div class="controls"> + <%= t.text_field :name, :id => form_tag_id(t.object_name, :name, locale), :class => "span4" %> + </div> + </div> + </div> + <% + end +end +%> + </div> +</div> + +<!--[eoform:public_body_heading]--> diff --git a/app/views/admin_public_body_headings/edit.html.erb b/app/views/admin_public_body_headings/edit.html.erb new file mode 100644 index 000000000..eff89285a --- /dev/null +++ b/app/views/admin_public_body_headings/edit.html.erb @@ -0,0 +1,30 @@ +<h1><%=@title%></h1> + +<div class="row"> + <div class="span8"> + <div id="public_body_heading_form"> + <%= form_for @heading, :url => admin_heading_path(@heading), :html => { :class => "form form-horizontal" } do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <div class="form-actions"> + <%= f.submit 'Save', :accesskey => 's', :class => "btn btn-success" %></p> + </div> + <% end %> + </div> +</div> + +<div class="row"> + <div class="span8 well"> + <%= link_to 'List all', admin_categories_path, :class => "btn" %> + </div> +</div> + +<% if @heading.public_body_categories.empty? %> + <div class="row"> + <div class="span8"> + <%= form_tag(admin_heading_path(@heading), :method => 'delete', :class => "form form-inline") do %> + <%= hidden_field_tag(:public_body_heading_id, { :value => @heading.id } ) %> + <%= submit_tag "Destroy #{@heading.name}", :name => @heading.name, :class => "btn btn-danger" %> (this is permanent!) + <% end %> + </div> + </div> +<% end %> diff --git a/app/views/admin_public_body_headings/new.html.erb b/app/views/admin_public_body_headings/new.html.erb new file mode 100644 index 000000000..91d5d4a9d --- /dev/null +++ b/app/views/admin_public_body_headings/new.html.erb @@ -0,0 +1,21 @@ +<% @title = 'New category heading' %> + +<h1><%=@title%></h1> +<div class="row"> + <div class="span8"> + <div id="public_heading_form"> + <%= form_for @heading, :url => admin_headings_path, :html => {:class => "form form-horizontal"} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + + <div class="form-actions"> + <%= f.submit "Create", :class => "btn btn-primary" %> + </div> + <% end %> + <div class="row"> + <div class="span8 well"> + <%= link_to 'List all', admin_categories_path, :class => "btn" %> + </div> + </div> + </div> + </div> +</div> diff --git a/app/views/public_body/list.html.erb b/app/views/public_body/list.html.erb index ce24daaf9..0750c7655 100644 --- a/app/views/public_body/list.html.erb +++ b/app/views/public_body/list.html.erb @@ -7,7 +7,7 @@ </li> </ul> <% first_row = true %> - <% for row in PublicBodyCategories::get().with_headings() %> + <% for row in PublicBodyCategory.get().with_headings() %> <% if row.instance_of?(Array) %> <li> <%= link_to_unless (@tag == row[0]), row[1], list_public_bodies_path(:tag => row[0]) %> diff --git a/config/initializers/alaveteli.rb b/config/initializers/alaveteli.rb index 9ea6428ba..9a151e3e8 100644 --- a/config/initializers/alaveteli.rb +++ b/config/initializers/alaveteli.rb @@ -44,7 +44,6 @@ require 'world_foi_websites.rb' require 'alaveteli_external_command.rb' require 'quiet_opener.rb' require 'mail_handler' -require 'public_body_categories' require 'ability' require 'normalize_string' require 'alaveteli_file_types' @@ -54,6 +53,8 @@ require 'theme' require 'xapian_queries' require 'date_quarter' require 'public_body_csv' +require 'category_and_heading_migrator' +require 'public_body_categories' AlaveteliLocalization.set_locales(AlaveteliConfiguration::available_locales, AlaveteliConfiguration::default_locale) @@ -62,3 +63,4 @@ AlaveteliLocalization.set_locales(AlaveteliConfiguration::available_locales, if Rails.env == 'test' and ActiveRecord::Base.configurations['test']['constraint_disabling'] == false require 'no_constraint_disabling' end + diff --git a/config/routes.rb b/config/routes.rb index 84ec86792..fd832a2ad 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -181,6 +181,24 @@ Alaveteli::Application.routes.draw do match '/admin/body/mass_tag_add' => 'admin_public_body#mass_tag_add', :as => :admin_body_mass_tag_add #### + #### AdminPublicBodyCategory controller + scope '/admin', :as => 'admin' do + resources :categories, + :controller => 'admin_public_body_categories' + end + #### + + #### AdminPublicBodyHeading controller + scope '/admin', :as => 'admin' do + resources :headings, + :controller => 'admin_public_body_headings', + :except => [:index] do + post 'reorder', :on => :collection + post 'reorder_categories', :on => :member + end + end + #### + #### AdminPublicBodyChangeRequest controller match '/admin/change_request/edit/:id' => 'admin_public_body_change_requests#edit', :as => :admin_change_request_edit match '/admin/change_request/update/:id' => 'admin_public_body_change_requests#update', :as => :admin_change_request_update diff --git a/db/migrate/20140710094405_create_public_body_headings_and_categories.rb b/db/migrate/20140710094405_create_public_body_headings_and_categories.rb new file mode 100644 index 000000000..0ba7f64a0 --- /dev/null +++ b/db/migrate/20140710094405_create_public_body_headings_and_categories.rb @@ -0,0 +1,27 @@ +class CreatePublicBodyHeadingsAndCategories < ActiveRecord::Migration + def up + create_table :public_body_headings, :force => true do |t| + t.string :locale + t.text :name, :null => false + t.integer :display_order + end + + create_table :public_body_categories, :force => true do |t| + t.string :locale + t.text :title, :null => false + t.text :category_tag, :null => false + t.text :description, :null => false + end + + create_table :public_body_categories_public_body_headings, :id => false do |t| + t.integer :public_body_category_id, :null => false + t.integer :public_body_heading_id, :null => false + end + end + + def down + drop_table :public_body_categories + drop_table :public_body_headings + drop_table :public_body_categories_public_body_headings + end +end
\ No newline at end of file diff --git a/db/migrate/20140716131107_create_category_translation_tables.rb b/db/migrate/20140716131107_create_category_translation_tables.rb new file mode 100644 index 000000000..f4b90b330 --- /dev/null +++ b/db/migrate/20140716131107_create_category_translation_tables.rb @@ -0,0 +1,163 @@ +class CreateCategoryTranslationTables < ActiveRecord::Migration + class PublicBodyCategory < ActiveRecord::Base + translates :title, :description + end + class PublicBodyHeading < ActiveRecord::Base + translates :name + end + def up + default_locale = I18n.locale.to_s + + fields = {:title => :text, + :description => :text} + PublicBodyCategory.create_translation_table!(fields) + + # copy current values across to the default locale + PublicBodyCategory.where(:locale => default_locale).each do |category| + category.translated_attributes.each do |a, default| + value = category.read_attribute(a) + unless value.nil? + category.send(:"#{a}=", value) + end + end + category.save! + end + + # copy current values across to the non-default locale(s) + PublicBodyCategory.where('locale != ?', default_locale).each do |category| + default_category = PublicBodyCategory.find_by_category_tag_and_locale(category.category_tag, default_locale) + I18n.with_locale(category.locale) do + category.translated_attributes.each do |a, default| + value = category.read_attribute(a) + unless value.nil? + if default_category + default_category.send(:"#{a}=", value) + else + category.send(:"#{a}=", value) + end + end + category.delete if default_category + end + end + if default_category + default_category.save! + category.delete + else + category.save! + end + end + + fields = { :name => :text } + PublicBodyHeading.create_translation_table!(fields) + + # copy current values across to the default locale + PublicBodyHeading.where(:locale => default_locale).each do |heading| + heading.translated_attributes.each do |a, default| + value = heading.read_attribute(a) + unless value.nil? + heading.send(:"#{a}=", value) + end + end + heading.save! + end + + # copy current values across to the non-default locale(s) + PublicBodyHeading.where('locale != ?', default_locale).each do |heading| + default_heading = PublicBodyHeading.find_by_name_and_locale(heading.name, default_locale) + I18n.with_locale(heading.locale) do + heading.translated_attributes.each do |a, default| + value = heading.read_attribute(a) + unless value.nil? + if default_heading + default_heading.send(:"#{a}=", value) + else + heading.send(:"#{a}=", value) + end + end + heading.delete if default_heading + end + end + if default_heading + default_heading.save! + heading.delete + else + heading.save! + end + end + + # finally, drop the old locale column from both tables + remove_column :public_body_headings, :locale + remove_column :public_body_categories, :locale + remove_column :public_body_headings, :name + remove_column :public_body_categories, :title + remove_column :public_body_categories, :description + + # and set category_tag to be unique + add_index :public_body_categories, :category_tag, :unique => true + end + + def down + # reinstate the columns + add_column :public_body_categories, :locale, :string + add_column :public_body_headings, :locale, :string + add_column :public_body_headings, :name, :string + add_column :public_body_categories, :title, :string + add_column :public_body_categories, :description, :string + + # drop the index + remove_index :public_body_categories, :category_tag + + # restore the data + new_categories = [] + PublicBodyCategory.all.each do |category| + category.locale = category.translation.locale.to_s + I18n.available_locales.each do |locale| + if locale.to_s != category.locale + translation = category.translations.find_by_locale(locale) + if translation + new_cat = category.dup + category.translated_attributes.each do |a, _| + value = translation.read_attribute(a) + new_cat.send(:"#{a}=", value) + end + new_cat.locale = locale.to_s + new_categories << new_cat + end + else + category.save! + end + end + end + new_categories.each do |cat| + cat.save! + end + + new_headings = [] + PublicBodyHeading.all.each do |heading| + heading.locale = heading.translation.locale.to_s + I18n.available_locales.each do |locale| + if locale.to_s != heading.locale + new_heading = heading.dup + translation = heading.translations.find_by_locale(locale) + if translation + heading.translated_attributes.each do |a, _| + value = translation.read_attribute(a) + new_heading.send(:"#{a}=", value) + end + new_heading.locale = locale.to_s + new_headings << new_heading + end + else + heading.save! + end + end + end + new_headings.each do |heading| + heading.save! + end + + # drop the translation tables + PublicBodyCategory.drop_translation_table! + PublicBodyHeading.drop_translation_table! + end +end diff --git a/db/migrate/20140804120601_add_display_order_to_categories_and_headings.rb b/db/migrate/20140804120601_add_display_order_to_categories_and_headings.rb new file mode 100644 index 000000000..c2e7e2ac3 --- /dev/null +++ b/db/migrate/20140804120601_add_display_order_to_categories_and_headings.rb @@ -0,0 +1,15 @@ +class AddDisplayOrderToCategoriesAndHeadings < ActiveRecord::Migration + def up + add_column :public_body_categories_public_body_headings, :category_display_order, :integer + rename_table :public_body_categories_public_body_headings, :public_body_category_links + add_column :public_body_category_links, :id, :primary_key + add_index :public_body_category_links, [:public_body_category_id, :public_body_heading_id], :name => "index_public_body_category_links_on_join_ids", :primary => true + end + + def down + remove_index :public_body_category_links, :name => "index_public_body_category_links_on_join_ids" + remove_column :public_body_category_links, :category_display_order + remove_column :public_body_category_links, :id + rename_table :public_body_category_links, :public_body_categories_public_body_headings + end +end diff --git a/doc/CHANGES.md b/doc/CHANGES.md index 748b37665..40834d4d0 100644 --- a/doc/CHANGES.md +++ b/doc/CHANGES.md @@ -8,6 +8,8 @@ rather than only as a database constraint. If you have added a `CensorRule` in your theme, you will now have to satisfy the additional validations on the `:replacement`, `:last_edit_comment` and `:last_edit_editor` attributes. +* Public body categories will now be stored in the database rather than being read directly from the `lib/public_body_categories_LOCALE` files. Once you have upgraded, run `script/migrate-public-body-categories`to import the contents of the files into the database. All further changes will then need to be made via the administrative interface. You can then remove any `pubic_body_categories_[locale].rb` files from your theme. If your theme has any calls to `PublicBodyCategories` methods outside these files, you should update them to call the corresponding method on `PublicBodyCategory` instead. + # Version 0.19 @@ -69,11 +71,11 @@ candidate: * Install `lockfile-progs` so that the `run-with-lockfile` shell script can be used instead of the C program -* Use responsive stylesheets in `config/general.yml`: +* Use responsive stylesheets in `config/general.yml`: `RESPONSIVE_STYLING: true`. If you don't currently use responsive styling, and you don't want to get switched over just set `RESPONSIVE_STYLING: false` and the fixed-width stylesheets will be used as before. -* Allow access to public body stats page if desired in `config/general/yml`: +* Allow access to public body stats page if desired in `config/general/yml`: `PUBLIC_BODY_STATISTICS_PAGE: true` * Run migrations to define track_things constraint correctly (Robin Houston) and add additional index for `event_type` on `info_request_events` (Steven Day) diff --git a/lib/category_and_heading_migrator.rb b/lib/category_and_heading_migrator.rb new file mode 100644 index 000000000..402ea7204 --- /dev/null +++ b/lib/category_and_heading_migrator.rb @@ -0,0 +1,91 @@ +module CategoryAndHeadingMigrator + + # This module migrates data from public_body_categories_[locale].rb files + # into PublicBodyHeading and PublicBodyCategory models + + # Load all the data from public_body_categories_[locale].rb files. + def self.migrate_categories_and_headings + if PublicBodyCategory.count > 0 + puts "PublicBodyCategories exist already, not migrating." + else + @first_locale = true + I18n.available_locales.each do |locale| + begin + load "public_body_categories_#{locale}.rb" + rescue MissingSourceFile + end + @first_locale = false + end + end + end + + # Load the categories and headings for a locale + def self.add_categories_and_headings_from_list(locale, data_list) + # set the counter for headings loaded from this locale + @@locale_heading_display_order = 0 + current_heading = nil + data_list.each do |list_item| + if list_item.is_a?(Array) + # item is list of category data + add_category(list_item, current_heading, locale) + else + # item is heading name + current_heading = add_heading(list_item, locale, @first_locale) + end + end + end + + def self.add_category(category_data, heading, locale) + tag, title, description = category_data + category = PublicBodyCategory.find_by_category_tag(tag) + if category + add_category_in_locale(category, title, description, locale) + else + category = PublicBodyCategory.create(:category_tag => tag, + :title => title, + :description => description) + + # add the translation if this is not the default locale + # (occurs when a category is not defined in default locale) + unless category.translations.map { |t| t.locale }.include?(locale) + add_category_in_locale(category, title, description, locale) + end + end + heading.add_category(category) + end + + def self.add_category_in_locale(category, title, description, locale) + I18n.with_locale(locale) do + category.title = title + category.description = description + category.save + end + end + + def self.add_heading(name, locale, first_locale) + heading = nil + I18n.with_locale(locale) do + heading = PublicBodyHeading.find_by_name(name) + end + # For multi-locale installs, we assume that all public_body_[locale].rb files + # use the same headings in the same order, so we add translations to the heading + # that was in the same position in the list loaded from other public_body_[locale].rb + # files. + if heading.nil? && !@first_locale + heading = PublicBodyHeading.where(:display_order => @@locale_heading_display_order).first + end + + if heading + I18n.with_locale(locale) do + heading.name = name + heading.save + end + else + I18n.with_locale(locale) do + heading = PublicBodyHeading.create(:name => name) + end + end + @@locale_heading_display_order += 1 + heading + end +end diff --git a/lib/public_body_categories.rb b/lib/public_body_categories.rb index 7f548b130..3528e85b1 100644 --- a/lib/public_body_categories.rb +++ b/lib/public_body_categories.rb @@ -1,60 +1,11 @@ -# lib/public_body_categories.rb: -# Categorisations of public bodies. -# -# Copyright (c) 2009 UK Citizens Online Democracy. All rights reserved. -# Email: hello@mysociety.org; WWW: http://www.mysociety.org/ - +# Allow the PublicBodyCategory model to be addressed using the same syntax +# as the old PublicBodyCategories class without needing to rename everything, +# make sure we're not going to break any themes class PublicBodyCategories - attr_reader :with_description, - :with_headings, - :tags, - :by_tag, - :singular_by_tag, - :by_heading, - :headings - - def initialize(categories) - @with_headings = categories - # Arranged in different ways for different sorts of displaying - @with_description = @with_headings.select() { |a| a.instance_of?(Array) } - @tags = @with_description.map() { |a| a[0] } - @by_tag = Hash[*@with_description.map() { |a| a[0..1] }.flatten] - @singular_by_tag = Hash[*@with_description.map() { |a| [a[0],a[2]] }.flatten] - @by_heading = {} - heading = nil - @headings = [] - @with_headings.each do |row| - if ! row.instance_of?(Array) - heading = row - @headings << row - @by_heading[row] = [] - else - @by_heading[heading] << row[0] - end - end - end - - - def PublicBodyCategories.get - load_categories if @@CATEGORIES.empty? - @@CATEGORIES[I18n.locale.to_s] || @@CATEGORIES[I18n.default_locale.to_s] || PublicBodyCategories.new([]) + def self.method_missing(method, *args, &block) + warn 'Use of PublicBodyCategories is deprecated and will be removed in release 0.21. Please use PublicBodyCategory instead.' + PublicBodyCategory.send(method, *args, &block) end - # Called from the data files themselves - def PublicBodyCategories.add(locale, categories) - @@CATEGORIES[locale.to_s] = PublicBodyCategories.new(categories) - end - - private - @@CATEGORIES = {} - - def PublicBodyCategories.load_categories() - I18n.available_locales.each do |locale| - begin - load "public_body_categories_#{locale}.rb" - rescue MissingSourceFile - end - end - end end diff --git a/lib/public_body_categories_en.rb b/lib/public_body_categories_en.rb deleted file mode 100644 index 95eed750b..000000000 --- a/lib/public_body_categories_en.rb +++ /dev/null @@ -1,19 +0,0 @@ -# The PublicBodyCategories structure works like this: -# [ -# "Main category name", -# [ "tag_to_use_as_category", "Sub category title", "sentence that can describes things in this subcategory" ], -# [ "another_tag", "Second sub category title", "another descriptive sentence for things in this subcategory"], -# "Another main category name", -# [ "another_tag_2", "Another sub category title", "another descriptive sentence"] -# ]) -# -# DO NOT EDIT THIS FILE! It should be overridden in a custom theme. -# See doc/THEMES.md for more info - -PublicBodyCategories.add(:en, [ - "Silly ministries", - [ "useless_agency", "Useless ministries", "a useless ministry" ], - [ "lonely_agency", "Lonely agencies", "a lonely agency"], - "Popular agencies", - [ "popular_agency", "Popular agencies", "a lonely agency"] -]) diff --git a/script/migrate-public-body-categories b/script/migrate-public-body-categories new file mode 100755 index 000000000..23abe4648 --- /dev/null +++ b/script/migrate-public-body-categories @@ -0,0 +1,4 @@ +#!/bin/bash +TOP_DIR="$(dirname "$BASH_SOURCE")/.." +cd "$TOP_DIR" +bundle exec rails runner 'CategoryAndHeadingMigrator.migrate_categories_and_headings' diff --git a/spec/controllers/admin_public_body_categories_controller_spec.rb b/spec/controllers/admin_public_body_categories_controller_spec.rb new file mode 100644 index 000000000..35454990d --- /dev/null +++ b/spec/controllers/admin_public_body_categories_controller_spec.rb @@ -0,0 +1,192 @@ +require 'spec_helper' + +describe AdminPublicBodyCategoriesController do + context 'when showing the index of categories and headings' do + render_views + + it 'shows the index page' do + get :index + end + end + + context 'when showing the form for a new public body category' do + it 'should assign a new public body category to the view' do + get :new + assigns[:category].should be_a(PublicBodyCategory) + end + end + + context 'when creating a public body category' do + it "creates a new public body category in one locale" do + n = PublicBodyCategory.count + post :create, { + :public_body_category => { + :title => 'New Category', + :category_tag => 'new_test_category', + :description => 'New category for testing stuff' + } + } + PublicBodyCategory.count.should == n + 1 + + category = PublicBodyCategory.find_by_title("New Category") + response.should redirect_to(admin_categories_path) + end + + it "saves the public body category's heading associations" do + heading = FactoryGirl.create(:public_body_heading) + category_attributes = FactoryGirl.attributes_for(:public_body_category) + post :create, { + :public_body_category => category_attributes, + :headings => {"heading_#{heading.id}" => heading.id} + } + request.flash[:notice].should include('successful') + category = PublicBodyCategory.find_by_title(category_attributes[:title]) + category.public_body_headings.should == [heading] + end + + + it 'creates a new public body category with multiple locales' do + n = PublicBodyCategory.count + post :create, { + :public_body_category => { + :title => 'New Category', + :category_tag => 'new_test_category', + :description => 'New category for testing stuff', + :translated_versions => [{ :locale => "es", + :title => "Mi Nuevo Category" }] + } + } + PublicBodyCategory.count.should == n + 1 + + category = PublicBodyCategory.find_by_title("New Category") + category.translations.map {|t| t.locale.to_s}.sort.should == ["en", "es"] + I18n.with_locale(:en) do + category.title.should == "New Category" + end + I18n.with_locale(:es) do + category.title.should == "Mi Nuevo Category" + end + + response.should redirect_to(admin_categories_path) + end + end + + context 'when editing a public body category' do + before do + @category = FactoryGirl.create(:public_body_category) + I18n.with_locale('es') do + @category.title = 'Los category' + @category.save! + end + end + + render_views + + it "edits a public body category" do + get :edit, :id => @category.id + end + + it "edits a public body in another locale" do + get :edit, {:id => @category.id, :locale => :en} + + # When editing a body, the controller returns all available translations + assigns[:category].find_translation_by_locale("es").title.should == 'Los category' + response.should render_template('edit') + end + end + + context 'when updating a public body category' do + + before do + @heading = FactoryGirl.create(:public_body_heading) + @category = FactoryGirl.create(:public_body_category) + link = FactoryGirl.create(:public_body_category_link, + :public_body_category => @category, + :public_body_heading => @heading, + :category_display_order => 0) + @tag = @category.category_tag + I18n.with_locale('es') do + @category.title = 'Los category' + @category.save! + end + end + + render_views + + it "saves edits to a public body category" do + post :update, { :id => @category.id, + :public_body_category => { :title => "Renamed" } } + request.flash[:notice].should include('successful') + pbc = PublicBodyCategory.find(@category.id) + pbc.title.should == "Renamed" + end + + it "saves edits to a public body category's heading associations" do + @category.public_body_headings.should == [@heading] + heading = FactoryGirl.create(:public_body_heading) + post :update, { :id => @category.id, + :public_body_category => { :title => "Renamed" }, + :headings => {"heading_#{heading.id}" => heading.id} } + request.flash[:notice].should include('successful') + pbc = PublicBodyCategory.find(@category.id) + pbc.public_body_headings.should == [heading] + end + + it "saves edits to a public body category in another locale" do + I18n.with_locale(:es) do + @category.title.should == 'Los category' + post :update, { + :id => @category.id, + :public_body_category => { + :title => "Category", + :translated_versions => { + @category.id => {:locale => "es", + :title => "Renamed"} + } + } + } + request.flash[:notice].should include('successful') + end + + pbc = PublicBodyCategory.find(@category.id) + I18n.with_locale(:es) do + pbc.title.should == "Renamed" + end + I18n.with_locale(:en) do + pbc.title.should == "Category" + end + end + + it "does not save edits to category_tag if the category has associated bodies" do + body = FactoryGirl.create(:public_body, :tag_string => @tag) + post :update, { :id => @category.id, + :public_body_category => { :category_tag => "renamed" } } + request.flash[:notice].should include('can\'t') + pbc = PublicBodyCategory.find(@category.id) + pbc.category_tag.should == @tag + end + + + it "save edits to category_tag if the category has no associated bodies" do + category = PublicBodyCategory.create(:title => "Empty Category", :category_tag => "empty", :description => "-") + post :update, { :id => category.id, + :public_body_category => { :category_tag => "renamed" } } + request.flash[:notice].should include('success') + pbc = PublicBodyCategory.find(category.id) + pbc.category_tag.should == "renamed" + end + end + + context 'when destroying a public body category' do + + it "destroys a public body category" do + pbc = PublicBodyCategory.create(:title => "Empty Category", :category_tag => "empty", :description => "-") + n = PublicBodyCategory.count + post :destroy, { :id => pbc.id } + response.should redirect_to(admin_categories_path) + PublicBodyCategory.count.should == n - 1 + end + end + + +end diff --git a/spec/controllers/admin_public_body_headings_controller_spec.rb b/spec/controllers/admin_public_body_headings_controller_spec.rb new file mode 100644 index 000000000..31517d238 --- /dev/null +++ b/spec/controllers/admin_public_body_headings_controller_spec.rb @@ -0,0 +1,240 @@ +require 'spec_helper' + +describe AdminPublicBodyHeadingsController do + + context 'when showing the form for a new public body category' do + it 'should assign a new public body heading to the view' do + get :new + assigns[:heading].should be_a(PublicBodyHeading) + end + end + + context 'when creating a public body heading' do + it "creates a new public body heading in one locale" do + n = PublicBodyHeading.count + post :create, { + :public_body_heading => { + :name => 'New Heading' + } + } + PublicBodyHeading.count.should == n + 1 + + heading = PublicBodyHeading.find_by_name("New Heading") + response.should redirect_to(admin_categories_path) + end + + it 'creates a new public body heading with multiple locales' do + n = PublicBodyHeading.count + post :create, { + :public_body_heading => { + :name => 'New Heading', + :translated_versions => [{ :locale => "es", + :name => "Mi Nuevo Heading" }] + } + } + PublicBodyHeading.count.should == n + 1 + + heading = PublicBodyHeading.find_by_name("New Heading") + heading.translations.map {|t| t.locale.to_s}.sort.should == ["en", "es"] + I18n.with_locale(:en) do + heading.name.should == "New Heading" + end + I18n.with_locale(:es) do + heading.name.should == "Mi Nuevo Heading" + end + + response.should redirect_to(admin_categories_path) + end + end + + context 'when editing a public body heading' do + before do + @heading = FactoryGirl.create(:public_body_heading) + end + + render_views + + it "edits a public body heading" do + get :edit, :id => @heading.id + end + end + + context 'when updating a public body heading' do + before do + @heading = FactoryGirl.create(:public_body_heading) + @name = @heading.name + end + + it "saves edits to a public body heading" do + post :update, { :id => @heading.id, + :public_body_heading => { :name => "Renamed" } } + request.flash[:notice].should include('successful') + found_heading = PublicBodyHeading.find(@heading.id) + found_heading.name.should == "Renamed" + end + + it "saves edits to a public body heading in another locale" do + I18n.with_locale(:es) do + post :update, { + :id => @heading.id, + :public_body_heading => { + :name => @name, + :translated_versions => { + @heading.id => {:locale => "es", + :name => "Renamed"} + } + } + } + request.flash[:notice].should include('successful') + end + + heading = PublicBodyHeading.find(@heading.id) + I18n.with_locale(:es) do + heading.name.should == "Renamed" + end + I18n.with_locale(:en) do + heading.name.should == @name + end + end + end + + context 'when destroying a public body heading' do + + before do + @heading = FactoryGirl.create(:public_body_heading) + end + + it "does not destroy a public body heading that has associated categories" do + category = FactoryGirl.create(:public_body_category) + link = FactoryGirl.create(:public_body_category_link, + :public_body_category => category, + :public_body_heading => @heading, + :category_display_order => 0) + n = PublicBodyHeading.count + post :destroy, { :id => @heading.id } + response.should redirect_to(edit_admin_heading_path(@heading)) + PublicBodyHeading.count.should == n + end + + it "destroys an empty public body heading" do + n = PublicBodyHeading.count + post :destroy, { :id => @heading.id } + response.should redirect_to(admin_categories_path) + PublicBodyHeading.count.should == n - 1 + end + end + + context 'when reordering public body headings' do + + render_views + + before do + @first = FactoryGirl.create(:public_body_heading, :display_order => 0) + @second = FactoryGirl.create(:public_body_heading, :display_order => 1) + @default_params = { :headings => [@second.id, @first.id] } + end + + def make_request(params=@default_params) + post :reorder, params + end + + context 'when handling valid input' do + + it 'should reorder headings according to their position in the submitted params' do + make_request + PublicBodyHeading.find(@second.id).display_order.should == 0 + PublicBodyHeading.find(@first.id).display_order.should == 1 + end + + it 'should return a "success" status' do + make_request + response.should be_success + end + end + + context 'when handling invalid input' do + + before do + @params = { :headings => [@second.id, @first.id, @second.id + 1]} + end + + it 'should return an "unprocessable entity" status and an error message' do + make_request(@params) + assert_response :unprocessable_entity + response.body.should match("Couldn't find PublicBodyHeading with id") + end + + it 'should not reorder headings' do + make_request(@params) + PublicBodyHeading.find(@first.id).display_order.should == 0 + PublicBodyHeading.find(@second.id).display_order.should == 1 + end + + end + end + + context 'when reordering public body categories' do + + render_views + + before do + @heading = FactoryGirl.create(:public_body_heading) + @first_category = FactoryGirl.create(:public_body_category) + @first_link = FactoryGirl.create(:public_body_category_link, + :public_body_category => @first_category, + :public_body_heading => @heading, + :category_display_order => 0) + @second_category = FactoryGirl.create(:public_body_category) + @second_link = FactoryGirl.create(:public_body_category_link, + :public_body_category => @second_category, + :public_body_heading => @heading, + :category_display_order => 1) + @default_params = { :categories => [@second_category.id, @first_category.id], + :id => @heading } + @old_order = [@first_category, @second_category] + @new_order = [@second_category, @first_category] + end + + def make_request(params=@default_params) + post :reorder_categories, params + end + + context 'when handling valid input' do + + it 'should reorder categories for the heading according to their position \ + in the submitted params' do + + @heading.public_body_categories.should == @old_order + make_request + @heading.public_body_categories(reload=true).should == @new_order + end + + it 'should return a success status' do + make_request + response.should be_success + end + end + + context 'when handling invalid input' do + + before do + @new_category = FactoryGirl.create(:public_body_category) + @params = @default_params.merge(:categories => [@second_category.id, + @first_category.id, + @new_category.id]) + end + + it 'should return an "unprocessable entity" status and an error message' do + make_request(@params) + assert_response :unprocessable_entity + response.body.should match("Couldn't find PublicBodyCategoryLink") + end + + it 'should not reorder the categories for the heading' do + make_request(@params) + @heading.public_body_categories(reload=true).should == @old_order + end + end + + end +end diff --git a/spec/controllers/public_body_controller_spec.rb b/spec/controllers/public_body_controller_spec.rb index f64975580..fc7143522 100644 --- a/spec/controllers/public_body_controller_spec.rb +++ b/spec/controllers/public_body_controller_spec.rb @@ -7,6 +7,7 @@ describe PublicBodyController, "when showing a body" do render_views before(:each) do + PublicBodyCategory.stub!(:load_categories) load_raw_emails_data get_fixtures_xapian_index end @@ -75,6 +76,10 @@ end describe PublicBodyController, "when listing bodies" do render_views + before(:each) do + PublicBodyCategory.stub!(:load_categories) + end + it "should be successful" do get :list response.should be_success @@ -204,16 +209,19 @@ describe PublicBodyController, "when listing bodies" do end end - it "should list a tagged thing on the appropriate list page, and others on the other page, and all still on the all page" do - load_test_categories - - public_bodies(:humpadink_public_body).tag_string = "foo local_council" + it "should list a tagged thing on the appropriate list page, and others on the other page, + and all still on the all page" do + category = FactoryGirl.create(:public_body_category) + heading = FactoryGirl.create(:public_body_heading) + PublicBodyCategoryLink.create(:public_body_heading_id => heading.id, + :public_body_category_id => category.id) + public_bodies(:humpadink_public_body).tag_string = category.category_tag - get :list, :tag => "local_council" + get :list, :tag => category.category_tag response.should render_template('list') assigns[:public_bodies].should == [ public_bodies(:humpadink_public_body) ] - assigns[:tag].should == "local_council" - assigns[:description].should == "in the category ‘Local councils’" + assigns[:tag].should == category.category_tag + assigns[:description].should == "in the category ‘#{category.title}’" get :list, :tag => "other" response.should render_template('list') diff --git a/spec/factories/public_body_categories.rb b/spec/factories/public_body_categories.rb new file mode 100644 index 000000000..baa474c6b --- /dev/null +++ b/spec/factories/public_body_categories.rb @@ -0,0 +1,8 @@ + +FactoryGirl.define do + factory :public_body_category do + sequence(:title) { |n| "Example Public Body Category #{n}" } + sequence(:category_tag) { |n| "example_tag_#{n}" } + sequence(:description) { |n| "Example Public body Description #{n}" } + end +end diff --git a/spec/factories/public_body_category_links.rb b/spec/factories/public_body_category_links.rb new file mode 100644 index 000000000..7663b1f52 --- /dev/null +++ b/spec/factories/public_body_category_links.rb @@ -0,0 +1,6 @@ +FactoryGirl.define do + factory :public_body_category_link do + association :public_body_category + association :public_body_heading + end +end diff --git a/spec/factories/public_body_headings.rb b/spec/factories/public_body_headings.rb new file mode 100644 index 000000000..ed54ddada --- /dev/null +++ b/spec/factories/public_body_headings.rb @@ -0,0 +1,5 @@ +FactoryGirl.define do + factory :public_body_heading do + sequence(:name) { |n| "Example Public Body Heading #{n}" } + end +end diff --git a/spec/lib/public_body_categories_spec.rb b/spec/lib/public_body_categories_spec.rb deleted file mode 100644 index e53d9a028..000000000 --- a/spec/lib/public_body_categories_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') - -describe PublicBodyCategories do - - before do - load_test_categories - end - - describe 'when asked for categories with headings' do - - it 'should return a list of headings as plain strings, each followed by n tag specifications as - lists in the form: - ["tag_to_use_as_category", "Sub category title", "Instance description"]' do - expected_categories = ["Local and regional", ["local_council", - "Local councils", - "a local council"], - "Miscellaneous", ["other", - "Miscellaneous", - "miscellaneous"]] - PublicBodyCategories::get().with_headings().should == expected_categories - end - - end - - describe 'when asked for headings' do - - it 'should return a list of headings' do - PublicBodyCategories::get().headings().should == ['Local and regional', 'Miscellaneous'] - end - - end - - describe 'when asked for tags by headings' do - - it 'should return a hash of tags keyed by heading' do - PublicBodyCategories::get().by_heading().should == {'Local and regional' => ['local_council'], - 'Miscellaneous' => ['other']} - end - - end - -end
\ No newline at end of file diff --git a/spec/models/public_body_category/category_collection_spec.rb b/spec/models/public_body_category/category_collection_spec.rb new file mode 100644 index 000000000..1fbcbe739 --- /dev/null +++ b/spec/models/public_body_category/category_collection_spec.rb @@ -0,0 +1,81 @@ +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') + +describe PublicBodyCategory::CategoryCollection do + context "requesting data" do + + before do + data = [ "Local and regional", + [ "local_council", "Local councils", "a local council" ], + "Miscellaneous", + [ "other", "Miscellaneous", "miscellaneous" ] ] + @categories = PublicBodyCategory::CategoryCollection.new + data.each { |item| @categories << item } + end + + describe 'when asked for headings' do + + it 'should return a list of headings' do + @categories.headings().should == ['Local and regional', 'Miscellaneous'] + end + + end + + describe 'when asked for categories with headings' do + it 'should return a list of headings as plain strings, each followed by n tag specifications as + lists in the form: + ["tag_to_use_as_category", "Sub category title", "Instance description"]' do + expected_categories = ["Local and regional", ["local_council", + "Local councils", + "a local council"], + "Miscellaneous", ["other", + "Miscellaneous", + "miscellaneous"]] + @categories.with_headings().should == expected_categories + end + end + + + + describe 'when asked for tags by headings' do + it 'should return a hash of tags keyed by heading' do + @categories.by_heading().should == {'Local and regional' => ['local_council'], + 'Miscellaneous' => ['other']} + end + end + + describe 'when asked for categories with description' do + it 'should return a list of tag specifications as lists in the form: + ["tag_to_use_as_category", "Sub category title", "Instance description"]' do + expected_categories = [ + ["local_council", "Local councils", "a local council"], + ["other", "Miscellaneous", "miscellaneous"] + ] + @categories.with_description().should == expected_categories + end + end + + describe 'when asked for tags' do + it 'should return a list of tags' do + @categories.tags().should == ["local_council", "other"] + end + end + + describe 'when asked for categories by tag' do + it 'should return a hash of categories keyed by tag' do + @categories.by_tag().should == { + "local_council" => "Local councils", + "other" => "Miscellaneous" + } + end + end + + describe 'when asked for singular_by_tag' do + it 'should return a hash of category descriptions keyed by tag' do + @categories.singular_by_tag().should == { + "local_council" => "a local council", + "other" => "miscellaneous" + } + end + end + end +end diff --git a/spec/models/public_body_category_link_spec.rb b/spec/models/public_body_category_link_spec.rb new file mode 100644 index 000000000..8d91f02d5 --- /dev/null +++ b/spec/models/public_body_category_link_spec.rb @@ -0,0 +1,53 @@ +# == Schema Information +# +# Table name: public_body_category_link +# +# public_body_category_id :integer not null +# public_body_heading_id :integer not null +# category_display_order :integer +# + +require 'spec_helper' + +describe PublicBodyHeading, 'when validating' do + + it 'should set a default display order based on the next available display order' do + heading = FactoryGirl.create(:public_body_heading) + category = FactoryGirl.create(:public_body_category) + category_link = PublicBodyCategoryLink.new(:public_body_heading => heading, + :public_body_category => category) + category_link.valid? + category_link.category_display_order.should == PublicBodyCategoryLink.next_display_order(heading) + end + + it 'should be invalid without a category' do + category_link = PublicBodyCategoryLink.new + category_link.should_not be_valid + category_link.errors[:public_body_category].should == ["can't be blank"] + end + + it 'should be invalid without a heading' do + category_link = PublicBodyCategoryLink.new + category_link.should_not be_valid + category_link.errors[:public_body_heading].should == ["can't be blank"] + end + +end + +describe PublicBodyCategoryLink, 'when setting a category display order' do + + it 'should return 0 if there are no public body headings' do + heading = FactoryGirl.create(:public_body_heading) + PublicBodyCategoryLink.next_display_order(heading).should == 0 + end + + it 'should return one more than the highest display order if there are public body headings' do + heading = FactoryGirl.create(:public_body_heading) + category = FactoryGirl.create(:public_body_category) + category_link = PublicBodyCategoryLink.create(:public_body_heading_id => heading.id, + :public_body_category_id => category.id) + + PublicBodyCategoryLink.next_display_order(heading).should == 1 + end + +end diff --git a/spec/models/public_body_category_spec.rb b/spec/models/public_body_category_spec.rb new file mode 100644 index 000000000..2d39a7376 --- /dev/null +++ b/spec/models/public_body_category_spec.rb @@ -0,0 +1,65 @@ +# == Schema Information +# +# Table name: public_body_categories +# +# id :integer not null, primary key +# locale :string +# title :text not null +# category_tag :text not null +# description :text not null +# display_order :integer +# + +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe PublicBodyCategory do + describe 'when loading the data' do + it 'should use the display_order field to preserve the original data order' do + PublicBodyCategory.add(:en, [ + "Local and regional", + [ "local_council", "Local councils", "a local council" ], + "Miscellaneous", + [ "other", "Miscellaneous", "miscellaneous" ], + [ "aardvark", "Aardvark", "daft test"],]) + + headings = PublicBodyHeading.all + cat_group1 = headings[0].public_body_categories + cat_group1.count.should eq 1 + cat_group1[0].title.should eq "Local councils" + + cat_group2 = headings[1].public_body_categories + cat_group2.count.should eq 2 + cat_group2[0].title.should eq "Miscellaneous" + cat_group2[0].public_body_category_links.where( + :public_body_heading_id => headings[1].id). + first. + category_display_order.should eq 0 + + cat_group2[1].title.should eq "Aardvark" + cat_group2[1].public_body_category_links.where( + :public_body_heading_id => headings[1].id). + first. + category_display_order.should eq 1 + end + end + + context 'when validating' do + + it 'should require a title' do + category = PublicBodyCategory.new + category.should_not be_valid + category.errors[:title].should == ["Title can't be blank"] + end + + it 'should require a category tag' do + category = PublicBodyCategory.new + category.should_not be_valid + category.errors[:category_tag].should == ["Tag can't be blank"] + end + + it 'should require a unique tag' do + existing = FactoryGirl.create(:public_body_category) + PublicBodyCategory.new(:email => existing.category_tag).should_not be_valid + end + end +end diff --git a/spec/models/public_body_heading_spec.rb b/spec/models/public_body_heading_spec.rb new file mode 100644 index 000000000..add2cac60 --- /dev/null +++ b/spec/models/public_body_heading_spec.rb @@ -0,0 +1,68 @@ +# == Schema Information +# +# Table name: public_body_headings +# +# id :integer not null, primary key +# locale :string +# name :text not null +# display_order :integer +# + +require 'spec_helper' + +describe PublicBodyHeading do + + context 'when loading the data' do + + before do + PublicBodyCategory.add(:en, [ + "Local and regional", + [ "local_council", "Local councils", "a local council" ], + "Miscellaneous", + [ "other", "Miscellaneous", "miscellaneous" ],]) + end + + it 'should use the display_order field to preserve the original data order' do + headings = PublicBodyHeading.all + headings[0].name.should eq 'Local and regional' + headings[0].display_order.should eq 0 + headings[1].name.should eq 'Miscellaneous' + headings[1].display_order.should eq 1 + end + + end + + context 'when validating' do + + it 'should require a name' do + heading = PublicBodyHeading.new + heading.should_not be_valid + heading.errors[:name].should == ["Name can't be blank"] + end + + it 'should require a unique name' do + heading = FactoryGirl.create(:public_body_heading) + new_heading = PublicBodyHeading.new(:name => heading.name) + new_heading.should_not be_valid + new_heading.errors[:name].should == ["Name is already taken"] + end + + it 'should set a default display order based on the next available display order' do + heading = PublicBodyHeading.new + heading.valid? + heading.display_order.should == PublicBodyHeading.next_display_order + end + end + + context 'when setting a display order' do + + it 'should return 0 if there are no public body headings' do + PublicBodyHeading.next_display_order.should == 0 + end + + it 'should return one more than the highest display order if there are public body headings' do + heading = FactoryGirl.create(:public_body_heading) + PublicBodyHeading.next_display_order.should == 1 + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0e3fe35c7..74a4891c2 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -201,14 +201,6 @@ Spork.prefork do I18n.default_locale = original_default_locale end - def load_test_categories - PublicBodyCategories.add(:en, [ - "Local and regional", - [ "local_council", "Local councils", "a local council" ], - "Miscellaneous", - [ "other", "Miscellaneous", "miscellaneous" ],]) - end - def basic_auth_login(request, username = nil, password = nil) username = AlaveteliConfiguration::admin_username if username.nil? password = AlaveteliConfiguration::admin_password if password.nil? |