Browse Source

test(fixes): Bring to 501 passed, 11 broken and 34 skipped.

jackyalcine 7 months ago
parent
commit
0ad92ac418
Signed by: Jacky Alciné <yo@jacky.wtf> GPG Key ID: 537A4F904B15268D
98 changed files with 1571 additions and 1836 deletions
  1. 3
    3
      config/config.exs
  2. 7
    1
      config/test.exs
  3. 3
    1
      lib/application.ex
  4. 2
    2
      lib/cache.ex
  5. 1
    1
      lib/http.ex
  6. 2
    1
      lib/indieweb/micropub.ex
  7. 50
    40
      lib/indieweb/micropub/content.ex
  8. 12
    16
      lib/indieweb/micropub/entry.ex
  9. 9
    2
      lib/indieweb/micropub/query.ex
  10. 21
    17
      lib/indieweb/websub.ex
  11. 12
    7
      lib/job.ex
  12. 1
    1
      lib/koype.ex
  13. 6
    0
      lib/mix.ex
  14. 22
    0
      lib/mix/koype/restore_webmentions.ex
  15. 4
    4
      lib/page.ex
  16. 5
    4
      lib/page/parser.ex
  17. 7
    6
      lib/page/parser/activitystreams2.ex
  18. 17
    4
      lib/page/parser/microformats2.ex
  19. 2
    1
      lib/repo.ex
  20. 0
    10
      lib/repo/category.ex
  21. 1
    0
      lib/repo/entry.ex
  22. 31
    0
      lib/repo/entry/category.ex
  23. 18
    10
      lib/repo/entry/syndication_result.ex
  24. 3
    0
      lib/repo/entry/visibility.ex
  25. 5
    1
      lib/repo/otp_secret.ex
  26. 3
    1
      lib/webmention.ex
  27. 5
    10
      mix.exs
  28. 9
    9
      priv/themes/default/tmpl/follow.html.liquid
  29. 3
    4
      test/features/settings.feature
  30. 6
    20
      test/fixtures/vcr_cassettes/contact_from_homepage.json
  31. 5
    35
      test/fixtures/vcr_cassettes/contact_import_hcard.json
  32. 7
    24
      test/fixtures/vcr_cassettes/fails_to_fetch_due_to_network_error.json
  33. 7
    24
      test/fixtures/vcr_cassettes/fails_to_fetch_due_to_server_error.json
  34. 4
    21
      test/fixtures/vcr_cassettes/fetch_from_page.json
  35. 7
    25
      test/fixtures/vcr_cassettes/fetch_from_page_on_omnibear.json
  36. 0
    55
      test/fixtures/vcr_cassettes/finds_hcard_from_authorship.json
  37. 0
    55
      test/fixtures/vcr_cassettes/finds_hcard_from_homepage.json
  38. 0
    38
      test/fixtures/vcr_cassettes/finds_hcards_from_authorship_2.json
  39. 0
    45
      test/fixtures/vcr_cassettes/finds_hcards_from_authorship_3.json
  40. 0
    72
      test/fixtures/vcr_cassettes/generate_hcard_from_uri.json
  41. 0
    47
      test/fixtures/vcr_cassettes/http_fetch_page_success.json
  42. 0
    40
      test/fixtures/vcr_cassettes/indieweb_syndication_endpoint_failure.json
  43. 0
    45
      test/fixtures/vcr_cassettes/indieweb_syndication_endpoint_success.json
  44. 90
    0
      test/fixtures/vcr_cassettes/micropub_entry_process_property_response_type.json
  45. 0
    30
      test/fixtures/vcr_cassettes/micropub_entry_process_propery_response_type.json
  46. 10
    10
      test/fixtures/vcr_cassettes/micropub_entry_send_webmention_passes.json
  47. 90
    0
      test/fixtures/vcr_cassettes/micropub_entry_success_create.json
  48. 56
    0
      test/fixtures/vcr_cassettes/page_fetch_no_title.json
  49. 76
    0
      test/fixtures/vcr_cassettes/page_fetch_success.json
  50. 29
    0
      test/fixtures/vcr_cassettes/page_fetch_unreachable.json
  51. 7
    24
      test/fixtures/vcr_cassettes/page_is_empty.json
  52. 148
    0
      test/fixtures/vcr_cassettes/page_parser_as2_from_json.json
  53. 0
    82
      test/fixtures/vcr_cassettes/parse_activtystreams_parse_success.json
  54. 0
    34
      test/fixtures/vcr_cassettes/parser_bridgy_success_mobile_twitter.json
  55. 5
    5
      test/fixtures/vcr_cassettes/parser_bridgy_success_twitter.json
  56. 9
    9
      test/fixtures/vcr_cassettes/parser_microformats2_parse_success.json
  57. 4
    21
      test/fixtures/vcr_cassettes/refresh_of_mf2_data.json
  58. 0
    31
      test/fixtures/vcr_cassettes/settings-relme-add-verified-link.json
  59. 5
    3
      test/fixtures/vcr_cassettes/syndication_fail_endpoint.json
  60. 0
    40
      test/fixtures/vcr_cassettes/syndication_result_endpoint_failure.json
  61. 0
    40
      test/fixtures/vcr_cassettes/syndication_result_successful.json
  62. 86
    0
      test/fixtures/vcr_cassettes/webmention_receive_store_new.json
  63. 86
    0
      test/fixtures/vcr_cassettes/webmention_receive_store_new_homepage.json
  64. 86
    0
      test/fixtures/vcr_cassettes/webmention_receive_store_new_random.json
  65. 29
    0
      test/fixtures/vcr_cassettes/webmention_receive_update_410.json
  66. 86
    0
      test/fixtures/vcr_cassettes/webmention_receive_updates.json
  67. 0
    1
      test/fixtures/vcr_cassettes/webmention_send_endpoint_fail.json
  68. 0
    82
      test/fixtures/vcr_cassettes/webmention_send_fail.json
  69. 0
    97
      test/fixtures/vcr_cassettes/webmention_send_success.json
  70. 0
    50
      test/fixtures/vcr_cassettes/webmention_test_for_headers_1.json
  71. 0
    50
      test/fixtures/vcr_cassettes/webmention_test_for_headers_2.json
  72. 0
    97
      test/fixtures/vcr_cassettes/webmention_test_for_headers_3.json
  73. 0
    97
      test/fixtures/vcr_cassettes/webmention_test_for_headers_4.json
  74. 6
    6
      test/integration/controllers/auth_controller_test.exs
  75. 5
    2
      test/integration/controllers/category_controller_test.exs
  76. 3
    5
      test/integration/controllers/contact_controller_test.exs
  77. 30
    28
      test/integration/controllers/indie/auth_controller_test.exs
  78. 24
    20
      test/integration/controllers/indie/micropub_controller_test.exs
  79. 5
    3
      test/integration/controllers/indie/token_api_controller_test.exs
  80. 6
    5
      test/support/factory.ex
  81. 0
    8
      test/support/steps/form.ex
  82. 3
    1
      test/unit/cache_test.exs
  83. 10
    5
      test/unit/feed/json_feed_test.exs
  84. 0
    10
      test/unit/http_test.exs
  85. 41
    10
      test/unit/indieweb/micropub/content_test.exs
  86. 69
    50
      test/unit/indieweb/micropub/entry_test.exs
  87. 1
    1
      test/unit/indieweb/syndication_test.exs
  88. 1
    1
      test/unit/koype_test.exs
  89. 28
    23
      test/unit/page/parser/activitystreams2_test.exs
  90. 9
    3
      test/unit/page/parser/bridgy_test.exs
  91. 1
    5
      test/unit/page/parser/microformats2_test.exs
  92. 8
    5
      test/unit/page/parser_test.exs
  93. 14
    21
      test/unit/page_test.exs
  94. 15
    0
      test/unit/repo/category_test.exs
  95. 33
    5
      test/unit/repo/entry/syndication_result_test.exs
  96. 12
    5
      test/unit/repo/otp_secret_test.exs
  97. 44
    108
      test/unit/webmention_test.exs
  98. 1
    1
      web/controllers/category_controller.ex

+ 3
- 3
config/config.exs View File

@@ -36,6 +36,7 @@ config :koype, Koype.Repo,
36 36
   json_library: Jason,
37 37
   migration_primary_key: [id: :id, type: :uuid],
38 38
   migration_timestamsp: [type: :utc_datetime],
39
+  db_timeout: 30_000,
39 40
   pool_timeout: 60_000,
40 41
   pool_size: 128,
41 42
   log: true,
@@ -44,7 +45,7 @@ config :koype, Koype.Repo,
44 45
 config :logger, :console,
45 46
   backends: [:console],
46 47
   handle_sasl_reports: true,
47
-  format: "\n[$time] $metadata[$level] $message",
48
+  format: "\n[$time] $metadata[$level] $message\n",
48 49
   metadata: :all,
49 50
   level: :debug
50 51
 
@@ -60,13 +61,12 @@ config :phoenix,
60 61
        ~w(access_token password secret code _csrf_token csrf_token state token)
61 62
 
62 63
 config :arc,
63
-  storage: Arc.Storage.Local,
64 64
   storage: Arc.Storage.S3,
65 65
   bucket: {:system, :string, "OBJECT_STORAGE_BUCKET", "koype"}
66 66
 
67 67
 config :ex_aws, :hackney_opts,
68 68
   follow_redirect: true,
69
-  recv_timeout: 3_000
69
+  recv_timeout: 5_000
70 70
 
71 71
 config :ex_aws,
72 72
   storage_dir: "koype",

+ 7
- 1
config/test.exs View File

@@ -2,7 +2,12 @@ use Mix.Config
2 2
 
3 3
 config :logger, level: :info
4 4
 
5
-config :koype, Koype.Repo, pool: Ecto.Adapters.SQL.Sandbox
5
+config :koype, Koype.Repo,
6
+  pool: Ecto.Adapters.SQL.Sandbox,
7
+  db_timeout: 100_000,
8
+  pool_timeout: 100_000,
9
+  pool_size: 1,
10
+  log: true
6 11
 
7 12
 config :koype, Koype.Web.Endpoint,
8 13
   debug_errors: false,
@@ -24,6 +29,7 @@ config :exvcr,
24 29
 config :hound,
25 30
   app_host: {:system, :string, "TEST_HOST", "localhost"},
26 31
   app_port: {:system, :integer, "TEST_PORT", 5001},
32
+  timeout: 30_000,
27 33
   driver: "chrome_driver",
28 34
   host: "http://webdriver",
29 35
   path_prefix: "wd/hub/",

+ 3
- 1
lib/application.ex View File

@@ -45,11 +45,13 @@ defmodule Koype.Application do
45 45
       :arc,
46 46
       :cowboy,
47 47
       :ex_aws,
48
+      :ex_aws_s3,
48 49
       :hound,
49 50
       :logger,
50 51
       :indieweb,
51 52
       :koype,
52
-      :phoenix
53
+      :phoenix,
54
+      :guardian
53 55
     ]
54 56
     |> Enum.each(&Confex.resolve_env!/1)
55 57
   end

+ 2
- 2
lib/cache.ex View File

@@ -38,7 +38,7 @@ defmodule Koype.Cache do
38 38
     case Cachex.put(:koype, key, value) do
39 39
       {:ok, _code} ->
40 40
         expiry = opts[:expire] || :timer.hours(24 * 7)
41
-        {:ok, _} = Cachex.expire(:koype, key, expiry)
41
+        Cachex.expire(:koype, key, expiry)
42 42
         :ok
43 43
 
44 44
       {:error, error} ->
@@ -77,7 +77,7 @@ defmodule Koype.Cache do
77 77
   end
78 78
 
79 79
   def get_supervisor() do
80
-    Supervisor.Spec.worker(Cachex, [:koype, []])
80
+    Supervisor.Spec.worker(Cachex, [:koype, [limit: 500]])
81 81
   end
82 82
 
83 83
   def refresh_for(id, key_func, value_func) do

+ 1
- 1
lib/http.ex View File

@@ -30,7 +30,7 @@ defmodule Koype.Http do
30 30
   @fake_human_agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133"
31 31
   @user_agent "Koype/#{Koype.version()} (https://koype.net/faq/user-agent) "
32 32
 
33
-  def timeout, do: 10_000
33
+  def timeout, do: 5_000
34 34
 
35 35
   defmodule Response do
36 36
     @moduledoc "Represents a HTTP response."

+ 2
- 1
lib/indieweb/micropub.ex View File

@@ -21,6 +21,7 @@ defmodule IndieWeb.Micropub do
21 21
   @reserved_mp_param_keys ~w(h action url content) ++ @actionable_keys
22 22
   @sensitive_properties ~w(access_token)
23 23
   @micropub_action_prefix "mp-"
24
+  @micropub_stable_extensions ~w(post-status published)
24 25
 
25 26
   @spec endpoint() :: binary()
26 27
   def endpoint() do
@@ -34,7 +35,7 @@ defmodule IndieWeb.Micropub do
34 35
 
35 36
   def reserved_keyword?(key) do
36 37
     cond do
37
-      Enum.member?(@reserved_mp_param_keys, key) -> true
38
+      Enum.member?(@reserved_mp_param_keys ++ @micropub_stable_extensions, key) -> true
38 39
       String.starts_with?(key |> to_string, @micropub_action_prefix) -> true
39 40
       true -> false
40 41
     end

+ 50
- 40
lib/indieweb/micropub/content.ex View File

@@ -53,20 +53,14 @@ defmodule IndieWeb.Micropub.Content do
53 53
 
54 54
   # NOTE: Add support for detecting venue information.
55 55
   # NOTE: Add support for piping information to atlas.p3k.io
56
-  def process_property("location", value) when is_binary(value) do
57
-    cond do
58
-      String.starts_with?(value, "geo:") ->
59
-        %{parsed_path: geo_data} = URL.parse(value)
60
-
61
-        {:ok,
62
-         %{
63
-           lat: geo_data.lat,
64
-           lng: geo_data.lng
65
-         }}
66
-
67
-      true ->
68
-        {:ok, value}
69
-    end
56
+  def process_property("location", "geo:" <> _ = value) when is_binary(value) do
57
+    %{parsed_path: geo_data} = URL.parse(value)
58
+
59
+    {:ok,
60
+     %{
61
+       lat: geo_data.lat,
62
+       lng: geo_data.lng
63
+     }}
70 64
   end
71 65
 
72 66
   def process_property("location", [value]) when is_binary(value) do
@@ -178,32 +172,33 @@ defmodule IndieWeb.Micropub.Content do
178 172
     expand_property(name, [value], model)
179 173
   end
180 174
 
181
-  def expand_property(name, value, _model) when is_binary(value) and name in ~w(start end)s do
175
+  def expand_property(dt, value, _) when dt in ~w(start end) and is_binary(value) do
182 176
     options = [
183 177
       &Calendar.DateTime.Parse.rfc3339_utc/1,
184
-      &Calendar.DateTime.Parse.rfc2822_utc/1,
185 178
       &Calendar.DateTime.Parse.httpdate/1
186 179
     ]
187 180
 
188
-    Enum.find_value(options, fn option ->
189
-      try do
190
-        case option.(value) do
191
-          %DateTime{} = result -> {:ok, result}
192
-          _ -> false
193
-        end
194
-      rescue
195
-        _ -> {:ok, value}
196
-      catch
197
-        _ -> {:ok, value}
181
+    Enum.find_value(options, value, fn option ->
182
+      case option.(value) do
183
+        {:ok, %DateTime{}} = result ->
184
+          result
185
+
186
+        _ ->
187
+          false
198 188
       end
199 189
     end)
200 190
   end
201 191
 
202
-  def expand_property(name, values, _model) when is_list(values) and name in ~w(start end)s,
192
+  def expand_property(name, values, _) when is_list(values) and name in ~w(start end)s,
203 193
     do: expand_property(name, List.first(values), nil)
204 194
 
205
-  def expand_property(_name, value, _model) do
206
-    Logger.debug("Thunking on #{inspect(value)}...")
195
+  def expand_property(name, value, model) do
196
+    Logger.info("Thunking on expanding a property.",
197
+      name: name,
198
+      value: inspect(value),
199
+      model: model.id
200
+    )
201
+
207 202
     {:ok, value}
208 203
   end
209 204
 
@@ -241,7 +236,7 @@ defmodule IndieWeb.Micropub.Content do
241 236
   end
242 237
 
243 238
   def parse_extensions(model, properties) do
244
-    Logger.info("Scanning for extensions in #{inspect(properties)} for #{model.id}...")
239
+    Logger.info("Scanning for extensions...", entry_id: model.id, keys: Map.keys(properties))
245 240
 
246 241
     properties
247 242
     |> IndieWeb.Micropub.reserved()
@@ -260,31 +255,38 @@ defmodule IndieWeb.Micropub.Content do
260 255
           "post-status" => :post_status
261 256
         }
