From 92cd59b7817ca30bf1fcb287ecb43dc6bc7710ff Mon Sep 17 00:00:00 2001
From: f <f@sutty.nl>
Date: Wed, 21 Apr 2021 14:11:11 -0300
Subject: [PATCH 1/6] wip: pruebas de #1142

---
 app/models/post.rb                        | 10 ++-
 app/views/posts/index.haml                | 91 ++++++++++++-----------
 config/environments/test.rb               |  9 +++
 test/controllers/posts_controller_test.rb | 14 +++-
 4 files changed, 76 insertions(+), 48 deletions(-)

diff --git a/app/models/post.rb b/app/models/post.rb
index a0e16706b..7be6c8c8f 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -23,7 +23,11 @@ class Post
     # TODO: Reemplazar cuando leamos el contenido del Document
     # a demanda?
     def find_layout(path)
-      IO.foreach(path).lazy.grep(/^layout: /).take(1).first&.split(' ')&.last&.tr('\'', '')&.tr('"', '')&.to_sym
+      IO.foreach(path).lazy.grep(/^layout: /).take(1).first&.split(' ')&.last&.tr('\'', '')&.tr('"', '')&.to_sym || :post
+    rescue Errno::ENOENT => e
+      ExceptionNotifier.notify(e)
+
+      :post
     end
   end
 
@@ -106,7 +110,7 @@ class Post
 
   # Devuelve una llave para poder guardar el post en una cache
   def cache_key
-    'posts/' + uuid.value
+    "posts/#{uuid.value}"
   end
 
   def cache_version
@@ -116,7 +120,7 @@ class Post
   # Agregar el timestamp para saber si cambió, siguiendo el módulo
   # ActiveRecord::Integration
   def cache_key_with_version
-    cache_key + '-' + cache_version
+    "#{cache_key}-#{cache_version}"
   end
 
   # TODO: Convertir a UUID?
diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml
index b2f3f6613..9f2ab9a61 100644
--- a/app/views/posts/index.haml
+++ b/app/views/posts/index.haml
@@ -83,46 +83,53 @@
 
                 TODO: Verificar qué pasa cuando se gestiona el sitio en
                 distintos idiomas a la vez
-              - cache_if @usuarie, post do
-                - checkbox_id = "checkbox-#{post.uuid.value}"
-                %tr{ id: post.uuid.value, data: { target: 'reorder.row' } }
-                  %td
-                    .custom-control.custom-checkbox
-                      %input.custom-control-input{ id: checkbox_id, type: 'checkbox', autocomplete: 'off', data: { action: 'reorder#select' } }
-                      %label.custom-control-label{ for: checkbox_id }
-                        %span.sr-only= t('posts.reorder.select')
-                    -# Orden más alto es mayor prioridad
-                    = hidden_field 'post[reorder]', post.uuid.value,
-                      value: @posts.length - i,
-                      data: { reorder: true }
-                  %td.w-100{ class: dir }
-                    = link_to site_post_path(@site, post.id) do
-                      %span{ lang: post.lang.value, dir: dir }= post.title.value
-                    - if post.attributes.include? :draft
-                      - if post.draft.value
-                        %span.badge.badge-primary
-                          = post_label_t(:draft, post: post)
-                    - if post.attributes.include? :categories
-                      - unless post.categories.value.empty?
-                        %br
-                        %small
-                          - (post.categories.respond_to?(:belongs_to) ? post.categories.belongs_to : post.categories.value).each do |c|
-                            = link_to site_posts_path(@site, category: (c.respond_to?(:uuid) ? c.uuid.value : c)) do
-                              %span{ lang: post.lang.value, dir: dir }= (c.respond_to?(:title) ? c.title.value : c)
+              - begin
+                - cache_if @usuarie, post do
+                  - checkbox_id = "checkbox-#{post.uuid.value}"
+                  %tr{ id: post.uuid.value, data: { target: 'reorder.row' } }
+                    %td
+                      .custom-control.custom-checkbox
+                        %input.custom-control-input{ id: checkbox_id, type: 'checkbox', autocomplete: 'off', data: { action: 'reorder#select' } }
+                        %label.custom-control-label{ for: checkbox_id }
+                          %span.sr-only= t('posts.reorder.select')
+                      -# Orden más alto es mayor prioridad
+                      = hidden_field 'post[reorder]', post.uuid.value,
+                        value: @posts.length - i,
+                        data: { reorder: true }
+                    %td.w-100{ class: dir }
+                      = link_to site_post_path(@site, post.id) do
+                        %span{ lang: post.lang.value, dir: dir }= post.title.value
+                      - if post.attributes.include? :draft
+                        - if post.draft.value
+                          %span.badge.badge-primary
+                            = post_label_t(:draft, post: post)
+                      - if post.attributes.include? :categories
+                        - unless post.categories.value.empty?
+                          %br
+                          %small
+                            - (post.categories.respond_to?(:belongs_to) ? post.categories.belongs_to : post.categories.value).each do |c|
+                              = link_to site_posts_path(@site, category: (c.respond_to?(:uuid) ? c.uuid.value : c)) do
+                                %span{ lang: post.lang.value, dir: dir }= (c.respond_to?(:title) ? c.title.value : c)
 
