From b82d1c2ca918ef951495641f8be1e23fbb01676c Mon Sep 17 00:00:00 2001
From: Benjamin Neff <benjamin@coding4coffee.ch>
Date: Thu, 21 Jul 2016 00:51:02 +0200
Subject: [PATCH] add migration for signature tables

---
 .../20160720212620_create_signature_tables.rb | 87 +++++++++++++++++++
 db/schema.rb                                  | 69 +++++++++++----
 2 files changed, 141 insertions(+), 15 deletions(-)
 create mode 100644 db/migrate/20160720212620_create_signature_tables.rb

diff --git a/db/migrate/20160720212620_create_signature_tables.rb b/db/migrate/20160720212620_create_signature_tables.rb
new file mode 100644
index 0000000000..8c8157d481
--- /dev/null
+++ b/db/migrate/20160720212620_create_signature_tables.rb
@@ -0,0 +1,87 @@
+class CreateSignatureTables < ActiveRecord::Migration
+  class SignatureOrder < ActiveRecord::Base
+  end
+
+  RELAYABLES = %i(comment like poll_participation).freeze
+
+  def self.up
+    create_table :signature_orders do |t|
+      t.string :order, null: false
+    end
+    add_index :signature_orders, :order, length: 191, unique: true
+
+    RELAYABLES.each {|relayable_type| create_signature_table(relayable_type) }
+
+    migrate_signatures
+
+    RELAYABLES.each {|relayable_type| remove_column "#{relayable_type}s", :author_signature }
+  end
+
+  def self.down
+    RELAYABLES.each {|relayable_type| add_column "#{relayable_type}s", :author_signature, :text }
+
+    RELAYABLES.each {|relayable_type| restore_signatures(relayable_type) }
+
+    drop_table :comment_signatures
+    drop_table :like_signatures
+    drop_table :poll_participation_signatures
+    drop_table :signature_orders
+  end
+
+  private
+
+  def create_signature_table(relayable_type)
+    create_table "#{relayable_type}_signatures", id: false do |t|
+      t.integer "#{relayable_type}_id", null: false
+      t.text    :author_signature,      null: false
+      t.integer :signature_order_id,    null: false
+      t.text    :additional_data
+    end
+
+    add_index "#{relayable_type}_signatures", "#{relayable_type}_id", unique: true
+
+    add_foreign_key "#{relayable_type}_signatures", :signature_orders,
+                    name: "#{relayable_type}_signatures_signature_orders_id_fk"
+    add_foreign_key "#{relayable_type}_signatures", "#{relayable_type}s",
+                    name: "#{relayable_type}_signatures_#{relayable_type}_id_fk", on_delete: :cascade
+  end
+
+  def migrate_signatures
+    comment_order_id = SignatureOrder.create!(order: "guid parent_guid text author").id
+    comment_parent_join = "INNER JOIN posts AS parent ON relayable.commentable_id = parent.id"
+    migrate_signatures_for(:comment, comment_order_id, comment_parent_join)
+
+    like_order_id = SignatureOrder.create!(order: "positive guid parent_type parent_guid author").id
+    post_like_join = "INNER JOIN posts AS parent ON relayable.target_id = parent.id AND relayable.target_type = 'Post'"
+    comment_like_join = "INNER JOIN comments ON relayable.target_id = comments.id " \
+                        "AND relayable.target_type = 'Comment' " \
+                        "INNER JOIN posts AS parent ON comments.commentable_id = parent.id"
+    migrate_signatures_for(:like, like_order_id, post_like_join)
+    migrate_signatures_for(:like, like_order_id, comment_like_join)
+
+    poll_participation_order_id = SignatureOrder.create!(order: "guid parent_guid author poll_answer_guid").id
+    poll_participation_parent_join = "INNER JOIN polls ON relayable.poll_id = polls.id " \
+                                     "INNER JOIN posts AS parent ON polls.status_message_id = parent.id"
+    migrate_signatures_for(:poll_participation, poll_participation_order_id, poll_participation_parent_join)
+  end
+
+  def migrate_signatures_for(relayable_type, order_id, parent_join)
+    execute "INSERT INTO #{relayable_type}_signatures (#{relayable_type}_id, signature_order_id, author_signature) " \
+            "SELECT relayable.id, #{order_id}, relayable.author_signature FROM #{relayable_type}s AS relayable " \
+            "INNER JOIN people AS author ON relayable.author_id = author.id " \
+            "#{parent_join} INNER JOIN people AS parent_author ON parent.author_id = parent_author.id " \
+            "WHERE author.owner_id IS NULL AND parent_author.owner_id IS NOT NULL"
+  end
+
+  def restore_signatures(relayable_type)
+    if AppConfig.postgres?
+      execute "UPDATE #{relayable_type}s SET author_signature = #{relayable_type}_signatures.author_signature " \
+              "FROM #{relayable_type}_signatures " \
+              "WHERE #{relayable_type}s.id = #{relayable_type}_signatures.#{relayable_type}_id "
+    else
+      execute "UPDATE #{relayable_type}s INNER JOIN #{relayable_type}_signatures " \
+              "ON #{relayable_type}s.id = #{relayable_type}_signatures.#{relayable_type}_id " \
+              "SET #{relayable_type}s.author_signature = #{relayable_type}_signatures.author_signature"
+    end
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 88ef2d80f9..5e9267dd91 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 20160618033455) do
+ActiveRecord::Schema.define(version: 20160720212620) do
 
   create_table "account_deletions", force: :cascade do |t|
     t.string   "diaspora_handle", limit: 255
