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
+
+
private
+
  • Planning office discussions

    @@ -54,7 +56,9 @@

    Placeford Cycles 5 days ago

    -
    private
    +
    +
    private
    +
  • Planning office discussions

    @@ -62,7 +66,9 @@

    Cambridge Cycling Campaign 5 days ago

    -
    shared
    +
    +
    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
    +
    +
    private
    +
  • 21replies
    @@ -63,7 +65,9 @@ -
    private
    +
    +
    private
    +
  • 13replies
    @@ -79,7 +83,9 @@ -
    shared
    +
    +
    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