From 0e5548804613f23b4e0303455a0086e98895d48f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Gaya?= <sebastien.gaya@gmail.com>
Date: Thu, 21 Oct 2021 18:41:44 +0200
Subject: [PATCH] medium

---
 .../communication/websites_controller.rb      |  4 +-
 .../communication/website/imported/medium.rb  | 78 ++++++++++---------
 .../communication/website/imported/page.rb    |  9 ++-
 .../communication/website/imported/post.rb    |  3 +
 app/models/communication/website/medium.rb    | 68 ++++++++++++++++
 app/models/communication/website/post.rb      |  1 +
 .../communication/websites/import.html.erb    |  6 +-
 ...2416_create_communication_website_media.rb | 14 ++++
 ...to_communication_website_imported_media.rb |  5 ++
 ...in_communication_website_imported_media.rb |  8 ++
 ...to_communication_website_imported_media.rb |  5 ++
 db/schema.rb                                  | 27 +++++--
 .../communication/website/imported/media.yml  | 24 +++---
 test/fixtures/communication/website/media.yml | 32 ++++++++
 .../website/imported/medium_test.rb           | 24 +++---
 .../communication/website/medium_test.rb      | 31 ++++++++
 16 files changed, 265 insertions(+), 74 deletions(-)
 create mode 100644 app/models/communication/website/medium.rb
 create mode 100644 db/migrate/20211021132416_create_communication_website_media.rb
 create mode 100644 db/migrate/20211021132440_add_medium_to_communication_website_imported_media.rb
 create mode 100644 db/migrate/20211021144633_replace_datetimes_in_communication_website_imported_media.rb
 create mode 100644 db/migrate/20211021152728_add_mime_type_to_communication_website_imported_media.rb
 create mode 100644 test/fixtures/communication/website/media.yml
 create mode 100644 test/models/communication/website/medium_test.rb

diff --git a/app/controllers/admin/communication/websites_controller.rb b/app/controllers/admin/communication/websites_controller.rb
index fbe9b765d..4a96cf0be 100644
--- a/app/controllers/admin/communication/websites_controller.rb
+++ b/app/controllers/admin/communication/websites_controller.rb
@@ -22,8 +22,8 @@ class Admin::Communication::WebsitesController < Admin::Communication::Applicati
     @imported_website = @website.imported_website
     @imported_pages = @imported_website.pages.page params[:pages_page]
     @imported_posts = @imported_website.posts.page params[:posts_page]
-    @imported_media = @imported_website.media.with_attached_file.page params[:media_page]
-    @imported_media_total_size = @imported_website.media.joins(file_attachment: :blob).sum(:byte_size)
+    @imported_media = @imported_website.media.includes(medium: { file_attachment: :blob }).page params[:media_page]
+    @imported_media_total_size = @imported_website.media.joins(medium: { file_attachment: :blob }).sum(:byte_size)
     breadcrumb
     add_breadcrumb Communication::Website::Imported::Website.model_name.human
   end
diff --git a/app/models/communication/website/imported/medium.rb b/app/models/communication/website/imported/medium.rb
index ad2308180..0331b0903 100644
--- a/app/models/communication/website/imported/medium.rb
+++ b/app/models/communication/website/imported/medium.rb
@@ -2,25 +2,27 @@
 #
 # Table name: communication_website_imported_media
 #
-#  id                :uuid             not null, primary key
-#  data              :jsonb
-#  file_url          :text
-#  filename          :string
-#  identifier        :string
-#  remote_created_at :datetime
-#  remote_updated_at :datetime
-#  created_at        :datetime         not null
-#  updated_at        :datetime         not null
-#  university_id     :uuid             not null
-#  website_id        :uuid             not null
+#  id            :uuid             not null, primary key
+#  data          :jsonb
+#  file_url      :text
+#  filename      :string
+#  identifier    :string
+#  mime_type     :string
+#  created_at    :datetime
+#  updated_at    :datetime
+#  medium_id     :uuid
+#  university_id :uuid             not null
+#  website_id    :uuid             not null
 #
 # Indexes
 #
