decidim-blogs 0.29.2 → 0.30.0.rc2

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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/blogs/content_blocks/highlighted_posts_cell.rb +0 -3
  3. data/app/commands/decidim/blogs/create_post.rb +35 -0
  4. data/app/commands/decidim/blogs/update_post.rb +21 -0
  5. data/app/controllers/decidim/blogs/admin/posts_controller.rb +12 -9
  6. data/app/controllers/decidim/blogs/posts_controller.rb +61 -1
  7. data/app/forms/decidim/blogs/post_form.rb +52 -0
  8. data/app/helpers/decidim/blogs/posts_helper.rb +5 -0
  9. data/app/helpers/decidim/blogs/posts_select_helper.rb +32 -0
  10. data/app/models/decidim/blogs/post.rb +2 -1
  11. data/app/packs/stylesheets/blogs.scss +0 -20
  12. data/app/permissions/decidim/blog/permissions.rb +85 -2
  13. data/app/presenters/decidim/blogs/admin_log/post_presenter.rb +1 -1
  14. data/app/presenters/decidim/blogs/post_presenter.rb +25 -1
  15. data/app/views/decidim/blogs/admin/posts/_actions.html.erb +21 -0
  16. data/app/views/decidim/blogs/admin/posts/_post-tr.html.erb +25 -0
  17. data/app/views/decidim/blogs/admin/posts/_posts-thead.html.erb +9 -0
  18. data/app/views/decidim/blogs/admin/posts/index.html.erb +16 -55
  19. data/app/views/decidim/blogs/admin/posts/manage_trash.html.erb +20 -0
  20. data/app/views/decidim/blogs/posts/_actions.html.erb +7 -14
  21. data/app/views/decidim/blogs/posts/_form.html.erb +11 -0
  22. data/app/views/decidim/blogs/posts/_menu_actions.html.erb +21 -0
  23. data/app/views/decidim/blogs/posts/_schema_org_blog_posting_post.html.erb +3 -0
  24. data/app/views/decidim/blogs/posts/edit.html.erb +21 -0
  25. data/app/views/decidim/blogs/posts/index.html.erb +16 -1
  26. data/app/views/decidim/blogs/posts/new.html.erb +21 -0
  27. data/app/views/decidim/blogs/posts/show.html.erb +15 -6
  28. data/config/locales/ar.yml +0 -1
  29. data/config/locales/bg.yml +0 -3
  30. data/config/locales/ca.yml +58 -3
  31. data/config/locales/cs.yml +57 -2
  32. data/config/locales/de.yml +58 -3
  33. data/config/locales/el.yml +0 -3
  34. data/config/locales/en.yml +58 -3
  35. data/config/locales/es-MX.yml +58 -3
  36. data/config/locales/es-PY.yml +58 -3
  37. data/config/locales/es.yml +58 -3
  38. data/config/locales/eu.yml +58 -3
  39. data/config/locales/fi-plain.yml +57 -2
  40. data/config/locales/fi.yml +57 -2
  41. data/config/locales/fr-CA.yml +32 -2
  42. data/config/locales/fr.yml +32 -2
  43. data/config/locales/gl.yml +0 -1
  44. data/config/locales/hu.yml +0 -3
  45. data/config/locales/ja.yml +57 -2
  46. data/config/locales/kaa.yml +0 -1
  47. data/config/locales/ko.yml +0 -2
  48. data/config/locales/lt.yml +0 -3
  49. data/config/locales/nl.yml +0 -1
  50. data/config/locales/no.yml +0 -1
  51. data/config/locales/pl.yml +0 -3
  52. data/config/locales/pt-BR.yml +0 -3
  53. data/config/locales/ro-RO.yml +92 -24
  54. data/config/locales/ru.yml +0 -3
  55. data/config/locales/sq-AL.yml +0 -3
  56. data/config/locales/sv.yml +58 -3
  57. data/config/locales/zh-TW.yml +0 -3
  58. data/db/migrate/20200827153709_add_commentable_counter_cache_to_posts.rb +1 -1
  59. data/db/migrate/20210310120514_add_followable_counter_cache_to_blogs.rb +1 -1
  60. data/db/migrate/20240828103324_add_deleted_at_to_decidim_blogs_posts.rb +8 -0
  61. data/decidim-blogs.gemspec +1 -1
  62. data/lib/decidim/api/blogs_type.rb +4 -5
  63. data/lib/decidim/api/post_type.rb +2 -2
  64. data/lib/decidim/blogs/admin_engine.rb +7 -1
  65. data/lib/decidim/blogs/component.rb +27 -0
  66. data/lib/decidim/blogs/engine.rb +1 -1
  67. data/lib/decidim/blogs/post_serializer.rb +70 -0
  68. data/lib/decidim/blogs/schema_org_blog_posting_post_serializer.rb +81 -0
  69. data/lib/decidim/blogs/test/factories.rb +9 -0
  70. data/lib/decidim/blogs/version.rb +1 -1
  71. data/lib/decidim/blogs.rb +2 -0
  72. metadata +34 -18
