decidim-lausanne-budgets 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +141 -0
- data/Rakefile +93 -0
- data/app/cells/decidim/lausanne/budgets/base_cell.rb +24 -0
- data/app/cells/decidim/lausanne/budgets/budget_cell.rb +23 -0
- data/app/cells/decidim/lausanne/budgets/budget_information_modal/show.erb +21 -0
- data/app/cells/decidim/lausanne/budgets/budget_information_modal_cell.rb +24 -0
- data/app/cells/decidim/lausanne/budgets/budget_list_item/show.erb +21 -0
- data/app/cells/decidim/lausanne/budgets/budget_list_item_cell.rb +43 -0
- data/app/cells/decidim/lausanne/budgets/budget_m/data.erb +12 -0
- data/app/cells/decidim/lausanne/budgets/budget_m/footer.erb +5 -0
- data/app/cells/decidim/lausanne/budgets/budget_m_cell.rb +18 -0
- data/app/cells/decidim/lausanne/budgets/budgets_header/show.erb +7 -0
- data/app/cells/decidim/lausanne/budgets/budgets_header_cell.rb +16 -0
- data/app/cells/decidim/lausanne/budgets/budgets_list/card_list.erb +7 -0
- data/app/cells/decidim/lausanne/budgets/budgets_list/highlighted.erb +11 -0
- data/app/cells/decidim/lausanne/budgets/budgets_list/show.erb +20 -0
- data/app/cells/decidim/lausanne/budgets/budgets_list/voted.erb +43 -0
- data/app/cells/decidim/lausanne/budgets/budgets_list_cell.rb +40 -0
- data/app/cells/decidim/lausanne/budgets/limit_announcement_cell.rb +47 -0
- data/app/cells/decidim/lausanne/budgets/project_cell.rb +23 -0
- data/app/cells/decidim/lausanne/budgets/project_list_item/project_data.erb +19 -0
- data/app/cells/decidim/lausanne/budgets/project_list_item/project_data_vote_button.erb +22 -0
- data/app/cells/decidim/lausanne/budgets/project_list_item/project_image.erb +5 -0
- data/app/cells/decidim/lausanne/budgets/project_list_item/project_text.erb +23 -0
- data/app/cells/decidim/lausanne/budgets/project_list_item/show.erb +5 -0
- data/app/cells/decidim/lausanne/budgets/project_list_item_cell.rb +75 -0
- data/app/cells/decidim/lausanne/budgets/project_m/data.erb +12 -0
- data/app/cells/decidim/lausanne/budgets/project_m/footer.erb +5 -0
- data/app/cells/decidim/lausanne/budgets/project_m_cell.rb +24 -0
- data/app/cells/decidim/lausanne/budgets/project_selected_status_cell.rb +30 -0
- data/app/cells/decidim/lausanne/budgets/project_tags/show.erb +4 -0
- data/app/cells/decidim/lausanne/budgets/project_tags_cell.rb +20 -0
- data/app/cells/decidim/lausanne/budgets/project_voted_hint_cell.rb +35 -0
- data/app/cells/decidim/lausanne/budgets/project_votes_count_cell.rb +46 -0
- data/app/commands/decidim/lausanne/budgets/add_line_item.rb +54 -0
- data/app/commands/decidim/lausanne/budgets/admin/create_budget.rb +50 -0
- data/app/commands/decidim/lausanne/budgets/admin/create_project.rb +71 -0
- data/app/commands/decidim/lausanne/budgets/admin/destroy_budget.rb +44 -0
- data/app/commands/decidim/lausanne/budgets/admin/destroy_project.rb +44 -0
- data/app/commands/decidim/lausanne/budgets/admin/import_proposals_to_budgets.rb +87 -0
- data/app/commands/decidim/lausanne/budgets/admin/update_budget.rb +50 -0
- data/app/commands/decidim/lausanne/budgets/admin/update_project.rb +79 -0
- data/app/commands/decidim/lausanne/budgets/cancel_order.rb +46 -0
- data/app/commands/decidim/lausanne/budgets/checkout.rb +43 -0
- data/app/commands/decidim/lausanne/budgets/command.rb +16 -0
- data/app/commands/decidim/lausanne/budgets/create_user_record.rb +39 -0
- data/app/commands/decidim/lausanne/budgets/remove_line_item.rb +40 -0
- data/app/commands/decidim/lausanne/budgets/update_user_record.rb +40 -0
- data/app/controllers/concerns/decidim/lausanne/budgets/needs_current_order.rb +52 -0
- data/app/controllers/concerns/decidim/lausanne/budgets/orderable.rb +54 -0
- data/app/controllers/decidim/lausanne/budgets/admin/application_controller.rb +34 -0
- data/app/controllers/decidim/lausanne/budgets/admin/attachment_collections_controller.rb +27 -0
- data/app/controllers/decidim/lausanne/budgets/admin/attachments_controller.rb +28 -0
- data/app/controllers/decidim/lausanne/budgets/admin/lausanne_budgets_controller.rb +105 -0
- data/app/controllers/decidim/lausanne/budgets/admin/projects_controller.rb +98 -0
- data/app/controllers/decidim/lausanne/budgets/admin/proposals_imports_controller.rb +43 -0
- data/app/controllers/decidim/lausanne/budgets/application_controller.rb +77 -0
- data/app/controllers/decidim/lausanne/budgets/lausanne_budgets_controller.rb +29 -0
- data/app/controllers/decidim/lausanne/budgets/line_items_controller.rb +63 -0
- data/app/controllers/decidim/lausanne/budgets/orders_controller.rb +59 -0
- data/app/controllers/decidim/lausanne/budgets/projects_controller.rb +103 -0
- data/app/controllers/decidim/lausanne/budgets/user_records_controller.rb +121 -0
- data/app/forms/decidim/lausanne/budgets/admin/component_form.rb +93 -0
- data/app/forms/decidim/lausanne/budgets/admin/lausanne_budget_form.rb +41 -0
- data/app/forms/decidim/lausanne/budgets/admin/project_form.rb +96 -0
- data/app/forms/decidim/lausanne/budgets/admin/project_import_proposals_form.rb +52 -0
- data/app/forms/decidim/lausanne/budgets/user_record_form.rb +61 -0
- data/app/helpers/decidim/lausanne/budgets/admin/application_helper.rb +15 -0
- data/app/helpers/decidim/lausanne/budgets/application_helper.rb +26 -0
- data/app/helpers/decidim/lausanne/budgets/projects_helper.rb +103 -0
- data/app/jobs/decidim/lausanne/budgets/send_order_summary_job.rb +17 -0
- data/app/mailers/decidim/lausanne/budgets/order_summary_mailer.rb +38 -0
- data/app/models/decidim/lausanne/budgets/application_record.rb +12 -0
- data/app/models/decidim/lausanne/budgets/lausanne_budget.rb +37 -0
- data/app/models/decidim/lausanne/budgets/line_item.rb +23 -0
- data/app/models/decidim/lausanne/budgets/order.rb +204 -0
- data/app/models/decidim/lausanne/budgets/project.rb +129 -0
- data/app/models/decidim/lausanne/budgets/user_record.rb +28 -0
- data/app/packs/entrypoints/decidim_lausanne_budgets.js +2 -0
- data/app/packs/images/decidim/lausanne/budgets/icon.svg +1 -0
- data/app/packs/images/decidim/lausanne/budgets/lausanneparticipe.gif +0 -0
- data/app/packs/src/decidim/lausanne/budgets/index.js +1 -0
- data/app/packs/src/decidim/lausanne/budgets/progressFixed.js.es6 +23 -0
- data/app/packs/src/decidim/lausanne/budgets/projects.js.es6 +66 -0
- data/app/packs/stylesheets/decidim/lausanne/budgets/_budgets.scss +13 -0
- data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_budget-list.scss +195 -0
- data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_budget-meter.scss +85 -0
- data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_print.scss +73 -0
- data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_progress.scss +25 -0
- data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_proposal_link.scss +38 -0
- data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_share_buttons.scss +15 -0
- data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_user_record_form.scss +8 -0
- data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_votation-progress.scss +100 -0
- data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_voting-rules.scss +20 -0
- data/app/permissions/decidim/lausanne/budgets/admin/permissions.rb +49 -0
- data/app/permissions/decidim/lausanne/budgets/permissions.rb +63 -0
- data/app/presenters/decidim/lausanne/budgets/admin_log/budget_presenter.rb +44 -0
- data/app/presenters/decidim/lausanne/budgets/admin_log/project_presenter.rb +44 -0
- data/app/queries/decidim/lausanne/budgets/filtered_projects.rb +47 -0
- data/app/queries/decidim/lausanne/budgets/metrics/budget_followers_metric_measure.rb +34 -0
- data/app/queries/decidim/lausanne/budgets/metrics/budget_participants_metric_measure.rb +29 -0
- data/app/queries/decidim/lausanne/budgets/query.rb +16 -0
- data/app/serializers/decidim/lausanne/budgets/data_portability_budgets_order_serializer.rb +46 -0
- data/app/services/decidim/lausanne/budgets/project_search.rb +65 -0
- data/app/services/decidim/lausanne/budgets/project_search_rs.rb +13 -0
- data/app/views/decidim/lausanne/budgets/admin/lausanne_budgets/_form.html.erb +23 -0
- data/app/views/decidim/lausanne/budgets/admin/lausanne_budgets/edit.html.erb +7 -0
- data/app/views/decidim/lausanne/budgets/admin/lausanne_budgets/index.html.erb +75 -0
- data/app/views/decidim/lausanne/budgets/admin/lausanne_budgets/new.html.erb +7 -0
- data/app/views/decidim/lausanne/budgets/admin/projects/_form.html.erb +47 -0
- data/app/views/decidim/lausanne/budgets/admin/projects/edit.html.erb +7 -0
- data/app/views/decidim/lausanne/budgets/admin/projects/index.html.erb +82 -0
- data/app/views/decidim/lausanne/budgets/admin/projects/new.html.erb +7 -0
- data/app/views/decidim/lausanne/budgets/admin/projects/proposals_picker.html.erb +1 -0
- data/app/views/decidim/lausanne/budgets/admin/proposals_imports/new.html.erb +32 -0
- data/app/views/decidim/lausanne/budgets/lausanne_budgets/index.html.erb +5 -0
- data/app/views/decidim/lausanne/budgets/line_items/update_budget.js.erb +41 -0
- data/app/views/decidim/lausanne/budgets/order_summary_mailer/order_summary.html.erb +22 -0
- data/app/views/decidim/lausanne/budgets/orders/show.html.erb +71 -0
- data/app/views/decidim/lausanne/budgets/projects/_budget_confirm.html.erb +37 -0
- data/app/views/decidim/lausanne/budgets/projects/_budget_excess.html.erb +14 -0
- data/app/views/decidim/lausanne/budgets/projects/_budget_summary.html.erb +95 -0
- data/app/views/decidim/lausanne/budgets/projects/_count.html.erb +1 -0
- data/app/views/decidim/lausanne/budgets/projects/_filters.html.erb +34 -0
- data/app/views/decidim/lausanne/budgets/projects/_filters_small_view.html.erb +18 -0
- data/app/views/decidim/lausanne/budgets/projects/_linked_projects.html.erb +12 -0
- data/app/views/decidim/lausanne/budgets/projects/_order_progress.html.erb +32 -0
- data/app/views/decidim/lausanne/budgets/projects/_order_selected_projects.html.erb +27 -0
- data/app/views/decidim/lausanne/budgets/projects/_order_total_budget.html.erb +7 -0
- data/app/views/decidim/lausanne/budgets/projects/_project.html.erb +1 -0
- data/app/views/decidim/lausanne/budgets/projects/_project_budget_button.html.erb +46 -0
- data/app/views/decidim/lausanne/budgets/projects/_projects.html.erb +13 -0
- data/app/views/decidim/lausanne/budgets/projects/_user_record_form.html.erb +40 -0
- data/app/views/decidim/lausanne/budgets/projects/_votation_banner.html.erb +71 -0
- data/app/views/decidim/lausanne/budgets/projects/index.html.erb +36 -0
- data/app/views/decidim/lausanne/budgets/projects/index.js.erb +10 -0
- data/app/views/decidim/lausanne/budgets/projects/show.html.erb +81 -0
- data/app/views/decidim/lausanne/budgets/user_records/edit.html.erb +6 -0
- data/app/views/decidim/proposals/proposals/show.html.erb +172 -0
- data/app/views/layouts/lausanne_budgets/print.erb +12 -0
- data/config/assets.rb +11 -0
- data/config/initializers/social_share.rb +3 -0
- data/config/locales/fr.yml +381 -0
- data/config/routes.rb +7 -0
- data/db/migrate/20170127114122_create_lausanne_projects.rb +15 -0
- data/db/migrate/20170127114123_create_lausanne_user_records.rb +14 -0
- data/db/migrate/20170130095615_create_lausanne_orders.rb +16 -0
- data/db/migrate/20170130101825_create_lausanne_line_items.rb +12 -0
- data/db/migrate/20170215132708_add_lausanne_reference_to_projects.rb +13 -0
- data/db/migrate/20200617105120_create_decidim_lausanne_budgets.rb +15 -0
- data/db/migrate/20200629134013_add_lausanne_budget_reference_to_project.rb +7 -0
- data/db/migrate/20200706142609_add_lausanne_budget_reference_to_order.rb +7 -0
- data/db/migrate/20200714103519_move_lausanne_budgets_to_own_model.rb +109 -0
- data/db/migrate/20200717140012_add_lausanne_scope_to_budgets.rb +7 -0
- data/db/migrate/20200728075039_add_lausanne_selected_at_to_project.rb +7 -0
- data/db/migrate/20200804175222_lausanne_votes_enabled_to_votes_choices.rb +35 -0
- data/db/migrate/20200827154129_add_lausanne_commentable_counter_cache_to_projects.rb +9 -0
- data/db/migrate/20210310120613_add_lausanne_followable_counter_cache_to_budgets.rb +16 -0
- data/db/migrate/20210508180613_add_checkboxes_to_user_record.rb +9 -0
- data/db/migrate/20221001151237_add_excerpt_to_decidim_lausanne_budgets_project.rb +7 -0
- data/lib/decidim/lausanne/budgets/admin.rb +12 -0
- data/lib/decidim/lausanne/budgets/admin_engine.rb +40 -0
- data/lib/decidim/lausanne/budgets/component.rb +107 -0
- data/lib/decidim/lausanne/budgets/current_user_record_middleware.rb +17 -0
- data/lib/decidim/lausanne/budgets/engine.rb +57 -0
- data/lib/decidim/lausanne/budgets/project_serializer.rb +83 -0
- data/lib/decidim/lausanne/budgets/seeds/Exampledocument.pdf +0 -0
- data/lib/decidim/lausanne/budgets/seeds/city.jpeg +0 -0
- data/lib/decidim/lausanne/budgets/test/factories.rb +169 -0
- data/lib/decidim/lausanne/budgets/version.rb +15 -0
- data/lib/decidim/lausanne/budgets/workflows/all.rb +22 -0
- data/lib/decidim/lausanne/budgets/workflows/base.rb +140 -0
- data/lib/decidim/lausanne/budgets/workflows/one.rb +35 -0
- data/lib/decidim/lausanne/budgets/workflows.rb +19 -0
- data/lib/decidim/lausanne/budgets.rb +17 -0
- metadata +372 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
.budget-summary__total {
|
2
|
+
margin-bottom: 0.5rem;
|
3
|
+
}
|
4
|
+
|
5
|
+
.budget-summary__progressbox {
|
6
|
+
align-items: stretch;
|
7
|
+
margin-bottom: 0.5rem;
|
8
|
+
|
9
|
+
@include breakpoint(smallmedium down) {
|
10
|
+
text-align: center;
|
11
|
+
}
|
12
|
+
|
13
|
+
@include breakpoint(medium) {
|
14
|
+
display: flex;
|
15
|
+
}
|
16
|
+
|
17
|
+
.button {
|
18
|
+
margin-bottom: 0;
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
.progressbox-fixed-wrapper {
|
23
|
+
position: fixed;
|
24
|
+
top: 0;
|
25
|
+
left: 0;
|
26
|
+
right: 0;
|
27
|
+
z-index: 2;
|
28
|
+
background: $white;
|
29
|
+
box-shadow: 0 2px 7px rgba(black, 0.1);
|
30
|
+
display: none;
|
31
|
+
|
32
|
+
&.is-progressbox-visible {
|
33
|
+
display: block;
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
.budget-summary__progressbox--fixed {
|
38
|
+
margin: auto;
|
39
|
+
max-width: $global-width;
|
40
|
+
padding: 1rem 2rem;
|
41
|
+
|
42
|
+
@include breakpoint(mediumlarge) {
|
43
|
+
padding: 1rem 4rem;
|
44
|
+
}
|
45
|
+
|
46
|
+
display: flex;
|
47
|
+
}
|
48
|
+
|
49
|
+
.budget-progress {
|
50
|
+
flex-grow: 1;
|
51
|
+
margin-bottom: 0.5rem;
|
52
|
+
min-height: 1.5rem;
|
53
|
+
|
54
|
+
@include breakpoint(medium) {
|
55
|
+
min-height: 2rem;
|
56
|
+
margin-bottom: 0;
|
57
|
+
margin-right: 1rem;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
.budget-progress--fixed {
|
62
|
+
min-height: 2rem;
|
63
|
+
margin-bottom: 0;
|
64
|
+
margin-right: 1rem;
|
65
|
+
}
|
66
|
+
|
67
|
+
.budget-progress__meter {
|
68
|
+
min-width: 0.1%;
|
69
|
+
}
|
70
|
+
|
71
|
+
.budget-summary__selected {
|
72
|
+
border-top: $border;
|
73
|
+
padding-top: 0.5rem;
|
74
|
+
padding-bottom: 0.5rem;
|
75
|
+
}
|
76
|
+
.budget-summary__excerpt {
|
77
|
+
font-style: italic;
|
78
|
+
}
|
79
|
+
.budget-summary__selected-list {
|
80
|
+
margin-top: 2rem;
|
81
|
+
}
|
82
|
+
|
83
|
+
.budget-summary__selected-number {
|
84
|
+
margin: 0 0.5rem;
|
85
|
+
}
|
@@ -0,0 +1,73 @@
|
|
1
|
+
body.lausanne_budget_print {
|
2
|
+
background: white;
|
3
|
+
color: black;
|
4
|
+
padding: 5% 10%;
|
5
|
+
font-family: Open Sans, sans-serif;
|
6
|
+
|
7
|
+
h1{
|
8
|
+
margin-top: 32px;
|
9
|
+
font-size: 120%;
|
10
|
+
}
|
11
|
+
p, strong {
|
12
|
+
font-size: 14px;
|
13
|
+
}
|
14
|
+
a, button {
|
15
|
+
color: var(--primary);
|
16
|
+
text-decoration: underline;
|
17
|
+
}
|
18
|
+
table {
|
19
|
+
border-collapse: collapse;
|
20
|
+
margin: 1em unset;
|
21
|
+
td {
|
22
|
+
padding: 0.1em 0.5em;
|
23
|
+
}
|
24
|
+
tr:nth-child(2n + 1) > td {
|
25
|
+
background: #EFEFEF;
|
26
|
+
}
|
27
|
+
&.personal-data{
|
28
|
+
margin-left: auto;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
.first-col{
|
33
|
+
min-width: 280px;
|
34
|
+
}
|
35
|
+
.vote {
|
36
|
+
margin-top: 48px;
|
37
|
+
width: 99%;
|
38
|
+
td {
|
39
|
+
padding: 0.5em 1em;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
$size: 38px;
|
43
|
+
|
44
|
+
.social-share-button {
|
45
|
+
.ssb-icon {
|
46
|
+
background-size: $size $size;
|
47
|
+
height: $size;
|
48
|
+
width: $size;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
@media (min-width:1025px) {
|
52
|
+
.social-share-button .ssb-icon.ssb-whatsapp_app, .shares .social-share-button .ssb-icon.ssb-whatsapp_app{
|
53
|
+
display:none !important;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
.actions {
|
57
|
+
margin-top: 64px;
|
58
|
+
display: flex;
|
59
|
+
gap: 1em;
|
60
|
+
text-align: center;
|
61
|
+
align-items: center;
|
62
|
+
justify-content: center;
|
63
|
+
}
|
64
|
+
.shares{
|
65
|
+
text-align: center;
|
66
|
+
margin-top: 64px;
|
67
|
+
}
|
68
|
+
@media print {
|
69
|
+
.shares, .actions{
|
70
|
+
display: none;
|
71
|
+
}
|
72
|
+
}
|
73
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
//Foundation progress extension
|
2
|
+
|
3
|
+
.progress {
|
4
|
+
position: relative;
|
5
|
+
}
|
6
|
+
|
7
|
+
.progress-meter--minimum {
|
8
|
+
background: repeating-linear-gradient(
|
9
|
+
-55deg,
|
10
|
+
rgba(white, 0.2),
|
11
|
+
rgba(white, 0.2) 8px,
|
12
|
+
rgba(black, 0.03) 8px,
|
13
|
+
rgba(black, 0.03) 16px
|
14
|
+
);
|
15
|
+
position: absolute;
|
16
|
+
}
|
17
|
+
|
18
|
+
.progress-meter-text--right {
|
19
|
+
left: auto;
|
20
|
+
min-width: 100%;
|
21
|
+
transform: translate(0, -50%);
|
22
|
+
text-align: right;
|
23
|
+
padding-left: 1rem;
|
24
|
+
padding-right: 0.5rem;
|
25
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
.vote_link {
|
2
|
+
width: 100%;
|
3
|
+
display: flex;
|
4
|
+
gap: 0.5rem;
|
5
|
+
padding: 30px;
|
6
|
+
background: var(--primary);
|
7
|
+
color: white;
|
8
|
+
box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);
|
9
|
+
margin-top: 128px;
|
10
|
+
margin-bottom: 64px;
|
11
|
+
h3 {
|
12
|
+
font-weight: 900;
|
13
|
+
}
|
14
|
+
p {
|
15
|
+
font-size: 110%;
|
16
|
+
a {
|
17
|
+
text-decoration: underline;
|
18
|
+
color: white;
|
19
|
+
&:hover{
|
20
|
+
color: white;
|
21
|
+
opacity: 0.8;
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
.vote_link__text {
|
26
|
+
flex: 1;
|
27
|
+
}
|
28
|
+
.vote_link__action {
|
29
|
+
align-self: flex-end;
|
30
|
+
background: white;
|
31
|
+
color: var(--primary);
|
32
|
+
&:hover {
|
33
|
+
background: white;
|
34
|
+
color: var(--primary);
|
35
|
+
opacity: 0.8;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
.shares .social-share-button .ssb-icon.ssb-whatsapp_app {
|
2
|
+
display: inline-block;
|
3
|
+
}
|
4
|
+
|
5
|
+
$size: 26px;
|
6
|
+
.shares {
|
7
|
+
text-align: center;
|
8
|
+
}
|
9
|
+
.shares .social-share-button {
|
10
|
+
.ssb-icon {
|
11
|
+
background-size: $size $size;
|
12
|
+
height: $size;
|
13
|
+
width: $size;
|
14
|
+
}
|
15
|
+
}
|
@@ -0,0 +1,100 @@
|
|
1
|
+
$block: "votation_banner";
|
2
|
+
.#{$block} {
|
3
|
+
padding: 1rem;
|
4
|
+
position: fixed;
|
5
|
+
bottom: 0;
|
6
|
+
width: 100%;
|
7
|
+
z-index: 999;
|
8
|
+
background: white;
|
9
|
+
right: 0;
|
10
|
+
left: 0;
|
11
|
+
display: flex;
|
12
|
+
flex-wrap: wrap;
|
13
|
+
flex-direction: column-reverse;
|
14
|
+
gap: 0.5rem;
|
15
|
+
-webkit-box-shadow: 0px -2px 6px 0px rgba(94, 111, 101, 0.6);
|
16
|
+
-moz-box-shadow: 0px -2px 6px 0px rgba(94, 111, 101,0.6);
|
17
|
+
box-shadow: 0px -2px 6px 0px rgba(94, 111, 101,0.6);
|
18
|
+
|
19
|
+
@include breakpoint(medium) {
|
20
|
+
flex-direction: row;
|
21
|
+
gap: 0;
|
22
|
+
padding-left: 3rem;
|
23
|
+
padding-right: 3rem;
|
24
|
+
}
|
25
|
+
|
26
|
+
}
|
27
|
+
.#{$block}--checked_out {
|
28
|
+
border-top-color: transparent;
|
29
|
+
border-top-width: 0;
|
30
|
+
background: rgb(222, 247, 232);
|
31
|
+
}
|
32
|
+
.#{$block}__header {
|
33
|
+
flex: 2;
|
34
|
+
display: flex;
|
35
|
+
align-items: center;
|
36
|
+
}
|
37
|
+
.#{$block}__title {
|
38
|
+
text-transform: none;
|
39
|
+
font-size: 100%;
|
40
|
+
width: 100%;
|
41
|
+
margin-bottom: 0;
|
42
|
+
text-align: center;
|
43
|
+
@include breakpoint(medium) {
|
44
|
+
text-align: left;
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
.#{$block}__buttons {
|
49
|
+
display: flex;
|
50
|
+
align-items: flex-end;
|
51
|
+
gap: 1rem;
|
52
|
+
}
|
53
|
+
.#{$block}__actions {
|
54
|
+
margin-top: 1rem;
|
55
|
+
.#{$block}__actions-container {
|
56
|
+
display: flex;
|
57
|
+
flex: 1;
|
58
|
+
align-items: center;
|
59
|
+
}
|
60
|
+
@include breakpoint(large) {
|
61
|
+
margin-top: 0;
|
62
|
+
display: block;
|
63
|
+
position: absolute;
|
64
|
+
right: 3rem;
|
65
|
+
top: 12px;
|
66
|
+
.#{$block}__actions-container {
|
67
|
+
flex: 0;
|
68
|
+
display: block;
|
69
|
+
width: 200%;
|
70
|
+
display: flex;
|
71
|
+
gap: 0.5rem;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
justify-content: center;
|
75
|
+
gap: 1rem;
|
76
|
+
button {
|
77
|
+
margin: 0;
|
78
|
+
}
|
79
|
+
button.primary, button.primary.small,
|
80
|
+
button.primary[disabled], button.primary.small[disabled] {
|
81
|
+
&:focus, &, &:hover {
|
82
|
+
color: white;
|
83
|
+
background: var(--primary);
|
84
|
+
}
|
85
|
+
font-weight: 600;
|
86
|
+
}
|
87
|
+
button.primary[disabled], button.primary.small[disabled] {
|
88
|
+
&, &:focus, &:hover{
|
89
|
+
opacity: 0.25;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
93
|
+
.#{$block}__helptext {
|
94
|
+
display: block;
|
95
|
+
padding-left: 0.5rem;
|
96
|
+
text-align:center;
|
97
|
+
opacity: 1;
|
98
|
+
color: var(--primary);
|
99
|
+
font-weight: bold;
|
100
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
.voting-rules {
|
2
|
+
.callout .button.primary {
|
3
|
+
color: #fff;
|
4
|
+
background-color: var(--primary);
|
5
|
+
&.hollow{ background-color: transparent; color: var(--primary);}
|
6
|
+
}
|
7
|
+
.callout .button.secondary {
|
8
|
+
color: #fff;
|
9
|
+
background-color: var(--secondary);
|
10
|
+
&.hollow{ background-color: transparent; color: var(--secondary);}
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
.button.primary, .button.primary.disabled, .button.primary[disabled], .button.primary.disabled:hover, .button.primary[disabled]:hover, .button.primary.disabled:focus, .button.primary[disabled]:focus{
|
15
|
+
background-color: var(--primary);
|
16
|
+
}
|
17
|
+
.button.primary:hover, .button.primary:focus{
|
18
|
+
background-color: var(--primary);
|
19
|
+
opacity: 0.87;
|
20
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Lausanne
|
5
|
+
module Budgets
|
6
|
+
module Admin
|
7
|
+
class Permissions < Decidim::DefaultPermissions
|
8
|
+
def permissions
|
9
|
+
return permission_action unless user
|
10
|
+
return permission_action if permission_action.scope != :admin
|
11
|
+
|
12
|
+
case permission_action.subject
|
13
|
+
when :budget
|
14
|
+
case permission_action.action
|
15
|
+
when :create, :read, :export
|
16
|
+
allow!
|
17
|
+
when :update
|
18
|
+
toggle_allow(budget)
|
19
|
+
when :delete, :publish, :unpublish
|
20
|
+
toggle_allow(budget && budget.projects.empty?)
|
21
|
+
end
|
22
|
+
when :project, :projects
|
23
|
+
case permission_action.action
|
24
|
+
when :create
|
25
|
+
permission_action.allow!
|
26
|
+
when :import_proposals
|
27
|
+
permission_action.allow!
|
28
|
+
when :update, :destroy
|
29
|
+
permission_action.allow! if project.present?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
permission_action
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def budget
|
39
|
+
@budget ||= context.fetch(:budget, nil)
|
40
|
+
end
|
41
|
+
|
42
|
+
def project
|
43
|
+
@project ||= context.fetch(:project, nil)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Lausanne
|
5
|
+
module Budgets
|
6
|
+
class Permissions < Decidim::DefaultPermissions
|
7
|
+
def permissions
|
8
|
+
# Delegate the admin permission checks to the admin permissions class
|
9
|
+
return Decidim::Lausanne::Budgets::Admin::Permissions.new(user, permission_action, context).permissions if permission_action.scope == :admin
|
10
|
+
return permission_action if permission_action.scope != :public
|
11
|
+
|
12
|
+
return permission_action unless [:project, :order].include? permission_action.subject
|
13
|
+
|
14
|
+
if permission_action.subject == :project
|
15
|
+
case permission_action.action
|
16
|
+
when :vote
|
17
|
+
can_vote?(false) if can_vote_project?(project || order&.projects&.first)
|
18
|
+
when :report
|
19
|
+
permission_action.allow!
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
can_vote?(true) if permission_action.action == :create && permission_action.subject == :order
|
24
|
+
|
25
|
+
permission_action
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def project
|
31
|
+
@project ||= context.fetch(:project, nil)
|
32
|
+
end
|
33
|
+
|
34
|
+
def order
|
35
|
+
@order ||= context.fetch(:order, nil)
|
36
|
+
end
|
37
|
+
|
38
|
+
def budget
|
39
|
+
@budget ||= context.fetch(:budget, nil)
|
40
|
+
end
|
41
|
+
|
42
|
+
def workflow
|
43
|
+
@workflow ||= context.fetch(:workflow, nil)
|
44
|
+
end
|
45
|
+
|
46
|
+
def can_vote?(active_allow)
|
47
|
+
is_allowed = workflow.vote_allowed?(budget)
|
48
|
+
|
49
|
+
if !is_allowed
|
50
|
+
disallow!
|
51
|
+
elsif active_allow
|
52
|
+
allow!
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def can_vote_project?(a_project)
|
57
|
+
is_allowed = a_project && authorized?(:vote, resource: project)
|
58
|
+
toggle_allow(is_allowed)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Lausanne
|
5
|
+
module Budgets
|
6
|
+
module AdminLog
|
7
|
+
# This class holds the logic to present a `Decidim::Lausanne::Budgets::LausanneBudget`
|
8
|
+
# for the `AdminLog` log.
|
9
|
+
#
|
10
|
+
# Usage should be automatic and you shouldn't need to call this class
|
11
|
+
# directly, but here's an example:
|
12
|
+
#
|
13
|
+
# action_log = Decidim::ActionLog.last
|
14
|
+
# view_helpers # => this comes from the views
|
15
|
+
# BudgetPresenter.new(action_log, view_helpers).present
|
16
|
+
class BudgetPresenter < Decidim::Log::BasePresenter
|
17
|
+
private
|
18
|
+
|
19
|
+
def action_string
|
20
|
+
case action
|
21
|
+
when "create", "delete", "update"
|
22
|
+
"decidim.lausanne_budgets.admin_log.budget.#{action}"
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def diff_fields_mapping
|
29
|
+
{
|
30
|
+
title: :i18n,
|
31
|
+
weight: :integer,
|
32
|
+
description: :i18n,
|
33
|
+
total_budget: :currency
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def i18n_labels_scope
|
38
|
+
"activemodel.attributes.budget"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Lausanne
|
5
|
+
module Budgets
|
6
|
+
module AdminLog
|
7
|
+
# This class holds the logic to present a `Decidim::Lausanne::Budgets::Project``
|
8
|
+
# for the `AdminLog` log.
|
9
|
+
#
|
10
|
+
# Usage should be automatic and you shouldn't need to call this class
|
11
|
+
# directly, but here's an example:
|
12
|
+
#
|
13
|
+
# action_log = Decidim::ActionLog.last
|
14
|
+
# view_helpers # => this comes from the views
|
15
|
+
# ProjectPresenter.new(action_log, view_helpers).present
|
16
|
+
class ProjectPresenter < Decidim::Log::BasePresenter
|
17
|
+
private
|
18
|
+
|
19
|
+
def action_string
|
20
|
+
case action
|
21
|
+
when "create", "delete", "update"
|
22
|
+
"decidim.lausanne_budgets.admin_log.project.#{action}"
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def diff_fields_mapping
|
29
|
+
{
|
30
|
+
budget: :currency,
|
31
|
+
description: :i18n,
|
32
|
+
title: :i18n,
|
33
|
+
decidim_scope_id: :scope
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def i18n_labels_scope
|
38
|
+
"activemodel.attributes.project"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Lausanne
|
5
|
+
module Budgets
|
6
|
+
# A class used to find projects filtered by components and a date range
|
7
|
+
class FilteredProjects < Decidim::Lausanne::Budgets::Query
|
8
|
+
# Syntactic sugar to initialize the class and return the queried objects.
|
9
|
+
#
|
10
|
+
# components - An array of Decidim::Component
|
11
|
+
# start_at - A date to filter resources created after it
|
12
|
+
# end_at - A date to filter resources created before it.
|
13
|
+
def self.for(components, start_at = nil, end_at = nil)
|
14
|
+
new(components, start_at, end_at).query
|
15
|
+
end
|
16
|
+
|
17
|
+
# Initializes the class.
|
18
|
+
#
|
19
|
+
# components - An array of Decidim::Component
|
20
|
+
# start_at - A date to filter resources created after it
|
21
|
+
# end_at - A date to filter resources created before it.
|
22
|
+
def initialize(components, start_at = nil, end_at = nil)
|
23
|
+
@components = components
|
24
|
+
@start_at = start_at
|
25
|
+
@end_at = end_at
|
26
|
+
end
|
27
|
+
|
28
|
+
# Finds the Projects scoped to an array of components and filtered
|
29
|
+
# by a range of dates.
|
30
|
+
def query
|
31
|
+
projects = Decidim::Lausanne::Budgets::Project.where(budget: budgets)
|
32
|
+
projects = projects.where("created_at >= ?", @start_at) if @start_at.present?
|
33
|
+
projects = projects.where("created_at <= ?", @end_at) if @end_at.present?
|
34
|
+
projects
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :components
|
40
|
+
|
41
|
+
def budgets
|
42
|
+
@budgets ||= Decidim::Lausanne::Budgets::LausanneBudget.where(component: components).order(weight: :asc)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Lausanne
|
5
|
+
module Budgets
|
6
|
+
module Metrics
|
7
|
+
# Searches for unique Users following the next objects
|
8
|
+
# - Budgets
|
9
|
+
class BudgetFollowersMetricMeasure < Decidim::MetricMeasure
|
10
|
+
def valid?
|
11
|
+
super && @resource.is_a?(Decidim::Component)
|
12
|
+
end
|
13
|
+
|
14
|
+
def calculate
|
15
|
+
budgets = Decidim::Lausanne::Budgets::LausanneBudget.where(component: @resource)
|
16
|
+
projects = Decidim::Lausanne::Budgets::Project.where(budget: budgets)
|
17
|
+
|
18
|
+
budgets_followers = Decidim::Follow.where(followable: projects).joins(:user)
|
19
|
+
.where("decidim_follows.created_at <= ?", end_time)
|
20
|
+
cumulative_users = budgets_followers.pluck(:loz_user_record_id)
|
21
|
+
|
22
|
+
budgets_followers = budgets_followers.where("decidim_follows.created_at >= ?", start_time)
|
23
|
+
quantity_users = budgets_followers.pluck(:loz_user_record_id)
|
24
|
+
|
25
|
+
{
|
26
|
+
cumulative_users: cumulative_users.uniq,
|
27
|
+
quantity_users: quantity_users.uniq
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Lausanne
|
5
|
+
module Budgets
|
6
|
+
module Metrics
|
7
|
+
# Searches for Participants in the following actions
|
8
|
+
# - Vote a participatory budgeting project (Budgets)
|
9
|
+
class BudgetParticipantsMetricMeasure < Decidim::MetricMeasure
|
10
|
+
def valid?
|
11
|
+
super && @resource.is_a?(Decidim::Component)
|
12
|
+
end
|
13
|
+
|
14
|
+
def calculate
|
15
|
+
budgets = Decidim::Lausanne::Budgets::LausanneBudget.where(component: @resource)
|
16
|
+
orders = Decidim::Lausanne::Budgets::Order.where(budget: budgets)
|
17
|
+
.finished
|
18
|
+
.where("decidim_lausanne_budgets_orders.checked_out_at <= ?", end_time)
|
19
|
+
|
20
|
+
{
|
21
|
+
cumulative_users: orders.pluck(:loz_user_record_id),
|
22
|
+
quantity_users: orders.where("decidim_lausanne_budgets_orders.checked_out_at >= ?", start_time).pluck(:loz_user_record_id)
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Lausanne
|
5
|
+
module Budgets
|
6
|
+
# maintains compatibility with v0.26 which uses Rectify
|
7
|
+
if defined? ::Decidim::Query
|
8
|
+
class Query < ::Decidim::Query
|
9
|
+
end
|
10
|
+
else
|
11
|
+
class Query < ::Rectify::Query
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|