+#  index_communication_website_imported_media_on_medium_id      (medium_id)
 #  index_communication_website_imported_media_on_university_id  (university_id)
 #  index_communication_website_imported_media_on_website_id     (website_id)
 #
 # Foreign Keys
 #
+#  fk_rails_...  (medium_id => communication_website_media.id)
 #  fk_rails_...  (university_id => universities.id)
 #  fk_rails_...  (website_id => communication_website_imported_websites.id)
 #
@@ -28,43 +30,43 @@ class Communication::Website::Imported::Medium < ApplicationRecord
   belongs_to :university
   belongs_to :website,
              class_name: 'Communication::Website::Imported::Website'
+  belongs_to :medium,
+             class_name: 'Communication::Website::Medium',
+             optional: true
   has_many :pages, class_name: 'Communication::Website::Imported::Page', foreign_key: :featured_medium_id
   has_many :posts, class_name: 'Communication::Website::Imported::Post', foreign_key: :featured_medium_id
 
-  has_one_attached :file
-
-  after_commit :download_file_from_file_url, on: [:create, :update], if: :saved_change_to_file_url
+  before_validation :sync
 
   def data=(value)
     super value
-    escaped_source_url = Addressable::URI.parse(value['source_url']).display_uri.to_s
-    self.file_url = escaped_source_url
-    self.filename = File.basename(URI(escaped_source_url).path)
-    # TODO unify with page and post?
-    self.remote_created_at = DateTime.parse(value['date_gmt'])
-    self.remote_updated_at = DateTime.parse(value['modified_gmt'])
+    sanitized_file_url = Addressable::URI.parse(value['source_url']).display_uri.to_s # ASCII-only for URI
+    self.file_url = sanitized_file_url
+    self.filename = File.basename(URI(file_url).path)
+    self.mime_type = value['mime_type']
+    self.created_at = value['date_gmt']
+    self.updated_at = value['modified_gmt']
   end
 
   protected
 
-  def download_file_from_file_url
-    uri = URI(file_url)
-    http = Net::HTTP.new(uri.host, uri.port)
-    http.use_ssl = true
-    # IUT Bordeaux Montaigne pb with certificate
-    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
-    request = Net::HTTP::Get.new(uri.request_uri)
-    response = http.request(request)
-    tempfile = Tempfile.open("Osuny-ImportedMedium-#{SecureRandom.hex}", Dir.tmpdir)
-    begin
-      tempfile.binmode
-      tempfile.write(response.body)
-      tempfile.flush
-      tempfile.rewind
-      file.attach(io: tempfile, filename: filename, content_type: data['mime_type'])
-    ensure
-      tempfile.close!
+  def sync
+    if medium.nil?
+      self.medium = Communication::Website::Medium.new  university: university,
+                                                        website: website.website # Real website, not imported website
+      self.medium.save
+    else
+      # Continue only if there are remote changes
+      # Don't touch if there are local changes (page.updated_at > updated_at)
+      # Don't touch if there are no remote changes (page.updated_at == updated_at)
+      return unless updated_at > medium.updated_at
     end
+    puts "Update medium #{medium.id}"
+    medium.file_url = Addressable::URI.parse(file_url).display_uri.to_s # ASCII-only for ActiveStorage
+    medium.filename = File.basename(URI(medium.file_url).path)
+    medium.mime_type = mime_type
+    medium.created_at = created_at
+    medium.updated_at = updated_at
+    medium.save
   end
-  handle_asynchronously :download_file_from_file_url, queue: 'default'
 end
diff --git a/app/models/communication/website/imported/page.rb b/app/models/communication/website/imported/page.rb
index 25f6fb93e..10de05dda 100644
--- a/app/models/communication/website/imported/page.rb
+++ b/app/models/communication/website/imported/page.rb
@@ -75,11 +75,12 @@ class Communication::Website::Imported::Page < ApplicationRecord
                                                     slug: path
       self.page.title = "Untitled"
       self.page.save