262 257
 
263
-        column_to_transform = %{
258
+        property_to_transform = %{
264 259
           "published" => fn
265
-            v when is_binary(v) -> Calendar.DateTime.Parse.rfc2822_utc(v)
266
-            [v] when is_binary(v) -> Calendar.DateTime.Parse.rfc2822_utc(v)
260
+            v when is_binary(v) -> Calendar.DateTime.Parse.rfc3339_utc(v) |> elem(1)
261
+            [v] when is_binary(v) -> Calendar.DateTime.Parse.rfc3339_utc(v) |> elem(1)
267 262
           end,
268 263
           "post-status" => fn v -> v end
269 264
         }
270 265
 
271 266
         column = property_to_column[property]
267
+        computed_value = property_to_transform[property].(value)
272 268
 
273
-        Logger.info("Applying expected property #{property} of #{value} to #{model.id}...")
269
+        Logger.info("Applying property to model directly.",
270
+          property: property,
271
+          value: inspect(value),
272
+          column: column,
273
+          computed_value: inspect(computed_value),
274
+          entry_id: model.id
275
+        )
274 276
 
275 277
         result =
276 278
           new_model
277
-          |> Ecto.Changeset.change(Map.put(%{}, column, column_to_transform[column].(value)))
279
+          |> Ecto.Changeset.change(Map.put(%{}, column, computed_value))
278 280
           |> Koype.Repo.update()
279 281
 
280 282
         case result do
281 283
           {:error, _} = error -> {:halt, error}
282
-          {:ok, updated_model} -> {:cont, {:ok, updated_model}}
284
+          {:ok, _} -> {:cont, result}
283 285
         end
284 286
 
285
-      {property, _}, {:ok, new_model} ->
287
+      {property, _}, acc ->
286 288
         Logger.info("Skipping over property #{property}...")
287
-        {:cont, {:ok, new_model}}
289
+        {:cont, acc}
288 290
     end)
289 291
   end
290 292
 
@@ -328,8 +330,16 @@ defmodule IndieWeb.Micropub.Content do
328 330
     end)
329 331
   end
330 332
 
331
-  defp do_parse_extension(extension_name, _, model) do
332
-    Logger.debug("Encountered unknown Micropub extension #{extension_name}; skipping.")
333
+  defp do_parse_extension("published", [date], model) when is_binary(date) do
334
+    case Calendar.DateTime.Parse.rfc2822_utc(date) do
335
+      {:ok, dt} -> Koype.Repo.Entry.update(model, dt)
336
+      _ -> {:ok, model}
337
+    end
338
+  end
339
+
340
+  defp do_parse_extension(extension_name, data, model) do
341
+    Logger.debug("Encountered an unknown extension.", extension: extension_name, data: inspect(data))
342
+
333 343
     {:ok, model}
334 344
   end
335 345
 

+ 12
- 16
lib/indieweb/micropub/entry.ex View File

@@ -280,15 +280,6 @@ defmodule IndieWeb.Micropub.Entry do
280 280
 
281 281
   defp do_enact_update_action(action, model, properties, action_data)
282 282
 
283
-  defp do_enact_update_action(action, _, _, action_data) when not is_map(action_data) do
284
-    Logger.warn("Attempted to remove a value incorrectly.",
285
-      action: action,
286
-      data: inspect(action_data)
287
-    )
288
-
289
-    {:error, key: action, error: :invalid_payload_for_action}
290
-  end
291
-
292 283
   defp do_enact_update_action("replace", model, properties, action_data)
293 284
        when is_map(action_data) do
294 285
     result =
@@ -389,6 +380,15 @@ defmodule IndieWeb.Micropub.Entry do
389 380
     end
390 381
   end
391 382
 
383
+  defp do_enact_update_action(action, _, _, action_data) do
384
+    Logger.warn("Attempted to remove a value incorrectly.",
385
+      action: action,
386
+      data: inspect(action_data)
387
+    )
388
+
389
+    {:error, key: action, action: :update, error: :invalid_payload_for_action}
390
+  end
391
+
392 392
   # TODO: Handle rollback cleanly if tx fails
393 393
   defp do_update_entry(model, scope: scope, params: params) do
394 394
     case Model.Json.find(model) do
@@ -433,13 +433,7 @@ defmodule IndieWeb.Micropub.Entry do
433 433
   end
434 434
 
435 435
   defp do_assoc_category_to_entry(model, %Koype.Repo.Category{} = record) do
436
-    preloaded_model = Koype.Repo.preload(model, :categories)
437
-    new_category_list = [record] ++ preloaded_model.categories
438
-
439
-    preloaded_model
440
-    |> Ecto.Changeset.change()
441
-    |> Ecto.Changeset.put_assoc(:categories, new_category_list)
442
-    |> Koype.Repo.update()
436
+    Koype.Repo.Entry.Category.bind(model, record)
443 437
   end
444 438
 
445 439
   defp do_assoc_category_to_entry(model, categories) when is_list(categories) do
@@ -457,6 +451,7 @@ defmodule IndieWeb.Micropub.Entry do
457 451
 
458 452
       case process_property(key, value) do
459 453
         {:error, error} -> {:halt, {:error, error}}
454
+        {:error, _, _} = error -> {:halt, {:error, [elem(error, 1), elem(error, 2)]}}
460 455
         {:ok, processed_value} -> {:cont, {:ok, Map.put(acc, key, processed_value)}}
461 456
       end
462 457
     end)
@@ -505,6 +500,7 @@ defmodule IndieWeb.Micropub.Entry do
505 500
         {:cont, {:ok, acc ++ [micro_mf2]}}
506 501
       else
507 502
         {:error, _} = error -> {:halt, error}
503
+        {:error, _, _} = error -> {:halt, error}
508 504
       end
509 505
     end)
510 506
   end

+ 9
- 2
lib/indieweb/micropub/query.ex View File

@@ -1,4 +1,5 @@
1 1
 defmodule IndieWeb.Micropub.Query do
2
+  require Logger
2 3
   alias Koype.Repo.Entry, as: Model
3 4
   def commands(), do: ~w(post-types syndicate-to media-endpoint config category)
4 5
 
@@ -90,10 +91,16 @@ defmodule IndieWeb.Micropub.Query do
90 91
         %{"properties" => properties, "type" => ["h-entry"]}
91 92
 
92 93
       {:error, _} = error ->
93
-        error
94
+        Logger.info("Failed to fetch JSON information for a model.",
95
+          model: model.id,
96
+          error: inspect(error)
97
+        )
98
+
99
+        nil
94 100
 
95 101
       {:ok, nil} ->
96
-        {:error, :entry_not_found}
102
+        Logger.warn("Missing JSON data of model.", model: model.id)
103
+        nil
97 104
     end
98 105
   end
99 106
 

+ 21
- 17
lib/indieweb/websub.ex View File

@@ -14,23 +14,27 @@ defmodule IndieWeb.WebSub do
14 14
   def notify!(urls) do
15 15
     payload = %{"hub.mode" => "publish", "hub.url" => urls} |> Plug.Conn.Query.encode()
16 16
 
17
-    case Koype.Http.post(hub_endpoint(),
18
-           body: payload,
19
-           headers: %{"Content-Type" => "application/x-www-form-urlencoded"}
20
-         ) do
21
-      {:ok, %Koype.Http.Response{code: 204, body: body}} ->
22
-        Enum.each(urls, fn url ->
23
-          Logger.info("WebSub publish action sent successfully.", url: url, body: body)
24
-        end)
25
-
26
-        :ok
27
-
28
-      error ->
29
-        Enum.each(urls, fn url ->
30
-          Logger.info("WebSub publish action failed.", url: url, error: inspect(error))
31
-        end)
32
-
33
-        error
17
+    if hub_endpoint() != nil do
18
+      case Koype.Http.post(hub_endpoint(),
19
+             body: payload,
20
+             headers: %{"Content-Type" => "application/x-www-form-urlencoded"}
21
+           ) do
22
+        {:ok, %Koype.Http.Response{code: 204, body: body}} ->
23
+          Enum.each(urls, fn url ->
24
+            Logger.info("WebSub publish action sent successfully.", url: url, body: body)
25
+          end)
26
+
27
+          :ok
28
+
29
+        error ->
30
+          Enum.each(urls, fn url ->
31
+            Logger.info("WebSub publish action failed.", url: url, error: inspect(error))
32
+          end)
33
+
34
+          error
35
+      end
36
+    else
37
+      Logger.warn("No WebSub endpoint was defined so no publish action will occur.", urls: urls)
34 38
     end
35 39
   end
36 40
 

+ 12
- 7
lib/job.ex View File

@@ -73,13 +73,18 @@ defmodule Koype.Job do
73 73
 
74 74
   @spec create(Executor.t(), keyword()) :: {:ok, __MODULE__.t()}
75 75
   def create(job_kind, args) do
76
-    job = %__MODULE__{args: args, name: job_kind.name(args), id: UUID.uuid4()}
77
-    Logger.info("Queuing job #{job.name}##{job.id}...")
78
-
79
-    task_args = [kind: job_kind, job: job]
80
-    {:ok, %Que.Job{id: que_job_id}} = Que.add(Koype.Job.Worker, task_args)
81
-    Koype.Cache.set("job:#{job.id}", que_job_id)
82
-    job
76
+    unless Mix.env() == :test do
77
+      job = %__MODULE__{args: args, name: job_kind.name(args), id: UUID.uuid4()}
78
+      Logger.info("Queuing job #{job.name}##{job.id}...")
79
+
80
+      task_args = [kind: job_kind, job: job]
81
+      {:ok, %Que.Job{id: que_job_id}} = Que.add(Koype.Job.Worker, task_args)
82
+      Koype.Cache.set("job:#{job.id}", que_job_id)
83
+      job
84
+    else
85
+      job_kind.execute(args)
86
+      %Koype.Job{}
87
+    end
83 88
   end
84 89
 
85 90
   def all() do

+ 1
- 1
lib/koype.ex View File

@@ -34,7 +34,7 @@ defmodule Koype do
34 34
 
35 35
   @spec version() :: binary()
36 36
   def version() do
37
-    "0.0.12"
37
+    Mix.Project.config()[:version]
38 38
   end
39 39
 
40 40
   @spec links() :: map()

+ 6
- 0
lib/mix.ex View File

@@ -0,0 +1,6 @@
1
+defmodule Koype.Mix do
2
+  def start() do
3
+    Koype.Application.load_runtime_config()
4
+    Mix.Task.run("app.start")
5
+  end
6
+end

+ 22
- 0
lib/mix/koype/restore_webmentions.ex View File

@@ -0,0 +1,22 @@
1
+defmodule Mix.Tasks.Koype.RestoreWebmentions do
2
+  use Mix.Task
3
+  require Logger
4
+
5
+  def run(_) do
6
+    Koype.Mix.start()
7
+
8
+    ExAws.S3.list_objects("koype-dev", prefix: "models/webmentions/")
9
+    |> ExAws.stream!()
10
+    |> Stream.map(&do_restore_webmention/1)
11
+    |> Stream.run()
12
+  end
13
+
14
+  defp do_restore_webmention(%{key: "models/webmentions/" <> id = json_path}) do
15
+    Logger.info(id |> String.replace(".json", "") |> String.replace("/model", ""))
16
+
17
+    ExAws.S3.get_object("koype-dev", json_path)
18
+    |> ExAws.request!()
19
+    |> Map.get(:body)
20
+    |> Jason.decode!()
21
+  end
22
+end

+ 4
- 4
lib/page.ex View File

@@ -97,15 +97,15 @@ defmodule Koype.Page do
97 97
   def fetch(url) do
98 98
     with(
99 99
       {:ok, %Koype.Http.Response{code: code}} when code < 499 <- Koype.Http.head(url),
100
-      {:ok, parsed_page} <- Koype.Page.Parser.resolve(url)
100
+      {:ok, parsed_page} <- Koype.Page.Parser.resolve(url),
101
+      res when is_map(res) <- Koype.Page.Parser.convert_to_mf2(parsed_page)
101 102
     ) do
102
-      mf2_json = Koype.Page.Parser.convert_to_mf2(parsed_page)
103
-      {:ok, mf2_json}
103
+      {:ok, res}
104 104
     else
105 105
       {:ok, %Koype.Http.Response{} = resp} ->
106 106
         {:error, :failed_to_check_page, reason: :status_code_not_handled, resp: resp}
107 107
 
108
-      error ->
108
+      error when is_tuple(error) ->
109 109
         {:error, :failed_to_fetch_page, reason: error}
110 110
     end
111 111
   end

+ 5
- 4
lib/page/parser.ex View File

@@ -141,16 +141,17 @@ defmodule Koype.Page.Parser do
141 141
   # TODO: Detect h-review.
142 142
   # TODO: Add media if any found.
143 143
   def convert_to_mf2(%Koype.Page.Structure{} = structure) do
144
-    required_params = ~w(name content author url)a
144
+    required_params = ~w(name url)a
145
+    missing_params = Enum.filter(required_params, &is_nil(Map.get(structure, &1)))
145 146
 
146
-    if Enum.all?(required_params, &Map.has_key?(structure, &1)) do
147
+    if missing_params == [] do
147 148
       %{
148 149
         "items" => [
149 150
           %{
150 151
             "type" => ["h-entry"],
151 152
             "properties" =>
152 153
               structure
153
-              |> Map.take(required_params)
154
+              |> Map.take(required_params ++ ~w(content author summary)a)
154 155
               |> Map.put(:category, structure.categories)
155 156
               |> do_import_media(:photo, structure)
156 157
               |> do_import_media(:video, structure)
@@ -162,7 +163,7 @@ defmodule Koype.Page.Parser do
162 163
         ]
163 164
       }
164 165
     else
165
-      {:error, :missing_required_field}
166
+      {:error, :missing_required_field, fields: missing_params}
166 167
     end
167 168
   end
168 169
 

+ 7
- 6
lib/page/parser/activitystreams2.ex View File

@@ -5,9 +5,8 @@ defmodule Koype.Page.ActivityStreams2Parser do
5 5
     Enum.find_value(Map.to_list(resp), fn
6 6
       {:body, html} ->
7 7
         case Floki.find(html, "link[type='application/activity+json'][rel=alternate]") do
8
-          [] -> false
9 8
           elem when not is_nil(elem) -> Floki.attribute(elem, "href") |> List.first()
10
-          _ -> false
9
+          _ -> nil
11 10
         end
12 11
 
13 12
       {:raw, raw} ->
@@ -40,10 +39,13 @@ defmodule Koype.Page.ActivityStreams2Parser do
40 39
   defp do_get_author(uri) do
41 40
     case IndieWeb.HCard.resolve(uri) do
42 41
       {:ok, author} ->
43
-        Map.merge(author, %{"type" => ["h-card"]})
42
+        author
44 43
 
45 44
       _ ->
46
-        uri
45
+        %{
46
+          "url" => uri,
47
+          "uid" => uri
48
+        }
47 49
     end
48 50
   end
49 51
 
@@ -94,8 +96,7 @@ defmodule Koype.Page.ActivityStreams2Parser do
94 96
            "text" => Koype.Content.to(:plain, as2_json["content"])
95 97
          },
96 98
          media: do_fetch_media_from_as2(as2_json),
97
-         name: as2_json["content"],
98
-         raw: as2_json
99
+         name: as2_json["content"]
99 100
        }}
100 101
     else
101 102
       error ->

+ 17
- 4
lib/page/parser/microformats2.ex View File

@@ -1,5 +1,6 @@
1 1
 defmodule Koype.Page.Microformats2Parser do
2 2
   @moduledoc false
3
+  require Logger
3 4
 
4 5
   # TODO: Check if a top-level `h-` element exists on the site.
5 6
   # TODO: Move this checking logic into the IndieWeb library.
@@ -14,10 +15,21 @@ defmodule Koype.Page.Microformats2Parser do
14 15
     end
15 16
   end
16 17
 
18
+  defp do_fetch_first_format(mf2) do
19
+    Enum.find_value(~w(feed event entry card), fn type ->
20
+      Logger.info("Scanning for a 'h-#{type}'..")
21
+
22
+      case Microformats2.Utility.get_format(mf2, type) do
23
+        mf2 when is_map(mf2) -> mf2
24
+        _ -> nil
25
+      end
26
+    end)
27
+  end
28
+
17 29
   def parse(%Koype.Http.Response{body: body, url: url}) do