@@ -5,7 +5,7 @@ ro:
5
5
  post:
6
6
  body: Conținut
7
7
  decidim_author_id: Autor
8
- published_at: Publicat la
8
+ published_at: Dată publicare
9
9
  title: Titlu
10
10
  models:
11
11
  decidim/blogs/create_post_event: Postare nouă pe blog
@@ -16,13 +16,19 @@ ro:
16
16
  few: Postări
17
17
  other: Postări
18
18
  decidim:
19
+ admin:
20
+ admin_log:
21
+ changeset:
22
+ posts: Postări
19
23
  blogs:
20
24
  actions:
21
- author_id: Creează postare ca
22
- destroy: Șterge
23
- edit: Editează
25
+ author_id: Creeați postare ca
26
+ confirm_delete_post: Sunteți sigur că doriți să ștergeți această postare?
27
+ deleted_posts_info: Postările șterse pot fi restaurate din gunoi.
28
+ edit: Modificați
24
29
  new: Postare nouă
25
30
  title: Acțiuni
31
+ view_deleted_posts: Vizualizați postările șterse
26
32
  admin:
27
33
  posts:
28
34
  create:
@@ -31,22 +37,31 @@ ro:
31
37
  destroy:
32
38
  success: Postarea a fost ștearsă cu succes.
33
39
  edit:
34
- save: Actualizează
35
- title: Editează postarea
40
+ save: Actualizați
41
+ title: Modificați postarea
36
42
  index:
37
43
  not_published_yet: Nu a fost publicat încă.
38
44
  title: Postări
45
+ manage_trash:
46
+ title: Postări șterse
39
47
  new:
40
- create: Creează
41
- title: Creează postare
48
+ create: Creați
49
+ title: Creați postare nouă
42
50
  update:
43
- invalid: A apărut o eroare la salvarea postării.
44
- success: Postarea a fost salvată cu succes.
51
+ invalid: A apărut o eroare la actualizarea acestei postări.
52
+ success: Postarea a fost actualizată cu succes.
45
53
  admin_log:
46
54
  post:
47
- create: "%{user_name} a creat postarea de blog %{resource_name} în %{space_name}"
48
- delete: "%{user_name} a șters postarea de blog %{resource_name} din %{space_name}"
49
- update: "%{user_name} a actualizat postarea de blog %{resource_name} în %{space_name}"
55
+ create: "%{user_name} a creat postarea %{resource_name} în %{space_name}"
56
+ delete: "%{user_name} a șters postarea %{resource_name} din %{space_name}"
57
+ restore: "%{user_name} a restaurat postarea %{resource_name} din %{space_name}"
58
+ soft_delete: "%{user_name} a mutat la gunoi postarea %{resource_name} din %{space_name}"
59
+ update: "%{user_name} a actualizat postarea %{resource_name} în %{space_name}"
60
+ content_blocks:
61
+ highlighted_posts:
62
+ last_published: Publicate recent
63
+ name: Postări
64
+ see_all: Vedeți toate postările
50
65
  last_activity:
