mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-23 20:18:00 +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 muted = store.get('unmute_videos') ? '' : 'muted';
|
||||||
|
const autoplay = elem.classList.contains('hidden') ? '' : 'autoplay'; // Fix for spoilered image pages
|
||||||
|
|
||||||
if (imageFormat === 'mp4') {
|
if (imageFormat === 'mp4') {
|
||||||
elem.classList.add('full-height');
|
elem.classList.add('full-height');
|
||||||
elem.insertAdjacentHTML('afterbegin',
|
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}">
|
width="${imageWidth}" height="${imageHeight}">
|
||||||
<source src="${uris.webm}" type="video/webm">
|
<source src="${uris.webm}" type="video/webm">
|
||||||
<source src="${uris.mp4}" type="video/mp4">
|
<source src="${uris.mp4}" type="video/mp4">
|
||||||
|
@ -104,7 +105,7 @@ function pickAndResize(elem) {
|
||||||
}
|
}
|
||||||
else if (imageFormat === 'webm') {
|
else if (imageFormat === 'webm') {
|
||||||
elem.insertAdjacentHTML('afterbegin',
|
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}" type="video/webm">
|
||||||
<source src="${uri.replace(/webm$/, 'mp4')}" type="video/mp4">
|
<source src="${uri.replace(/webm$/, 'mp4')}" type="video/mp4">
|
||||||
<p class="block block--fixed block--warning">
|
<p class="block block--fixed block--warning">
|
||||||
|
|
|
@ -369,6 +369,19 @@ describe('Image utils', () => {
|
||||||
expect(mockShowElement).toHaveClass(spoilerPendingClass);
|
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', () => {
|
it('should not throw if image-filtered element is missing', () => {
|
||||||
const mockElement = document.createElement('div');
|
const mockElement = document.createElement('div');
|
||||||
createImageShowElement(mockElement);
|
createImageShowElement(mockElement);
|
||||||
|
|
|
@ -64,9 +64,15 @@ export function showThumb(img: HTMLDivElement) {
|
||||||
export function showBlock(img: HTMLDivElement) {
|
export function showBlock(img: HTMLDivElement) {
|
||||||
img.querySelector('.image-filtered')?.classList.add('hidden');
|
img.querySelector('.image-filtered')?.classList.add('hidden');
|
||||||
const imageShowClasses = img.querySelector('.image-show')?.classList;
|
const imageShowClasses = img.querySelector('.image-show')?.classList;
|
||||||
|
|
||||||
if (imageShowClasses) {
|
if (imageShowClasses) {
|
||||||
imageShowClasses.remove('hidden');
|
imageShowClasses.remove('hidden');
|
||||||
imageShowClasses.add('spoiler-pending');
|
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"),
|
anonymous_name_salt: System.fetch_env!("ANONYMOUS_NAME_SALT"),
|
||||||
hcaptcha_secret_key: System.fetch_env!("HCAPTCHA_SECRET_KEY"),
|
hcaptcha_secret_key: System.fetch_env!("HCAPTCHA_SECRET_KEY"),
|
||||||
hcaptcha_site_key: System.fetch_env!("HCAPTCHA_SITE_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"),
|
advert_file_root: System.fetch_env!("ADVERT_FILE_ROOT"),
|
||||||
avatar_file_root: System.fetch_env!("AVATAR_FILE_ROOT"),
|
avatar_file_root: System.fetch_env!("AVATAR_FILE_ROOT"),
|
||||||
badge_file_root: System.fetch_env!("BADGE_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")
|
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,
|
config :ex_aws, :hackney_opts,
|
||||||
timeout: 180_000,
|
timeout: 180_000,
|
||||||
recv_timeout: 180_000,
|
recv_timeout: 180_000,
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
version: '3'
|
version: '3'
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data: {}
|
postgres_data: {}
|
||||||
elastic_data: {}
|
opensearch_data: {}
|
||||||
|
app_cargo_data: {}
|
||||||
|
app_build_data: {}
|
||||||
|
app_deps_data: {}
|
||||||
|
app_native_data: {}
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
|
@ -27,8 +31,8 @@ services:
|
||||||
- IMAGE_URL_ROOT=/img
|
- IMAGE_URL_ROOT=/img
|
||||||
- BADGE_URL_ROOT=/badge-img
|
- BADGE_URL_ROOT=/badge-img
|
||||||
- TAG_URL_ROOT=/tag-img
|
- TAG_URL_ROOT=/tag-img
|
||||||
- ELASTICSEARCH_URL=http://elasticsearch:9200
|
- OPENSEARCH_URL=http://opensearch:9200
|
||||||
- REDIS_HOST=redis
|
- REDIS_HOST=valkey
|
||||||
- DATABASE_URL=ecto://postgres:postgres@postgres/philomena_dev
|
- DATABASE_URL=ecto://postgres:postgres@postgres/philomena_dev
|
||||||
- CDN_HOST=localhost
|
- CDN_HOST=localhost
|
||||||
- MAILER_ADDRESS=noreply@philomena.local
|
- MAILER_ADDRESS=noreply@philomena.local
|
||||||
|
@ -44,10 +48,14 @@ services:
|
||||||
tty: true
|
tty: true
|
||||||
volumes:
|
volumes:
|
||||||
- .:/srv/philomena
|
- .:/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:
|
depends_on:
|
||||||
- postgres
|
- postgres
|
||||||
- elasticsearch
|
- opensearch
|
||||||
- redis
|
- valkey
|
||||||
ports:
|
ports:
|
||||||
- '5173:5173'
|
- '5173:5173'
|
||||||
|
|
||||||
|
@ -60,21 +68,20 @@ services:
|
||||||
logging:
|
logging:
|
||||||
driver: "none"
|
driver: "none"
|
||||||
|
|
||||||
elasticsearch:
|
opensearch:
|
||||||
image: elasticsearch:7.9.3
|
image: opensearchproject/opensearch:2.14.0
|
||||||
volumes:
|
volumes:
|
||||||
- elastic_data:/usr/share/elasticsearch/data
|
- opensearch_data:/usr/share/opensearch/data
|
||||||
|
- ./docker/opensearch/opensearch.yml:/usr/share/opensearch/config/opensearch.yml
|
||||||
logging:
|
logging:
|
||||||
driver: "none"
|
driver: "none"
|
||||||
environment:
|
|
||||||
- discovery.type=single-node
|
|
||||||
ulimits:
|
ulimits:
|
||||||
nofile:
|
nofile:
|
||||||
soft: 65536
|
soft: 65536
|
||||||
hard: 65536
|
hard: 65536
|
||||||
|
|
||||||
redis:
|
valkey:
|
||||||
image: redis:7.2.4-alpine
|
image: valkey/valkey:7.2.5-alpine
|
||||||
logging:
|
logging:
|
||||||
driver: "none"
|
driver: "none"
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,11 @@ npm install
|
||||||
# Always install mix dependencies
|
# Always install mix dependencies
|
||||||
(cd /srv/philomena && mix deps.get)
|
(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
|
# 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 "."
|
echo -n "."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
|
@ -9,7 +9,7 @@ export MIX_ENV=test
|
||||||
# if it's not done doing whatever it does yet
|
# if it's not done doing whatever it does yet
|
||||||
echo -n "Waiting for Elasticsearch"
|
echo -n "Waiting for Elasticsearch"
|
||||||
|
|
||||||
until wget -qO - elasticsearch:9200; do
|
until wget -qO - opensearch:9200; do
|
||||||
echo -n "."
|
echo -n "."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
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 index_for(Filter), do: FilterIndex
|
||||||
|
|
||||||
defp elastic_url do
|
defp elastic_url do
|
||||||
Application.get_env(:philomena, :elasticsearch_url)
|
Application.get_env(:philomena, :opensearch_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_index!(module) do
|
def create_index!(module) do
|
||||||
|
|
|
@ -5,6 +5,7 @@ defmodule Philomena.Images.Thumbnailer do
|
||||||
|
|
||||||
alias Philomena.DuplicateReports
|
alias Philomena.DuplicateReports
|
||||||
alias Philomena.ImageIntensities
|
alias Philomena.ImageIntensities
|
||||||
|
alias Philomena.ImagePurgeWorker
|
||||||
alias Philomena.Images.Image
|
alias Philomena.Images.Image
|
||||||
alias Philomena.Processors
|
alias Philomena.Processors
|
||||||
alias Philomena.Analyzers
|
alias Philomena.Analyzers
|
||||||
|
@ -103,8 +104,14 @@ defmodule Philomena.Images.Thumbnailer do
|
||||||
defp apply_change(image, {:intensities, intensities}),
|
defp apply_change(image, {:intensities, intensities}),
|
||||||
do: ImageIntensities.create_image_intensity(image, intensities)
|
do: ImageIntensities.create_image_intensity(image, intensities)
|
||||||
|
|
||||||
defp apply_change(image, {:replace_original, new_file}),
|
defp apply_change(image, {:replace_original, new_file}) do
|
||||||
do: upload_file(image, new_file, "full.#{image.image_format}")
|
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}),
|
defp apply_change(image, {:thumbnails, thumbnails}),
|
||||||
do: Enum.map(thumbnails, &apply_thumbnail(image, &1))
|
do: Enum.map(thumbnails, &apply_thumbnail(image, &1))
|
||||||
|
|
|
@ -29,6 +29,8 @@ defmodule Philomena.Search.Parser do
|
||||||
__data__: nil
|
__data__: nil
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@max_clause_count 512
|
||||||
|
|
||||||
def parser(options) do
|
def parser(options) do
|
||||||
parser = struct(Parser, options)
|
parser = struct(Parser, options)
|
||||||
|
|
||||||
|
@ -305,14 +307,16 @@ defmodule Philomena.Search.Parser do
|
||||||
|
|
||||||
# Flattens the child of a disjunction or conjunction to improve performance.
|
# Flattens the child of a disjunction or conjunction to improve performance.
|
||||||
defp flatten_disjunction_child(this_child, %{bool: %{should: next_child}} = child)
|
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]}}
|
do: %{bool: %{should: [this_child | next_child]}}
|
||||||
|
|
||||||
defp flatten_disjunction_child(this_child, next_child),
|
defp flatten_disjunction_child(this_child, next_child),
|
||||||
do: %{bool: %{should: [this_child, next_child]}}
|
do: %{bool: %{should: [this_child, next_child]}}
|
||||||
|
|
||||||
defp flatten_conjunction_child(this_child, %{bool: %{must: next_child}} = 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]}}
|
do: %{bool: %{must: [this_child | next_child]}}
|
||||||
|
|
||||||
defp flatten_conjunction_child(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]))
|
|> Ecto.Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, [context]))
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc ~S"""
|
||||||
Delivers the update email instructions to the given user.
|
Delivers the update email instructions to the given user.
|
||||||
|
|
||||||
## Examples
|
## 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: ...}}
|
{:ok, %{to: ..., body: ...}}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -263,12 +263,12 @@ defmodule Philomena.Users do
|
||||||
|> Repo.update()
|
|> Repo.update()
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc ~S"""
|
||||||
Delivers the unlock instructions to the given user.
|
Delivers the unlock instructions to the given user.
|
||||||
|
|
||||||
## Examples
|
## 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: ...}}
|
{:ok, %{to: ..., body: ...}}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -379,15 +379,15 @@ defmodule Philomena.Users do
|
||||||
|
|
||||||
## Confirmation
|
## Confirmation
|
||||||
|
|
||||||
@doc """
|
@doc ~S"""
|
||||||
Delivers the confirmation email instructions to the given user.
|
Delivers the confirmation email instructions to the given user.
|
||||||
|
|
||||||
## Examples
|
## 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: ...}}
|
{: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}
|
{:error, :already_confirmed}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -426,12 +426,12 @@ defmodule Philomena.Users do
|
||||||
|
|
||||||
## Reset password
|
## Reset password
|
||||||
|
|
||||||
@doc """
|
@doc ~S"""
|
||||||
Delivers the reset password email to the given user.
|
Delivers the reset password email to the given user.
|
||||||
|
|
||||||
## Examples
|
## 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: ...}}
|
{:ok, %{to: ..., body: ...}}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -17,6 +17,8 @@ defmodule PhilomenaWeb do
|
||||||
and import those modules here.
|
and import those modules here.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def static_paths, do: ~w(assets favicon.ico favicon.svg robots.txt)
|
||||||
|
|
||||||
def controller do
|
def controller do
|
||||||
quote do
|
quote do
|
||||||
use Phoenix.Controller, namespace: PhilomenaWeb
|
use Phoenix.Controller, namespace: PhilomenaWeb
|
||||||
|
@ -26,6 +28,8 @@ defmodule PhilomenaWeb do
|
||||||
import Canary.Plugs
|
import Canary.Plugs
|
||||||
import PhilomenaWeb.ModerationLogPlug, only: [moderation_log: 2]
|
import PhilomenaWeb.ModerationLogPlug, only: [moderation_log: 2]
|
||||||
alias PhilomenaWeb.Router.Helpers, as: Routes
|
alias PhilomenaWeb.Router.Helpers, as: Routes
|
||||||
|
|
||||||
|
unquote(verified_routes())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -47,6 +51,8 @@ defmodule PhilomenaWeb do
|
||||||
|
|
||||||
# Wrong way around for convenience
|
# Wrong way around for convenience
|
||||||
import PhilomenaWeb.AppView
|
import PhilomenaWeb.AppView
|
||||||
|
|
||||||
|
unquote(verified_routes())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -65,6 +71,15 @@ defmodule PhilomenaWeb do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def verified_routes do
|
||||||
|
quote do
|
||||||
|
use Phoenix.VerifiedRoutes,
|
||||||
|
endpoint: PhilomenaWeb.Endpoint,
|
||||||
|
router: PhilomenaWeb.Router,
|
||||||
|
statics: PhilomenaWeb.static_paths()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
When used, dispatch to the appropriate controller/view/etc.
|
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)
|
if user, do: Channels.clear_notification(channel, user)
|
||||||
|
|
||||||
redirect(conn, external: url(channel))
|
redirect(conn, external: channel_url(channel))
|
||||||
end
|
end
|
||||||
|
|
||||||
def new(conn, _params) do
|
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, true), do: query
|
||||||
defp maybe_show_nsfw(query, _falsy), do: where(query, [c], c.nsfw == false)
|
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}"
|
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}"
|
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}"
|
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}"
|
do: "https://www.twitch.tv/#{short_name}"
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,8 @@ defmodule PhilomenaWeb.TorPlug do
|
||||||
plug PhilomenaWeb.TorPlug
|
plug PhilomenaWeb.TorPlug
|
||||||
"""
|
"""
|
||||||
alias PhilomenaWeb.Router.Helpers, as: Routes
|
alias PhilomenaWeb.Router.Helpers, as: Routes
|
||||||
|
use PhilomenaWeb, :verified_routes
|
||||||
|
|
||||||
alias Phoenix.Controller
|
alias Phoenix.Controller
|
||||||
alias Plug.Conn
|
alias Plug.Conn
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ defmodule PhilomenaWeb.TotpPlug do
|
||||||
"""
|
"""
|
||||||
|
|
||||||
alias PhilomenaWeb.Router.Helpers, as: Routes
|
alias PhilomenaWeb.Router.Helpers, as: Routes
|
||||||
|
use PhilomenaWeb, :verified_routes
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
@spec init(any()) :: any()
|
@spec init(any()) :: any()
|
||||||
|
|
|
@ -24,7 +24,7 @@ defmodule PhilomenaWeb.UserAttributionPlug do
|
||||||
attributes = [
|
attributes = [
|
||||||
ip: remote_ip,
|
ip: remote_ip,
|
||||||
fingerprint: fingerprint(conn, conn.path_info),
|
fingerprint: fingerprint(conn, conn.path_info),
|
||||||
referrer: conn.assigns.referrer,
|
referrer: referrer(conn.assigns.referrer),
|
||||||
user: user,
|
user: user,
|
||||||
user_agent: user_agent(conn)
|
user_agent: user_agent(conn)
|
||||||
]
|
]
|
||||||
|
@ -47,4 +47,7 @@ defmodule PhilomenaWeb.UserAttributionPlug do
|
||||||
defp fingerprint(conn, _) do
|
defp fingerprint(conn, _) do
|
||||||
conn.cookies["_ses"]
|
conn.cookies["_ses"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp referrer(nil), do: nil
|
||||||
|
defp referrer(r), do: String.slice(r, 0, 255)
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
strong
|
strong
|
||||||
= link("This image is blocked by your current filter - click here to display it anyway", to: "#", data: [click_unfilter: @image.id])
|
= link("This image is blocked by your current filter - click here to display it anyway", to: "#", data: [click_unfilter: @image.id])
|
||||||
p
|
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
|
span.filter-explanation
|
||||||
=< link("your current filter", to: Routes.filter_path(@conn, :show, @conn.assigns.current_filter), class: "filter-link")
|
=< 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)
|
link rel="stylesheet" href=stylesheet_path(@conn, @current_user)
|
||||||
= if is_nil(@current_user) do
|
= if is_nil(@current_user) do
|
||||||
link rel="stylesheet" href=light_stylesheet_path(@conn) media="(prefers-color-scheme: light)"
|
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=~p"/favicon.ico" type="image/x-icon"
|
||||||
link rel="icon" href="/favicon.svg" type="image/svg+xml"
|
link rel="icon" href=~p"/favicon.svg" type="image/svg+xml"
|
||||||
meta name="generator" content="philomena"
|
meta name="generator" content="philomena"
|
||||||
meta name="theme-color" content="#618fc3"
|
meta name="theme-color" content="#618fc3"
|
||||||
meta name="format-detection" content="telephone=no"
|
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/@vite/client"
|
||||||
script type="module" src="http://localhost:5173/js/app.ts"
|
script type="module" src="http://localhost:5173/js/app.ts"
|
||||||
- else
|
- 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
|
= render PhilomenaWeb.LayoutView, "_opengraph.html", assigns
|
||||||
body data-theme=theme_name(@current_user) data-vite-reload=to_string(vite_reload?())
|
body data-theme=theme_name(@current_user) data-vite-reload=to_string(vite_reload?())
|
||||||
= render PhilomenaWeb.LayoutView, "_burger.html", assigns
|
= render PhilomenaWeb.LayoutView, "_burger.html", assigns
|
||||||
|
|
|
@ -7,6 +7,8 @@ defmodule PhilomenaWeb.UserAuth do
|
||||||
alias PhilomenaWeb.UserIpUpdater
|
alias PhilomenaWeb.UserIpUpdater
|
||||||
alias PhilomenaWeb.UserFingerprintUpdater
|
alias PhilomenaWeb.UserFingerprintUpdater
|
||||||
|
|
||||||
|
use PhilomenaWeb, :verified_routes
|
||||||
|
|
||||||
# Make the remember me cookie valid for 365 days.
|
# Make the remember me cookie valid for 365 days.
|
||||||
# If you want bump or reduce this value, also change
|
# If you want bump or reduce this value, also change
|
||||||
# the token expiry itself in UserToken.
|
# the token expiry itself in UserToken.
|
||||||
|
|
|
@ -88,13 +88,13 @@ defmodule PhilomenaWeb.LayoutView do
|
||||||
"light-cyan",
|
"light-cyan",
|
||||||
"light-grey"
|
"light-grey"
|
||||||
],
|
],
|
||||||
do: Routes.static_path(conn, "/css/#{theme}.css")
|
do: static_path(conn, "/css/#{theme}.css")
|
||||||
|
|
||||||
def stylesheet_path(conn, _user),
|
def stylesheet_path(_conn, _user),
|
||||||
do: Routes.static_path(conn, "/css/dark-blue.css")
|
do: ~p"/css/dark-blue.css"
|
||||||
|
|
||||||
def light_stylesheet_path(conn),
|
def light_stylesheet_path(_conn),
|
||||||
do: Routes.static_path(conn, "/css/light-blue.css")
|
do: ~p"/css/light-blue.css"
|
||||||
|
|
||||||
def theme_name(%{theme: theme}), do: theme
|
def theme_name(%{theme: theme}), do: theme
|
||||||
def theme_name(_user), do: "default"
|
def theme_name(_user), do: "default"
|
||||||
|
|
|
@ -1,52 +1,52 @@
|
||||||
defmodule PhilomenaWeb.SettingView do
|
defmodule PhilomenaWeb.SettingView do
|
||||||
use PhilomenaWeb, :view
|
use PhilomenaWeb, :view
|
||||||
|
|
||||||
def theme_options(conn) do
|
def theme_options do
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
key: "Red",
|
key: "Red",
|
||||||
value: "dark-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",
|
key: "Orange",
|
||||||
value: "dark-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",
|
key: "Yellow",
|
||||||
value: "dark-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",
|
key: "Green",
|
||||||
value: "dark-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",
|
key: "Blue",
|
||||||
value: "dark-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",
|
key: "Purple",
|
||||||
value: "dark-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",
|
key: "Cyan",
|
||||||
value: "dark-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",
|
key: "Pink",
|
||||||
value: "dark-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",
|
key: "Grey",
|
||||||
value: "dark-grey",
|
value: "dark-grey",
|
||||||
data: [theme_path: Routes.static_path(conn, "/css/dark-grey.css")]
|
data: [theme_path: ~p"/css/dark-grey.css"]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
@ -56,47 +56,47 @@ defmodule PhilomenaWeb.SettingView do
|
||||||
[
|
[
|
||||||
key: "Red",
|
key: "Red",
|
||||||
value: "light-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",
|
key: "Orange",
|
||||||
value: "light-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",
|
key: "Yellow",
|
||||||
value: "light-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",
|
key: "Green",
|
||||||
value: "light-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",
|
key: "Blue",
|
||||||
value: "light-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",
|
key: "Purple",
|
||||||
value: "light-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",
|
key: "Cyan",
|
||||||
value: "light-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",
|
key: "Pink",
|
||||||
value: "light-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",
|
key: "Grey",
|
||||||
value: "light-grey",
|
value: "light-grey",
|
||||||
data: [theme_path: Routes.static_path(conn, "/css/light-grey.css")]
|
data: [theme_path: ~p"/css/light-grey.css"]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
57
native/philomena/Cargo.lock
generated
57
native/philomena/Cargo.lock
generated
|
@ -43,8 +43,8 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "comrak"
|
name = "comrak"
|
||||||
version = "0.22.0"
|
version = "0.24.1"
|
||||||
source = "git+https://github.com/philomena-dev/comrak?branch=main#a27d6b6487d94e040e5cdb70733d3a59cba5bab0"
|
source = "git+https://github.com/philomena-dev/comrak?branch=main#6a03dabfc80033b24070dc5826c9225686e3a98a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_builder",
|
"derive_builder",
|
||||||
"entities",
|
"entities",
|
||||||
|
@ -59,9 +59,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.14.4"
|
version = "0.20.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
|
checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"darling_macro",
|
"darling_macro",
|
||||||
|
@ -69,58 +69,58 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling_core"
|
name = "darling_core"
|
||||||
version = "0.14.4"
|
version = "0.20.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
|
checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fnv",
|
"fnv",
|
||||||
"ident_case",
|
"ident_case",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strsim",
|
"strsim",
|
||||||
"syn 1.0.109",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling_macro"
|
name = "darling_macro"
|
||||||
version = "0.14.4"
|
version = "0.20.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
|
checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_builder"
|
name = "derive_builder"
|
||||||
version = "0.12.0"
|
version = "0.20.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8"
|
checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_builder_macro",
|
"derive_builder_macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_builder_core"
|
name = "derive_builder_core"
|
||||||
version = "0.12.0"
|
version = "0.20.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f"
|
checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_builder_macro"
|
name = "derive_builder_macro"
|
||||||
version = "0.12.0"
|
version = "0.20.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"
|
checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_builder_core",
|
"derive_builder_core",
|
||||||
"syn 1.0.109",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -348,7 +348,7 @@ dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.59",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -379,20 +379,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[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",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
|
@ -506,7 +495,7 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.59",
|
"syn",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -528,7 +517,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.59",
|
"syn",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
|
@ -25,6 +25,8 @@ defmodule PhilomenaWeb.ConnCase do
|
||||||
|
|
||||||
# The default endpoint for testing
|
# The default endpoint for testing
|
||||||
@endpoint PhilomenaWeb.Endpoint
|
@endpoint PhilomenaWeb.Endpoint
|
||||||
|
|
||||||
|
use PhilomenaWeb, :verified_routes
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue