diff --git a/.env.example b/.env.example index 80e368a7..7736ad50 100644 --- a/.env.example +++ b/.env.example @@ -5,6 +5,7 @@ export BASIC_AUTH_PASSWORD= export BASIC_AUTH_USERNAME= export CANONICAL_DOMAIN=https://example.com export DATE_DISPLAY_TZ=America/Chicago +export DEFAULT_BLUESKY_HANDLE= export DEFAULT_TWITTER_HANDLE= export ENABLE_BASIC_AUTH= export GOOGLE_CLIENT_ID= @@ -18,3 +19,5 @@ export twitter_access_token= export twitter_access_token_secret= export twitter_consumer_key= export twitter_consumer_secret= +export bluesky_username= +export bluesky_password= diff --git a/config/config.exs b/config/config.exs index 56658113..33042ee8 100644 --- a/config/config.exs +++ b/config/config.exs @@ -58,6 +58,7 @@ config :tilex, :twitter_notifier, Tilex.Notifications.Notifiers.Twitter config :tilex, :organization_name, System.get_env("ORGANIZATION_NAME") config :tilex, :canonical_domain, System.get_env("CANONICAL_DOMAIN") config :tilex, :default_twitter_handle, System.get_env("DEFAULT_TWITTER_HANDLE") +config :tilex, :default_bluesky_handle, System.get_env("DEFAULT_BLUESKY_HANDLE") config :tilex, :cors_origin, System.get_env("CORS_ORIGIN") config :tilex, :hosted_domain, System.get_env("HOSTED_DOMAIN") config :tilex, :guest_author_allowlist, System.get_env("GUEST_AUTHOR_ALLOWLIST") @@ -114,6 +115,10 @@ config :tilex, Tilex.Notifications.Notifiers.Twitter, token: System.get_env("twitter_access_token"), token_secret: System.get_env("twitter_access_token_secret") +config :tilex, Tilex.Notifications.Notifiers.Bluesky, + username: System.get_env("bluesky_username"), + password: System.get_env("bluesky_password") + # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{Mix.env()}.exs" diff --git a/lib/test/notifications/notifiers/bluesky.ex b/lib/test/notifications/notifiers/bluesky.ex new file mode 100644 index 00000000..569bf7f1 --- /dev/null +++ b/lib/test/notifications/notifiers/bluesky.ex @@ -0,0 +1,15 @@ +defmodule Test.Notifications.Notifiers.Bluesky do + use Tilex.Notifications.Notifier + + def handle_post_created(_post, _developer, _channel, _url) do + :ok + end + + def handle_post_liked(_post, _developer, _url) do + :ok + end + + def handle_page_views_report(_report) do + :ok + end +end diff --git a/lib/tilex/notifications/notifiers/bluesky.ex b/lib/tilex/notifications/notifiers/bluesky.ex new file mode 100644 index 00000000..4b63353d --- /dev/null +++ b/lib/tilex/notifications/notifiers/bluesky.ex @@ -0,0 +1,28 @@ +defmodule Tilex.Notifications.Notifiers.Bluesky do + alias BlueskyEx.Client + alias Tilex.Blog.Developer + + use Tilex.Notifications.Notifier + + def handle_post_created(post, developer, channel, url) do + "#{post.title} #{url} via @#{Developer.twitter_handle(developer)} #til ##{channel.twitter_hashtag}" + |> create_post() + end + + def handle_post_liked(_post, _dev, _url) do + :ok + end + + def handle_page_views_report(_report) do + :ok + end + + def create_post(text) do + Client.Credentials + |> struct(credentials()) + |> Client.Session.create("https://bsky.social") + |> Client.RecordManager.create_post(text: text) + end + + defp credentials, do: Application.get_env(:tilex, __MODULE__) +end diff --git a/lib/tilex_web/endpoint.ex b/lib/tilex_web/endpoint.ex index 04408c5d..2216ae73 100644 --- a/lib/tilex_web/endpoint.ex +++ b/lib/tilex_web/endpoint.ex @@ -1,6 +1,5 @@ defmodule TilexWeb.Endpoint do use Phoenix.Endpoint, otp_app: :tilex - use Appsignal.Phoenix if sandbox = Application.compile_env(:tilex, :sandbox) do plug(Phoenix.Ecto.SQL.Sandbox, sandbox: sandbox) diff --git a/lib/tilex_web/templates/layout/root.html.heex b/lib/tilex_web/templates/layout/root.html.heex index cd7c3cb0..9b4261c4 100644 --- a/lib/tilex_web/templates/layout/root.html.heex +++ b/lib/tilex_web/templates/layout/root.html.heex @@ -92,6 +92,10 @@ <%= icon("twitter", :small) %> Follow on Twitter + + <%= icon("bluesky", :small) %> + Follow on Bluesky + diff --git a/mix.exs b/mix.exs index 30d13321..27c25a5a 100644 --- a/mix.exs +++ b/mix.exs @@ -34,6 +34,7 @@ defmodule Tilex.Mixfile do defp deps do [ {:appsignal_phoenix, "~> 2.0"}, + {:bluesky_ex, "~> 0.1.6"}, {:cachex, "~> 3.1"}, {:cors_plug, "~> 3.0"}, {:credo, "~> 1.6", only: [:dev, :test], runtime: false}, diff --git a/mix.lock b/mix.lock index 5aed5a52..5810dd03 100644 --- a/mix.lock +++ b/mix.lock @@ -2,6 +2,7 @@ "appsignal": {:hex, :appsignal, "2.12.3", "de6aff6241bf7f1b5c6e058d976d3dcf00071613f7800f66049d9a77a3aa15d8", [:make, :mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:decorator, "~> 1.2.3 or ~> 1.3", [hex: :decorator, repo: "hexpm", optional: false]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2744685894960b5b0421e77240d1a8ccc1ff3a256344f42055af892efe6d1f06"}, "appsignal_phoenix": {:hex, :appsignal_phoenix, "2.5.0", "b0f5855d02d1f522f6029e71d3b11ebb1d37df63b562e380750841de25d35a7c", [:mix], [{:appsignal, ">= 2.11.0 and < 3.0.0", [hex: :appsignal, repo: "hexpm", optional: false]}, {:appsignal_plug, ">= 2.0.15 and < 3.0.0", [hex: :appsignal_plug, repo: "hexpm", optional: false]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.11 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 0.9 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "01fe404add5fe32b837f6cf922cbc7f0047a8abbc78f1e943268cd48e0ed3169"}, "appsignal_plug": {:hex, :appsignal_plug, "2.0.15", "758a8a78944878e8461bbc77ca86219121a56f4299c6d79940ab083cf9afea00", [:mix], [{:appsignal, ">= 2.7.6 and < 3.0.0", [hex: :appsignal, repo: "hexpm", optional: false]}, {:plug, ">= 1.1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1c6059049e2081e808aaef04e2b9917e06277f61a35a0e103db860d08cbc41f1"}, + "bluesky_ex": {:hex, :bluesky_ex, "0.1.6", "a4c6a8ecaac6d63f91877aee829f251becb27b376234967f566db5c093550dea", [:make, :mix], [{:httpoison, "~> 2.1", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.3", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "54b591093a4fe0dd9db63e867a3bdf9fd2fa03c091b71150bf72d0a100b62198"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"}, "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, diff --git a/priv/static/images/icons.svg b/priv/static/images/icons.svg index 3a9b0056..ddde9c9f 100644 --- a/priv/static/images/icons.svg +++ b/priv/static/images/icons.svg @@ -31,4 +31,7 @@ + + +