51
66
  new_post: 'Postare nouă:'
52
67
  models:
@@ -55,33 +70,86 @@ ro:
55
70
  author: Autor
56
71
  body: Conținut
57
72
  official_blog_post: Postare oficială
58
- published_at: Publicat la
73
+ published_at: Dată publicare
59
74
  title: Titlu
75
+ posts:
76
+ edit:
77
+ back: Înapoi la postare
78
+ button: Actualizați
79
+ title: Modificați postarea
80
+ form:
81
+ author_id: Autor
82
+ body: Conținut
83
+ title: Titlu
84
+ index:
85
+ count:
86
+ one: "%{count} postare"
87
+ few: "%{count} postări"
88
+ other: "%{count} postări"
89
+ empty: Nu există postări încă.
90
+ new_post: Postare nouă
91
+ menu_actions:
92
+ button_destroy: Ștergeți postarea
93
+ button_destroy_confirm: Sunteți sigur că doriți să ștergeți această postare?
94
+ button_edit: Modificați postarea
95
+ new:
96
+ back: Înapoi la postări
97
+ button: Creați
98
+ title: Creați o postare nouă
60
99
  components:
61
100
  blogs:
62
101
  actions:
63
- comment: Comentariu
64
- create: Creează
65
- destroy: Șterge
66
- endorse: Susține
67
- update: Actualizează
102
+ comment: Comentați
103
+ create: Creați
104
+ destroy: Ștergeți
105
+ endorse: Susțineți
106
+ update: Actualizați
68
107
  name: Blog
69
108
  settings:
70
109
  global:
71
- announcement: Anunţ
110
+ announcement: Anunț
72
111
  comments_enabled: Comentarii activate
73
112
  comments_max_length: Lungimea maximă a comentariilor (lăsați 0 pentru valoarea implicită)
113
+ creation_enabled_for_participants: Participanții pot crea postări
74
114
  step:
75
- announcement: Anunţ
115
+ announcement: Anunț
76
116
  comments_blocked: Comentarii blocate
77
- endorsements_blocked: Susțineri blocate
117
+ endorsements_blocked: Susțineri dezactivate
78
118
  endorsements_enabled: Susțineri activate
79
119
  events:
80
120
  blogs:
81
121
  post_created:
82
- email_intro: Postarea "%{resource_title}" a fost publicată în "%{participatory_space_title}" pe care o urmărești.
83
- email_outro: Ai primit această notificare deoarece urmărești „%{participatory_space_title}”. Poți anula abonarea de la link-ul anterior.
122
+ email_intro: Postarea "%{resource_title}" a fost publicată în "%{participatory_space_title}" pe care o urmăriți.
123
+ email_outro: Ați primit această notificare deoarece urmarăți „%{participatory_space_title}”. Puteți anula abonarea de la link-ul anterior.
84
124
  email_subject: Postare nouă publicată în %{participatory_space_title}
85
125
  notification_title: Postarea <a href="%{resource_path}">%{resource_title}</a> a fost publicată în %{participatory_space_title}
126
+ open_data:
127
+ help:
128
+ post_comments:
129
+ alignment: Acest comentariu a fost favorabil, contrar sau neutru
130
+ author: Numele participantului care a făcut acest comentariu
131
+ body: Comentariul în sine
132
+ commentable_id: Id-ul unic al resursei comentate
133
+ commentable_type: Tipul resursei comentate (dacă este întâlnire, propunere etc.)
134
+ created_at: Data la care acest comentariu a fost creat
135
+ depth: Locul în care acest comentariu este în cele trei comentarii (dacă este un răspuns sau un răspuns la un răspuns)
136
+ id: Id-ul unic al comentariului
137
+ locale: Localizarea (limba) pe care participantul a folosit-o atunci când a lăsat acest comentariu
138
+ root_commentable_url: URL-ul resursei care se leagă de acest comentariu
139
+ user_group: Numele grupului de utilizatori care a făcut acest comentariu (dacă există)
140
+ posts:
141
+ author: Informațiile autorului
142
+ body: Conținutul postării
143
+ comments_count: Numărul de comentarii pe care le are această postare
144
+ component: Componenta căreia îi aparține postarea
145
+ created_at: Data la care acestă postare a fost creată
146
+ endorsements_count: Numărul de aprobări pe care această postare le-a primit
147
+ follows_count: Numărul de urmăritori al acestei postări
148
+ id: Identificatorul unic al acestei postări
149
+ participatory_space: Cărui spațiu (de exemplu, proces participativ sau adunare) aparține această postare
150
+ published_at: Data la care acestă postare a fost publicată
151
+ title: Titlul postării
152
+ updated_at: Ultima dată când această postare a fost actualizată
153
+ url: URL-ul pentru această postare
86
154
  statistics:
