decidim-lausanne-budgets 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +141 -0
  3. data/Rakefile +93 -0
  4. data/app/cells/decidim/lausanne/budgets/base_cell.rb +24 -0
  5. data/app/cells/decidim/lausanne/budgets/budget_cell.rb +23 -0
  6. data/app/cells/decidim/lausanne/budgets/budget_information_modal/show.erb +21 -0
  7. data/app/cells/decidim/lausanne/budgets/budget_information_modal_cell.rb +24 -0
  8. data/app/cells/decidim/lausanne/budgets/budget_list_item/show.erb +21 -0
  9. data/app/cells/decidim/lausanne/budgets/budget_list_item_cell.rb +43 -0
  10. data/app/cells/decidim/lausanne/budgets/budget_m/data.erb +12 -0
  11. data/app/cells/decidim/lausanne/budgets/budget_m/footer.erb +5 -0
  12. data/app/cells/decidim/lausanne/budgets/budget_m_cell.rb +18 -0
  13. data/app/cells/decidim/lausanne/budgets/budgets_header/show.erb +7 -0
  14. data/app/cells/decidim/lausanne/budgets/budgets_header_cell.rb +16 -0
  15. data/app/cells/decidim/lausanne/budgets/budgets_list/card_list.erb +7 -0
  16. data/app/cells/decidim/lausanne/budgets/budgets_list/highlighted.erb +11 -0
  17. data/app/cells/decidim/lausanne/budgets/budgets_list/show.erb +20 -0
  18. data/app/cells/decidim/lausanne/budgets/budgets_list/voted.erb +43 -0
  19. data/app/cells/decidim/lausanne/budgets/budgets_list_cell.rb +40 -0
  20. data/app/cells/decidim/lausanne/budgets/limit_announcement_cell.rb +47 -0
  21. data/app/cells/decidim/lausanne/budgets/project_cell.rb +23 -0
  22. data/app/cells/decidim/lausanne/budgets/project_list_item/project_data.erb +19 -0
  23. data/app/cells/decidim/lausanne/budgets/project_list_item/project_data_vote_button.erb +22 -0
  24. data/app/cells/decidim/lausanne/budgets/project_list_item/project_image.erb +5 -0
  25. data/app/cells/decidim/lausanne/budgets/project_list_item/project_text.erb +23 -0
  26. data/app/cells/decidim/lausanne/budgets/project_list_item/show.erb +5 -0
  27. data/app/cells/decidim/lausanne/budgets/project_list_item_cell.rb +75 -0
  28. data/app/cells/decidim/lausanne/budgets/project_m/data.erb +12 -0
  29. data/app/cells/decidim/lausanne/budgets/project_m/footer.erb +5 -0
  30. data/app/cells/decidim/lausanne/budgets/project_m_cell.rb +24 -0
  31. data/app/cells/decidim/lausanne/budgets/project_selected_status_cell.rb +30 -0
  32. data/app/cells/decidim/lausanne/budgets/project_tags/show.erb +4 -0
  33. data/app/cells/decidim/lausanne/budgets/project_tags_cell.rb +20 -0
  34. data/app/cells/decidim/lausanne/budgets/project_voted_hint_cell.rb +35 -0
  35. data/app/cells/decidim/lausanne/budgets/project_votes_count_cell.rb +46 -0
  36. data/app/commands/decidim/lausanne/budgets/add_line_item.rb +54 -0
  37. data/app/commands/decidim/lausanne/budgets/admin/create_budget.rb +50 -0
  38. data/app/commands/decidim/lausanne/budgets/admin/create_project.rb +71 -0
  39. data/app/commands/decidim/lausanne/budgets/admin/destroy_budget.rb +44 -0
  40. data/app/commands/decidim/lausanne/budgets/admin/destroy_project.rb +44 -0
  41. data/app/commands/decidim/lausanne/budgets/admin/import_proposals_to_budgets.rb +87 -0
  42. data/app/commands/decidim/lausanne/budgets/admin/update_budget.rb +50 -0
  43. data/app/commands/decidim/lausanne/budgets/admin/update_project.rb +79 -0
  44. data/app/commands/decidim/lausanne/budgets/cancel_order.rb +46 -0
  45. data/app/commands/decidim/lausanne/budgets/checkout.rb +43 -0
  46. data/app/commands/decidim/lausanne/budgets/command.rb +16 -0
  47. data/app/commands/decidim/lausanne/budgets/create_user_record.rb +39 -0
  48. data/app/commands/decidim/lausanne/budgets/remove_line_item.rb +40 -0
  49. data/app/commands/decidim/lausanne/budgets/update_user_record.rb +40 -0
  50. data/app/controllers/concerns/decidim/lausanne/budgets/needs_current_order.rb +52 -0
  51. data/app/controllers/concerns/decidim/lausanne/budgets/orderable.rb +54 -0
  52. data/app/controllers/decidim/lausanne/budgets/admin/application_controller.rb +34 -0
  53. data/app/controllers/decidim/lausanne/budgets/admin/attachment_collections_controller.rb +27 -0
  54. data/app/controllers/decidim/lausanne/budgets/admin/attachments_controller.rb +28 -0
  55. data/app/controllers/decidim/lausanne/budgets/admin/lausanne_budgets_controller.rb +105 -0
  56. data/app/controllers/decidim/lausanne/budgets/admin/projects_controller.rb +98 -0
  57. data/app/controllers/decidim/lausanne/budgets/admin/proposals_imports_controller.rb +43 -0
  58. data/app/controllers/decidim/lausanne/budgets/application_controller.rb +77 -0
  59. data/app/controllers/decidim/lausanne/budgets/lausanne_budgets_controller.rb +29 -0
  60. data/app/controllers/decidim/lausanne/budgets/line_items_controller.rb +63 -0
  61. data/app/controllers/decidim/lausanne/budgets/orders_controller.rb +59 -0
  62. data/app/controllers/decidim/lausanne/budgets/projects_controller.rb +103 -0
  63. data/app/controllers/decidim/lausanne/budgets/user_records_controller.rb +121 -0
  64. data/app/forms/decidim/lausanne/budgets/admin/component_form.rb +93 -0
  65. data/app/forms/decidim/lausanne/budgets/admin/lausanne_budget_form.rb +41 -0
  66. data/app/forms/decidim/lausanne/budgets/admin/project_form.rb +96 -0
  67. data/app/forms/decidim/lausanne/budgets/admin/project_import_proposals_form.rb +52 -0
  68. data/app/forms/decidim/lausanne/budgets/user_record_form.rb +61 -0
  69. data/app/helpers/decidim/lausanne/budgets/admin/application_helper.rb +15 -0
  70. data/app/helpers/decidim/lausanne/budgets/application_helper.rb +26 -0
  71. data/app/helpers/decidim/lausanne/budgets/projects_helper.rb +103 -0
  72. data/app/jobs/decidim/lausanne/budgets/send_order_summary_job.rb +17 -0
  73. data/app/mailers/decidim/lausanne/budgets/order_summary_mailer.rb +38 -0
  74. data/app/models/decidim/lausanne/budgets/application_record.rb +12 -0
  75. data/app/models/decidim/lausanne/budgets/lausanne_budget.rb +37 -0
  76. data/app/models/decidim/lausanne/budgets/line_item.rb +23 -0
  77. data/app/models/decidim/lausanne/budgets/order.rb +204 -0
  78. data/app/models/decidim/lausanne/budgets/project.rb +129 -0
  79. data/app/models/decidim/lausanne/budgets/user_record.rb +28 -0
  80. data/app/packs/entrypoints/decidim_lausanne_budgets.js +2 -0
  81. data/app/packs/images/decidim/lausanne/budgets/icon.svg +1 -0
  82. data/app/packs/images/decidim/lausanne/budgets/lausanneparticipe.gif +0 -0
  83. data/app/packs/src/decidim/lausanne/budgets/index.js +1 -0
  84. data/app/packs/src/decidim/lausanne/budgets/progressFixed.js.es6 +23 -0
  85. data/app/packs/src/decidim/lausanne/budgets/projects.js.es6 +66 -0
  86. data/app/packs/stylesheets/decidim/lausanne/budgets/_budgets.scss +13 -0
  87. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_budget-list.scss +195 -0
  88. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_budget-meter.scss +85 -0
  89. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_print.scss +73 -0
  90. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_progress.scss +25 -0
  91. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_proposal_link.scss +38 -0
  92. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_share_buttons.scss +15 -0
  93. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_user_record_form.scss +8 -0
  94. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_votation-progress.scss +100 -0
  95. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_voting-rules.scss +20 -0
  96. data/app/permissions/decidim/lausanne/budgets/admin/permissions.rb +49 -0
  97. data/app/permissions/decidim/lausanne/budgets/permissions.rb +63 -0
  98. data/app/presenters/decidim/lausanne/budgets/admin_log/budget_presenter.rb +44 -0
  99. data/app/presenters/decidim/lausanne/budgets/admin_log/project_presenter.rb +44 -0
  100. data/app/queries/decidim/lausanne/budgets/filtered_projects.rb +47 -0
  101. data/app/queries/decidim/lausanne/budgets/metrics/budget_followers_metric_measure.rb +34 -0
  102. data/app/queries/decidim/lausanne/budgets/metrics/budget_participants_metric_measure.rb +29 -0
  103. data/app/queries/decidim/lausanne/budgets/query.rb +16 -0
  104. data/app/serializers/decidim/lausanne/budgets/data_portability_budgets_order_serializer.rb +46 -0
  105. data/app/services/decidim/lausanne/budgets/project_search.rb +65 -0
  106. data/app/services/decidim/lausanne/budgets/project_search_rs.rb +13 -0
  107. data/app/views/decidim/lausanne/budgets/admin/lausanne_budgets/_form.html.erb +23 -0
  108. data/app/views/decidim/lausanne/budgets/admin/lausanne_budgets/edit.html.erb +7 -0
  109. data/app/views/decidim/lausanne/budgets/admin/lausanne_budgets/index.html.erb +75 -0
  110. data/app/views/decidim/lausanne/budgets/admin/lausanne_budgets/new.html.erb +7 -0
  111. data/app/views/decidim/lausanne/budgets/admin/projects/_form.html.erb +47 -0
  112. data/app/views/decidim/lausanne/budgets/admin/projects/edit.html.erb +7 -0
  113. data/app/views/decidim/lausanne/budgets/admin/projects/index.html.erb +82 -0
  114. data/app/views/decidim/lausanne/budgets/admin/projects/new.html.erb +7 -0
  115. data/app/views/decidim/lausanne/budgets/admin/projects/proposals_picker.html.erb +1 -0
  116. data/app/views/decidim/lausanne/budgets/admin/proposals_imports/new.html.erb +32 -0
  117. data/app/views/decidim/lausanne/budgets/lausanne_budgets/index.html.erb +5 -0
  118. data/app/views/decidim/lausanne/budgets/line_items/update_budget.js.erb +41 -0
  119. data/app/views/decidim/lausanne/budgets/order_summary_mailer/order_summary.html.erb +22 -0
  120. data/app/views/decidim/lausanne/budgets/orders/show.html.erb +71 -0
  121. data/app/views/decidim/lausanne/budgets/projects/_budget_confirm.html.erb +37 -0
  122. data/app/views/decidim/lausanne/budgets/projects/_budget_excess.html.erb +14 -0
  123. data/app/views/decidim/lausanne/budgets/projects/_budget_summary.html.erb +95 -0
  124. data/app/views/decidim/lausanne/budgets/projects/_count.html.erb +1 -0
  125. data/app/views/decidim/lausanne/budgets/projects/_filters.html.erb +34 -0
  126. data/app/views/decidim/lausanne/budgets/projects/_filters_small_view.html.erb +18 -0
  127. data/app/views/decidim/lausanne/budgets/projects/_linked_projects.html.erb +12 -0
  128. data/app/views/decidim/lausanne/budgets/projects/_order_progress.html.erb +32 -0
  129. data/app/views/decidim/lausanne/budgets/projects/_order_selected_projects.html.erb +27 -0
  130. data/app/views/decidim/lausanne/budgets/projects/_order_total_budget.html.erb +7 -0
  131. data/app/views/decidim/lausanne/budgets/projects/_project.html.erb +1 -0
  132. data/app/views/decidim/lausanne/budgets/projects/_project_budget_button.html.erb +46 -0
  133. data/app/views/decidim/lausanne/budgets/projects/_projects.html.erb +13 -0
  134. data/app/views/decidim/lausanne/budgets/projects/_user_record_form.html.erb +40 -0
  135. data/app/views/decidim/lausanne/budgets/projects/_votation_banner.html.erb +71 -0
  136. data/app/views/decidim/lausanne/budgets/projects/index.html.erb +36 -0
  137. data/app/views/decidim/lausanne/budgets/projects/index.js.erb +10 -0
  138. data/app/views/decidim/lausanne/budgets/projects/show.html.erb +81 -0
  139. data/app/views/decidim/lausanne/budgets/user_records/edit.html.erb +6 -0
  140. data/app/views/decidim/proposals/proposals/show.html.erb +172 -0
  141. data/app/views/layouts/lausanne_budgets/print.erb +12 -0
  142. data/config/assets.rb +11 -0
  143. data/config/initializers/social_share.rb +3 -0
  144. data/config/locales/fr.yml +381 -0
  145. data/config/routes.rb +7 -0
  146. data/db/migrate/20170127114122_create_lausanne_projects.rb +15 -0
  147. data/db/migrate/20170127114123_create_lausanne_user_records.rb +14 -0
  148. data/db/migrate/20170130095615_create_lausanne_orders.rb +16 -0
  149. data/db/migrate/20170130101825_create_lausanne_line_items.rb +12 -0
  150. data/db/migrate/20170215132708_add_lausanne_reference_to_projects.rb +13 -0
  151. data/db/migrate/20200617105120_create_decidim_lausanne_budgets.rb +15 -0
  152. data/db/migrate/20200629134013_add_lausanne_budget_reference_to_project.rb +7 -0
  153. data/db/migrate/20200706142609_add_lausanne_budget_reference_to_order.rb +7 -0
  154. data/db/migrate/20200714103519_move_lausanne_budgets_to_own_model.rb +109 -0
  155. data/db/migrate/20200717140012_add_lausanne_scope_to_budgets.rb +7 -0
  156. data/db/migrate/20200728075039_add_lausanne_selected_at_to_project.rb +7 -0
  157. data/db/migrate/20200804175222_lausanne_votes_enabled_to_votes_choices.rb +35 -0
  158. data/db/migrate/20200827154129_add_lausanne_commentable_counter_cache_to_projects.rb +9 -0
  159. data/db/migrate/20210310120613_add_lausanne_followable_counter_cache_to_budgets.rb +16 -0
  160. data/db/migrate/20210508180613_add_checkboxes_to_user_record.rb +9 -0
  161. data/db/migrate/20221001151237_add_excerpt_to_decidim_lausanne_budgets_project.rb +7 -0
  162. data/lib/decidim/lausanne/budgets/admin.rb +12 -0
  163. data/lib/decidim/lausanne/budgets/admin_engine.rb +40 -0
  164. data/lib/decidim/lausanne/budgets/component.rb +107 -0
  165. data/lib/decidim/lausanne/budgets/current_user_record_middleware.rb +17 -0
  166. data/lib/decidim/lausanne/budgets/engine.rb +57 -0
  167. data/lib/decidim/lausanne/budgets/project_serializer.rb +83 -0
  168. data/lib/decidim/lausanne/budgets/seeds/Exampledocument.pdf +0 -0
  169. data/lib/decidim/lausanne/budgets/seeds/city.jpeg +0 -0
  170. data/lib/decidim/lausanne/budgets/test/factories.rb +169 -0
  171. data/lib/decidim/lausanne/budgets/version.rb +15 -0
  172. data/lib/decidim/lausanne/budgets/workflows/all.rb +22 -0
  173. data/lib/decidim/lausanne/budgets/workflows/base.rb +140 -0
  174. data/lib/decidim/lausanne/budgets/workflows/one.rb +35 -0
  175. data/lib/decidim/lausanne/budgets/workflows.rb +19 -0
  176. data/lib/decidim/lausanne/budgets.rb +17 -0
  177. 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,8 @@
1
+ .user_record_form {
2
+ .actions{
3
+ margin-top: 1rem;
4
+ }
5
+ .blockquote {
6
+ margin-bottom: 1px;
7
+ }
8
+ }
@@ -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