+    else
+      # Continue only if there are remote changes
+      # Don't touch if there are local changes (page.updated_at > updated_at)
+      # Don't touch if there are no remote changes (page.updated_at == updated_at)
+      return unless updated_at > page.updated_at
     end
-    # Don't touch if there are local changes (this would destroy some nice work)
-    return if page.updated_at > updated_at
-    # Don't touch if there are no remote changes (this would do useless server workload)
-    return if page.updated_at == updated_at
     puts "Update page #{page.id}"
     page.slug = slug
     page.title = Wordpress.clean title.to_s
diff --git a/app/models/communication/website/imported/post.rb b/app/models/communication/website/imported/post.rb
index 20cc39941..19ecc883e 100644
--- a/app/models/communication/website/imported/post.rb
+++ b/app/models/communication/website/imported/post.rb
@@ -89,6 +89,9 @@ class Communication::Website::Imported::Post < ApplicationRecord
     post.created_at = created_at
     post.updated_at = updated_at
     post.published_at = published_at if published_at
+    if featured_medium.nil?
+      # Use first image in text as featured medium
+    end
     post.save
   end
 end
diff --git a/app/models/communication/website/medium.rb b/app/models/communication/website/medium.rb
new file mode 100644
index 000000000..b9fd23689
--- /dev/null
+++ b/app/models/communication/website/medium.rb
@@ -0,0 +1,68 @@
+# == Schema Information
+#
+# Table name: communication_website_media
+#
+#  id            :uuid             not null, primary key
+#  file_url      :text
+#  filename      :string
+#  identifier    :string
+#  mime_type     :string
+#  created_at    :datetime         not null
+#  updated_at    :datetime         not null
+#  university_id :uuid             not null
+#  website_id    :uuid             not null
+#
+# Indexes
+#
+#  index_communication_website_media_on_university_id  (university_id)
+#  index_communication_website_media_on_website_id     (website_id)
+#
+# Foreign Keys
+#
+#  fk_rails_...  (university_id => universities.id)
+#  fk_rails_...  (website_id => communication_websites.id)
+#
+class Communication::Website::Medium < ApplicationRecord
+  belongs_to :university
+  belongs_to :website
+  has_one    :imported_medium,
+             class_name: 'Communication::Website::Imported::Medium',
+             foreign_key: :medium_id,
+             dependent: :destroy
+
+  has_one_attached_deletable :file
+
+  after_commit :download_file_from_file_url, on: [:create, :update], if: :saved_change_to_file_url
+
+  protected
+
+  def download_file_from_file_url
+    uri = URI(file_url)
+    http = Net::HTTP.new(uri.host, uri.port)
+    http.use_ssl = true
+    # IUT Bordeaux Montaigne pb with certificate
+    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+    request = Net::HTTP::Get.new(uri.request_uri)
+    response = http.request(request)
+    tempfile = Tempfile.open("Osuny-CommunicationWebsiteMedium-#{SecureRandom.hex}", Dir.tmpdir)
+    begin
+      tempfile.binmode
+      tempfile.write(response.body)
+      tempfile.flush
+      tempfile.rewind
+      file.attach(io: tempfile, filename: filename, content_type: mime_type)
+      set_featured_images
+    ensure
+      tempfile.close!
+    end
+  end
+  handle_asynchronously :download_file_from_file_url, queue: 'default'
+
+  def set_featured_images
+    posts = Communication::Website::Post.joins(:imported_post)
+                                        .where(communication_website_imported_posts: { featured_medium_id: imported_medium.id })
+    posts.each do |post|
+      post.featured_image.attach(io: URI.open(file.url), filename: filename, content_type: mime_type)
+    end
+  end
+end
diff --git a/app/models/communication/website/post.rb b/app/models/communication/website/post.rb
index 1a146d187..8919f6b46 100644
--- a/app/models/communication/website/post.rb
+++ b/app/models/communication/website/post.rb
@@ -29,6 +29,7 @@ class Communication::Website::Post < ApplicationRecord
   include Communication::Website::WithGithub
 
   has_rich_text :text
+  has_one_attached_deletable :featured_image
 
   belongs_to :university
   belongs_to :website,
diff --git a/app/views/admin/communication/websites/import.html.erb b/app/views/admin/communication/websites/import.html.erb
index 086d4f676..4b8432431 100644
--- a/app/views/admin/communication/websites/import.html.erb
+++ b/app/views/admin/communication/websites/import.html.erb
@@ -84,11 +84,11 @@
       <% @imported_media.each do |medium| %>
         <tr>
           <td><%= medium.filename %></td>
-          <td><%= number_to_human_size(medium.file.blob.byte_size) if medium.file.attached? %></td>
+          <td><%= number_to_human_size(medium.medium.file.blob.byte_size) if medium.medium&.file&.attached? %></td>
           <td class="text-end">
-            <% if medium.file.attached? %>
+            <% if medium.medium&.file&.attached? %>
               <%= link_to t('show'),
-                            url_for(medium.file),
+                            url_for(medium.medium.file),
                             class: button_classes,
                             target: :blank %>
             <% else %>
diff --git a/db/migrate/20211021132416_create_communication_website_media.rb b/db/migrate/20211021132416_create_communication_website_media.rb
new file mode 100644
index 000000000..4c67abade
--- /dev/null
+++ b/db/migrate/20211021132416_create_communication_website_media.rb
@@ -0,0 +1,14 @@
+class CreateCommunicationWebsiteMedia < ActiveRecord::Migration[6.1]
+  def change
+    create_table :communication_website_media, id: :uuid do |t|
+      t.string :identifier
+      t.string :filename
+      t.string :mime_type
+      t.text :file_url
+      t.references :university, null: false, foreign_key: true, type: :uuid
+      t.references :website, null: false, foreign_key: { to_table: :communication_websites }, type: :uuid
+
+      t.timestamps
+    end
+  end
+end
diff --git a/db/migrate/20211021132440_add_medium_to_communication_website_imported_media.rb b/db/migrate/20211021132440_add_medium_to_communication_website_imported_media.rb
new file mode 100644
index 000000000..3c0ed4f57
--- /dev/null
+++ b/db/migrate/20211021132440_add_medium_to_communication_website_imported_media.rb
@@ -0,0 +1,5 @@
+class AddMediumToCommunicationWebsiteImportedMedia < ActiveRecord::Migration[6.1]
+  def change
+    add_reference :communication_website_imported_media, :medium, foreign_key: { to_table: :communication_website_media }, type: :uuid
+  end
+end
diff --git a/db/migrate/20211021144633_replace_datetimes_in_communication_website_imported_media.rb b/db/migrate/20211021144633_replace_datetimes_in_communication_website_imported_media.rb
new file mode 100644
index 000000000..667fb85a3
--- /dev/null
+++ b/db/migrate/20211021144633_replace_datetimes_in_communication_website_imported_media.rb
@@ -0,0 +1,8 @@
+class ReplaceDatetimesInCommunicationWebsiteImportedMedia < ActiveRecord::Migration[6.1]
+  def change
+    remove_column :communication_website_imported_media, :created_at, :datetime
+    remove_column :communication_website_imported_media, :updated_at, :datetime
+    rename_column :communication_website_imported_media, :remote_created_at, :created_at
+    rename_column :communication_website_imported_media, :remote_updated_at, :updated_at
+  end
+end
diff --git a/db/migrate/20211021152728_add_mime_type_to_communication_website_imported_media.rb b/db/migrate/20211021152728_add_mime_type_to_communication_website_imported_media.rb
new file mode 100644
index 000000000..22a217137
--- /dev/null
+++ b/db/migrate/20211021152728_add_mime_type_to_communication_website_imported_media.rb
@@ -0,0 +1,5 @@
+class AddMimeTypeToCommunicationWebsiteImportedMedia < ActiveRecord::Migration[6.1]
+  def change
+    add_column :communication_website_imported_media, :mime_type, :string
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 84ec856e3..f632ae2c0 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 2021_10_21_095157) do
+ActiveRecord::Schema.define(version: 2021_10_21_152728) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "pgcrypto"
@@ -82,13 +82,14 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do
     t.string "identifier"
     t.jsonb "data"
     t.text "file_url"
