mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-27 13:47:58 +01:00
Merge commit '974d2109e2afbc066a2470ddea3f1c5e3ad44945' into redesign
This commit is contained in:
commit
44e99997e0
25 changed files with 405 additions and 101 deletions
|
@ -87,11 +87,12 @@ function pickAndResize(elem) {
|
|||
}
|
||||
|
||||
const muted = store.get('unmute_videos') ? '' : 'muted';
|
||||
const autoplay = elem.classList.contains('hidden') ? '' : 'autoplay'; // Fix for spoilered image pages
|
||||
|
||||
if (imageFormat === 'mp4') {
|
||||
elem.classList.add('full-height');
|
||||
elem.insertAdjacentHTML('afterbegin',
|
||||
`<video controls autoplay loop ${muted} playsinline preload="auto" id="image-display"
|
||||
`<video controls ${autoplay} loop ${muted} playsinline preload="auto" id="image-display"
|
||||
width="${imageWidth}" height="${imageHeight}">
|
||||
<source src="${uris.webm}" type="video/webm">
|
||||
<source src="${uris.mp4}" type="video/mp4">
|
||||
|
@ -104,7 +105,7 @@ function pickAndResize(elem) {
|
|||
}
|
||||
else if (imageFormat === 'webm') {
|
||||
elem.insertAdjacentHTML('afterbegin',
|
||||
`<video controls autoplay loop ${muted} playsinline id="image-display">
|
||||
`<video controls ${autoplay} loop ${muted} playsinline id="image-display">
|
||||
<source src="${uri}" type="video/webm">
|
||||
<source src="${uri.replace(/webm$/, 'mp4')}" type="video/mp4">
|
||||
<p class="block block--fixed block--warning">
|
||||
|
|
|
@ -369,6 +369,19 @@ describe('Image utils', () => {
|
|||
expect(mockShowElement).toHaveClass(spoilerPendingClass);
|
||||
});
|
||||
|
||||
it('should play the video if it is present', () => {
|
||||
const mockElement = document.createElement('div');
|
||||
const { mockShowElement } = createImageShowElement(mockElement);
|
||||
const mockVideo = document.createElement('video');
|
||||
mockShowElement.appendChild(mockVideo);
|
||||
|
||||
const playSpy = vi.spyOn(mockVideo, 'play').mockReturnValue(Promise.resolve());
|
||||
|
||||
showBlock(mockElement);
|
||||
|
||||
expect(playSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should not throw if image-filtered element is missing', () => {
|
||||
const mockElement = document.createElement('div');
|
||||
createImageShowElement(mockElement);
|
||||
|
|
|
@ -64,9 +64,15 @@ export function showThumb(img: HTMLDivElement) {
|
|||
export function showBlock(img: HTMLDivElement) {
|
||||
img.querySelector('.image-filtered')?.classList.add('hidden');
|
||||
const imageShowClasses = img.querySelector('.image-show')?.classList;
|
||||
|
||||
if (imageShowClasses) {
|
||||
imageShowClasses.remove('hidden');
|
||||
imageShowClasses.add('spoiler-pending');
|
||||
|
||||
const vidEl = img.querySelector('video');
|
||||
if (vidEl) {
|
||||
vidEl.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ config :philomena,
|
|||
anonymous_name_salt: System.fetch_env!("ANONYMOUS_NAME_SALT"),
|
||||
hcaptcha_secret_key: System.fetch_env!("HCAPTCHA_SECRET_KEY"),
|
||||
hcaptcha_site_key: System.fetch_env!("HCAPTCHA_SITE_KEY"),
|
||||
elasticsearch_url: System.get_env("ELASTICSEARCH_URL", "http://localhost:9200"),
|
||||
opensearch_url: System.get_env("OPENSEARCH_URL", "https://admin:admin@localhost:9200"),
|
||||
advert_file_root: System.fetch_env!("ADVERT_FILE_ROOT"),
|
||||
avatar_file_root: System.fetch_env!("AVATAR_FILE_ROOT"),
|
||||
badge_file_root: System.fetch_env!("BADGE_FILE_ROOT"),
|
||||
|
@ -90,6 +90,10 @@ config :philomena, :s3_secondary_options,
|
|||
|
||||
config :philomena, :s3_secondary_bucket, System.get_env("ALT_S3_BUCKET")
|
||||
|
||||
# Don't bail on OpenSearch's self-signed certificate
|
||||
config :elastix,
|
||||
httpoison_options: [ssl: [verify: :verify_none]]
|
||||
|
||||
config :ex_aws, :hackney_opts,
|
||||
timeout: 180_000,
|
||||
recv_timeout: 180_000,
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
version: '3'
|
||||
volumes:
|
||||
postgres_data: {}
|
||||
elastic_data: {}
|
||||
opensearch_data: {}
|
||||
app_cargo_data: {}
|
||||
app_build_data: {}
|
||||
app_deps_data: {}
|
||||
app_native_data: {}
|
||||
|
||||
services:
|
||||
app:
|
||||
|
@ -27,8 +31,8 @@ services:
|
|||
- IMAGE_URL_ROOT=/img
|
||||
- BADGE_URL_ROOT=/badge-img
|
||||
- TAG_URL_ROOT=/tag-img
|
||||
- ELASTICSEARCH_URL=http://elasticsearch:9200
|
||||
- REDIS_HOST=redis
|
||||
- OPENSEARCH_URL=http://opensearch:9200
|
||||
- REDIS_HOST=valkey
|
||||
- DATABASE_URL=ecto://postgres:postgres@postgres/philomena_dev
|
||||
- CDN_HOST=localhost
|
||||
- MAILER_ADDRESS=noreply@philomena.local
|
||||
|
@ -44,10 +48,14 @@ services:
|
|||
tty: true
|
||||
volumes:
|
||||
- .:/srv/philomena
|
||||
- app_cargo_data:/srv/philomena/.cargo
|
||||
- app_build_data:/srv/philomena/_build
|
||||
- app_deps_data:/srv/philomena/deps
|
||||
- app_native_data:/srv/philomena/priv/native
|
||||
depends_on:
|
||||
- postgres
|
||||
- elasticsearch
|
||||
- redis
|
||||
- opensearch
|
||||
- valkey
|
||||
ports:
|
||||
- '5173:5173'
|
||||
|
||||
|
@ -60,21 +68,20 @@ services:
|
|||
logging:
|
||||
driver: "none"
|
||||
|
||||
elasticsearch:
|
||||
image: elasticsearch:7.9.3
|
||||
opensearch:
|
||||
image: opensearchproject/opensearch:2.14.0
|
||||
volumes:
|
||||
- elastic_data:/usr/share/elasticsearch/data
|
||||
- opensearch_data:/usr/share/opensearch/data
|
||||
- ./docker/opensearch/opensearch.yml:/usr/share/opensearch/config/opensearch.yml
|
||||
logging:
|
||||
driver: "none"
|
||||
environment:
|
||||
- discovery.type=single-node
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 65536
|
||||
hard: 65536
|
||||
|
||||
redis:
|
||||
image: redis:7.2.4-alpine
|
||||
valkey:
|
||||
image: valkey/valkey:7.2.5-alpine
|
||||
logging:
|
||||
driver: "none"
|
||||
|
||||
|
|
|
@ -34,11 +34,11 @@ npm install
|
|||
# Always install mix dependencies
|
||||
(cd /srv/philomena && mix deps.get)
|
||||
|
||||
# Sleep to allow Elasticsearch to finish initializing
|
||||
# Sleep to allow OpenSearch to finish initializing
|
||||
# if it's not done doing whatever it does yet
|
||||
echo -n "Waiting for Elasticsearch"
|
||||
echo -n "Waiting for OpenSearch"
|
||||
|
||||
until wget -qO - elasticsearch:9200; do
|
||||
until wget --no-check-certificate -qO - http://opensearch:9200; do
|
||||
echo -n "."
|
||||
sleep 2
|
||||
done
|
||||
|
|
|
@ -9,7 +9,7 @@ export MIX_ENV=test
|
|||
# if it's not done doing whatever it does yet
|
||||
echo -n "Waiting for Elasticsearch"
|
||||
|
||||
until wget -qO - elasticsearch:9200; do
|
||||
until wget -qO - opensearch:9200; do
|
||||
echo -n "."
|
||||
sleep 2
|
||||
done
|
||||
|
|
15
docker/opensearch/opensearch.yml
Normal file
15
docker/opensearch/opensearch.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
cluster.name: docker-cluster
|
||||
|
||||
# Bind to all interfaces because we don't know what IP address Docker will assign to us.
|
||||
network.host: 0.0.0.0
|
||||
|
||||
# Setting network.host to a non-loopback address enables the annoying bootstrap checks. "Single-node" mode disables them again.
|
||||
discovery.type: single-node
|
||||
|
||||
# Disable security. We don't need it for dev environment.
|
||||
# Also, whoever thought it's a GREAT IDEA TO ENFORCE SECURITY FEATURES
|
||||
# BY DEFAULT IN A FREAKING DOCKER CONTAINER should be forced to play
|
||||
# the password game every time they would like to create a new account
|
||||
# anywhere whatsoever.
|
||||
plugins.security.disabled: true
|
233
lib/mix/tasks/convert_to_verified_routes.ex
Normal file
233
lib/mix/tasks/convert_to_verified_routes.ex
Normal file
|
@ -0,0 +1,233 @@
|
|||
defmodule Mix.Tasks.ConvertToVerifiedRoutes do
|
||||
@moduledoc """
|
||||
Replaces routes with verified routes.
|
||||
Forked from
|
||||
https://gist.github.com/andreaseriksson/e454b9244a734310d4ab74d8595f98cd
|
||||
https://gist.github.com/jiegillet/e6357c82e36a848ad59295eb3d5a1135
|
||||
|
||||
This requires all routes to consistently be aliased with
|
||||
alias PhilomenaWeb.Router.Helpers, as: Routes
|
||||
|
||||
Run with
|
||||
mix convert_to_verified_routes
|
||||
"""
|
||||
|
||||
use Mix.Task
|
||||
|
||||
@regex ~r/(Routes\.)([a-zA-Z0-9_]+)(path|url)\(/
|
||||
@web_module PhilomenaWeb
|
||||
|
||||
def run(_) do
|
||||
Path.wildcard("test/**/*.ex*")
|
||||
|> Enum.concat(Path.wildcard("lib/**/*.ex*"))
|
||||
|> Enum.concat(Path.wildcard("lib/**/*.eex*"))
|
||||
|> Enum.concat(Path.wildcard("lib/**/*.slime"))
|
||||
|> Enum.sort()
|
||||
|> Enum.reject(&String.contains?(&1, "convert_to_verified_routes.ex"))
|
||||
|> Enum.filter(&(&1 |> File.read!() |> String.contains?("Routes.")))
|
||||
|> Enum.each(&format_file/1)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
def format_file(filename) do
|
||||
Mix.shell().info(filename)
|
||||
|
||||
formatted_content =
|
||||
filename
|
||||
|> File.read!()
|
||||
|> format_string()
|
||||
|
||||
File.write!(filename, [formatted_content])
|
||||
end
|
||||
|
||||
def format_string(source) do
|
||||
case Regex.run(@regex, source, capture: :first, return: :index) do
|
||||
[{index, length}] ->
|
||||
# Compute full length of expression
|
||||
length = nibble_expression(source, index, length)
|
||||
|
||||
# Convert to verified route format
|
||||
route = format_route(String.slice(source, index, length))
|
||||
|
||||
# Split string around expression
|
||||
prefix = String.slice(source, 0, index)
|
||||
suffix = String.slice(source, index + length, String.length(source))
|
||||
|
||||
# Insert verified route and rerun
|
||||
format_string("#{prefix}#{route}#{suffix}")
|
||||
|
||||
_ ->
|
||||
source
|
||||
end
|
||||
end
|
||||
|
||||
defp nibble_expression(source, index, length) do
|
||||
if index + length > String.length(source) do
|
||||
raise "Failed to match route expression"
|
||||
end
|
||||
|
||||
case Code.string_to_quoted(String.slice(source, index, length)) do
|
||||
{:ok, _macro} ->
|
||||
length
|
||||
|
||||
_ ->
|
||||
nibble_expression(source, index, length + 1)
|
||||
end
|
||||
end
|
||||
|
||||
defp format_route(route) do
|
||||
ast =
|
||||
Code.string_to_quoted!(route,
|
||||
literal_encoder: &{:ok, {:__block__, &2, [&1]}},
|
||||
unescape: false,
|
||||
token_metadata: true
|
||||
)
|
||||
|
||||
ast
|
||||
|> Macro.prewalk(&replace_route/1)
|
||||
|> Code.quoted_to_algebra(escape: false)
|
||||
|> Inspect.Algebra.format(:infinity)
|
||||
end
|
||||
|
||||
defp decode_literal(literal) when is_binary(literal) or is_integer(literal) do
|
||||
{:ok, literal}
|
||||
end
|
||||
|
||||
defp decode_literal({:__block__, _, [literal]}) do
|
||||
{:ok, literal}
|
||||
end
|
||||
|
||||
defp decode_literal(node), do: {:error, node}
|
||||
|
||||
defp encode_literal(literal) do
|
||||
{:__block__, [], [literal]}
|
||||
end
|
||||
|
||||
# Routes.url(MyAppWeb.Endpoint)
|
||||
defp replace_route({{:., _, [{:__aliases__, _, [:Routes]}, :url]}, _, [_conn_or_endpoint]}) do
|
||||
{:url, [], [{:sigil_p, [delimiter: "\""], [{:<<>>, [], ["/"]}, []]}]}
|
||||
end
|
||||
|
||||
# Routes.static_path(conn, "/images/favicon.ico")
|
||||
defp replace_route({{:., _, [{:__aliases__, _, [:Routes]}, :static_path]}, _, args}) do
|
||||
[_conn_or_endpoint, path] = args
|
||||
|
||||
case decode_literal(path) do
|
||||
{:ok, path} -> {:sigil_p, [delimiter: "\""], [{:<<>>, [], [path]}, []]}
|
||||
_ -> {:sigil_p, [delimiter: "\""], [path, []]}
|
||||
end
|
||||
end
|
||||
|
||||
# Routes.static_url(conn, "/images/favicon.ico")
|
||||
defp replace_route({{:., _, [{:__aliases__, _, [:Routes]}, :static_url]}, _, args}) do
|
||||
[_conn_or_endpoint, path] = args
|
||||
|
||||
sigil =
|
||||
case decode_literal(path) do
|
||||
{:ok, path} -> {:sigil_p, [delimiter: "\""], [{:<<>>, [], [path]}, []]}
|
||||
_ -> {:sigil_p, [delimiter: "\""], [path, []]}
|
||||
end
|
||||
|
||||
{:url, [], [sigil]}
|
||||
end
|
||||
|
||||
# Routes.some_path(conn, :action, "en", query_params)
|
||||
defp replace_route(
|
||||
{{:., _, [{:__aliases__, _, [:Routes]}, path_name]}, _, [_ | _] = args} = node
|
||||
) do
|
||||
[_conn_or_endpoint, action | params] = args
|
||||
|
||||
action =
|
||||
case decode_literal(action) do
|
||||
{:ok, action} -> action
|
||||
_ -> action
|
||||
end
|
||||
|
||||
path_name = "#{path_name}"
|
||||
|
||||
case find_verified_route(path_name, action, params) do
|
||||
:ok -> node
|
||||
route -> route
|
||||
end
|
||||
end
|
||||
|
||||
defp replace_route(node), do: node
|
||||
|
||||
defp find_verified_route(path_name, action, arguments) do
|
||||
# pleaaaase don't have a route named Routes.product_url_path(conn, :index)
|
||||
trimmed_path = path_name |> String.trim_trailing("_path") |> String.trim_trailing("_url")
|
||||
|
||||
route =
|
||||
Phoenix.Router.routes(@web_module.Router)
|
||||
|> Enum.find(fn %{helper: helper, plug_opts: plug_opts} ->
|
||||
plug_opts == action && is_binary(helper) && trimmed_path == helper
|
||||
end)
|
||||
|
||||
case route do
|
||||
%{path: path} ->
|
||||
{path_bits, query_params} =
|
||||
path
|
||||
|> String.split("/", trim: true)
|
||||
|> replace_path_variables(arguments, [])
|
||||
|
||||
path_bits =
|
||||
path_bits
|
||||
|> Enum.flat_map(fn bit -> ["/", bit] end)
|
||||
|> format_for_sigil_binary_args(query_params)
|
||||
|
||||
sigil = {:sigil_p, [delimiter: "\""], [{:<<>>, [], path_bits}, []]}
|
||||
|
||||
if String.ends_with?(path_name, "_url") do
|
||||
{:url, [], [sigil]}
|
||||
else
|
||||
sigil
|
||||
end
|
||||
|
||||
_ ->
|
||||
Mix.shell().error(
|
||||
"Could not find route #{path_name}, with action #{inspect(action)} and arguments #{inspect(arguments)}"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
defp replace_path_variables([], arguments, path_bits) do
|
||||
{Enum.reverse(path_bits), arguments}
|
||||
end
|
||||
|
||||
defp replace_path_variables(path, [], path_bits) do
|
||||
{Enum.reverse(path_bits) ++ path, []}
|
||||
end
|
||||
|
||||
# conceptually /post/:post_id -> /post/#{id}
|
||||
defp replace_path_variables([path_piece | rest], [arg | args], path_bits) do
|
||||
if String.starts_with?(path_piece, ":") do
|
||||
replace_path_variables(rest, args, [arg | path_bits])
|
||||
else
|
||||
replace_path_variables(rest, [arg | args], [path_piece | path_bits])
|
||||
end
|
||||
end
|
||||
|
||||
defp format_for_sigil_binary_args(path_bits, [_ | _] = query_params) do
|
||||
format_for_sigil_binary_args(path_bits ++ ["?" | query_params], [])
|
||||
end
|
||||
|
||||
defp format_for_sigil_binary_args(path_bits, []) do
|
||||
path_bits
|
||||
|> Enum.map(&decode_literal/1)
|
||||
|> Enum.map(fn
|
||||
{:ok, bit} when is_binary(bit) ->
|
||||
bit
|
||||
|
||||
{:ok, bit} when is_atom(bit) or is_integer(bit) ->
|
||||
to_string(bit)
|
||||
|
||||
{_, bit} ->
|
||||
{:"::", [],
|
||||
[
|
||||
{{:., [], [Kernel, :to_string]}, [from_interpolation: true], [encode_literal(bit)]},
|
||||
{:binary, [], Elixir}
|
||||
]}
|
||||
end)
|
||||
end
|
||||
end
|
|
@ -30,7 +30,7 @@ defmodule Philomena.Elasticsearch do
|
|||
defp index_for(Filter), do: FilterIndex
|
||||
|
||||
defp elastic_url do
|
||||
Application.get_env(:philomena, :elasticsearch_url)
|
||||
Application.get_env(:philomena, :opensearch_url)
|
||||
end
|
||||
|
||||
def create_index!(module) do
|
||||
|
|
|
@ -5,6 +5,7 @@ defmodule Philomena.Images.Thumbnailer do
|
|||
|
||||
alias Philomena.DuplicateReports
|
||||
alias Philomena.ImageIntensities
|
||||
alias Philomena.ImagePurgeWorker
|
||||
alias Philomena.Images.Image
|
||||
alias Philomena.Processors
|
||||
alias Philomena.Analyzers
|
||||
|
@ -103,8 +104,14 @@ defmodule Philomena.Images.Thumbnailer do
|
|||
defp apply_change(image, {:intensities, intensities}),
|
||||
do: ImageIntensities.create_image_intensity(image, intensities)
|
||||
|
||||
defp apply_change(image, {:replace_original, new_file}),
|
||||
do: upload_file(image, new_file, "full.#{image.image_format}")
|
||||
defp apply_change(image, {:replace_original, new_file}) do
|
||||
full = "full.#{image.image_format}"
|
||||
upload_file(image, new_file, full)
|
||||
|
||||
Exq.enqueue(Exq, "indexing", ImagePurgeWorker, [
|
||||
Path.join(image_url_base(image, nil), full)
|
||||
])
|
||||
end
|
||||
|
||||
defp apply_change(image, {:thumbnails, thumbnails}),
|
||||
do: Enum.map(thumbnails, &apply_thumbnail(image, &1))
|
||||
|
|
|
@ -29,6 +29,8 @@ defmodule Philomena.Search.Parser do
|
|||
__data__: nil
|
||||
]
|
||||
|
||||
@max_clause_count 512
|
||||
|
||||
def parser(options) do
|
||||
parser = struct(Parser, options)
|
||||
|
||||
|
@ -305,14 +307,16 @@ defmodule Philomena.Search.Parser do
|
|||
|
||||
# Flattens the child of a disjunction or conjunction to improve performance.
|
||||
defp flatten_disjunction_child(this_child, %{bool: %{should: next_child}} = child)
|
||||
when child == %{bool: %{should: next_child}} and is_list(next_child),
|
||||
when child == %{bool: %{should: next_child}} and is_list(next_child) and
|
||||
length(next_child) <= @max_clause_count,
|
||||
do: %{bool: %{should: [this_child | next_child]}}
|
||||
|
||||
defp flatten_disjunction_child(this_child, next_child),
|
||||
do: %{bool: %{should: [this_child, next_child]}}
|
||||
|
||||
defp flatten_conjunction_child(this_child, %{bool: %{must: next_child}} = child)
|
||||
when child == %{bool: %{must: next_child}} and is_list(next_child),
|
||||
when child == %{bool: %{must: next_child}} and is_list(next_child) and
|
||||
length(next_child) <= @max_clause_count,
|
||||
do: %{bool: %{must: [this_child | next_child]}}
|
||||
|
||||
defp flatten_conjunction_child(this_child, next_child),
|
||||
|
|
|
@ -213,12 +213,12 @@ defmodule Philomena.Users do
|
|||
|> Ecto.Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, [context]))
|
||||
end
|
||||
|
||||
@doc """
|
||||
@doc ~S"""
|
||||
Delivers the update email instructions to the given user.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> deliver_update_email_instructions(user, current_email, &Routes.user_update_email_url(conn, :edit, &1))
|
||||
iex> deliver_update_email_instructions(user, current_email, &url(~p"/registrations/email/#{&1})")
|
||||
{:ok, %{to: ..., body: ...}}
|
||||
|
||||
"""
|
||||
|
@ -263,12 +263,12 @@ defmodule Philomena.Users do
|
|||
|> Repo.update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
@doc ~S"""
|
||||
Delivers the unlock instructions to the given user.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> deliver_user_unlock_instructions(user, &Routes.unlock_url(conn, :show, &1))
|
||||
iex> deliver_user_unlock_instructions(user, &url(~p"/unlocks/#{&1}"))
|
||||
{:ok, %{to: ..., body: ...}}
|
||||
|
||||
"""
|
||||
|
@ -379,15 +379,15 @@ defmodule Philomena.Users do
|
|||
|
||||
## Confirmation
|
||||
|
||||
@doc """
|
||||
@doc ~S"""
|
||||
Delivers the confirmation email instructions to the given user.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> deliver_user_confirmation_instructions(user, &Routes.user_confirmation_url(conn, :confirm, &1))
|
||||
iex> deliver_user_confirmation_instructions(user, &url(~p"/confirmations/#{&1}"))
|
||||
{:ok, %{to: ..., body: ...}}
|
||||
|
||||
iex> deliver_user_confirmation_instructions(confirmed_user, &Routes.user_confirmation_url(conn, :confirm, &1))
|
||||
iex> deliver_user_confirmation_instructions(confirmed_user, &url(~p"/confirmations/#{&1}"))
|
||||
{:error, :already_confirmed}
|
||||
|
||||
"""
|
||||
|
@ -426,12 +426,12 @@ defmodule Philomena.Users do
|
|||
|
||||
## Reset password
|
||||
|
||||
@doc """
|
||||
@doc ~S"""
|
||||
Delivers the reset password email to the given user.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> deliver_user_reset_password_instructions(user, &Routes.user_reset_password_url(conn, :edit, &1))
|
||||
iex> deliver_user_reset_password_instructions(user, &url(~p"/passwords/#{&1}/edit"))
|
||||
{:ok, %{to: ..., body: ...}}
|
||||
|
||||
"""
|
||||
|
|
|
@ -17,6 +17,8 @@ defmodule PhilomenaWeb do
|
|||
and import those modules here.
|
||||
"""
|
||||
|
||||
def static_paths, do: ~w(assets favicon.ico favicon.svg robots.txt)
|
||||
|
||||
def controller do
|
||||
quote do
|
||||
use Phoenix.Controller, namespace: PhilomenaWeb
|
||||
|
@ -26,6 +28,8 @@ defmodule PhilomenaWeb do
|
|||
import Canary.Plugs
|
||||
import PhilomenaWeb.ModerationLogPlug, only: [moderation_log: 2]
|
||||
alias PhilomenaWeb.Router.Helpers, as: Routes
|
||||
|
||||
unquote(verified_routes())
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -47,6 +51,8 @@ defmodule PhilomenaWeb do
|
|||
|
||||
# Wrong way around for convenience
|
||||
import PhilomenaWeb.AppView
|
||||
|
||||
unquote(verified_routes())
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -65,6 +71,15 @@ defmodule PhilomenaWeb do
|
|||
end
|
||||
end
|
||||
|
||||
def verified_routes do
|
||||
quote do
|
||||
use Phoenix.VerifiedRoutes,
|
||||
endpoint: PhilomenaWeb.Endpoint,
|
||||
router: PhilomenaWeb.Router,
|
||||
statics: PhilomenaWeb.static_paths()
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
When used, dispatch to the appropriate controller/view/etc.
|
||||
"""
|
||||
|
|
|
@ -39,7 +39,7 @@ defmodule PhilomenaWeb.ChannelController do
|
|||
|
||||
if user, do: Channels.clear_notification(channel, user)
|
||||
|
||||
redirect(conn, external: url(channel))
|
||||
redirect(conn, external: channel_url(channel))
|
||||
end
|
||||
|
||||
def new(conn, _params) do
|
||||
|
@ -101,15 +101,15 @@ defmodule PhilomenaWeb.ChannelController do
|
|||
defp maybe_show_nsfw(query, true), do: query
|
||||
defp maybe_show_nsfw(query, _falsy), do: where(query, [c], c.nsfw == false)
|
||||
|
||||
defp url(%{type: "LivestreamChannel", short_name: short_name}),
|
||||
defp channel_url(%{type: "LivestreamChannel", short_name: short_name}),
|
||||
do: "http://www.livestream.com/#{short_name}"
|
||||
|
||||
defp url(%{type: "PicartoChannel", short_name: short_name}),
|
||||
defp channel_url(%{type: "PicartoChannel", short_name: short_name}),
|
||||
do: "https://picarto.tv/#{short_name}"
|
||||
|
||||
defp url(%{type: "PiczelChannel", short_name: short_name}),
|
||||
defp channel_url(%{type: "PiczelChannel", short_name: short_name}),
|
||||
do: "https://piczel.tv/watch/#{short_name}"
|
||||
|
||||
defp url(%{type: "TwitchChannel", short_name: short_name}),
|
||||
defp channel_url(%{type: "TwitchChannel", short_name: short_name}),
|
||||
do: "https://www.twitch.tv/#{short_name}"
|
||||
end
|
||||
|
|
|
@ -7,6 +7,8 @@ defmodule PhilomenaWeb.TorPlug do
|
|||
plug PhilomenaWeb.TorPlug
|
||||
"""
|
||||
alias PhilomenaWeb.Router.Helpers, as: Routes
|
||||
use PhilomenaWeb, :verified_routes
|
||||
|
||||
alias Phoenix.Controller
|
||||
alias Plug.Conn
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ defmodule PhilomenaWeb.TotpPlug do
|
|||
"""
|
||||
|
||||
alias PhilomenaWeb.Router.Helpers, as: Routes
|
||||
use PhilomenaWeb, :verified_routes
|
||||
|
||||
@doc false
|
||||
@spec init(any()) :: any()
|
||||
|
|
|
@ -24,7 +24,7 @@ defmodule PhilomenaWeb.UserAttributionPlug do
|
|||
attributes = [
|
||||
ip: remote_ip,
|
||||
fingerprint: fingerprint(conn, conn.path_info),
|
||||
referrer: conn.assigns.referrer,
|
||||
referrer: referrer(conn.assigns.referrer),
|
||||
user: user,
|
||||
user_agent: user_agent(conn)
|
||||
]
|
||||
|
@ -47,4 +47,7 @@ defmodule PhilomenaWeb.UserAttributionPlug do
|
|||
defp fingerprint(conn, _) do
|
||||
conn.cookies["_ses"]
|
||||
end
|
||||
|
||||
defp referrer(nil), do: nil
|
||||
defp referrer(r), do: String.slice(r, 0, 255)
|
||||
end
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
strong
|
||||
= link("This image is blocked by your current filter - click here to display it anyway", to: "#", data: [click_unfilter: @image.id])
|
||||
p
|
||||
= img_tag(Routes.static_path(PhilomenaWeb.Endpoint, "/images/tagblocked.svg"), width: 250, height: 250, data: [click_unfilter: @image.id])
|
||||
= img_tag(static_path(@conn, "/images/tagblocked.svg"), width: 250, height: 250, data: [click_unfilter: @image.id])
|
||||
span.filter-explanation
|
||||
=< link("your current filter", to: Routes.filter_path(@conn, :show, @conn.assigns.current_filter), class: "filter-link")
|
||||
' .
|
||||
|
|
|
@ -15,8 +15,8 @@ html lang="en"
|
|||
link rel="stylesheet" href=stylesheet_path(@conn, @current_user)
|
||||
= if is_nil(@current_user) do
|
||||
link rel="stylesheet" href=light_stylesheet_path(@conn) media="(prefers-color-scheme: light)"
|
||||
link rel="icon" href="/favicon.ico" type="image/x-icon"
|
||||
link rel="icon" href="/favicon.svg" type="image/svg+xml"
|
||||
link rel="icon" href=~p"/favicon.ico" type="image/x-icon"
|
||||
link rel="icon" href=~p"/favicon.svg" type="image/svg+xml"
|
||||
meta name="generator" content="philomena"
|
||||
meta name="theme-color" content="#618fc3"
|
||||
meta name="format-detection" content="telephone=no"
|
||||
|
@ -26,7 +26,7 @@ html lang="en"
|
|||
script type="module" src="http://localhost:5173/@vite/client"
|
||||
script type="module" src="http://localhost:5173/js/app.ts"
|
||||
- else
|
||||
script type="text/javascript" src=Routes.static_path(@conn, "/js/app.js") async="async"
|
||||
script type="text/javascript" src=~p"/js/app.js" async="async"
|
||||
= render PhilomenaWeb.LayoutView, "_opengraph.html", assigns
|
||||
body data-theme=theme_name(@current_user) data-vite-reload=to_string(vite_reload?())
|
||||
= render PhilomenaWeb.LayoutView, "_burger.html", assigns
|
||||
|
|
|
@ -7,6 +7,8 @@ defmodule PhilomenaWeb.UserAuth do
|
|||
alias PhilomenaWeb.UserIpUpdater
|
||||
alias PhilomenaWeb.UserFingerprintUpdater
|
||||
|
||||
use PhilomenaWeb, :verified_routes
|
||||
|
||||
# Make the remember me cookie valid for 365 days.
|
||||
# If you want bump or reduce this value, also change
|
||||
# the token expiry itself in UserToken.
|
||||
|
|
|
@ -88,13 +88,13 @@ defmodule PhilomenaWeb.LayoutView do
|
|||
"light-cyan",
|
||||
"light-grey"
|
||||
],
|
||||
do: Routes.static_path(conn, "/css/#{theme}.css")
|
||||
do: static_path(conn, "/css/#{theme}.css")
|
||||
|
||||
def stylesheet_path(conn, _user),
|
||||
do: Routes.static_path(conn, "/css/dark-blue.css")
|
||||
def stylesheet_path(_conn, _user),
|
||||
do: ~p"/css/dark-blue.css"
|
||||
|
||||
def light_stylesheet_path(conn),
|
||||
do: Routes.static_path(conn, "/css/light-blue.css")
|
||||
def light_stylesheet_path(_conn),
|
||||
do: ~p"/css/light-blue.css"
|
||||
|
||||
def theme_name(%{theme: theme}), do: theme
|
||||
def theme_name(_user), do: "default"
|
||||
|
|
|
@ -1,52 +1,52 @@
|
|||
defmodule PhilomenaWeb.SettingView do
|
||||
use PhilomenaWeb, :view
|
||||
|
||||
def theme_options(conn) do
|
||||
def theme_options do
|
||||
[
|
||||
[
|
||||
key: "Red",
|
||||
value: "dark-red",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/dark-red.css")]
|
||||
data: [theme_path: ~p"/css/dark-red.css"]
|
||||
],
|
||||
[
|
||||
key: "Orange",
|
||||
value: "dark-orange",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/dark-orange.css")]
|
||||
data: [theme_path: ~p"/css/dark-orange.css"]
|
||||
],
|
||||
[
|
||||
key: "Yellow",
|
||||
value: "dark-yellow",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/dark-yellow.css")]
|
||||
data: [theme_path: ~p"/css/dark-yellow.css"]
|
||||
],
|
||||
[
|
||||
key: "Green",
|
||||
value: "dark-green",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/dark-green.css")]
|
||||
data: [theme_path: ~p"/css/dark-green.css"]
|
||||
],
|
||||
[
|
||||
key: "Blue",
|
||||
value: "dark-blue",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/dark-blue.css")]
|
||||
data: [theme_path: ~p"/css/dark-blue.css"]
|
||||
],
|
||||
[
|
||||
key: "Purple",
|
||||
value: "dark-purple",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/dark-purple.css")]
|
||||
data: [theme_path: ~p"/css/dark-purple.css"]
|
||||
],
|
||||
[
|
||||
key: "Cyan",
|
||||
value: "dark-cyan",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/dark-cyan.css")]
|
||||
data: [theme_path: ~p"/css/dark-cyan.css"]
|
||||
],
|
||||
[
|
||||
key: "Pink",
|
||||
value: "dark-pink",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/dark-pink.css")]
|
||||
data: [theme_path: ~p"/css/dark-pink.css"]
|
||||
],
|
||||
[
|
||||
key: "Grey",
|
||||
value: "dark-grey",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/dark-grey.css")]
|
||||
data: [theme_path: ~p"/css/dark-grey.css"]
|
||||
]
|
||||
]
|
||||
end
|
||||
|
@ -56,47 +56,47 @@ defmodule PhilomenaWeb.SettingView do
|
|||
[
|
||||
key: "Red",
|
||||
value: "light-red",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/light-red.css")]
|
||||
data: [theme_path: ~p"/css/light-red.css"]
|
||||
],
|
||||
[
|
||||
key: "Orange",
|
||||
value: "light-orange",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/light-orange.css")]
|
||||
data: [theme_path: ~p"/css/light-orange.css"]
|
||||
],
|
||||
[
|
||||
key: "Yellow",
|
||||
value: "light-yellow",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/light-yellow.css")]
|
||||
data: [theme_path: ~p"/css/light-yellow.css"]
|
||||
],
|
||||
[
|
||||
key: "Green",
|
||||
value: "light-green",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/light-green.css")]
|
||||
data: [theme_path: ~p"/css/light-green.css"]
|
||||
],
|
||||
[
|
||||
key: "Blue",
|
||||
value: "light-blue",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/light-blue.css")]
|
||||
data: [theme_path: ~p"/css/light-blue.css"]
|
||||
],
|
||||
[
|
||||
key: "Purple",
|
||||
value: "light-purple",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/light-purple.css")]
|
||||
data: [theme_path: ~p"/css/light-purple.css"]
|
||||
],
|
||||
[
|
||||
key: "Cyan",
|
||||
value: "light-cyan",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/light-cyan.css")]
|
||||
data: [theme_path: ~p"/css/light-cyan.css"]
|
||||
],
|
||||
[
|
||||
key: "Pink",
|
||||
value: "light-pink",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/light-pink.css")]
|
||||
data: [theme_path: ~p"/css/light-pink.css"]
|
||||
],
|
||||
[
|
||||
key: "Grey",
|
||||
value: "light-grey",
|
||||
data: [theme_path: Routes.static_path(conn, "/css/light-grey.css")]
|
||||
data: [theme_path: ~p"/css/light-grey.css"]
|
||||
]
|
||||
]
|
||||
end
|
||||
|
|
57
native/philomena/Cargo.lock
generated
57
native/philomena/Cargo.lock
generated
|
@ -43,8 +43,8 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "comrak"
|
||||
version = "0.22.0"
|
||||
source = "git+https://github.com/philomena-dev/comrak?branch=main#a27d6b6487d94e040e5cdb70733d3a59cba5bab0"
|
||||
version = "0.24.1"
|
||||
source = "git+https://github.com/philomena-dev/comrak?branch=main#6a03dabfc80033b24070dc5826c9225686e3a98a"
|
||||
dependencies = [
|
||||
"derive_builder",
|
||||
"entities",
|
||||
|
@ -59,9 +59,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.14.4"
|
||||
version = "0.20.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
|
||||
checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
|
@ -69,58 +69,58 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.14.4"
|
||||
version = "0.20.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
|
||||
checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 1.0.109",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.14.4"
|
||||
version = "0.20.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
|
||||
checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder"
|
||||
version = "0.12.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8"
|
||||
checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7"
|
||||
dependencies = [
|
||||
"derive_builder_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_core"
|
||||
version = "0.12.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f"
|
||||
checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_macro"
|
||||
version = "0.12.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"
|
||||
checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b"
|
||||
dependencies = [
|
||||
"derive_builder_core",
|
||||
"syn 1.0.109",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -348,7 +348,7 @@ dependencies = [
|
|||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.59",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -379,20 +379,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
|||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
|
@ -506,7 +495,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.59",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -528,7 +517,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.59",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
|
|
@ -25,6 +25,8 @@ defmodule PhilomenaWeb.ConnCase do
|
|||
|
||||
# The default endpoint for testing
|
||||
@endpoint PhilomenaWeb.Endpoint
|
||||
|
||||
use PhilomenaWeb, :verified_routes
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue