decidim-notify 0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE-AGPLv3.txt +661 -0
- data/README.md +160 -0
- data/Rakefile +40 -0
- data/app/assets/config/decidim_notify_manifest.css +2 -0
- data/app/assets/config/decidim_notify_manifest.js +3 -0
- data/app/assets/images/decidim/notify/icon.svg +1 -0
- data/app/assets/javascripts/cable.js +13 -0
- data/app/assets/javascripts/channels/decidim/notify/conversations.js +90 -0
- data/app/assets/javascripts/decidim/notify/conversations.js.es6 +70 -0
- data/app/assets/javascripts/decidim/notify/select2.js.es6 +100 -0
- data/app/assets/stylesheets/decidim/notify/_hexagon.scss +126 -0
- data/app/assets/stylesheets/decidim/notify/admin.scss +25 -0
- data/app/assets/stylesheets/decidim/notify/notify.scss +220 -0
- data/app/cells/decidim/notify/chapter/show.erb +35 -0
- data/app/cells/decidim/notify/chapter_cell.rb +43 -0
- data/app/cells/decidim/notify/note/show.erb +20 -0
- data/app/cells/decidim/notify/note_cell.rb +38 -0
- data/app/cells/decidim/notify/participant/show.erb +9 -0
- data/app/cells/decidim/notify/participant_cell.rb +26 -0
- data/app/channels/decidim/notify/chapters_channel.rb +17 -0
- data/app/channels/decidim/notify/connection.rb +17 -0
- data/app/channels/decidim/notify/notes_channel.rb +17 -0
- data/app/channels/decidim/notify/participants_channel.rb +17 -0
- data/app/commands/decidim/notify/admin/create_chapter.rb +51 -0
- data/app/commands/decidim/notify/admin/destroy_chapter.rb +30 -0
- data/app/commands/decidim/notify/admin/update_chapter.rb +52 -0
- data/app/commands/decidim/notify/admin/update_config.rb +71 -0
- data/app/commands/decidim/notify/create_note.rb +52 -0
- data/app/commands/decidim/notify/delete_chapter.rb +28 -0
- data/app/commands/decidim/notify/delete_note.rb +28 -0
- data/app/commands/decidim/notify/update_chapter.rb +35 -0
- data/app/commands/decidim/notify/update_note.rb +51 -0
- data/app/controllers/concerns/decidim/notify/broadcasts.rb +56 -0
- data/app/controllers/concerns/decidim/notify/needs_ajax_rescue.rb +25 -0
- data/app/controllers/decidim/notify/admin/application_controller.rb +18 -0
- data/app/controllers/decidim/notify/admin/chapters_controller.rb +90 -0
- data/app/controllers/decidim/notify/admin/conversations_controller.rb +61 -0
- data/app/controllers/decidim/notify/application_controller.rb +16 -0
- data/app/controllers/decidim/notify/chapters_controller.rb +41 -0
- data/app/controllers/decidim/notify/conversations_controller.rb +105 -0
- data/app/forms/decidim/notify/admin/chapter_form.rb +14 -0
- data/app/forms/decidim/notify/admin/notify_config_form.rb +14 -0
- data/app/forms/decidim/notify/chapter_form.rb +13 -0
- data/app/forms/decidim/notify/note_form.rb +16 -0
- data/app/helpers/decidim/notify/application_helper.rb +10 -0
- data/app/models/concerns/decidim/notify/belongs_to_notify_component.rb +31 -0
- data/app/models/decidim/notify/application_record.rb +10 -0
- data/app/models/decidim/notify/author.rb +29 -0
- data/app/models/decidim/notify/chapter.rb +22 -0
- data/app/models/decidim/notify/note.rb +23 -0
- data/app/permissions/decidim/notify/admin/permissions.rb +23 -0
- data/app/permissions/decidim/notify/permissions.rb +45 -0
- data/app/views/decidim/notify/admin/chapters/_form.html.erb +20 -0
- data/app/views/decidim/notify/admin/chapters/edit.html.erb +7 -0
- data/app/views/decidim/notify/admin/chapters/index.html.erb +52 -0
- data/app/views/decidim/notify/admin/chapters/new.html.erb +7 -0
- data/app/views/decidim/notify/admin/conversations/_form.html.erb +27 -0
- data/app/views/decidim/notify/admin/conversations/index.html.erb +27 -0
- data/app/views/decidim/notify/conversations/_chapter.html.erb +1 -0
- data/app/views/decidim/notify/conversations/_form.html.erb +9 -0
- data/app/views/decidim/notify/conversations/_note.html.erb +1 -0
- data/app/views/decidim/notify/conversations/_participant.html.erb +1 -0
- data/app/views/decidim/notify/conversations/_script.js.erb +7 -0
- data/app/views/decidim/notify/conversations/index.html.erb +48 -0
- data/app/views/decidim/notify/conversations/private.html.erb +11 -0
- data/config/i18n-tasks.yml +35 -0
- data/config/locales/ca.yml +110 -0
- data/config/locales/cs.yml +110 -0
- data/config/locales/en.yml +110 -0
- data/config/locales/es.yml +110 -0
- data/db/migrate/20200504071404_create_notify_notes.rb +11 -0
- data/db/migrate/20200505061547_create_notify_authors.rb +17 -0
- data/db/migrate/20200505061640_add_notify_notes_references.rb +9 -0
- data/db/migrate/20200505195918_add_notify_author_admin.rb +7 -0
- data/db/migrate/20200507103034_change_notify_notes_authors.rb +15 -0
- data/db/migrate/20200514144040_add_notify_note_chapters.rb +15 -0
- data/lib/decidim/notify.rb +57 -0
- data/lib/decidim/notify/admin.rb +10 -0
- data/lib/decidim/notify/admin_engine.rb +25 -0
- data/lib/decidim/notify/component.rb +135 -0
- data/lib/decidim/notify/engine.rb +39 -0
- data/lib/decidim/notify/seeds/avatar1.png +0 -0
- data/lib/decidim/notify/seeds/avatar2.png +0 -0
- data/lib/decidim/notify/seeds/avatar3.png +0 -0
- data/lib/decidim/notify/seeds/avatar4.png +0 -0
- data/lib/decidim/notify/seeds/avatar5.png +0 -0
- data/lib/decidim/notify/test/factories.rb +48 -0
- data/lib/decidim/notify/test/shared_examples/component_examples.rb +23 -0
- data/lib/decidim/notify/version.rb +9 -0
- data/vendor/assets/javascripts/select2.js +6147 -0
- data/vendor/assets/stylesheets/select2-foundation-theme.css +249 -0
- data/vendor/assets/stylesheets/select2.css +515 -0
- metadata +177 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
module Admin
|
6
|
+
class NotifyConfigForm < Decidim::Form
|
7
|
+
attribute :users, Array[String]
|
8
|
+
attribute :note_takers, Array[String]
|
9
|
+
attribute :private, Boolean
|
10
|
+
attribute :restricted, Boolean
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
class NoteForm < Decidim::Form
|
6
|
+
mimic :note
|
7
|
+
|
8
|
+
attribute :id, Integer
|
9
|
+
attribute :code, Integer
|
10
|
+
attribute :chapter, String
|
11
|
+
attribute :body, String
|
12
|
+
|
13
|
+
validates :body, presence: true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
|
5
|
+
module Decidim
|
6
|
+
module Notify
|
7
|
+
# A concern with the components needed when you want a model to be have a questionnaire attached
|
8
|
+
module BelongsToNotifyComponent
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
belongs_to :component, foreign_key: "decidim_component_id", class_name: "Decidim::Component"
|
13
|
+
|
14
|
+
validates :component, presence: true
|
15
|
+
validate :component_is_notify
|
16
|
+
|
17
|
+
def self.for(component)
|
18
|
+
where(component: component)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def component_is_notify
|
24
|
+
return unless component
|
25
|
+
|
26
|
+
errors.add(:component, :invalid) unless component.manifest.name == :notify
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
# The data store for a Author in the Decidim::Notify component.
|
6
|
+
class Author < ApplicationRecord
|
7
|
+
include BelongsToNotifyComponent
|
8
|
+
|
9
|
+
self.table_name = :decidim_notify_authors
|
10
|
+
|
11
|
+
belongs_to :user, foreign_key: "decidim_user_id", class_name: "Decidim::User", optional: true
|
12
|
+
|
13
|
+
validates :user, uniqueness: { scope: :decidim_component_id }
|
14
|
+
validates :code, numericality: { greater_than_or_equal_to: 1 }, uniqueness: { scope: :decidim_component_id }
|
15
|
+
|
16
|
+
delegate :name, :nickname, :organization, :avatar, to: :user
|
17
|
+
delegate :profile_url, :avatar_url, to: :user, allow_nil: true
|
18
|
+
|
19
|
+
default_scope { order(code: :asc) }
|
20
|
+
|
21
|
+
scope :note_takers, -> { where(admin: true) }
|
22
|
+
scope :participants, -> { where(admin: false) }
|
23
|
+
|
24
|
+
def notes
|
25
|
+
Note.where(decidim_author_id: decidim_user_id)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
# The data store for a Chapter in the Decidim::Notify component.
|
6
|
+
class Chapter < ApplicationRecord
|
7
|
+
include BelongsToNotifyComponent
|
8
|
+
|
9
|
+
self.table_name = :decidim_notify_chapters
|
10
|
+
|
11
|
+
has_many :notes,
|
12
|
+
foreign_key: "decidim_notify_chapter_id",
|
13
|
+
class_name: "Decidim::Notify::Note",
|
14
|
+
dependent: :nullify
|
15
|
+
|
16
|
+
validates :title, presence: true
|
17
|
+
validates :title, uniqueness: { scope: :decidim_component_id }
|
18
|
+
|
19
|
+
default_scope { order(created_at: :desc) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
# The data store for a Note in the Decidim::Notify component.
|
6
|
+
class Note < ApplicationRecord
|
7
|
+
include BelongsToNotifyComponent
|
8
|
+
|
9
|
+
self.table_name = :decidim_notify_notes
|
10
|
+
|
11
|
+
belongs_to :author, foreign_key: "decidim_author_id", class_name: "Decidim::User", optional: true
|
12
|
+
belongs_to :creator, foreign_key: "decidim_creator_id", class_name: "Decidim::User"
|
13
|
+
belongs_to :chapter, foreign_key: "decidim_notify_chapter_id", class_name: "Decidim::Notify::Chapter", optional: true
|
14
|
+
|
15
|
+
validates :creator, presence: true
|
16
|
+
|
17
|
+
default_scope { order(decidim_notify_chapter_id: :asc, created_at: :desc) }
|
18
|
+
|
19
|
+
scope :orphan, -> { where(author: nil) }
|
20
|
+
scope :unclassified, -> { where(chapter: nil) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
module Admin
|
6
|
+
class Permissions < Decidim::DefaultPermissions
|
7
|
+
def permissions
|
8
|
+
return permission_action unless user
|
9
|
+
|
10
|
+
return permission_action if permission_action.scope != :admin
|
11
|
+
|
12
|
+
return permission_action unless [:config, :chapter].include? permission_action.subject
|
13
|
+
|
14
|
+
case permission_action.action
|
15
|
+
when :index, :create, :update, :destroy
|
16
|
+
permission_action.allow!
|
17
|
+
end
|
18
|
+
permission_action
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
class Permissions < Decidim::DefaultPermissions
|
6
|
+
def permissions
|
7
|
+
return permission_action unless permission_action.subject.in? [:notes, :chapter]
|
8
|
+
|
9
|
+
index_action?
|
10
|
+
edit_action?
|
11
|
+
|
12
|
+
permission_action
|
13
|
+
end
|
14
|
+
|
15
|
+
def index_action?
|
16
|
+
return unless permission_action.action == :index
|
17
|
+
|
18
|
+
component = context.fetch(:current_component)
|
19
|
+
|
20
|
+
if component.settings.private
|
21
|
+
return unless user
|
22
|
+
|
23
|
+
participants = Author.for(component).pluck :decidim_user_id
|
24
|
+
return allow! if participants.include? user.id
|
25
|
+
elsif component.settings.restricted
|
26
|
+
return allow! if user
|
27
|
+
else
|
28
|
+
return allow!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def edit_action?
|
33
|
+
return unless user
|
34
|
+
|
35
|
+
case permission_action.action
|
36
|
+
when :create, :update, :destroy
|
37
|
+
component = context.fetch(:current_component)
|
38
|
+
|
39
|
+
note_takers = Author.for(component).note_takers.pluck :decidim_user_id
|
40
|
+
return allow! if note_takers.include? user.id
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<div class="card">
|
2
|
+
<div class="card-divider">
|
3
|
+
<h2 class="card-title">
|
4
|
+
<%= title %>
|
5
|
+
<div class="button--title">
|
6
|
+
<%= link_to t(".cancel"), chapters_path, class: "button tiny button--simple" %>
|
7
|
+
</div>
|
8
|
+
</h2>
|
9
|
+
</div>
|
10
|
+
<div class="card-section">
|
11
|
+
<div class="row column hashtags__container">
|
12
|
+
<%= form.text_field :title, autofocus: true %>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<div class="row column">
|
16
|
+
<%= form.check_box :active %>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
</div>
|
20
|
+
</div>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<%= decidim_form_for(@form, url: chapter_path, html: { class: "form edit_chapter" }) do |f| %>
|
2
|
+
<%= render partial: "form", object: f, locals: { title: t(".title") } %>
|
3
|
+
|
4
|
+
<div class="button--double form-general-submit">
|
5
|
+
<%= f.submit t(".update") %>
|
6
|
+
</div>
|
7
|
+
<% end %>
|
@@ -0,0 +1,52 @@
|
|
1
|
+
<div class="card">
|
2
|
+
<div class="card-divider">
|
3
|
+
<h2 class="card-title">
|
4
|
+
<%= t(".title") %>
|
5
|
+
<div class="button--title">
|
6
|
+
<%= link_to t("chapters.actions.new", scope: "decidim.notify.admin", name: t("chapter.title", scope: "activemodel.attributes")), new_chapter_path, class: "button tiny button--simple" %>
|
7
|
+
</div>
|
8
|
+
<div class="button--title">
|
9
|
+
<%= link_to t(".conversations"), conversations_path, class: "button tiny button--simple" %>
|
10
|
+
</div>
|
11
|
+
</h2>
|
12
|
+
</div>
|
13
|
+
|
14
|
+
<div class="card-section">
|
15
|
+
<div class="table-scroll">
|
16
|
+
<table class="table-list">
|
17
|
+
<thead>
|
18
|
+
<tr>
|
19
|
+
<th><%= t("chapter.title", scope: "activemodel.attributes") %></th>
|
20
|
+
<th><%= t("chapter.active", scope: "activemodel.attributes") %></th>
|
21
|
+
<th class="actions"><%= t("actions.title", scope: "decidim.notify.admin") %></th>
|
22
|
+
</tr>
|
23
|
+
</thead>
|
24
|
+
<tbody>
|
25
|
+
<% chapters.each do |chapter| %>
|
26
|
+
<tr data-id="<%= chapter.id %>">
|
27
|
+
<td>
|
28
|
+
<%= chapter.title %>
|
29
|
+
</td>
|
30
|
+
<td>
|
31
|
+
<% if chapter.active? %>
|
32
|
+
<span class="text-success"><%= icon("check", class: "icon", aria_label: "ok", role: "img") %></span>
|
33
|
+
<% else %>
|
34
|
+
<span class="text-muted"><%= icon("check", class: "icon", aria_label: "ko", role: "img") %></span>
|
35
|
+
<% end %>
|
36
|
+
</td>
|
37
|
+
<td class="table-list__actions">
|
38
|
+
<% if allowed_to? :update, :chapter, chapter: chapter %>
|
39
|
+
<%= icon_link_to "pencil", edit_chapter_path(chapter), t("edit", scope: "decidim.notify.chapter"), class: "action-icon--edit" %>
|
40
|
+
<% end %>
|
41
|
+
|
42
|
+
<% if allowed_to? :destroy, :chapter, chapter: chapter %>
|
43
|
+
<%= icon_link_to "circle-x", chapter_path(chapter), t("delete", scope: "decidim.notify.chapter"), method: :delete, class: "action-icon--remove", data: { confirm: t("destroy.sure", scope: "decidim.notify.chapter") } %>
|
44
|
+
<% end %>
|
45
|
+
</td>
|
46
|
+
</tr>
|
47
|
+
<% end %>
|
48
|
+
</tbody>
|
49
|
+
</table>
|
50
|
+
</div>
|
51
|
+
</div>
|
52
|
+
</div>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<%= decidim_form_for(@form, url: chapters_path, html: { class: "form edit_chapter" }) do |f| %>
|
2
|
+
<%= render partial: "form", object: f, locals: { title: t(".title") } %>
|
3
|
+
|
4
|
+
<div class="button--double form-general-submit">
|
5
|
+
<%= f.submit t(".create") %>
|
6
|
+
</div>
|
7
|
+
<% end %>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<div class="row column">
|
2
|
+
<%= form.select :users, options_from_collection_for_select(@users, :id, :text, proc { true }), { include_blank: false }, { class: "multiusers-select", multiple: true, data: { url: users_path } } %>
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<div class="row column">
|
6
|
+
<%= form.select :note_takers, options_from_collection_for_select(@note_takers, :id, :text, proc { true }), { include_blank: false }, { class: "multiusers-select", multiple: true, data: { url: users_path } } %>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<div class="row column">
|
10
|
+
<div class="switch tiny switch-with-label restricted">
|
11
|
+
<%= form.label :restricted do %>
|
12
|
+
<%= form.check_box :restricted, label: false, class: "switch-input" %>
|
13
|
+
<span class="switch-paddle"></span>
|
14
|
+
<span class="switch-label"><%= t("restricted", scope: "decidim.components.notify.settings.global") %></span>
|
15
|
+
<% end %>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<div class="row column">
|
20
|
+
<div class="switch tiny switch-with-label private">
|
21
|
+
<%= form.label :private do %>
|
22
|
+
<%= form.check_box :private, label: false, class: "switch-input" %>
|
23
|
+
<span class="switch-paddle"></span>
|
24
|
+
<span class="switch-label"><%= t("private", scope: "decidim.components.notify.settings.global") %></span>
|
25
|
+
<% end %>
|
26
|
+
</div>
|
27
|
+
</div>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<div class="card">
|
2
|
+
<div class="card-divider">
|
3
|
+
<h2 class="card-title">
|
4
|
+
<%= t(".title") %>
|
5
|
+
<div class="button--title">
|
6
|
+
<%= link_to t("actions.configure", scope: "decidim.admin"), Decidim::EngineRouter.admin_proxy(current_component.participatory_space).edit_component_path(current_component.id), class: "button tiny button--simple" %>
|
7
|
+
</div>
|
8
|
+
<div class="button--title">
|
9
|
+
<%= link_to t(".chapters"), chapters_path, class: "button tiny button--simple" %>
|
10
|
+
</div>
|
11
|
+
</h2>
|
12
|
+
</div>
|
13
|
+
|
14
|
+
<div class="card-section multiusers-select-container">
|
15
|
+
<p class="text-help"><%= t(".help").html_safe %></p>
|
16
|
+
<%= decidim_form_for(@form, url: conversations_path, html: { class: "form users" }) do |f| %>
|
17
|
+
|
18
|
+
<%= render partial: "form", object: f %>
|
19
|
+
|
20
|
+
<div class="button--double form-conversations-submit">
|
21
|
+
<%= f.submit t(".save") %>
|
22
|
+
</div>
|
23
|
+
<% end %>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<%= javascript_include_tag "decidim/notify/select2" %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= cell "decidim/notify/chapter", chapter %>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<div class="row column">
|
2
|
+
<%= form.select :chapter, options_from_collection_for_select(chapters, :title, :title, active_chapter&.title), { include_blank: true }, placeholder: t("placeholders.chapter", scope: "decidim.notify.conversations"), class: "chapter-select" %>
|
3
|
+
</div>
|
4
|
+
<div class="row column">
|
5
|
+
<%= form.select :code, [], {}, placeholder: t("placeholders.author", scope: "decidim.notify.conversations"), class: "user-select", data: { url: users_path } %>
|
6
|
+
</div>
|
7
|
+
<div class="row column">
|
8
|
+
<%= form.text_area :body, placeholder: t("placeholders.statement", scope: "decidim.notify.conversations"), rows: 3 %>
|
9
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= cell "decidim/notify/note", note %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= cell "decidim/notify/participant", participant %>
|