-    t.datetime "remote_created_at"
-    t.datetime "remote_updated_at"
+    t.datetime "created_at"
+    t.datetime "updated_at"
     t.uuid "university_id", null: false
     t.uuid "website_id", null: false
-    t.datetime "created_at", precision: 6, null: false
-    t.datetime "updated_at", precision: 6, null: false
     t.string "filename"
+    t.uuid "medium_id"
+    t.string "mime_type"
+    t.index ["medium_id"], name: "index_communication_website_imported_media_on_medium_id"
     t.index ["university_id"], name: "index_communication_website_imported_media_on_university_id"
     t.index ["website_id"], name: "index_communication_website_imported_media_on_website_id"
   end
@@ -149,6 +150,19 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do
     t.index ["website_id"], name: "index_communication_website_imported_websites_on_website_id"
   end
 
+  create_table "communication_website_media", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+    t.string "identifier"
+    t.string "filename"
+    t.string "mime_type"
+    t.text "file_url"
+    t.uuid "university_id", null: false
+    t.uuid "website_id", null: false
+    t.datetime "created_at", precision: 6, null: false
+    t.datetime "updated_at", precision: 6, null: false
+    t.index ["university_id"], name: "index_communication_website_media_on_university_id"
+    t.index ["website_id"], name: "index_communication_website_media_on_website_id"
+  end
+
   create_table "communication_website_pages", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "communication_website_id", null: false
@@ -366,6 +380,7 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do
   add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
   add_foreign_key "administration_qualiopi_indicators", "administration_qualiopi_criterions", column: "criterion_id"
   add_foreign_key "communication_website_imported_media", "communication_website_imported_websites", column: "website_id"
+  add_foreign_key "communication_website_imported_media", "communication_website_media", column: "medium_id"
   add_foreign_key "communication_website_imported_media", "universities"
   add_foreign_key "communication_website_imported_pages", "communication_website_imported_media", column: "featured_medium_id"
   add_foreign_key "communication_website_imported_pages", "communication_website_imported_websites", column: "website_id"
@@ -377,6 +392,8 @@ ActiveRecord::Schema.define(version: 2021_10_21_095157) do
   add_foreign_key "communication_website_imported_posts", "universities"
   add_foreign_key "communication_website_imported_websites", "communication_websites", column: "website_id"
   add_foreign_key "communication_website_imported_websites", "universities"
+  add_foreign_key "communication_website_media", "communication_websites", column: "website_id"
+  add_foreign_key "communication_website_media", "universities"
   add_foreign_key "communication_website_pages", "communication_website_pages", column: "parent_id"
   add_foreign_key "communication_website_pages", "communication_websites"
   add_foreign_key "communication_website_pages", "universities"
diff --git a/test/fixtures/communication/website/imported/media.yml b/test/fixtures/communication/website/imported/media.yml
index 3414bff4c..a0c0f6823 100644
--- a/test/fixtures/communication/website/imported/media.yml
+++ b/test/fixtures/communication/website/imported/media.yml
@@ -2,25 +2,27 @@
 #
 # Table name: communication_website_imported_media
 #
-#  id                :uuid             not null, primary key
-#  data              :jsonb
-#  file_url          :text
-#  filename          :string
-#  identifier        :string
-#  remote_created_at :datetime
-#  remote_updated_at :datetime
-#  created_at        :datetime         not null
-#  updated_at        :datetime         not null
-#  university_id     :uuid             not null
-#  website_id        :uuid             not null
+#  id            :uuid             not null, primary key
+#  data          :jsonb
+#  file_url      :text
+#  filename      :string
+#  identifier    :string
+#  mime_type     :string
+#  created_at    :datetime
+#  updated_at    :datetime
+#  medium_id     :uuid
+#  university_id :uuid             not null
+#  website_id    :uuid             not null
 #
 # Indexes
 #
+#  index_communication_website_imported_media_on_medium_id      (medium_id)
 #  index_communication_website_imported_media_on_university_id  (university_id)
 #  index_communication_website_imported_media_on_website_id     (website_id)
 #
 # Foreign Keys
 #