-                  %td
-                    = post.date.value.strftime('%F')
-                    %br/
-                    - if post.attribute? :order
-                      = post.order.value
-                  %td
-                    - if @usuarie || policy(post).edit?
-                      = link_to t('posts.edit'),
-                      edit_site_post_path(@site, post.id),
-                      class: 'btn btn-block'
-                    - if @usuarie || policy(post).destroy?
-                      = link_to t('posts.destroy'),
-                        site_post_path(@site, post.id),
-                        class: 'btn btn-block',
-                        method: :delete,
-                        data: { confirm: t('posts.confirm_destroy') }
+                    %td
+                      = post.date.value.strftime('%F')
+                      %br/
+                      - if post.attribute? :order
+                        = post.order.value
+                    %td
+                      - if @usuarie || policy(post).edit?
+                        = link_to t('posts.edit'),
+                        edit_site_post_path(@site, post.id),
+                        class: 'btn btn-block'
+                      - if @usuarie || policy(post).destroy?
+                        = link_to t('posts.destroy'),
+                          site_post_path(@site, post.id),
+                          class: 'btn btn-block',
+                          method: :delete,
+                          data: { confirm: t('posts.confirm_destroy') }
+              -# 
+                Rescatar cualquier error en un post, notificarlo e
+                ignorar su renderización.
+              - rescue ActionView::Template::Error => e
+                - binding.pry
+                - ExceptionNotifier.notify_exception(e.cause, data: { site: @site.name, post: @post.path.absolute, usuarie: current_usuarie.id })
diff --git a/config/environments/test.rb b/config/environments/test.rb
index f8169828f..599c5f28f 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -50,6 +50,15 @@ Rails.application.configure do
   config.action_mailer.default_url_options = { host: 'localhost',
                                                port: 3000 }
 
+  config.middleware.use ExceptionNotification::Rack,
+                        error_grouping: true,
+                        email: {
+                          email_prefix: '',
+                          sender_address: ENV['DEFAULT_FROM'],
+                          exception_recipients: ENV['EXCEPTION_TO'],
+                          normalize_subject: true
+                        }
+
   # Print deprecation notices to the stderr.
   config.active_support.deprecation = :stderr
 
diff --git a/test/controllers/posts_controller_test.rb b/test/controllers/posts_controller_test.rb
index b8c9f5605..3349f09b8 100644
--- a/test/controllers/posts_controller_test.rb
+++ b/test/controllers/posts_controller_test.rb
@@ -150,7 +150,7 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
     end
 
     posts = @site.posts(**lang)
-    reorder = Hash[posts.map { |p| p.uuid.value }.shuffle.each_with_index.to_a]
+    reorder = posts.map { |p| p.uuid.value }.shuffle.each_with_index.to_a.to_h
 
     post site_posts_reorder_url(@site),
          headers: @authorization,
@@ -159,10 +159,18 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
     @site = Site.find @site.id
 
     assert_equal reorder,
