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,20 @@
|
|
1
|
+
<div class="media-object notify-note <%= note_author_class %>" id="notify-note-<%= id %>" data-author-code="<%= notify_author&.code %>" data-chapter="<%= chapter&.title %>">
|
2
|
+
<div class="media-object-section">
|
3
|
+
<%= cell("decidim/notify/participant", author) %>
|
4
|
+
</div>
|
5
|
+
<div class="media-object-section main-section">
|
6
|
+
<h4 class="note-name"><%= author&.name %> (@<%= author&.nickname %>)</h4>
|
7
|
+
<p class="note-body"><%= body %></p>
|
8
|
+
<em><%= l created_at, format: :decidim_short %></em>
|
9
|
+
</div>
|
10
|
+
<% if note_taker? %>
|
11
|
+
<div class="media-object-section buttons">
|
12
|
+
<%= button_to edit_path, method: :delete, remote: true, class: "delete", data: { confirm: t("decidim.notify.conversations.destroy.sure") } do %>
|
13
|
+
<%= icon "trash" %>
|
14
|
+
<% end %>
|
15
|
+
<%= link_to edit_path, class: "edit" do %>
|
16
|
+
<%= icon "pencil" %>
|
17
|
+
<% end %>
|
18
|
+
</div>
|
19
|
+
<% end %>
|
20
|
+
</div>
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
# This cell renders the card for an instance of a Notify Participant
|
6
|
+
class NoteCell < Decidim::ViewModel
|
7
|
+
include Decidim::LayoutHelper
|
8
|
+
|
9
|
+
property :id
|
10
|
+
property :body
|
11
|
+
property :author
|
12
|
+
property :creator
|
13
|
+
property :user
|
14
|
+
property :chapter
|
15
|
+
property :created_at
|
16
|
+
|
17
|
+
def notify_author
|
18
|
+
Author.find_by(user: model.author, component: model.component)
|
19
|
+
end
|
20
|
+
|
21
|
+
def note_taker?
|
22
|
+
return unless current_user
|
23
|
+
|
24
|
+
Author.for(model.component).note_takers.find_by(user: current_user)
|
25
|
+
end
|
26
|
+
|
27
|
+
def note_author_class
|
28
|
+
return "by-note-taker" if author&.admin
|
29
|
+
|
30
|
+
"by-participant"
|
31
|
+
end
|
32
|
+
|
33
|
+
def edit_path
|
34
|
+
EngineRouter.main_proxy(model.component).conversation_path(model.id)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
# This cell renders the card for an instance of a Notify Participant
|
6
|
+
class ParticipantCell < Decidim::ViewModel
|
7
|
+
def code
|
8
|
+
return model.code if model.is_a? Author
|
9
|
+
|
10
|
+
Author.find_by(user: model, component: current_component)&.code if model
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
model&.name
|
15
|
+
end
|
16
|
+
|
17
|
+
def avatar_url
|
18
|
+
model&.avatar_url(:profile)
|
19
|
+
end
|
20
|
+
|
21
|
+
def current_component
|
22
|
+
context&.dig(:current_component) || controller&.current_component
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
class ChaptersChannel < ActionCable::Channel::Base
|
6
|
+
def subscribed
|
7
|
+
stream_from current_channel
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def current_channel
|
13
|
+
"notify-chapters-#{params[:id]}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
class Connection < ActionCable::Connection::Base
|
6
|
+
identified_by :session_id
|
7
|
+
|
8
|
+
def connect
|
9
|
+
self.session_id = request.session.id
|
10
|
+
|
11
|
+
logger.add_tags(session_id)
|
12
|
+
|
13
|
+
logger.info "Connected to notify"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
class NotesChannel < ActionCable::Channel::Base
|
6
|
+
def subscribed
|
7
|
+
stream_from current_channel
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def current_channel
|
13
|
+
"notify-notes-#{params[:id]}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
class ParticipantsChannel < ActionCable::Channel::Base
|
6
|
+
def subscribed
|
7
|
+
stream_from current_channel
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def current_channel
|
13
|
+
"notify-participants-#{params[:id]}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
module Admin
|
6
|
+
class CreateChapter < Rectify::Command
|
7
|
+
# Public: Initializes the command.
|
8
|
+
#
|
9
|
+
# form - A chapter form
|
10
|
+
def initialize(form)
|
11
|
+
@form = form
|
12
|
+
end
|
13
|
+
|
14
|
+
# Executes the command. Broadcasts these events:
|
15
|
+
#
|
16
|
+
# - :ok when everything is valid.
|
17
|
+
# - :invalid if we couldn't proceed.
|
18
|
+
#
|
19
|
+
# Returns nothing.
|
20
|
+
def call
|
21
|
+
return broadcast(:invalid) if form.invalid?
|
22
|
+
|
23
|
+
unset_actives
|
24
|
+
create_chapter!
|
25
|
+
|
26
|
+
broadcast(:ok, @chapter)
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :form
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def create_chapter!
|
34
|
+
@chapter = Chapter.create!(
|
35
|
+
title: form.title,
|
36
|
+
active: form.active,
|
37
|
+
component: current_component
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def unset_actives
|
42
|
+
return unless form.active
|
43
|
+
|
44
|
+
# rubocop:disable Rails/SkipsModelValidations
|
45
|
+
Chapter.for(current_component).update_all(active: false)
|
46
|
+
# rubocop:enable Rails/SkipsModelValidations
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
module Admin
|
6
|
+
class DestroyChapter < Rectify::Command
|
7
|
+
# Public: Initializes the command.
|
8
|
+
#
|
9
|
+
# chapter - the chapter to be update
|
10
|
+
def initialize(chapter)
|
11
|
+
@chapter = chapter
|
12
|
+
end
|
13
|
+
|
14
|
+
# Executes the command. Broadcasts these events:
|
15
|
+
#
|
16
|
+
# - :ok when everything is valid.
|
17
|
+
# - :invalid if we couldn't proceed.
|
18
|
+
#
|
19
|
+
# Returns nothing.
|
20
|
+
def call
|
21
|
+
chapter.destroy!
|
22
|
+
|
23
|
+
broadcast(:ok)
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :chapter
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
module Admin
|
6
|
+
class UpdateChapter < Rectify::Command
|
7
|
+
# Public: Initializes the command.
|
8
|
+
#
|
9
|
+
# form - A chapter form
|
10
|
+
# chapter - the chapter to be update
|
11
|
+
def initialize(form, chapter)
|
12
|
+
@form = form
|
13
|
+
@chapter = chapter
|
14
|
+
end
|
15
|
+
|
16
|
+
# Executes the command. Broadcasts these events:
|
17
|
+
#
|
18
|
+
# - :ok when everything is valid.
|
19
|
+
# - :invalid if we couldn't proceed.
|
20
|
+
#
|
21
|
+
# Returns nothing.
|
22
|
+
def call
|
23
|
+
return broadcast(:invalid) if form.invalid?
|
24
|
+
|
25
|
+
unset_actives
|
26
|
+
update_chapter!
|
27
|
+
|
28
|
+
broadcast(:ok)
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :form, :chapter
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def update_chapter!
|
36
|
+
chapter.update!(
|
37
|
+
title: form.title,
|
38
|
+
active: form.active
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def unset_actives
|
43
|
+
return unless form.active
|
44
|
+
|
45
|
+
# rubocop:disable Rails/SkipsModelValidations
|
46
|
+
Chapter.for(current_component).update_all(active: false)
|
47
|
+
# rubocop:enable Rails/SkipsModelValidations
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
module Admin
|
6
|
+
class UpdateConfig < Rectify::Command
|
7
|
+
# Public: Initializes the command.
|
8
|
+
#
|
9
|
+
# form - A config form
|
10
|
+
def initialize(form)
|
11
|
+
@form = form
|
12
|
+
end
|
13
|
+
|
14
|
+
# Executes the command. Broadcasts these events:
|
15
|
+
#
|
16
|
+
# - :ok when everything is valid.
|
17
|
+
# - :invalid if we couldn't proceed.
|
18
|
+
#
|
19
|
+
# Returns nothing.
|
20
|
+
def call
|
21
|
+
return broadcast(:invalid) if form.invalid?
|
22
|
+
|
23
|
+
begin
|
24
|
+
remove_users
|
25
|
+
update_users
|
26
|
+
update_config
|
27
|
+
|
28
|
+
broadcast(:ok, @participants)
|
29
|
+
rescue ActiveRecord::RecordInvalid => e
|
30
|
+
broadcast(:invalid, e.message)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_reader :form
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def update_config
|
39
|
+
current_component.attributes["settings"]["global"]["restricted"] = form.restricted
|
40
|
+
current_component.attributes["settings"]["global"]["private"] = form.private
|
41
|
+
current_component.save!
|
42
|
+
end
|
43
|
+
|
44
|
+
def update_users
|
45
|
+
@participants = []
|
46
|
+
all_users.each_with_index do |id, idx|
|
47
|
+
user = Decidim::User.find_by(id: id, organization: current_organization)
|
48
|
+
next unless user
|
49
|
+
|
50
|
+
author = Author.find_or_create_by(
|
51
|
+
user: user,
|
52
|
+
component: current_component
|
53
|
+
)
|
54
|
+
author.code = idx + 1
|
55
|
+
author.admin = form.note_takers.include?(user.id.to_s)
|
56
|
+
author.save!
|
57
|
+
@participants << author
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def remove_users
|
62
|
+
Author.for(current_component).destroy_all
|
63
|
+
end
|
64
|
+
|
65
|
+
def all_users
|
66
|
+
@all_users ||= (form.users + form.note_takers).uniq.reject(&:blank?)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
class CreateNote < Rectify::Command
|
6
|
+
# Public: Initializes the command.
|
7
|
+
#
|
8
|
+
# form - A config form
|
9
|
+
def initialize(form)
|
10
|
+
@form = form
|
11
|
+
end
|
12
|
+
|
13
|
+
# Executes the command. Broadcasts these events:
|
14
|
+
#
|
15
|
+
# - :ok when everything is valid.
|
16
|
+
# - :invalid if we couldn't proceed.
|
17
|
+
#
|
18
|
+
# Returns nothing.
|
19
|
+
def call
|
20
|
+
return broadcast(:invalid) if form.invalid?
|
21
|
+
|
22
|
+
begin
|
23
|
+
note = Note.create!(
|
24
|
+
author: Author.find_by(code: form.code, component: current_component)&.user,
|
25
|
+
body: form.body,
|
26
|
+
creator: current_user,
|
27
|
+
chapter: create_chapter,
|
28
|
+
component: current_component
|
29
|
+
)
|
30
|
+
|
31
|
+
broadcast(:ok, note, @new_chapter)
|
32
|
+
rescue ActiveRecord::ActiveRecordError => e
|
33
|
+
broadcast(:invalid, e.message)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :form
|
40
|
+
|
41
|
+
def create_chapter
|
42
|
+
return nil if form.chapter.blank?
|
43
|
+
|
44
|
+
chapter = Chapter.find_or_initialize_by(title: form.chapter, component: current_component)
|
45
|
+
@new_chapter = chapter unless chapter.id
|
46
|
+
chapter.title = form.chapter
|
47
|
+
chapter.save!
|
48
|
+
chapter
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Notify
|
5
|
+
class DeleteChapter < Rectify::Command
|
6
|
+
# Public: Initializes the command.
|
7
|
+
#
|
8
|
+
def initialize(id)
|
9
|
+
@id = id
|
10
|
+
end
|
11
|
+
|
12
|
+
# Executes the command. Broadcasts these events:
|
13
|
+
#
|
14
|
+
# - :ok when everything is valid.
|
15
|
+
# - :invalid if we couldn't proceed.
|
16
|
+
#
|
17
|
+
# Returns nothing.
|
18
|
+
def call
|
19
|
+
chapter = Chapter.for(current_component).find(@id)
|
20
|
+
chapter.destroy!
|
21
|
+
|
22
|
+
broadcast(:ok)
|
23
|
+
rescue ActiveRecord::ActiveRecordError => e
|
24
|
+
broadcast(:invalid, e.message)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|