user links

This commit is contained in:
byte[] 2019-12-04 09:04:25 -05:00
parent 50759774f6
commit 846c99e563
11 changed files with 318 additions and 5 deletions

View file

@ -7,6 +7,7 @@ defmodule Philomena.UserLinks do
alias Philomena.Repo
alias Philomena.UserLinks.UserLink
alias Philomena.Tags.Tag
@doc """
Returns the list of user_links.
@ -49,9 +50,11 @@ defmodule Philomena.UserLinks do
{:error, %Ecto.Changeset{}}
"""
def create_user_link(attrs \\ %{}) do
def create_user_link(user, attrs \\ %{}) do
tag = Repo.get_by(Tag, name: attrs["tag_name"])
%UserLink{}
|> UserLink.changeset(attrs)
|> UserLink.creation_changeset(attrs, user, tag)
|> Repo.insert()
end

View file

@ -11,14 +11,14 @@ defmodule Philomena.UserLinks.UserLink do
belongs_to :contacted_by_user, User
belongs_to :tag, Tag
field :aasm_state, :string
field :aasm_state, :string, default: "unverified"
field :uri, :string
field :hostname, :string
field :path, :string
field :verification_code, :string
field :public, :boolean, default: true
field :next_check_at, :naive_datetime
field :contacted_at, :naive_datetime
field :next_check_at, :utc_datetime
field :contacted_at, :utc_datetime
timestamps(inserted_at: :created_at)
end
@ -29,4 +29,37 @@ defmodule Philomena.UserLinks.UserLink do
|> cast(attrs, [])
|> validate_required([])
end
def creation_changeset(user_link, attrs, user, tag) do
user_link
|> cast(attrs, [:uri])
|> put_assoc(:tag, tag)
|> put_assoc(:user, user)
|> validate_required([:user, :uri])
|> parse_uri()
|> put_verification_code()
|> put_next_check_at()
end
defp parse_uri(changeset) do
string_uri = get_field(changeset, :uri) |> to_string()
uri = URI.parse(string_uri)
changeset
|> change(hostname: uri.host, path: uri.path)
end
defp put_verification_code(changeset) do
code = :crypto.strong_rand_bytes(5) |> Base.encode16()
change(changeset, verification_code: "DERPI-LINKVALIDATION-#{code}")
end
defp put_next_check_at(changeset) do
time =
DateTime.utc_now()
|> DateTime.add(60 * 2, :second)
|> DateTime.truncate(:second)
change(changeset, next_check_at: time)
end
end

View file

@ -8,6 +8,7 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do
alias Philomena.Posts.Post
alias Philomena.Filters.Filter
alias Philomena.DnpEntries.DnpEntry
alias Philomena.UserLinks.UserLink
# Admins can do anything
def can?(%User{role: "admin"}, _action, _model), do: true
@ -60,6 +61,9 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do
# Edit filters they own
def can?(%User{id: id}, action, %Filter{user_id: id}) when action in [:edit, :update], do: true
# View user links they've created
def can?(%User{id: id}, :show, %UserLink{user_id: id}), do: true
# View non-deleted images
def can?(_user, action, Image)
when action in [:new, :create, :index],

View file

@ -0,0 +1,45 @@
defmodule PhilomenaWeb.UserLinkController do
use PhilomenaWeb, :controller
alias Philomena.UserLinks
alias Philomena.UserLinks.UserLink
alias Philomena.Repo
import Ecto.Query
plug PhilomenaWeb.FilterBannedUsersPlug when action in [:new, :create]
plug :load_and_authorize_resource, model: UserLink, only: [:show], preload: [:user, :tag, :contacted_by_user]
def index(conn, _params) do
user = conn.assigns.current_user
user_links =
UserLink
|> where(user_id: ^user.id)
|> Repo.all()
render(conn, "index.html", user_links: user_links)
end
def new(conn, _params) do
changeset = UserLinks.change_user_link(%UserLink{})
render(conn, "new.html", changeset: changeset)
end
def create(conn, %{"user_link" => user_link_params}) do
user = conn.assigns.current_user
case UserLinks.create_user_link(user, user_link_params) do
{:ok, user_link} ->
conn
|> put_flash(:info, "Link submitted! Please put '#{user_link.verification_code}' on your linked webpage now.")
|> redirect(to: Routes.user_link_path(conn, :show, user_link))
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "new.html", changeset: changeset)
end
end
def show(conn, _params) do
user_link = conn.assigns.user_link
render(conn, "show.html", user_link: user_link)
end
end

