total rebase
[anni] / lib / mix / tasks / pleroma / openapi_spec.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Mix.Tasks.Pleroma.OpenapiSpec do
6   def run([path]) do
7     # Load Pleroma application to get version info
8     Application.load(:pleroma)
9
10     spec_json = Pleroma.Web.ApiSpec.spec(server_specific: false) |> Jason.encode!()
11     # to get rid of the structs
12     spec_regened = spec_json |> Jason.decode!()
13
14     check_specs!(spec_regened)
15
16     File.write(path, spec_json)
17   end
18
19   defp check_specs!(spec) do
20     with :ok <- check_specs(spec) do
21       :ok
22     else
23       {_, errors} ->
24         IO.puts(IO.ANSI.format([:red, :bright, "Spec check failed, errors:"]))
25         Enum.map(errors, &IO.puts/1)
26
27         raise "Spec check failed"
28     end
29   end
30
31   def check_specs(spec) do
32     errors =
33       spec["paths"]
34       |> Enum.flat_map(fn {path, %{} = endpoints} ->
35         Enum.map(
36           endpoints,
37           fn {method, endpoint} ->
38             with :ok <- check_endpoint(spec, endpoint) do
39               :ok
40             else
41               error ->
42                 "#{endpoint["operationId"]} (#{method} #{path}): #{error}"
43             end
44           end
45         )
46         |> Enum.reject(fn res -> res == :ok end)
47       end)
48
49     if errors == [] do
50       :ok
51     else
52       {:error, errors}
53     end
54   end
55
56   defp check_endpoint(spec, endpoint) do
57     valid_tags = available_tags(spec)
58
59     with {_, [_ | _] = tags} <- {:tags, endpoint["tags"]},
60          {_, []} <- {:unavailable, Enum.reject(tags, &(&1 in valid_tags))} do
61       :ok
62     else
63       {:tags, _} ->
64         "No tags specified"
65
66       {:unavailable, tags} ->
67         "Tags #{inspect(tags)} not available. Please add it in \"x-tagGroups\" in Pleroma.Web.ApiSpec"
68     end
69   end
70
71   defp available_tags(spec) do
72     spec["x-tagGroups"]
73     |> Enum.flat_map(fn %{"tags" => tags} -> tags end)
74   end
75 end