diff --git a/app/api/route/thread_api.rb b/app/api/route/thread_api.rb
index d0ad91365..a64e0c0d3 100644
--- a/app/api/route/thread_api.rb
+++ b/app/api/route/thread_api.rb
@@ -12,6 +12,7 @@ class ThreadApi < Base
optional :end_date, types: [DateTime, Date], desc: 'Only threads after or at the end date or time are returned'
optional :start_date, types: [DateTime, Date], desc: 'Only threads before or at the start date or time are returned'
optional :after_id, types: Integer, desc: 'Only threads with ID greather than this are returned'
+ optional :external_service, type: String, desc: 'Filter by external service short name'
end
helpers do
@@ -27,6 +28,7 @@ def post_or_get_thread
scope = scope.before_date(params[:end_date]) if params[:end_date]
scope = scope.after_date(params[:start_date]) if params[:start_date]
scope = scope.after_id(params[:after_id]) if params[:after_id]
+ scope = scope.joins(:external_service).where('external_services.short_name' => params[:external_service]) if params[:external_service]
scope = paginate scope
end
end
diff --git a/app/assets/stylesheets/content.scss b/app/assets/stylesheets/content.scss
index 05eb671ff..4a105fd4a 100644
--- a/app/assets/stylesheets/content.scss
+++ b/app/assets/stylesheets/content.scss
@@ -177,7 +177,7 @@
.meta {
float:left;
}
- .permissions {
+ .thread-parameters {
float:right;
}
}
diff --git a/app/assets/stylesheets/shared_elements.scss b/app/assets/stylesheets/shared_elements.scss
index 93bce6bb7..122843aab 100644
--- a/app/assets/stylesheets/shared_elements.scss
+++ b/app/assets/stylesheets/shared_elements.scss
@@ -260,7 +260,7 @@ ul.thread-list {
padding-left:42px;
background: image-url("map-icons/m-roadworks.png") 0 20px no-repeat;
}
- .permissions {
+ .thread-parameters {
float:right;
}
}
@@ -278,7 +278,7 @@ ul.thread-list {
}
}
-.permissions {
+.thread-parameters {
width: 80px;
color: $lightgrey;
text: {
diff --git a/app/controllers/admin/external_services_controller.rb b/app/controllers/admin/external_services_controller.rb
new file mode 100644
index 000000000..6dece21d9
--- /dev/null
+++ b/app/controllers/admin/external_services_controller.rb
@@ -0,0 +1,44 @@
+class Admin::ExternalServicesController < ApplicationController
+ def index
+ @external_services = ExternalService.all
+ end
+
+ def new
+ @external_service = ExternalService.new
+ end
+
+ def create
+ @external_service = ExternalService.new(permitted_params)
+ puts @external_service
+
+ if @external_service.save
+ set_flash_message(:success)
+ redirect_to action: :index
+ else
+ render :new
+ end
+ end
+
+ def edit
+ external_service
+ end
+
+ def update
+ if external_service.update permitted_params
+ set_flash_message :success
+ redirect_to action: :index
+ else
+ render :edit
+ end
+ end
+
+ protected
+
+ def permitted_params
+ params.require(:external_service).permit :name, :short_name
+ end
+
+ def external_service
+ @external_service ||= ExternalService.find params[:id]
+ end
+end
diff --git a/app/controllers/issue/message_threads_controller.rb b/app/controllers/issue/message_threads_controller.rb
index 29c85135f..3faa40047 100644
--- a/app/controllers/issue/message_threads_controller.rb
+++ b/app/controllers/issue/message_threads_controller.rb
@@ -17,6 +17,24 @@ def new
@message = @thread.messages.build
@message.body = issue.description if issue.threads.count == 0
@available_groups = current_user.groups
+ @external_services = ExternalService.all
+ end
+
+ helper_method :new_external
+
+ def new_external
+ @thread = issue.threads.build
+ set_page_title nil, issue: issue.title
+ if current_group
+ @thread.group = current_group
+ @thread.privacy = current_group.default_thread_privacy
+ end
+ @message = @thread.messages.build
+ @message.body = issue.description
+ @thread.title = issue.title
+ @thread.privacy = "public"
+ @available_groups = current_user.groups
+ @external_services = ExternalService.all
end
def create
diff --git a/app/controllers/message_threads_controller.rb b/app/controllers/message_threads_controller.rb
index da0b7c070..a420f4118 100644
--- a/app/controllers/message_threads_controller.rb
+++ b/app/controllers/message_threads_controller.rb
@@ -103,7 +103,7 @@ def thread
end
def permitted_params
- params.require(:thread).permit :title, :privacy, :group_id, :issue_id, :tags_string
+ params.require(:thread).permit :title, :privacy, :group_id, :issue_id, :tags_string, :external_service_id
end
def permitted_message_params
diff --git a/app/models/external_service.rb b/app/models/external_service.rb
new file mode 100644
index 000000000..a091d9c94
--- /dev/null
+++ b/app/models/external_service.rb
@@ -0,0 +1,27 @@
+# == Schema Information
+#
+# Table name: external_services
+#
+# id :integer not null, primary key
+# name :string(255) not null
+# short_name :string(255) not null
+#
+# Indexes
+#
+# index_external_services_on_short_name (short_name)
+#
+
+class ExternalService < ActiveRecord::Base
+ has_many :threads, class_name: 'MessageThread', inverse_of: :external_service
+
+ validates :name, presence: true, uniqueness: true
+ validates :short_name, presence: true, uniqueness: true, subdomain: true
+
+ normalize_attributes :short_name, with: [:strip, :blank, :downcase]
+
+ def to_param
+ "#{id}-#{short_name}"
+ end
+
+ protected
+end
diff --git a/app/models/message_thread.rb b/app/models/message_thread.rb
index be4aa01a1..e80edf827 100644
--- a/app/models/message_thread.rb
+++ b/app/models/message_thread.rb
@@ -51,6 +51,7 @@ class MessageThread < ActiveRecord::Base
belongs_to :group, inverse_of: :threads, counter_cache: true
belongs_to :issue, inverse_of: :threads
belongs_to :user, inverse_of: :private_threads
+ belongs_to :external_service, inverse_of: :threads
has_many :messages, -> { order(created_at: :asc) }, foreign_key: 'thread_id', autosave: true, inverse_of: :thread
has_many :subscriptions, -> { where(deleted_at: nil) }, class_name: 'ThreadSubscription', foreign_key: 'thread_id', inverse_of: :thread
has_many :subscribers, through: :subscriptions, source: :user
@@ -327,6 +328,7 @@ def as_json(_options = nil)
group_id: group_id,
title: title,
public_token: public_token,
+ external_service: external_service ? external_service.short_name : nil,
created_at: created_at,
updated_at: updated_at,
closed: closed,
diff --git a/app/views/admin/external_services/_form.html.haml b/app/views/admin/external_services/_form.html.haml
new file mode 100644
index 000000000..9e65bdc0b
--- /dev/null
+++ b/app/views/admin/external_services/_form.html.haml
@@ -0,0 +1,7 @@
+= semantic_form_for @external_service, url: [:admin, @external_service] do |f|
+ = f.inputs do
+ = f.input :name, input_html: { size: 30 }
+ = f.input :short_name, input_html: { size: 30 }
+ = f.actions do
+ = f.action :submit, button_html: {class: "btn-green submit"}
+ = cancel_link
diff --git a/app/views/admin/external_services/edit.html.haml b/app/views/admin/external_services/edit.html.haml
new file mode 100644
index 000000000..e67bb23e0
--- /dev/null
+++ b/app/views/admin/external_services/edit.html.haml
@@ -0,0 +1,5 @@
+%header
+ %h1
+ = t ".edit_external_service"
+%section
+ = render "form"
diff --git a/app/views/admin/external_services/index.html.haml b/app/views/admin/external_services/index.html.haml
new file mode 100644
index 000000000..32a2292b1
--- /dev/null
+++ b/app/views/admin/external_services/index.html.haml
@@ -0,0 +1,15 @@
+%header
+ %h1= t ".title"
+%section
+ .tasks
+ %p= link_to t(".new_external_service"), new_admin_external_service_path
+ %table
+ %thead
+ %th= t ".name"
+ %th= t ".short_name"
+ %tbody
+ - @external_services.each do |external_service|
+ %tr
+ %td= external_service.name
+ %td= external_service.short_name
+ %td= link_to t(".edit"), [:edit, :admin, external_service]
diff --git a/app/views/admin/external_services/new.html.haml b/app/views/admin/external_services/new.html.haml
new file mode 100644
index 000000000..585160c27
--- /dev/null
+++ b/app/views/admin/external_services/new.html.haml
@@ -0,0 +1,5 @@
+%header
+ %h1= t ".title"
+ %p= t ".introduction"
+%section
+ = render "form"
diff --git a/app/views/admin/home/index.html.haml b/app/views/admin/home/index.html.haml
index 494d8a892..23542331f 100644
--- a/app/views/admin/home/index.html.haml
+++ b/app/views/admin/home/index.html.haml
@@ -6,6 +6,7 @@
%li= link_to t(".manage_users"), admin_users_path
%li= link_to t(".manage_comments"), site_comments_path
%li= link_to t(".manage_message_moderations"), admin_message_moderations_path
+ %li= link_to t(".manage_external_services"), admin_external_services_path
%li= link_to t(".manage_site_config"), admin_site_config_path
%li= link_to t(".stats"), admin_stats_path
%li= link_to t(".resque"), resque_server_path
diff --git a/app/views/home/issue_template.html.erb b/app/views/home/issue_template.html.erb
index a68997dde..4e4f7194f 100644
--- a/app/views/home/issue_template.html.erb
+++ b/app/views/home/issue_template.html.erb
@@ -46,7 +46,9 @@
Cambridge Cycling Campaign 5 days ago
- private
+
@@ -54,7 +56,9 @@
- private
+
@@ -62,7 +66,9 @@
- shared
+
diff --git a/app/views/home/user_profile_template.html.erb b/app/views/home/user_profile_template.html.erb
index a1d95c003..12d7430ef 100644
--- a/app/views/home/user_profile_template.html.erb
+++ b/app/views/home/user_profile_template.html.erb
@@ -47,7 +47,9 @@
- private
+
21replies
@@ -63,7 +65,9 @@
- private
+
13replies
@@ -79,7 +83,9 @@
- shared
+
diff --git a/app/views/issue/message_threads/new_external.html.haml b/app/views/issue/message_threads/new_external.html.haml
new file mode 100644
index 000000000..e5e0d563f
--- /dev/null
+++ b/app/views/issue/message_threads/new_external.html.haml
@@ -0,0 +1,25 @@
+%section.new-thread
+ %h2= t ".title", issue: @issue.title.truncate(50)
+ - if @issue.threads.count == 0
+ %div.meta
+ %p
+ %i= simple_format t ".new_hint"
+ = semantic_form_for @thread, as: :thread, url: {action: :create}, html: {class: 'guided'} do |f|
+ = f.semantic_errors
+ = f.inputs do
+ = f.input :title
+ - if @available_groups.present?
+ = f.input :group,
+ collection: @available_groups.map {|g| [g.name, g.id, "data-privacy" => g.default_thread_privacy, "data-privacy-options" => Hash[g.thread_privacy_options_map_for(current_user).map { |n,v| [v, n]}].to_json] },
+ include_blank: false
+ - if @external_services.present?
+ = f.input :external_service,
+ as: :select,
+ collection: @external_services.map {|g| [g.name, g.id] },
+ include_blank: false
+ = semantic_fields_for @message do |f2|
+ = f2.semantic_errors
+ = f2.input :body, input_html: { rows: 10 }
+ = f.actions do
+ = f.action :submit, button_html: {class: "btn-green submit", data: { disable_with: t("formtastic.actions.saving") }}
+ = cancel_link issue_path(@issue)
diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml
index bd27bd97b..3004950ef 100644
--- a/app/views/issues/show.html.haml
+++ b/app/views/issues/show.html.haml
@@ -49,6 +49,10 @@
%aside#sidebar.wide
- if permitted_to? :create, :issue_message_threads
= link_to t(".new_thread", count: @issue.threads.count), new_issue_thread_path(@issue), class: "btn-green", rel: "#overlay"
+ - if current_user and current_user.groups.present?
+ - if ExternalService.all.present?
+ - if permitted_to? :create, :issue_message_threads
+ = link_to t(".new_send_thread", count: @issue.threads.count), issue_threads_new_external_path(@issue), class: "btn-green", rel: "#overlay"
%section.social
= tweet_button text: @issue.title, link: issue_url(@issue)
= facebook_like issue_url(@issue)
diff --git a/app/views/message_threads/_compact.html.haml b/app/views/message_threads/_compact.html.haml
index b077e17b8..33cc43ce7 100644
--- a/app/views/message_threads/_compact.html.haml
+++ b/app/views/message_threads/_compact.html.haml
@@ -13,4 +13,7 @@
= thread.latest_activity_by.display_name_or_anon
= time_tag_with_title(thread.latest_activity_at) do
- t ".posted_at", time_ago: time_ago_in_words(thread.latest_activity_at)
- .permissions= thread_type(thread)
+ .thread-parameters
+ - if thread.external_service
+ .external-service= thread.external_service.name
+ .permissions= thread_type(thread)
diff --git a/app/views/message_threads/edit.html.haml b/app/views/message_threads/edit.html.haml
index 21be26018..9928abd56 100644
--- a/app/views/message_threads/edit.html.haml
+++ b/app/views/message_threads/edit.html.haml
@@ -9,6 +9,8 @@
- unless f.object.private_message?
= f.input :group
= f.input :privacy, as: :select, collection: f.object.class.privacies_map
+ -if ExternalService.all.present?
+ = f.input :external_service
= f.input :issue, as: :select, collection: Issue.by_most_recent.map { |iss| ["#{iss.id} - #{iss.title}", iss.id] }
= f.actions do
= f.action :submit, button_html: {class: "btn-green submit", data: { disable_with: t("formtastic.actions.saving") }}
diff --git a/app/views/shared/_message_threads_list.html.haml b/app/views/shared/_message_threads_list.html.haml
index 750343389..d2b7655bd 100644
--- a/app/views/shared/_message_threads_list.html.haml
+++ b/app/views/shared/_message_threads_list.html.haml
@@ -20,4 +20,7 @@
- t ".posted_at", time_ago: time_ago_in_words(thread.latest_activity_at)
.status
= render 'message_threads/subscribe_button', thread: thread
- .permissions= thread_type(thread)
+ .thread-parameters
+ - if thread.external_service
+ .external-service= thread.external_service.name
+ .permissions= thread_type(thread)
diff --git a/config/authorization_rules.rb b/config/authorization_rules.rb
index beb7884a9..f336f0368 100644
--- a/config/authorization_rules.rb
+++ b/config/authorization_rules.rb
@@ -7,6 +7,7 @@
includes :member
has_permission_on :group_members, :group_memberships, :group_membership_requests, :group_profiles, :group_prefs, to: :manage
has_permission_on :admin_groups, to: [:manage, :disable, :enable]
+ has_permission_on :admin_external_services, to: :manage
has_permission_on :group_requests do
to [:index, :review, :confirm, :reject, :destroy]
end
@@ -86,7 +87,7 @@
has_permission_on :messages, to: [:new, :create, :vote_up, :vote_clear]
has_permission_on :message_library_notes, to: [:new, :create]
has_permission_on :message_library_documents, to: [:new, :create]
- has_permission_on :issue_message_threads, to: [:new, :create]
+ has_permission_on :issue_message_threads, to: [:new, :new_external, :create]
has_permission_on :group_message_threads do
to [:new, :create]
if_attribute group: is_in { user.groups }
diff --git a/config/locales/cs-CZ.yml b/config/locales/cs-CZ.yml
index 50b43c0b3..cf97c63a8 100644
--- a/config/locales/cs-CZ.yml
+++ b/config/locales/cs-CZ.yml
@@ -69,10 +69,27 @@ cs-CZ:
manage_issue_categories: Spravovat kategorie podnětů
manage_users: Spravovat uživatele
manage_message_moderations: Spravovat moderované zprávy
+ manage_external_services: Manage external services
manage_site_config: Upravit nastavení portálu
stats: Statistiky
resque: Resque
manage_planning_filters: Spravovat filtry plánování
+ external_services:
+ create:
+ success: Externí služba vytvořena
+ new:
+ title: Nová externí služba
+ introduction: Vytvořit novou externí službu
+ edit:
+ edit_external_service: Upravit externí službu
+ update:
+ success: Externí služba upravena
+ index:
+ name: Jméno
+ short_name: Identifikátor
+ title: Externí služby
+ new_external_service: Nová externí služba
+ edit: Upravit nastavení
issue_categories:
create:
success: Kategorie vytvořena
@@ -678,6 +695,8 @@ cs-CZ:
Např. nový stavební záměr se může dotýkat dopravy na silnici a zároveň ovlivňovat přístup na lesní cyklostezku.
title: Nové vlákno na téma %{issue}
everyone: Každý
+ new_external:
+ title: Odeslat podnět "%{issue}" na úřad
photos:
show:
photo_alt: Fotka pro %{caption}.
@@ -739,6 +758,7 @@ cs-CZ:
zero: Diskutujte
one: Nové diskuzní vlákno
other: Nové diskuzní vlákno
+ new_send_thread: Odeslat na úřad
no_threads_yet: O tomto podnětu zatím neexistují žádná diskuzní vlákna.
group_private: Soukromé pro %{group}
group_public: Veřejné od %{group}
diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml
index 98a1d40a1..051b20315 100644
--- a/config/locales/en-GB.yml
+++ b/config/locales/en-GB.yml
@@ -65,10 +65,27 @@
manage_issue_categories: Manage Issue Categories
manage_users: Manage users
manage_message_moderations: Manage message moderations
+ manage_external_services: Manage external services
manage_site_config: Manage site config
stats: Stats
resque: Resque
manage_planning_filters: Manage planning filters
+ external_services:
+ create:
+ success: External service created
+ new:
+ title: New external service
+ introduction: Create new external service
+ edit:
+ edit_external_service: Edit external service
+ update:
+ success: External service updated
+ index:
+ name: Name
+ short_name: Identifier
+ title: External services
+ new_external_service: New external service
+ edit: Edit preferences
issue_categories:
create:
success: Category created
@@ -575,6 +592,8 @@
access to woods."
title: New Thread on %{issue}
everyone: Everyone
+ new_external:
+ title: Send issue "%{issue}" to municipality
photos:
show:
photo_alt: The photo for %{caption}.
@@ -636,6 +655,7 @@
zero: Discuss
one: New Thread
other: New Thread
+ new_send_thread: Send to municipality
no_threads_yet: There are no discussion threads for this issue yet.
group_private: Private to %{group}
group_public: Public, by %{group}
diff --git a/config/routes.rb b/config/routes.rb
index 5e674093f..88586aeaa 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -13,6 +13,7 @@ def issues_route(opts = {})
get :all_geometries, on: :collection
scope module: 'issue' do
resource :photo, only: [:show]
+ get "/threads/new_external", to: "message_threads#new_external"
resources :threads, controller: 'message_threads'
resource :tags, only: [:update]
end
@@ -50,6 +51,7 @@ def issues_route(opts = {})
resources :groups do
put :disable, :enable, on: :member
end
+ resources :external_services
resource :site_config
resources :stats, only: :index
resources :message_moderations, only: :index
diff --git a/db/migrate/20171212101253_add_submit_external_to_message_thread.rb b/db/migrate/20171212101253_add_submit_external_to_message_thread.rb
new file mode 100644
index 000000000..099031e6c
--- /dev/null
+++ b/db/migrate/20171212101253_add_submit_external_to_message_thread.rb
@@ -0,0 +1,9 @@
+class AddSubmitExternalToMessageThread < ActiveRecord::Migration
+ def change
+ add_column :message_threads, :external_service_id, :integer
+ create_table :external_services do |t|
+ t.string :name, null: false
+ t.string :short_name, null: false
+ end
+ end
+end