aboutsummaryrefslogtreecommitdiffstats
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/info_request.rb9
-rw-r--r--app/models/public_body.rb287
-rw-r--r--app/models/public_body_category.rb65
-rw-r--r--app/models/public_body_heading.rb43
-rw-r--r--app/models/track_thing.rb3
-rw-r--r--app/models/user.rb12
6 files changed, 219 insertions, 200 deletions
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index 8d455e488..fd42ccd9c 100644
--- a/app/models/info_request.rb
+++ b/app/models/info_request.rb
@@ -187,11 +187,9 @@ class InfoRequest < ActiveRecord::Base
@@custom_states_loaded = false
begin
- if !Rails.env.test?
- require 'customstates'
- include InfoRequestCustomStates
- @@custom_states_loaded = true
- end
+ require 'customstates'
+ include InfoRequestCustomStates
+ @@custom_states_loaded = true
rescue MissingSourceFile, NameError
end
@@ -748,7 +746,6 @@ public
# This is a long stop - even with UK public interest test extensions, 40
# days is a very long time.
def date_very_overdue_after
- last_sent = last_event_forming_initial_request
if self.public_body.is_school?
# schools have 60 working days maximum (even over a long holiday)
Holiday.due_date_from(self.date_initial_request_last_sent_at, AlaveteliConfiguration::special_reply_very_late_after_days, AlaveteliConfiguration::working_or_calendar_days)
diff --git a/app/models/public_body.rb b/app/models/public_body.rb
index a9cdfeab2..232c0ffa1 100644
--- a/app/models/public_body.rb
+++ b/app/models/public_body.rb
@@ -64,6 +64,7 @@ class PublicBody < ActiveRecord::Base
}
translates :name, :short_name, :request_email, :url_name, :notes, :first_letter, :publication_scheme
+ accepts_nested_attributes_for :translations, :reject_if => :empty_translation_in_params?
# Default fields available for importing from CSV, in the format
# [field_name, 'short description of field (basic html allowed)']
@@ -151,30 +152,24 @@ class PublicBody < ActiveRecord::Base
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
+ def ordered_translations
+ translations.
+ select { |t| I18n.available_locales.include?(t.locale) }.
+ sort_by { |t| I18n.available_locales.index(t.locale) }
+ 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]) || PublicBody::Translation.new
- t.attributes = attrs
- calculate_cached_fields(t)
- t.save!
- end
- else # Array => creating
- translation_attrs.each do |attrs|
- next if empty_translation?(attrs)
- new_translation = PublicBody::Translation.new(attrs)
- calculate_cached_fields(new_translation)
- translations << new_translation
- end
+ def build_all_translations
+ I18n.available_locales.each do |locale|
+ translations.build(:locale => locale) unless translations.detect{ |t| t.locale == locale }
end
end
+ def translated_versions=(translation_attrs)
+ warn "[DEPRECATION] PublicBody#translated_versions= will be replaced " \
+ "by PublicBody#translations_attributes= as of release 0.22"
+ self.translations_attributes = translation_attrs
+ end
+
def set_default_publication_scheme
# Make sure publication_scheme gets the correct default value.
# (This would work automatically, were publication_scheme not a translated attribute)
@@ -222,39 +217,38 @@ class PublicBody < ActiveRecord::Base
return self.has_tag?('defunct')
end
- # Can an FOI (etc.) request be made to this body, and if not why not?
+ # Can an FOI (etc.) request be made to this body?
def is_requestable?
- if self.defunct?
- return false
- end
- if self.not_apply?
- return false
- end
- if self.request_email.nil?
- return false
- end
- return !self.request_email.empty? && self.request_email != 'blank'
+ has_request_email? && !defunct? && !not_apply?
end
+
# Strict superset of is_requestable?
def is_followupable?
- if self.request_email.nil?
- return false
- end
- return !self.request_email.empty? && self.request_email != 'blank'
+ has_request_email?
end
+
+ def has_request_email?
+ !request_email.blank? && request_email != 'blank'
+ end
+
# Also used as not_followable_reason
def not_requestable_reason
if self.defunct?
return 'defunct'
elsif self.not_apply?
return 'not_apply'
- elsif self.request_email.nil? or self.request_email.empty? or self.request_email == 'blank'
+ elsif !has_request_email?
return 'bad_contact'
else
- raise "requestable_failure_reason called with type that has no reason"
+ raise "not_requestable_reason called with type that has no reason"
end
end
+ def special_not_requestable_reason?
+ self.defunct? || self.not_apply?
+ end
+
+
class Version
def last_edit_comment_for_html_display
@@ -333,39 +327,6 @@ class PublicBody < ActiveRecord::Base
end
end
-
- # Use tags to describe what type of thing this is
- def type_of_authority(html = false)
- types = []
- first = true
- for tag in self.tags
- 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)
- desc = desc[0,1].capitalize + desc[1,desc.size]
- first = false
- end
- if html
- # TODO: this should call proper route helpers, but is in model sigh
- desc = '<a href="/body/list/' + tag.name + '">' + desc + '</a>'
- end
- types.push(desc)
- end
- end
- if types.size > 0
- ret = types[0, types.size - 1].join(", ")
- if types.size > 1
- ret = ret + " and "
- end
- ret = ret + types[-1]
- return ret.html_safe
- else
- return _("A public authority")
- end
- end
-
# Guess home page from the request email, or use explicit override, or nil
# if not known.
def calculated_home_page
@@ -445,8 +406,6 @@ class PublicBody < ActiveRecord::Base
def self.import_csv_from_file(csv_filename, tag, tag_behaviour, dry_run, editor, available_locales = [])
errors = []
notes = []
- available_locales = [I18n.default_locale] if available_locales.empty?
-
begin
ActiveRecord::Base.transaction do
# Use the default locale when retrieving existing bodies; otherwise
@@ -467,9 +426,18 @@ class PublicBody < ActiveRecord::Base
end
set_of_importing = Set.new()
- field_names = { 'name'=>1, 'request_email'=>2 } # Default values in case no field list is given
+ # Default values in case no field list is given
+ field_names = { 'name' => 1, 'request_email' => 2 }
line = 0
+ import_options = {:field_names => field_names,
+ :available_locales => available_locales,
+ :tag => tag,
+ :tag_behaviour => tag_behaviour,
+ :editor => editor,
+ :notes => notes,
+ :errors => errors }
+
CSV.foreach(csv_filename) do |row|
line = line + 1
@@ -481,7 +449,7 @@ class PublicBody < ActiveRecord::Base
end
fields = {}
- field_names.each{|name, i| fields[name] = row[i]}
+ field_names.each{ |name, i| fields[name] = row[i] }
yield line, fields if block_given?
@@ -497,83 +465,11 @@ class PublicBody < ActiveRecord::Base
next
end
- field_list = []
- self.csv_import_fields.each do |field_name, field_notes|
- field_list.push field_name
- end
-
- if public_body = bodies_by_name[name] # Existing public body
- available_locales.each do |locale|
- I18n.with_locale(locale) do
- changed = ActiveSupport::OrderedHash.new
- field_list.each do |field_name|
- localized_field_name = (locale.to_s == I18n.default_locale.to_s) ? field_name : "#{field_name}.#{locale}"
- localized_value = field_names[localized_field_name] && row[field_names[localized_field_name]]
-
- # Tags are a special case, as we support adding to the field, not just setting a new value
- if localized_field_name == 'tag_string'
- if localized_value.nil?
- localized_value = tag unless tag.empty?
- else
- if tag_behaviour == 'add'
- localized_value = "#{localized_value} #{tag}" unless tag.empty?
- localized_value = "#{localized_value} #{public_body.tag_string}"
- end
- end
- end
-
- if !localized_value.nil? and public_body.send(field_name) != localized_value
- changed[field_name] = "#{public_body.send(field_name)}: #{localized_value}"
- public_body.send("#{field_name}=", localized_value)
- end
- end
-
- unless changed.empty?
- notes.push "line #{line.to_s}: updating authority '#{name}' (locale: #{locale}):\n\t#{changed.to_json}"
- public_body.last_edit_editor = editor
- public_body.last_edit_comment = 'Updated from spreadsheet'
- public_body.save!
- end
- end
- end
- else # New public body
- public_body = PublicBody.new(:name=>"", :short_name=>"", :request_email=>"")
- available_locales.each do |locale|
- I18n.with_locale(locale) do
- changed = ActiveSupport::OrderedHash.new
- field_list.each do |field_name|
- localized_field_name = (locale.to_s == I18n.default_locale.to_s) ? field_name : "#{field_name}.#{locale}"
- localized_value = field_names[localized_field_name] && row[field_names[localized_field_name]]
-
- if localized_field_name == 'tag_string' and tag_behaviour == 'add'
- localized_value = "#{localized_value} #{tag}" unless tag.empty?
- end
-
- if !localized_value.nil? and public_body.send(field_name) != localized_value
- changed[field_name] = localized_value
- public_body.send("#{field_name}=", localized_value)
- end
- end
-
- unless changed.empty?
- notes.push "line #{line.to_s}: creating new authority '#{name}' (locale: #{locale}):\n\t#{changed.to_json}"
- public_body.publication_scheme = public_body.publication_scheme || ""
- public_body.last_edit_editor = editor
- public_body.last_edit_comment = 'Created from spreadsheet'
-
- begin
- public_body.save!
- rescue ActiveRecord::RecordInvalid
- public_body.errors.full_messages.each do |msg|
- errors.push "error: line #{ line }: #{ msg } for authority '#{ name }'"
- end
- next
- end
- end
- end
- end
- end
+ public_body = bodies_by_name[name] || PublicBody.new(:name => "",
+ :short_name => "",
+ :request_email => "")
+ public_body.import_values_from_csv_row(row, line, name, import_options)
set_of_importing.add(name)
end
@@ -595,6 +491,77 @@ class PublicBody < ActiveRecord::Base
return [errors, notes]
end
+ def self.localized_csv_field_name(locale, field_name)
+ (locale.to_s == I18n.default_locale.to_s) ? field_name : "#{field_name}.#{locale}"
+ end
+
+
+ # import values from a csv row (that may include localized columns)
+ def import_values_from_csv_row(row, line, name, options)
+ is_new = new_record?
+ edit_info = if is_new
+ { :action => "creating new authority",
+ :comment => 'Created from spreadsheet' }
+ else
+ { :action => "updating authority",
+ :comment => 'Updated from spreadsheet' }
+ end
+ locales = options[:available_locales]
+ locales = [I18n.default_locale] if locales.empty?
+ locales.each do |locale|
+ I18n.with_locale(locale) do
+ changed = set_locale_fields_from_csv_row(is_new, locale, row, options)
+ unless changed.empty?
+ options[:notes].push "line #{ line }: #{ edit_info[:action] } '#{ name }' (locale: #{ locale }):\n\t#{ changed.to_json }"
+ self.last_edit_comment = edit_info[:comment]
+ self.publication_scheme = publication_scheme || ""
+ self.last_edit_editor = options[:editor]
+
+ begin
+ save!
+ rescue ActiveRecord::RecordInvalid
+ errors.full_messages.each do |msg|
+ options[:errors].push "error: line #{ line }: #{ msg } for authority '#{ name }'"
+ end
+ next
+ end
+ end
+ end
+ end
+ end
+
+ # Sets attribute values for a locale from a csv row
+ def set_locale_fields_from_csv_row(is_new, locale, row, options)
+ changed = ActiveSupport::OrderedHash.new
+ csv_field_names = options[:field_names]
+ csv_import_fields.each do |field_name, field_notes|
+ localized_field_name = self.class.localized_csv_field_name(locale, field_name)
+ column = csv_field_names[localized_field_name]
+ value = column && row[column]
+ # Tags are a special case, as we support adding to the field, not just setting a new value
+ if field_name == 'tag_string'
+ new_tags = [value, options[:tag]].select{ |new_tag| !new_tag.blank? }
+ if new_tags.empty?
+ value = nil
+ else
+ value = new_tags.join(" ")
+ value = "#{value} #{tag_string}"if options[:tag_behaviour] == 'add'
+ end
+
+ end
+
+ if value and read_attribute_value(field_name, locale) != value
+ if is_new
+ changed[field_name] = value
+ else
+ changed[field_name] = "#{read_attribute_value(field_name, locale)}: #{value}"
+ end
+ assign_attributes({ field_name => value })
+ end
+ end
+ changed
+ end
+
# Does this user have the power of FOI officer for this body?
def is_foi_officer?(user)
user_domain = user.email_domain
@@ -793,6 +760,26 @@ class PublicBody < ActiveRecord::Base
private
+ # Read an attribute value (without using locale fallbacks if the attribute is translated)
+ def read_attribute_value(name, locale)
+ if self.class.translates.include?(name.to_sym)
+ if globalize.stash.contains?(locale, name)
+ globalize.stash.read(locale, name)
+ else
+ translation_for(locale).send(name)
+ end
+ else
+ send(name)
+ end
+ end
+
+ def empty_translation_in_params?(attributes)
+ attrs_with_values = attributes.select do |key, value|
+ value != '' and key.to_s != 'locale'
+ end
+ attrs_with_values.empty?
+ end
+
def request_email_if_requestable
# Request_email can be blank, meaning we don't have details
if self.is_requestable?
diff --git a/app/models/public_body_category.rb b/app/models/public_body_category.rb
index c313e5734..eeb2511fa 100644
--- a/app/models/public_body_category.rb
+++ b/app/models/public_body_category.rb
@@ -10,12 +10,15 @@ require 'forwardable'
class PublicBodyCategory < ActiveRecord::Base
attr_accessible :locale, :category_tag, :title, :description,
- :translated_versions, :display_order
+ :translated_versions, :translations_attributes,
+ :display_order
has_many :public_body_category_links, :dependent => :destroy
has_many :public_body_headings, :through => :public_body_category_links
translates :title, :description
+ accepts_nested_attributes_for :translations, :reject_if => :empty_translation_in_params?
+
validates_uniqueness_of :category_tag, :message => 'Tag is already taken'
validates_presence_of :title, :message => "Title can't be blank"
validates_presence_of :category_tag, :message => "Tag can't be blank"
@@ -49,11 +52,6 @@ class PublicBodyCategory < ActiveRecord::Base
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)
@@ -64,25 +62,48 @@ class PublicBodyCategory < ActiveRecord::Base
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?
+ warn "[DEPRECATION] PublicBodyCategory#translated_versions= will be replaced " \
+ "by PublicBodyCategory#translations_attributes= as of release 0.22"
+ self.translations_attributes = translation_attrs
+ end
+
+ def ordered_translations
+ translations.
+ select { |t| I18n.available_locales.include?(t.locale) }.
+ sort_by { |t| I18n.available_locales.index(t.locale) }
+ end
+
+ def build_all_translations
+ I18n.available_locales.each do |locale|
+ translations.build(:locale => locale) unless translations.detect{ |t| t.locale == locale }
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
+
+ private
+
+ def empty_translation_in_params?(attributes)
+ attrs_with_values = attributes.select do |key, value|
+ value != '' and key.to_s != 'locale'
end
+ attrs_with_values.empty?
end
+
end
+PublicBodyCategory::Translation.class_eval do
+ with_options :if => lambda { |t| !t.default_locale? && t.required_attribute_submitted? } do |required|
+ required.validates :title, :presence => { :message => _("Title can't be blank") }
+ required.validates :description, :presence => { :message => _("Description can't be blank") }
+ end
+ def default_locale?
+ locale == I18n.default_locale
+ end
+
+ def required_attribute_submitted?
+ PublicBodyCategory.required_translated_attributes.compact.any? do |attribute|
+ !read_attribute(attribute).blank?
+ end
+ end
+
+end
diff --git a/app/models/public_body_heading.rb b/app/models/public_body_heading.rb
index f394c37c6..8c160ba8b 100644
--- a/app/models/public_body_heading.rb
+++ b/app/models/public_body_heading.rb
@@ -7,13 +7,15 @@
#
class PublicBodyHeading < ActiveRecord::Base
- attr_accessible :name, :display_order, :translated_versions
+ attr_accessible :locale, :name, :display_order, :translated_versions,
+ :translations_attributes
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
+ accepts_nested_attributes_for :translations, :reject_if => :empty_translation_in_params?
validates_uniqueness_of :name, :message => 'Name is already taken'
validates_presence_of :name, :message => 'Name can\'t be blank'
@@ -36,24 +38,20 @@ class PublicBodyHeading < ActiveRecord::Base
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
+ warn "[DEPRECATION] PublicBodyHeading#translated_versions= will be replaced " \
+ "by PublicBodyHeading#translations_attributes= as of release 0.22"
+ self.translations_attributes = translation_attrs
+ end
+
+ def ordered_translations
+ translations.
+ select { |t| I18n.available_locales.include?(t.locale) }.
+ sort_by { |t| I18n.available_locales.index(t.locale) }
+ 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
+ def build_all_translations
+ I18n.available_locales.each do |locale|
+ translations.build(:locale => locale) unless translations.detect{ |t| t.locale == locale }
end
end
@@ -71,4 +69,13 @@ class PublicBodyHeading < ActiveRecord::Base
end
end
+ private
+
+ def empty_translation_in_params?(attributes)
+ attrs_with_values = attributes.select do |key, value|
+ value != '' and key.to_s != 'locale'
+ end
+ attrs_with_values.empty?
+ end
+
end
diff --git a/app/models/track_thing.rb b/app/models/track_thing.rb
index 5819876ff..cd90c4a9e 100644
--- a/app/models/track_thing.rb
+++ b/app/models/track_thing.rb
@@ -231,8 +231,7 @@ class TrackThing < ActiveRecord::Base
{ # Website
:verb_on_page => _("Follow requests to {{public_body_name}}",
:public_body_name => public_body.name),
- :verb_on_page_already => _("You are already following requests to {{public_body_name}}",
- :public_body_name => public_body.name),
+ :verb_on_page_already => _("Following"),
# Email
:title_in_email => _("{{foi_law}} requests to '{{public_body_name}}'",
:foi_law => public_body.law_only_short,
diff --git a/app/models/user.rb b/app/models/user.rb
index c953e52f2..920c0da46 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -207,7 +207,7 @@ class User < ActiveRecord::Base
if not name.nil?
name.strip!
end
- if public_banned?
+ if banned?
# Use interpolation to return a string rather than a SafeBuffer so that
# gsub can be called on it until we upgrade to Rails 3.2. The name returned
# is not marked as HTML safe so will be escaped automatically in views. We
@@ -294,10 +294,18 @@ class User < ActiveRecord::Base
def admin_page_links?
super?
end
+
# Is it public that they are banned?
+ def banned?
+ !ban_text.empty?
+ end
+
def public_banned?
- !ban_text.empty?
+ warn %q([DEPRECATION] User#public_banned? will be replaced with
+ User#banned? as of 0.22).squish
+ banned?
end
+
# Various ways the user can be banned, and text to describe it if failed
def can_file_requests?
ban_text.empty? && !exceeded_limit?