+#  fk_rails_...  (medium_id => communication_website_media.id)
 #  fk_rails_...  (university_id => universities.id)
 #  fk_rails_...  (website_id => communication_website_imported_websites.id)
 #
diff --git a/test/fixtures/communication/website/media.yml b/test/fixtures/communication/website/media.yml
new file mode 100644
index 000000000..d50a108ec
--- /dev/null
+++ b/test/fixtures/communication/website/media.yml
@@ -0,0 +1,32 @@
+# == Schema Information
+#
+# Table name: communication_website_media
+#
+#  id            :uuid             not null, primary key
+#  file_url      :text
+#  filename      :string
+#  identifier    :string
+#  mime_type     :string
+#  created_at    :datetime         not null
+#  updated_at    :datetime         not null
+#  university_id :uuid             not null
+#  website_id    :uuid             not null
+#
+# Indexes
+#
+#  index_communication_website_media_on_university_id  (university_id)
+#  index_communication_website_media_on_website_id     (website_id)
+#
+# Foreign Keys
+#
+#  fk_rails_...  (university_id => universities.id)
+#  fk_rails_...  (website_id => communication_websites.id)
+#
+
+one:
+  university: one
+  website: one
+
+two:
+  university: two
+  website: two
diff --git a/test/models/communication/website/imported/medium_test.rb b/test/models/communication/website/imported/medium_test.rb
index c084dcee9..e20280d2a 100644
--- a/test/models/communication/website/imported/medium_test.rb
+++ b/test/models/communication/website/imported/medium_test.rb
@@ -2,25 +2,27 @@
 #
 # Table name: communication_website_imported_media
 #
-#  id                :uuid             not null, primary key
-#  data              :jsonb
-#  file_url          :text
-#  filename          :string
-#  identifier        :string
-#  remote_created_at :datetime
-#  remote_updated_at :datetime
-#  created_at        :datetime         not null
-#  updated_at        :datetime         not null
-#  university_id     :uuid             not null
-#  website_id        :uuid             not null
+#  id            :uuid             not null, primary key
+#  data          :jsonb
+#  file_url      :text
+#  filename      :string
+#  identifier    :string
+#  mime_type     :string
+#  created_at    :datetime
+#  updated_at    :datetime
+#  medium_id     :uuid
+#  university_id :uuid             not null
+#  website_id    :uuid             not null
 #
 # Indexes
 #
+#  index_communication_website_imported_media_on_medium_id      (medium_id)
 #  index_communication_website_imported_media_on_university_id  (university_id)
 #  index_communication_website_imported_media_on_website_id     (website_id)
 #
 # Foreign Keys
 #
+#  fk_rails_...  (medium_id => communication_website_media.id)
 #  fk_rails_...  (university_id => universities.id)
 #  fk_rails_...  (website_id => communication_website_imported_websites.id)
 #
diff --git a/test/models/communication/website/medium_test.rb b/test/models/communication/website/medium_test.rb
new file mode 100644
index 000000000..216a43e11
--- /dev/null
+++ b/test/models/communication/website/medium_test.rb
@@ -0,0 +1,31 @@
+# == Schema Information
+#
+# Table name: communication_website_media
+#
+#  id            :uuid             not null, primary key
+#  file_url      :text
+#  filename      :string
+#  identifier    :string
+#  mime_type     :string
+#  created_at    :datetime         not null
+#  updated_at    :datetime         not null
+#  university_id :uuid             not null
+#  website_id    :uuid             not null
+#
+# Indexes
+#
+#  index_communication_website_media_on_university_id  (university_id)
+#  index_communication_website_media_on_website_id     (website_id)
+#
+# Foreign Keys
+#
+#  fk_rails_...  (university_id => universities.id)
+#  fk_rails_...  (website_id => communication_websites.id)
+#
+require "test_helper"
+
+class Communication::Website::MediumTest < ActiveSupport::TestCase
+  # test "the truth" do
+  #   assert true
+  # end
+end
-- 
GitLab