18 30
     with(
19 31
       mf2 when is_map(mf2) <- Microformats2.parse(body, url),
20
-      entry_mf2 when is_map(entry_mf2) <- Microformats2.Utility.get_format(mf2, :entry)
32
+      entry_mf2 when is_map(entry_mf2) <- do_fetch_first_format(mf2)
21 33
     ) do
22 34
       properties = entry_mf2[:properties]
23 35
 
@@ -25,9 +37,9 @@ defmodule Koype.Page.Microformats2Parser do
25 37
        %Koype.Page.Structure{
26 38
          name: Map.get(properties, :name, []) |> List.first(),
27 39
          url: Map.get(properties, :url, [url]),
28
-         content: properties[:content] |> List.first(),
40
+         content: Map.get(properties, :content, [%{}]) |> List.first(),
29 41
          summary: Map.get(properties, :summary, []) |> List.first(),
30
-         author: do_resolve_author(properties[:author]),
42
+         author: do_resolve_author(properties[:author] || url),
31 43
          media: [photo: properties[:photo], video: properties[:video], audio: properties[:audio]],
32 44
          categories: properties[:category],
33 45
          raw: entry_mf2
@@ -43,7 +55,7 @@ defmodule Koype.Page.Microformats2Parser do
43 55
   defp do_resolve_author(author_url) when is_binary(author_url) do
44 56
     case IndieWeb.HCard.resolve(author_url) do
45 57
       {:ok, author} -> author
46
-      _ -> author_url
58
+      _ -> %{url: author_url, uid: author_url}
47 59
     end
48 60
   end
49 61
 
@@ -53,4 +65,5 @@ defmodule Koype.Page.Microformats2Parser do
53 65
 
54 66
   # TODO: Resolve current author from page.
55 67
   defp do_resolve_author(hcards) when is_list(hcards), do: do_resolve_author(List.first(hcards))
68
+  defp do_resolve_author(nil), do: nil
56 69
 end

+ 2
- 1
lib/repo.ex View File

@@ -35,7 +35,8 @@ defmodule Koype.Repo do
35 35
   end
36 36
 
37 37
   def find_in_column(query, column, value) do
38
-    from(q in query, where: ilike(^Map.get(query, column), ^value))
38
+    like_str = "%#{value}%"
39
+    from(q in query, where: like(^Apex.ap(Map.get(query, column)), ^like_str))
39 40
   end
40 41
 
41 42
   @spec find_by_columns(schema :: Ecto.Schema.t(), value :: String.t(), columns :: Keyword.t()) ::

+ 0
- 10
lib/repo/category.ex View File

@@ -72,16 +72,6 @@ defmodule Koype.Repo.Category do
72 72
     |> Koype.Repo.find_in_column(:name, name)
73 73
     |> Koype.Repo.all()
74 74
   end
75
-
76
-  @spec entries(category :: %__MODULE__{}) :: list(%__MODULE__{})
77
-  def entries(category) do
78
-    Koype.Repo.Entry
79
-    |> Ecto.Query.join(:left, [e], c in assoc(e, :categories))
80
-    |> Koype.Repo.undeleted()
81
-    |> Ecto.Query.where([e, c], c.id == ^category.id)
82
-    |> Koype.Repo.Entry.published()
83
-    |> Koype.Repo.all()
84
-  end
85 75
 end
86 76
 
87 77
 defimpl Jason.Encoder, for: Koype.Repo.Category do

+ 1
- 0
lib/repo/entry.ex View File

@@ -39,6 +39,7 @@ defmodule Koype.Repo.Entry do
39 39
     field(:deleted_at, :utc_datetime, default: nil, null: true)
40 40
     field(:published_at, :utc_datetime, default: nil, null: true)
41 41
     field(:post_status, :string, default: "published", null: false)
42
+    field(:visibility, :string, default: nil, virtual: true)
42 43
 
43 44
     many_to_many(:categories, Category, join_through: "entries_categories", on_delete: :nothing)
44 45
     has_many(:syndication_results, Koype.Repo.Entry.SyndicationResult)

+ 31
- 0
lib/repo/entry/category.ex View File

@@ -0,0 +1,31 @@
1
+defmodule Koype.Repo.Entry.Category do
2
+  @moduledoc false
3
+  require Ecto.Query
4
+  use Koype.Repo.Base
5
+
6
+  schema "entries_categories" do
7
+    belongs_to(:entry, Koype.Repo.Entry)
8
+    belongs_to(:category, Koype.Repo.Category)
9
+  end
10
+
11
+  # TODO: Do upsert.
12
+  def bind(model, record) do
13
+    preloaded_model = Koype.Repo.preload(model, :categories)
14
+    new_category_list = [record] ++ preloaded_model.categories
15
+
16
+    preloaded_model
17
+    |> Ecto.Changeset.change()
18
+    |> Ecto.Changeset.put_assoc(:categories, new_category_list)
19
+    |> Koype.Repo.update()
20
+  end
21
+
22
+  # NOTE: This query doesn't feel right.
23
+  def find_for(category) do
24
+    __MODULE__
25
+    |> Ecto.Query.where(category_id: ^category.id)
26
+    |> Ecto.Query.join(:inner, [category], e in assoc(category, :entry))
27
+    |> Ecto.Query.select([category], category.entry_id)
28
+    |> Koype.Repo.all()
29
+    |> Enum.map(&Koype.Repo.Entry.get/1)
30
+  end
31
+end

+ 18
- 10
lib/repo/entry/syndication_result.ex View File

@@ -34,21 +34,29 @@ defmodule Koype.Repo.Entry.SyndicationResult do
34 34
           {:ok, Koype.Repo.Syndication.Result.t()} | {:error, any()}
35 35
   def upsert(%Koype.Repo.Entry{} = entry, %Koype.Repo.Syndication.Target{} = target, args) do
36 36
     case find(entry, target) do
37
-      nil -> create(entry, target, args)
38
-      result -> Koype.Repo.Syndication.Result.update(result.result, args)
37
+      nil ->
38
+        create(entry, target, args)
39
+
40
+      result ->
41
+        result
42
+        |> Koype.Repo.preload([:result])
43
+        |> Map.get(:result)
44
+        |> Koype.Repo.Syndication.Result.update(args)
39 45
     end
40 46
   end
41 47
 
42 48
   @spec find(Koype.Repo.Entry.t(), Koype.Repo.Syndication.Target.t()) ::
43 49
           Koype.Repo.Syndication.Result.t() | nil
44 50
   def find(entry, target) do
45
-    entry
46
-    |> Koype.Repo.preload(:syndication_results)
47
-    |> Map.get(:syndication_results)
48
-    |> Enum.map(&Koype.Repo.preload(&1, ~w(source result)a))
49
-    |> Enum.find(fn result ->
50
-      result.source.id == entry.id and result.result.target_id == target.id
51
-    end)
51
+    Koype.Repo.Entry.SyndicationResult
52
+    |> Ecto.Query.join(:inner, [s], result in Koype.Repo.Syndication.Result)
53
+    |> Ecto.Query.join(:inner, [s], source in Koype.Repo.Entry)
54
+    |> Ecto.Query.where(
55
+      [s, result, source],
56
+      result.target_id == ^target.id and source.id == ^entry.id
57
+    )
58
+    |> Ecto.Query.limit(1)
59
+    |> Koype.Repo.one()
52 60
   end
53 61
 
54 62
   @spec create(Koype.Repo.Entry.t(), Koype.Repo.Syndication.Target.t(), map()) ::
@@ -75,7 +83,7 @@ defmodule Koype.Repo.Entry.SyndicationResult do
75 83
   end
76 84
 
77 85
   def status(expected_status) do
78
-    Ecto.Query.where(all(), [s, result], result.status != ^expected_status)
86
+    Ecto.Query.where(all(), [s, result], result.status == ^expected_status)
79 87
   end
80 88
 
81 89
   def status_not(expected_status) do

+ 3
- 0
lib/repo/entry/visibility.ex View File

@@ -0,0 +1,3 @@
1
+defmodule Koype.Repo.Entry.Visibility do
2
+  defstruct [:level]
3
+end

+ 5
- 1
lib/repo/otp_secret.ex View File

@@ -18,6 +18,7 @@
18 18
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
19 19
 defmodule Koype.Repo.OtpSecret do
20 20
   use Koype.Repo.Base
21
+  require Ecto.Query
21 22
 
22 23
   @moduledoc "Logic for OTP secrets."
23 24
   @secret_age 60 * 60 * 24 * 30
@@ -62,7 +63,7 @@ defmodule Koype.Repo.OtpSecret do
62 63
     today = DateTime.utc_now()
63 64
 
64 65
     __MODULE__
65
-    |> Ecto.Query.where([otp], otp.expired_at >= ^today)
66
+    |> Ecto.Query.where([otp], otp.expired_at > ^today)
66 67
     |> Ecto.Query.order_by(desc: :expired_at)
67 68
     |> Ecto.Query.limit(1)
68 69
     |> Koype.Repo.one()
@@ -102,7 +103,10 @@ defmodule Koype.Repo.OtpSecret do
102 103
   def valid?(_, _), do: false
103 104
 
104 105
   def last() do
106
+    now = DateTime.utc_now()
107
+
105 108
     __MODULE__
109
+    |> Ecto.Query.where([otp], otp.expired_at <= ^now)
106 110
     |> Ecto.Query.order_by(desc: :expired_at)
107 111
     |> Ecto.Query.limit(1)
108 112
     |> Koype.Repo.one()

+ 3
- 1
lib/webmention.ex View File

@@ -20,6 +20,7 @@ defmodule Koype.Webmention do
20 20
   @moduledoc false
21 21
 
22 22
   require Koype.Http
23
+  require Ecto.Query
23 24
   require Logger
24 25
 
25 26
   defmodule URIAdapter do
@@ -186,7 +187,8 @@ defmodule Koype.Webmention do
186 187
   defp do_deletion_of_webmention(args) do
187 188
     _mentions =
188 189
       Koype.Repo.Webmention
189
-      |> Koype.Repo.all(source: args[:source], target: args[:target_url])
190
+      |> Ecto.Query.where(source: ^args[:source], target: ^args[:target_url])
191
+      |> Koype.Repo.all()
190 192
       |> Enum.map(&Koype.Repo.delete(&1))
191 193
 
192 194
     Logger.warn("Dropped all relating Webmentions from the database.",

+ 5
- 10
mix.exs View File

@@ -28,6 +28,7 @@ defmodule Koype.Mixfile do
28 28
       version: @version,
29 29
       elixir: "~> 1.7",
30 30
       elixirc_paths: elixirc_paths(Mix.env()),
31
+      elixirc_options: [warnings_as_errors: true],
31 32
       compilers: [:phoenix, :gettext, :phoenix_swagger] ++ Mix.compilers(),
32 33
       start_permanent: Mix.env() == :prod,
33 34
       aliases: aliases(),
@@ -55,7 +56,8 @@ defmodule Koype.Mixfile do
55 56
         logo: "priv/static/images/logo.png",
56 57
         extras: Path.wildcard("docs/*.markdown"),
57 58
         main: "koype",
58
-        output: "priv/static/doc"
59
+        output: "priv/static/doc",
60
+        groups_for_extras: []
59 61
       ]
60 62
     ]
61 63
   end
@@ -63,23 +65,16 @@ defmodule Koype.Mixfile do
63 65
   def application do
64 66
     [
65 67
       mod: {Koype.Application, []},
66
-      extra_applications: [
67
-        :sasl,
68
-        :logger,
69
-        :runtime_tools,
68
+      extra_applications: [:logger, :runtime_tools, :cachex, :que, :arc],
69
+      included_applications: [
70 70
         :scrivener_ecto,
71 71
         :confex,
72 72
         :corsica,
73 73
         :indieweb,
74 74
         :httpotion,
75
-        :mime,
76
-        :cachex,
77 75
         :phoenix_ecto,
78 76
         :phoenix,
79
-        :arc,
80
-        :arc_ecto,
81 77
         :logster,
82
-        :que,
83 78
         :liquid,
84 79
         :readability
85 80
       ]

+ 9
- 9
priv/themes/default/tmpl/follow.html.liquid View File

@@ -71,7 +71,7 @@
71 71
             <ul class="lh-copy f5 ma0 pa0">
72 72
               {% for type in feed.types %}
73 73
               <li class="lh-copy">
74
-                <a class="color-inherit dim"
74
+                <a class="color-inherit dim" rel="feed"
75 75
                   href="/feeds/{{ format }}?type={{ type }}">
76 76
                   {{ feed.names|map_get:type }}
77 77
                 </a>
@@ -93,17 +93,17 @@
93 93
           <a class="color-inherit" href="https://indieweb.org/reader">reader</a>
94 94
           of choice and you'll be set!
95 95
           <ul class="lh-copy f5 ma0 mv2 pa0">
96
-            <li><a class="color-inherit" href="{% route stream.all %}">Everything</a></li>
97
-            <li><a class="color-inherit" href="{% route stream.article
96
+            <li><a rel="feed" class="color-inherit" href="{% route stream.all %}">Everything</a></li>
97
+            <li><a rel="feed" class="color-inherit" href="{% route stream.article
98 98
                 %}">Articles</a></li>
99
-            <li><a class="color-inherit" href="{% route stream.note %}">Notes</a></li>
100
-            <li><a class="color-inherit" href="{% route stream.responses
99
+            <li><a rel="feed" class="color-inherit" href="{% route stream.note %}">Notes</a></li>
100
+            <li><a rel="feed" class="color-inherit" href="{% route stream.responses
101 101
                 %}">Responses</a></li>
102
-            <li><a class="color-inherit" href="{% route stream.like %}">Likes</a></li>
103
-            <li><a class="color-inherit" href="{% route stream.rsvp %}">RSVPs</a></li>
104
-            <li><a class="color-inherit" href="{% route stream.checkin
102
+            <li><a rel="feed" class="color-inherit" href="{% route stream.like %}">Likes</a></li>
103
+            <li><a rel="feed" class="color-inherit" href="{% route stream.rsvp %}">RSVPs</a></li>
104
+            <li><a rel="feed" class="color-inherit" href="{% route stream.checkin
105 105
                 %}">Check-ins</a></li>
106
-            <li><a class="color-inherit" href="{% route stream.event %}">Events</a></li>
106
+            <li><a rel="feed" class="color-inherit" href="{% route stream.event %}">Events</a></li>
107 107
           </ul>
108 108
         </dd>
109 109
       </dl>

+ 3
- 4
test/features/settings.feature View File

@@ -57,8 +57,7 @@ Feature: Settings
57 57
     Given Koype is fully set-up
58 58
     And I am logged into Koype as an owner
59 59
     And I navigate to "/~/settings?component=relme"
60
-    And I set "input[name=uri]" to "https://fake.test/rel-me-site"
60
+    And I set "input[name=uri]" to "https://black.af"
61 61
 
62
-    When I submit the form under a network stub called "settings-relme-add-verified-link"
63
-    Then I see the text "Fake Request - Verified Link" on the page
64
-    Then I see the text "https://fake.test"
62
+    When I submit the form
63
+    Then I see the text "https://black.af"

+ 6
- 20
test/fixtures/vcr_cassettes/contact_from_homepage.json
File diff suppressed because it is too large
View File


+ 5
- 35
test/fixtures/vcr_cassettes/contact_import_hcard.json View File

