slightly changed how files are stored in the bucket and allows post deletion
This commit is contained in:
@@ -11,6 +11,10 @@ defmodule Mixer.Posts.Media do
|
|||||||
postgres do
|
postgres do
|
||||||
table "media"
|
table "media"
|
||||||
repo Mixer.Repo
|
repo Mixer.Repo
|
||||||
|
|
||||||
|
references do
|
||||||
|
reference :tweet, on_delete: :delete
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
typescript do
|
typescript do
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ defmodule Mixer.Posts.MediaUploader do
|
|||||||
if ext in @extensions, do: :ok, else: {:error, "unsupported file type #{ext}"}
|
if ext in @extensions, do: :ok, else: {:error, "unsupported file type #{ext}"}
|
||||||
end
|
end
|
||||||
|
|
||||||
def storage_dir(_version, {_file, scope}), do: "uploads/media/#{scope.id}"
|
def storage_dir(_version, {_file, scope}), do: "uploads/media/#{scope.user_id}/#{scope.media_id}"
|
||||||
|
|
||||||
def filename(_version, {file, _scope}) do
|
def filename(_version, {file, _scope}) do
|
||||||
Path.basename(file.file_name, Path.extname(file.file_name))
|
Path.basename(file.file_name, Path.extname(file.file_name))
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ defmodule Mixer.Posts.TweetLike do
|
|||||||
postgres do
|
postgres do
|
||||||
table "tweet_likes"
|
table "tweet_likes"
|
||||||
repo Mixer.Repo
|
repo Mixer.Repo
|
||||||
|
|
||||||
|
references do
|
||||||
|
reference :tweet, on_delete: :delete
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
actions do
|
actions do
|
||||||
|
|||||||
@@ -11,15 +11,17 @@ defmodule MixerWeb.UploadController do
|
|||||||
|> put_status(:unauthorized)
|
|> put_status(:unauthorized)
|
||||||
|> json(%{error: "authentication required"})
|
|> json(%{error: "authentication required"})
|
||||||
else
|
else
|
||||||
scope = %{id: Ash.UUID.generate()}
|
media_id = Ash.UUID.generate()
|
||||||
|
scope = %{user_id: actor.id, media_id: media_id}
|
||||||
|
|
||||||
case MediaUploader.store({upload, scope}) do
|
case MediaUploader.store({upload, scope}) do
|
||||||
{:ok, file_name} ->
|
{:ok, file_name} ->
|
||||||
s3_key = "uploads/media/#{scope.id}/#{file_name}"
|
s3_key = "uploads/media/#{scope.user_id}/#{scope.media_id}/#{file_name}"
|
||||||
url = MediaUploader.url({file_name, scope})
|
url = MediaUploader.url({file_name, scope})
|
||||||
|
|
||||||
Mixer.Posts.Media
|
Mixer.Posts.Media
|
||||||
|> Ash.Changeset.for_create(:upload, %{s3_key: s3_key}, actor: actor)
|
|> Ash.Changeset.for_create(:upload, %{s3_key: s3_key}, actor: actor)
|
||||||
|
|> Ash.Changeset.force_change_attribute(:id, media_id)
|
||||||
|> Ash.create()
|
|> Ash.create()
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, media} ->
|
{:ok, media} ->
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
defmodule Mixer.Repo.Migrations.CascadeDeleteTweetRelations do
|
||||||
|
@moduledoc """
|
||||||
|
Updates resources based on their most recent snapshots.
|
||||||
|
|
||||||
|
This file was autogenerated with `mix ash_postgres.generate_migrations`
|
||||||
|
"""
|
||||||
|
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
drop constraint(:tweet_likes, "tweet_likes_tweet_id_fkey")
|
||||||
|
|
||||||
|
alter table(:tweet_likes) do
|
||||||
|
modify :tweet_id,
|
||||||
|
references(:tweets,
|
||||||
|
column: :id,
|
||||||
|
name: "tweet_likes_tweet_id_fkey",
|
||||||
|
type: :uuid,
|
||||||
|
prefix: "public",
|
||||||
|
on_delete: :delete_all
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
drop constraint(:media, "media_tweet_id_fkey")
|
||||||
|
|
||||||
|
alter table(:media) do
|
||||||
|
modify :tweet_id,
|
||||||
|
references(:tweets,
|
||||||
|
column: :id,
|
||||||
|
name: "media_tweet_id_fkey",
|
||||||
|
type: :uuid,
|
||||||
|
prefix: "public",
|
||||||
|
on_delete: :delete_all
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
drop constraint(:media, "media_tweet_id_fkey")
|
||||||
|
|
||||||
|
alter table(:media) do
|
||||||
|
modify :tweet_id,
|
||||||
|
references(:tweets,
|
||||||
|
column: :id,
|
||||||
|
name: "media_tweet_id_fkey",
|
||||||
|
type: :uuid,
|
||||||
|
prefix: "public"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
drop constraint(:tweet_likes, "tweet_likes_tweet_id_fkey")
|
||||||
|
|
||||||
|
alter table(:tweet_likes) do
|
||||||
|
modify :tweet_id,
|
||||||
|
references(:tweets,
|
||||||
|
column: :id,
|
||||||
|
name: "tweet_likes_tweet_id_fkey",
|
||||||
|
type: :uuid,
|
||||||
|
prefix: "public"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
106
priv/resource_snapshots/repo/media/20260331210905.json
Normal file
106
priv/resource_snapshots/repo/media/20260331210905.json
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "fragment(\"gen_random_uuid()\")",
|
||||||
|
"generated?": false,
|
||||||
|
"precision": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"references": null,
|
||||||
|
"scale": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "id",
|
||||||
|
"type": "uuid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"precision": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": null,
|
||||||
|
"scale": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "s3_key",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"precision": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": {
|
||||||
|
"deferrable": false,
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"index?": false,
|
||||||
|
"match_type": null,
|
||||||
|
"match_with": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"attribute": null,
|
||||||
|
"global": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"name": "media_user_id_fkey",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"schema": "public",
|
||||||
|
"table": "users"
|
||||||
|
},
|
||||||
|
"scale": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "user_id",
|
||||||
|
"type": "uuid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": true,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"precision": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": {
|
||||||
|
"deferrable": false,
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"index?": false,
|
||||||
|
"match_type": null,
|
||||||
|
"match_with": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"attribute": null,
|
||||||
|
"global": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"name": "media_tweet_id_fkey",
|
||||||
|
"on_delete": "delete",
|
||||||
|
"on_update": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"schema": "public",
|
||||||
|
"table": "tweets"
|
||||||
|
},
|
||||||
|
"scale": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "tweet_id",
|
||||||
|
"type": "uuid"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"base_filter": null,
|
||||||
|
"check_constraints": [],
|
||||||
|
"create_table_options": null,
|
||||||
|
"custom_indexes": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true,
|
||||||
|
"hash": "B9772141860212686745F81D509EBD97BACB9A5A4E7C26A0EB924D6926D1827E",
|
||||||
|
"identities": [],
|
||||||
|
"multitenancy": {
|
||||||
|
"attribute": null,
|
||||||
|
"global": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"repo": "Elixir.Mixer.Repo",
|
||||||
|
"schema": null,
|
||||||
|
"table": "media"
|
||||||
|
}
|
||||||
113
priv/resource_snapshots/repo/tweet_likes/20260331210906.json
Normal file
113
priv/resource_snapshots/repo/tweet_likes/20260331210906.json
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "fragment(\"gen_random_uuid()\")",
|
||||||
|
"generated?": false,
|
||||||
|
"precision": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"references": null,
|
||||||
|
"scale": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "id",
|
||||||
|
"type": "uuid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"precision": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": {
|
||||||
|
"deferrable": false,
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"index?": false,
|
||||||
|
"match_type": null,
|
||||||
|
"match_with": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"attribute": null,
|
||||||
|
"global": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"name": "tweet_likes_tweet_id_fkey",
|
||||||
|
"on_delete": "delete",
|
||||||
|
"on_update": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"schema": "public",
|
||||||
|
"table": "tweets"
|
||||||
|
},
|
||||||
|
"scale": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "tweet_id",
|
||||||
|
"type": "uuid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_nil?": false,
|
||||||
|
"default": "nil",
|
||||||
|
"generated?": false,
|
||||||
|
"precision": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"references": {
|
||||||
|
"deferrable": false,
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"index?": false,
|
||||||
|
"match_type": null,
|
||||||
|
"match_with": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"attribute": null,
|
||||||
|
"global": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"name": "tweet_likes_user_id_fkey",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"schema": "public",
|
||||||
|
"table": "users"
|
||||||
|
},
|
||||||
|
"scale": null,
|
||||||
|
"size": null,
|
||||||
|
"source": "user_id",
|
||||||
|
"type": "uuid"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"base_filter": null,
|
||||||
|
"check_constraints": [],
|
||||||
|
"create_table_options": null,
|
||||||
|
"custom_indexes": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true,
|
||||||
|
"hash": "A5479A2259477E7040C393810B5805794903152376377FA38E92C119C4947108",
|
||||||
|
"identities": [
|
||||||
|
{
|
||||||
|
"all_tenants?": false,
|
||||||
|
"base_filter": null,
|
||||||
|
"index_name": "tweet_likes_unique_user_tweet_index",
|
||||||
|
"keys": [
|
||||||
|
{
|
||||||
|
"type": "atom",
|
||||||
|
"value": "tweet_id"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "atom",
|
||||||
|
"value": "user_id"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "unique_user_tweet",
|
||||||
|
"nils_distinct?": true,
|
||||||
|
"where": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"multitenancy": {
|
||||||
|
"attribute": null,
|
||||||
|
"global": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"repo": "Elixir.Mixer.Repo",
|
||||||
|
"schema": null,
|
||||||
|
"table": "tweet_likes"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user