-                 Hash[@site.posts(**lang).map do |p|
+                 @site.posts(**lang).map do |p|
                    [p.uuid.value, p.order.value]
-                 end]
+                 end.to_h
     assert_equal I18n.t('post_service.reorder'),
                  @site.repository.rugged.head.target.message
   end
+
+  test 'si hay algún error se recupera' do
+    File.open(File.join(@site.path, '_es', "#{Date.today}-#{SecureRandom.hex}.markdown"), 'w') do |f|
+      f.write ''
+    end
+
+    get site_posts_url(@site), headers: @authorization
+  end
 end
-- 
GitLab


From d879b5bbfe087e79519dc2e2affcb5ad8204ccda Mon Sep 17 00:00:00 2001
From: f <f@sutty.nl>
Date: Mon, 7 Mar 2022 11:57:02 -0300
Subject: [PATCH 2/6] eliminar pry

---
 app/views/posts/index.haml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml
index 9f2ab9a61..0fbcf50a5 100644
--- a/app/views/posts/index.haml
+++ b/app/views/posts/index.haml
@@ -131,5 +131,4 @@
                 Rescatar cualquier error en un post, notificarlo e
                 ignorar su renderización.
               - rescue ActionView::Template::Error => e
-                - binding.pry
                 - ExceptionNotifier.notify_exception(e.cause, data: { site: @site.name, post: @post.path.absolute, usuarie: current_usuarie.id })
-- 
GitLab


From 15454596f21fe2a0059e71d573a84fbc937a6a36 Mon Sep 17 00:00:00 2001
From: f <f@sutty.nl>
Date: Tue, 19 Jul 2022 13:50:30 -0300
Subject: [PATCH 3/6] no actualizar al cargar el listado de sitios

hace que todo tarde demasiado tiempo
---
 app/views/sites/index.haml | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/app/views/sites/index.haml b/app/views/sites/index.haml
index d69dbeace..7a240f970 100644
--- a/app/views/sites/index.haml
+++ b/app/views/sites/index.haml
@@ -54,10 +54,4 @@
                       text: t('usuaries.index.title'),
                       type: 'info',
                       link: site_usuaries_path(site)
-                  - if policy(site).pull? && site.repository.needs_pull?
-                    = render 'layouts/btn_with_tooltip',
-                      tooltip: t('help.sites.pull'),
-                      text: t('.pull'),
-                      type: 'info',
-                      link: site_pull_path(site)
                   = render 'sites/build', site: site
-- 
GitLab


From fdfc5db3454fcce26555c52e8faf68f1cea071f8 Mon Sep 17 00:00:00 2001
From: f <f@sutty.nl>
Date: Tue, 19 Jul 2022 13:52:38 -0300
Subject: [PATCH 4/6] no fallar todo si un sitio no funciona

---
 app/views/sites/index.haml | 83 ++++++++++++++++++++------------------
 1 file changed, 43 insertions(+), 40 deletions(-)

diff --git a/app/views/sites/index.haml b/app/views/sites/index.haml
index 7a240f970..b3d99ca53 100644
--- a/app/views/sites/index.haml
+++ b/app/views/sites/index.haml
@@ -14,44 +14,47 @@
     %table.table.table-condensed
       %tbody
         - @sites.each do |site|
-          - next unless site.jekyll
-          - rol = current_usuarie.rol_for_site(site)
-          -#
-            TODO: Solo les usuaries cachean porque tenemos que separar
-            les botones por permisos.
-          - cache_if (rol.usuarie? && !rol.temporal), [site, I18n.locale] do
-            %tr
-              %td
-                %h2
-                  - if policy(site).show?
-                    = link_to site.title, site_posts_path(site, locale: site.default_locale)
+          - begin
+            - next unless site.jekyll
+            - rol = current_usuarie.rol_for_site(site)
+            -#
+              TODO: Solo les usuaries cachean porque tenemos que separar
+              les botones por permisos.
+            - cache_if (rol.usuarie? && !rol.temporal), [site, I18n.locale] do
+              %tr
+                %td
+                  %h2
+                    - if policy(site).show?
+                      = link_to site.title, site_posts_path(site, locale: site.default_locale)
+                    - else
+                      = site.title
+                  %p.lead= site.description
+                  %br
+                  = link_to t('.visit'), site.url, class: 'btn'
+                  - if rol.temporal
+                    = button_to t('sites.invitations.accept'),
+                      site_usuaries_accept_invitation_path(site),
+                      method: :patch,
+                      title: t('help.sites.invitations.accept'),
+                      class: 'btn'
+                    = button_to t('sites.invitations.reject'),
+                      site_usuaries_reject_invitation_path(site),
+                      method: :patch,
+                      title: t('help.sites.invitations.reject'),
+                      class: 'btn'
                   - else