@@ -2,41 +2,11 @@
2 2
   {
3 3
     "request": {
4 4
       "body": "",
5
-      "headers": [],
6
-      "method": "get",
7
-      "options": {
8
-        "ssl_options": {
9
-          "server_name_indication": [
10
-            115,
11
-            116,
12
-            97,
13
-            116,
14
-            105,
15
-            99,
16
-            45,
17
-            114,
18
-            101,
19
-            108,
20
-            109,
21
-            101,
22
-            45,
23
-            115,
24
-            105,
25
-            116,
26
-            101,
27
-            46,
28
-            106,
29
-            97,
30
-            99,
31
-            107,
32
-            121,
33
-            46,
34
-            119,
35
-            116,
36
-            102
37
-          ]
38
-        }
5
+      "headers": {
6
+        "user-agent": "IndieWeb-Elixir/0.0.42 (https://git.jacky.wtf/indieweb/elixir)"
39 7
       },
8
+      "method": "get",
9
+      "options": [],
40 10
       "request_body": "",
41 11
       "url": "https://static-relme-site.jacky.wtf"
42 12
     },
@@ -44,7 +14,7 @@
44 14
       "binary": false,
45 15
       "body": "<!DOCTYPE html>\n<html lang=\"en\">\n  <title> </title>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <link rel=\"stylesheet\" href=\"https://unpkg.com/tachyons/css/tachyons.min.css\">\n  <link rel=\"me\" href=\"https://github.com/jalcine\">\n  <body class=\"flex flex-row items-center justify-center vh-100\">\n    <header class=\"tc pv4 pv5-ns h-card\">\n      <img src=\"/me.jpeg\" class=\"br3 ba b--black-10 h-auto w-auto u-photo\" alt=\"avatar\">\n      <h1 class=\"p-name f5 f4-ns fw6 black-70\">Anthony Edward Stark</h1>\n      <h2 class=\"p-location h-adr f6 black-70 fw2 ttu tracked\">\n        <span class=\"p-locality\">Malibu</span>,\n        <span class=\"p-country-name\">United States of America</span>\n      </h2>\n    </header>\n  </body>\n</html>\n",
46 16
       "headers": {
47
-        "Date": "Thu, 07 Mar 2019 23:04:16 GMT",
17
+        "Date": "Mon, 15 Apr 2019 00:08:32 GMT",
48 18
         "Content-Type": "text/html",
49 19
         "Content-Length": "751",
50 20
         "Connection": "keep-alive",

+ 7
- 24
test/fixtures/vcr_cassettes/fails_to_fetch_due_to_network_error.json View File

@@ -3,26 +3,10 @@
3 3
     "request": {
4 4
       "body": "",
5 5
       "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7 7
       },
8 8
       "method": "get",
9
-      "options": {
10
-        "ssl_options": {
11
-          "server_name_indication": [
12
-            104,
13
-            116,
14
-            116,
15
-            112,
16
-            98,
17
-            105,
18
-            110,
19
-            46,
20
-            111,
21
-            114,
22
-            103
23
-          ]
24
-        }
25
-      },
9
+      "options": [],
26 10
       "request_body": "",
27 11
       "url": "https://httpbin.org/status/404"
28 12
     },
@@ -30,14 +14,13 @@
30 14
       "binary": false,
31 15
       "body": "",
32 16
       "headers": {
33
-        "Connection": "keep-alive",
34
-        "Server": "gunicorn/19.9.0",
35
-        "Date": "Mon, 04 Feb 2019 01:34:08 GMT",
36
-        "Content-Type": "text/html; charset=utf-8",
37
-        "Access-Control-Allow-Origin": "*",
38 17
         "Access-Control-Allow-Credentials": "true",
18
+        "Access-Control-Allow-Origin": "*",
19
+        "Content-Type": "text/html; charset=utf-8",
20
+        "Date": "Mon, 15 Apr 2019 00:08:02 GMT",
21
+        "Server": "nginx",
39 22
         "Content-Length": "0",
40
-        "Via": "1.1 vegur"
23
+        "Connection": "keep-alive"
41 24
       },
42 25
       "status_code": 404,
43 26
       "type": "ok"

+ 7
- 24
test/fixtures/vcr_cassettes/fails_to_fetch_due_to_server_error.json View File

@@ -3,26 +3,10 @@
3 3
     "request": {
4 4
       "body": "",
5 5
       "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7 7
       },
8 8
       "method": "get",
9
-      "options": {
10
-        "ssl_options": {
11
-          "server_name_indication": [
12
-            104,
13
-            116,
14
-            116,
15
-            112,
16
-            98,
17
-            105,
18
-            110,
19
-            46,
20
-            111,
21
-            114,
22
-            103
23
-          ]
24
-        }
25
-      },
9
+      "options": [],
26 10
       "request_body": "",
27 11
       "url": "https://httpbin.org/status/500"
28 12
     },
@@ -30,14 +14,13 @@
30 14
       "binary": false,
31 15
       "body": "",
32 16
       "headers": {
33
-        "Connection": "keep-alive",
34
-        "Server": "gunicorn/19.9.0",
35
-        "Date": "Mon, 04 Feb 2019 01:34:09 GMT",
36
-        "Content-Type": "text/html; charset=utf-8",
37
-        "Access-Control-Allow-Origin": "*",
38 17
         "Access-Control-Allow-Credentials": "true",
18
+        "Access-Control-Allow-Origin": "*",
19
+        "Content-Type": "text/html; charset=utf-8",
20
+        "Date": "Mon, 15 Apr 2019 00:08:13 GMT",
21
+        "Server": "nginx",
39 22
         "Content-Length": "0",
40
-        "Via": "1.1 vegur"
23
+        "Connection": "keep-alive"
41 24
       },
42 25
       "status_code": 500,
43 26
       "type": "ok"

+ 4
- 21
test/fixtures/vcr_cassettes/fetch_from_page.json
File diff suppressed because it is too large
View File


+ 7
- 25
test/fixtures/vcr_cassettes/fetch_from_page_on_omnibear.json
File diff suppressed because it is too large
View File


+ 0
- 55
test/fixtures/vcr_cassettes/finds_hcard_from_authorship.json
File diff suppressed because it is too large
View File


+ 0
- 55
test/fixtures/vcr_cassettes/finds_hcard_from_homepage.json
File diff suppressed because it is too large
View File


+ 0
- 38
test/fixtures/vcr_cassettes/finds_hcards_from_authorship_2.json View File

@@ -1,38 +0,0 @@
1
-[
2
-  {
3
-    "request": {
4
-      "body": "",
5
-      "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
7
-      },
8
-      "method": "get",
9
-      "options": {
10
-        "ssl_options": {
11
-          "server_name_indication": [
12
-            97,
13
-            115,
14
-            99,
15
-            114,
16
-            97,
17
-            101,
18
-            117,
19
-            115,
20
-            46,
21
-            111,
22
-            114,
23
-            103
24
-          ]
25
-        }
26
-      },
27
-      "request_body": "",
28
-      "url": "https://ascraeus.org/link/down-the-rabbit-hole/"
29
-    },
30
-    "response": {
31
-      "binary": true,
32
-      "body": "g2wAAAACbQAAAAtjb25uX2ZhaWxlZGwAAAACbQAAAAVlcnJvcm0AAAANZWFkZHJub3RhdmFpbGpq",
33
-      "headers": [],
34
-      "status_code": null,
35
-      "type": "error"
36
-    }
37
-  }
38
-]

+ 0
- 45
test/fixtures/vcr_cassettes/finds_hcards_from_authorship_3.json View File

@@ -1,45 +0,0 @@
1
-[
2
-  {
3
-    "request": {
4
-      "body": "",
5
-      "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
7
-      },
8
-      "method": "get",
9
-      "options": {
10
-        "ssl_options": {
11
-          "server_name_indication": [
12
-            98,
13
-            114,
14
-            105,
15
-            100,
16
-            45,
17
-            103,
18
-            121,
19
-            46,
20
-            97,
21
-            112,
22
-            112,
23
-            115,
24
-            112,
25
-            111,
26
-            116,
27
-            46,
28
-            99,
29
-            111,
30
-            109
31
-          ]
32
-        }
33
-      },
34
-      "request_body": "",
35
-      "url": "https://brid-gy.appspot.com/repost/twitter/jackyalcine/1089056171779084288/1089126346092146688"
36
-    },
37
-    "response": {
38
-      "binary": true,
39
-      "body": "g2wAAAACbQAAAAtjb25uX2ZhaWxlZGwAAAACbQAAAAVlcnJvcm0AAAANZWFkZHJub3RhdmFpbGpq",
40
-      "headers": [],
41
-      "status_code": null,
42
-      "type": "error"
43
-    }
44
-  }
45
-]

+ 0
- 72
test/fixtures/vcr_cassettes/generate_hcard_from_uri.json View File

@@ -1,72 +0,0 @@
1
-[
2
-  {
3
-    "request": {
4
-      "body": "",
5
-      "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
7
-      },
8
-      "method": "get",
9
-      "options": {
10
-        "ssl_options": {
11
-          "server_name_indication": [
12
-            119,
13
-            119,
14
-            119,
15
-            46,
16
-            109,
17
-            111,
18
-            122,
19
-            105,
20
-            108,
21
-            108,
22
-            97,
23
-            46,
24
-            111,
25
-            114,
26
-            103
27
-          ]
28
-        }
29
-      },
30
-      "request_body": "",
31
-      "url": "https://www.mozilla.org/firefox/new/?redirect_source=firefox-com"
32
-    },
33
-    "response": {
34
-      "binary": true,
35
-      "body": "g2wAAAACbQAAAAtjb25uX2ZhaWxlZGwAAAACbQAAAAVlcnJvcm0AAAANZWFkZHJub3RhdmFpbGpq",
36
-      "headers": [],
37
-      "status_code": null,
38
-      "type": "error"
39
-    }
40
-  },
41
-  {
42
-    "request": {
43
-      "body": "",
44
-      "headers": {
45
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
46
-      },
47
-      "method": "get",
48
-      "options": [],
49
-      "request_body": "",
50
-      "url": "http://firefox.com"
51
-    },
52
-    "response": {
53
-      "binary": false,
54
-      "body": "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>301 Moved Permanently</title>\n</head><body>\n<h1>Moved Permanently</h1>\n<p>The document has moved <a href=\"https://www.mozilla.org/firefox/new/?redirect_source=firefox-com\">here</a>.</p>\n</body></html>\n",
55
-      "headers": {
56
-        "Server": "Apache/2.4.6 (CentOS)",
57
-        "X-Backend-Server": "redirect1.webapp.mdc1.mozilla.com",
58
-        "Cache-Control": "max-age=300",
59
-        "Content-Type": "text/html; charset=iso-8859-1",
60
-        "Date": "Fri, 08 Feb 2019 02:32:59 GMT",
61
-        "Location": "https://www.mozilla.org/firefox/new/?redirect_source=firefox-com",
62
-        "Keep-Alive": "timeout=5, max=100",
63
-        "Accept-Ranges": "bytes",
64
-        "Connection": "Keep-Alive",
65
-        "X-Cache-Info": "cached",
66
-        "Content-Length": "272"
67
-      },
68
-      "status_code": 301,
69
-      "type": "ok"
70
-    }
71
-  }
72
-]

+ 0
- 47
test/fixtures/vcr_cassettes/http_fetch_page_success.json
File diff suppressed because it is too large
View File


+ 0
- 40
test/fixtures/vcr_cassettes/indieweb_syndication_endpoint_failure.json View File

@@ -1,40 +0,0 @@
1
-[
2
-  {
3
-    "request": {
4
-      "body": "",
5
-      "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
7
-      },
8
-      "method": "get",
9
-      "options": [],
10
-      "request_body": "",
11
-      "url": "http://test.example.faker/endpoint"
12
-    },
13
-    "response": {
14
-      "binary": true,
15
-      "body": "g2wAAAACbQAAAAtjb25uX2ZhaWxlZGwAAAACbQAAAAVlcnJvcm0AAAAIbnhkb21haW5qag==",
16
-      "headers": [],
17
-      "status_code": null,
18
-      "type": "error"
19
-    }
20
-  },
21
-  {
22
-    "request": {
23
-      "body": "",
24
-      "headers": {
25
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
26
-      },
27
-      "method": "head",
28
-      "options": [],
29
-      "request_body": "",
30
-      "url": "http://test.example.faker/endpoint"
31
-    },
32
-    "response": {
33
-      "binary": true,
34
-      "body": "g2wAAAACbQAAAAtjb25uX2ZhaWxlZGwAAAACbQAAAAVlcnJvcm0AAAAIbnhkb21haW5qag==",
35
-      "headers": [],
36
-      "status_code": null,
37
-      "type": "error"
38
-    }
39
-  }
40
-]

+ 0
- 45
test/fixtures/vcr_cassettes/indieweb_syndication_endpoint_success.json View File

@@ -1,45 +0,0 @@
1
-[
2
-  {
3
-    "request": {
4
-      "body": "",
5
-      "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
7
-      },
8
-      "method": "head",
9
-      "options": [],
10
-      "request_body": "",
11
-      "url": "http://test.example.faker/endpoint"
12
-    },
13
-    "response": {
14
-      "binary": false,
15
-      "body": "",
16
-      "headers": {
17
-        "link": "<http://test.example.faker>; rel=webmention"
18
-      },
19
-      "status_code": 200,
20
-      "type": "ok"
21
-    }
22
-  },
23
-  {
24
-    "request": {
25
-      "body": "",
26
-      "headers": {
27
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)",
28
-        "content-type": "application/x-www-form-urlencoded"
29
-      },
30
-      "method": "post",
31
-      "options": [],
32
-      "request_body": "",
33
-      "url": "http://test.example.faker"
34
-    },
35
-    "response": {
36
-      "binary": false,
37
-      "body": "{\"url\":\"http://test.example.faker\/result\"}",
38
-      "headers": {
39
-        "link": "<http://test.example.faker>; rel=webmention"
40
-      },
41
-      "status_code": 200,
42
-      "type": "ok"
43
-    }
44
-  }
45
-]

+ 90
- 0
test/fixtures/vcr_cassettes/micropub_entry_process_property_response_type.json View File

@@ -0,0 +1,90 @@
1
+[
2
+  {
3
+    "request": {
4
+      "body": "",
5
+      "headers": {
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7
+      },
8
+      "method": "get",
9
+      "options": [],
10
+      "request_body": "",
11
+      "url": "https://raw.githubusercontent.com/microformats/tests/master/tests/microformats-v2/h-entry/urlincontent.html"
12
+    },
13
+    "response": {
14
+      "binary": false,
15
+      "body": "<div class=\"h-entry\">\n    <h1><a class=\"p-name\">Expanding URLs within HTML content</a></h1>\n    <div class=\"e-content\">\n        <ul>\n            <li><a href=\"http://www.w3.org/\">Should not change: http://www.w3.org/</a></li>\n            <li><a href=\"http://example.com/\">Should not change: http://example.com/</a></li>\n            <li><a href=\"test.html\">File relative: test.html = http://example.com/test.html</a></li>\n            <li><a href=\"/test/test.html\">Directory relative: /test/test.html = http://example.com/test/test.html</a></li>\n            <li><a href=\"/test.html\">Relative to root: /test.html = http://example.com/test.html</a></li>\n        </ul>\n        <img src=\"images/photo.gif\" />\n    </div>  \n</div>",
16
+      "headers": {
17
+        "Content-Security-Policy": "default-src 'none'; style-src 'unsafe-inline'; sandbox",
18
+        "Strict-Transport-Security": "max-age=31536000",
19
+        "X-Content-Type-Options": "nosniff",
20
+        "X-Frame-Options": "deny",
21
+        "X-XSS-Protection": "1; mode=block",
22
+        "ETag": "\"61acaf9e7bc8a10d662dc7f5582e55296ca37b20\"",
23
+        "Content-Type": "text/plain; charset=utf-8",
24
+        "Cache-Control": "max-age=300",
25
+        "X-Geo-Block-List": "",
26
+        "X-GitHub-Request-Id": "3A0E:2B3C:B98B16:C9A8FE:5CB3CB03",
27
+        "Content-Length": "721",
28
+        "Accept-Ranges": "bytes",
29
+        "Date": "Mon, 15 Apr 2019 00:07:51 GMT",
30
+        "Via": "1.1 varnish",
31
+        "Connection": "keep-alive",
32
+        "X-Served-By": "cache-bur17525-BUR",
33
+        "X-Cache": "HIT",
34
+        "X-Cache-Hits": "4",
35
+        "X-Timer": "S1555286871.089169,VS0,VE0",
36
+        "Vary": "Authorization,Accept-Encoding",
37
+        "Access-Control-Allow-Origin": "*",
38
+        "X-Fastly-Request-ID": "f1e1f4e8a7dafe81eee325af8cd1187b34d246f5",
39
+        "Expires": "Mon, 15 Apr 2019 00:12:51 GMT",
40
+        "Source-Age": "84"
41
+      },
42
+      "status_code": 200,
43
+      "type": "ok"
44
+    }
45
+  },
46
+  {
47
+    "request": {
48
+      "body": "",
49
+      "headers": {
50
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
51
+      },
52
+      "method": "head",
53
+      "options": [],
54
+      "request_body": "",
55
+      "url": "https://raw.githubusercontent.com/microformats/tests/master/tests/microformats-v2/h-entry/urlincontent.html"
56
+    },
57
+    "response": {
58
+      "binary": false,
59
+      "body": null,
60
+      "headers": {
61
+        "Content-Security-Policy": "default-src 'none'; style-src 'unsafe-inline'; sandbox",
62
+        "Strict-Transport-Security": "max-age=31536000",
63
+        "X-Content-Type-Options": "nosniff",
64
+        "X-Frame-Options": "deny",
65
+        "X-XSS-Protection": "1; mode=block",
66
+        "ETag": "\"61acaf9e7bc8a10d662dc7f5582e55296ca37b20\"",
67
+        "Content-Type": "text/plain; charset=utf-8",
68
+        "Cache-Control": "max-age=300",
69
+        "X-Geo-Block-List": "",
70
+        "X-GitHub-Request-Id": "3A0E:2B3C:B98B16:C9A8FE:5CB3CB03",
71
+        "Content-Length": "721",
72
+        "Accept-Ranges": "bytes",
73
+        "Date": "Mon, 15 Apr 2019 00:07:51 GMT",
74
+        "Via": "1.1 varnish",
75
+        "Connection": "keep-alive",
76
+        "X-Served-By": "cache-bur17525-BUR",
77
+        "X-Cache": "HIT",
78
+        "X-Cache-Hits": "3",
79
+        "X-Timer": "S1555286871.059456,VS0,VE0",
80
+        "Vary": "Authorization,Accept-Encoding",
81
+        "Access-Control-Allow-Origin": "*",
82
+        "X-Fastly-Request-ID": "94d311c76361425584e9d0bf4c34af1b816e6b1e",
83
+        "Expires": "Mon, 15 Apr 2019 00:12:51 GMT",
84
+        "Source-Age": "84"
85
+      },
86
+      "status_code": 200,
87
+      "type": "ok"
88
+    }
89
+  }
90
+]

+ 0
- 30
test/fixtures/vcr_cassettes/micropub_entry_process_propery_response_type.json View File

@@ -1,30 +0,0 @@
1
-[
2
-  {
3
-    "request": {
4
-      "body": "",
5
-      "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
7
-      },
8
-      "method": "get",
9
-      "options": [],
10
-      "request_body": "",
11
-      "url": "http://tantek.com/2019/023/f1"
12
-    },
13
-    "response": {
14
-      "binary": false,
15
-      "body": "<!DOCTYPE html><html><head><meta charset=\"utf-8\" />\n<title>Tantek likes Adam Dawkins’s note</title>\n<base href=\"http://tantek.com/2019/\" />\n<link rel=\"icon\" href=\"/logo.jpg\" />\n<meta name=\"viewport\" content=\"initial-scale=0.7\"/>\n<link rel=\"webmention\" href=\"http://webmention.io/tantek.com/webmention\" />\n<style type=\"text/css\">/*<![CDATA[*/ \n@import \"simple.css\";\nform.search { width:34%; float:right; white-space:nowrap; font-size:1.3em; text-align:right }\ninput,button { font-size:1em }\nbutton { margin: 0 0.5em 0 0; padding:0 0.5em }\nform.search input[type=search] { width:62% }\n/*]]>*/</style>\n<script type=\"text/javascript\" src=\"cassis.js\"></script>\n<script type=\"text/javascript\" src=\"../scripts/indieconfig.js\"></script> \n<script type=\"text/javascript\" src=\"../scripts/webaction.js\"></script>\n</head>\n<body class=\"post hentry h-entry as-like\">\n<header><div class=\"header\">\n<h1><a href=\"../\" rel=\"author home\">tantek.com</a></h1>\n\n<form class=\"search\" action=\"https://duckduckgo.com/html/\" method=\"get\">\n<input type=\"hidden\" name=\"type\" value=\"list\" />\n<input type=\"search\" value=\"site:tantek.com \" name=\"q\" />\n<button type=\"submit\">Search</button>\n</form>\n\n</div></header>\n\n<div class=\"sidestuff\">\n<ul class=\"snav\">\n<li><a href=\"023/t1/one-year-ago-w3c-indieauth-websub\" id=\"previtem\" title=\"View the previous (older) item in the stream.\" rel=\"prev\"><abbr>&#x2190;</abbr></a></li><li><a href=\"023/f2\" id=\"nextitem\" title=\"View the next (newer) item in the stream\" rel=\"next\"><abbr>&#x2192;</abbr></a></li>\n</ul>\n</div>\n<a href=\"../\" class=\"p-author h-card author-icon\" rel=\"author\" title=\"Tantek Çelik\"><img src=\"../logo.jpg\" alt=\"Tantek Çelik\" /></a>\n\n<p class=\"p-name p-summary article\">likes <a class=\"u-like-of\" href=\"https://adamdawkins.uk/2019/1/22/i-just-added-some-basic-auto-linking-to-notes-on-my-site-this-is-proof-stealing-heavily-from-kylewms-python-port-of-ts-cassis-autolink-i-ca\">Adam Dawkins’s note</a>\n (<a class=\"u-like-of\" href=\"https://twitter.com/adamdawkins/status/1087861135141949441\">@</a>)</p>\n<span class=\"info footer\">\n  <span class=\"dt-published published dt-updated updated\">\n  <time class=\"value\" datetime=\"18:51-0800\">18:51</time> on <time class=\"value\">2019-01-23</time>  </span>\n <span class=\"lt\">\n (ttk.me f/4ye1) </span>\n  using <span class=\"using\">BBEdit</span> </span> \n<div class=\"info footer\">\n<form action=\"http://tantek.com/2019/023/f1\"><div>\n<label><span class=\"lt\">URL:</span>\n<input class=\"u-url url u-uid uid bookmark\" type=\"url\" size=\"70\" style=\"max-width:100%\" value=\"http://tantek.com/2019/023/f1\" />\n</label>\n</div></form>\n</div>\n</li>\n<script type=\"text/javascript\">/*<![CDATA[*/\nfunction select_all(e) {\n e = e ? e : window.event;\n var el = targetelement(e);\n el.focus();\n /* el.select(); // fails in Mobile Safari */\n el.selectionStart=0;\n el.selectionEnd=el.value.length;\n}\n\nvar fs = document.forms, i = 0, j = 0, es;\nfor (i = 0; i<fs.length; i++) {\n  es = document.forms[i].elements;\n  if (es) {\n    for (j=0;j<es.length;j++) {\n      switch (es[j].type) {\n      case \"text\":\n      case \"url\":\n        es[j].onclick = select_all;\n      }\n    }\n  }\n}\n\n\ndocument.onkeyup = keyup;\n\nfunction clearactive() {\n  var e = document.getElementById(\"previtem\");\n  if (e) { e.className = \"\"; }\n  e = document.getElementById(\"nextitem\");\n  if (e) { e.className = \"\"; }\n}\n\nfunction keyup(e)\n{\n   var kid = (window.event) ? event.keyCode : e.keyCode;\n   var nid = \"\";\n   if (document.activeElement !== document.body) {\n     return;\n   }\n   switch(kid) {\n    case 33:\n    case 37:\n    case 74:\n      nid = \"previtem\";\n      break;\n    case 34:\n    case 39:\n    case 75:\n      nid = \"nextitem\";\n      break;\n   }\n   if (nid!=\"\") {\n      ne = document.getElementById(nid);\n      if (ne) {\n        ne.className = \"active\";\n        doevent(ne,\"click\");\n        window.onunload = clearactive;\n        return false;\n      }\n   }\n}\n\n/*]]>*/</script>\n<script src=\"/fragmention.min.js\"></script>\n</body>\n</html>\n",
16
-      "headers": {
17
-        "X-Powered-By": "PHP/5.4.44",
18
-        "Content-Type": "text/html; charset=UTF-8",
19
-        "Content-Security-Policy": "default-src 'self'; img-src *; media-src *; script-src 'self' 'unsafe-inline' https://platform.twitter.com; style-src 'self' 'unsafe-inline'; object-src https://indiewebcamp.com https://indieweb.org stream.thatmustbe.us; frame-src *; child-src *;",
20
-        "Content-Length": "3955",
21
-        "Date": "Mon, 04 Feb 2019 01:33:44 GMT",
22
-        "Server": "LiteSpeed",
23
-        "Vary": "User-Agent",
24
-        "Connection": "close"
25
-      },
26
-      "status_code": 200,
27
-      "type": "ok"
28
-    }
29
-  }
30
-]

+ 10
- 10
test/fixtures/vcr_cassettes/micropub_entry_send_webmention_passes.json View File

@@ -3,30 +3,30 @@
3 3
     "request": {
4 4
       "body": "",
5 5
       "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7 7
       },
8 8
       "method": "get",
9 9
       "options": [],
10 10
       "request_body": "",
11
-      "url": "http://objectstorage:9000/koype-test/models/entries/870df8e8-3107-4487-8316-81e089b8c2cf/model.json.json?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=access_minio%2F20190204%2Flocal%2Fs3%2Faws4_request&X-Amz-Date=20190204T013343Z&X-Amz-Expires=300&X-Amz-SignedHeaders=host&X-Amz-Signature=a847e8d382ca761db8947ed482c0b90ba80244de9a7b0a62cc13f7d480801abf"
11
+      "url": "http://objectstorage:9000/koype-test/models/entries/870df8e8-3107-4487-8316-81e089b8c2cf/model.json.json?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=access_minio%2F20190415%2Flocal%2Fs3%2Faws4_request&X-Amz-Date=20190415T000749Z&X-Amz-Expires=300&X-Amz-SignedHeaders=host&X-Amz-Signature=6ebbbafd47d6ef7971fc4655e90bd54113a9a46f461bfe99d2e41af6b9070aaa"
12 12
     },
13 13
     "response": {
14 14
       "binary": false,
15
-      "body": "{\"content\":{\"html\":[\"<p><a href='http://berge.com' class='h-card u-category'>Wow</a></p>\"],\"value\":[\"<a href='http://berge.com' class='h-card u-category'>Wow</a>\"]}}",
15
+      "body": "{\"content\":{\"html\":[\"<p><a href='http://johnson.info' class='h-card u-category'>Wow</a></p>\"],\"value\":[\"<a href='http://johnson.info' class='h-card u-category'>Wow</a>\"]}}",
16 16
       "headers": {
17 17
         "Accept-Ranges": "bytes",
18
-        "Content-Length": "165",
18
+        "Content-Length": "171",
19 19
         "Content-Security-Policy": "block-all-mixed-content",
20 20
         "Content-Type": "application/octet-stream",
21
-        "Etag": "\"a01aadbac849185bdf5c4237fa0e297a\"",
22
-        "Last-Modified": "Mon, 04 Feb 2019 01:33:42 GMT",
23
-        "Server": "Minio/RELEASE.2018-12-27T18-33-08Z (linux; amd64)",
21
+        "Etag": "\"f57ac45ba47ac0d13772fd89cb83f275\"",
22
+        "Last-Modified": "Mon, 15 Apr 2019 00:07:49 GMT",
23
+        "Server": "Minio/RELEASE.2019-03-27T22-35-21Z",
24 24
         "Vary": "Origin",
25 25
         "X-Amz-Bucket-Region": "local",
26
-        "X-Amz-Request-Id": "1580053B29A5CC97",
27
-        "X-Minio-Deployment-Id": "c92b2907-84fc-45f7-80fd-a50c0dd62808",
26
+        "X-Amz-Request-Id": "15957D2AF52147B6",
27
+        "X-Minio-Deployment-Id": "3127cc92-d6c9-49e3-b0da-ed8dc7bf6348",
28 28
         "X-Xss-Protection": "1; mode=block",
29
-        "Date": "Mon, 04 Feb 2019 01:33:43 GMT"
29
+        "Date": "Mon, 15 Apr 2019 00:07:49 GMT"
30 30
       },
31 31
       "status_code": 200,
32 32
       "type": "ok"

+ 90
- 0
test/fixtures/vcr_cassettes/micropub_entry_success_create.json View File

@@ -0,0 +1,90 @@
1
+[
2
+  {
3
+    "request": {
4
+      "body": "",
5
+      "headers": {
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7
+      },
8
+      "method": "get",
9
+      "options": [],
10
+      "request_body": "",
11
+      "url": "https://raw.githubusercontent.com/microformats/tests/master/tests/microformats-v2/h-entry/urlincontent.html"
12
+    },
13
+    "response": {
14
+      "binary": false,
15
+      "body": "<div class=\"h-entry\">\n    <h1><a class=\"p-name\">Expanding URLs within HTML content</a></h1>\n    <div class=\"e-content\">\n        <ul>\n            <li><a href=\"http://www.w3.org/\">Should not change: http://www.w3.org/</a></li>\n            <li><a href=\"http://example.com/\">Should not change: http://example.com/</a></li>\n            <li><a href=\"test.html\">File relative: test.html = http://example.com/test.html</a></li>\n            <li><a href=\"/test/test.html\">Directory relative: /test/test.html = http://example.com/test/test.html</a></li>\n            <li><a href=\"/test.html\">Relative to root: /test.html = http://example.com/test.html</a></li>\n        </ul>\n        <img src=\"images/photo.gif\" />\n    </div>  \n</div>",
16
+      "headers": {
17
+        "Content-Security-Policy": "default-src 'none'; style-src 'unsafe-inline'; sandbox",
18
+        "Strict-Transport-Security": "max-age=31536000",
19
+        "X-Content-Type-Options": "nosniff",
20
+        "X-Frame-Options": "deny",
21
+        "X-XSS-Protection": "1; mode=block",
22
+        "ETag": "\"61acaf9e7bc8a10d662dc7f5582e55296ca37b20\"",
23
+        "Content-Type": "text/plain; charset=utf-8",
24
+        "Cache-Control": "max-age=300",
25
+        "X-Geo-Block-List": "",
26
+        "X-GitHub-Request-Id": "3A0E:2B3C:B98B16:C9A8FE:5CB3CB03",
27
+        "Content-Length": "721",
28
+        "Accept-Ranges": "bytes",
29
+        "Date": "Mon, 15 Apr 2019 00:07:50 GMT",
30
+        "Via": "1.1 varnish",
31
+        "Connection": "keep-alive",
32
+        "X-Served-By": "cache-bur17525-BUR",
33
+        "X-Cache": "HIT",
34
+        "X-Cache-Hits": "2",
35
+        "X-Timer": "S1555286870.495937,VS0,VE0",
36
+        "Vary": "Authorization,Accept-Encoding",
37
+        "Access-Control-Allow-Origin": "*",
38
+        "X-Fastly-Request-ID": "7dae92a2e39abe4a4d1e6db19f8127d42a0937ed",
39
+        "Expires": "Mon, 15 Apr 2019 00:12:50 GMT",
40
+        "Source-Age": "83"
41
+      },
42
+      "status_code": 200,
43
+      "type": "ok"
44
+    }
45
+  },
46
+  {
47
+    "request": {
48
+      "body": "",
49
+      "headers": {
50
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
51
+      },
52
+      "method": "head",
53
+      "options": [],
54
+      "request_body": "",
55
+      "url": "https://raw.githubusercontent.com/microformats/tests/master/tests/microformats-v2/h-entry/urlincontent.html"
56
+    },
57
+    "response": {
58
+      "binary": false,
59
+      "body": null,
60
+      "headers": {
61
+        "Content-Security-Policy": "default-src 'none'; style-src 'unsafe-inline'; sandbox",
62
+        "Strict-Transport-Security": "max-age=31536000",
63
+        "X-Content-Type-Options": "nosniff",
64
+        "X-Frame-Options": "deny",
65
+        "X-XSS-Protection": "1; mode=block",
66
+        "ETag": "\"61acaf9e7bc8a10d662dc7f5582e55296ca37b20\"",
67
+        "Content-Type": "text/plain; charset=utf-8",
68
+        "Cache-Control": "max-age=300",
69
+        "X-Geo-Block-List": "",
70
+        "X-GitHub-Request-Id": "3A0E:2B3C:B98B16:C9A8FE:5CB3CB03",
71
+        "Content-Length": "721",
72
+        "Accept-Ranges": "bytes",
73
+        "Date": "Mon, 15 Apr 2019 00:07:50 GMT",
74
+        "Via": "1.1 varnish",
75
+        "Connection": "keep-alive",
76
+        "X-Served-By": "cache-bur17525-BUR",
77
+        "X-Cache": "HIT",
78
+        "X-Cache-Hits": "1",
79
+        "X-Timer": "S1555286870.455288,VS0,VE1",
80
+        "Vary": "Authorization,Accept-Encoding",
81
+        "Access-Control-Allow-Origin": "*",
82
+        "X-Fastly-Request-ID": "9158fb02ff628047f0ca55b272e850cf25145be8",
83
+        "Expires": "Mon, 15 Apr 2019 00:12:50 GMT",
84
+        "Source-Age": "83"
85
+      },
86
+      "status_code": 200,
87
+      "type": "ok"
88
+    }
89
+  }
90
+]

+ 56
- 0
test/fixtures/vcr_cassettes/page_fetch_no_title.json View File

@@ -0,0 +1,56 @@
1
+[
2
+  {
3
+    "request": {
4
+      "body": "",
5
+      "headers": {
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7
+      },
8
+      "method": "get",
9
+      "options": [],
10
+      "request_body": "",
11
+      "url": "https://httpbin.org/status/200"
12
+    },
13
+    "response": {
14
+      "binary": false,
15
+      "body": "",
16
+      "headers": {
17
+        "Access-Control-Allow-Credentials": "true",
18
+        "Access-Control-Allow-Origin": "*",
19
+        "Content-Type": "text/html; charset=utf-8",
20
+        "Date": "Mon, 15 Apr 2019 00:08:02 GMT",
21
+        "Server": "nginx",
22
+        "Content-Length": "0",
23
+        "Connection": "keep-alive"
24
+      },
25
+      "status_code": 200,
26
+      "type": "ok"
27
+    }
28
+  },
29
+  {
30
+    "request": {
31
+      "body": "",
32
+      "headers": {
33
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
34
+      },
35
+      "method": "head",
36
+      "options": [],
37
+      "request_body": "",
38
+      "url": "https://httpbin.org/status/200"
39
+    },
40
+    "response": {
41
+      "binary": false,
42
+      "body": null,
43
+      "headers": {
44
+        "Access-Control-Allow-Credentials": "true",
45
+        "Access-Control-Allow-Origin": "*",
46
+        "Content-Length": "0",
47
+        "Content-Type": "text/html; charset=utf-8",
48
+        "Date": "Mon, 15 Apr 2019 00:08:02 GMT",
49
+        "Server": "nginx",
50
+        "Connection": "keep-alive"
51
+      },
52
+      "status_code": 200,
53
+      "type": "ok"
54
+    }
55
+  }
56
+]

+ 76
- 0
test/fixtures/vcr_cassettes/page_fetch_success.json
File diff suppressed because it is too large
View File


+ 29
- 0
test/fixtures/vcr_cassettes/page_fetch_unreachable.json View File

@@ -0,0 +1,29 @@
1
+[
2
+  {
3
+    "request": {
4
+      "body": "",
5
+      "headers": {
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7
+      },
8
+      "method": "head",
9
+      "options": [],
10
+      "request_body": "",
11
+      "url": "https://httpbin.org/status/500"
12
+    },
13
+    "response": {
14
+      "binary": false,
15
+      "body": null,
16
+      "headers": {
17
+        "Access-Control-Allow-Credentials": "true",
18
+        "Access-Control-Allow-Origin": "*",
19
+        "Content-Length": "0",
20
+        "Content-Type": "text/html; charset=utf-8",
21
+        "Date": "Mon, 15 Apr 2019 00:08:10 GMT",
22
+        "Server": "nginx",
23
+        "Connection": "keep-alive"
24
+      },
25
+      "status_code": 500,
26
+      "type": "ok"
27
+    }
28
+  }
29
+]

+ 7
- 24
test/fixtures/vcr_cassettes/page_is_empty.json View File

@@ -3,26 +3,10 @@
3 3
     "request": {
4 4
       "body": "",
5 5
       "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7 7
       },
8 8
       "method": "get",
9
-      "options": {
10
-        "ssl_options": {
11
-          "server_name_indication": [
12
-            104,
13
-            116,
14
-            116,
15
-            112,
16
-            98,
17
-            105,
18
-            110,
19
-            46,
20
-            111,
21
-            114,
22
-            103
23
-          ]
24
-        }
25
-      },
9
+      "options": [],
26 10
       "request_body": "",
27 11
       "url": "https://httpbin.org/status/200"
28 12
     },
@@ -30,14 +14,13 @@
30 14
       "binary": false,
31 15
       "body": "",
32 16
       "headers": {
33
-        "Connection": "keep-alive",
34
-        "Server": "gunicorn/19.9.0",
35
-        "Date": "Mon, 04 Feb 2019 01:34:10 GMT",
36
-        "Content-Type": "text/html; charset=utf-8",
37
-        "Access-Control-Allow-Origin": "*",
38 17
         "Access-Control-Allow-Credentials": "true",
18
+        "Access-Control-Allow-Origin": "*",
19
+        "Content-Type": "text/html; charset=utf-8",
20
+        "Date": "Mon, 15 Apr 2019 00:08:11 GMT",
21
+        "Server": "nginx",
39 22
         "Content-Length": "0",
40
-        "Via": "1.1 vegur"
23
+        "Connection": "keep-alive"
41 24
       },
42 25
       "status_code": 200,
43 26
       "type": "ok"

+ 148
- 0
test/fixtures/vcr_cassettes/page_parser_as2_from_json.json
File diff suppressed because it is too large
View File


+ 0
- 82
test/fixtures/vcr_cassettes/parse_activtystreams_parse_success.json
File diff suppressed because it is too large
View File


+ 0
- 34
test/fixtures/vcr_cassettes/parser_bridgy_success_mobile_twitter.json View File

@@ -1,34 +0,0 @@
1
-[
2
-  {
3
-    "request": {
4
-      "body": "",
5
-      "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://koype.net/faq/user-agent)"
7
-      },
8
-      "method": "get",
9
-      "options": [],
10
-      "request_body": "",
11
-      "url": "https://brid.gy/post/twitter/jackyalcine/1101331482067587077"
12
-    },
13
-    "response": {
14
-      "binary": false,
15
-      "body": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<title>When my account on here hits 10 years old; I'm nuking it.</title>\n<style type=\"text/css\">\nbody {\n  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n.p-uid {\n  display: none;\n}\n.u-photo {\n  max-width: 50px;\n  border-radius: 4px;\n}\n.e-content {\n  margin-top: 10px;\n  font-size: 1.3em;\n}\n</style>\n</head>\n<article class=\"h-entry\">\n  <span class=\"p-uid\">tag:twitter.com,2013:1101331482067587077</span>\n  \n  <time class=\"dt-published\" datetime=\"2019-03-01T04:01:01+00:00\">2019-03-01T04:01:01+00:00</time>\n  \n  <span class=\"p-author h-card\">\n    <data class=\"p-uid\" value=\"tag:twitter.com,2013:jackyalcine\"></data>\n<data class=\"p-numeric-id\" value=\"44119449\"></data>\n    <a class=\"p-name u-url\" href=\"https://twitter.com/jackyalcine\">I post from https://v2.jacky.wtf. 🆓 != safe.</a>\n<a class=\"u-url\" href=\"https://v2.jacky.wtf/\"></a>\n<a class=\"u-url\" href=\"https://black.af\"></a>\n<a class=\"u-url\" href=\"https://jacky.wtf\"></a>\n    <span class=\"p-nickname\">jackyalcine</span>\n    <img class=\"u-photo\" src=\"https://pbs.twimg.com/profile_images/1070875401872797697/O2ZSNaNO.jpg\" alt=\"\" />\n  </span>\n\n  <a class=\"u-url\" href=\"https://twitter.com/jackyalcine/status/1101331482067587077\">https://twitter.com/jackyalcine/status/1101331482067587077</a>\n  <div class=\"e-content p-name\">\n  \n  When my account on here hits 10 years old; I'm nuking it.\n  </div>\n\n\n\n\n\n\n\n</article>\n\n</html>\n",
16
-      "headers": {
17
-        "Cache-Control": "no-cache",
18
-        "X-XSS-Protection": "1; mode=block",
19
-        "Content-Security-Policy": "script-src https: localhost:8080 'unsafe-inline'; frame-ancestors 'self'; report-uri /csp-report;",
20
-        "X-Content-Type-Options": "nosniff",
21
-        "Strict-Transport-Security": "max-age=16070400; preload",
22
-        "X-Frame-Options": "SAMEORIGIN",
23
-        "Access-Control-Allow-Origin": "*",
24
-        "Content-Type": "text/html; charset=utf-8",
25
-        "X-Cloud-Trace-Context": "a001a3a50d65a67dd142c05f576735d8;o=1",
26
-        "Date": "Fri, 29 Mar 2019 07:04:29 GMT",
27
-        "Server": "Google Frontend",
28
-        "Content-Length": "1448"
29
-      },
30
-      "status_code": 200,
31
-      "type": "ok"
32
-    }
33
-  }
34
-]

+ 5
- 5
test/fixtures/vcr_cassettes/parser_bridgy_success_twitter.json View File

@@ -3,7 +3,7 @@
3 3
     "request": {
4 4
       "body": "",
5 5
       "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://koype.net/faq/user-agent)"
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7 7
       },
8 8
       "method": "get",
9 9
       "options": [],
@@ -12,7 +12,7 @@
12 12
     },
13 13
     "response": {
14 14
       "binary": false,
15
-      "body": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<title>When my account on here hits 10 years old; I'm nuking it.</title>\n<style type=\"text/css\">\nbody {\n  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n.p-uid {\n  display: none;\n}\n.u-photo {\n  max-width: 50px;\n  border-radius: 4px;\n}\n.e-content {\n  margin-top: 10px;\n  font-size: 1.3em;\n}\n</style>\n</head>\n<article class=\"h-entry\">\n  <span class=\"p-uid\">tag:twitter.com,2013:1101331482067587077</span>\n  \n  <time class=\"dt-published\" datetime=\"2019-03-01T04:01:01+00:00\">2019-03-01T04:01:01+00:00</time>\n  \n  <span class=\"p-author h-card\">\n    <data class=\"p-uid\" value=\"tag:twitter.com,2013:jackyalcine\"></data>\n<data class=\"p-numeric-id\" value=\"44119449\"></data>\n    <a class=\"p-name u-url\" href=\"https://twitter.com/jackyalcine\">I post from https://v2.jacky.wtf. 🆓 != safe.</a>\n<a class=\"u-url\" href=\"https://v2.jacky.wtf/\"></a>\n<a class=\"u-url\" href=\"https://black.af\"></a>\n<a class=\"u-url\" href=\"https://jacky.wtf\"></a>\n    <span class=\"p-nickname\">jackyalcine</span>\n    <img class=\"u-photo\" src=\"https://pbs.twimg.com/profile_images/1070875401872797697/O2ZSNaNO.jpg\" alt=\"\" />\n  </span>\n\n  <a class=\"u-url\" href=\"https://twitter.com/jackyalcine/status/1101331482067587077\">https://twitter.com/jackyalcine/status/1101331482067587077</a>\n  <div class=\"e-content p-name\">\n  \n  When my account on here hits 10 years old; I'm nuking it.\n  </div>\n\n\n\n\n\n\n\n</article>\n\n</html>\n",
15
+      "body": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<title>When my account on here hits 10 years old; I'm nuking it.</title>\n<style type=\"text/css\">\nbody {\n  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n.p-uid {\n  display: none;\n}\n.u-photo {\n  max-width: 50px;\n  border-radius: 4px;\n}\n.e-content {\n  margin-top: 10px;\n  font-size: 1.3em;\n}\n</style>\n</head>\n<article class=\"h-entry\">\n  <span class=\"p-uid\">tag:twitter.com,2013:1101331482067587077</span>\n  \n  <time class=\"dt-published\" datetime=\"2019-03-01T04:01:01+00:00\">2019-03-01T04:01:01+00:00</time>\n  \n  <span class=\"p-author h-card\">\n    <data class=\"p-uid\" value=\"tag:twitter.com,2013:jackyalcine\"></data>\n<data class=\"p-numeric-id\" value=\"44119449\"></data>\n    <a class=\"p-name u-url\" href=\"https://twitter.com/jackyalcine\">jackyalciné</a>\n<a class=\"u-url\" href=\"https://jacky.wtf/\"></a>\n<a class=\"u-url\" href=\"http://black.af\"></a>\n<a class=\"u-url\" href=\"http://v2.jacky.wtf\"></a>\n<a class=\"u-url\" href=\"http://koype.net\"></a>\n    <span class=\"p-nickname\">jackyalcine</span>\n    <img class=\"u-photo\" src=\"https://pbs.twimg.com/profile_images/1070875401872797697/O2ZSNaNO.jpg\" alt=\"\" />\n  </span>\n\n  <a class=\"u-url\" href=\"https://twitter.com/jackyalcine/status/1101331482067587077\">https://twitter.com/jackyalcine/status/1101331482067587077</a>\n  <div class=\"e-content p-name\">\n  \n  When my account on here hits 10 years old; I'm nuking it.\n  </div>\n\n\n\n\n\n\n\n</article>\n\n</html>\n",
16 16
       "headers": {
17 17
         "Cache-Control": "no-cache",
18 18
         "X-XSS-Protection": "1; mode=block",
@@ -22,10 +22,10 @@
22 22
         "X-Frame-Options": "SAMEORIGIN",
23 23
         "Access-Control-Allow-Origin": "*",
24 24
         "Content-Type": "text/html; charset=utf-8",
25
-        "X-Cloud-Trace-Context": "987f6f5e96d7cbded43efa2d60c3f549",
26
-        "Date": "Fri, 29 Mar 2019 06:15:11 GMT",
25
+        "X-Cloud-Trace-Context": "77d9277361dc6ebb0f8bead340077591;o=1",
26
+        "Date": "Mon, 15 Apr 2019 00:08:18 GMT",
27 27
         "Server": "Google Frontend",
28
-        "Content-Length": "1448"
28
+        "Content-Length": "1457"
29 29
       },
30 30
       "status_code": 200,
31 31
       "type": "ok"

+ 9
- 9
test/fixtures/vcr_cassettes/parser_microformats2_parse_success.json
File diff suppressed because it is too large
View File


+ 4
- 21
test/fixtures/vcr_cassettes/refresh_of_mf2_data.json View File

@@ -3,27 +3,10 @@
3 3
     "request": {
4 4
       "body": "",
5 5
       "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7 7
       },
8 8
       "method": "get",
9
-      "options": {
10
-        "ssl_options": {
11
-          "server_name_indication": [
12
-            113,
13
-            117,
14
-            105,
15
-            108,
16
-            108,
17
-            46,
18
-            112,
19
-            51,
20
-            107,
21
-            46,
22
-            105,
23
-            111
24
-          ]
25
-        }
26
-      },
9
+      "options": [],
27 10
       "request_body": "",
28 11
       "url": "https://quill.p3k.io"
29 12
     },
@@ -32,12 +15,12 @@
32 15
       "body": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <title>Quill</title>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n    <link rel=\"pingback\" href=\"https://webmention.io/aaronpk/xmlrpc\" />\n    <link rel=\"webmention\" href=\"https://webmention.io/aaronpk/webmention\" />\n\n    <!-- standard viewport tag to set the viewport to the device's width\n      , Android 2.3 devices need this so 100% width works properly and\n      doesn't allow children to blow up the viewport width-->\n    <meta name=\"viewport\" content=\"initial-scale=1.0,user-scalable=no,maximum-scale=1,width=device-width\" />\n    <!-- width=device-width causes the iPhone 5 to letterbox the app, so\n      we want to exclude it for iPhone 5 to allow full screen apps -->\n    <meta name=\"viewport\" content=\"initial-scale=1.0,user-scalable=no,maximum-scale=1\" media=\"(device-height: 568px)\" />\n\n    <link rel=\"stylesheet\" href=\"/bootstrap/css/bootstrap.min.css\">\n    <link rel=\"stylesheet\" href=\"/bootstrap/css/bootstrap-theme.min.css\">\n\n    <script src=\"/js/jquery-1.7.1.min.js\"></script>\n    <script src=\"/libs/localforage.js\"></script>\n\n    <script src=\"/bootstrap/js/bootstrap.min.js\"></script>\n    <script src=\"/libs/tokenfield/bootstrap-tokenfield.min.js\"></script>\n    <link rel=\"stylesheet\" href=\"/libs/tokenfield/bootstrap-tokenfield.min.css\">\n    <link rel=\"stylesheet\" href=\"/libs/tokenfield/tokenfield-typeahead.min.css\">\n\n    <link rel=\"stylesheet\" href=\"/css/style.css\">\n\n    <link rel=\"apple-touch-icon\" sizes=\"57x57\" href=\"/images/quill-icon-57.png\">\n    <link rel=\"apple-touch-icon\" sizes=\"72x72\" href=\"/images/quill-icon-72.png\">\n    <link rel=\"apple-touch-icon\" sizes=\"114x114\" href=\"/images/quill-icon-114.png\">\n    <link rel=\"apple-touch-icon\" sizes=\"144x144\" href=\"/images/quill-icon-144.png\">\n    <link rel=\"apple-touch-icon\" sizes=\"196x196\" href=\"/images/quill-icon-196.png\">\n\n    <link rel=\"icon\" href=\"/favicon.ico\" type=\"image/x-icon\">\n    <link rel=\"icon\" sizes=\"196x196\" href=\"/images/quill-icon-196.png\">\n\n    <meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n    <meta name=\"mobile-web-app-capable\" content=\"yes\">\n    <meta name=\"theme-color\" content=\"#428bca\">\n\n    <link rel=\"manifest\" href=\"/js/manifest.json\">\n\n    <script src=\"/js/script.js\"></script>\n    <script src=\"/js/date.js\"></script>\n    <script src=\"/js/cassis.js\"></script>\n  </head>\n\n<body role=\"document\">\n<script type=\"text/javascript\">\n\n  var _gaq = _gaq || [];\n  _gaq.push(['_setAccount', '']);\n  _gaq.push(['_trackPageview']);\n\n  (function() {\n    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\n    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\n    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n  })();\n\n</script>\n\n<div class=\"page\">\n\n  <div class=\"container\">\n    <div class=\"narrow\">\n\n  <div class=\"jumbotron h-app h-x-app\">\n    <h1><img src=\"/images/quill-logo-144.png\" height=\"72\" style=\"margin-bottom: 13px;\" class=\"u-logo p-name\" alt=\"Quill\">Quill</h1>\n\n    <p class=\"tagline\">Quill is a simple app for posting text notes to your website.</p>\n\n          <p>To use Quill, sign in with your domain. Your website will need to support <a href=\"https://indieweb.org/micropub\">Micropub</a> for creating new posts.</p>\n\n      <form action=\"/auth/start\" method=\"get\" class=\"form-inline\">\n        <input type=\"url\" name=\"me\" placeholder=\"https://example.com\" value=\"\" class=\"form-control\" onchange=\"auto_prefix_url_field(this)\" autofocus>\n        <input type=\"submit\" value=\"Sign In\" class=\"btn btn-primary\">\n        <input type=\"hidden\" name=\"client_id\" value=\"https://quill.p3k.io/\">\n        <input type=\"hidden\" name=\"redirect_uri\" value=\"https://quill.p3k.io/auth/callback\">\n      </form>\n    \n    <a href=\"\" class=\"u-url\"></a>\n  </div>\n\n</div>\n  </div>\n\n  <div class=\"footer\">\n    <div class=\"nav\">\n      <ul class=\"nav navbar-nav\">\n\n        \n        <li><a href=\"/docs\">Docs</a></li>\n      </ul>\n      <ul class=\"nav navbar-nav navbar-right\">\n                  <li class=\"navbar-text\"></li>\n        \n      </ul>\n    </div>\n\n    <p class=\"credits\">&copy; 2019 by <a href=\"https://aaronparecki.com\">Aaron Parecki</a>.\n      This code is <a href=\"https://github.com/aaronpk/Quill\">open source</a>.\n      Feel free to send a pull request, or <a href=\"https://github.com/aaronpk/Quill/issues\">file an issue</a>.</p>\n  </div>\n</div>\n\n</body>\n</html>\n",
33 16
       "headers": {
34 17
         "Server": "nginx/1.14.0",
35
-        "Date": "Mon, 04 Feb 2019 01:34:19 GMT",
18
+        "Date": "Mon, 15 Apr 2019 00:08:20 GMT",
36 19
         "Content-Type": "text/html;charset=UTF-8",
37 20
         "Transfer-Encoding": "chunked",
38 21
         "Connection": "keep-alive",
39 22
         "X-Powered-By": "PHP/5.6.36-1+ubuntu16.04.1+deb.sury.org+1",
40
-        "Set-Cookie": "quill=5vs1t5epb8705khv5ddok2dmt6; expires=Wed, 06-Mar-2019 01:34:19 GMT; Max-Age=2592000; path=/",
23
+        "Set-Cookie": "quill=5ncfeapca83v4js3trdfdn3ip1; expires=Wed, 15-May-2019 00:08:20 GMT; Max-Age=2592000; path=/",
41 24
         "Expires": "Thu, 19 Nov 1981 08:52:00 GMT",
42 25
         "Cache-Control": "no-store, no-cache, must-revalidate, post-check=0, pre-check=0",
43 26
         "Pragma": "no-cache"

+ 0
- 31
test/fixtures/vcr_cassettes/settings-relme-add-verified-link.json View File

@@ -1,31 +0,0 @@
1
-[
2
-  {
3
-    "request": {
4
-      "body": "",
5
-      "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
7
-      },
8
-      "method": "get",
9
-      "request_body": "",
10
-      "url": "https://fake.test/rel-me-site"
11
-    },
12
-    "response": {
13
-      "binary": false,
14
-      "body": "<html><title>Fake Request - Verified Link</title></html>",
15
-      "headers": {
16
-        "Server": "nginx/1.14.0",
17
-        "Date": "Mon, 04 Feb 2019 01:34:19 GMT",
18
-        "Content-Type": "text/html;charset=UTF-8",
19
-        "Transfer-Encoding": "chunked",
20
-        "Connection": "keep-alive",
21
-        "X-Powered-By": "PHP/5.6.36-1+ubuntu16.04.1+deb.sury.org+1",
22
-        "Set-Cookie": "quill=5vs1t5epb8705khv5ddok2dmt6; expires=Wed, 06-Mar-2019 01:34:19 GMT; Max-Age=2592000; path=/",
23
-        "Expires": "Thu, 19 Nov 1981 08:52:00 GMT",
24
-        "Cache-Control": "no-store, no-cache, must-revalidate, post-check=0, pre-check=0",
25
-        "Pragma": "no-cache"
26
-      },
27
-      "status_code": 200,
28
-      "type": "ok"
29
-    }
30
-  }
31
-]

+ 5
- 3
test/fixtures/vcr_cassettes/syndication_fail_endpoint.json View File

