some ai generated code from claude that does not work
This commit is contained in:
@@ -4,6 +4,7 @@ defmodule Mixer.Accounts do
|
||||
typescript_rpc do
|
||||
resource Mixer.Accounts.User do
|
||||
rpc_action :read_user, :read
|
||||
rpc_action :update_profile, :update_profile
|
||||
end
|
||||
|
||||
resource Mixer.Accounts.Follow do
|
||||
|
||||
33
lib/mixer/accounts/avatar_uploader.ex
Normal file
33
lib/mixer/accounts/avatar_uploader.ex
Normal file
@@ -0,0 +1,33 @@
|
||||
defmodule Mixer.Accounts.AvatarUploader do
|
||||
use Waffle.Definition
|
||||
|
||||
@versions [:original, :thumb]
|
||||
@extensions ~w(.jpg .jpeg .png .gif .webp)
|
||||
|
||||
def validate({file, _scope}) do
|
||||
ext = file.file_name |> Path.extname() |> String.downcase()
|
||||
if ext in @extensions, do: :ok, else: {:error, "unsupported file type #{ext}"}
|
||||
end
|
||||
|
||||
# Resize to a 256×256 square (centre-crop) and convert to WebP for efficiency
|
||||
def transform(:thumb, _) do
|
||||
{:convert, "-strip -thumbnail 256x256^ -gravity center -extent 256x256 -format webp", :webp}
|
||||
end
|
||||
|
||||
# Store both versions under avatars/:user_id/
|
||||
def storage_dir(_version, {_file, scope}), do: "avatars/#{scope.user_id}"
|
||||
|
||||
def filename(:original, {file, _scope}) do
|
||||
Path.basename(file.file_name, Path.extname(file.file_name))
|
||||
end
|
||||
|
||||
def filename(:thumb, _), do: "thumb"
|
||||
|
||||
def s3_object_headers(:thumb, _), do: [content_type: "image/webp"]
|
||||
|
||||
def s3_object_headers(_version, {file, _scope}) do
|
||||
[content_type: MIME.from_path(file.file_name)]
|
||||
end
|
||||
|
||||
def acl(_version, _), do: :public_read
|
||||
end
|
||||
@@ -177,9 +177,21 @@ defmodule Mixer.Accounts.User do
|
||||
sensitive? true
|
||||
end
|
||||
|
||||
argument :username, :string do
|
||||
description "The desired username for the user (letters, numbers, underscores)."
|
||||
allow_nil? false
|
||||
|
||||
constraints match: ~r/^[a-zA-Z0-9_]+$/,
|
||||
min_length: 3,
|
||||
max_length: 30
|
||||
end
|
||||
|
||||
# Sets the email from the argument
|
||||
change set_attribute(:email, arg(:email))
|
||||
|
||||
# Sets the username from the argument
|
||||
change set_attribute(:username, arg(:username))
|
||||
|
||||
# Hashes the provided password
|
||||
change AshAuthentication.Strategy.Password.HashPasswordChange
|
||||
|
||||
@@ -211,6 +223,18 @@ defmodule Mixer.Accounts.User do
|
||||
get_by :email
|
||||
end
|
||||
|
||||
update :update_profile do
|
||||
description "Update the user's public profile (username, display name)."
|
||||
accept [:username, :display_name]
|
||||
require_atomic? false
|
||||
end
|
||||
|
||||
update :update_avatar do
|
||||
description "Store the S3 key of the user's processed avatar thumbnail."
|
||||
accept [:avatar_url]
|
||||
require_atomic? false
|
||||
end
|
||||
|
||||
update :reset_password_with_token do
|
||||
argument :reset_token, :string do
|
||||
allow_nil? false
|
||||
@@ -256,6 +280,15 @@ defmodule Mixer.Accounts.User do
|
||||
allow_nil? true
|
||||
end
|
||||
|
||||
argument :username, :string do
|
||||
description "Username chosen during first-time magic link registration."
|
||||
allow_nil? true
|
||||
|
||||
constraints match: ~r/^[a-zA-Z0-9_]+$/,
|
||||
min_length: 3,
|
||||
max_length: 30
|
||||
end
|
||||
|
||||
upsert? true
|
||||
upsert_identity :unique_email
|
||||
upsert_fields [:email]
|
||||
@@ -266,6 +299,32 @@ defmodule Mixer.Accounts.User do
|
||||
change {AshAuthentication.Strategy.RememberMe.MaybeGenerateTokenChange,
|
||||
strategy_name: :remember_me}
|
||||
|
||||
# Set username on new users (or existing users who haven't set one yet)
|
||||
change fn changeset, _ctx ->
|
||||
case Ash.Changeset.get_argument(changeset, :username) do
|
||||
nil ->
|
||||
changeset
|
||||
|
||||
username ->
|
||||
Ash.Changeset.after_action(changeset, fn _cs, user ->
|
||||
if is_nil(user.username) do
|
||||
user
|
||||
|> Ash.Changeset.for_update(:update_profile, %{username: username},
|
||||
authorize?: false
|
||||
)
|
||||
|> Ash.update()
|
||||
|> case do
|
||||
{:ok, updated} -> {:ok, updated}
|
||||
# Don't fail the sign-in just because username set failed
|
||||
{:error, _} -> {:ok, user}
|
||||
end
|
||||
else
|
||||
{:ok, user}
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
metadata :token, :string do
|
||||
allow_nil? false
|
||||
end
|
||||
@@ -293,6 +352,14 @@ defmodule Mixer.Accounts.User do
|
||||
policy action_type(:read) do
|
||||
authorize_if always()
|
||||
end
|
||||
|
||||
policy action(:update_profile) do
|
||||
authorize_if expr(id == ^actor(:id))
|
||||
end
|
||||
|
||||
policy action(:update_avatar) do
|
||||
authorize_if expr(id == ^actor(:id))
|
||||
end
|
||||
end
|
||||
|
||||
attributes do
|
||||
@@ -308,6 +375,23 @@ defmodule Mixer.Accounts.User do
|
||||
end
|
||||
|
||||
attribute :confirmed_at, :utc_datetime_usec
|
||||
|
||||
attribute :username, :string do
|
||||
public? true
|
||||
|
||||
constraints match: ~r/^[a-zA-Z0-9_]+$/,
|
||||
min_length: 3,
|
||||
max_length: 30
|
||||
end
|
||||
|
||||
attribute :display_name, :string do
|
||||
public? true
|
||||
constraints max_length: 50
|
||||
end
|
||||
|
||||
attribute :avatar_url, :string do
|
||||
public? true
|
||||
end
|
||||
end
|
||||
|
||||
relationships do
|
||||
@@ -350,5 +434,6 @@ defmodule Mixer.Accounts.User do
|
||||
|
||||
identities do
|
||||
identity :unique_email, [:email]
|
||||
identity :unique_username, [:username], nils_distinct?: true
|
||||
end
|
||||
end
|
||||
|
||||
@@ -254,6 +254,18 @@ defmodule Mixer.Posts.Tweet do
|
||||
calculate :user_email, :string, expr(user.email) do
|
||||
public? true
|
||||
end
|
||||
|
||||
calculate :user_username, :string, expr(user.username) do
|
||||
public? true
|
||||
end
|
||||
|
||||
calculate :user_display_name, :string, expr(user.display_name) do
|
||||
public? true
|
||||
end
|
||||
|
||||
calculate :user_avatar_url, :string, expr(user.avatar_url) do
|
||||
public? true
|
||||
end
|
||||
end
|
||||
|
||||
aggregates do
|
||||
|
||||
Reference in New Issue
Block a user