-                    = site.title
-                %p.lead= site.description
-                %br
-                = link_to t('.visit'), site.url, class: 'btn'
-                - if rol.temporal
-                  = button_to t('sites.invitations.accept'),
-                    site_usuaries_accept_invitation_path(site),
-                    method: :patch,
-                    title: t('help.sites.invitations.accept'),
-                    class: 'btn'
-                  = button_to t('sites.invitations.reject'),
-                    site_usuaries_reject_invitation_path(site),
-                    method: :patch,
-                    title: t('help.sites.invitations.reject'),
-                    class: 'btn'
-                - else
-                  - if policy(site).show?
-                    = render 'layouts/btn_with_tooltip',
-                      tooltip: t('help.sites.edit_posts'),
-                      type: 'success',
-                      link: site_path(site),
-                      text: t('sites.posts')
-                  - if policy(SiteUsuarie.new(site, current_usuarie)).index?
-                    = render 'layouts/btn_with_tooltip',
-                      tooltip: t('usuaries.index.help.self'),
-                      text: t('usuaries.index.title'),
-                      type: 'info',
-                      link: site_usuaries_path(site)
-                  = render 'sites/build', site: site
+                    - if policy(site).show?
+                      = render 'layouts/btn_with_tooltip',
+                        tooltip: t('help.sites.edit_posts'),
+                        type: 'success',
+                        link: site_path(site),
+                        text: t('sites.posts')
+                    - if policy(SiteUsuarie.new(site, current_usuarie)).index?
+                      = render 'layouts/btn_with_tooltip',
+                        tooltip: t('usuaries.index.help.self'),
+                        text: t('usuaries.index.title'),
+                        type: 'info',
+                        link: site_usuaries_path(site)
+                    = render 'sites/build', site: site
+          - rescue ActionView::Template::Error => e
+            - ExceptionNotifier.notify_exception(e.cause, data: { site: @site.name, usuarie: current_usuarie.id })
-- 
GitLab


From a81b59035645410f659318383b3b667e83d5a0e1 Mon Sep 17 00:00:00 2001
From: f <f@sutty.nl>
Date: Tue, 19 Jul 2022 14:15:06 -0300
Subject: [PATCH 5/6] =?UTF-8?q?no=20fallar=20si=20el=20sitio=20no=20existe?=
 =?UTF-8?q?=20m=C3=A1s?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/views/sites/index.haml | 85 ++++++++++++++++++++------------------
 1 file changed, 44 insertions(+), 41 deletions(-)

diff --git a/app/views/sites/index.haml b/app/views/sites/index.haml
index b3d99ca53..4b483e755 100644
--- a/app/views/sites/index.haml
+++ b/app/views/sites/index.haml
@@ -14,47 +14,50 @@
     %table.table.table-condensed
       %tbody
         - @sites.each do |site|
+          -# Los sitios pueden fallar en cargar si los eliminamos físicamente del disco
           - begin
             - next unless site.jekyll