View file

@ -117,6 +117,7 @@ defmodule PhilomenaWeb.Router do
end
resources "/reports", ReportController, only: [:index]
resources "/user_links", UserLinkController, only: [:index, :new, :create, :show]
end
scope "/", PhilomenaWeb do

View file

@ -0,0 +1,38 @@
= form_for @changeset, @action, fn f ->
= if @changeset.action do
.alert.alert-danger
p Oops, something went wrong! Please check the errors below.
.field
.field
p
label for="tag_name"
' The tag,
em> specific
' to you, usually
code>
| artist:
em artist name here
' or a series name
p Should be blank only if your content isn't on the site, generally
= text_input f, :tag_name, class: "input", autocomplete: "off", placeholder: "artist:name", data: [ac: "true", ac_min_length: "3", ac_source: "/tags/autocomplete?term="]
.field
label for="uri"
' URL of your art webpage
= url_input f, :uri, class: "input input--wide", placeholder: "https://www.deviantart.com/your-name"#, required: true
= error_tag f, :uri
.field
=> radio_button f, :public, "true"
=> label f, :public, "Visible to everyone"
.field
=> radio_button f, :public, "false"
=> label f, :public, "Visible only to site staff"
h4 Instructions
p
strong Review details carefully as only site staff can edit later.
p
strong> For quick results, put the LINKVALIDATION code on your linked webpage after submission.
| We'll message you there otherwise.
.actions
= submit "Submit", class: "button"

View file

@ -0,0 +1,23 @@
h1 Your Links
p
a.button href=Routes.user_link_path(@conn, :new)
' Create a link
p
' User links associate your account on Derpibooru with tags about content you create and with accounts on sites elsewhere. This allows users to easily identify artists and admins to act more rapidly on takedown requests.
table.table
thead
tr
th URI
th Options
th Verification Code
th Verified?
th Public
tbody
= for link <- @user_links do
tr
td = link link.uri, to: link.uri
td = link "View Details", to: Routes.user_link_path(@conn, :show, link)
td = link.verification_code
th = verified_as_string(link)
th = public_as_string(link)

View file

@ -0,0 +1,2 @@
h1 Create Link
= render PhilomenaWeb.UserLinkView, "_form.html", changeset: @changeset, action: Routes.user_link_path(@conn, :create)

View file

@ -0,0 +1,59 @@
h1
' Link to
= link @user_link.uri, to: @user_link.uri
h3 Status
= cond do
- verified?(@user_link) ->
p This link has been verified by a member of the administration team.
p You can now remove the verification text from your website if you have not done so already.
- contacted?(@user_link) ->
p
strong This link is awaiting your reply on the linked website in order to be verified.
p
' An administrator
=> "(#{@user_link.contacted_by_user.name})"
' has manually contacted you at the address above, as your verification code was not found on the website. Please respond to the message from the administrator to confirm your link.
p The verification code is:
p
code
h1 = @user_link.verification_code
- link_verified?(@user_link) ->
p
strong This link is pending verification by a member of the administration team.
p We've now found the verification code on your website. An administrator still needs to check the tag list before verifying the link. Please leave the code on your website until verification is complete.
p If you need it again, your verification code is:
p
code
h1 = @user_link.verification_code
- unverified?(@user_link) ->
p
strong This link is pending verification by a member of the administration team.
p
h3 To have your link verified as fast as possible, please place this text somewhere on the page you are linking.
p
code
h1 = @user_link.verification_code
p Otherwise, an administrator will have to contact you to verify your identity.
p Once the link has been verified you can remove the text; the text simply allows the team to directly check with your website rather than messaging you and waiting for a reply.
- rejected?(@user_link) ->
p This link has been rejected by a member of the administration team; this is probably because you were not reachable in a timely manner (~1 week) to verify the link.
h3 Visibility
= if public?(@user_link) do
p This link is public, and will be shown around the site.
- else
p This link is not public, and will only be shown to administrators.
h3 Associated tag
= if @user_link.tag do
p
= render PhilomenaWeb.TagView, "_tag.html", tag: @user_link.tag
- else
p There is no tag associated with this link.
= link "Back", to: Routes.user_link_path(@conn, :index)

