mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-27 13:47:58 +01:00
duplicate reports
This commit is contained in:
parent
b972c85675
commit
bec983fdf1
8 changed files with 538 additions and 0 deletions
57
lib/philomena_web/controllers/duplicate_report_controller.ex
Normal file
57
lib/philomena_web/controllers/duplicate_report_controller.ex
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
defmodule PhilomenaWeb.DuplicateReportController do
|
||||||
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
|
alias Philomena.DuplicateReports
|
||||||
|
alias Philomena.DuplicateReports.DuplicateReport
|
||||||
|
alias Philomena.Images.Image
|
||||||
|
alias Philomena.Repo
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
|
@valid_states ~W(open rejected accepted claimed)
|
||||||
|
|
||||||
|
plug PhilomenaWeb.FilterBannedUsersPlug when action in [:create]
|
||||||
|
plug :load_resource, model: DuplicateReport, only: [:show], preload: [:user, image: :tags, duplicate_of_image: :tags]
|
||||||
|
|
||||||
|
def index(conn, params) do
|
||||||
|
states =
|
||||||
|
params["states"]
|
||||||
|
|> wrap()
|
||||||
|
|> Enum.filter(&Enum.member?(@valid_states, &1))
|
||||||
|
|
||||||
|
duplicate_reports =
|
||||||
|
DuplicateReport
|
||||||
|
|> where([d], d.state in ^states)
|
||||||
|
|> preload([:user, image: :tags, duplicate_of_image: :tags])
|
||||||
|
|> order_by(desc: :created_at)
|
||||||
|
|> Repo.paginate(conn.assigns.pagination)
|
||||||
|
|
||||||
|
render(conn, "index.html", duplicate_reports: duplicate_reports, layout_class: "layout--wide")
|
||||||
|
end
|
||||||
|
|
||||||
|
def create(conn, %{"duplicate_report" => duplicate_report_params}) do
|
||||||
|
attribution = conn.assigns.attribution
|
||||||
|
source = Repo.get!(Image, duplicate_report_params["image_id"])
|
||||||
|
target = Repo.get!(Image, duplicate_report_params["duplicate_of_image_id"])
|
||||||
|
|
||||||
|
case DuplicateReports.create_duplicate_report(source, target, attribution, duplicate_report_params) do
|
||||||
|
{:ok, duplicate_report} ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, "Duplicate report created successfully.")
|
||||||
|
|> redirect(to: Routes.image_path(conn, :show, duplicate_report.image_id))
|
||||||
|
|
||||||
|
{:error, _changeset} ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:error, "Failed to submit duplicate report")
|
||||||
|
|> redirect(external: conn.assigns.referrer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def show(conn, _params) do
|
||||||
|
dr = conn.assigns.duplicate_report
|
||||||
|
|
||||||
|
render(conn, "show.html", duplicate_report: dr, layout_class: "layout--wide")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp wrap(list) when is_list(list), do: list
|
||||||
|
defp wrap(not_a_list), do: [not_a_list]
|
||||||
|
end
|
|
@ -155,6 +155,7 @@ defmodule PhilomenaWeb.Router do
|
||||||
resources "/stats", StatController, only: [:index]
|
resources "/stats", StatController, only: [:index]
|
||||||
resources "/channels", ChannelController, only: [:index, :show]
|
resources "/channels", ChannelController, only: [:index, :show]
|
||||||
resources "/settings", SettingController, only: [:edit, :update], singleton: true
|
resources "/settings", SettingController, only: [:edit, :update], singleton: true
|
||||||
|
resources "/duplicate_reports", DuplicateReportController, only: [:index, :show]
|
||||||
|
|
||||||
get "/:id", ImageController, :show
|
get "/:id", ImageController, :show
|
||||||
# get "/:forum_id", ForumController, :show # impossible to do without constraints
|
# get "/:forum_id", ForumController, :show # impossible to do without constraints
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
.grid--dupe-report-list__cell.flex.flex--column.flex--spaced-out.flex--centered.flex--no-wrap.center.dr__image-cell.border-vertical
|
||||||
|
p
|
||||||
|
- if is_nil(@image) do
|
||||||
|
| (Image now hard-deleted)
|
||||||
|
- else
|
||||||
|
| #
|
||||||
|
= @image.id
|
||||||
|
|
||||||
|
= render PhilomenaWeb.ImageView, "_image_container.html", image: @image, size: @thumb_small, conn: @conn
|
||||||
|
|
||||||
|
p
|
||||||
|
= @image.image_width
|
||||||
|
| x
|
||||||
|
= @image.image_height
|
||||||
|
|
||||||
|
p
|
||||||
|
= render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @image, conn: @conn
|
||||||
|
|
||||||
|
/- if report.valid? && can_manage_dr
|
||||||
|
- if source
|
||||||
|
a href=duplicate_report_accept_reverse_path(report) data-method="post"
|
||||||
|
button.button
|
||||||
|
' Keep Source
|
||||||
|
i.fa.fa-arrow-left
|
||||||
|
- else
|
||||||
|
a href=duplicate_report_accept_path(report) data-method="post"
|
||||||
|
button.button
|
||||||
|
i.fa.fa-arrow-right>
|
||||||
|
| Keep Target
|
155
lib/philomena_web/templates/duplicate_report/_list.html.slime
Normal file
155
lib/philomena_web/templates/duplicate_report/_list.html.slime
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
.grid.grid--dupe-report-list
|
||||||
|
p Source image
|
||||||
|
p Target image
|
||||||
|
p Diff
|
||||||
|
p Status/options
|
||||||
|
|
||||||
|
= for report <- @duplicate_reports do
|
||||||
|
- background_class = background_class(report)
|
||||||
|
|
||||||
|
= render PhilomenaWeb.DuplicateReportView, "_image_cell.html", image: report.image, source: true, report: report, conn: @conn
|
||||||
|
= render PhilomenaWeb.DuplicateReportView, "_image_cell.html", image: report.duplicate_of_image, source: false, report: report, conn: @conn
|
||||||
|
|
||||||
|
.grid--dupe-report-list__cell.dr__diff.border-vertical
|
||||||
|
table.table
|
||||||
|
tr
|
||||||
|
= if same_aspect_ratio?(report) do
|
||||||
|
td.success
|
||||||
|
a href=Routes.duplicate_report_path(@conn, :show, report)
|
||||||
|
' Visual diff
|
||||||
|
| (Same aspect ratio)
|
||||||
|
|
||||||
|
- else
|
||||||
|
td.warning Different aspect ratio
|
||||||
|
tr
|
||||||
|
= cond do
|
||||||
|
- both_are_edits?(report) ->
|
||||||
|
td.warning Both are edits
|
||||||
|
|
||||||
|
- target_is_edit?(report) ->
|
||||||
|
td.danger Target is an edit
|
||||||
|
|
||||||
|
- source_is_edit?(report) ->
|
||||||
|
td.danger Source is an edit
|
||||||
|
|
||||||
|
- true ->
|
||||||
|
td.success Neither is an edit
|
||||||
|
|
||||||
|
tr
|
||||||
|
= cond do
|
||||||
|
- both_are_alternate_versions?(report) ->
|
||||||
|
td.warning Both are alternate versions
|
||||||
|
|
||||||
|
- target_is_alternate_version?(report) ->
|
||||||
|
td.danger Target is an alternate version
|
||||||
|
|
||||||
|
- source_is_alternate_version?(report) ->
|
||||||
|
td.danger Source is an alternate version
|
||||||
|
|
||||||
|
- true ->
|
||||||
|
td.success Neither is an alternate version
|
||||||
|
|
||||||
|
tr
|
||||||
|
= cond do
|
||||||
|
- same_res?(report) ->
|
||||||
|
td.sucecss Same resolution
|
||||||
|
|
||||||
|
- higher_res?(report) ->
|
||||||
|
td.warning Target resolution better
|
||||||
|
|
||||||
|
- true ->
|
||||||
|
td.warning Source resolution better
|
||||||
|
|
||||||
|
tr
|
||||||
|
= cond do
|
||||||
|
- same_format?(report) ->
|
||||||
|
td.success
|
||||||
|
' Same format
|
||||||
|
= file_types(report)
|
||||||
|
|
||||||
|
- better_format?(report) ->
|
||||||
|
td.warning
|
||||||
|
' Target format better
|
||||||
|
= file_types(report)
|
||||||
|
|
||||||
|
- true ->
|
||||||
|
td.warning
|
||||||
|
' Source format better
|
||||||
|
= file_types(report)
|
||||||
|
|
||||||
|
tr
|
||||||
|
= cond do
|
||||||
|
- same_artist_tags?(report) ->
|
||||||
|
td.success Same artist tags
|
||||||
|
|
||||||
|
- more_artist_tags_on_target?(report) ->
|
||||||
|
td.warning More artist tags on target
|
||||||
|
|
||||||
|
- more_artist_tags_on_source?(report) ->
|
||||||
|
td.warning More artist tags on source
|
||||||
|
|
||||||
|
- true ->
|
||||||
|
td.danger Different artist tags
|
||||||
|
|
||||||
|
tr
|
||||||
|
= cond do
|
||||||
|
- neither_have_source?(report) ->
|
||||||
|
td.warning Neither have sources
|
||||||
|
|
||||||
|
- same_source?(report) ->
|
||||||
|
td.success Same sources
|
||||||
|
|
||||||
|
- similar_source?(report) ->
|
||||||
|
td.warning Same hostname
|
||||||
|
|
||||||
|
- source_on_target?(report) ->
|
||||||
|
td.warning Target has a source
|
||||||
|
|
||||||
|
- source_on_source?(report) ->
|
||||||
|
td.warning Source has a source
|
||||||
|
|
||||||
|
- true ->
|
||||||
|
td.danger Different sources
|
||||||
|
|
||||||
|
tr
|
||||||
|
= if same_rating_tags?(report) do
|
||||||
|
td.success Same rating tags
|
||||||
|
- else
|
||||||
|
td.danger Different rating tags
|
||||||
|
|
||||||
|
tr
|
||||||
|
= if forward_merge?(report) do
|
||||||
|
td.warning Target newer
|
||||||
|
- else
|
||||||
|
td.success Target older
|
||||||
|
|
||||||
|
.flex.flex--column.grid--dupe-report-list__cell.border-vertical id="report_options_#{report.id}"
|
||||||
|
.dr__status-options class=background_class
|
||||||
|
= String.capitalize(report.state)
|
||||||
|
|
||||||
|
/- if can_manage_dr && report.modifier.present?
|
||||||
|
' by
|
||||||
|
= report.modifier.name
|
||||||
|
/- if can_manage_dr
|
||||||
|
div
|
||||||
|
- if report.state == 'open'
|
||||||
|
a href=duplicate_report_claim_path(report, target: "report_options_#{report.id}") data-method="post"
|
||||||
|
button.button.button--separate-right
|
||||||
|
i.fa.fa-clipboard>
|
||||||
|
| Claim
|
||||||
|
- if report.state != 'rejected'
|
||||||
|
a href=duplicate_report_reject_path(report) data-method="post"
|
||||||
|
button.button
|
||||||
|
i.fa.fa-times>
|
||||||
|
| Reject
|
||||||
|
|
||||||
|
.dr__status-options
|
||||||
|
div
|
||||||
|
' Reported
|
||||||
|
=> pretty_time(report.created_at)
|
||||||
|
|
||||||
|
= if report.user do
|
||||||
|
' by
|
||||||
|
=< link report.user.name, to: Routes.profile_path(@conn, :show, report.user)
|
||||||
|
|
||||||
|
= report.reason
|
|
@ -0,0 +1,24 @@
|
||||||
|
h1 Duplicate Reports
|
||||||
|
|
||||||
|
- route = fn p -> Routes.duplicate_report_path(@conn, :index, p) end
|
||||||
|
- pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @duplicate_reports, route: route, conn: @conn
|
||||||
|
|
||||||
|
.block
|
||||||
|
.block__header
|
||||||
|
= pagination
|
||||||
|
|
||||||
|
span.block__header__title Display only:
|
||||||
|
=> link "Open (All)", to: Routes.duplicate_report_path(@conn, :index, states: ~W(open claimed))
|
||||||
|
=> link "Open (Unclaimed)", to: Routes.duplicate_report_path(@conn, :index, states: ~W(open))
|
||||||
|
=> link "Open (Claimed)", to: Routes.duplicate_report_path(@conn, :index, states: ~W(claimed))
|
||||||
|
=> link "Open + Rejected", to: Routes.duplicate_report_path(@conn, :index, states: ~W(open rejected))
|
||||||
|
=> link "Rejected", to: Routes.duplicate_report_path(@conn, :index, states: ~W(rejected))
|
||||||
|
=> link "Rejected + Accepted", to: Routes.duplicate_report_path(@conn, :index, states: ~W(rejected accepted))
|
||||||
|
=> link "Accepted", to: Routes.duplicate_report_path(@conn, :index, states: ~W(accepted))
|
||||||
|
= link "All", to: Routes.duplicate_report_path(@conn, :index, states: ~W(open rejected accepted claimed))
|
||||||
|
|
||||||
|
= render PhilomenaWeb.DuplicateReportView, "_list.html", duplicate_reports: @duplicate_reports, conn: @conn
|
||||||
|
|
||||||
|
.block
|
||||||
|
.block__header.block__header--light
|
||||||
|
= pagination
|
49
lib/philomena_web/templates/duplicate_report/show.html.slime
Normal file
49
lib/philomena_web/templates/duplicate_report/show.html.slime
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
elixir:
|
||||||
|
source_url = comparison_url(@conn, @duplicate_report.image)
|
||||||
|
target_url = comparison_url(@conn, @duplicate_report.duplicate_of_image)
|
||||||
|
{width, height} = largest_dimensions([@duplicate_report.image, @duplicate_report.duplicate_of_image])
|
||||||
|
|
||||||
|
h1 Difference
|
||||||
|
.difference
|
||||||
|
svg.difference__image viewBox="0 0 #{width} #{height}" height=height
|
||||||
|
defs
|
||||||
|
filter#overlay-diff
|
||||||
|
feImage#source xlink:href=source_url result="source" width="100%" height="100%" x="0" y="0"
|
||||||
|
feImage#target xlink:href=target_url result="target" width="100%" height="100%" x="0" y="0"
|
||||||
|
feBlend in="source" in2="target" mode="difference" result="diff"
|
||||||
|
|
||||||
|
/ Contrast-boost matrix = (5I|0) [4x5]
|
||||||
|
feColorMatrix in="diff" type="matrix" values="5 0 0 0 0 0 5 0 0 0 0 0 5 0 0 0 0 0 5 0"
|
||||||
|
rect width=width height=height filter="url(#overlay-diff)"
|
||||||
|
|
||||||
|
h1 Swipe
|
||||||
|
.swipe
|
||||||
|
svg.swipe__image viewBox="0 0 #{width} #{height}" height=height
|
||||||
|
defs
|
||||||
|
pattern#checkerboard width="16" height="16" patternUnits="userSpaceOnUse"
|
||||||
|
rect width="8" height="8" x="0" y="0" fill="#ffffff44"
|
||||||
|
rect width="8" height="8" x="0" y="8" fill="#00000044"
|
||||||
|
rect width="8" height="8" x="8" y="0" fill="#00000044"
|
||||||
|
rect width="8" height="8" x="8" y="8" fill="#ffffff44"
|
||||||
|
clipPath#clip
|
||||||
|
rect width=div(width, 2) height=height
|
||||||
|
rect width=width height=height fill="url(#checkerboard)"
|
||||||
|
image#target width="100%" height="100%" xlink:href=target_url
|
||||||
|
image#source width="100%" height="100%" xlink:href=source_url clip-path="url(#clip)"
|
||||||
|
rect#divider width="3" height=height x=div(width, 2) fill="#000" stroke="#fff" stroke-width="1"
|
||||||
|
|
||||||
|
h1 Onion Skin
|
||||||
|
.onion-skin
|
||||||
|
svg.onion-skin__image viewBox="0 0 #{width} #{height}" height=height
|
||||||
|
defs
|
||||||
|
pattern#checkerboard width="16" height="16" patternUnits="userSpaceOnUse"
|
||||||
|
rect width="8" height="8" x="0" y="0" fill="#ffffff44"
|
||||||
|
rect width="8" height="8" x="0" y="8" fill="#00000044"
|
||||||
|
rect width="8" height="8" x="8" y="0" fill="#00000044"
|
||||||
|
rect width="8" height="8" x="8" y="8" fill="#ffffff44"
|
||||||
|
rect width=width height=height fill="url(#checkerboard)"
|
||||||
|
image#source width="100%" height="100%" xlink:href=source_url
|
||||||
|
image#target width="100%" height="100%" xlink:href=target_url
|
||||||
|
input.onion-skin__slider type="range" min="0" max="1" step="0.01"
|
||||||
|
|
||||||
|
p Left is source, right is target
|
135
lib/philomena_web/views/duplicate_report_view.ex
Normal file
135
lib/philomena_web/views/duplicate_report_view.ex
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
defmodule PhilomenaWeb.DuplicateReportView do
|
||||||
|
use PhilomenaWeb, :view
|
||||||
|
|
||||||
|
alias PhilomenaWeb.ImageView
|
||||||
|
|
||||||
|
@formats_order ~W(video/webm image/svg+xml image/png image/gif image/jpeg other)
|
||||||
|
|
||||||
|
def comparison_url(conn, image),
|
||||||
|
do: ImageView.thumb_url(image, can?(conn, :show, image), :full)
|
||||||
|
|
||||||
|
def largest_dimensions(images) do
|
||||||
|
images
|
||||||
|
|> Enum.map(&{&1.image_width, &1.image_height})
|
||||||
|
|> Enum.max_by(fn {w, h} -> w * h end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def background_class(%{state: "rejected"}), do: "background-danger"
|
||||||
|
def background_class(%{state: "accepted"}), do: "background-success"
|
||||||
|
def background_class(%{state: "claimed"}), do: "background-warning"
|
||||||
|
def background_class(_duplicate_report), do: nil
|
||||||
|
|
||||||
|
def file_types(%{image: image, duplicate_of_image: duplicate_of_image}) do
|
||||||
|
source_type = String.upcase(image.image_format)
|
||||||
|
target_type = String.upcase(duplicate_of_image.image_format)
|
||||||
|
|
||||||
|
"(#{source_type}, #{target_type})"
|
||||||
|
end
|
||||||
|
|
||||||
|
def forward_merge?(%{image_id: image_id, duplicate_of_image_id: duplicate_of_image_id}),
|
||||||
|
do: duplicate_of_image_id > image_id
|
||||||
|
|
||||||
|
def higher_res?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: duplicate_of_image.image_width > image.image_width or duplicate_of_image.image_height > image.image_height
|
||||||
|
|
||||||
|
def same_res?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: duplicate_of_image.image_width == image.image_width and duplicate_of_image.image_height == image.image_height
|
||||||
|
|
||||||
|
def same_format?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: duplicate_of_image.image_mime_type == image.image_mime_type
|
||||||
|
|
||||||
|
def better_format?(%{image: image, duplicate_of_image: duplicate_of_image}) do
|
||||||
|
source_index = Enum.find_index(@formats_order, image.image_mime_type) || length(@formats_order) - 1
|
||||||
|
target_index = Enum.find_index(@formats_order, duplicate_of_image.image_mime_type) || length(@formats_order) - 1
|
||||||
|
|
||||||
|
target_index < source_index
|
||||||
|
end
|
||||||
|
|
||||||
|
def same_aspect_ratio?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: abs(duplicate_of_image.image_aspect_ratio - image.image_aspect_ratio) <= 0.009
|
||||||
|
|
||||||
|
def neither_have_source?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: blank?(duplicate_of_image.source_url) and blank?(image.source_url)
|
||||||
|
|
||||||
|
def same_source?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: to_string(duplicate_of_image.source_url) == to_string(image.source_url)
|
||||||
|
|
||||||
|
def similar_source?(%{image: image, duplicate_of_image: duplicate_of_image}) do
|
||||||
|
host1 = URI.parse(image.source_url).host
|
||||||
|
host2 = URI.parse(duplicate_of_image.source_url).host
|
||||||
|
|
||||||
|
host1 == host2
|
||||||
|
end
|
||||||
|
|
||||||
|
def source_on_target?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: present?(duplicate_of_image.source_url) and blank?(image.source_url)
|
||||||
|
|
||||||
|
def source_on_source?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: blank?(duplicate_of_image.source_url) && present?(image.source_url)
|
||||||
|
|
||||||
|
def same_artist_tags?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: MapSet.equal?(artist_tags(image), artist_tags(duplicate_of_image))
|
||||||
|
|
||||||
|
def more_artist_tags_on_target?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: proper_subset?(artist_tags(image), artist_tags(duplicate_of_image))
|
||||||
|
|
||||||
|
def more_artist_tags_on_source?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: proper_subset?(artist_tags(duplicate_of_image), artist_tags(image))
|
||||||
|
|
||||||
|
def same_rating_tags?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: MapSet.equal?(rating_tags(image), rating_tags(duplicate_of_image))
|
||||||
|
|
||||||
|
def target_is_edit?(%{duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: edit?(duplicate_of_image)
|
||||||
|
|
||||||
|
def source_is_edit?(%{image: image}),
|
||||||
|
do: edit?(image)
|
||||||
|
|
||||||
|
def both_are_edits?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: edit?(image) and edit?(duplicate_of_image)
|
||||||
|
|
||||||
|
def target_is_alternate_version?(%{duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: alternate_version?(duplicate_of_image)
|
||||||
|
|
||||||
|
def source_is_alternate_version?(%{image: image}),
|
||||||
|
do: alternate_version?(image)
|
||||||
|
|
||||||
|
def both_are_alternate_versions?(%{image: image, duplicate_of_image: duplicate_of_image}),
|
||||||
|
do: alternate_version?(image) and alternate_version?(duplicate_of_image)
|
||||||
|
|
||||||
|
defp artist_tags(%{tags: tags}) do
|
||||||
|
tags
|
||||||
|
|> Enum.filter(& &1.namespace == "artist")
|
||||||
|
|> Enum.map(& &1.name)
|
||||||
|
|> MapSet.new()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp rating_tags(%{tags: tags}) do
|
||||||
|
tags
|
||||||
|
|> Enum.filter(& &1.category == "rating")
|
||||||
|
|> Enum.map(& &1.name)
|
||||||
|
|> MapSet.new()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp edit?(%{tags: tags}) do
|
||||||
|
tags
|
||||||
|
|> Enum.filter(& &1.name == "edit")
|
||||||
|
|> Enum.any?()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp alternate_version?(%{tags: tags}) do
|
||||||
|
tags
|
||||||
|
|> Enum.filter(& &1.name == "alternate version")
|
||||||
|
|> Enum.any?()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp blank?(nil), do: true
|
||||||
|
defp blank?(""), do: true
|
||||||
|
defp blank?(str) when is_binary(str), do: String.trim(str) == ""
|
||||||
|
defp blank?(_object), do: false
|
||||||
|
|
||||||
|
defp present?(object), do: not blank?(object)
|
||||||
|
|
||||||
|
defp proper_subset?(set1, set2),
|
||||||
|
do: MapSet.subset?(set1, set2) and not MapSet.equal?(set1, set2)
|
||||||
|
end
|
|
@ -0,0 +1,88 @@
|
||||||
|
defmodule PhilomenaWeb.DuplicateReportControllerTest do
|
||||||
|
use PhilomenaWeb.ConnCase
|
||||||
|
|
||||||
|
alias Philomena.DuplicateReports
|
||||||
|
|
||||||
|
@create_attrs %{}
|
||||||
|
@update_attrs %{}
|
||||||
|
@invalid_attrs %{}
|
||||||
|
|
||||||
|
def fixture(:duplicate_report) do
|
||||||
|
{:ok, duplicate_report} = DuplicateReports.create_duplicate_report(@create_attrs)
|
||||||
|
duplicate_report
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "index" do
|
||||||
|
test "lists all duplicate_reports", %{conn: conn} do
|
||||||
|
conn = get(conn, Routes.duplicate_report_path(conn, :index))
|
||||||
|
assert html_response(conn, 200) =~ "Listing Duplicate reports"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "new duplicate_report" do
|
||||||
|
test "renders form", %{conn: conn} do
|
||||||
|
conn = get(conn, Routes.duplicate_report_path(conn, :new))
|
||||||
|
assert html_response(conn, 200) =~ "New Duplicate report"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "create duplicate_report" do
|
||||||
|
test "redirects to show when data is valid", %{conn: conn} do
|
||||||
|
conn = post(conn, Routes.duplicate_report_path(conn, :create), duplicate_report: @create_attrs)
|
||||||
|
|
||||||
|
assert %{id: id} = redirected_params(conn)
|
||||||
|
assert redirected_to(conn) == Routes.duplicate_report_path(conn, :show, id)
|
||||||
|
|
||||||
|
conn = get(conn, Routes.duplicate_report_path(conn, :show, id))
|
||||||
|
assert html_response(conn, 200) =~ "Show Duplicate report"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "renders errors when data is invalid", %{conn: conn} do
|
||||||
|
conn = post(conn, Routes.duplicate_report_path(conn, :create), duplicate_report: @invalid_attrs)
|
||||||
|
assert html_response(conn, 200) =~ "New Duplicate report"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "edit duplicate_report" do
|
||||||
|
setup [:create_duplicate_report]
|
||||||
|
|
||||||
|
test "renders form for editing chosen duplicate_report", %{conn: conn, duplicate_report: duplicate_report} do
|
||||||
|
conn = get(conn, Routes.duplicate_report_path(conn, :edit, duplicate_report))
|
||||||
|
assert html_response(conn, 200) =~ "Edit Duplicate report"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "update duplicate_report" do
|
||||||
|
setup [:create_duplicate_report]
|
||||||
|
|
||||||
|
test "redirects when data is valid", %{conn: conn, duplicate_report: duplicate_report} do
|
||||||
|
conn = put(conn, Routes.duplicate_report_path(conn, :update, duplicate_report), duplicate_report: @update_attrs)
|
||||||
|
assert redirected_to(conn) == Routes.duplicate_report_path(conn, :show, duplicate_report)
|
||||||
|
|
||||||
|
conn = get(conn, Routes.duplicate_report_path(conn, :show, duplicate_report))
|
||||||
|
assert html_response(conn, 200)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "renders errors when data is invalid", %{conn: conn, duplicate_report: duplicate_report} do
|
||||||
|
conn = put(conn, Routes.duplicate_report_path(conn, :update, duplicate_report), duplicate_report: @invalid_attrs)
|
||||||
|
assert html_response(conn, 200) =~ "Edit Duplicate report"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "delete duplicate_report" do
|
||||||
|
setup [:create_duplicate_report]
|
||||||
|
|
||||||
|
test "deletes chosen duplicate_report", %{conn: conn, duplicate_report: duplicate_report} do
|
||||||
|
conn = delete(conn, Routes.duplicate_report_path(conn, :delete, duplicate_report))
|
||||||
|
assert redirected_to(conn) == Routes.duplicate_report_path(conn, :index)
|
||||||
|
assert_error_sent 404, fn ->
|
||||||
|
get(conn, Routes.duplicate_report_path(conn, :show, duplicate_report))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp create_duplicate_report(_) do
|
||||||
|
duplicate_report = fixture(:duplicate_report)
|
||||||
|
{:ok, duplicate_report: duplicate_report}
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue