From 3f199a86fe6b417debbb627424e61e218fc9a120 Mon Sep 17 00:00:00 2001 From: CJ_Clippy <cj@futureporn.net> Date: Mon, 17 Mar 2025 15:30:16 -0800 Subject: [PATCH] x_posts tests are passing --- apps/bright/lib/bright/platforms.ex | 11 +- apps/bright/lib/bright/platforms/platform.ex | 4 +- .../lib/bright/platforms/platform_alias.ex | 4 +- apps/bright/lib/bright/socials/x_post.ex | 43 +- .../test/bright/socials/x_post_test.exs | 468 +++++++++--------- .../support/fixtures/platforms_fixtures.ex | 6 +- .../test/support/fixtures/x_posts_fixtures.ex | 166 ++++--- terraform/main.tf | 162 +++--- 8 files changed, 474 insertions(+), 390 deletions(-) diff --git a/apps/bright/lib/bright/platforms.ex b/apps/bright/lib/bright/platforms.ex index f16d9d0..3f842b1 100644 --- a/apps/bright/lib/bright/platforms.ex +++ b/apps/bright/lib/bright/platforms.ex @@ -122,13 +122,22 @@ defmodule Bright.Platforms do """ def create_platform_alias(attrs \\ %{}) do + IO.inspect(attrs, label: "PlatformAlias Attributes Before Insert") + %PlatformAlias{} |> PlatformAlias.changeset(attrs) |> Repo.insert() end def match_platform?(a, b) do - URI.parse(a.url).host === URI.parse(b.url).host + host_a = URI.parse(a.url).host + host_b = URI.parse(b.url).host + + Logger.debug( + "🚨 Comparing hosts: #{inspect(host_a)} vs #{inspect(host_b)} (#{host_a === host_b})" + ) + + host_a === host_b end @doc """ diff --git a/apps/bright/lib/bright/platforms/platform.ex b/apps/bright/lib/bright/platforms/platform.ex index ec2aa62..c859092 100644 --- a/apps/bright/lib/bright/platforms/platform.ex +++ b/apps/bright/lib/bright/platforms/platform.ex @@ -16,8 +16,8 @@ defmodule Bright.Platforms.Platform do @doc false def changeset(platform, attrs) do platform - |> cast(attrs, [:name, :url, :slug]) - |> validate_required([:name, :url, :slug]) + |> cast(attrs, [:name, :url, :slug, :nsfw]) + |> validate_required([:name, :url, :slug, :nsfw]) |> unique_constraint(:name) end end diff --git a/apps/bright/lib/bright/platforms/platform_alias.ex b/apps/bright/lib/bright/platforms/platform_alias.ex index dab0301..052035a 100644 --- a/apps/bright/lib/bright/platforms/platform_alias.ex +++ b/apps/bright/lib/bright/platforms/platform_alias.ex @@ -12,7 +12,7 @@ defmodule Bright.Platforms.PlatformAlias do @doc false def changeset(platform_alias, attrs) do platform_alias - |> cast(attrs, [:url]) - |> validate_required([:url]) + |> cast(attrs, [:url, :platform_id]) + |> validate_required([:url, :platform_id]) end end diff --git a/apps/bright/lib/bright/socials/x_post.ex b/apps/bright/lib/bright/socials/x_post.ex index 4c4401b..1b8b95a 100644 --- a/apps/bright/lib/bright/socials/x_post.ex +++ b/apps/bright/lib/bright/socials/x_post.ex @@ -116,6 +116,12 @@ defmodule Bright.Socials.XPost do %Platform{url: url, platform_aliases: %Ecto.Association.NotLoaded{}} = platform ) do platform = Repo.preload(platform, :platform_aliases) + + Logger.debug( + "include_platform? called with a platform that doesnt have platform_aliases preloaded, so we will preload for them." + ) + + Logger.debug(inspect(platform)) includes_platform?(raw_text, platform) end @@ -124,18 +130,17 @@ defmodule Bright.Socials.XPost do end def includes_platform?(raw_text, %Platform{url: url, platform_aliases: aliases}) do - host = URI.parse(url).host + platform_host = URI.parse(url).host Logger.debug( "includes_platform? with raw_text=#{inspect(raw_text)} and aliases=#{inspect(aliases)}" ) - aliases = + aliases_hosts = aliases - # Assuming platform_aliases have an `alias` field. - |> Enum.map(& &1.alias) + |> Enum.map(&URI.parse(&1.url).host) - values_to_match = [host | aliases] + values_to_match = [platform_host | aliases_hosts] Enum.any?(values_to_match, fn value -> String.contains?(raw_text, value) @@ -145,9 +150,29 @@ defmodule Bright.Socials.XPost do def includes_platform?(_, _), do: false def get_platforms_mentioned(raw_text, platforms) do + Logger.debug( + "get_platforms_mentioned with raw_text=#{inspect(raw_text)} platforms=#{inspect(platforms)}" + ) + Enum.filter(platforms, &includes_platform?(raw_text, &1)) end + # def platform_alias_mentioned?(%XPost{id: xpost_id}) do + # xpost = Repo.get(XPost, xpost_id) + + # if xpost do + # aliases = + # from(pa in PlatformAlias, select: pa.url) + # |> Repo.all() + + # Enum.any?(aliases, fn alias -> + # String.contains?(xpost.raw, alias) + # end) + # else + # false + # end + # end + def parse(%XPost{} = post) do known_platforms = Platforms.list_platforms() parse(post, known_platforms) @@ -181,15 +206,19 @@ defmodule Bright.Socials.XPost do ) do mentioned_platforms = get_platforms_mentioned(post, known_platforms) Logger.debug("Checking if post is NSFW live announcement: #{inspect(post)}") + Logger.debug("🐉 known_platforms: #{inspect(known_platforms)}") nsfw_platforms = Enum.filter(known_platforms, & &1.nsfw) sfw_platforms = Enum.reject(known_platforms, & &1.nsfw) + Logger.debug("🐉 Mentioned platforms: #{inspect(mentioned_platforms)}") + Logger.debug("🐉 NSFW platforms: #{inspect(nsfw_platforms)}") + conditions = [ {:is_not_rt, XPost.authored_by_vtuber?(post, vtuber)}, {:is_not_vod, not String.contains?(String.downcase(post.raw), "vod")}, - {:is_nsfw_platform, Platforms.contains_platform?(mentioned_platforms, nsfw_platforms)}, - {:is_not_sfw_platform, not Platforms.contains_platform?(mentioned_platforms, sfw_platforms)} + {:is_nsfw_platform, Platforms.contains_platform?(nsfw_platforms, mentioned_platforms)}, + {:is_no_sfw_platform, not Platforms.contains_platform?(mentioned_platforms, sfw_platforms)} ] Enum.reduce_while(conditions, true, fn {label, condition}, _acc -> diff --git a/apps/bright/test/bright/socials/x_post_test.exs b/apps/bright/test/bright/socials/x_post_test.exs index 050f5ea..ad405ce 100644 --- a/apps/bright/test/bright/socials/x_post_test.exs +++ b/apps/bright/test/bright/socials/x_post_test.exs @@ -120,7 +120,8 @@ defmodule Bright.XPostTest do post = SocialsFixtures.x_post_fixture(%{ - raw: "check me out LIVE at https://chaturbate.com/projektmelody", + raw: + "check me out LIVE at https://chaturbate.com/projektmelody https://fansly.com/projektmelody https://onlyfans.com/projektmelody", vtuber_id: vtuber.id }) |> Repo.preload(:vtuber) @@ -137,78 +138,87 @@ defmodule Bright.XPostTest do assert is_live end + @tag :taco test "get platforms_mentioned", %{ known_platforms: known_platforms, + vtuber: vtuber, post: post } do %{platforms_mentioned: platforms_mentioned} = XPost.parse(post, known_platforms) - assert length(platforms_mentioned) > 3 + assert length(platforms_mentioned) === 3 end end - describe "includes_alias?/2" do - setup do - {:ok, ytmnd} = - Platforms.create_platform(%{ - name: "You're The Man Now Dog", - slug: "ytmnd", - url: "https://blueballfixed.ytmnd.com", - nsfw: false - }) + # describe "platform_alias_mentioned?/1" do + # setup do + # {:ok, ytmnd} = + # Platforms.create_platform(%{ + # name: "You're The Man Now Dog", + # slug: "ytmnd", + # url: "https://blueballfixed.ytmnd.com", + # nsfw: false + # }) - Platforms.create_platform_alias(%{url: "https://shorturl.at/lZ3NM", platform_id: ytmnd.id}) + # Platforms.create_platform_alias(%{url: "https://shorturl.at/lZ3NM", platform_id: ytmnd.id}) - Platforms.create_platform(%{ - name: "Twitch", - slug: "twitch", - url: "https://twitch.tv", - nsfw: false - }) + # Platforms.create_platform(%{ + # name: "Twitch", + # slug: "twitch", + # url: "https://twitch.tv", + # nsfw: false + # }) - :ok - end + # :ok + # end - @tag :unit - test "returns true when a platform alias url is found in XPost raw content" do - platform = Platform |> Repo.get_by!(slug: "ytmnd") |> Repo.preload(:platform_aliases) - x_post = %XPost{raw: "Hello World please join my stream rn https://shorturl.at/lZ3NM"} - assert XPost.includes_alias?(x_post, platform) - end + # @tag :unit + # test "returns true when a platform alias url is found in XPost raw content" do + # platform = Platform |> Repo.get_by!(slug: "ytmnd") |> Repo.preload(:platform_aliases) + # x_post = %XPost{raw: "Hello World please join my stream rn https://shorturl.at/lZ3NM"} + # assert XPost.platform_alias_mentioned?(x_post) + # end - @tag :unit - test "returns false when no platform alias url is present in XPost raw content" do - platform = Platform |> Repo.get_by!(slug: "ytmnd") |> Repo.preload(:platform_aliases) - x_post = %XPost{raw: "i just ate breakfast and then i went outside it was gret"} - assert not XPost.includes_alias?(x_post, platform) - end + # @tag :unit + # test "returns false when no platform alias url is present in XPost raw content" do + # platform = Platform |> Repo.get_by!(slug: "ytmnd") |> Repo.preload(:platform_aliases) + # x_post = %XPost{raw: "i just ate breakfast and then i went outside it was gret"} + # assert not XPost.platform_alias_mentioned?(x_post) + # end - @tag :unit - test "returns true when a platform alias url is found in raw_text" do - platform = Platform |> Repo.get_by!(slug: "ytmnd") |> Repo.preload(:platform_aliases) - raw_text = "GOING LIVE NOW shorturl.at/lZ3NM" - assert XPost.includes_alias?(raw_text, platform) - end + # @tag :unit + # test "returns true when a platform alias url is found in raw_text" do + # platform = Platform |> Repo.get_by!(slug: "ytmnd") |> Repo.preload(:platform_aliases) + # raw_text = "GOING LIVE NOW shorturl.at/lZ3NM" + # assert XPost.platform_alias_mentioned?(raw_text) + # end - @tag :unit - test "returns false when no platform alias url is present in raw_text" do - platform = Platform |> Repo.get_by!(slug: "ytmnd") |> Repo.preload(:platform_aliases) - raw_text = "#420 #blazeit #bbq #LuL" - assert not XPost.includes_alias?(raw_text, platform) - end - end + # @tag :unit + # test "returns false when no platform alias url is present in raw_text" do + # platform = Platform |> Repo.get_by!(slug: "ytmnd") |> Repo.preload(:platform_aliases) + # raw_text = "#420 #blazeit #bbq #LuL" + # assert not XPost.platform_alias_mentioned?(raw_text) + # end + # end describe "includes_platform?" do setup do - %Platform{ + %{ name: "Chaturbate", slug: "chaturbate", url: "https://chaturbate.com", nsfw: true } - |> Repo.insert!() + |> Platforms.create_platform() - %Platform{name: "Twitch", slug: "twitch", url: "https://twitch.tv", nsfw: false} - |> Repo.insert!() + %{name: "Twitch", slug: "twitch", url: "https://twitch.tv", nsfw: false} + |> Platforms.create_platform() + + {:ok, fansly} = + %{name: "Fansly", slug: "fansly", url: "https://fansly.com", nsfw: true} + |> Platforms.create_platform() + + %{url: "https://melody.buzz", platform_id: fansly.id} + |> Platforms.create_platform_alias() :ok end @@ -227,6 +237,20 @@ defmodule Bright.XPostTest do XPost.includes_platform?(raw_text, platform) end + @tag :unit + test "includes_platform? matches associated PlatformAlias" do + raw_text = "hello world check out my stream: http://melody.buzz" + + platforms = Platform |> Repo.all() + + platform = + Platform + |> Repo.get_by!(slug: "fansly") + |> Repo.preload(:platform_aliases) + + XPost.includes_platform?(raw_text, platform) + end + @tag :unit test "includes_platform? with x_post" do x_post = %XPost{raw: "LIVE NOW https://chaturbate.com"} @@ -243,20 +267,23 @@ defmodule Bright.XPostTest do describe "get_platforms_mentioned" do setup %{} do known_platforms = PlatformsFixtures.known_platforms_fixture() + known_platforms = Repo.preload(known_platforms, :platform_aliases) + vtuber = VtubersFixtures.projektmelody_fixture() - {:ok, known_platforms: known_platforms} + idk = Repo.all(PlatformAlias) + + {:ok, known_platforms: known_platforms, vtuber: vtuber} end @tag :unit - @tag :taco - test "post with no links" do + test "post with no links", %{vtuber: vtuber} do platforms = Platforms.list_platforms() expected_platform_names = [] actual_platform_names = XPost.get_platforms_mentioned( - XPostsFixtures.fixture_offline_1() |> Map.get(:raw), + XPostsFixtures.fixture_offline_1(%{vtuber_id: vtuber.id}) |> Map.get(:raw), platforms ) # Extract only names @@ -266,98 +293,12 @@ defmodule Bright.XPostTest do end @tag :unit - test "post with non-invite links" do - platforms = Platforms.list_platforms() - - expected_platform_names = [] + test "post with non-invite links", %{known_platforms: known_platforms, vtuber: vtuber} do + expected_platform_names = ["Linktree"] actual_platform_names = XPost.get_platforms_mentioned( - XPostsFixtures.fixture_offline_2() |> Map.get(:raw), - platforms - ) - # Extract only names - |> Enum.map(& &1.name) - - assert Enum.sort(actual_platform_names) == Enum.sort(expected_platform_names) - end - - @tag :unit - test "post with only SFW invite links" do - platforms = Platforms.list_platforms() - - expected_platform_names = ["Fansly", "Twitch"] - - actual_platform_names = - XPost.get_platforms_mentioned( - XPostsFixtures.fixture_offline_3() |> Map.get(:raw), - platforms - ) - # Extract only names - |> Enum.map(& &1.name) - - assert Enum.sort(actual_platform_names) == Enum.sort(expected_platform_names) - end - - @tag :unit - test "another post with only SFW invite links" do - platforms = Platforms.list_platforms() - - expected_platform_names = ["Fansly", "Twitch"] - - actual_platform_names = - XPost.get_platforms_mentioned( - XPostsFixtures.fixture_offline_4() |> Map.get(:raw), - platforms - ) - # Extract only names - |> Enum.map(& &1.name) - - assert Enum.sort(actual_platform_names) == Enum.sort(expected_platform_names) - end - - @tag :unit - test "post with 3 platform invites 1" do - platforms = Platforms.list_platforms() - - expected_platform_names = ["Fansly", "OnlyFans", "Chaturbate"] - - actual_platform_names = - XPost.get_platforms_mentioned( - XPostsFixtures.fixture_live_1() |> Map.get(:raw), - platforms - ) - # Extract only names - |> Enum.map(& &1.name) - - assert Enum.sort(actual_platform_names) == Enum.sort(expected_platform_names) - end - - @tag :unit - test "post with 3 platform invites 2" do - platforms = Platforms.list_platforms() - - expected_platform_names = ["Fansly", "OnlyFans", "Chaturbate"] - - actual_platform_names = - XPost.get_platforms_mentioned( - XPostsFixtures.fixture_live_2() |> Map.get(:raw), - platforms - ) - # Extract only names - |> Enum.map(& &1.name) - - assert Enum.sort(actual_platform_names) == Enum.sort(expected_platform_names) - end - - @tag :unit - @tag :taco - test "post with 3 platform invites 3", %{known_platforms: known_platforms} do - expected_platform_names = ["Fansly", "OnlyFans", "Chaturbate"] - - actual_platform_names = - XPost.get_platforms_mentioned( - XPostsFixtures.fixture_live_3() |> Map.get(:raw), + XPostsFixtures.fixture_offline_2(%{vtuber_id: vtuber.id}) |> Map.get(:raw), known_platforms ) # Extract only names @@ -367,12 +308,92 @@ defmodule Bright.XPostTest do end @tag :unit - test "post with a platform alias", %{known_platforms: known_platforms} do + test "post with only SFW invite links", %{known_platforms: known_platforms, vtuber: vtuber} do + expected_platform_names = ["Fansly", "Twitch"] + + actual_platform_names = + XPost.get_platforms_mentioned( + XPostsFixtures.fixture_offline_3(%{vtuber_id: vtuber.id}) |> Map.get(:raw), + known_platforms + ) + # Extract only names + |> Enum.map(& &1.name) + + assert Enum.sort(actual_platform_names) == Enum.sort(expected_platform_names) + end + + @tag :unit + test "another post with only SFW invite links", %{vtuber: vtuber} do + platforms = Platforms.list_platforms() + + expected_platform_names = ["Fansly", "Twitch"] + + actual_platform_names = + XPost.get_platforms_mentioned( + XPostsFixtures.fixture_offline_4(%{vtuber_id: vtuber.id}) |> Map.get(:raw), + platforms + ) + # Extract only names + |> Enum.map(& &1.name) + + assert Enum.sort(actual_platform_names) == Enum.sort(expected_platform_names) + end + + @tag :unit + test "post with 3 platform invites 1", %{vtuber: vtuber} do + platforms = Platforms.list_platforms() + + expected_platform_names = ["Fansly", "OnlyFans", "Chaturbate"] + + actual_platform_names = + XPost.get_platforms_mentioned( + XPostsFixtures.fixture_live_1(%{vtuber_id: vtuber.id}) |> Map.get(:raw), + platforms + ) + # Extract only names + |> Enum.map(& &1.name) + + assert Enum.sort(actual_platform_names) == Enum.sort(expected_platform_names) + end + + @tag :unit + test "post with 3 platform invites 2", %{vtuber: vtuber} do + platforms = Platforms.list_platforms() + + expected_platform_names = ["Fansly", "OnlyFans", "Chaturbate"] + + actual_platform_names = + XPost.get_platforms_mentioned( + XPostsFixtures.fixture_live_2(%{vtuber_id: vtuber.id}) |> Map.get(:raw), + platforms + ) + # Extract only names + |> Enum.map(& &1.name) + + assert Enum.sort(actual_platform_names) == Enum.sort(expected_platform_names) + end + + @tag :unit + test "post with 3 platform invites 3", %{known_platforms: known_platforms, vtuber: vtuber} do + expected_platform_names = ["Fansly", "OnlyFans", "Chaturbate"] + + actual_platform_names = + XPost.get_platforms_mentioned( + XPostsFixtures.fixture_live_3(%{vtuber_id: vtuber.id}) |> Map.get(:raw), + known_platforms + ) + |> Enum.map(& &1.name) + + assert Enum.sort(actual_platform_names) == Enum.sort(expected_platform_names) + end + + @tag :unit + test "post with a platform alias", %{known_platforms: known_platforms, vtuber: vtuber} do expected_platform_names = ["Fansly"] actual_platform_names = XPost.get_platforms_mentioned( - XPostsFixtures.fixture_live_4() |> Map.get(:raw), + XPostsFixtures.fixture_live_4(%{vtuber_id: vtuber.id}) |> Map.get(:raw), known_platforms ) |> Enum.map(& &1.name) @@ -381,109 +402,88 @@ defmodule Bright.XPostTest do end end - # describe "is_nsfw_live_announcement?/3" do - # setup do - # vtuber = VtubersFixtures.projektmelody_fixture() + describe "is_nsfw_live_announcement?/2" do + setup do + vtuber = VtubersFixtures.projektmelody_fixture() - # {:ok, x_post} = - # Socials.create_x_post(%{ - # raw: "I'm going live https://chaturbate.com/projektmelody", - # url: "https://x.com/projektmelody/status/1234", - # date: DateTime.utc_now(:second), - # vtuber_id: vtuber.id - # }) + {:ok, x_post} = + Socials.create_x_post(%{ + raw: "I'm going live https://chaturbate.com/projektmelody", + url: "https://x.com/projektmelody/status/1234", + date: DateTime.utc_now(:second), + vtuber_id: vtuber.id + }) - # x_post = Repo.preload(x_post, :vtuber) - # known_platforms = PlatformsFixtures.known_platforms_fixture() + x_post = Repo.preload(x_post, :vtuber) - # mentioned_platforms = [ - # PlatformsFixtures.onlyfans_fixture(), - # PlatformsFixtures.chaturbate_fixture(), - # PlatformsFixtures.fansly_fixture() - # ] + known_platforms = PlatformsFixtures.known_platforms_fixture() - # {:ok, - # vtuber: vtuber, - # x_post: x_post, - # known_platforms: known_platforms, - # mentioned_platforms: mentioned_platforms} - # end + {:ok, vtuber: vtuber, x_post: x_post, known_platforms: known_platforms} + end - # @tag :integration - # test "should return false when receiving a XPost linking to a SFW platform", %{ - # vtuber: vtuber, - # x_post: x_post, - # known_platforms: known_platforms - # } do - # mentioned_platforms = [ - # PlatformsFixtures.twitch_fixture(), - # PlatformsFixtures.fansly_fixture(), - # PlatformsFixtures.onlyfans_fixture(), - # PlatformsFixtures.chaturbate_fixture() - # ] + @tag :integration + @tag :taco + test "should return false when receiving a XPost linking to a SFW platform", %{ + known_platforms: known_platforms, + vtuber: vtuber + } do + x_post = XPostsFixtures.fixture_offline_3(%{vtuber_id: vtuber.id}) + x_post = Repo.preload(x_post, :vtuber) + IO.puts(">>> x_post=#{inspect(x_post)}") + assert not XPost.is_nsfw_live_announcement?(x_post, known_platforms) + end - # assert not XPost.is_nsfw_live_announcement?(x_post, mentioned_platforms, known_platforms) - # end + test "should return true when receiving an XPost with only Chaturbate mentioned", %{ + vtuber: vtuber, + x_post: x_post, + known_platforms: known_platforms + } do + assert XPost.is_nsfw_live_announcement?(x_post, known_platforms) + end - # test "should return true when receiving an XPost with only Chaturbate mentioned", %{ - # vtuber: vtuber, - # x_post: x_post, - # known_platforms: known_platforms, - # mentioned_platforms: mentioned_platforms - # } do - # mentioned_platforms = [ - # PlatformsFixtures.chaturbate_fixture() - # ] + test "should return true when receiving an XPost with only NSFW platforms mentioned", %{ + vtuber: vtuber, + x_post: x_post, + known_platforms: known_platforms + } do + assert XPost.is_nsfw_live_announcement?(x_post, known_platforms) + end - # assert XPost.is_nsfw_live_announcement?(x_post, mentioned_platforms, known_platforms) - # end + test "should return false when the XPost is a retweet", %{ + known_platforms: known_platforms + } do + vtuber = VtubersFixtures.el_xox_fixture() - # test "should return true when receiving an XPost with only NSFW platforms mentioned", %{ - # vtuber: vtuber, - # x_post: x_post, - # known_platforms: known_platforms, - # mentioned_platforms: mentioned_platforms - # } do - # assert XPost.is_nsfw_live_announcement?(x_post, mentioned_platforms, known_platforms) - # end + x_post = %XPost{ + url: "https://x.com/mangel0399/status/1898602105851506907", + raw: "#34_XoX", + date: ~U[2025-03-09T05:09:51.000Z], + processed_at: nil, + vtuber_id: vtuber.id + } - # test "should return false when the XPost is a retweet", %{ - # known_platforms: known_platforms, - # mentioned_platforms: mentioned_platforms - # } do - # vtuber = VtubersFixtures.el_xox_fixture() + x_post = Repo.preload(x_post, :vtuber) - # x_post = %XPost{ - # url: "https://x.com/mangel0399/status/1898602105851506907", - # raw: "#34_XoX", - # date: ~U[2025-03-09T05:09:51.000Z], - # processed_at: nil, - # vtuber_id: vtuber.id - # } + assert not XPost.is_nsfw_live_announcement?(x_post, known_platforms) + end - # x_post = Repo.preload(x_post, :vtuber) + test "should return false when receiving an XPost with `vod/i`", %{ + known_platforms: known_platforms + } do + vtuber = VtubersFixtures.el_xox_fixture() - # assert not XPost.is_nsfw_live_announcement?(x_post, mentioned_platforms, known_platforms) - # end + x_post = %XPost{ + raw: + "IRL JOI handcam stream! Listen to my instructions and stroke your cock for me until you cum 🍆💦\n\nThe rest of the VOD is available here for Tier 1 subscribers or for $10! 💛\n▶️ https://fansly.com/post/755934614", + url: "https://x.com/el_XoX34/status/1900275678152712493", + date: ~U[2025-03-09T05:09:51.000Z], + processed_at: nil, + vtuber_id: vtuber.id + } - # test "should return false when receiving an XPost with `vod/i`", %{ - # known_platforms: known_platforms - # } do - # vtuber = VtubersFixtures.el_xox_fixture() + x_post = Repo.preload(x_post, :vtuber) - # x_post = %XPost{ - # raw: - # "IRL JOI handcam stream! Listen to my instructions and stroke your cock for me until you cum 🍆💦\n\nThe rest of the VOD is available here for Tier 1 subscribers or for $10! 💛\n▶️ https://fansly.com/post/755934614", - # url: "https://x.com/el_XoX34/status/1900275678152712493", - # date: ~U[2025-03-09T05:09:51.000Z], - # processed_at: nil, - # vtuber_id: vtuber.id - # } - - # x_post = Repo.preload(x_post, :vtuber) - - # mentioned_platforms = [PlatformsFixtures.fansly_fixture()] - # assert not XPost.is_nsfw_live_announcement?(x_post, mentioned_platforms, known_platforms) - # end - # end + assert not XPost.is_nsfw_live_announcement?(x_post, known_platforms) + end + end end diff --git a/apps/bright/test/support/fixtures/platforms_fixtures.ex b/apps/bright/test/support/fixtures/platforms_fixtures.ex index a841153..c865ce7 100644 --- a/apps/bright/test/support/fixtures/platforms_fixtures.ex +++ b/apps/bright/test/support/fixtures/platforms_fixtures.ex @@ -16,7 +16,8 @@ defmodule Bright.PlatformsFixtures do |> Enum.into(%{ slug: "some_slug", name: "some name", - url: "some url" + url: "some url", + nsfw: true }) |> Bright.Platforms.create_platform() @@ -54,14 +55,13 @@ defmodule Bright.PlatformsFixtures do } |> Bright.Platforms.create_platform() - {:ok, alias} = + {:ok, platform_alias} = %{ url: "https://melody.buzz", platform_id: platform.id } |> Bright.Platforms.create_platform_alias() - # Repo.preload(platform, :platform_aliases) platform end diff --git a/apps/bright/test/support/fixtures/x_posts_fixtures.ex b/apps/bright/test/support/fixtures/x_posts_fixtures.ex index c8efc3d..c230a8e 100644 --- a/apps/bright/test/support/fixtures/x_posts_fixtures.ex +++ b/apps/bright/test/support/fixtures/x_posts_fixtures.ex @@ -1,5 +1,6 @@ defmodule Bright.XPostsFixtures do alias Bright.Socials.XPost + alias Bright.Socials @moduledoc """ This module defines test helpers for creating @@ -9,85 +10,130 @@ defmodule Bright.XPostsFixtures do @doc """ A x_post which does NOT contain an invite link to any of Chaturbate, Fansly, OnlyFans. """ - def fixture_offline_1() do - %XPost{ - raw: - "sry i got off early, gots a headphone headache but regardles.... I REALLY LIKE MONSTER HUNTER (we kicked 2 monster asses solo today!!!!)", - date: ~U[2025-03-12T05:00:00.000Z], - url: "https://x.com/ProjektMelody/status/1899686928913412421" - } + def fixture_offline_1(attrs \\ %{}) do + {:ok, x_post} = + attrs + |> Enum.into(%{ + raw: + "sry i got off early, gots a headphone headache but regardles.... I REALLY LIKE MONSTER HUNTER (we kicked 2 monster asses solo today!!!!)", + date: ~U[2025-03-12T05:00:00.000Z], + url: "https://x.com/ProjektMelody/status/1899686928913412421" + }) + |> Socials.create_x_post() + + x_post end - def fixture_offline_2() do - %XPost{ - raw: - "▀▄▀▄▀▄ SCHEDULE ▄▀▄▀▄▀\n⦉ LINKS: http://linktr.ee/projektmelody\n⦉╰( ߬⚈ o⚈ꪷ)╯𖹭 ˗ˏˋ(‿(ᶅ͒)‿) ˎˊ˗ : https://afterdark.market\n", - date: ~U[2025-03-05T06:25:35.000Z], - url: "https://x.com/ProjektMelody/status/1897171614439223545" - } + def fixture_offline_2(attrs \\ %{}) do + {:ok, x_post} = + attrs + |> Enum.into(%{ + raw: + "▀▄▀▄▀▄ SCHEDULE ▄▀▄▀▄▀\n⦉ LINKS: http://linktr.ee/projektmelody\n⦉╰( ߬⚈ o⚈ꪷ)╯𖹭 ˗ˏˋ(‿(ᶅ͒)‿) ˎˊ˗ : https://afterdark.market\n", + date: ~U[2025-03-05T06:25:35.000Z], + url: "https://x.com/ProjektMelody/status/1897171614439223545" + }) + |> Socials.create_x_post() + + x_post end - def fixture_offline_3() do - %XPost{ - raw: - "I'M LIVE! FEELIN GOOD! LETS GAEM! \n\nhttp://twitch.tv/projektmelody \nhttp://melody.buzz\n\nWe're also doin' a lil giveaway, as @GFuelEnergy\n\n sponsored us :D ---- use !join in twitch chat at spec. times!\n\nFeelin' shoppy? Code MEL gets ur butt 20% OFF ur order-- http://gfuel.ly/mel", - date: ~U[2025-02-25T03:22:57.000Z], - url: "https://x.com/ProjektMelody/status/1894226549215281249" - } + def fixture_offline_3(attrs \\ %{}) do + {:ok, x_post} = + attrs + |> Enum.into(%{ + raw: + "I'M LIVE! FEELIN GOOD! LETS GAEM! \n\nhttp://twitch.tv/projektmelody \nhttp://melody.buzz\n\nWe're also doin' a lil giveaway, as @GFuelEnergy\n\n sponsored us :D ---- use !join in twitch chat at spec. times!\n\nFeelin' shoppy? Code MEL gets ur butt 20% OFF ur order-- http://gfuel.ly/mel", + date: ~U[2025-02-25T03:22:57.000Z], + url: "https://x.com/ProjektMelody/status/1894226549215281249" + }) + |> Socials.create_x_post() + + x_post end - def fixture_offline_4() do - %XPost{ - raw: - "HAPPY TWITCHIVERSARY!\n\nsadly ive succombed to doom scrolling & family issues lately. i couldnt push myself to bring my A-game.... so, we're 2D. however, @iJinzu is joining us! he offered to coach me in monster hunter! :,)\n\nlive: http://twitch.tv/projektmelody\nhttp://melody.buzz", - date: ~U[2025-03-07T22:15:00.000Z], - url: "https://x.com/ProjektMelody/status/1898135320874344448" - } + def fixture_offline_4(attrs \\ %{}) do + {:ok, x_post} = + attrs + |> Enum.into(%{ + raw: + "HAPPY TWITCHIVERSARY!\n\nsadly ive succombed to doom scrolling & family issues lately. i couldnt push myself to bring my A-game.... so, we're 2D. however, @iJinzu is joining us! he offered to coach me in monster hunter! :,)\n\nlive: http://twitch.tv/projektmelody\nhttp://melody.buzz", + date: ~U[2025-03-07T22:15:00.000Z], + url: "https://x.com/ProjektMelody/status/1898135320874344448" + }) + |> Socials.create_x_post() + + x_post end - def fixture_offline_5() do - %XPost{ - raw: "It's happening.. hold my hands please.. 🥺 ▶ twitch.tv/el_xox", - date: ~U[2025-03-12 22:53:24Z], - url: "https://x.com/el_XoX34/status/1832215752591470655" - } + def fixture_offline_5(attrs \\ %{}) do + {:ok, x_post} = + attrs + |> Enum.into(%{ + raw: "It's happening.. hold my hands please.. 🥺 ▶ twitch.tv/el_xox", + date: ~U[2025-03-12 22:53:24Z], + url: "https://x.com/el_XoX34/status/1832215752591470655" + }) + |> Socials.create_x_post() + + x_post end @doc """ A x_post which contains an invite link to any of Fansly, Chaturbate, OnlyFans. """ - def fixture_live_1() do - %XPost{ - raw: "🥯fansly: melody.buzz \n📷onlyfans.com/?ref=16786030 \n📷chaturbate.com/projektmelody", - date: ~U[2025-03-05T18:30:00.000Z], - url: "https://x.com/ProjektMelody/status/1897385055640805666" - } + def fixture_live_1(attrs \\ %{}) do + {:ok, x_post} = + attrs + |> Enum.into(%{ + raw: "🥯fansly: melody.buzz \n📷onlyfans.com/?ref=16786030 \n📷chaturbate.com/projektmelody", + date: ~U[2025-03-05T18:30:00.000Z], + url: "https://x.com/ProjektMelody/status/1897385055640805666" + }) + |> Socials.create_x_post() + + x_post end - def fixture_live_2() do - %XPost{ - raw: - "bruh wassup, it's movie night~\n(have a faptastic day!!!!)\n\n🥯fansly: http://melody.buzz \n🍆http://onlyfans.com/?ref=16786030 \n💦http://chaturbate.com/projektmelody", - date: ~U[2025-02-26T02:14:59.000Z], - url: "https://x.com/ProjektMelody/status/1894571836408504825" - } + def fixture_live_2(attrs \\ %{}) do + {:ok, x_post} = + attrs + |> Enum.into(%{ + raw: + "bruh wassup, it's movie night~\n(have a faptastic day!!!!)\n\n🥯fansly: http://melody.buzz \n🍆http://onlyfans.com/?ref=16786030 \n💦http://chaturbate.com/projektmelody", + date: ~U[2025-02-26T02:14:59.000Z], + url: "https://x.com/ProjektMelody/status/1894571836408504825" + }) + |> Socials.create_x_post() + + x_post end - def fixture_live_3() do - %XPost{ - raw: - "oh, damn---if @Lovense\never starts making tip-assissted ejaculating dildos. my community would frost my ass like a 30-layer wedding cake. i;d become a literal cannoli-hole... hmmm...\nANYWAY, i'm live: \n🥯fansly: http://melody.buzz \n🍆http://onlyfans.com/?ref=16786030 \n💦http://chaturbate.com/projektmelody\n", - date: ~U[2025-03-01T01:05:12.000Z], - url: "https://x.com/ProjektMelody/status/1895641435187151207" - } + def fixture_live_3(attrs \\ %{}) do + {:ok, x_post} = + attrs + |> Enum.into(%{ + raw: + "oh, damn---if @Lovense\never starts making tip-assissted ejaculating dildos. my community would frost my ass like a 30-layer wedding cake. i;d become a literal cannoli-hole... hmmm...\nANYWAY, i'm live: \n🥯fansly: http://melody.buzz \n🍆http://onlyfans.com/?ref=16786030 \n💦http://chaturbate.com/projektmelody\n", + date: ~U[2025-03-01T01:05:12.000Z], + url: "https://x.com/ProjektMelody/status/1895641435187151207" + }) + |> Socials.create_x_post() + + x_post end - def fixture_live_4() do - %XPost{ - raw: "http://melody.buzz", - date: ~U[2025-05-05T05:05:05.000Z], - url: "https://x.com/ProjektMelody/status/5555" - } + def fixture_live_4(attrs \\ %{}) do + {:ok, x_post} = + attrs + |> Enum.into(%{ + raw: "http://melody.buzz", + date: ~U[2025-05-05T05:05:05.000Z], + url: "https://x.com/ProjektMelody/status/5555" + }) + |> Socials.create_x_post() + + x_post end @doc """ diff --git a/terraform/main.tf b/terraform/main.tf index 895bda2..270563e 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -7,46 +7,46 @@ locals { } -variable bright_port { +variable "bright_port" { default = "4000" } -variable database_host { +variable "database_host" { default = "10.2.128.4" } -variable public_s3_endpoint { +variable "public_s3_endpoint" { default = "https://futureporn-b2.b-cdn.net" } -variable patreon_redirect_uri { +variable "patreon_redirect_uri" { default = "https://bright.futureporn.net/auth/patreon/callback" } -variable site_url { +variable "site_url" { default = "https://bright.futureporn.net" } -variable phx_host { +variable "phx_host" { default = "bright.futureporn.net" } -variable aws_bucket { +variable "aws_bucket" { default = "futureporn" } -variable aws_region { +variable "aws_region" { default = "us-west-000" } -variable aws_host { +variable "aws_host" { default = "s3.us-west-000.backblazeb2.com" } variable "vps_user_data" { - # most packages are installed using ansible, but we do use cloud-config - # to install python3, an ansible dependency - default = <<-EOT + # most packages are installed using ansible, but we do use cloud-config + # to install python3, an ansible dependency + default = <<-EOT #cloud-config package_update: true packages: @@ -62,11 +62,11 @@ variable "vps_user_data" { terraform { required_providers { vultr = { - source = "vultr/vultr" + source = "vultr/vultr" version = "2.23.1" } ansible = { - source = "ansible/ansible" + source = "ansible/ansible" version = "1.2.0" } } @@ -74,44 +74,44 @@ terraform { provider "vultr" { - api_key = "${local.envs.VULTR_API_KEY}" + api_key = local.envs.VULTR_API_KEY } # reserved IP lets us spin down the system and spin up without losing the IP reservation resource "vultr_reserved_ip" "futureporn_v2_ip" { - label = "futureporn-v2" - region = "ord" - ip_type = "v4" + label = "futureporn-v2" + region = "ord" + ip_type = "v4" } resource "vultr_reserved_ip" "futureporn_tracker_ip" { - label = "futureporn-tracker" - region = "ord" - ip_type = "v4" + label = "futureporn-tracker" + region = "ord" + ip_type = "v4" } # Virtual Private Cloud for connecting many VPS together on a private network # We use this network connection for app<->db comms. resource "vultr_vpc2" "futureporn_vpc2" { - region = "ord" + region = "ord" description = "Futureporn V2 VPC2" } # load balancing instance resource "vultr_instance" "load_balancer" { - count = 1 - hostname = "fp-lb-${count.index}" - plan = "vc2-1c-2gb" - region = "ord" - backups = "disabled" + count = 1 + hostname = "fp-lb-${count.index}" + plan = "vc2-1c-2gb" + region = "ord" + backups = "disabled" ddos_protection = "false" - os_id = 1743 - enable_ipv6 = true - label = "fp lb ${count.index}" - tags = ["futureporn", "load_balancer", "bright"] - ssh_key_ids = [local.envs.VULTR_SSH_KEY_ID] - user_data = base64encode(var.vps_user_data) + os_id = 1743 + enable_ipv6 = true + label = "fp lb ${count.index}" + tags = ["futureporn", "load_balancer", "bright"] + ssh_key_ids = [local.envs.VULTR_SSH_KEY_ID] + user_data = base64encode(var.vps_user_data) vpc2_ids = [ vultr_vpc2.futureporn_vpc2.id ] @@ -120,17 +120,17 @@ resource "vultr_instance" "load_balancer" { # vultr instance for running bright app resource "vultr_instance" "bright" { - count = 1 - hostname = "fp-bright-${count.index}" - plan = "vc2-2c-4gb" - region = "ord" - backups = "disabled" + count = 1 + hostname = "fp-bright-${count.index}" + plan = "vc2-2c-4gb" + region = "ord" + backups = "disabled" ddos_protection = "false" - os_id = 1743 - enable_ipv6 = true - label = "fp bright ${count.index}" - tags = ["futureporn", "phoenix", "bright"] - ssh_key_ids = [local.envs.VULTR_SSH_KEY_ID] + os_id = 1743 + enable_ipv6 = true + label = "fp bright ${count.index}" + tags = ["futureporn", "phoenix", "bright"] + ssh_key_ids = [local.envs.VULTR_SSH_KEY_ID] vpc2_ids = [ vultr_vpc2.futureporn_vpc2.id ] @@ -148,19 +148,19 @@ resource "vultr_instance" "capture_vps" { ddos_protection = "false" os_id = 1743 enable_ipv6 = true - vpc2_ids = [vultr_vpc2.futureporn_vpc2.id] - label = "fp capture ${count.index}" - tags = ["futureporn", "capture"] - ssh_key_ids = [local.envs.VULTR_SSH_KEY_ID] - user_data = base64encode(var.vps_user_data) + vpc2_ids = [vultr_vpc2.futureporn_vpc2.id] + label = "fp capture ${count.index}" + tags = ["futureporn", "capture"] + ssh_key_ids = [local.envs.VULTR_SSH_KEY_ID] + user_data = base64encode(var.vps_user_data) } resource "vultr_instance" "database" { - count = 1 - hostname = "fp-db-${count.index}" - plan = "vc2-1c-2gb" - region = "ord" - backups = "enabled" + count = 1 + hostname = "fp-db-${count.index}" + plan = "vc2-1c-2gb" + region = "ord" + backups = "enabled" backups_schedule { hour = "2" type = "daily" @@ -168,11 +168,11 @@ resource "vultr_instance" "database" { ddos_protection = "false" os_id = 1743 enable_ipv6 = true - vpc2_ids = [vultr_vpc2.futureporn_vpc2.id] - label = "fp database ${count.index}" - tags = ["futureporn", "database"] - ssh_key_ids = [local.envs.VULTR_SSH_KEY_ID] - user_data = base64encode(var.vps_user_data) + vpc2_ids = [vultr_vpc2.futureporn_vpc2.id] + label = "fp database ${count.index}" + tags = ["futureporn", "database"] + ssh_key_ids = [local.envs.VULTR_SSH_KEY_ID] + user_data = base64encode(var.vps_user_data) } resource "vultr_instance" "tracker" { @@ -184,18 +184,18 @@ resource "vultr_instance" "tracker" { ddos_protection = "false" os_id = 1743 enable_ipv6 = true - vpc2_ids = [vultr_vpc2.futureporn_vpc2.id] - label = "fp tracker ${count.index}" - tags = ["futureporn", "tracker"] - ssh_key_ids = [local.envs.VULTR_SSH_KEY_ID] - user_data = base64encode(var.vps_user_data) - reserved_ip_id = vultr_reserved_ip.futureporn_tracker_ip.id + vpc2_ids = [vultr_vpc2.futureporn_vpc2.id] + label = "fp tracker ${count.index}" + tags = ["futureporn", "tracker"] + ssh_key_ids = [local.envs.VULTR_SSH_KEY_ID] + user_data = base64encode(var.vps_user_data) + reserved_ip_id = vultr_reserved_ip.futureporn_tracker_ip.id } resource "ansible_host" "capture_vps" { for_each = { for idx, host in vultr_instance.capture_vps : idx => host } - name = each.value.hostname - groups = ["capture"] # Groups this host is part of. + name = each.value.hostname + groups = ["capture"] # Groups this host is part of. variables = { # Connection vars. @@ -210,42 +210,42 @@ resource "ansible_host" "capture_vps" { resource "ansible_host" "load_balancer" { for_each = { for idx, host in vultr_instance.load_balancer : idx => host } - name = each.value.hostname - groups = ["load_balancer"] + name = each.value.hostname + groups = ["load_balancer"] variables = { ansible_host = each.value.main_ip - internal_ip = each.value.internal_ip + internal_ip = each.value.internal_ip } } resource "ansible_host" "database" { for_each = { for idx, host in vultr_instance.database : idx => host } - name = each.value.hostname - groups = ["database"] + name = each.value.hostname + groups = ["database"] variables = { ansible_host = each.value.main_ip - internal_ip = each.value.internal_ip + internal_ip = each.value.internal_ip } } resource "ansible_host" "bright" { for_each = { for idx, host in vultr_instance.bright : idx => host } - name = each.value.hostname - groups = ["bright"] + name = each.value.hostname + groups = ["bright"] variables = { - ansible_host = each.value.main_ip - internal_ip = each.value.internal_ip + ansible_host = each.value.main_ip + internal_ip = each.value.internal_ip vultr_instance_id = each.value.id } } resource "ansible_host" "tracker" { for_each = { for idx, host in vultr_instance.tracker : idx => host } - name = each.value.hostname - groups = ["tracker"] + name = each.value.hostname + groups = ["tracker"] variables = { - ansible_host = each.value.main_ip - internal_ip = each.value.internal_ip + ansible_host = each.value.main_ip + internal_ip = each.value.internal_ip vultr_instance_id = each.value.id } } @@ -322,4 +322,4 @@ resource "ansible_group" "futureporn" { # - ufw allow 4001 # EOT -# ) \ No newline at end of file +# )