aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet')
-rw-r--r--perllib/FixMyStreet/App.pm123
-rw-r--r--perllib/FixMyStreet/App/Controller/About.pm31
-rw-r--r--perllib/FixMyStreet/App/Controller/Root.pm80
-rw-r--r--perllib/FixMyStreet/App/View/Web.pm45
-rw-r--r--perllib/FixMyStreet/Cobrand.pm71
-rw-r--r--perllib/FixMyStreet/Cobrand/Barnet.pm79
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm510
-rw-r--r--perllib/FixMyStreet/Cobrand/EmptyHomes.pm70
-rw-r--r--perllib/FixMyStreet/Cobrand/FiksGataMi.pm38
9 files changed, 1047 insertions, 0 deletions
diff --git a/perllib/FixMyStreet/App.pm b/perllib/FixMyStreet/App.pm
new file mode 100644
index 000000000..bc9bd7672
--- /dev/null
+++ b/perllib/FixMyStreet/App.pm
@@ -0,0 +1,123 @@
+package FixMyStreet::App;
+use Moose;
+use namespace::autoclean;
+
+use Catalyst::Runtime 5.80;
+use FixMyStreet;
+use FixMyStreet::Cobrand;
+use Memcached;
+use Problems;
+
+use Catalyst qw/
+ ConfigLoader
+ Static::Simple
+ /;
+
+extends 'Catalyst';
+
+our $VERSION = '0.01';
+
+# Configure the application.
+#
+# Note that settings in fixmystreet_app.conf (or other external
+# configuration file that you set up manually) take precedence
+# over this when using ConfigLoader. Thus configuration
+# details given here can function as a default configuration,
+# with an external configuration file acting as an override for
+# local deployment.
+
+__PACKAGE__->config(
+
+ # get the config from the core object
+ %{ FixMyStreet->config() },
+
+ name => 'FixMyStreet::App',
+
+ # Disable deprecated behavior needed by old applications
+ disable_component_resolution_regex_fallback => 1,
+
+ # Serve anything in web dir that is not a .cgi script
+ static => { #
+ include_path => [ FixMyStreet->path_to("web") . "" ],
+ ignore_extensions => ['cgi'],
+ }
+);
+
+# Start the application
+__PACKAGE__->setup();
+
+=head1 NAME
+
+FixMyStreet::App - Catalyst based application
+
+=head1 SYNOPSIS
+
+ script/fixmystreet_app_server.pl
+
+=head1 DESCRIPTION
+
+FixMyStreet.com codebase
+
+=head1 METHODS
+
+=head2 cobrand
+
+ $cobrand = $c->cobrand();
+
+Returns the cobrand object. If not already determined this request finds it and
+caches it to the stash.
+
+=cut
+
+sub cobrand {
+ my $c = shift;
+ return $c->stash->{cobrand} ||= $c->_get_cobrand();
+}
+
+sub _get_cobrand {
+ my $c = shift;
+ my $host = $c->req->uri->host;
+ my $cobrand_class = FixMyStreet::Cobrand->get_class_for_host($host);
+ return $cobrand_class->new( { request => $c->req } );
+}
+
+=head2 setup_cobrand
+
+ $cobrand = $c->setup_cobrand();
+
+Work out which cobrand we should be using. Set the environment correctly - eg
+template paths
+
+=cut
+
+sub setup_cobrand {
+ my $c = shift;
+ my $cobrand = $c->cobrand;
+
+ # append the cobrand templates to the include path
+ $c->stash->{additional_template_paths} =
+ [ $cobrand->path_to_web_templates . '' ];
+
+ my $host = $c->req->uri->host;
+ my $lang =
+ $host =~ /^en\./ ? 'en-gb'
+ : $host =~ /cy/ ? 'cy'
+ : undef;
+
+ # set the language and the translation file to use
+ $cobrand->set_lang_and_domain( $lang, 1 );
+
+ Problems::set_site_restriction_with_cobrand_object($cobrand);
+
+ Memcached::set_namespace( FixMyStreet->config('BCI_DB_NAME') . ":" );
+
+ return $cobrand;
+}
+
+=head1 SEE ALSO
+
+L<FixMyStreet::App::Controller::Root>, L<Catalyst>
+
+=cut
+
+1;
diff --git a/perllib/FixMyStreet/App/Controller/About.pm b/perllib/FixMyStreet/App/Controller/About.pm
new file mode 100644
index 000000000..42a0ed18e
--- /dev/null
+++ b/perllib/FixMyStreet/App/Controller/About.pm
@@ -0,0 +1,31 @@
+package FixMyStreet::App::Controller::About;
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Catalyst::Controller'; }
+
+=head1 NAME
+
+FixMyStreet::App::Controller::About - Catalyst Controller
+
+=head1 DESCRIPTION
+
+Catalyst Controller.
+
+=head1 METHODS
+
+=cut
+
+=head2 index
+
+=cut
+
+sub index : Path : Args(0) {
+ my ( $self, $c ) = @_;
+
+ # don't need to do anything here - should just pass through.
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
diff --git a/perllib/FixMyStreet/App/Controller/Root.pm b/perllib/FixMyStreet/App/Controller/Root.pm
new file mode 100644
index 000000000..42ac856c6
--- /dev/null
+++ b/perllib/FixMyStreet/App/Controller/Root.pm
@@ -0,0 +1,80 @@
+package FixMyStreet::App::Controller::Root;
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Catalyst::Controller' }
+
+__PACKAGE__->config( namespace => '' );
+
+=head1 NAME
+
+FixMyStreet::App::Controller::Root - Root Controller for FixMyStreet::App
+
+=head1 DESCRIPTION
+
+[enter your description here]
+
+=head1 METHODS
+
+=head2 auto
+
+Set up general things for this instance
+
+=cut
+
+sub auto : Private {
+ my ( $self, $c ) = @_;
+
+ # decide which cobrand this request should use
+ $c->setup_cobrand();
+
+ return 1;
+}
+
+=head2 index
+
+=cut
+
+sub index : Path : Args(0) {
+ my ( $self, $c ) = @_;
+ $c->res->body('index');
+}
+
+=head2 default
+
+Forward to the standard 404 error page
+
+=cut
+
+sub default : Path {
+ my ( $self, $c ) = @_;
+ $c->detach('/page_not_found');
+}
+
+=head2 page_not_found
+
+ $c->detach('/page_not_found');
+
+Display a 404 page.
+
+=cut
+
+sub page_not_found : Private {
+ my ( $self, $c ) = @_;
+
+ $c->stash->{template} = 'errors/page_not_found.html';
+ $c->response->status(404);
+}
+
+=head2 end
+
+Attempt to render a view, if needed.
+
+=cut
+
+sub end : ActionClass('RenderView') {
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
diff --git a/perllib/FixMyStreet/App/View/Web.pm b/perllib/FixMyStreet/App/View/Web.pm
new file mode 100644
index 000000000..306e4c5a7
--- /dev/null
+++ b/perllib/FixMyStreet/App/View/Web.pm
@@ -0,0 +1,45 @@
+package FixMyStreet::App::View::Web;
+use base 'Catalyst::View::TT';
+
+use strict;
+use warnings;
+
+use mySociety::Locale;
+use FixMyStreet;
+
+__PACKAGE__->config(
+ TEMPLATE_EXTENSION => '.html',
+ INCLUDE_PATH => [ #
+ FixMyStreet->path_to( 'templates', 'web', 'default' ),
+ ],
+ render_die => 1,
+ expose_methods => ['loc'],
+);
+
+=head1 NAME
+
+FixMyStreet::App::View::Web - TT View for FixMyStreet::App
+
+=head1 DESCRIPTION
+
+TT View for FixMyStreet::App.
+
+=cut
+
+=head2 loc
+
+ [% loc('Some text to localize') %]
+
+Passes the text to the localisation engine for translations.
+
+FIXME - currently just passes through.
+
+=cut
+
+sub loc {
+ my ( $self, $c, @args ) = @_;
+ return _(@args);
+}
+
+1;
+
diff --git a/perllib/FixMyStreet/Cobrand.pm b/perllib/FixMyStreet/Cobrand.pm
new file mode 100644
index 000000000..91155db6e
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand.pm
@@ -0,0 +1,71 @@
+# Copyright (c) 2009 UK Citizens Online Democracy. All rights reserved.
+# Email: evdb@mysociety.org. WWW: http://www.mysociety.org
+
+package FixMyStreet::Cobrand;
+
+use strict;
+use warnings;
+
+use FixMyStreet;
+use Carp;
+
+use Module::Pluggable
+ sub_name => '_cobrands',
+ search_path => ['FixMyStreet::Cobrand'],
+ require => 1;
+
+my @ALL_COBRAND_CLASSES = __PACKAGE__->_cobrands;
+
+=head2 get_allowed_cobrands
+
+Return an array reference of allowed cobrand subdomains
+
+=cut
+
+sub get_allowed_cobrands {
+ my $allowed_cobrand_string = FixMyStreet->config('ALLOWED_COBRANDS');
+ my @allowed_cobrands = split( /\|/, $allowed_cobrand_string );
+ return \@allowed_cobrands;
+}
+
+=head2 available_cobrand_classes
+
+ @available_cobrand_classes =
+ FixMyStreet::Cobrand->available_cobrand_classes();
+
+Return an array of all the classes that were found and that have monikers that
+match the values from get_allowed_cobrands.
+
+=cut
+
+sub available_cobrand_classes {
+ my $class = shift;
+
+ my %allowed = map { $_ => 1 } @{ $class->get_allowed_cobrands };
+ my @avail = grep { $allowed{ $_->moniker } } @ALL_COBRAND_CLASSES;
+
+ return @avail;
+}
+
+=head2 get_class_for_host
+
+ $cobrand_class = FixMyStreet::Cobrand->get_class_for_host( $host );
+
+Given a host determine which cobrand we should be using.
+
+=cut
+
+sub get_class_for_host {
+ my $class = shift;
+ my $host = shift;
+
+ foreach my $avail ( $class->available_cobrand_classes ) {
+ my $moniker = $avail->moniker;
+ return $avail if $host =~ m{$moniker};
+ }
+
+ # if none match then use the default
+ return 'FixMyStreet::Cobrand::Default';
+}
+
+1;
diff --git a/perllib/FixMyStreet/Cobrand/Barnet.pm b/perllib/FixMyStreet/Cobrand/Barnet.pm
new file mode 100644
index 000000000..7f8638c21
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/Barnet.pm
@@ -0,0 +1,79 @@
+package FixMyStreet::Cobrand::Barnet;
+use base 'FixMyStreet::Cobrand::Default';
+
+use strict;
+use warnings;
+
+use Carp;
+use URI::Escape;
+use mySociety::VotingArea;
+
+sub site_restriction {
+ return ( "and council='2489'", 'barnet' );
+}
+
+sub base_url {
+ my $base_url = mySociety::Config::get('BASE_URL');
+ if ( $base_url !~ /barnet/ ) {
+ $base_url =~ s{http://(?!www\.)}{http://barnet.}g;
+ $base_url =~ s{http://www\.}{http://barnet.}g;
+ }
+ return $base_url;
+}
+
+sub site_title {
+ my ($self) = @_;
+ return 'Barnet Council FixMyStreet';
+}
+
+sub enter_postcode_text {
+ my ( $self ) = @_;
+ return 'Enter a Barnet postcode, or street name and area:';
+}
+
+sub council_check {
+ my ( $self, $params, $q, $context ) = @_;
+ my $councils;
+ if ( $params->{all_councils} ) {
+ $councils = $params->{all_councils};
+ }
+ elsif ( defined $params->{lat} ) {
+ my $parent_types = $mySociety::VotingArea::council_parent_types;
+ $councils = mySociety::MaPit::call(
+ 'point',
+ "4326/$params->{lon},$params->{lat}",
+ type => $parent_types
+ );
+ }
+ my $council_match = defined $councils->{2489};
+ if ($council_match) {
+ return 1;
+ }
+ my $url = 'http://www.fixmystreet.com/';
+ $url .= 'alert' if $context eq 'alert';
+ $url .= '?pc=' . URI::Escape::uri_escape( $q->param('pc') )
+ if $q->param('pc');
+ my $error_msg = "That location is not covered by Barnet.
+Please visit <a href=\"$url\">the main FixMyStreet site</a>.";
+ return ( 0, $error_msg );
+}
+
+# All reports page only has the one council.
+sub all_councils_report {
+ return 0;
+}
+
+sub disambiguate_location {
+ my ( $self, $s, $q ) = @_;
+ $s = "ll=51.612832,-0.218169&spn=0.0563,0.09&$s";
+ return $s;
+}
+
+sub recent_photos {
+ my ( $self, $num, $lat, $lon, $dist ) = @_;
+ $num = 2 if $num == 3;
+ return Problems::recent_photos( $num, $lat, $lon, $dist );
+}
+
+1;
+
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
new file mode 100644
index 000000000..608a754f7
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -0,0 +1,510 @@
+package FixMyStreet::Cobrand::Default;
+
+use strict;
+use warnings;
+use FixMyStreet;
+
+use Carp;
+
+=head2 new
+
+ my $cobrand = $class->new;
+ my $cobrand = $class->new( { request => $c->req } );
+
+Create a new cobrand object, optionally setting the web request.
+
+You probably shouldn't need to do this and should get the cobrand object via a
+method in L<FixMyStreet::Cobrand> instead.
+
+=cut
+
+sub new {
+ my $class = shift;
+ my $self = shift || {};
+ return bless $self, $class;
+}
+
+=head2 moniker
+
+ $moniker = $cobrand_class->moniker();
+
+Returns a moniker that can be used to identify this cobrand. By default this is
+the last part of the class name lowercased - eg 'F::C::SomeCobrand' becomes
+'somecobrand'.
+
+=cut
+
+sub moniker {
+ my $class = ref( $_[0] ) || $_[0]; # deal with object or class
+ my ($last_part) = $class =~ m{::(\w+)$};
+ return lc($last_part);
+}
+
+=head2 q
+
+ $request = $cobrand->q;
+
+Often the cobrand needs access to the request so we add it at the start by
+passing it to ->new. If the request has not been set and you call this (or a
+method that needs it) then it croaks. This is probably because you are trying to
+use a request-related method out of a request-context.
+
+=cut
+
+sub q {
+ my $self = shift;
+ return $self->{request}
+ || croak "No request has been set"
+ . " - should you be calling this method outside of a web request?";
+}
+
+=head2 path_to_web_templates
+
+ $path = $cobrand->path_to_web_templates( );
+
+Returns the path to the templates for this cobrand - by default
+"templates/web/$moniker"
+
+=cut
+
+sub path_to_web_templates {
+ my $self = shift;
+ return FixMyStreet->path_to( 'templates/web', $self->moniker );
+}
+
+=head1 site_restriction
+
+Return a site restriction clause and a site key if the cobrand uses a subset of
+the FixMyStreet data. Parameter is any extra data the cobrand needs. Returns an
+empty string and site key 0 if the cobrand uses all the data.
+
+=cut
+
+sub site_restriction { return ( "", 0 ) }
+
+=head2 contact_restriction
+
+Return a contact restriction clause if the cobrand uses a subset of the
+FixMyStreet contact data.
+
+=cut
+
+sub contact_restriction {
+ '';
+}
+
+=head2 base_url_for_emails
+
+Return the base url to use in links in emails for the cobranded version of the
+site, parameter is extra data.
+
+=cut
+
+sub base_url_for_emails {
+ my $self = shift;
+ return $self->base_url;
+}
+
+=head2 admin_base_url
+
+Base URL for the admin interface.
+
+=cut
+
+sub admin_base_url { 0 }
+
+=head2 writetothem_url
+
+URL for writetothem; parameter is COBRAND_DATA.
+
+=cut
+
+sub writetothem_url { 0 }
+
+=head2 base_url
+
+Return the base url for the cobranded version of the site
+
+=cut
+
+sub base_url { mySociety::Config::get('BASE_URL') }
+
+=head2 enter_postcode_text
+
+Return the text that prompts the user to enter their postcode/place name.
+Parameter is QUERY
+
+=cut
+
+sub enter_postcode_text { '' }
+
+=head2 set_lang_and_domain
+
+ $cobrand->set_lang_and_domain( $lang, $unicode )
+
+Set the language and domain of the site based on the cobrand and host.
+
+=cut
+
+sub set_lang_and_domain {
+ my ( $self, $lang, $unicode ) = @_;
+ mySociety::Locale::negotiate_language(
+ 'en-gb,English,en_GB|nb,Norwegian,nb_NO', $lang ); # XXX Testing
+ mySociety::Locale::gettext_domain( 'FixMyStreet', $unicode );
+ mySociety::Locale::change();
+}
+
+=head2 alert_list_options
+
+Return HTML for a list of alert options for the cobrand, given QUERY and
+OPTIONS.
+
+=cut
+
+sub alert_list_options { 0 }
+
+=head2 recent_photos
+
+Return N recent photos. If EASTING, NORTHING and DISTANCE are supplied, the
+photos must be attached to problems within DISTANCE of the point defined by
+EASTING and NORTHING.
+
+=cut
+
+sub recent_photos {
+ my $self = shift;
+ return Problems::recent_photos(@_);
+}
+
+=head2 recent
+
+Return recent problems on the site.
+
+=cut
+
+sub recent {
+ my $self = shift;
+ return Problems::recent(@_);
+}
+
+=head2 front_stats
+
+Given a QUERY, return a block of html for showing front stats for the site
+
+=cut
+
+sub front_stats {
+ my $self = shift;
+ return Problems::front_stats(@_);
+}
+
+=head2 disambiguate_location
+
+Given a STRING ($_[1]) representing a location and a QUERY, return a string that
+includes any disambiguating information available
+
+=cut
+
+sub disambiguate_location { "$_[1]&gl=uk" }
+
+=head2 prettify_epoch
+
+Parameter is EPOCHTIME
+
+=cut
+
+sub prettify_epoch { 0 }
+
+=head2 form_elements
+
+Parameters are FORM_NAME, QUERY. Return HTML for any extra needed elements for
+FORM_NAME
+
+=cut
+
+sub form_elements { '' }
+
+=head2 cobrand_data_for_generic_update
+
+Parameter is UPDATE_DATA, a reference to a hash of non-cobranded update data.
+Return cobrand extra data for the update
+
+=cut
+
+sub cobrand_data_for_generic_update { '' }
+
+=head2 cobrand_data_for_generic_update
+
+Parameter is PROBLEM_DATA, a reference to a hash of non-cobranded problem data.
+Return cobrand extra data for the problem
+
+=cut
+
+sub cobrand_data_for_generic_problem { '' }
+
+=head2 extra_problem_data
+
+Parameter is QUERY. Return a string of extra data to be stored with a problem
+
+=cut
+
+sub extra_problem_data { '' }
+
+=head2 extra_update_data
+
+Parameter is QUERY. Return a string of extra data to be stored with an update
+
+=cut
+
+sub extra_update_data { '' }
+
+=head2 extra_alert_data
+
+Parameter is QUERY. Return a string of extra data to be stored with an alert
+
+=cut
+
+sub extra_alert_data { '' }
+
+=head2 extra_data
+
+Given a QUERY, extract any extra data required by the cobrand
+
+=cut
+
+sub extra_data { '' }
+
+=head2 extra_params
+
+Given a QUERY, return a hash of extra params to be included in any URLs in links
+produced on the page returned by that query.
+
+=cut
+
+sub extra_params { '' }
+
+=head2 extra_problem_meta_text
+
+Returns any extra text to be displayed with a PROBLEM.
+
+=cut
+
+sub extra_problem_meta_text { '' }
+
+=head2 extra_update_meta_text
+
+Returns any extra text to be displayed with an UPDATE.
+
+=cut
+
+sub extra_update_meta_text { '' }
+
+=head2 url
+
+Given a URL ($_[1]), QUERY, EXTRA_DATA, return a URL with any extra params
+needed appended to it.
+
+=cut
+
+sub url { $_[1] }
+
+=head2 header_params
+
+Return any params to be added to responses
+
+=cut
+
+sub header_params { return {} }
+
+=head2 root_path_js
+
+Parameter is QUERY. Return some js to set the root path from which AJAX queries
+should be made.
+
+=cut
+
+sub root_path_js { 'var root_path = "";' }
+
+=head2 site_title
+
+Return the title to be used in page heads.
+
+=cut
+
+sub site_title { '' }
+
+=head2 on_map_list_limit
+
+Return the maximum number of items to be given in the list of reports on the map
+
+=cut
+
+sub on_map_list_limit { return undef; }
+
+=head2 allow_photo_upload
+
+Return a boolean indicating whether the cobrand allows photo uploads
+
+=cut
+
+sub allow_photo_upload { return 1; }
+
+=head2 allow_crosssell_adverts
+
+Return a boolean indicating whether the cobrand allows the display of crosssell
+adverts
+
+=cut
+
+sub allow_crosssell_adverts { return 1; }
+
+=head2 allow_photo_display
+
+Return a boolean indicating whether the cobrand allows photo display
+
+=cut
+
+sub allow_photo_display { return 1; }
+
+=head2 allow_update_reporting
+
+Return a boolean indication whether users should see links next to updates
+allowing them to report them as offensive.
+
+=cut
+
+sub allow_update_reporting { return 0; }
+
+=head2 geocoded_string_check
+
+Parameters are LOCATION, QUERY. Return a boolean indicating whether the
+string LOCATION passes the cobrands checks.
+
+=cut
+
+sub geocoded_string_check { return 1; }
+
+=head2 council_check
+
+Paramters are COUNCILS, QUERY, CONTEXT. Return a boolean indicating whether
+COUNCILS pass any extra checks. CONTEXT is where we are on the site.
+
+=cut
+
+sub council_check { return ( 1, '' ); }
+
+=head2 feed_xsl
+
+Return an XSL to be used in rendering feeds
+
+=cut
+
+sub feed_xsl { '/xsl.xsl' }
+
+=head2 all_councils_report
+
+Return a boolean indicating whether the cobrand displays a report of all
+councils
+
+=cut
+
+sub all_councils_report { 1 }
+
+=head2 ask_ever_reported
+
+Return a boolean indicating whether people should be asked whether this is the
+first time they' ve reported a problem
+
+=cut
+
+sub ask_ever_reported { 1 }
+
+=head2 admin_pages
+
+List of names of pages to display on the admin interface
+
+=cut
+
+sub admin_pages { 0 }
+
+=head2 admin_show_creation_graph
+
+Show the problem creation graph in the admin interface
+=cut
+
+sub admin_show_creation_graph { 1 }
+
+=head2 area_types, area_min_generation
+
+The MaPit types this site handles
+
+=cut
+
+sub area_types { return qw(DIS LBO MTD UTA CTY COI); }
+sub area_min_generation { 10 }
+
+=head2 contact_name, contact_email
+
+Return the contact name or email for the cobranded version of the site (to be
+used in emails).
+
+=cut
+
+sub contact_name { $_[0]->get_cobrand_conf('CONTACT_NAME') }
+sub contact_email { $_[0]->get_cobrand_conf('CONTACT_EMAIL') }
+
+=head2 get_cobrand_conf COBRAND KEY
+
+Get the value for KEY from the config file for COBRAND
+
+=cut
+
+sub get_cobrand_conf {
+ my ( $self, $key ) = @_;
+ my $value = undef;
+ my $cobrand_moniker = $self->moniker;
+
+ my $cobrand_config_file =
+ FixMyStreet->path_to("conf/cobrands/$cobrand_moniker/general");
+ my $normal_config_file = FixMyStreet->path_to('conf/general');
+
+ if ( -e $cobrand_config_file ) {
+
+ # FIXME - don't rely on the config file name - should
+ # change mySociety::Config so that it can return values from a
+ # particular config file instead
+ mySociety::Config::set_file("$cobrand_config_file");
+ my $config_key = $key . "_" . uc($cobrand_moniker);
+ $value = mySociety::Config::get( $config_key, undef );
+ mySociety::Config::set_file("$normal_config_file");
+ }
+
+ # If we didn't find a value use one from normal config
+ if ( !defined($value) ) {
+ $value = mySociety::Config::get($key);
+ }
+
+ return $value;
+}
+
+=item email_host
+
+Return if we are the virtual host that sends email for this cobrand
+
+=cut
+
+sub email_host {
+ my $self = shift;
+ my $cobrand_moniker_uc = uc( $self->moniker );
+
+ my $email_vhost =
+ mySociety::Config::get("EMAIL_VHOST_$cobrand_moniker_uc")
+ || mySociety::Config::get("EMAIL_VHOST")
+ || '';
+
+ return $email_vhost
+ && "http://$email_vhost" eq mySociety::Config::get("BASE_URL");
+}
+
+1;
+
diff --git a/perllib/FixMyStreet/Cobrand/EmptyHomes.pm b/perllib/FixMyStreet/Cobrand/EmptyHomes.pm
new file mode 100644
index 000000000..6b907cbd0
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/EmptyHomes.pm
@@ -0,0 +1,70 @@
+package FixMyStreet::Cobrand::EmptyHomes;
+use base 'FixMyStreet::Cobrand::Default';
+
+use strict;
+use warnings;
+
+use FixMyStreet;
+use mySociety::Locale;
+use Carp;
+
+=item
+
+Return the base url for this cobranded site
+
+=cut
+
+sub base_url {
+ my $base_url = FixMyStreet->config('BASE_URL');
+ if ( $base_url !~ /emptyhomes/ ) {
+ $base_url =~ s/http:\/\//http:\/\/emptyhomes\./g;
+ }
+ return $base_url;
+}
+
+sub admin_base_url {
+ return 'https://secure.mysociety.org/admin/emptyhomes/';
+}
+
+sub area_types {
+ return qw(DIS LBO MTD UTA LGD COI); # No CTY
+}
+
+=item set_lang_and_domain LANG UNICODE
+
+Set the language and text domain for the site based on the query and host.
+
+=cut
+
+sub set_lang_and_domain {
+ my ( $self, $lang, $unicode ) = @_;
+ mySociety::Locale::negotiate_language(
+ 'en-gb,English,en_GB|cy,Cymraeg,cy_GB', $lang );
+ mySociety::Locale::gettext_domain( 'FixMyStreet-EmptyHomes', $unicode );
+ mySociety::Locale::change();
+}
+
+=item site_title
+
+Return the title to be used in page heads
+
+=cut
+
+sub site_title {
+ my ($self) = @_;
+ return _('Report Empty Homes');
+}
+
+=item feed_xsl
+
+Return the XSL file path to be used for feeds'
+
+=cut
+
+sub feed_xsl {
+ my ($self) = @_;
+ return '/xsl.eha.xsl';
+}
+
+1;
+
diff --git a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
new file mode 100644
index 000000000..25a4ad83c
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
@@ -0,0 +1,38 @@
+package FixMyStreet::Cobrand::FiksGataMi;
+use base 'FixMyStreet::Cobrand::Default';
+
+use strict;
+use warnings;
+
+use Carp;
+
+sub set_lang_and_domain {
+ my ( $self, $lang, $unicode ) = @_;
+ mySociety::Locale::negotiate_language(
+ 'en-gb,English,en_GB|nb,Norwegian,nb_NO', 'nb' );
+ mySociety::Locale::gettext_domain( 'FixMyStreet', $unicode );
+ mySociety::Locale::change();
+}
+
+sub enter_postcode_text {
+ my ( $self, $q ) = @_;
+ return _('Enter a nearby postcode, or street name and area:');
+}
+
+# Is also adding language parameter
+sub disambiguate_location {
+ my ( $self, $s, $q ) = @_;
+ $s = "hl=no&gl=no&$s";
+ return $s;
+}
+
+sub area_types {
+ return ( 'NKO', 'NFY' );
+}
+
+sub area_min_generation {
+ return '';
+}
+
+1;
+