-            - rol = current_usuarie.rol_for_site(site)
-            -#
-              TODO: Solo les usuaries cachean porque tenemos que separar
-              les botones por permisos.
-            - cache_if (rol.usuarie? && !rol.temporal), [site, I18n.locale] do
-              %tr
-                %td
-                  %h2
-                    - if policy(site).show?
-                      = link_to site.title, site_posts_path(site, locale: site.default_locale)
-                    - else
-                      = site.title
-                  %p.lead= site.description
-                  %br
-                  = link_to t('.visit'), site.url, class: 'btn'
-                  - if rol.temporal
-                    = button_to t('sites.invitations.accept'),
-                      site_usuaries_accept_invitation_path(site),
-                      method: :patch,
-                      title: t('help.sites.invitations.accept'),
-                      class: 'btn'
-                    = button_to t('sites.invitations.reject'),
-                      site_usuaries_reject_invitation_path(site),
-                      method: :patch,
-                      title: t('help.sites.invitations.reject'),
-                      class: 'btn'
+          - rescue StandardError => e
+            - ExceptionNotifier.notify_exception(e, data: { site: @site.name, usuarie: current_usuarie.id })
+            - next
+
+          - rol = current_usuarie.rol_for_site(site)
+          -#
+            TODO: Solo les usuaries cachean porque tenemos que separar
+            les botones por permisos.
+          - cache_if (rol.usuarie? && !rol.temporal), [site, I18n.locale] do
+            %tr
+              %td
+                %h2
+                  - if policy(site).show?
+                    = link_to site.title, site_posts_path(site, locale: site.default_locale)
                   - else
-                    - if policy(site).show?
-                      = render 'layouts/btn_with_tooltip',
-                        tooltip: t('help.sites.edit_posts'),
-                        type: 'success',
-                        link: site_path(site),
-                        text: t('sites.posts')
-                    - if policy(SiteUsuarie.new(site, current_usuarie)).index?
-                      = render 'layouts/btn_with_tooltip',
-                        tooltip: t('usuaries.index.help.self'),
-                        text: t('usuaries.index.title'),
-                        type: 'info',
-                        link: site_usuaries_path(site)
-                    = render 'sites/build', site: site
-          - rescue ActionView::Template::Error => e
-            - ExceptionNotifier.notify_exception(e.cause, data: { site: @site.name, usuarie: current_usuarie.id })
+                    = site.title
+                %p.lead= site.description
+                %br
+                = link_to t('.visit'), site.url, class: 'btn'
+                - if rol.temporal
+                  = button_to t('sites.invitations.accept'),
+                    site_usuaries_accept_invitation_path(site),
+                    method: :patch,
+                    title: t('help.sites.invitations.accept'),
+                    class: 'btn'
+                  = button_to t('sites.invitations.reject'),
+                    site_usuaries_reject_invitation_path(site),
+                    method: :patch,
+                    title: t('help.sites.invitations.reject'),
+                    class: 'btn'
+                - else
+                  - if policy(site).show?
+                    = render 'layouts/btn_with_tooltip',
+                      tooltip: t('help.sites.edit_posts'),
+                      type: 'success',
+                      link: site_path(site),
+                      text: t('sites.posts')
+                  - if policy(SiteUsuarie.new(site, current_usuarie)).index?
+                    = render 'layouts/btn_with_tooltip',
+                      tooltip: t('usuaries.index.help.self'),
+                      text: t('usuaries.index.title'),
+                      type: 'info',
+                      link: site_usuaries_path(site)
+                  = render 'sites/build', site: site
-- 
GitLab


From a07611b2dcb106ec5c9554b94509ae111dc12f1c Mon Sep 17 00:00:00 2001
From: f <f@sutty.nl>
Date: Tue, 19 Jul 2022 14:18:39 -0300
Subject: [PATCH 6/6] =?UTF-8?q?fixup!=20no=20fallar=20si=20el=20sitio=20no?=
 =?UTF-8?q?=20existe=20m=C3=A1s?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/views/sites/index.haml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/views/sites/index.haml b/app/views/sites/index.haml
index 4b483e755..fb4b9780f 100644
--- a/app/views/sites/index.haml
+++ b/app/views/sites/index.haml
@@ -18,7 +18,7 @@
           - begin
             - next unless site.jekyll
           - rescue StandardError => e
-            - ExceptionNotifier.notify_exception(e, data: { site: @site.name, usuarie: current_usuarie.id })
+            - ExceptionNotifier.notify_exception(e, data: { site: site.name, usuarie: current_usuarie.id })
             - next
 
           - rol = current_usuarie.rol_for_site(site)
-- 
GitLab