change the structure of image ttl parsar
authorSachin Joshi <satchin.joshi@gmail.com>
Fri, 19 Jul 2019 05:58:42 +0000 (11:43 +0545)
committerSachin Joshi <satchin.joshi@gmail.com>
Fri, 19 Jul 2019 05:58:42 +0000 (11:43 +0545)
docs/config/howto_set_richmedia_cache_ttl_based_on_image.md
lib/pleroma/web/rich_media/parser.ex
lib/pleroma/web/rich_media/parsers/ttl/aws_signed_url.ex
lib/pleroma/web/rich_media/parsers/ttl/ttl.ex [new file with mode: 0644]
test/web/rich_media/aws_signed_url_test.exs

index 489f9ece8b531ee16e4d02469f739b8cf4e819bb..5846b6ab08721ea664d9978e4d4207133388a9a0 100644 (file)
@@ -4,7 +4,7 @@
 Richmedia are cached without the ttl but the rich media may have image which can expire, like aws signed url.
 In such cases the old image url (expired) is returned from the media cache.
 
-So to avoid such situation we can define a moddule that will set ttl based no image.
+So to avoid such situation we can define a moddule that will set ttl based on image.
 
 The module must have a `run` function and it should be registered in the config.
 
index ba8dc6f2a4b0812a9d3a715ce36deefdd921b215..b69b2be610a6383ed5f5c97a92f3db4c0fe3ea02 100644 (file)
@@ -35,17 +35,17 @@ defmodule Pleroma.Web.RichMedia.Parser do
   @doc """
   Set the rich media cache based on the expiration time of image.
 
-  Define a module that has `run` function
+  Adopt behaviour `Pleroma.Web.RichMedia.Parser.TTL`
 
   ## Example
 
       defmodule MyModule do
-        def run(data, url) do
+        @behaviour Pleroma.Web.RichMedia.Parser.TTL
+        def ttl(data, url) do
           image_url = Map.get(data, :image)
           # do some parsing in the url and get the ttl of the image
-          # ttl is unix time
-          ttl = parse_ttl_from_url(image_url)  
-          Cachex.expire_at(:rich_media_cache, url, ttl * 1000)
+          # and return ttl is unix time
+          parse_ttl_from_url(image_url)
         end
       end
 
@@ -55,22 +55,26 @@ defmodule Pleroma.Web.RichMedia.Parser do
         ttl_setters: [MyModule]
   """
   def set_ttl_based_on_image({:ok, data}, url) do
-    case Cachex.ttl(:rich_media_cache, url) do
-      {:ok, nil} ->
-        modules = Pleroma.Config.get([:rich_media, :ttl_setters])
-
-        if Enum.count(modules) > 0 do
-          Enum.each(modules, & &1.run(data, url))
-        end
-
-        {:ok, data}
-
+    with {:ok, nil} <- Cachex.ttl(:rich_media_cache, url) do
+      ttl = get_ttl_from_image(data, url)
+      Cachex.expire_at(:rich_media_cache, url, ttl * 1000)
+      {:ok, data}
+    else
       _ ->
         {:ok, data}
     end
   end
 
-  def set_ttl_based_on_image(data, _url), do: data
+  defp get_ttl_from_image(data, url) do
+    Pleroma.Config.get([:rich_media, :ttl_setters])
+    |> Enum.reduce({:ok, nil}, fn
+      module, {:ok, _ttl} ->
+        module.ttl(data, url)
+
+      _, error ->
+        error
+    end)
+  end
 
   defp parse_url(url) do
     try do
index d5710793929343ec05fe592a61e97396aded0d18..014c0935f44c3968fa3b3cfd1b84c229973b5ab0 100644 (file)
@@ -1,5 +1,8 @@
 defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl do
-  def run(data, url) do
+  @behaviour Pleroma.Web.RichMedia.Parser.TTL
+
+  @impl Pleroma.Web.RichMedia.Parser.TTL
+  def ttl(data, _url) do
     image = Map.get(data, :image)
 
     if is_aws_signed_url(image) do
@@ -7,7 +10,6 @@ defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl do
       |> parse_query_params()
       |> format_query_params()
       |> get_expiration_timestamp()
-      |> set_ttl(url)
     end
   end
 
@@ -47,8 +49,4 @@ defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl do
 
     Timex.to_unix(date) + String.to_integer(Map.get(params, "X-Amz-Expires"))
   end
-
-  defp set_ttl(ttl, url) do
-    Cachex.expire_at(:rich_media_cache, url, ttl * 1000)
-  end
 end
