philomena/lib/philomena_web/controllers/profile_controller.ex

280 lines
7.5 KiB
Elixir
Raw Normal View History

2019-11-12 02:27:09 +01:00
defmodule PhilomenaWeb.ProfileController do
use PhilomenaWeb, :controller
2019-12-01 03:22:05 +01:00
alias PhilomenaWeb.ImageLoader
alias Philomena.Elasticsearch
2020-05-08 04:19:08 +02:00
alias PhilomenaWeb.TextileRenderer
2019-12-05 14:55:49 +01:00
alias Philomena.UserStatistics.UserStatistic
2019-12-01 03:22:05 +01:00
alias Philomena.Users.User
2019-12-08 21:32:54 +01:00
alias Philomena.Bans
2019-12-05 05:53:56 +01:00
alias Philomena.Galleries.Gallery
alias Philomena.Posts.Post
alias Philomena.Comments.Comment
2019-12-01 03:22:05 +01:00
alias Philomena.Interactions
alias Philomena.Tags.Tag
2019-12-17 06:44:24 +01:00
alias Philomena.UserIps.UserIp
alias Philomena.UserFingerprints.UserFingerprint
2019-12-17 18:29:18 +01:00
alias Philomena.ModNotes.ModNote
alias Philomena.Polymorphic
2019-12-05 05:53:56 +01:00
alias Philomena.Repo
import Ecto.Query
2019-11-12 02:27:09 +01:00
2020-01-11 05:20:19 +01:00
plug :load_and_authorize_resource,
model: User,
only: :show,
id_field: "slug",
preload: [
awards: [:badge, :awarded_by],
public_links: :tag,
verified_links: :tag,
commission: [sheet_image: :tags, items: [example_image: :tags]]
]
2019-12-17 06:44:24 +01:00
plug :set_admin_metadata
2019-12-17 18:29:18 +01:00
plug :set_mod_notes
2019-11-12 02:27:09 +01:00
def show(conn, _params) do
current_filter = conn.assigns.current_filter
2019-11-12 02:27:09 +01:00
current_user = conn.assigns.current_user
user = conn.assigns.user
2019-12-05 22:57:59 +01:00
{:ok, {recent_uploads, _tags}} =
2019-12-01 03:22:05 +01:00
ImageLoader.search_string(
conn,
"uploader_id:#{user.id}",
2019-12-20 02:23:37 +01:00
pagination: %{page_number: 1, page_size: 4}
2019-11-12 02:27:09 +01:00
)
2019-12-05 22:57:59 +01:00
{:ok, {recent_faves, _tags}} =
2019-12-01 03:22:05 +01:00
ImageLoader.search_string(
conn,
"faved_by_id:#{user.id}",
2019-12-20 02:23:37 +01:00
pagination: %{page_number: 1, page_size: 4}
2019-11-12 02:27:09 +01:00
)
2019-12-07 23:07:53 +01:00
tags = tags(conn.assigns.user.public_links)
2020-01-11 05:20:19 +01:00
all_tag_ids =
2019-12-11 02:21:37 +01:00
conn.assigns.user.verified_links
|> tags()
|> Enum.map(& &1.id)
watcher_counts =
Tag
2019-12-11 02:21:37 +01:00
|> where([t], t.id in ^all_tag_ids)
2020-01-11 05:20:19 +01:00
|> join(
:inner_lateral,
[t],
_ in fragment("SELECT count(*) FROM users WHERE watched_tag_ids @> ARRAY[?]", t.id)
)
|> select([t, c], {t.id, c.count})
|> Repo.all()
|> Map.new()
2019-12-07 23:07:53 +01:00
recent_artwork = recent_artwork(conn, tags)
2019-12-05 05:53:56 +01:00
recent_comments =
Elasticsearch.search_records(
Comment,
2019-12-05 05:53:56 +01:00
%{
query: %{
bool: %{
must: [
%{term: %{user_id: user.id}},
%{term: %{anonymous: false}},
%{term: %{hidden_from_users: false}}
],
must_not: [
%{terms: %{image_tag_ids: current_filter.hidden_tag_ids}}
2019-12-05 05:53:56 +01:00
]
}
2019-12-05 06:02:08 +01:00
},
sort: %{posted_at: :desc}
2019-12-05 05:53:56 +01:00
},
%{page_size: 3},
Comment |> preload(user: [awards: :badge], image: :tags)
)
|> Enum.filter(&Canada.Can.can?(current_user, :show, &1.image))
2019-12-05 06:00:41 +01:00
recent_comments =
recent_comments
2020-05-08 04:19:08 +02:00
|> TextileRenderer.render_collection(conn)
2019-12-05 06:00:41 +01:00
|> Enum.zip(recent_comments)
2019-12-05 05:53:56 +01:00
recent_posts =
Elasticsearch.search_records(
Post,
2019-12-05 05:53:56 +01:00
%{
query: %{
bool: %{
must: [
%{term: %{user_id: user.id}},
%{term: %{anonymous: false}},
2019-12-05 19:32:53 +01:00
%{term: %{deleted: false}},
2019-12-05 06:02:08 +01:00
%{term: %{access_level: "normal"}}
2019-12-05 05:53:56 +01:00
]
}
2019-12-05 06:02:08 +01:00
},
sort: %{created_at: :desc}
2019-12-05 05:53:56 +01:00
},
%{page_size: 6},
Post |> preload(user: [awards: :badge], topic: :forum)
)
|> Enum.filter(&Canada.Can.can?(current_user, :show, &1.topic))
2020-05-08 04:19:08 +02:00
about_me = TextileRenderer.render_one(%{body: user.description || ""}, conn)
2020-05-08 04:19:08 +02:00
scratchpad = TextileRenderer.render_one(%{body: user.scratchpad || ""}, conn)
2019-12-05 19:32:53 +01:00
2020-01-11 05:20:19 +01:00
commission_information = commission_info(user.commission, conn)
2019-12-06 00:11:15 +01:00
2019-12-05 05:53:56 +01:00
recent_galleries =
Gallery
|> where(creator_id: ^user.id)
|> preload([:creator, thumbnail: :tags])
2019-12-20 02:23:37 +01:00
|> limit(4)
2019-12-05 05:53:56 +01:00
|> Repo.all()
2019-12-05 14:55:49 +01:00
statistics = calculate_statistics(user)
2019-12-01 03:22:05 +01:00
interactions =
2019-12-20 17:55:16 +01:00
Interactions.user_interactions([recent_uploads, recent_faves, recent_artwork], current_user)
2019-12-01 03:22:05 +01:00
2019-12-08 21:32:54 +01:00
bans =
Bans.User
|> where(user_id: ^user.id)
|> Repo.all()
2020-06-04 03:40:42 +02:00
|> Enum.reject(&String.contains?(&1.note || "", "discourage"))
2019-12-08 21:32:54 +01:00
2019-11-12 02:27:09 +01:00
render(
conn,
"show.html",
user: user,
2019-12-01 03:22:05 +01:00
interactions: interactions,
2019-12-06 00:11:15 +01:00
commission_information: commission_information,
2019-12-07 23:07:53 +01:00
recent_artwork: recent_artwork,
2019-11-12 02:27:09 +01:00
recent_uploads: recent_uploads,
2019-11-18 15:14:26 +01:00
recent_faves: recent_faves,
2019-12-05 05:53:56 +01:00
recent_comments: recent_comments,
recent_posts: recent_posts,
recent_galleries: recent_galleries,
2019-12-05 14:55:49 +01:00
statistics: statistics,
watcher_counts: watcher_counts,
2019-12-05 19:32:53 +01:00
about_me: about_me,
scratchpad: scratchpad,
2019-12-07 23:07:53 +01:00
tags: tags,
2019-12-08 21:32:54 +01:00
bans: bans,
2019-12-16 20:24:38 +01:00
layout_class: "layout--medium",
title: "#{user.name}'s profile"
2019-11-12 02:27:09 +01:00
)
end
2019-12-05 14:55:49 +01:00
defp calculate_statistics(user) do
now =
DateTime.utc_now()
|> DateTime.to_unix(:second)
|> div(86400)
last_90 =
UserStatistic
|> where(user_id: ^user.id)
|> where([us], us.day > ^(now - 89))
|> Repo.all()
2019-12-05 15:01:06 +01:00
|> Map.new(&{now - &1.day, &1})
2019-12-05 14:55:49 +01:00
%{
uploads: individual_stat(last_90, :uploads),
images_favourited: individual_stat(last_90, :images_favourited),
comments_posted: individual_stat(last_90, :comments_posted),
votes_cast: individual_stat(last_90, :votes_cast),
metadata_updates: individual_stat(last_90, :metadata_updates),
forum_posts: individual_stat(last_90, :forum_posts)
}
end
defp individual_stat(mapping, stat_name) do
2020-01-11 05:20:19 +01:00
Enum.map(89..0, &(map_fetch(mapping[&1], stat_name) || 0))
2019-12-05 14:55:49 +01:00
end
defp map_fetch(nil, _field_name), do: nil
defp map_fetch(map, field_name), do: Map.get(map, field_name)
2019-12-06 00:11:15 +01:00
defp commission_info(%{information: info}, conn) when info not in [nil, ""],
2020-05-08 04:19:08 +02:00
do: TextileRenderer.render_one(%{body: info}, conn)
2020-01-11 05:20:19 +01:00
2019-12-06 00:11:15 +01:00
defp commission_info(_commission, _conn), do: ""
2019-12-07 23:07:53 +01:00
defp tags([]), do: []
2019-12-07 23:08:24 +01:00
defp tags(links), do: Enum.map(links, & &1.tag) |> Enum.reject(&is_nil/1)
2019-12-07 23:07:53 +01:00
defp recent_artwork(_conn, []), do: []
2020-01-11 05:20:19 +01:00
2019-12-07 23:07:53 +01:00
defp recent_artwork(conn, tags) do
{images, _tags} =
ImageLoader.query(
conn,
%{terms: %{tag_ids: Enum.map(tags, & &1.id)}},
2019-12-20 02:23:37 +01:00
pagination: %{page_number: 1, page_size: 4}
2019-12-07 23:07:53 +01:00
)
images
end
2019-12-17 06:44:24 +01:00
defp set_admin_metadata(conn, _opts) do
case Canada.Can.can?(conn.assigns.current_user, :index, User) do
true ->
2020-06-07 03:03:17 +02:00
user = Repo.preload(conn.assigns.user, [:current_filter, :forced_filter])
2019-12-17 06:44:24 +01:00
filter = user.current_filter
2020-06-07 03:03:17 +02:00
forced = user.forced_filter
2020-01-11 05:20:19 +01:00
2019-12-17 06:44:24 +01:00
last_ip =
UserIp
|> where(user_id: ^user.id)
|> order_by(desc: :updated_at)
|> limit(1)
|> Repo.one()
last_fp =
UserFingerprint
|> where(user_id: ^user.id)
|> order_by(desc: :updated_at)
|> limit(1)
|> Repo.one()
conn
|> assign(:filter, filter)
2020-06-07 03:03:17 +02:00
|> assign(:forced, forced)
2019-12-17 06:44:24 +01:00
|> assign(:last_ip, last_ip)
|> assign(:last_fp, last_fp)
_false ->
conn
end
end
2019-12-17 18:29:18 +01:00
defp set_mod_notes(conn, _opts) do
case Canada.Can.can?(conn.assigns.current_user, :index, ModNote) do
true ->
user = conn.assigns.user
mod_notes =
ModNote
|> where(notable_type: "User", notable_id: ^user.id)
|> order_by(desc: :id)
|> preload(:moderator)
|> Repo.all()
|> Polymorphic.load_polymorphic(notable: [notable_id: :notable_type])
mod_notes =
mod_notes
2020-05-08 04:19:08 +02:00
|> TextileRenderer.render_collection(conn)
2019-12-17 18:29:18 +01:00
|> Enum.zip(mod_notes)
assign(conn, :mod_notes, mod_notes)
_false ->
conn
end
end
2019-11-12 02:27:09 +01:00
end