@@ -100,12 +100,21 @@ ActiveRecord::Schema.define(version: 20160618033455) do
     t.datetime "created_at",               null: false
   end
 
+  create_table "comment_signatures", id: false, force: :cascade do |t|
+    t.integer "comment_id",         limit: 4,     null: false
+    t.text    "author_signature",   limit: 65535, null: false
+    t.integer "signature_order_id", limit: 4,     null: false
+    t.text    "additional_data",    limit: 65535
+  end
+
+  add_index "comment_signatures", ["comment_id"], name: "index_comment_signatures_on_comment_id", unique: true, using: :btree
+  add_index "comment_signatures", ["signature_order_id"], name: "comment_signatures_signature_orders_id_fk", using: :btree
+
   create_table "comments", force: :cascade do |t|
     t.text     "text",             limit: 65535,                  null: false
     t.integer  "commentable_id",   limit: 4,                      null: false
     t.integer  "author_id",        limit: 4,                      null: false
     t.string   "guid",             limit: 255,                    null: false
-    t.text     "author_signature", limit: 65535
     t.datetime "created_at",                                      null: false
     t.datetime "updated_at",                                      null: false
     t.integer  "likes_count",      limit: 4,     default: 0,      null: false
@@ -186,15 +195,24 @@ ActiveRecord::Schema.define(version: 20160618033455) do
   add_index "invitations", ["recipient_id"], name: "index_invitations_on_recipient_id", using: :btree
   add_index "invitations", ["sender_id"], name: "index_invitations_on_sender_id", using: :btree
 
+  create_table "like_signatures", id: false, force: :cascade do |t|
+    t.integer "like_id",            limit: 4,     null: false
+    t.text    "author_signature",   limit: 65535, null: false
+    t.integer "signature_order_id", limit: 4,     null: false
+    t.text    "additional_data",    limit: 65535
+  end
+
+  add_index "like_signatures", ["like_id"], name: "index_like_signatures_on_like_id", unique: true, using: :btree
+  add_index "like_signatures", ["signature_order_id"], name: "like_signatures_signature_orders_id_fk", using: :btree
+
   create_table "likes", force: :cascade do |t|
-    t.boolean  "positive",                       default: true
-    t.integer  "target_id",        limit: 4
-    t.integer  "author_id",        limit: 4
-    t.string   "guid",             limit: 255
-    t.text     "author_signature", limit: 65535
-    t.datetime "created_at",                                    null: false
-    t.datetime "updated_at",                                    null: false
-    t.string   "target_type",      limit: 60,                   null: false
+    t.boolean  "positive",                default: true
+    t.integer  "target_id",   limit: 4
+    t.integer  "author_id",   limit: 4
+    t.string   "guid",        limit: 255
+    t.datetime "created_at",                             null: false
+    t.datetime "updated_at",                             null: false
+    t.string   "target_type", limit: 60,                 null: false
   end
 
   add_index "likes", ["author_id"], name: "likes_author_id_fk", using: :btree
@@ -394,12 +412,21 @@ ActiveRecord::Schema.define(version: 20160618033455) do
   add_index "poll_answers", ["guid"], name: "index_poll_answers_on_guid", unique: true, length: {"guid"=>191}, using: :btree
   add_index "poll_answers", ["poll_id"], name: "index_poll_answers_on_poll_id", using: :btree
 
