Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User find #31

Merged
merged 40 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
fa6bfe5
feat(user-find): initial db query for user find, updated to query by …
akinsey Oct 22, 2024
f11ff6e
feat(user-find-route): implement initial route for user find proxy
akinsey Oct 23, 2024
30a4e19
feat(profile): bring back user id in last post info for linking to pr…
akinsey Oct 24, 2024
ebdb77c
feat(posts-by-username): implement db query for posts by username proxy
akinsey Oct 25, 2024
9c4a64a
Merge remote-tracking branch 'origin/main' into profile
akinsey Oct 28, 2024
bd247d8
feat(post-by-username): route for post by username
akinsey Oct 28, 2024
f141bdf
refactor(post-by-username): remove unneeded error check
akinsey Oct 29, 2024
6f414bc
feat(thread-by-username): initial implementation of thread by usernam…
akinsey Oct 29, 2024
e48300b
Merge remote-tracking branch 'origin/main' into profile
akinsey Oct 29, 2024
bf3d726
yolo(parser): poolboy parser implementation wip
akinsey Oct 31, 2024
b043e7a
fix(bbcode_parser): check for empty string before running bbcode parser
unenglishable Oct 31, 2024
e271bf8
feat(upgrade-elixir): upgrade to latest elixir
akinsey Nov 1, 2024
b3de482
refactor(bbc-parser): clean up bbcode parser gen server
akinsey Nov 1, 2024
e8bddb4
refactor(general): update code syntax for latest elixir updatE
akinsey Nov 1, 2024
163ad43
style(format): run mix format
akinsey Nov 1, 2024
3d18378
fix(user-find): bring back missing user avatar
akinsey Nov 4, 2024
9f94b85
fix(last-post-user-id): bring back last post user id for linking to u…
akinsey Nov 4, 2024
e282db0
fix(proxy-pagination): fix for prev/next style pagination when there …
akinsey Nov 4, 2024
144b3a4
feat(parser): user async parser for signature, code cleanup
akinsey Nov 4, 2024
4a80097
fix(parser): add missing settings that were causing portuguese charac…
akinsey Nov 4, 2024
c0cb6db
feat(credo): upgrade credo to latest
akinsey Nov 4, 2024
7a41e9a
fix(credo): resolve credo issues in bbc parser
akinsey Nov 4, 2024
8cde747
Merge remote-tracking branch 'origin/bbc-parser' into user-find
akinsey Nov 4, 2024
f618c32
feat(last-active): bring back last post date for last active in user …
akinsey Nov 5, 2024
9bace91
refactor(cleanup): use BBCParser Gen Server for parsing user signatur…
akinsey Nov 7, 2024
8af4e0a
feat(gender): calculate gender for user find proxy
akinsey Nov 7, 2024
94157d7
feat(dob): calculate dob for user find proxy
akinsey Nov 7, 2024
a5af549
test(static): resolve dialyzer errors after upgrade of elixir/erlang
akinsey Nov 12, 2024
d8dbf14
feat(user-find): convert gender and dob into human readable format
akinsey Nov 12, 2024
42f7e3d
Merge remote-tracking branch 'origin/main' into user-find
akinsey Nov 12, 2024
e09340f
test(warnings): resolve test warnings
akinsey Nov 12, 2024
b9cefea
feat(last-active): implement last active, respecting flag showOnline …
akinsey Nov 14, 2024
dfd0a30
fix(last-login): use users last login instead of test value, resolve …
akinsey Nov 14, 2024
0068cf4
refactor(user-find): move manipulation of user object into user_json …
akinsey Nov 14, 2024
1bdd8b6
fix(credo): resolve credo error with user_json
akinsey Nov 14, 2024
99ab836
feat(docker): upgrade elixir version in docker file
akinsey Nov 14, 2024
40044b4
refactor(config): poolboy_config -> bbc_parser_poolboy_config
unenglishable Nov 15, 2024
dc41123
refactor(bbc_parser): reduce bbc parser php call timeout to 1 second
unenglishable Nov 15, 2024
d0f1a03
style(application): mix format
unenglishable Nov 15, 2024
393278e
Merge branch 'main' into user-find
unenglishable Nov 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
elixir 1.14.4-otp-25
erlang 25.3.1
elixir 1.17.3-otp-27
erlang 27.1.2
php 8.3.7
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM elixir:1.14.0
FROM elixir:1.17.3
# install php
RUN curl -sSL https://packages.sury.org/php/README.txt | bash -x
RUN apt update
Expand Down
10 changes: 10 additions & 0 deletions config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,16 @@ end

##### PROXY REPO CONFIGURATIONS #####

bbc_parser_poolboy_config = [
name: {:local, :bbc_parser},
worker_module: EpochtalkServer.BBCParser,
size: 5,
max_overflow: 2,
strategy: :fifo
]

config :epochtalk_server, bbc_parser_poolboy_config: bbc_parser_poolboy_config

# conditionally show debug logs in prod
if config_env() == :prod do
logger_level =
Expand Down
5 changes: 5 additions & 0 deletions lib/epochtalk_server/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ defmodule EpochtalkServer.Application do
EpochtalkServer.Repo,
# Start the Smf repository
EpochtalkServer.SmfRepo,
# Start the BBC Parser
:poolboy.child_spec(:bbc_parser, bbc_parser_poolboy_config()),
# Start Role Cache
EpochtalkServer.Cache.Role,
# Warm frontend_config variable (referenced by api controllers)
Expand Down Expand Up @@ -68,4 +70,7 @@ defmodule EpochtalkServer.Application do

# fetch redix config
defp redix_config(), do: Application.get_env(:epochtalk_server, :redix)

defp bbc_parser_poolboy_config,
do: Application.get_env(:epochtalk_server, :bbc_parser_poolboy_config)
end
74 changes: 74 additions & 0 deletions lib/epochtalk_server/bbc_parser.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
defmodule EpochtalkServer.BBCParser do
use GenServer
require Logger
alias Porcelain.Process, as: Proc
@timeout 1_000

@moduledoc """
`BBCParser` genserver, runs interactive php shell to call bbcode parser
"""

## === genserver functions ====

@impl true
def init(:ok), do: {:ok, load()}

@impl true
def handle_call({:parse, ""}, _from, {proc, pid}),
do: {:reply, "", {proc, pid}}

def handle_call({:parse, bbcode_data}, _from, {proc, pid}) when is_binary(bbcode_data) do
Proc.send_input(proc, "echo parse_bbc('#{bbcode_data}');\n")

parsed =
receive do
{^pid, :data, :out, data} ->
Logger.debug(data)
data
end

{:reply, parsed, {proc, pid}}
end

## === parser api functions ====

@doc """
Start genserver and create a reference for supervision tree
"""
def start_link(_opts), do: GenServer.start_link(__MODULE__, :ok)

@doc """
Uses poolboy to call parser
"""
def async_parse(bbcode_data) do
:poolboy.transaction(
:bbc_parser,
fn pid ->
try do
Logger.debug("#{__MODULE__}(ASYNC PARSE): #{inspect(pid)}")
GenServer.call(pid, {:parse, bbcode_data}, @timeout)
catch
e, r ->
Logger.debug("poolboy transaction caught error: #{inspect(e)}, #{inspect(r)}")
:ok
end
end,
@timeout
)
end

## === private functions ====

# returns loaded interactive php shell
defp load() do
proc = %Proc{pid: pid} = Porcelain.spawn_shell("php -a", in: :receive, out: {:send, self()})
Proc.send_input(proc, "require 'parsing.php';\n")
Logger.debug("#{__MODULE__}(LOAD): #{inspect(pid)}")
# clear initial php interactive shell message
receive do
{^pid, :data, :out, data} -> Logger.debug("#{__MODULE__}: #{inspect(data)}")
end

{proc, pid}
end
end
3 changes: 0 additions & 3 deletions lib/epochtalk_server_web/controllers/board.ex
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,6 @@ defmodule EpochtalkServerWeb.Controllers.Board do
400,
"Error, cannot convert slug: board does not exist"
)

_ ->
ErrorHelpers.render_json_error(conn, 400, "Error, cannot convert board slug to id")
end
end

Expand Down
2 changes: 0 additions & 2 deletions lib/epochtalk_server_web/controllers/image_reference.ex
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ defmodule EpochtalkServerWeb.Controllers.ImageReference do
# checksum <- Validate.cast(attrs, "checksum", :string, required: true),
file_type <- Validate.cast(attrs, "file_type", :string, required: true) do
%{length: length, type: file_type}
else
_ -> %{error: "Invalid attrs"}
end
end
end
5 changes: 2 additions & 3 deletions lib/epochtalk_server_web/controllers/mention.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ defmodule EpochtalkServerWeb.Controllers.Mention do
pagination_data: data,
extended: extended
}),
else:
({:auth, nil} ->
ErrorHelpers.render_json_error(conn, 400, "Not logged in, cannot page mentions"))
else: ({:auth, nil} ->
ErrorHelpers.render_json_error(conn, 400, "Not logged in, cannot page mentions"))
end
end
7 changes: 1 addition & 6 deletions lib/epochtalk_server_web/controllers/moderation_log.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ defmodule EpochtalkServerWeb.Controllers.ModerationLog do
@moduledoc """
Controller For `ModerationLog` related API requests
"""
alias EpochtalkServer.Auth.Guardian
alias EpochtalkServer.Models.ModerationLog
alias EpochtalkServerWeb.ErrorHelpers
alias EpochtalkServerWeb.Helpers.Validate
Expand All @@ -14,16 +13,12 @@ defmodule EpochtalkServerWeb.Controllers.ModerationLog do
Used to page `ModerationLog` models for moderation log view`
"""
def page(conn, attrs) do
with {:auth, true} <- {:auth, Guardian.Plug.authenticated?(conn)},
:ok <- ACL.allow!(conn, "moderationLogs.page"),
with :ok <- ACL.allow!(conn, "moderationLogs.page"),
page <- Validate.cast(attrs, "page", :integer, min: 1),
limit <- Validate.cast(attrs, "limit", :integer, min: 1),
{:ok, moderation_logs, data} <- ModerationLog.page(attrs, page, per_page: limit) do
render(conn, :page, %{moderation_logs: moderation_logs, pagination_data: data})
else
{:auth, false} ->
ErrorHelpers.render_json_error(conn, 400, "Not logged in, cannot page moderation log")

{:error, data} ->
ErrorHelpers.render_json_error(conn, 400, data)

Expand Down
33 changes: 6 additions & 27 deletions lib/epochtalk_server_web/controllers/notification.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,16 @@ defmodule EpochtalkServerWeb.Controllers.Notification do
Used to retrieve `Notification` counts for a specific `User`
"""
def counts(conn, attrs) do
with {:auth, %{} = user} <- {:auth, Guardian.Plug.current_resource(conn)},
with user <- Guardian.Plug.current_resource(conn),
:ok <- ACL.allow!(conn, "notifications.counts"),
max <- Validate.cast(attrs, "max", :integer, min: 1) do
render(conn, :counts, data: Notification.counts_by_user_id(user.id, max: max || 99))
else
{:auth, nil} ->
ErrorHelpers.render_json_error(
conn,
400,
"Not logged in, cannot fetch notification counts"
)

{:access, false} ->
_ ->
ErrorHelpers.render_json_error(
conn,
400,
"Not logged in, cannot fetch notification counts"
500,
"Something went wrong, cannot fetch notification counts"
)
end
end
Expand All @@ -39,19 +32,12 @@ defmodule EpochtalkServerWeb.Controllers.Notification do
Used to dismiss `Notification` counts for a specific `User`
"""
def dismiss(conn, %{"id" => id}) do
with {:auth, %{} = user} <- {:auth, Guardian.Plug.current_resource(conn)},
with user <- Guardian.Plug.current_resource(conn),
:ok <- ACL.allow!(conn, "notifications.dismiss"),
{_count, nil} <- Notification.dismiss(id) do
EpochtalkServerWeb.Endpoint.broadcast("user:#{user.id}", "refreshMentions", %{})
render(conn, :dismiss, success: true)
else
{:auth, nil} ->
ErrorHelpers.render_json_error(
conn,
400,
"Not logged in, cannot dismiss notification counts"
)

_ ->
ErrorHelpers.render_json_error(
conn,
Expand All @@ -62,19 +48,12 @@ defmodule EpochtalkServerWeb.Controllers.Notification do
end

def dismiss(conn, %{"type" => type}) do
with {:auth, %{} = user} <- {:auth, Guardian.Plug.current_resource(conn)},
with user <- Guardian.Plug.current_resource(conn),
:ok <- ACL.allow!(conn, "notifications.dismiss"),
{_count, nil} <- Notification.dismiss_type_by_user_id(user.id, type) do
EpochtalkServerWeb.Endpoint.broadcast("user:#{user.id}", "refreshMentions", %{})
render(conn, :dismiss, success: true)
else
{:auth, nil} ->
ErrorHelpers.render_json_error(
conn,
400,
"Not logged in, cannot dismiss notification counts"
)

{:error, :invalid_notification_type} ->
ErrorHelpers.render_json_error(conn, 400, "Cannot dismiss, invalid notification type")

Expand Down
14 changes: 1 addition & 13 deletions lib/epochtalk_server_web/controllers/poll.ex
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,6 @@ defmodule EpochtalkServerWeb.Controllers.Poll do
"Account must be active to modify lock on poll"
)

{:error, data} ->
ErrorHelpers.render_json_error(conn, 400, data)

_ ->
ErrorHelpers.render_json_error(conn, 400, "Error, cannot lock poll")
end
Expand Down Expand Up @@ -316,9 +313,6 @@ defmodule EpochtalkServerWeb.Controllers.Poll do
poll <- Poll.by_thread(thread_id) do
render(conn, :poll, %{poll: poll, has_voted: false})
else
{:valid_answers_list, false} ->
ErrorHelpers.render_json_error(conn, 400, "Error, 'answer_ids' must be a list")

{:can_read, {:ok, false}} ->
ErrorHelpers.render_json_error(
conn,
Expand Down Expand Up @@ -355,14 +349,8 @@ defmodule EpochtalkServerWeb.Controllers.Poll do
{:board_banned, {:ok, true}} ->
ErrorHelpers.render_json_error(conn, 403, "Unauthorized, you are banned from this board")

{:error, :board_does_not_exist} ->
ErrorHelpers.render_json_error(conn, 400, "Error, board does not exist")

{:error, data} ->
ErrorHelpers.render_json_error(conn, 400, data)

_ ->
ErrorHelpers.render_json_error(conn, 400, "Error, cannot cast vote")
ErrorHelpers.render_json_error(conn, 400, "Error, cannot delete vote")
end
end

Expand Down
31 changes: 27 additions & 4 deletions lib/epochtalk_server_web/controllers/post.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ defmodule EpochtalkServerWeb.Controllers.Post do

@max_post_title_length 255

plug :check_proxy when action in [:by_thread]
plug :check_proxy when action in [:by_thread, :by_username]

@doc """
Used to create posts
Expand Down Expand Up @@ -420,9 +420,6 @@ defmodule EpochtalkServerWeb.Controllers.Post do
Validate.cast(attrs, "body", :string, required: true, max: post_max_length, min: 1),
parsed_body <- Parse.markdown(body) do
render(conn, :preview, %{parsed_body: parsed_body})
else
_ ->
ErrorHelpers.render_json_error(conn, 400, "Error, cannot generate preview")
end
end

Expand Down Expand Up @@ -542,13 +539,39 @@ defmodule EpochtalkServerWeb.Controllers.Post do
conn
end

:by_username ->
conn
|> proxy_by_username(conn.params)
|> halt()

_ ->
conn
end

conn
end

defp proxy_by_username(conn, attrs) do
# Parameter Validation
with user_id <- Validate.cast(attrs, "id", :integer, required: true),
page <- Validate.cast(attrs, "page", :integer, default: 1, min: 1),
limit <- Validate.cast(attrs, "limit", :integer, default: 25, min: 1, max: 100),
desc <- Validate.cast(attrs, "desc", :boolean, default: true),
{:ok, posts, data} <-
ProxyConversion.build_model("posts.by_user", user_id, page, limit, desc) do
render(conn, :proxy_by_username, %{
posts: posts,
count: data.total_records,
limit: data.per_page,
page: data.page,
desc: desc
})
else
_ ->
ErrorHelpers.render_json_error(conn, 400, "Error, cannot get posts by username")
end
end

defp proxy_by_thread(conn, attrs) do
with thread_id <- Validate.cast(attrs, "thread_id", :integer, required: true),
page <- Validate.cast(attrs, "page", :integer, default: 1),
Expand Down
9 changes: 6 additions & 3 deletions lib/epochtalk_server_web/controllers/preference.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ defmodule EpochtalkServerWeb.Controllers.Preference do
def preferences(conn, _attrs) do
with {:auth, %{} = user} <- {:auth, Guardian.Plug.current_resource(conn)},
do: render(conn, :preferences, preferences: Preference.by_user_id(user.id)),
else:
({:auth, nil} ->
ErrorHelpers.render_json_error(conn, 400, "Not logged in, cannot fetch preferences"))
else: ({:auth, nil} ->
ErrorHelpers.render_json_error(
conn,
400,
"Not logged in, cannot fetch preferences"
))
end
end
Loading
Loading