@@ -2,15 +2,17 @@
2 2
   {
3 3
     "request": {
4 4
       "body": "",
5
-      "headers": [],
5
+      "headers": {
6
+        "user-agent": "IndieWeb-Elixir/0.0.42 (https://git.jacky.wtf/indieweb/elixir)"
7
+      },
6 8
       "method": "get",
7 9
       "options": [],
8 10
       "request_body": "",
9 11
       "url": "http://test.example.faker/endpoint"
10 12
     },
11 13
     "response": {
12
-      "binary": true,
13
-      "body": "g2wAAAACbQAAAAtjb25uX2ZhaWxlZGwAAAACbQAAAAVlcnJvcm0AAAAIbnhkb21haW5qag==",
14
+      "binary": false,
15
+      "body": "nxdomain",
14 16
       "headers": [],
15 17
       "status_code": null,
16 18
       "type": "error"

+ 0
- 40
test/fixtures/vcr_cassettes/syndication_result_endpoint_failure.json View File

@@ -1,40 +0,0 @@
1
-[
2
-  {
3
-    "request": {
4
-      "body": "",
5
-      "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
7
-      },
8
-      "method": "get",
9
-      "options": [],
10
-      "request_body": "",
11
-      "url": "http://test.example.faker/endpoint"
12
-    },
13
-    "response": {
14
-      "binary": true,
15
-      "body": "g2wAAAACbQAAAAtjb25uX2ZhaWxlZGwAAAACbQAAAAVlcnJvcm0AAAAIbnhkb21haW5qag==",
16
-      "headers": [],
17
-      "status_code": null,
18
-      "type": "error"
19
-    }
20
-  },
21
-  {
22
-    "request": {
23
-      "body": "",
24
-      "headers": {
25
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
26
-      },
27
-      "method": "head",
28
-      "options": [],
29
-      "request_body": "",
30
-      "url": "http://test.example.faker/endpoint"
31
-    },
32
-    "response": {
33
-      "binary": true,
34
-      "body": "g2wAAAACbQAAAAtjb25uX2ZhaWxlZGwAAAACbQAAAAVlcnJvcm0AAAAIbnhkb21haW5qag==",
35
-      "headers": [],
36
-      "status_code": null,
37
-      "type": "error"
38
-    }
39
-  }
40
-]

+ 0
- 40
test/fixtures/vcr_cassettes/syndication_result_successful.json View File

@@ -1,40 +0,0 @@
1
-[
2
-  {
3
-    "request": {
4
-      "body": "",
5
-      "headers": {
6
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
7
-      },
8
-      "method": "get",
9
-      "options": [],
10
-      "request_body": "",
11
-      "url": "http://test.example.faker/endpoint"
12
-    },
13
-    "response": {
14
-      "binary": true,
15
-      "body": "g2wAAAACbQAAAAtjb25uX2ZhaWxlZGwAAAACbQAAAAVlcnJvcm0AAAAIbnhkb21haW5qag==",
16
-      "headers": [],
17
-      "status_code": null,
18
-      "type": "error"
19
-    }
20
-  },
21
-  {
22
-    "request": {
23
-      "body": "",
24
-      "headers": {
25
-        "user-agent": "Koype/0.0.7 (https://faq.koype.net/user-agent)"
26
-      },
27
-      "method": "head",
28
-      "options": [],
29
-      "request_body": "",
30
-      "url": "http://test.example.faker/endpoint"
31
-    },
32
-    "response": {
33
-      "binary": true,
34
-      "body": "g2wAAAACbQAAAAtjb25uX2ZhaWxlZGwAAAACbQAAAAVlcnJvcm0AAAAIbnhkb21haW5qag==",
35
-      "headers": [],
36
-      "status_code": null,
37
-      "type": "error"
38
-    }
39
-  }
40
-]

+ 86
- 0
test/fixtures/vcr_cassettes/webmention_receive_store_new.json View File

@@ -0,0 +1,86 @@
1
+[
2
+  {
3
+    "request": {
4
+      "body": "",
5
+      "headers": {
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7
+      },
8
+      "method": "get",
9
+      "options": [],
10
+      "request_body": "",
11
+      "url": "https://raw.githubusercontent.com/microformats/tests/master/tests/microformats-v2/h-entry/summarycontent.html"
12
+    },
13
+    "response": {
14
+      "binary": false,
15
+      "body": "<meta charset=\"utf-8\">\n<div class=\"h-entry\">\n    <h1><a class=\"p-name u-url\" href=\"http://microformats.org/2012/06/25/microformats-org-at-7\">microformats.org at 7</a></h1>\n    <div class=\"e-content\">\n        <p class=\"p-summary\">Last week the microformats.org community \n            celebrated its 7th birthday at a gathering hosted by Mozilla in \n            San Francisco and recognized accomplishments, challenges, and \n            opportunities.</p>\n\n        <p>The microformats tagline “humans first, machines second” \n            forms the basis of many of our \n            <a href=\"http://microformats.org/wiki/principles\">principles</a>, and \n            in that regard, we’d like to recognize a few people and \n            thank them for their years of volunteer service </p>\n    </div>  \n    <p>Updated \n        <time class=\"dt-updated\" datetime=\"2012-06-25T17:08:26\">June 25th, 2012</time> by\n        <a class=\"p-author h-card\" href=\"http://tantek.com/\">Tantek</a>\n    </p>\n</div>",
16
+      "headers": {
17
+        "Content-Security-Policy": "default-src 'none'; style-src 'unsafe-inline'; sandbox",
18
+        "Strict-Transport-Security": "max-age=31536000",
19
+        "X-Content-Type-Options": "nosniff",
20
+        "X-Frame-Options": "deny",
21
+        "X-XSS-Protection": "1; mode=block",
22
+        "ETag": "\"22fb20b8ec1f6e1f5d9feb52030fed4db6016750\"",
23
+        "Content-Type": "text/plain; charset=utf-8",
24
+        "Cache-Control": "max-age=300",
25
+        "X-Geo-Block-List": "",
26
+        "X-GitHub-Request-Id": "4E32:05C2:CB0B9D:DBFD7C:5CB424FF",
27
+        "Content-Length": "997",
28
+        "Accept-Ranges": "bytes",
29
+        "Date": "Mon, 15 Apr 2019 06:30:24 GMT",
30
+        "Via": "1.1 varnish",
31
+        "Connection": "keep-alive",
32
+        "X-Served-By": "cache-lax8621-LAX",
33
+        "X-Cache": "MISS",
34
+        "X-Cache-Hits": "0",
35
+        "X-Timer": "S1555309825.570381,VS0,VE170",
36
+        "Vary": "Authorization,Accept-Encoding",
37
+        "Access-Control-Allow-Origin": "*",
38
+        "X-Fastly-Request-ID": "68c22b95094f51f288f6aef290f8317f32a5d618",
39
+        "Expires": "Mon, 15 Apr 2019 06:35:24 GMT",
40
+        "Source-Age": "0"
41
+      },
42
+      "status_code": 200,
43
+      "type": "ok"
44
+    }
45
+  },
46
+  {
47
+    "request": {
48
+      "body": "{\"accessed\":\"2019-04-15T06:30:24.771Z\",\"author\":{\"name\":\"Tantek\",\"uid\":\"http://tantek.com/\",\"url\":\"http://tantek.com/\"},\"mf2\":{\"properties\":{\"author\":[{\"properties\":{\"name\":[\"Tantek\"],\"url\":[\"http://tantek.com/\"]},\"type\":[\"h-card\"],\"value\":\"Tantek\"}],\"content\":[{\"html\":\"<p class=\\\"p-summary\\\">Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.</p><p>The microformats tagline “humans first, machines second” \\n            forms the basis of many of our \\n            <a href=\\\"http://microformats.org/wiki/principles\\\">principles</a>, and \\n            in that regard, we’d like to recognize a few people and \\n            thank them for their years of volunteer service </p>\",\"text\":\"Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.The microformats tagline “humans first, machines second” \\n            forms the basis of many of our \\n            principles, and \\n            in that regard, we’d like to recognize a few people and \\n            thank them for their years of volunteer service\"}],\"name\":[\"microformats.org at 7\"],\"summary\":[\"Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.\"],\"updated\":[\"2012-06-25T17:08:26\"],\"url\":[\"http://microformats.org/2012/06/25/microformats-org-at-7\"]},\"type\":[\"h-entry\"]},\"source\":{\"content\":{\"html\":\"<p class=\\\"p-summary\\\">Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.</p><p>The microformats tagline “humans first, machines second” \\n            forms the basis of many of our \\n            <a href=\\\"http://microformats.org/wiki/principles\\\">principles</a>, and \\n            in that regard, we’d like to recognize a few people and \\n            thank them for their years of volunteer service </p>\",\"text\":\"Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.The microformats tagline “humans first, machines second” \\n            forms the basis of many of our \\n            principles, and \\n            in that regard, we’d like to recognize a few people and \\n            thank them for their years of volunteer service\"},\"published\":null,\"title\":\"microformats.org at 7\",\"updated\":\"2012-06-25T17:08:26\"},\"url\":\"https://raw.githubusercontent.com/microformats/tests/master/tests/microformats-v2/h-entry/summarycontent.html\"}",
49
+      "headers": {
50
+        "Authorization": "AWS4-HMAC-SHA256 Credential=access_minio/20190415/local/s3/aws4_request,SignedHeaders=content-length;host;x-amz-acl;x-amz-content-sha256;x-amz-date,Signature=82ace5f7c9b6e42b5df48b92da61bfe2adc58a45c14128124b1defe6af7a5827",
51
+        "host": "objectstorage:9000",
52
+        "x-amz-date": "20190415T063024Z",
53
+        "content-length": "3070",
54
+        "x-amz-acl": "private",
55
+        "x-amz-content-sha256": "7519274ce1f54a60b6cbbd358b3fcc254a8fb266d21395457c1f931b59001c93"
56
+      },
57
+      "method": "put",
58
+      "options": {
59
+        "with_body": "true",
60
+        "follow_redirect": "true",
61
+        "recv_timeout": 5000
62
+      },
63
+      "request_body": "",
64
+      "url": "http://objectstorage:9000/koype-test/models/webmentions/5aa7a1d5-2de8-4fe4-a82f-618eec7080d2/model.json.json"
65
+    },
66
+    "response": {
67
+      "binary": false,
68
+      "body": "",
69
+      "headers": {
70
+        "Accept-Ranges": "bytes",
71
+        "Content-Security-Policy": "block-all-mixed-content",
72
+        "Etag": "\"22bf43450495fbad8fdee4198bea1728\"",
73
+        "Server": "Minio/RELEASE.2019-03-27T22-35-21Z",
74
+        "Vary": "Origin",
75
+        "X-Amz-Bucket-Region": "local",
76
+        "X-Amz-Request-Id": "1595920B959DA830",
77
+        "X-Minio-Deployment-Id": "3127cc92-d6c9-49e3-b0da-ed8dc7bf6348",
78
+        "X-Xss-Protection": "1; mode=block",
79
+        "Date": "Mon, 15 Apr 2019 06:30:24 GMT",
80
+        "Content-Length": "0"
81
+      },
82
+      "status_code": 200,
83
+      "type": "ok"
84
+    }
85
+  }
86
+]

+ 86
- 0
test/fixtures/vcr_cassettes/webmention_receive_store_new_homepage.json View File

@@ -0,0 +1,86 @@
1
+[
2
+  {
3
+    "request": {
4
+      "body": "",
5
+      "headers": {
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7
+      },
8
+      "method": "get",
9
+      "options": [],
10
+      "request_body": "",
11
+      "url": "https://raw.githubusercontent.com/microformats/tests/master/tests/microformats-v2/h-entry/summarycontent.html"
12
+    },
13
+    "response": {
14
+      "binary": false,
15
+      "body": "<meta charset=\"utf-8\">\n<div class=\"h-entry\">\n    <h1><a class=\"p-name u-url\" href=\"http://microformats.org/2012/06/25/microformats-org-at-7\">microformats.org at 7</a></h1>\n    <div class=\"e-content\">\n        <p class=\"p-summary\">Last week the microformats.org community \n            celebrated its 7th birthday at a gathering hosted by Mozilla in \n            San Francisco and recognized accomplishments, challenges, and \n            opportunities.</p>\n\n        <p>The microformats tagline “humans first, machines second” \n            forms the basis of many of our \n            <a href=\"http://microformats.org/wiki/principles\">principles</a>, and \n            in that regard, we’d like to recognize a few people and \n            thank them for their years of volunteer service </p>\n    </div>  \n    <p>Updated \n        <time class=\"dt-updated\" datetime=\"2012-06-25T17:08:26\">June 25th, 2012</time> by\n        <a class=\"p-author h-card\" href=\"http://tantek.com/\">Tantek</a>\n    </p>\n</div>",
16
+      "headers": {
17
+        "Content-Security-Policy": "default-src 'none'; style-src 'unsafe-inline'; sandbox",
18
+        "Strict-Transport-Security": "max-age=31536000",
19
+        "X-Content-Type-Options": "nosniff",
20
+        "X-Frame-Options": "deny",
21
+        "X-XSS-Protection": "1; mode=block",
22
+        "ETag": "\"22fb20b8ec1f6e1f5d9feb52030fed4db6016750\"",
23
+        "Content-Type": "text/plain; charset=utf-8",
24
+        "Cache-Control": "max-age=300",
25
+        "X-Geo-Block-List": "",
26
+        "X-GitHub-Request-Id": "4E32:05C2:CB0B9D:DBFD7C:5CB424FF",
27
+        "Content-Length": "997",
28
+        "Accept-Ranges": "bytes",
29
+        "Date": "Mon, 15 Apr 2019 06:30:25 GMT",
30
+        "Via": "1.1 varnish",
31
+        "Connection": "keep-alive",
32
+        "X-Served-By": "cache-lax8621-LAX",
33
+        "X-Cache": "HIT",
34
+        "X-Cache-Hits": "1",
35
+        "X-Timer": "S1555309825.409685,VS0,VE0",
36
+        "Vary": "Authorization,Accept-Encoding",
37
+        "Access-Control-Allow-Origin": "*",
38
+        "X-Fastly-Request-ID": "85245adeab0e6feeea9e638257a4722bcda7617d",
39
+        "Expires": "Mon, 15 Apr 2019 06:35:25 GMT",
40
+        "Source-Age": "1"
41
+      },
42
+      "status_code": 200,
43
+      "type": "ok"
44
+    }
45
+  },
46
+  {
47
+    "request": {
48
+      "body": "{\"accessed\":\"2019-04-15T06:30:25.438Z\",\"author\":{\"name\":\"Tantek\",\"uid\":\"http://tantek.com/\",\"url\":\"http://tantek.com/\"},\"mf2\":{\"properties\":{\"author\":[{\"properties\":{\"name\":[\"Tantek\"],\"url\":[\"http://tantek.com/\"]},\"type\":[\"h-card\"],\"value\":\"Tantek\"}],\"content\":[{\"html\":\"<p class=\\\"p-summary\\\">Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.</p><p>The microformats tagline “humans first, machines second” \\n            forms the basis of many of our \\n            <a href=\\\"http://microformats.org/wiki/principles\\\">principles</a>, and \\n            in that regard, we’d like to recognize a few people and \\n            thank them for their years of volunteer service </p>\",\"text\":\"Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.The microformats tagline “humans first, machines second” \\n            forms the basis of many of our \\n            principles, and \\n            in that regard, we’d like to recognize a few people and \\n            thank them for their years of volunteer service\"}],\"name\":[\"microformats.org at 7\"],\"summary\":[\"Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.\"],\"updated\":[\"2012-06-25T17:08:26\"],\"url\":[\"http://microformats.org/2012/06/25/microformats-org-at-7\"]},\"type\":[\"h-entry\"]},\"source\":{\"content\":{\"html\":\"<p class=\\\"p-summary\\\">Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.</p><p>The microformats tagline “humans first, machines second” \\n            forms the basis of many of our \\n            <a href=\\\"http://microformats.org/wiki/principles\\\">principles</a>, and \\n            in that regard, we’d like to recognize a few people and \\n            thank them for their years of volunteer service </p>\",\"text\":\"Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.The microformats tagline “humans first, machines second” \\n            forms the basis of many of our \\n            principles, and \\n            in that regard, we’d like to recognize a few people and \\n            thank them for their years of volunteer service\"},\"published\":null,\"title\":\"microformats.org at 7\",\"updated\":\"2012-06-25T17:08:26\"},\"url\":\"https://raw.githubusercontent.com/microformats/tests/master/tests/microformats-v2/h-entry/summarycontent.html\"}",
49
+      "headers": {
50
+        "Authorization": "AWS4-HMAC-SHA256 Credential=access_minio/20190415/local/s3/aws4_request,SignedHeaders=content-length;host;x-amz-acl;x-amz-content-sha256;x-amz-date,Signature=eb78d163447fbe2011ad06a2457c33aa9565f81295c1b18ac5656c9ca363c7c3",
51
+        "host": "objectstorage:9000",
52
+        "x-amz-date": "20190415T063025Z",
53
+        "content-length": "3070",
54
+        "x-amz-acl": "private",
55
+        "x-amz-content-sha256": "ae79fc7f241cff6673aeedc64510a73c71dcf26ceafe8a2d6a271bcd9bb9fcf3"
56
+      },
57
+      "method": "put",
58
+      "options": {
59
+        "with_body": "true",
60
+        "follow_redirect": "true",
61
+        "recv_timeout": 5000
62
+      },
63
+      "request_body": "",
64
+      "url": "http://objectstorage:9000/koype-test/models/webmentions/83842fb2-9ec7-4fc7-93c6-8ffa1c2e876c/model.json.json"
65
+    },
66
+    "response": {
67
+      "binary": false,
68
+      "body": "",
69
+      "headers": {
70
+        "Accept-Ranges": "bytes",
71
+        "Content-Security-Policy": "block-all-mixed-content",
72
+        "Etag": "\"68e3855f61e61e3ae91998091cd8b4ae\"",
73
+        "Server": "Minio/RELEASE.2019-03-27T22-35-21Z",
74
+        "Vary": "Origin",
75
+        "X-Amz-Bucket-Region": "local",
76
+        "X-Amz-Request-Id": "1595920BBD59228D",
77
+        "X-Minio-Deployment-Id": "3127cc92-d6c9-49e3-b0da-ed8dc7bf6348",
78
+        "X-Xss-Protection": "1; mode=block",
79
+        "Date": "Mon, 15 Apr 2019 06:30:25 GMT",
80
+        "Content-Length": "0"
81
+      },
82
+      "status_code": 200,
83
+      "type": "ok"
84
+    }
85
+  }
86
+]

+ 86
- 0
test/fixtures/vcr_cassettes/webmention_receive_store_new_random.json View File

@@ -0,0 +1,86 @@
1
+[
2
+  {
3
+    "request": {
4
+      "body": "",
5
+      "headers": {
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7
+      },
8
+      "method": "get",
9
+      "options": [],
10
+      "request_body": "",
11
+      "url": "https://raw.githubusercontent.com/microformats/tests/master/tests/microformats-v2/h-entry/summarycontent.html"
12
+    },
13
+    "response": {
14
+      "binary": false,
15
+      "body": "<meta charset=\"utf-8\">\n<div class=\"h-entry\">\n    <h1><a class=\"p-name u-url\" href=\"http://microformats.org/2012/06/25/microformats-org-at-7\">microformats.org at 7</a></h1>\n    <div class=\"e-content\">\n        <p class=\"p-summary\">Last week the microformats.org community \n            celebrated its 7th birthday at a gathering hosted by Mozilla in \n            San Francisco and recognized accomplishments, challenges, and \n            opportunities.</p>\n\n        <p>The microformats tagline “humans first, machines second” \n            forms the basis of many of our \n            <a href=\"http://microformats.org/wiki/principles\">principles</a>, and \n            in that regard, we’d like to recognize a few people and \n            thank them for their years of volunteer service </p>\n    </div>  \n    <p>Updated \n        <time class=\"dt-updated\" datetime=\"2012-06-25T17:08:26\">June 25th, 2012</time> by\n        <a class=\"p-author h-card\" href=\"http://tantek.com/\">Tantek</a>\n    </p>\n</div>",
16
+      "headers": {
17
+        "Content-Security-Policy": "default-src 'none'; style-src 'unsafe-inline'; sandbox",
18
+        "Strict-Transport-Security": "max-age=31536000",
19
+        "X-Content-Type-Options": "nosniff",
20
+        "X-Frame-Options": "deny",
21
+        "X-XSS-Protection": "1; mode=block",
22
+        "ETag": "\"22fb20b8ec1f6e1f5d9feb52030fed4db6016750\"",
23
+        "Content-Type": "text/plain; charset=utf-8",
24
+        "Cache-Control": "max-age=300",
25
+        "X-Geo-Block-List": "",
26
+        "X-GitHub-Request-Id": "4E32:05C2:CB0B9D:DBFD7C:5CB424FF",
27
+        "Content-Length": "997",
28
+        "Accept-Ranges": "bytes",
29
+        "Date": "Mon, 15 Apr 2019 06:30:26 GMT",
30
+        "Via": "1.1 varnish",
31
+        "Connection": "keep-alive",
32
+        "X-Served-By": "cache-lax8621-LAX",
33
+        "X-Cache": "HIT",
34
+        "X-Cache-Hits": "2",
35
+        "X-Timer": "S1555309826.209572,VS0,VE0",
36
+        "Vary": "Authorization,Accept-Encoding",
37
+        "Access-Control-Allow-Origin": "*",
38
+        "X-Fastly-Request-ID": "4d3cfe27ef56a2020aa2c53d33b2133968fdd6f1",
39
+        "Expires": "Mon, 15 Apr 2019 06:35:26 GMT",
40
+        "Source-Age": "1"
41
+      },
42
+      "status_code": 200,
43
+      "type": "ok"
44
+    }
45
+  },
46
+  {
47
+    "request": {
48
+      "body": "{\"accessed\":\"2019-04-15T06:30:26.237Z\",\"author\":{\"name\":\"Tantek\",\"uid\":\"http://tantek.com/\",\"url\":\"http://tantek.com/\"},\"mf2\":{\"properties\":{\"author\":[{\"properties\":{\"name\":[\"Tantek\"],\"url\":[\"http://tantek.com/\"]},\"type\":[\"h-card\"],\"value\":\"Tantek\"}],\"content\":[{\"html\":\"<p class=\\\"p-summary\\\">Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.</p><p>The microformats tagline “humans first, machines second” \\n            forms the basis of many of our \\n            <a href=\\\"http://microformats.org/wiki/principles\\\">principles</a>, and \\n            in that regard, we’d like to recognize a few people and \\n            thank them for their years of volunteer service </p>\",\"text\":\"Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.The microformats tagline “humans first, machines second” \\n            forms the basis of many of our \\n            principles, and \\n            in that regard, we’d like to recognize a few people and \\n            thank them for their years of volunteer service\"}],\"name\":[\"microformats.org at 7\"],\"summary\":[\"Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.\"],\"updated\":[\"2012-06-25T17:08:26\"],\"url\":[\"http://microformats.org/2012/06/25/microformats-org-at-7\"]},\"type\":[\"h-entry\"]},\"source\":{\"content\":{\"html\":\"<p class=\\\"p-summary\\\">Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.</p><p>The microformats tagline “humans first, machines second” \\n            forms the basis of many of our \\n            <a href=\\\"http://microformats.org/wiki/principles\\\">principles</a>, and \\n            in that regard, we’d like to recognize a few people and \\n            thank them for their years of volunteer service </p>\",\"text\":\"Last week the microformats.org community \\n            celebrated its 7th birthday at a gathering hosted by Mozilla in \\n            San Francisco and recognized accomplishments, challenges, and \\n            opportunities.The microformats tagline “humans first, machines second” \\n            forms the basis of many of our \\n            principles, and \\n            in that regard, we’d like to recognize a few people and \\n            thank them for their years of volunteer service\"},\"published\":null,\"title\":\"microformats.org at 7\",\"updated\":\"2012-06-25T17:08:26\"},\"url\":\"https://raw.githubusercontent.com/microformats/tests/master/tests/microformats-v2/h-entry/summarycontent.html\"}",
49
+      "headers": {
50
+        "Authorization": "AWS4-HMAC-SHA256 Credential=access_minio/20190415/local/s3/aws4_request,SignedHeaders=content-length;host;x-amz-acl;x-amz-content-sha256;x-amz-date,Signature=75a36780268c193f59c77b32b3610fd049e5a779c4dffbcd2d5a2896628c3f3d",
51
+        "host": "objectstorage:9000",
52
+        "x-amz-date": "20190415T063026Z",
53
+        "content-length": "3070",
54
+        "x-amz-acl": "private",
55
+        "x-amz-content-sha256": "380711b55e7ff7dcd58da4c258820ec4cb59d48e07d8f0e333b25da853f1bcd3"
56
+      },
57
+      "method": "put",
58
+      "options": {
59
+        "with_body": "true",
60
+        "follow_redirect": "true",
61
+        "recv_timeout": 5000
62
+      },
63
+      "request_body": "",
64
+      "url": "http://objectstorage:9000/koype-test/models/webmentions/0919221c-b093-4b73-90b3-0c389da89cab/model.json.json"
65
+    },
66
+    "response": {
67
+      "binary": false,
68
+      "body": "",
69
+      "headers": {
70
+        "Accept-Ranges": "bytes",
71
+        "Content-Security-Policy": "block-all-mixed-content",
72
+        "Etag": "\"3ca2fdfaafce2d1272bcfc535c0d4f73\"",
73
+        "Server": "Minio/RELEASE.2019-03-27T22-35-21Z",
74
+        "Vary": "Origin",
75
+        "X-Amz-Bucket-Region": "local",
76
+        "X-Amz-Request-Id": "1595920BED044433",
77
+        "X-Minio-Deployment-Id": "3127cc92-d6c9-49e3-b0da-ed8dc7bf6348",
78
+        "X-Xss-Protection": "1; mode=block",
79
+        "Date": "Mon, 15 Apr 2019 06:30:26 GMT",
80
+        "Content-Length": "0"
81
+      },
82
+      "status_code": 200,
83
+      "type": "ok"
84
+    }
85
+  }
86
+]

+ 29
- 0
test/fixtures/vcr_cassettes/webmention_receive_update_410.json View File

@@ -0,0 +1,29 @@
1
+[
2
+  {
3
+    "request": {
4
+      "body": "",
5
+      "headers": {
6
+        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Koype/0.0.12 (https://koype.net/faq/user-agent) "
7
+      },
8
+      "method": "get",
9
+      "options": [],
10
+      "request_body": "",
11
+      "url": "https://httpbin.org/status/410"
12
+    },
13
+    "response": {
14
+      "binary": false,
15
+      "body": "",
16
+      "headers": {
17
+        "Access-Control-Allow-Credentials": "true",
18
+        "Access-Control-Allow-Origin": "*",
19
+        "Content-Type": "text/html; charset=utf-8",
20
+        "Date": "Mon, 15 Apr 2019 06:30:27 GMT",
21
+        "Server": "nginx",
22
+        "Content-Length": "0",
23
+        "Connection": "keep-alive"
24
+      },
25
+      "status_code": 410,
26
+      "type": "ok"
27
+    }
28
+  }