mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-23 20:18:00 +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 "/channels", ChannelController, only: [:index, :show]
|
||||
resources "/settings", SettingController, only: [:edit, :update], singleton: true
|
||||
resources "/duplicate_reports", DuplicateReportController, only: [:index, :show]
|
||||
|
||||
get "/:id", ImageController, :show
|
||||
# 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