87
155
  posts_count: Postări
@@ -20,7 +20,6 @@ ru:
20
20
  blogs:
21
21
  actions:
22
22
  author_id: Создать пост как
23
- destroy: Удалить
24
23
  edit: Редактировать
25
24
  new: Создать новый пост
26
25
  title: Действия
@@ -29,8 +28,6 @@ ru:
29
28
  create:
30
29
  invalid: При попытке добавить этот пост произошла ошибка.
31
30
  success: Пост успешно создан.
32
- destroy:
33
- success: Пост успешно удален.
34
31
  edit:
35
32
  save: Обновить
36
33
  title: Изменить пост
@@ -18,7 +18,6 @@ sq:
18
18
  blogs:
19
19
  actions:
20
20
  author_id: Krijo postimin si
21
- destroy: Fshij
22
21
  edit: Përpuno
23
22
  new: Postim i ri
24
23
  title: Veprime
@@ -27,8 +26,6 @@ sq:
27
26
  create:
28
27
  invalid: Ndodhi një gabim gjatë krijimit të këtij postimi.
29
28
  success: Postimi u krijua me sukses.
30
- destroy:
31
- success: Postimi u fshi me sukses.
32
29
  edit:
33
30
  save: Përditëso
34
31
  title: Përpuno postimin
@@ -15,27 +15,34 @@ sv:
15
15
  one: Inlägg
16
16
  other: Inlägg
17
17
  decidim:
18
+ admin:
19
+ admin_log:
20
+ changeset:
21
+ posts: Inlägg
18
22
  blogs:
19
23
  actions:
20
24
  author_id: Skapa inlägg som
21
- confirm_destroy: Är du säker på att du vill radera inlägget?
22
- destroy: Radera
25
+ confirm_delete_post: Är du säker på att du vill radera inlägget?
26
+ deleted_posts_info: Raderade inlägg kan återställas från papperskorgen.
23
27
  edit: Redigera
24
28
  new: Nytt inlägg
25
29
  title: Åtgärder
30
+ view_deleted_posts: Visa raderade inlägg
26
31
  admin:
27
32
  posts:
28
33
  create:
29
34
  invalid: Det gick inte att skapa inlägget.
30
35
  success: Inlägget har skapats.
31
36
  destroy:
32
- success: Inlägget har raderats.
37
+ success: Inlägget raderades.
33
38
  edit:
34
39
  save: Uppdatera
35
40
  title: Redigera inlägg
36
41
  index:
37
42
  not_published_yet: Ej publicerat.
38
43
  title: Inlägg
44
+ manage_trash:
45
+ title: Raderade inlägg
39
46
  new:
40
47
  create: Skapa
41
48
  title: Skapa inlägg
@@ -46,6 +53,8 @@ sv:
46
53
  post:
47
54
  create: "%{user_name} skapade blogginlägget %{resource_name} i %{space_name}"
48
55
  delete: "%{user_name} raderade blogginlägget %{resource_name} från %{space_name}"
56
+ restore: "%{user_name} återställde %{resource_name} blogginlägg i %{space_name}"
57
+ soft_delete: "%{user_name} flyttade blogginlägget %{resource_name} i %{space_name} till papperskorgen"
49
58
  update: "%{user_name} uppdaterade blogginlägget %{resource_name} i %{space_name}"
50
59
  content_blocks:
51
60
  highlighted_posts:
@@ -63,11 +72,28 @@ sv:
63
72
  published_at: Publicerad
64
73
  title: Titel
65
74
  posts:
75
+ edit:
76
+ back: Tillbaka till inlägget
77
+ button: Uppdatera
78
+ title: Redigera inlägg
79
+ form:
80
+ author_id: Författare
81
+ body: Text
82
+ title: Titel
66
83
  index:
67
84
  count:
68
85
  one: "%{count} inlägg"
69
86
  other: "%{count} inlägg"
70
87
  empty: Det finns inga inlägg ännu.
88
+ new_post: Nytt inlägg
89
+ menu_actions:
90
+ button_destroy: Ta bort inlägg
91
+ button_destroy_confirm: Är du säker på att du vill radera inlägget?
92
+ button_edit: Redigera inlägg
93
+ new:
94
+ back: Tillbaka till inlägg
95
+ button: Skapa
96
+ title: Skapa nytt inlägg
71
97
  components:
72
98
  blogs:
73
99
  actions:
@@ -82,6 +108,7 @@ sv:
82
108
  announcement: Meddelande
83
109
  comments_enabled: Aktivera kommentarer
84
110
  comments_max_length: Maximal kommentarslängd (ange 0 för att använda standardvärdet)
111
+ creation_enabled_for_participants: Deltagarna kan skapa inlägg
85
112
  step:
86
113
  announcement: Meddelande
87
114
  comments_blocked: Stäng av kommentarer
@@ -94,5 +121,33 @@ sv:
94
121
  email_outro: Du har fått det här meddelandet eftersom du följer "%{participatory_space_title}". Du kan sluta att följa det från den föregående länken.
95
122
  email_subject: Ett nytt inlägg har publicerats i %{participatory_space_title}
96
123
  notification_title: Inlägget <a href="%{resource_path}">%{resource_title}</a> har publicerats i %{participatory_space_title}
124
+ open_data:
125
+ help:
126
+ post_comments:
127
+ alignment: Positiva, negativa eller neutrala kommentarer
128
+ author: Namn på den som kommenterat
129
+ body: Kommentaren
130
+ commentable_id: Kommentarens unika id
131
+ commentable_type: Vad som kommenterades (resultat, förslag etc)
132
+ created_at: Datum för kommentaren
133
+ depth: Kommentarens plats i en hierarki av kommentarer (om den är ett svar på en annan kommentar)
134
+ id: Id för kommentaren
135
+ locale: Kommentarförfattarens språk
136
+ root_commentable_url: URL till innehållet som är relaterat till kommentaren
137
+ user_group: Namn på gruppen som kommenterat (om det var en grupp)
138
+ posts:
139
+ author: Uppgifter om författaren
140
+ body: Inläggets text
141
+ comments_count: Antalet kommentarer till inlägget
142
+ component: Komponenten som inlägget tillhör
143
+ created_at: Datum för inlägget
144
+ endorsements_count: Antal gilla-markeringar för inlägget
145
+ follows_count: Antal följare för inlägget
146
+ id: Unikt id för inlägget
147
+ participatory_space: Vilket utrymme (deltagandeprocess eller samråd) inlägget tillhör
148
+ published_at: Publiceringsdatum för inlägget
149
+ title: Titeln på inlägget
150
+ updated_at: Senaste datum när inlägget uppdaterades
151
+ url: URL för inlägget
97
152
  statistics:
98
153
  posts_count: Inlägg
@@ -17,7 +17,6 @@ zh-TW:
17
17
  blogs:
18
18
  actions:
19
19
  author_id: 發佈文章
20
- destroy: 刪除
21
20
  edit: 編輯
22
21
  new: 新貼文
23
22
  title: 操作
@@ -26,8 +25,6 @@ zh-TW:
26
25
  create:
27
26
  invalid: 建立此文章時出現問題
28
27
  success: 文章已成功建立