View file

@ -0,0 +1,17 @@
defmodule PhilomenaWeb.UserLinkView do
use PhilomenaWeb, :view
def verified?(%{aasm_state: state}), do: state == "verified"
def contacted?(%{aasm_state: state}), do: state == "contacted"
def link_verified?(%{aasm_state: state}), do: state == "link_verified"
def unverified?(%{aasm_state: state}), do: state == "unverified"
def rejected?(%{aasm_state: state}), do: state == "rejected"
def public?(%{public: public}), do: !!public
def verified_as_string(%{aasm_state: "verified"}), do: "Yes"
def verified_as_string(_user_link), do: "No"
def public_as_string(%{public: true}), do: "Yes"
def public_as_string(_user_link), do: "No"
end

View file

@ -0,0 +1,88 @@
defmodule PhilomenaWeb.UserLinkControllerTest do
use PhilomenaWeb.ConnCase
alias Philomena.UserLinks
@create_attrs %{}
@update_attrs %{}
@invalid_attrs %{}
def fixture(:user_link) do
{:ok, user_link} = UserLinks.create_user_link(@create_attrs)
user_link
end
describe "index" do
test "lists all user_links", %{conn: conn} do
conn = get(conn, Routes.user_link_path(conn, :index))
assert html_response(conn, 200) =~ "Listing User links"
end
end
describe "new user_link" do
test "renders form", %{conn: conn} do
conn = get(conn, Routes.user_link_path(conn, :new))
assert html_response(conn, 200) =~ "New User link"
end
end
describe "create user_link" do
test "redirects to show when data is valid", %{conn: conn} do
conn = post(conn, Routes.user_link_path(conn, :create), user_link: @create_attrs)
assert %{id: id} = redirected_params(conn)
assert redirected_to(conn) == Routes.user_link_path(conn, :show, id)
conn = get(conn, Routes.user_link_path(conn, :show, id))
assert html_response(conn, 200) =~ "Show User link"
end
test "renders errors when data is invalid", %{conn: conn} do
conn = post(conn, Routes.user_link_path(conn, :create), user_link: @invalid_attrs)
assert html_response(conn, 200) =~ "New User link"
end
end
describe "edit user_link" do
setup [:create_user_link]
test "renders form for editing chosen user_link", %{conn: conn, user_link: user_link} do
conn = get(conn, Routes.user_link_path(conn, :edit, user_link))
assert html_response(conn, 200) =~ "Edit User link"
end
end
describe "update user_link" do
setup [:create_user_link]
test "redirects when data is valid", %{conn: conn, user_link: user_link} do
conn = put(conn, Routes.user_link_path(conn, :update, user_link), user_link: @update_attrs)
assert redirected_to(conn) == Routes.user_link_path(conn, :show, user_link)
conn = get(conn, Routes.user_link_path(conn, :show, user_link))
assert html_response(conn, 200)
end
test "renders errors when data is invalid", %{conn: conn, user_link: user_link} do
conn = put(conn, Routes.user_link_path(conn, :update, user_link), user_link: @invalid_attrs)
assert html_response(conn, 200) =~ "Edit User link"
end
end
describe "delete user_link" do
setup [:create_user_link]
test "deletes chosen user_link", %{conn: conn, user_link: user_link} do
conn = delete(conn, Routes.user_link_path(conn, :delete, user_link))
assert redirected_to(conn) == Routes.user_link_path(conn, :index)
assert_error_sent 404, fn ->
get(conn, Routes.user_link_path(conn, :show, user_link))
end
end
end
defp create_user_link(_) do
user_link = fixture(:user_link)
{:ok, user_link: user_link}
end
end