diff --git a/lib/pleroma/web/rich_media/parsers/ttl/ttl.ex b/lib/pleroma/web/rich_media/parsers/ttl/ttl.ex
new file mode 100644 (file)
index 0000000..6b3ec6d
--- /dev/null
@@ -0,0 +1,3 @@
+defmodule Pleroma.Web.RichMedia.Parser.TTL do
+  @callback ttl(Map.t(), String.t()) :: {:ok, Integer.t()} | {:error, String.t()}
+end
index 75bf6c6df5524b548a0337a39962f01ce7db56e3..122787bc253b66e30ae795b3e1214464d754386c 100644 (file)
@@ -5,7 +5,7 @@
 defmodule Pleroma.Web.RichMedia.TTL.AwsSignedUrlTest do
   use ExUnit.Case, async: true
 
-  test "amazon signed url is parsed and correct ttl is set for rich media" do
+  test "s3 signed url is parsed correct for expiration time" do
     url = "https://pleroma.social/amz"
 
     {:ok, timestamp} =
@@ -16,22 +16,66 @@ defmodule Pleroma.Web.RichMedia.TTL.AwsSignedUrlTest do
     # in seconds
     valid_till = 30
 
-    data = %{
-      image:
-        "https://pleroma.s3.ap-southeast-1.amazonaws.com/sachin%20%281%29%20_a%20-%25%2Aasdasd%20BNN%20bnnn%20.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIBLWWK6RGDQXDLJQ%2F20190716%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=#{
-          timestamp
-        }&X-Amz-Expires=#{valid_till}&X-Amz-Signature=04ffd6b98634f4b1bbabc62e0fac4879093cd54a6eed24fe8eb38e8369526bbf&X-Amz-SignedHeaders=host",
-      locale: "en_US",
-      site_name: "Pleroma",
-      title: "PLeroma",
-      url: url
-    }
+    metadata = construct_metadata(timestamp, valid_till, url)
+
+    expire_time =
+      Timex.parse!(timestamp, "{ISO:Basic:Z}") |> Timex.to_unix() |> Kernel.+(valid_till)
+
+    assert expire_time == Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl.ttl(metadata, url)
+  end
+
+  test "s3 signed url is parsed and correct ttl is set for rich media" do
+    url = "https://pleroma.social/amz"
+
+    {:ok, timestamp} =
+      Timex.now()
+      |> DateTime.truncate(:second)
+      |> Timex.format("{ISO:Basic:Z}")
+
+    # in seconds
+    valid_till = 30
+
+    metadata = construct_metadata(timestamp, valid_till, url)
+
+    body = """
+    <meta name="twitter:card" content="Pleroma" />
+    <meta name="twitter:site" content="Pleroma" />
+    <meta name="twitter:title" content="Pleroma" />
+    <meta name="twitter:description" content="Pleroma" />
+    <meta name="twitter:image" content="#{Map.get(metadata, :image)}" />
+    """
+
+    Tesla.Mock.mock(fn
+      %{
+        method: :get,
+        url: "https://pleroma.social/amz"
+      } ->
+        %Tesla.Env{status: 200, body: body}
+    end)
+
+    Cachex.put(:rich_media_cache, url, metadata)
+
+    Pleroma.Web.RichMedia.Parser.set_ttl_based_on_image({:ok, metadata}, url)
 
-    Cachex.put(:rich_media_cache, url, data)
-    assert {:ok, _} = Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl.run(data, url)
     {:ok, cache_ttl} = Cachex.ttl(:rich_media_cache, url)
 
     # as there is delay in setting and pulling the data from cache we ignore 1 second
     assert_in_delta(valid_till * 1000, cache_ttl, 1000)
   end
+
+  defp construct_s3_url(timestamp, valid_till) do
+    "https://pleroma.s3.ap-southeast-1.amazonaws.com/sachin%20%281%29%20_a%20-%25%2Aasdasd%20BNN%20bnnn%20.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIBLWWK6RGDQXDLJQ%2F20190716%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=#{
+      timestamp
+    }&X-Amz-Expires=#{valid_till}&X-Amz-Signature=04ffd6b98634f4b1bbabc62e0fac4879093cd54a6eed24fe8eb38e8369526bbf&X-Amz-SignedHeaders=host"
+  end
+
+  defp construct_metadata(timestamp, valid_till, url) do
+    %{
+      image: construct_s3_url(timestamp, valid_till),
+      site: "Pleroma",
+      title: "Pleroma",
+      description: "Pleroma",
+      url: url
+    }
+  end
 end