mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-23 20:18:00 +01:00
wip
This commit is contained in:
parent
f91d9f2143
commit
4d7f229641
17 changed files with 474 additions and 204 deletions
|
@ -10,13 +10,13 @@ defmodule Philomena.Comments do
|
||||||
alias PhilomenaQuery.Search
|
alias PhilomenaQuery.Search
|
||||||
alias Philomena.UserStatistics
|
alias Philomena.UserStatistics
|
||||||
alias Philomena.Comments.Comment
|
alias Philomena.Comments.Comment
|
||||||
|
alias Philomena.Comments.Version
|
||||||
alias Philomena.Comments.SearchIndex, as: CommentIndex
|
alias Philomena.Comments.SearchIndex, as: CommentIndex
|
||||||
alias Philomena.IndexWorker
|
alias Philomena.IndexWorker
|
||||||
alias Philomena.Images.Image
|
alias Philomena.Images.Image
|
||||||
alias Philomena.Images
|
alias Philomena.Images
|
||||||
alias Philomena.Notifications
|
alias Philomena.Notifications
|
||||||
alias Philomena.NotificationWorker
|
alias Philomena.NotificationWorker
|
||||||
alias Philomena.Versions
|
|
||||||
alias Philomena.Reports
|
alias Philomena.Reports
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
@ -93,21 +93,46 @@ defmodule Philomena.Comments do
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def update_comment(%Comment{} = comment, editor, attrs) do
|
def update_comment(%Comment{} = comment, editor, attrs) do
|
||||||
now = DateTime.utc_now(:second)
|
version_changeset =
|
||||||
current_body = comment.body
|
Version.changeset(%Version{}, comment, editor, %{
|
||||||
current_reason = comment.edit_reason
|
body: comment.body,
|
||||||
|
edit_reason: comment.edit_reason,
|
||||||
|
created_at: comment.edited_at || comment.created_at
|
||||||
|
})
|
||||||
|
|
||||||
comment_changes = Comment.changeset(comment, attrs, now)
|
now = DateTime.utc_now(:second)
|
||||||
|
comment_changeset = Comment.changeset(comment, attrs, now)
|
||||||
|
|
||||||
Multi.new()
|
Multi.new()
|
||||||
|> Multi.update(:comment, comment_changes)
|
|> Multi.insert(:version, version_changeset)
|
||||||
|> Multi.run(:version, fn _repo, _changes ->
|
|> Multi.update(:comment, comment_changeset)
|
||||||
Versions.create_version("Comment", comment.id, editor.id, %{
|
|
||||||
"body" => current_body,
|
|
||||||
"edit_reason" => current_reason
|
|
||||||
})
|
|
||||||
end)
|
|
||||||
|> Repo.transaction()
|
|> Repo.transaction()
|
||||||
|
|> case do
|
||||||
|
{:ok, %{comment: comment}} ->
|
||||||
|
if not comment.approved do
|
||||||
|
report_non_approved(comment)
|
||||||
|
end
|
||||||
|
|
||||||
|
reindex_comment(comment)
|
||||||
|
|
||||||
|
{:ok, comment}
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
{:error, comment_changeset}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_comment_versions(%Comment{} = comment, collection_renderer, pagination) do
|
||||||
|
versions =
|
||||||
|
Version
|
||||||
|
|> where(comment_id: ^comment.id)
|
||||||
|
|> order_by(desc: :created_at, desc: :id)
|
||||||
|
|> select([v], %{v | index: over(row_number(), order_by: [asc: :created_at, asc: :id])})
|
||||||
|
|> preload(:user)
|
||||||
|
|> Repo.paginate(pagination)
|
||||||
|
|
||||||
|
bodies = collection_renderer.(versions)
|
||||||
|
put_in(versions.entries, Enum.zip(versions, bodies))
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
|
25
lib/philomena/comments/version.ex
Normal file
25
lib/philomena/comments/version.ex
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
defmodule Philomena.Comments.Version do
|
||||||
|
use Ecto.Schema
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
alias Philomena.Comments.Comment
|
||||||
|
alias Philomena.Users.User
|
||||||
|
|
||||||
|
schema "comment_versions" do
|
||||||
|
belongs_to :comment, Comment
|
||||||
|
belongs_to :user, User
|
||||||
|
field :body, :string
|
||||||
|
field :edit_reason, :string
|
||||||
|
field :index, :integer, virtual: true
|
||||||
|
timestamps(inserted_at: :created_at, updated_at: false, type: :utc_datetime)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def changeset(comment_version, comment, user, attrs) do
|
||||||
|
comment_version
|
||||||
|
|> cast(attrs, [:body, :edit_reason, :created_at])
|
||||||
|
|> put_assoc(:comment, comment)
|
||||||
|
|> put_assoc(:user, user)
|
||||||
|
|> validate_required([:comment, :user, :body, :created_at])
|
||||||
|
end
|
||||||
|
end
|
|
@ -12,12 +12,12 @@ defmodule Philomena.Posts do
|
||||||
alias Philomena.Topics
|
alias Philomena.Topics
|
||||||
alias Philomena.UserStatistics
|
alias Philomena.UserStatistics
|
||||||
alias Philomena.Posts.Post
|
alias Philomena.Posts.Post
|
||||||
|
alias Philomena.Posts.Version
|
||||||
alias Philomena.Posts.SearchIndex, as: PostIndex
|
alias Philomena.Posts.SearchIndex, as: PostIndex
|
||||||
alias Philomena.IndexWorker
|
alias Philomena.IndexWorker
|
||||||
alias Philomena.Forums.Forum
|
alias Philomena.Forums.Forum
|
||||||
alias Philomena.Notifications
|
alias Philomena.Notifications
|
||||||
alias Philomena.NotificationWorker
|
alias Philomena.NotificationWorker
|
||||||
alias Philomena.Versions
|
|
||||||
alias Philomena.Reports
|
alias Philomena.Reports
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
@ -142,32 +142,46 @@ defmodule Philomena.Posts do
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def update_post(%Post{} = post, editor, attrs) do
|
def update_post(%Post{} = post, editor, attrs) do
|
||||||
now = DateTime.utc_now(:second)
|
version_changeset =
|
||||||
current_body = post.body
|
Version.changeset(%Version{}, post, editor, %{
|
||||||
current_reason = post.edit_reason
|
body: post.body,
|
||||||
|
edit_reason: post.edit_reason,
|
||||||
|
created_at: post.edited_at || post.created_at
|
||||||
|
})
|
||||||
|
|
||||||
post_changes = Post.changeset(post, attrs, now)
|
now = DateTime.utc_now(:second)
|
||||||
|
post_changeset = Post.changeset(post, attrs, now)
|
||||||
|
|
||||||
Multi.new()
|
Multi.new()
|
||||||
|> Multi.update(:post, post_changes)
|
|> Multi.insert(:version, version_changeset)
|
||||||
|> Multi.run(:version, fn _repo, _changes ->
|
|> Multi.update(:post, post_changeset)
|
||||||
Versions.create_version("Post", post.id, editor.id, %{
|
|
||||||
"body" => current_body,
|
|
||||||
"edit_reason" => current_reason
|
|
||||||
})
|
|
||||||
end)
|
|
||||||
|> Repo.transaction()
|
|> Repo.transaction()
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, %{post: post}} = result ->
|
{:ok, %{post: post}} ->
|
||||||
|
if not post.approved do
|
||||||
|
report_non_approved(post)
|
||||||
|
end
|
||||||
|
|
||||||
reindex_post(post)
|
reindex_post(post)
|
||||||
|
|
||||||
result
|
{:ok, post}
|
||||||
|
|
||||||
error ->
|
_ ->
|
||||||
error
|
{:error, post_changeset}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def list_post_versions(%Post{} = post, collection_renderer, pagination) do
|
||||||
|
versions =
|
||||||
|
Version
|
||||||
|
|> where(post_id: ^post.id)
|
||||||
|
|> order_by(desc: :created_at, desc: :id)
|
||||||
|
|> Repo.paginate(pagination)
|
||||||
|
|
||||||
|
bodies = collection_renderer.(versions)
|
||||||
|
put_in(versions.entries, Enum.zip(versions, bodies))
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Deletes a Post.
|
Deletes a Post.
|
||||||
|
|
||||||
|
|
24
lib/philomena/posts/version.ex
Normal file
24
lib/philomena/posts/version.ex
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
defmodule Philomena.Posts.Version do
|
||||||
|
use Ecto.Schema
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
alias Philomena.Posts.Post
|
||||||
|
alias Philomena.Users.User
|
||||||
|
|
||||||
|
schema "post_versions" do
|
||||||
|
belongs_to :post, Post
|
||||||
|
belongs_to :user, User
|
||||||
|
field :body, :string
|
||||||
|
field :edit_reason, :string
|
||||||
|
timestamps(inserted_at: :created_at, updated_at: false, type: :utc_datetime)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def changeset(post_version, post, user, attrs) do
|
||||||
|
post_version
|
||||||
|
|> cast(attrs, [:body, :edit_reason, :created_at])
|
||||||
|
|> put_assoc(:post, post)
|
||||||
|
|> put_assoc(:user, user)
|
||||||
|
|> validate_required([:post, :user, :body, :created_at])
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,75 +5,77 @@ defmodule Philomena.Versions do
|
||||||
|
|
||||||
import Ecto.Query, warn: false
|
import Ecto.Query, warn: false
|
||||||
alias Philomena.Repo
|
alias Philomena.Repo
|
||||||
|
alias Philomena.Versions.Difference
|
||||||
alias Philomena.Versions.Version
|
|
||||||
alias Philomena.Users.User
|
|
||||||
|
|
||||||
def load_data_and_associations(versions, parent) do
|
|
||||||
user_ids =
|
|
||||||
versions
|
|
||||||
|> Enum.map(& &1.whodunnit)
|
|
||||||
|> Enum.reject(&is_nil/1)
|
|
||||||
|
|
||||||
users =
|
|
||||||
User
|
|
||||||
|> where([u], u.id in ^user_ids)
|
|
||||||
|> preload(awards: :badge)
|
|
||||||
|> Repo.all()
|
|
||||||
|> Map.new(&{to_string(&1.id), &1})
|
|
||||||
|
|
||||||
{versions, _last_body} =
|
|
||||||
versions
|
|
||||||
|> Enum.map_reduce(
|
|
||||||
{parent.body, parent.edit_reason},
|
|
||||||
fn version, {previous_body, previous_reason} ->
|
|
||||||
json = Jason.decode!(version.object || "{}")
|
|
||||||
body = json["body"] || ""
|
|
||||||
edit_reason = json["edit_reason"]
|
|
||||||
|
|
||||||
v = %{
|
|
||||||
version
|
|
||||||
| parent: parent,
|
|
||||||
user: users[version.whodunnit],
|
|
||||||
body: body,
|
|
||||||
edit_reason: previous_reason,
|
|
||||||
difference: difference(body, previous_body)
|
|
||||||
}
|
|
||||||
|
|
||||||
{v, {body, edit_reason}}
|
|
||||||
end
|
|
||||||
)
|
|
||||||
|
|
||||||
versions
|
|
||||||
end
|
|
||||||
|
|
||||||
defp difference(previous, nil), do: [eq: previous]
|
|
||||||
defp difference(previous, next), do: String.myers_difference(previous, next)
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Creates a version.
|
Calculate a list of `m:Philomena.Versions.Difference` structs that represent
|
||||||
|
paginated differences between different versions of the object.
|
||||||
|
|
||||||
|
When expanded, the list of differences may look like:
|
||||||
|
|
||||||
|
[
|
||||||
|
%Difference{
|
||||||
|
previous_version: %CommentVersion{},
|
||||||
|
parent: %Comment{},
|
||||||
|
user: %User{},
|
||||||
|
difference: [del: "goodbye ", ins: "hello ", eq: "world"],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
iex> create_version(%{field: value})
|
iex> compute_text_differences(CommentVersion, %Comment{}, :body, page: 1, page_size: 25)
|
||||||
{:ok, %Version{}}
|
%Scrivener.Page{}
|
||||||
|
|
||||||
iex> create_version(%{field: bad_value})
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def create_version(item_type, item_id, whodunnit, attrs \\ %{}) do
|
def compute_text_differences(query, parent, name, pagination) do
|
||||||
%Version{
|
page = Repo.paginate(preload_and_order(query), pagination)
|
||||||
item_type: item_type,
|
initial = get_comparison_version(query, parent, page)
|
||||||
item_id: item_id,
|
|
||||||
event: "update",
|
{differences, _prev} =
|
||||||
whodunnit: whodunnit(whodunnit)
|
Enum.map_reduce(page, initial, fn older, newer ->
|
||||||
}
|
d = %Difference{
|
||||||
|> Version.changeset(attrs, item_id)
|
previous_version: newer,
|
||||||
|> Repo.insert()
|
created_at: older.created_at,
|
||||||
|
parent: parent,
|
||||||
|
user: older.user,
|
||||||
|
difference: difference(older, newer, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
{d, older}
|
||||||
|
end)
|
||||||
|
|
||||||
|
%{page | entries: differences}
|
||||||
end
|
end
|
||||||
|
|
||||||
# revolver ocelot
|
#
|
||||||
defp whodunnit(user_id) when is_integer(user_id), do: to_string(user_id)
|
# Get the first version to use when reducing the list of differences.
|
||||||
defp whodunnit(nil), do: nil
|
#
|
||||||
|
defp get_comparison_version(query, parent, page) do
|
||||||
|
curr = Enum.at(page, 0)
|
||||||
|
|
||||||
|
prev =
|
||||||
|
if curr do
|
||||||
|
query
|
||||||
|
|> where([v], v.created_at > ^curr.created_at and v.id > ^curr.id)
|
||||||
|
|> order_by(asc: :created_at, asc: :id)
|
||||||
|
|> limit(1)
|
||||||
|
|> Repo.one()
|
||||||
|
end
|
||||||
|
|
||||||
|
prev || parent
|
||||||
|
end
|
||||||
|
|
||||||
|
defp preload_and_order(query) do
|
||||||
|
query
|
||||||
|
|> preload(:user)
|
||||||
|
|> order_by(desc: :created_at, desc: :id)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp difference(curr, prev, name) do
|
||||||
|
curr_body = Map.fetch!(curr, name)
|
||||||
|
prev_body = Map.fetch!(prev, name)
|
||||||
|
|
||||||
|
String.myers_difference(curr_body, prev_body)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
defimpl Philomena.Attribution, for: Philomena.Versions.Version do
|
defimpl Philomena.Attribution, for: Philomena.Versions.Difference do
|
||||||
def object_identifier(version) do
|
def object_identifier(difference) do
|
||||||
Philomena.Attribution.object_identifier(version.parent)
|
Philomena.Attribution.object_identifier(difference.parent)
|
||||||
end
|
end
|
||||||
|
|
||||||
def best_user_identifier(version) do
|
def best_user_identifier(difference) do
|
||||||
Philomena.Attribution.best_user_identifier(version.parent)
|
Philomena.Attribution.best_user_identifier(difference.parent)
|
||||||
end
|
end
|
||||||
|
|
||||||
def anonymous?(version) do
|
def anonymous?(difference) do
|
||||||
same_user?(version.user, version.parent) and !!version.parent.anonymous
|
same_user?(difference.user, difference.parent) and !!difference.parent.anonymous
|
||||||
end
|
end
|
||||||
|
|
||||||
defp same_user?(%{id: id}, %{user_id: id}), do: true
|
defp same_user?(%{id: id}, %{user_id: id}), do: true
|
||||||
|
|
8
lib/philomena/versions/difference.ex
Normal file
8
lib/philomena/versions/difference.ex
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
defmodule Philomena.Versions.Difference do
|
||||||
|
defstruct previous_version: nil,
|
||||||
|
created_at: nil,
|
||||||
|
parent: nil,
|
||||||
|
user: nil,
|
||||||
|
edit_reason: nil,
|
||||||
|
difference: []
|
||||||
|
end
|
|
@ -1,43 +0,0 @@
|
||||||
defmodule Philomena.Versions.Version do
|
|
||||||
use Ecto.Schema
|
|
||||||
import Ecto.Changeset
|
|
||||||
|
|
||||||
schema "versions" do
|
|
||||||
field :event, :string
|
|
||||||
field :whodunnit, :string
|
|
||||||
field :object, :string
|
|
||||||
|
|
||||||
# fixme: rails polymorphic relation
|
|
||||||
field :item_id, :integer
|
|
||||||
field :item_type, :string
|
|
||||||
|
|
||||||
field :user, :any, virtual: true
|
|
||||||
field :parent, :any, virtual: true
|
|
||||||
field :body, :string, virtual: true
|
|
||||||
field :edit_reason, :string, virtual: true
|
|
||||||
field :difference, :any, virtual: true
|
|
||||||
|
|
||||||
timestamps(inserted_at: :created_at, updated_at: false, type: :utc_datetime)
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc false
|
|
||||||
def changeset(version, attrs, item_id) do
|
|
||||||
version
|
|
||||||
|> cast(attrs, [:body, :edit_reason])
|
|
||||||
|> put_object(item_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp put_object(changeset, item_id) do
|
|
||||||
body = get_field(changeset, :body)
|
|
||||||
edit_reason = get_field(changeset, :edit_reason)
|
|
||||||
|
|
||||||
object =
|
|
||||||
Jason.encode!(%{
|
|
||||||
id: item_id,
|
|
||||||
body: body,
|
|
||||||
edit_reason: edit_reason
|
|
||||||
})
|
|
||||||
|
|
||||||
change(changeset, object: object)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,11 +1,9 @@
|
||||||
defmodule PhilomenaWeb.Image.Comment.HistoryController do
|
defmodule PhilomenaWeb.Image.Comment.HistoryController do
|
||||||
use PhilomenaWeb, :controller
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
alias Philomena.Versions.Version
|
alias PhilomenaWeb.MarkdownRenderer
|
||||||
alias Philomena.Versions
|
|
||||||
alias Philomena.Images.Image
|
alias Philomena.Images.Image
|
||||||
alias Philomena.Repo
|
alias Philomena.Comments
|
||||||
import Ecto.Query
|
|
||||||
|
|
||||||
plug PhilomenaWeb.CanaryMapPlug, index: :show
|
plug PhilomenaWeb.CanaryMapPlug, index: :show
|
||||||
plug :load_and_authorize_resource, model: Image, id_name: "image_id", persisted: true
|
plug :load_and_authorize_resource, model: Image, id_name: "image_id", persisted: true
|
||||||
|
@ -15,18 +13,13 @@ defmodule PhilomenaWeb.Image.Comment.HistoryController do
|
||||||
def index(conn, _params) do
|
def index(conn, _params) do
|
||||||
image = conn.assigns.image
|
image = conn.assigns.image
|
||||||
comment = conn.assigns.comment
|
comment = conn.assigns.comment
|
||||||
|
renderer = &MarkdownRenderer.render_collection(&1, conn)
|
||||||
versions =
|
versions = Comments.list_comment_versions(comment, renderer, conn.assigns.scrivener)
|
||||||
Version
|
|
||||||
|> where(item_type: "Comment", item_id: ^comment.id)
|
|
||||||
|> order_by(desc: :created_at)
|
|
||||||
|> limit(25)
|
|
||||||
|> Repo.all()
|
|
||||||
|> Versions.load_data_and_associations(comment)
|
|
||||||
|
|
||||||
render(conn, "index.html",
|
render(conn, "index.html",
|
||||||
title: "Comment History for comment #{comment.id} on image #{image.id}",
|
title: "Comment History for comment #{comment.id} on image #{image.id}",
|
||||||
versions: versions
|
versions: versions,
|
||||||
|
body: renderer.([comment])
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -111,24 +111,18 @@ defmodule PhilomenaWeb.Image.CommentController do
|
||||||
|
|
||||||
def update(conn, %{"comment" => comment_params}) do
|
def update(conn, %{"comment" => comment_params}) do
|
||||||
case Comments.update_comment(conn.assigns.comment, conn.assigns.current_user, comment_params) do
|
case Comments.update_comment(conn.assigns.comment, conn.assigns.current_user, comment_params) do
|
||||||
{:ok, %{comment: comment}} ->
|
{:ok, comment} ->
|
||||||
if not comment.approved do
|
|
||||||
Comments.report_non_approved(comment)
|
|
||||||
end
|
|
||||||
|
|
||||||
PhilomenaWeb.Endpoint.broadcast!(
|
PhilomenaWeb.Endpoint.broadcast!(
|
||||||
"firehose",
|
"firehose",
|
||||||
"comment:update",
|
"comment:update",
|
||||||
PhilomenaWeb.Api.Json.CommentView.render("show.json", %{comment: comment})
|
PhilomenaWeb.Api.Json.CommentView.render("show.json", %{comment: comment})
|
||||||
)
|
)
|
||||||
|
|
||||||
Comments.reindex_comment(comment)
|
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Comment updated successfully.")
|
|> put_flash(:info, "Comment updated successfully.")
|
||||||
|> redirect(to: ~p"/images/#{conn.assigns.image}" <> "#comment_#{comment.id}")
|
|> redirect(to: ~p"/images/#{conn.assigns.image}" <> "#comment_#{comment.id}")
|
||||||
|
|
||||||
{:error, :comment, changeset, _changes} ->
|
{:error, changeset} ->
|
||||||
render(conn, "edit.html", comment: conn.assigns.comment, changeset: changeset)
|
render(conn, "edit.html", comment: conn.assigns.comment, changeset: changeset)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
defmodule PhilomenaWeb.Topic.Post.HistoryController do
|
defmodule PhilomenaWeb.Topic.Post.HistoryController do
|
||||||
use PhilomenaWeb, :controller
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
alias Philomena.Versions.Version
|
alias PhilomenaWeb.MarkdownRenderer
|
||||||
alias Philomena.Versions
|
|
||||||
alias Philomena.Forums.Forum
|
alias Philomena.Forums.Forum
|
||||||
alias Philomena.Repo
|
alias Philomena.Posts
|
||||||
import Ecto.Query
|
|
||||||
|
|
||||||
plug PhilomenaWeb.CanaryMapPlug, index: :show
|
plug PhilomenaWeb.CanaryMapPlug, index: :show
|
||||||
|
|
||||||
|
@ -21,14 +19,8 @@ defmodule PhilomenaWeb.Topic.Post.HistoryController do
|
||||||
def index(conn, _params) do
|
def index(conn, _params) do
|
||||||
topic = conn.assigns.topic
|
topic = conn.assigns.topic
|
||||||
post = conn.assigns.post
|
post = conn.assigns.post
|
||||||
|
renderer = &MarkdownRenderer.render_collection(&1, conn)
|
||||||
versions =
|
versions = Posts.list_post_versions(post, renderer, conn.assigns.scrivener)
|
||||||
Version
|
|
||||||
|> where(item_type: "Post", item_id: ^post.id)
|
|
||||||
|> order_by(desc: :created_at)
|
|
||||||
|> limit(25)
|
|
||||||
|> Repo.all()
|
|
||||||
|> Versions.load_data_and_associations(post)
|
|
||||||
|
|
||||||
render(conn, "index.html",
|
render(conn, "index.html",
|
||||||
title: "Post History for Post #{post.id} - #{topic.title} - Forums",
|
title: "Post History for Post #{post.id} - #{topic.title} - Forums",
|
||||||
|
|
|
@ -79,11 +79,7 @@ defmodule PhilomenaWeb.Topic.PostController do
|
||||||
user = conn.assigns.current_user
|
user = conn.assigns.current_user
|
||||||
|
|
||||||
case Posts.update_post(post, user, post_params) do
|
case Posts.update_post(post, user, post_params) do
|
||||||
{:ok, %{post: post}} ->
|
{:ok, post} ->
|
||||||
if not post.approved do
|
|
||||||
Posts.report_non_approved(post)
|
|
||||||
end
|
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Post successfully edited.")
|
|> put_flash(:info, "Post successfully edited.")
|
||||||
|> redirect(
|
|> redirect(
|
||||||
|
@ -92,7 +88,7 @@ defmodule PhilomenaWeb.Topic.PostController do
|
||||||
"#post_#{post.id}"
|
"#post_#{post.id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
{:error, :post, changeset, _changes} ->
|
{:error, changeset} ->
|
||||||
render(conn, "edit.html", post: conn.assigns.post, changeset: changeset)
|
render(conn, "edit.html", post: conn.assigns.post, changeset: changeset)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,46 +1,49 @@
|
||||||
h1
|
h1
|
||||||
' Viewing last 25 versions of comment by
|
' Viewing history for comment by
|
||||||
= render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @comment, conn: @conn
|
= render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @comment, conn: @conn
|
||||||
' on image
|
' on image
|
||||||
a href=~p"/images/#{@comment.image}"
|
a href=~p"/images/#{@comment.image}"
|
||||||
| #
|
| #
|
||||||
= @comment.image_id
|
= @comment.image_id
|
||||||
|
|
||||||
= for version <- @versions do
|
h2 Current version
|
||||||
|
= render PhilomenaWeb.CommentView, "_comment.html", comment: @comment, body: @body, conn: @conn
|
||||||
|
|
||||||
|
h2 Previous versions
|
||||||
|
= for {version, body} <- @versions do
|
||||||
|
- comment = merge_version(@comment, version)
|
||||||
|
|
||||||
article.block.communication
|
article.block.communication
|
||||||
.block__content.flex.flex--no-wrap
|
.block__content.flex.flex--no-wrap
|
||||||
.flex__fixed.spacing-right
|
.flex__fixed.spacing-right
|
||||||
= render PhilomenaWeb.UserAttributionView, "_anon_user_avatar.html", object: @comment, conn: @conn
|
= render PhilomenaWeb.UserAttributionView, "_anon_user_avatar.html", object: comment, conn: @conn
|
||||||
|
|
||||||
.flex__grow.communication__body
|
.flex__grow.communication__body
|
||||||
span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @comment, awards: true, conn: @conn
|
span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: comment, awards: true, conn: @conn
|
||||||
br
|
br
|
||||||
|
|
||||||
= render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @comment, conn: @conn
|
= render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: comment, conn: @conn
|
||||||
|
|
||||||
.communication__body__text
|
.communication__body__text
|
||||||
= for edit <- version.difference do
|
= body
|
||||||
= case edit do
|
|
||||||
- {:eq, value} ->
|
|
||||||
= escape_nl2br(value)
|
|
||||||
|
|
||||||
- {:ins, value} ->
|
|
||||||
ins.differ = escape_nl2br(value)
|
|
||||||
|
|
||||||
- {:del, value} ->
|
|
||||||
del.differ = escape_nl2br(value)
|
|
||||||
|
|
||||||
.block__content.communication__options
|
.block__content.communication__options
|
||||||
.flex.flex--wrap.flex--spaced-out
|
.flex.flex--wrap.flex--spaced-out
|
||||||
div
|
div
|
||||||
= if version.edit_reason not in [nil, ""] do
|
= cond do
|
||||||
' Reason:
|
- version.index > 1 and comment.edit_reason not in [nil, ""] ->
|
||||||
= version.edit_reason
|
' Reason:
|
||||||
- else
|
= comment.edit_reason
|
||||||
' No reason given
|
- version.index > 1 ->
|
||||||
|
' No reason given
|
||||||
|
- true ->
|
||||||
|
' Original
|
||||||
|
|
||||||
.flex__right
|
.flex__right
|
||||||
' Edited
|
= if version.index == 1 do
|
||||||
|
' Created
|
||||||
|
- else
|
||||||
|
' Edited
|
||||||
=> pretty_time(version.created_at)
|
=> pretty_time(version.created_at)
|
||||||
' by
|
' by
|
||||||
=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: version, conn: @conn
|
=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: comment, conn: @conn
|
||||||
|
|
|
@ -5,7 +5,7 @@ h1
|
||||||
a href=(~p"/forums/#{@post.topic.forum}/topics/#{@post.topic}?#{[post_id: @post.id]}" <> "#post_#{@post.id}")
|
a href=(~p"/forums/#{@post.topic.forum}/topics/#{@post.topic}?#{[post_id: @post.id]}" <> "#post_#{@post.id}")
|
||||||
= @post.topic.title
|
= @post.topic.title
|
||||||
|
|
||||||
= for version <- @versions do
|
/= for version <- @versions do
|
||||||
article.block.communication
|
article.block.communication
|
||||||
.block__content.flex.flex--no-wrap
|
.block__content.flex.flex--no-wrap
|
||||||
.flex__fixed.spacing-right
|
.flex__fixed.spacing-right
|
||||||
|
@ -31,10 +31,11 @@ h1
|
||||||
|
|
||||||
.block__content.communication__options
|
.block__content.communication__options
|
||||||
.flex.flex--wrap.flex--spaced-out
|
.flex.flex--wrap.flex--spaced-out
|
||||||
|
- edit_reason = version.previous_version.edit_reason
|
||||||
div
|
div
|
||||||
= if version.edit_reason not in [nil, ""] do
|
= if edit_reason not in [nil, ""] do
|
||||||
' Reason:
|
' Reason:
|
||||||
= version.edit_reason
|
= edit_reason
|
||||||
- else
|
- else
|
||||||
' No reason given
|
' No reason given
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
defmodule PhilomenaWeb.Image.Comment.HistoryView do
|
defmodule PhilomenaWeb.Image.Comment.HistoryView do
|
||||||
use PhilomenaWeb, :view
|
use PhilomenaWeb, :view
|
||||||
|
|
||||||
|
def merge_version(comment, version) do
|
||||||
|
comment
|
||||||
|
|> Map.put(:body, version.body)
|
||||||
|
|> Map.put(:edited_at, version.created_at)
|
||||||
|
|> Map.put(:edit_reason, version.edit_reason)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
72
priv/repo/migrations/20240731132924_new_versions.exs
Normal file
72
priv/repo/migrations/20240731132924_new_versions.exs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
defmodule Philomena.Repo.Migrations.NewVersions do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
create table(:comment_versions) do
|
||||||
|
add :comment_id, references(:comments, on_delete: :delete_all), null: false
|
||||||
|
add :user_id, references(:users, on_delete: :delete_all), null: false
|
||||||
|
timestamps inserted_at: :created_at, updated_at: false
|
||||||
|
|
||||||
|
add :body, :string, null: false
|
||||||
|
add :edit_reason, :string
|
||||||
|
end
|
||||||
|
|
||||||
|
create table(:post_versions) do
|
||||||
|
add :post_id, references(:posts, on_delete: :delete_all), null: false
|
||||||
|
add :user_id, references(:users, on_delete: :delete_all), null: false
|
||||||
|
timestamps inserted_at: :created_at, updated_at: false
|
||||||
|
|
||||||
|
add :body, :string, null: false
|
||||||
|
add :edit_reason, :string
|
||||||
|
end
|
||||||
|
|
||||||
|
create index(:comment_versions, [:comment_id, "created_at desc"])
|
||||||
|
create index(:comment_versions, [:user_id])
|
||||||
|
create index(:post_versions, [:post_id, "created_at desc"])
|
||||||
|
create index(:post_versions, [:user_id])
|
||||||
|
|
||||||
|
insert_statements =
|
||||||
|
"""
|
||||||
|
insert into comment_versions (comment_id, user_id, created_at, body, edit_reason)
|
||||||
|
select
|
||||||
|
v.item_id as comment_id,
|
||||||
|
v.whodunnit::bigint as user_id,
|
||||||
|
v.created_at,
|
||||||
|
v.object::json->>'body' as body,
|
||||||
|
v.object::json->>'edit_reason' as edit_reason
|
||||||
|
from versions v
|
||||||
|
where v.item_type = 'Comment'
|
||||||
|
and exists(select 1 from comments c where c.id = v.item_id)
|
||||||
|
and v.whodunnit is not null
|
||||||
|
and v.event = 'update'
|
||||||
|
order by created_at asc;
|
||||||
|
|
||||||
|
insert into post_versions (post_id, user_id, created_at, body, edit_reason)
|
||||||
|
select
|
||||||
|
v.item_id as post_id,
|
||||||
|
v.whodunnit::bigint as user_id,
|
||||||
|
v.created_at,
|
||||||
|
v.object::json->>'body' as body,
|
||||||
|
v.object::json->>'edit_reason' as edit_reason
|
||||||
|
from versions v
|
||||||
|
where v.item_type = 'Post'
|
||||||
|
and exists(select 1 from posts p where p.id = v.item_id)
|
||||||
|
and v.whodunnit is not null
|
||||||
|
and v.event = 'update'
|
||||||
|
order by created_at asc;
|
||||||
|
"""
|
||||||
|
|
||||||
|
# These statements should not be run by the migration in production.
|
||||||
|
# Run them manually in psql instead.
|
||||||
|
if System.get_env("MIX_ENV") != "prod" do
|
||||||
|
for stmt <- String.split(insert_statements, "\n\n") do
|
||||||
|
execute(stmt)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
drop table(:comment_versions)
|
||||||
|
drop table(:post_versions)
|
||||||
|
end
|
||||||
|
end
|
|
@ -272,6 +272,39 @@ CREATE SEQUENCE public.channels_id_seq
|
||||||
ALTER SEQUENCE public.channels_id_seq OWNED BY public.channels.id;
|
ALTER SEQUENCE public.channels_id_seq OWNED BY public.channels.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: comment_versions; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.comment_versions (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
comment_id bigint NOT NULL,
|
||||||
|
user_id bigint NOT NULL,
|
||||||
|
created_at timestamp(0) without time zone NOT NULL,
|
||||||
|
body character varying(255) NOT NULL,
|
||||||
|
edit_reason character varying(255)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: comment_versions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.comment_versions_id_seq
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: comment_versions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.comment_versions_id_seq OWNED BY public.comment_versions.id;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: comments; Type: TABLE; Schema: public; Owner: -
|
-- Name: comments; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -1337,6 +1370,39 @@ CREATE SEQUENCE public.polls_id_seq
|
||||||
ALTER SEQUENCE public.polls_id_seq OWNED BY public.polls.id;
|
ALTER SEQUENCE public.polls_id_seq OWNED BY public.polls.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: post_versions; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.post_versions (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
post_id bigint NOT NULL,
|
||||||
|
user_id bigint NOT NULL,
|
||||||
|
created_at timestamp(0) without time zone NOT NULL,
|
||||||
|
body character varying(255) NOT NULL,
|
||||||
|
edit_reason character varying(255)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: post_versions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.post_versions_id_seq
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: post_versions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.post_versions_id_seq OWNED BY public.post_versions.id;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: posts; Type: TABLE; Schema: public; Owner: -
|
-- Name: posts; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -2267,6 +2333,13 @@ ALTER TABLE ONLY public.badges ALTER COLUMN id SET DEFAULT nextval('public.badge
|
||||||
ALTER TABLE ONLY public.channels ALTER COLUMN id SET DEFAULT nextval('public.channels_id_seq'::regclass);
|
ALTER TABLE ONLY public.channels ALTER COLUMN id SET DEFAULT nextval('public.channels_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: comment_versions id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.comment_versions ALTER COLUMN id SET DEFAULT nextval('public.comment_versions_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: comments id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: comments id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -2428,6 +2501,13 @@ ALTER TABLE ONLY public.poll_votes ALTER COLUMN id SET DEFAULT nextval('public.p
|
||||||
ALTER TABLE ONLY public.polls ALTER COLUMN id SET DEFAULT nextval('public.polls_id_seq'::regclass);
|
ALTER TABLE ONLY public.polls ALTER COLUMN id SET DEFAULT nextval('public.polls_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: post_versions id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.post_versions ALTER COLUMN id SET DEFAULT nextval('public.post_versions_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: posts id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: posts id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -2615,6 +2695,14 @@ ALTER TABLE ONLY public.channels
|
||||||
ADD CONSTRAINT channels_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT channels_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: comment_versions comment_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.comment_versions
|
||||||
|
ADD CONSTRAINT comment_versions_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: comments comments_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: comments comments_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -2799,6 +2887,14 @@ ALTER TABLE ONLY public.polls
|
||||||
ADD CONSTRAINT polls_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT polls_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: post_versions post_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.post_versions
|
||||||
|
ADD CONSTRAINT post_versions_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: posts posts_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: posts posts_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -3003,6 +3099,20 @@ CREATE INDEX channel_live_notifications_user_id_read_index ON public.channel_liv
|
||||||
CREATE INDEX channel_live_notifications_user_id_updated_at_desc_index ON public.channel_live_notifications USING btree (user_id, updated_at DESC);
|
CREATE INDEX channel_live_notifications_user_id_updated_at_desc_index ON public.channel_live_notifications USING btree (user_id, updated_at DESC);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: comment_versions_comment_id_created_at_desc_index; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX comment_versions_comment_id_created_at_desc_index ON public.comment_versions USING btree (comment_id, created_at DESC);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: comment_versions_user_id_index; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX comment_versions_user_id_index ON public.comment_versions USING btree (user_id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: forum_post_notifications_post_id_index; Type: INDEX; Schema: public; Owner: -
|
-- Name: forum_post_notifications_post_id_index; Type: INDEX; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -4424,6 +4534,20 @@ CREATE INDEX moderation_logs_user_id_created_at_index ON public.moderation_logs
|
||||||
CREATE INDEX moderation_logs_user_id_index ON public.moderation_logs USING btree (user_id);
|
CREATE INDEX moderation_logs_user_id_index ON public.moderation_logs USING btree (user_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: post_versions_post_id_created_at_desc_index; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX post_versions_post_id_created_at_desc_index ON public.post_versions USING btree (post_id, created_at DESC);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: post_versions_user_id_index; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX post_versions_user_id_index ON public.post_versions USING btree (user_id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: reports_system_index; Type: INDEX; Schema: public; Owner: -
|
-- Name: reports_system_index; Type: INDEX; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -4461,6 +4585,22 @@ ALTER TABLE ONLY public.channel_live_notifications
|
||||||
ADD CONSTRAINT channel_live_notifications_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
ADD CONSTRAINT channel_live_notifications_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: comment_versions comment_versions_comment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.comment_versions
|
||||||
|
ADD CONSTRAINT comment_versions_comment_id_fkey FOREIGN KEY (comment_id) REFERENCES public.comments(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: comment_versions comment_versions_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.comment_versions
|
||||||
|
ADD CONSTRAINT comment_versions_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: channels fk_rails_021c624081; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: channels fk_rails_021c624081; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -5389,6 +5529,22 @@ ALTER TABLE ONLY public.moderation_logs
|
||||||
ADD CONSTRAINT moderation_logs_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
ADD CONSTRAINT moderation_logs_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: post_versions post_versions_post_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.post_versions
|
||||||
|
ADD CONSTRAINT post_versions_post_id_fkey FOREIGN KEY (post_id) REFERENCES public.posts(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: post_versions post_versions_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.post_versions
|
||||||
|
ADD CONSTRAINT post_versions_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: source_changes source_changes_image_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: source_changes source_changes_image_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -5447,3 +5603,4 @@ INSERT INTO public."schema_migrations" (version) VALUES (20211219194836);
|
||||||
INSERT INTO public."schema_migrations" (version) VALUES (20220321173359);
|
INSERT INTO public."schema_migrations" (version) VALUES (20220321173359);
|
||||||
INSERT INTO public."schema_migrations" (version) VALUES (20240723122759);
|
INSERT INTO public."schema_migrations" (version) VALUES (20240723122759);
|
||||||
INSERT INTO public."schema_migrations" (version) VALUES (20240728191353);
|
INSERT INTO public."schema_migrations" (version) VALUES (20240728191353);
|
||||||
|
INSERT INTO public."schema_migrations" (version) VALUES (20240731132924);
|
||||||
|
|
Loading…
Reference in a new issue