mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-25 04:47:59 +01:00
266 lines
7.4 KiB
Elixir
266 lines
7.4 KiB
Elixir
defmodule PhilomenaWeb.AppView do
|
|
use Phoenix.HTML
|
|
|
|
import PhilomenaWeb.Gettext
|
|
|
|
@time_strings %{
|
|
seconds: "less than a minute",
|
|
minute: "about a minute",
|
|
minutes: "%d minutes",
|
|
hour: "about an hour",
|
|
hours: "about %d hours",
|
|
day: "a day",
|
|
days: "%d days",
|
|
month: "about a month",
|
|
months: "%d months",
|
|
year: "about a year",
|
|
years: "%d years"
|
|
}
|
|
|
|
@months %{
|
|
1 => "January",
|
|
2 => "February",
|
|
3 => "March",
|
|
4 => "April",
|
|
5 => "May",
|
|
6 => "June",
|
|
7 => "July",
|
|
8 => "August",
|
|
9 => "September",
|
|
10 => "October",
|
|
11 => "November",
|
|
12 => "December"
|
|
}
|
|
|
|
def pretty_time(time) do
|
|
now = DateTime.utc_now()
|
|
seconds = DateTime.diff(now, time, :second)
|
|
relation = if seconds < 0, do: "from now", else: "ago"
|
|
|
|
words = distance_of_time_in_words(now, time)
|
|
|
|
content_tag(:time, "#{words} #{relation}",
|
|
datetime: DateTime.to_iso8601(time),
|
|
title: datetime_string(time)
|
|
)
|
|
end
|
|
|
|
def tag_list(image) do
|
|
Philomena.Images.tag_list(image)
|
|
end
|
|
|
|
def distance_of_time_in_words(time_2, time_1) do
|
|
seconds = abs(DateTime.diff(time_2, time_1, :second))
|
|
minutes = div(seconds, 60)
|
|
hours = div(minutes, 60)
|
|
days = div(hours, 24)
|
|
months = div(days, 30)
|
|
years = div(days, 365)
|
|
|
|
cond do
|
|
seconds < 45 -> String.replace(@time_strings[:seconds], "%d", to_string(seconds))
|
|
seconds < 90 -> String.replace(@time_strings[:minute], "%d", to_string(1))
|
|
minutes < 45 -> String.replace(@time_strings[:minutes], "%d", to_string(minutes))
|
|
minutes < 90 -> String.replace(@time_strings[:hour], "%d", to_string(1))
|
|
hours < 24 -> String.replace(@time_strings[:hours], "%d", to_string(hours))
|
|
hours < 42 -> String.replace(@time_strings[:day], "%d", to_string(1))
|
|
days < 30 -> String.replace(@time_strings[:days], "%d", to_string(days))
|
|
days < 45 -> String.replace(@time_strings[:month], "%d", to_string(1))
|
|
days < 365 -> String.replace(@time_strings[:months], "%d", to_string(months))
|
|
days < 548 -> String.replace(@time_strings[:year], "%d", to_string(1))
|
|
true -> String.replace(@time_strings[:years], "%d", to_string(years))
|
|
end
|
|
end
|
|
|
|
def can?(conn, action, model) do
|
|
Canada.Can.can?(conn.assigns.current_user, action, model)
|
|
end
|
|
|
|
def map_join(enumerable, joiner, map_fn) do
|
|
enumerable
|
|
|> Enum.map(map_fn)
|
|
|> Enum.intersperse(joiner)
|
|
end
|
|
|
|
def number_with_delimiter(nil), do: "0"
|
|
|
|
def number_with_delimiter(number) do
|
|
number
|
|
|> to_charlist()
|
|
|> Enum.reverse()
|
|
|> Enum.chunk_every(3)
|
|
|> Enum.map(&Enum.reverse(&1))
|
|
|> Enum.reverse()
|
|
|> Enum.join(",")
|
|
end
|
|
|
|
def pluralize(singular, plural, count) do
|
|
if count == 1 do
|
|
singular
|
|
else
|
|
plural
|
|
end
|
|
end
|
|
|
|
def button_to(text, route, args \\ []) do
|
|
method = Keyword.get(args, :method, "get")
|
|
class = Keyword.get(args, :class, nil)
|
|
data = Keyword.get(args, :data, [])
|
|
|
|
form_for(nil, route, [method: method, class: "button_to"], fn _f ->
|
|
submit(text, class: class, data: data)
|
|
end)
|
|
end
|
|
|
|
def escape_nl2br(nil), do: nil
|
|
|
|
# Everything is escaped before being sent to raw/1
|
|
# sobelow_skip ["XSS.Raw"]
|
|
def escape_nl2br(text) do
|
|
text
|
|
|> String.split("\n")
|
|
|> Enum.map(&html_escape/1)
|
|
|> Enum.map(&safe_to_string/1)
|
|
|> Enum.join("<br/>")
|
|
|> raw()
|
|
end
|
|
|
|
defp datetime_string(time) do
|
|
:io_lib.format("~2..0B:~2..0B:~2..0B, ~s ~B, ~B", [
|
|
time.hour,
|
|
time.minute,
|
|
time.second,
|
|
@months[time.month],
|
|
time.day,
|
|
time.year
|
|
])
|
|
|> to_string()
|
|
end
|
|
|
|
def link_to_ip(_conn, nil), do: content_tag(:code, "null")
|
|
|
|
def link_to_ip(_conn, ip) do
|
|
link(to: "/ip_profiles/#{ip}") do
|
|
[
|
|
content_tag(:i, "", class: "fas fa-network-wired"),
|
|
" ",
|
|
to_string(ip)
|
|
]
|
|
end
|
|
end
|
|
|
|
def link_to_fingerprint(_conn, nil), do: content_tag(:code, "null")
|
|
|
|
def link_to_fingerprint(_conn, fp) do
|
|
link(to: "/fingerprint_profiles/#{fp}") do
|
|
[
|
|
content_tag(:i, "", class: "fas fa-desktop"),
|
|
" ",
|
|
String.slice(fp, 0..6)
|
|
]
|
|
end
|
|
end
|
|
|
|
def communication_body_class(%{destroyed_content: true}), do: "communication--destroyed"
|
|
def communication_body_class(_communication), do: nil
|
|
|
|
def can_view_communication?(conn, communication) do
|
|
user_id =
|
|
case conn.assigns.current_user do
|
|
nil -> -1
|
|
user -> user.id
|
|
end
|
|
|
|
cond do
|
|
can?(conn, :hide, communication) and not hide_staff_tools?(conn) -> true
|
|
communication.destroyed_content -> false
|
|
not communication.approved and communication.user_id != user_id -> false
|
|
true -> true
|
|
end
|
|
end
|
|
|
|
def hide_staff_tools?(conn),
|
|
do: conn.cookies["hide_staff_tools"] == "true"
|
|
|
|
def blank?(nil), do: true
|
|
def blank?(""), do: true
|
|
def blank?([]), do: true
|
|
def blank?(map) when is_map(map), do: map == %{}
|
|
def blank?(str) when is_binary(str), do: String.trim(str) == ""
|
|
def blank?(_object), do: false
|
|
|
|
def present?(object), do: not blank?(object)
|
|
|
|
# This and related functions are taken from
|
|
# https://github.com/adam12/phoenix_mtm
|
|
# Copied due to the package no longer being actively updated
|
|
# and screwing up our dependencies.
|
|
# Credit goes to the respective authors.
|
|
def collection_checkboxes(form, field, collection, opts \\ []) do
|
|
name = input_name(form, field) <> "[]"
|
|
selected = Keyword.get(opts, :selected, [])
|
|
input_opts = Keyword.get(opts, :input_opts, [])
|
|
label_opts = Keyword.get(opts, :label_opts, [])
|
|
mapper = Keyword.get(opts, :mapper, &mapper_unwrapped/6)
|
|
wrapper = Keyword.get(opts, :wrapper, & &1)
|
|
|
|
inputs =
|
|
Enum.map(collection, fn {label_content, value} ->
|
|
id = input_id(form, field) <> "_#{value}"
|
|
|
|
input_opts =
|
|
input_opts
|
|
|> Keyword.put(:type, "checkbox")
|
|
|> Keyword.put(:id, id)
|
|
|> Keyword.put(:name, name)
|
|
|> Keyword.put(:value, "#{value}")
|
|
|> put_selected(selected, value)
|
|
|
|
label_opts = label_opts ++ [for: id]
|
|
|
|
mapper.(form, field, input_opts, label_content, label_opts, opts)
|
|
|> wrapper.()
|
|
end)
|
|
|
|
html_escape(
|
|
inputs ++
|
|
hidden_input(form, field, name: name, value: "")
|
|
)
|
|
end
|
|
|
|
defp put_selected(opts, selected, value) do
|
|
if Enum.member?(selected, value) do
|
|
Keyword.put(opts, :checked, true)
|
|
else
|
|
opts
|
|
end
|
|
end
|
|
|
|
defp mapper_unwrapped(form, field, input_opts, label_content, label_opts, _opts) do
|
|
[
|
|
tag(:input, input_opts),
|
|
label(form, field, "#{label_content}", label_opts)
|
|
]
|
|
end
|
|
|
|
def image_has_sources(image), do: Enum.count(image.sources) > 0
|
|
|
|
def image_first_source(image) do
|
|
if image_has_sources(image), do: Enum.at(image.sources, 0).source, else: ""
|
|
end
|
|
|
|
def get_flash(%{assigns: %{flash: nil}}), do: %{}
|
|
def get_flash(%{assigns: %{flash: flash}}), do: flash
|
|
def get_flash(_), do: %{}
|
|
|
|
def get_flash(%{assigns: %{flash: nil}}, _key), do: %{}
|
|
def get_flash(%{assigns: %{flash: flash}}, key), do: Phoenix.Flash.get(flash, key)
|
|
def get_flash(_, _key), do: %{}
|
|
|
|
def site_name, do: gettext("Philomena Site")
|
|
|
|
def shorten_number(n) when n >= 1_000_000_000, do: "#{Float.floor(n / 1_000_000_000, 1)}B"
|
|
def shorten_number(n) when n >= 1_000_000, do: "#{Float.floor(n / 1_000_000, 1)}M"
|
|
def shorten_number(n) when n >= 1_000, do: "#{Float.floor(n / 1_000, 1)}K"
|
|
def shorten_number(n), do: n
|
|
end
|