29
- destroy:
30
- success: 文章已成功刪除
31
28
  edit:
32
29
  save: 更新
33
30
  title: 编辑文章
@@ -4,6 +4,6 @@ class AddCommentableCounterCacheToPosts < ActiveRecord::Migration[5.2]
4
4
  def change
5
5
  add_column :decidim_blogs_posts, :comments_count, :integer, null: false, default: 0, index: true
6
6
  Decidim::Blogs::Post.reset_column_information
7
- Decidim::Blogs::Post.find_each(&:update_comments_count)
7
+ Decidim::Blogs::Post.unscoped.find_each(&:update_comments_count)
8
8
  end
9
9
  end
@@ -7,7 +7,7 @@ class AddFollowableCounterCacheToBlogs < ActiveRecord::Migration[5.2]
7
7
  reversible do |dir|
8
8
  dir.up do
9
9
  Decidim::Blogs::Post.reset_column_information
10
- Decidim::Blogs::Post.find_each do |record|
10
+ Decidim::Blogs::Post.unscoped.find_each do |record|
11
11
  record.class.reset_counters(record.id, :follows)
12
12
  end
13
13
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddDeletedAtToDecidimBlogsPosts < ActiveRecord::Migration[7.0]
4
+ def change
5
+ add_column :decidim_blogs_posts, :deleted_at, :datetime
6
+ add_index :decidim_blogs_posts, :deleted_at
7
+ end
8
+ end
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  "homepage_uri" => "https://decidim.org",
20
20
  "source_code_uri" => "https://github.com/decidim/decidim"
21
21
  }
22
- s.required_ruby_version = "~> 3.2.0"
22
+ s.required_ruby_version = "~> 3.3.0"
23
23
 
24
24
  s.name = "decidim-blogs"
25
25
  s.summary = "Decidim blogs module"
@@ -6,14 +6,13 @@ module Decidim
6
6
  graphql_name "Blogs"
7
7
  description "A blogs component of a participatory space."
8
8
 
9
- field :posts, type: Decidim::Blogs::PostType.connection_type, description: "List all posts", connection: true, null: false do
10
- argument :order, Decidim::Blogs::PostInputSort, "Provides several methods to order the results", required: false
11
- argument :filter, Decidim::Blogs::PostInputFilter, "Provides several methods to filter the results", required: false
12
- end
13
-
14
9
  field :post, type: Decidim::Blogs::PostType, description: "Finds one post", null: true do
15
10
  argument :id, GraphQL::Types::ID, "The ID of the post", required: true
16
11
  end
12
+ field :posts, type: Decidim::Blogs::PostType.connection_type, description: "List all posts", connection: true, null: false do
13
+ argument :filter, Decidim::Blogs::PostInputFilter, "Provides several methods to filter the results", required: false
14
+ argument :order, Decidim::Blogs::PostInputSort, "Provides several methods to order the results", required: false
15
+ end
17
16
 
18
17
  def posts(filter: {}, order: {})
19
18
  base_query = Decidim::Core::ComponentListBase.new(model_class: Post).call(object, { filter:, order: }, context)
@@ -13,10 +13,10 @@ module Decidim
13
13
 
14
14
  description "A post"
15
15
 
16
- field :id, GraphQL::Types::ID, "The internal ID of this post", null: false
17
- field :title, Decidim::Core::TranslatedFieldType, "The title for this post", null: true
18
16
  field :body, Decidim::Core::TranslatedFieldType, "The body of this post", null: true
17
+ field :id, GraphQL::Types::ID, "The internal ID of this post", null: false
19
18
  field :published_at, Decidim::Core::DateTimeType, "The time this page was published", null: false
19
+ field :title, Decidim::Core::TranslatedFieldType, "The title for this post", null: true
20
20
 
21
21
  def self.authorized?(object, context)
22
22
  context[:post] = object
@@ -11,9 +11,15 @@ module Decidim
11
11
  paths["lib/tasks"] = nil
12
12
 
13
13
  routes do
14
- resources :posts do
14
+ resources :posts, except: [:destroy] do
15
15
  resources :attachment_collections, except: [:show]