+  create_table "poll_participation_signatures", id: false, force: :cascade do |t|
+    t.integer "poll_participation_id", limit: 4,     null: false
+    t.text    "author_signature",      limit: 65535, null: false
+    t.integer "signature_order_id",    limit: 4,     null: false
+    t.text    "additional_data",       limit: 65535
+  end
+
+  add_index "poll_participation_signatures", ["poll_participation_id"], name: "index_poll_participation_signatures_on_poll_participation_id", unique: true, using: :btree
+  add_index "poll_participation_signatures", ["signature_order_id"], name: "poll_participation_signatures_signature_orders_id_fk", using: :btree
+
   create_table "poll_participations", force: :cascade do |t|
-    t.integer  "poll_answer_id",   limit: 4,     null: false
-    t.integer  "author_id",        limit: 4,     null: false
-    t.integer  "poll_id",          limit: 4,     null: false
-    t.string   "guid",             limit: 255
-    t.text     "author_signature", limit: 65535
+    t.integer  "poll_answer_id", limit: 4,   null: false
+    t.integer  "author_id",      limit: 4,   null: false
+    t.integer  "poll_id",        limit: 4,   null: false
+    t.string   "guid",           limit: 255
     t.datetime "created_at"
     t.datetime "updated_at"
   end
@@ -557,6 +584,12 @@ ActiveRecord::Schema.define(version: 20160618033455) do
   add_index "share_visibilities", ["shareable_id"], name: "index_post_visibilities_on_post_id", using: :btree
   add_index "share_visibilities", ["user_id"], name: "index_share_visibilities_on_user_id", using: :btree
 
+  create_table "signature_orders", force: :cascade do |t|
+    t.string "order", limit: 255, null: false
+  end
+
+  add_index "signature_orders", ["order"], name: "index_signature_orders_on_order", unique: true, length: {"order"=>191}, using: :btree
+
   create_table "simple_captcha_data", force: :cascade do |t|
     t.string   "key",        limit: 40
     t.string   "value",      limit: 12
@@ -662,6 +695,8 @@ ActiveRecord::Schema.define(version: 20160618033455) do
   add_foreign_key "aspect_visibilities", "aspects", name: "aspect_visibilities_aspect_id_fk", on_delete: :cascade
   add_foreign_key "authorizations", "o_auth_applications"
   add_foreign_key "authorizations", "users"
+  add_foreign_key "comment_signatures", "comments", name: "comment_signatures_comment_id_fk", on_delete: :cascade
+  add_foreign_key "comment_signatures", "signature_orders", name: "comment_signatures_signature_orders_id_fk"
   add_foreign_key "comments", "people", column: "author_id", name: "comments_author_id_fk", on_delete: :cascade
   add_foreign_key "contacts", "people", name: "contacts_person_id_fk", on_delete: :cascade
   add_foreign_key "conversation_visibilities", "conversations", name: "conversation_visibilities_conversation_id_fk", on_delete: :cascade
@@ -670,6 +705,8 @@ ActiveRecord::Schema.define(version: 20160618033455) do
   add_foreign_key "id_tokens", "authorizations"
   add_foreign_key "invitations", "users", column: "recipient_id", name: "invitations_recipient_id_fk", on_delete: :cascade
   add_foreign_key "invitations", "users", column: "sender_id", name: "invitations_sender_id_fk", on_delete: :cascade
+  add_foreign_key "like_signatures", "likes", name: "like_signatures_like_id_fk", on_delete: :cascade
+  add_foreign_key "like_signatures", "signature_orders", name: "like_signatures_signature_orders_id_fk"
   add_foreign_key "likes", "people", column: "author_id", name: "likes_author_id_fk", on_delete: :cascade
   add_foreign_key "messages", "conversations", name: "messages_conversation_id_fk", on_delete: :cascade
   add_foreign_key "messages", "people", column: "author_id", name: "messages_author_id_fk", on_delete: :cascade
@@ -677,6 +714,8 @@ ActiveRecord::Schema.define(version: 20160618033455) do
   add_foreign_key "o_auth_access_tokens", "authorizations"
   add_foreign_key "o_auth_applications", "users"
   add_foreign_key "people", "pods", name: "people_pod_id_fk", on_delete: :cascade
+  add_foreign_key "poll_participation_signatures", "poll_participations", name: "poll_participation_signatures_poll_participation_id_fk", on_delete: :cascade
+  add_foreign_key "poll_participation_signatures", "signature_orders", name: "poll_participation_signatures_signature_orders_id_fk"
   add_foreign_key "posts", "people", column: "author_id", name: "posts_author_id_fk", on_delete: :cascade
   add_foreign_key "ppid", "o_auth_applications"
   add_foreign_key "ppid", "users"
-- 
GitLab