decidim-comparative_stats 1.0.1
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 +187 -0
- data/Rakefile +40 -0
- data/app/assets/config/admin/comparative_stats_manifest.css +4 -0
- data/app/assets/config/admin/comparative_stats_manifest.js +2 -0
- data/app/assets/config/comparative_stats_manifest.css +4 -0
- data/app/assets/config/comparative_stats_manifest.js +2 -0
- data/app/assets/images/bcn-logo.png +0 -0
- data/app/assets/images/decidim/comparative_stats/icon.svg +1 -0
- data/app/assets/images/platoniq-logo.png +0 -0
- data/app/assets/javascripts/decidim/comparative_stats/geocoded_events.js.es6 +94 -0
- data/app/assets/javascripts/decidim/comparative_stats/graphs.js.es6 +13 -0
- data/app/assets/stylesheets/decidim/comparative_stats/geocoded_events.scss +23 -0
- data/app/assets/stylesheets/decidim/comparative_stats/graphs.scss +6 -0
- data/app/assets/stylesheets/decidim/comparative_stats/widget.scss +8 -0
- data/app/cells/decidim/comparative_stats/metric_piecharts/show.erb +14 -0
- data/app/cells/decidim/comparative_stats/metric_piecharts_cell.rb +39 -0
- data/app/cells/decidim/comparative_stats/metric_timelines/show.erb +14 -0
- data/app/cells/decidim/comparative_stats/metric_timelines_cell.rb +23 -0
- data/app/cells/decidim/comparative_stats/participatory_processes_timeline/show.erb +55 -0
- data/app/cells/decidim/comparative_stats/participatory_processes_timeline_cell.rb +51 -0
- data/app/cells/decidim/comparative_stats/participatory_spaces_geocoded_events/show.erb +55 -0
- data/app/cells/decidim/comparative_stats/participatory_spaces_geocoded_events_cell.rb +108 -0
- data/app/commands/decidim/comparative_stats/admin/create_endpoint.rb +46 -0
- data/app/commands/decidim/comparative_stats/admin/destroy_endpoint.rb +43 -0
- data/app/commands/decidim/comparative_stats/admin/update_endpoint.rb +47 -0
- data/app/controllers/decidim/comparative_stats/admin/application_controller.rb +16 -0
- data/app/controllers/decidim/comparative_stats/admin/endpoints_controller.rb +83 -0
- data/app/controllers/decidim/comparative_stats/admin/graphs_controller.rb +16 -0
- data/app/controllers/decidim/comparative_stats/widgets_controller.rb +31 -0
- data/app/forms/decidim/comparative_stats/admin/endpoint_form.rb +26 -0
- data/app/helpers/decidim/comparative_stats/application_helper.rb +27 -0
- data/app/models/decidim/comparative_stats/application_record.rb +10 -0
- data/app/models/decidim/comparative_stats/endpoint.rb +22 -0
- data/app/permissions/decidim/comparative_stats/admin/permissions.rb +24 -0
- data/app/presenters/decidim/comparative_stats/admin_log/endpoint_presenter.rb +46 -0
- data/app/views/decidim/comparative_stats/admin/endpoints/_form.html.erb +7 -0
- data/app/views/decidim/comparative_stats/admin/endpoints/edit.html.erb +16 -0
- data/app/views/decidim/comparative_stats/admin/endpoints/index.html.erb +66 -0
- data/app/views/decidim/comparative_stats/admin/endpoints/new.html.erb +16 -0
- data/app/views/decidim/comparative_stats/admin/graphs/show.html.erb +15 -0
- data/app/views/decidim/comparative_stats/widgets/_all.html.erb +1 -0
- data/app/views/decidim/comparative_stats/widgets/_embed.html.erb +7 -0
- data/app/views/decidim/comparative_stats/widgets/_embed_modal.html.erb +27 -0
- data/app/views/decidim/comparative_stats/widgets/_global_stats.html.erb +4 -0
- data/app/views/decidim/comparative_stats/widgets/_global_stats_timeline.html.erb +4 -0
- data/app/views/decidim/comparative_stats/widgets/_processes_timeline.html.erb +4 -0
- data/app/views/decidim/comparative_stats/widgets/_spaces_geocoded_events.html.erb +5 -0
- data/app/views/decidim/comparative_stats/widgets/_tabs.html.erb +19 -0
- data/app/views/decidim/comparative_stats/widgets/show.html.erb +1 -0
- data/app/views/layouts/decidim/admin/comparative_stats.html.erb +28 -0
- data/app/views/layouts/decidim/comparative_stats/widget.html.erb +22 -0
- data/config/i18n-tasks.yml +10 -0
- data/config/locales/ca.yml +57 -0
- data/config/locales/cs.yml +57 -0
- data/config/locales/en.yml +64 -0
- data/config/locales/es.yml +57 -0
- data/db/migrate/20191219104548_create_decidim_comparative_stats_endpoints.rb +13 -0
- data/db/migrate/20200122072955_add_name_version_to_comparative_stats_endpoints.rb +8 -0
- data/db/migrate/20200130203914_rename_version_field_in_comparative_stats_endpoints.rb +7 -0
- data/db/seeds.rb +42 -0
- data/lib/decidim/comparative_stats.rb +22 -0
- data/lib/decidim/comparative_stats/admin.rb +10 -0
- data/lib/decidim/comparative_stats/admin_engine.rb +50 -0
- data/lib/decidim/comparative_stats/api_fetcher.rb +93 -0
- data/lib/decidim/comparative_stats/cached_http_adapter.rb +23 -0
- data/lib/decidim/comparative_stats/engine.rb +34 -0
- data/lib/decidim/comparative_stats/queries/global_events.graphql +84 -0
- data/lib/decidim/comparative_stats/queries/global_history_metrics.graphql +10 -0
- data/lib/decidim/comparative_stats/queries/global_metrics.graphql +6 -0
- data/lib/decidim/comparative_stats/queries/name_and_version.graphql +6 -0
- data/lib/decidim/comparative_stats/queries/participatory_processes.graphql +12 -0
- data/lib/decidim/comparative_stats/queries/v022/global_events.graphql +76 -0
- data/lib/decidim/comparative_stats/test/factories.rb +13 -0
- data/lib/decidim/comparative_stats/version.rb +10 -0
- data/vendor/assets/images/draw/layers-2x.png +0 -0
- data/vendor/assets/images/draw/layers.png +0 -0
- data/vendor/assets/images/draw/marker-icon-2x.png +0 -0
- data/vendor/assets/images/draw/marker-icon.png +0 -0
- data/vendor/assets/images/draw/marker-shadow.png +0 -0
- data/vendor/assets/images/draw/spritesheet-2x.png +0 -0
- data/vendor/assets/images/draw/spritesheet.png +0 -0
- data/vendor/assets/images/draw/spritesheet.svg +156 -0
- data/vendor/assets/images/images/layers-2x.png +0 -0
- data/vendor/assets/images/images/layers.png +0 -0
- data/vendor/assets/images/images/marker-icon-2x.png +0 -0
- data/vendor/assets/images/images/marker-icon.png +0 -0
- data/vendor/assets/images/images/marker-shadow.png +0 -0
- data/vendor/assets/javascripts/leaflet.js +5 -0
- metadata +234 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<div class="row">
|
|
2
|
+
<% metrics.each do |name, metric| %>
|
|
3
|
+
<div class="column" style="padding: 1em">
|
|
4
|
+
<div class="card">
|
|
5
|
+
<div class="card-divider">
|
|
6
|
+
<%= title name %>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="card-section">
|
|
9
|
+
<%= line_chart metric, id: "line_chart_#{name}" %>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
<% end %>
|
|
14
|
+
</div>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module ComparativeStats
|
|
5
|
+
class MetricTimelinesCell < MetricPiechartsCell
|
|
6
|
+
def metrics
|
|
7
|
+
history = {}
|
|
8
|
+
endpoints.each do |endpoint|
|
|
9
|
+
endpoint.api.fetch_global_history_metrics.data.metrics.each do |item|
|
|
10
|
+
history[item.name] ||= []
|
|
11
|
+
history[item.name] << {
|
|
12
|
+
name: endpoint.name,
|
|
13
|
+
data: item.history.map do |i|
|
|
14
|
+
[i.key, i.value]
|
|
15
|
+
end.to_h
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
history
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<div class="row column full-height">
|
|
2
|
+
<%= timeline [], id: "participatoryProcessesChart", height: "100%" %>
|
|
3
|
+
</div>
|
|
4
|
+
<script>
|
|
5
|
+
(function() {
|
|
6
|
+
var rows = [];
|
|
7
|
+
<% timeline_graph.each do |row| %>
|
|
8
|
+
rows.push([
|
|
9
|
+
"<%= row[:name] %>",
|
|
10
|
+
"<%= row[:title] %>",
|
|
11
|
+
new Date("<%= row[:start_date] %>"),
|
|
12
|
+
new Date("<%= row[:end_date] %>")
|
|
13
|
+
]);
|
|
14
|
+
<% end %>
|
|
15
|
+
|
|
16
|
+
var drawChart = function() {
|
|
17
|
+
var dataTable = new google.visualization.DataTable();
|
|
18
|
+
dataTable.addColumn({ type: 'string', id: 'Platform' });
|
|
19
|
+
dataTable.addColumn({ type: 'string', id: 'Process' });
|
|
20
|
+
dataTable.addColumn({ type: 'date', id: 'Start' });
|
|
21
|
+
dataTable.addColumn({ type: 'date', id: 'End' });
|
|
22
|
+
dataTable.addRows(rows);
|
|
23
|
+
var chart = Chartkick.charts["participatoryProcessesChart"];
|
|
24
|
+
chart.getChartObject().draw(dataTable);
|
|
25
|
+
|
|
26
|
+
// hack the real height
|
|
27
|
+
var h = parseInt($("#participatoryProcessesChart div:first-child div:first-child div:first-child div svg").attr("height")) + 70;
|
|
28
|
+
chart.getChartObject().draw(dataTable, {
|
|
29
|
+
height: h,
|
|
30
|
+
// hAxis: {
|
|
31
|
+
// minValue: new Date(2019, 0, 0),
|
|
32
|
+
// maxValue: new Date(2020, 0, 0)
|
|
33
|
+
// },
|
|
34
|
+
width: "100%",
|
|
35
|
+
timeline: {
|
|
36
|
+
// showRowLabels: false,
|
|
37
|
+
rowLabelStyle: {
|
|
38
|
+
fontSize: 16
|
|
39
|
+
},
|
|
40
|
+
// showBarLabels: false
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
// extra svg tweaks
|
|
44
|
+
$('#participatoryProcessesChart div div div svg g:first text').attr({'x': 5, "text-anchor": "start", "font-weight": "bold"})
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
google.charts.setOnLoadCallback(drawChart);
|
|
48
|
+
|
|
49
|
+
// Rewdraw on tab appearance
|
|
50
|
+
$("[data-tabs]").on("change.zf.tabs", drawChart);
|
|
51
|
+
// redraw graph when window resize is completed
|
|
52
|
+
$(window).on('resizeEnd', drawChart);
|
|
53
|
+
|
|
54
|
+
}());
|
|
55
|
+
</script>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "chartkick"
|
|
4
|
+
require "chartkick/helper"
|
|
5
|
+
|
|
6
|
+
module Decidim
|
|
7
|
+
module ComparativeStats
|
|
8
|
+
# This cell renders an graph with participatory processes
|
|
9
|
+
# the `model` is expected to be a collection of API endpoints
|
|
10
|
+
#
|
|
11
|
+
class ParticipatoryProcessesTimelineCell < Decidim::ViewModel
|
|
12
|
+
include Chartkick::Helper
|
|
13
|
+
|
|
14
|
+
def show
|
|
15
|
+
return unless model
|
|
16
|
+
|
|
17
|
+
render :show
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def endpoints
|
|
21
|
+
model
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def timeline_graph
|
|
25
|
+
rows = []
|
|
26
|
+
endpoints.each do |endpoint|
|
|
27
|
+
endpoint.api.fetch_participatory_processes.data.participatory_processes.each do |item|
|
|
28
|
+
next unless item.start_date
|
|
29
|
+
|
|
30
|
+
start_date = Date.parse(item.start_date)
|
|
31
|
+
end_date = Date.parse(item.end_date.presence || Date.current.end_of_year.to_s)
|
|
32
|
+
# let's not trust people writing proper ordered dates
|
|
33
|
+
start_date, end_date = end_date, start_date if start_date > end_date
|
|
34
|
+
rows << {
|
|
35
|
+
name: endpoint.name,
|
|
36
|
+
title: first_text(item.title.translations),
|
|
37
|
+
start_date: start_date,
|
|
38
|
+
end_date: end_date
|
|
39
|
+
}
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
rows
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def first_text(translations)
|
|
46
|
+
item = translations.find { |i| i.text.present? }
|
|
47
|
+
item&.text || ""
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<template id="marker-popup-meeting">
|
|
2
|
+
<div class="map-info__content">
|
|
3
|
+
<h3>${title}</h3>
|
|
4
|
+
<div id="bodyContent">
|
|
5
|
+
<p>{{html description}}</p>
|
|
6
|
+
<div class="map__date-adress">
|
|
7
|
+
<div class="card__datetime">
|
|
8
|
+
<div class="card__datetime__date">
|
|
9
|
+
${startTimeDay} <span class="card__datetime__month">${startTimeMonth} ${startTimeYear}</span>
|
|
10
|
+
</div>
|
|
11
|
+
<div class="card__datetime__time">${starTime}</div>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="address card__extra">
|
|
14
|
+
<div class="address__icon">{{html icon}}</div>
|
|
15
|
+
<div class="address__details">
|
|
16
|
+
<strong>{{html location}}</strong><br>
|
|
17
|
+
<span>${address}</span><br>
|
|
18
|
+
<span>{{html locationHints}}</span>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="map-info__button">
|
|
23
|
+
<a href="${link}" class="button button--sc">
|
|
24
|
+
<%= t("decidim.meetings.meetings_map.view_meeting") %>
|
|
25
|
+
</a>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<template id="marker-popup-proposal">
|
|
32
|
+
<div class="map-info__content">
|
|
33
|
+
<h3>${title}</h3>
|
|
34
|
+
<div id="bodyContent">
|
|
35
|
+
<p>{{html body}}</p>
|
|
36
|
+
<div class="map__date-adress">
|
|
37
|
+
<div class="address card__extra">
|
|
38
|
+
<div class="address__icon">{{html icon}}</div>
|
|
39
|
+
<div class="address__details">
|
|
40
|
+
<span>${address}</span><br>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="map-info__button">
|
|
45
|
+
<a href="${link}" class="button button--sc">
|
|
46
|
+
<%= t("decidim.proposals.proposals.index.view_proposal") %>
|
|
47
|
+
</a>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|
|
52
|
+
|
|
53
|
+
<div class="row column full-height">
|
|
54
|
+
<%= content_tag(:div, "", id: "geocoded_events", class: "map", data: { geocoded_events: geocoded_events }) %>
|
|
55
|
+
</div>
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module ComparativeStats
|
|
5
|
+
# This cell renders a map with participatory spaces
|
|
6
|
+
# the `model` is spected to be a collection of API endpoints
|
|
7
|
+
class ParticipatorySpacesGeocodedEventsCell < Decidim::ViewModel
|
|
8
|
+
include Decidim::MapHelper
|
|
9
|
+
include Decidim::LayoutHelper
|
|
10
|
+
|
|
11
|
+
def show
|
|
12
|
+
return unless model
|
|
13
|
+
|
|
14
|
+
render :show
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def endpoints
|
|
18
|
+
model
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def geocoded_events
|
|
22
|
+
@events = {}
|
|
23
|
+
|
|
24
|
+
endpoints.each do |endpoint|
|
|
25
|
+
# skip endpoints under version 0.21
|
|
26
|
+
next unless endpoint.api.valid? "0.21"
|
|
27
|
+
|
|
28
|
+
@events[endpoint.id] = {
|
|
29
|
+
name: endpoint.name,
|
|
30
|
+
meetings: {},
|
|
31
|
+
proposals: {}
|
|
32
|
+
}
|
|
33
|
+
results = endpoint.api.fetch_global_events
|
|
34
|
+
next unless results.respond_to? :data
|
|
35
|
+
|
|
36
|
+
results.data.assemblies.each do |assembly|
|
|
37
|
+
assembly.components.each do |component|
|
|
38
|
+
if component.respond_to? :meetings
|
|
39
|
+
component.meetings.edges.each do |edge|
|
|
40
|
+
add_meeting(edge.node.to_h, endpoint, assembly, component, :assemblies)
|
|
41
|
+
end
|
|
42
|
+
elsif componet.respond_to? :proposals
|
|
43
|
+
component.proposals.edges.each do |edge|
|
|
44
|
+
add_proposal(edge.node.to_h, endpoint, assembly, component, :assemblies)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
results.data.participatory_processes.each do |participatory_process|
|
|
50
|
+
participatory_process.components.each do |component|
|
|
51
|
+
if component.respond_to? :meetings
|
|
52
|
+
component.meetings.edges.each do |edge|
|
|
53
|
+
add_meeting(edge.node.to_h, endpoint, participatory_process, component, :processes)
|
|
54
|
+
end
|
|
55
|
+
elsif component.respond_to? :proposals
|
|
56
|
+
component.proposals.edges.each do |edge|
|
|
57
|
+
add_proposal(edge.node.to_h, endpoint, participatory_process, component, :processes)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
@events.to_json
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def first_translation(text)
|
|
67
|
+
return text unless text.is_a? Hash
|
|
68
|
+
|
|
69
|
+
translations = text["translations"]
|
|
70
|
+
if translations
|
|
71
|
+
item = translations.find { |i| i["text"].present? }
|
|
72
|
+
return item["text"] || "" if item
|
|
73
|
+
end
|
|
74
|
+
""
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def add_proposal(proposal, endpoint, participatory_space, component, type)
|
|
78
|
+
@events[endpoint.id][:proposals]["#{type}_proposal_#{proposal["id"]}"] = {
|
|
79
|
+
latitude: proposal["coordinates"]["latitude"],
|
|
80
|
+
longitude: proposal["coordinates"]["longitude"],
|
|
81
|
+
address: proposal["address"],
|
|
82
|
+
title: first_translation(proposal["title"]),
|
|
83
|
+
body: truncate(first_translation(proposal["body"]), length: 100),
|
|
84
|
+
icon: icon("proposals", width: 40, height: 70, remove_icon_class: true),
|
|
85
|
+
link: endpoint.endpoint.remove("api") << "#{type}/#{participatory_space.slug}/f/#{component.id}/proposals/#{proposal["id"]}"
|
|
86
|
+
}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def add_meeting(meeting, endpoint, participatory_space, component, type)
|
|
90
|
+
@events[endpoint.id][:meetings]["#{type}_meeting_#{meeting["id"]}"] = {
|
|
91
|
+
latitude: meeting["coordinates"]["latitude"],
|
|
92
|
+
longitude: meeting["coordinates"]["longitude"],
|
|
93
|
+
address: meeting["address"],
|
|
94
|
+
title: first_translation(meeting["title"]),
|
|
95
|
+
# description: first_translation(meeting["description"]),
|
|
96
|
+
startTimeDay: l(meeting["startTime"].to_date, format: "%d"),
|
|
97
|
+
startTimeMonth: l(meeting["startTime"].to_date, format: "%B"),
|
|
98
|
+
startTimeYear: l(meeting["startTime"].to_date, format: "%Y"),
|
|
99
|
+
startTime: "#{meeting["startTime"].to_date.strftime("%H:%M")} - #{meeting["endTime"].to_date.strftime("%H:%M")}",
|
|
100
|
+
icon: icon("meetings", width: 40, height: 70, remove_icon_class: true),
|
|
101
|
+
location: first_translation(meeting["location"]),
|
|
102
|
+
locationHints: first_translation(meeting["location_hints"]),
|
|
103
|
+
link: endpoint.endpoint.remove("api") << "#{type}/#{participatory_space.slug}/f/#{component.id}/meetings/#{meeting["id"]}"
|
|
104
|
+
}
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module ComparativeStats
|
|
5
|
+
module Admin
|
|
6
|
+
# A command with all the business logic when creating an endpoint
|
|
7
|
+
class CreateEndpoint < Rectify::Command
|
|
8
|
+
# Public: Initializes the command.
|
|
9
|
+
#
|
|
10
|
+
# form - A form object with the params.
|
|
11
|
+
def initialize(form)
|
|
12
|
+
@form = form
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Executes the command. Broadcasts these events:
|
|
16
|
+
#
|
|
17
|
+
# - :ok when everything is valid.
|
|
18
|
+
# - :invalid if the form wasn't valid and we couldn't proceed.
|
|
19
|
+
#
|
|
20
|
+
# Returns nothing.
|
|
21
|
+
def call
|
|
22
|
+
return broadcast(:invalid) if form.invalid?
|
|
23
|
+
|
|
24
|
+
create_endpoint
|
|
25
|
+
broadcast(:ok)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
attr_reader :form
|
|
31
|
+
|
|
32
|
+
def create_endpoint
|
|
33
|
+
Decidim.traceability.create!(
|
|
34
|
+
Decidim::ComparativeStats::Endpoint,
|
|
35
|
+
form.current_user,
|
|
36
|
+
endpoint: form.endpoint,
|
|
37
|
+
name: form.context.api.name_and_version.application_name,
|
|
38
|
+
api_version: form.context.api.name_and_version.version,
|
|
39
|
+
organization: form.current_organization,
|
|
40
|
+
active: form.active
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module ComparativeStats
|
|
5
|
+
module Admin
|
|
6
|
+
# A command with all the business logic when destroying an endpoint
|
|
7
|
+
class DestroyEndpoint < Rectify::Command
|
|
8
|
+
# Public: Initializes the command.
|
|
9
|
+
#
|
|
10
|
+
# form - A form object with the params.
|
|
11
|
+
def initialize(endpoint, current_user)
|
|
12
|
+
@endpoint = endpoint
|
|
13
|
+
@current_user = current_user
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Executes the command. Broadcasts these events:
|
|
17
|
+
#
|
|
18
|
+
# - :ok when everything is valid.
|
|
19
|
+
# - :invalid if the form wasn't valid and we couldn't proceed.
|
|
20
|
+
#
|
|
21
|
+
# Returns nothing.
|
|
22
|
+
def call
|
|
23
|
+
destroy_endpoint!
|
|
24
|
+
broadcast(:ok)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
attr_reader :endpoint, :current_user
|
|
30
|
+
|
|
31
|
+
def destroy_endpoint!
|
|
32
|
+
Decidim.traceability.perform_action!(
|
|
33
|
+
:delete,
|
|
34
|
+
endpoint,
|
|
35
|
+
current_user
|
|
36
|
+
) do
|
|
37
|
+
endpoint.destroy!
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module ComparativeStats
|
|
5
|
+
module Admin
|
|
6
|
+
# A command with all the business logic when updating an endpoint
|
|
7
|
+
class UpdateEndpoint < Rectify::Command
|
|
8
|
+
# Public: Initializes the command.
|
|
9
|
+
#
|
|
10
|
+
# form - A form object with the params.
|
|
11
|
+
def initialize(endpoint, form, user)
|
|
12
|
+
@endpoint = endpoint
|
|
13
|
+
@form = form
|
|
14
|
+
@user = user
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Executes the command. Broadcasts these events:
|
|
18
|
+
#
|
|
19
|
+
# - :ok when everything is valid.
|
|
20
|
+
# - :invalid if the form wasn't valid and we couldn't proceed.
|
|
21
|
+
#
|
|
22
|
+
# Returns nothing.
|
|
23
|
+
def call
|
|
24
|
+
return broadcast(:invalid) if form.invalid?
|
|
25
|
+
|
|
26
|
+
update_endpoint!
|
|
27
|
+
broadcast(:ok)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
attr_reader :form
|
|
33
|
+
|
|
34
|
+
def update_endpoint!
|
|
35
|
+
Decidim.traceability.update!(
|
|
36
|
+
@endpoint,
|
|
37
|
+
@user,
|
|
38
|
+
endpoint: form.endpoint,
|
|
39
|
+
name: form.name,
|
|
40
|
+
api_version: form.context.api.name_and_version.version,
|
|
41
|
+
active: form.active
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|