16
16
  resources :attachments, except: [:show]
17
+ get :manage_trash, on: :collection
18
+
19
+ member do
20
+ patch :soft_delete
21
+ patch :restore
22
+ end
17
23
  end
18
24
  root to: "posts#index"
19
25
  end
@@ -23,6 +23,7 @@ Decidim.register_component(:blogs) do |component|
23
23
  settings.attribute :announcement, type: :text, translated: true, editor: true
24
24
  settings.attribute :comments_enabled, type: :boolean, default: true
25
25
  settings.attribute :comments_max_length, type: :integer, required: true
26
+ settings.attribute :creation_enabled_for_participants, type: :boolean, default: false
26
27
  end
27
28
 
28
29
  component.settings(:step) do |settings|
@@ -39,6 +40,32 @@ Decidim.register_component(:blogs) do |component|
39
40
  resource.searchable = true
40
41
  end
41
42
 
43
+ component.exports :posts do |exports|
44
+ exports.collection do |component_instance|
45
+ Decidim::Blogs::Post
46
+ .not_hidden
47
+ .published
48
+ .where(component: component_instance)
49
+ .includes(component: { participatory_space: :organization })
50
+ end
51
+
52
+ exports.include_in_open_data = true
53
+
54
+ exports.serializer Decidim::Blogs::PostSerializer
55
+ end
56
+
57
+ component.exports :post_comments do |exports|
58
+ exports.collection do |component_instance|
59
+ Decidim::Comments::Export.comments_for_resource(
60
+ Decidim::Blogs::Post, component_instance
61
+ ).includes(:author, :user_group, root_commentable: { component: { participatory_space: :organization } })
62
+ end
63
+
64
+ exports.include_in_open_data = true
65
+
66
+ exports.serializer Decidim::Comments::CommentSerializer
67
+ end
68
+
42
69
  component.seeds do |participatory_space|
43
70
  require "decidim/blogs/seeds"
44
71
 
@@ -14,7 +14,7 @@ module Decidim
14
14
  isolate_namespace Decidim::Blogs
15
15
 
16
16
  routes do
17
- resources :posts, only: [:index, :show]
17
+ resources :posts
18
18
  scope "/posts" do
19
19
  root to: "posts#index"
20
20
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Blogs
5
+ # This class serializes a Post so can be exported to CSV, JSON or other
6
+ # formats.
7
+ class PostSerializer < Decidim::Exporters::Serializer
8
+ include Decidim::ApplicationHelper
9
+ include Decidim::ResourceHelper
10
+
11
+ # Public: Initializes the serializer with a post.
12
+ def initialize(post)
13
+ @post = post
14
+ end
15
+
16
+ # Public: Exports a hash with the serialized data for this post.
17
+ def serialize
18
+ {
19
+ id: post.id,
20
+ author: {
21
+ **author_fields
22
+ },
23
+ title: post.title,
24
+ body: post.body,
25
+ created_at: post.created_at,
26
+ updated_at: post.updated_at,
27
+ published_at: post.published_at,
28
+ endorsements_count: post.endorsements_count,
29
+ comments_count: post.comments_count,
30
+ follows_count: post.follows_count,
31
+ participatory_space: {
32
+ id: post.participatory_space.id,
33
+ url: Decidim::ResourceLocatorPresenter.new(post.participatory_space).url
34
+ },
35
+ component: { id: component.id },
36
+ url:
37
+ }
38
+ end
39
+
40
+ private
41
+
42
+ attr_reader :post
43
+ alias resource post
44
+
45
+ def url
46
+ Decidim::ResourceLocatorPresenter.new(post).url
47
+ end
48
+
49
+ def author_fields
50
+ {
51
+ id: resource.author.id,
52
+ name: author_name(resource.author),
53
+ url: author_url(resource.author)
54
+ }
55
+ end
56
+
57
+ def author_name(author)
58
+ translated_attribute(author.name)
59
+ end
60
+
61
+ def author_url(author)
62
+ if author.respond_to?(:nickname)
63
+ profile_url(author) # is a Decidim::User or Decidim::UserGroup
64
+ else
65
+ root_url # is a Decidim::Organization
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Blogs
5
+ class SchemaOrgBlogPostingPostSerializer < Decidim::Exporters::Serializer
6
+ include Decidim::TranslationsHelper
7
+ include Decidim::SanitizeHelper
8
+ include ActionView::Helpers::UrlHelper
9
+
10
+ # Public: Initializes the serializer with a post.
11
+ def initialize(post)
12
+ @post = post
13
+ end
14
+
15
+ # Serializes a post for the Schema.org Event type
16
+ #
17
+ # @see https://schema.org/BlogPosting
18
+ # @see https://developers.google.com/search/docs/appearance/structured-data/article?hl=en
19
+ def serialize
20
+ attributes = {
21
+ "@context": "https://schema.org",
22
+ "@type": "BlogPosting",
23
+ headline: decidim_escape_translated(post.title),
24
+ author:
25
+ }
26
+
27
+ attributes = attributes.merge(image:) if post.photos.any?
28
+ attributes = attributes.merge(datePublished: published) if post.published?
29
+ attributes
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :post
35
+ alias resource post
36
+
37
+ def author
38
+ case post.author.class.name
39
+ when "Decidim::Organization"
40
+ author_organization
41
+ when "Decidim::UserGroup"
42
+ author_user_group
43
+ when "Decidim::User"
44
+ author_user
45
+ end
46
+ end
47
+
48
+ def author_user_group
49
+ {
50
+ "@type": "Organization",
51
+ name: post.author.name,
52
+ url: profile_url(post.author)
53
+ }
54
+ end
55
+
56
+ def author_organization
57
+ {
58
+ "@type": "Organization",
59
+ name: decidim_escape_translated(post.author.name),
60
+ url: EngineRouter.new("decidim", router_options).root_url
61
+ }
62
+ end
63
+
64
+ def author_user
65
+ {
66
+ "@type": "Person",
67
+ name: decidim_escape_translated(post.author.name),
68
+ url: profile_url(post.author)
69
+ }
70
+ end
71
+
72
+ def router_options = { host: post.organization.host }
73
+
74
+ def image = post.photos.map(&:thumbnail_url)
75
+
76
+ def published
77
+ post.published_at.iso8601
78
+ end
79
+ end
80
+ end
81
+ end
@@ -30,6 +30,14 @@ FactoryBot.define do
30
30
  }
31
31
  end
32
32
  end
33
+
34
+ trait :with_creation_enabled do
35
+ settings do
36
+ {
37
+ creation_enabled_for_participants: true
38
+ }
39
+ end
40
+ end
33
41
  end
34
42
 
35
43
  factory :post, class: "Decidim::Blogs::Post" do
@@ -41,6 +49,7 @@ FactoryBot.define do
41
49
  body { generate_localized_description(:blog_body, skip_injection:) }
42
50
  component { build(:post_component, skip_injection:) }
43
51
  author { build(:user, :confirmed, skip_injection:, organization: component.organization) }
52
+ deleted_at { nil }
44
53
 
45
54
  trait :with_endorsements do
46
55
  after :create do |post, evaluator|
@@ -4,7 +4,7 @@ module Decidim
4
4
  # This holds the decidim-pages version.
5
5
  module Blogs
6
6
  def self.version
7
- "0.29.2"
7
+ "0.30.0.rc2"
8
8
  end
9
9
  end
10
10
  end
data/lib/decidim/blogs.rb CHANGED
@@ -10,5 +10,7 @@ module Decidim
10
10
  # This namespace holds the logic of the `Blogs` component. This component
11
11
  # allows the admins to create a custom blog for a participatory process.
12
12
  module Blogs
13
+ autoload :PostSerializer, "decidim/blogs/post_serializer"
14
+ autoload :SchemaOrgBlogPostingPostSerializer, "decidim/blogs/schema_org_blog_posting_post_serializer"
13
15
  end
14
16
  end