From d2ec7b12a923d34f143174a8a10b8a131cbce025 Mon Sep 17 00:00:00 2001 From: Pierre de Lacroix Date: Thu, 22 Jan 2026 19:26:40 +0100 Subject: [PATCH 1/2] add gauge API --- config/config.exs | 2 ++ lib/camp_api/grist.ex | 21 +++++++++++++++++++ lib/camp_api/grist/gauge.ex | 14 +++++++++++++ .../controllers/grist_controller.ex | 14 +++++++++++++ lib/camp_api_web/controllers/grist_json.ex | 7 +++++++ lib/camp_api_web/router.ex | 2 ++ mix.exs | 3 ++- mix.lock | 5 +++++ 8 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 lib/camp_api/grist.ex create mode 100644 lib/camp_api/grist/gauge.ex create mode 100644 lib/camp_api_web/controllers/grist_controller.ex create mode 100644 lib/camp_api_web/controllers/grist_json.ex diff --git a/config/config.exs b/config/config.exs index 80547d3..eef8600 100644 --- a/config/config.exs +++ b/config/config.exs @@ -29,6 +29,8 @@ config :logger, :default_formatter, # Use Jason for JSON parsing in Phoenix config :phoenix, :json_library, Jason +config :camp_api, :grist, api_key: System.get_env("GRIST_API_KEY") + # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{config_env()}.exs" diff --git a/lib/camp_api/grist.ex b/lib/camp_api/grist.ex new file mode 100644 index 0000000..8e8d97a --- /dev/null +++ b/lib/camp_api/grist.ex @@ -0,0 +1,21 @@ +defmodule CampApi.Grist do + @moduledoc false + + @api_url "https://grist.interhacker.space/o/camp" + + def get_records(doc, table) do + url = "#{@api_url}/api/docs/#{doc}/tables/#{table}/records" + + request(:get, url) + end + + defp request(method, url) do + Req.request( + method: method, + url: url, + headers: [ + {"authorization", "Bearer " <> Application.fetch_env!(:camp_api, :grist)[:api_key]} + ] + ) + end +end diff --git a/lib/camp_api/grist/gauge.ex b/lib/camp_api/grist/gauge.ex new file mode 100644 index 0000000..2516074 --- /dev/null +++ b/lib/camp_api/grist/gauge.ex @@ -0,0 +1,14 @@ +defmodule CampApi.Grist.Gauge do + @moduledoc false + + alias CampApi.Grist + + @gauge_doc "wpwHRjzfdR9A" + @gauge_table "Infos" + + def get() do + {:ok, %{body: %{"records" => records}}} = Grist.get_records(@gauge_doc, @gauge_table) + + length(records) + end +end diff --git a/lib/camp_api_web/controllers/grist_controller.ex b/lib/camp_api_web/controllers/grist_controller.ex new file mode 100644 index 0000000..0e7323f --- /dev/null +++ b/lib/camp_api_web/controllers/grist_controller.ex @@ -0,0 +1,14 @@ +defmodule CampApiWeb.GristController do + use CampApiWeb, :controller + + alias CampApi.Grist + alias CampApi.Grist.Gauge + + action_fallback CampApiWeb.FallbackController + + def gauge(conn, _params) do + gauge = Gauge.get() + + render(conn, :gauge, gauge: gauge) + end +end diff --git a/lib/camp_api_web/controllers/grist_json.ex b/lib/camp_api_web/controllers/grist_json.ex new file mode 100644 index 0000000..746a4f3 --- /dev/null +++ b/lib/camp_api_web/controllers/grist_json.ex @@ -0,0 +1,7 @@ +defmodule CampApiWeb.GristJSON do + alias CampApi.Grist.Gauge + + def gauge(%{gauge: gauge}) do + %{gauge: gauge} + end +end diff --git a/lib/camp_api_web/router.ex b/lib/camp_api_web/router.ex index 0a74d62..bb1804e 100644 --- a/lib/camp_api_web/router.ex +++ b/lib/camp_api_web/router.ex @@ -7,6 +7,8 @@ defmodule CampApiWeb.Router do scope "/api", CampApiWeb do pipe_through :api + + get "/gauge", GristController, :gauge end # Enable LiveDashboard in development diff --git a/mix.exs b/mix.exs index fc07daa..fafc410 100644 --- a/mix.exs +++ b/mix.exs @@ -45,7 +45,8 @@ defmodule CampApi.MixProject do {:telemetry_poller, "~> 1.0"}, {:jason, "~> 1.2"}, {:dns_cluster, "~> 0.2.0"}, - {:bandit, "~> 1.5"} + {:bandit, "~> 1.5"}, + {:req, "~> 0.5.0"} ] end diff --git a/mix.lock b/mix.lock index a77cfc2..e822db9 100644 --- a/mix.lock +++ b/mix.lock @@ -1,9 +1,13 @@ %{ "bandit": {:hex, :bandit, "1.9.0", "6dc1ff2c30948dfecf32db574cc3447c7b9d70e0b61140098df3818870b01b76", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "2538aaa1663b40ca9cbd8ca1f8a540cb49e5baf34c6ffef068369cc45f9146f2"}, "dns_cluster": {:hex, :dns_cluster, "0.2.0", "aa8eb46e3bd0326bd67b84790c561733b25c5ba2fe3c7e36f28e88f384ebcb33", [:mix], [], "hexpm", "ba6f1893411c69c01b9e8e8f772062535a4cf70f3f35bcc964a324078d8c8240"}, + "finch": {:hex, :finch, "0.21.0", "b1c3b2d48af02d0c66d2a9ebfb5622be5c5ecd62937cf79a88a7f98d48a8290c", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "87dc6e169794cb2570f75841a19da99cfde834249568f2a5b121b809588a4377"}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, + "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"}, + "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, + "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "phoenix": {:hex, :phoenix, "1.8.3", "49ac5e485083cb1495a905e47eb554277bdd9c65ccb4fc5100306b350151aa95", [:mix], [{:bandit, "~> 1.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "36169f95cc2e155b78be93d9590acc3f462f1e5438db06e6248613f27c80caec"}, "phoenix_html": {:hex, :phoenix_html, "4.3.0", "d3577a5df4b6954cd7890c84d955c470b5310bb49647f0a114a6eeecc850f7ad", [:mix], [], "hexpm", "3eaa290a78bab0f075f791a46a981bbe769d94bc776869f4f3063a14f30497ad"}, "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.7", "405880012cb4b706f26dd1c6349125bfc903fb9e44d1ea668adaf4e04d4884b7", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "3a8625cab39ec261d48a13b7468dc619c0ede099601b084e343968309bd4d7d7"}, @@ -12,6 +16,7 @@ "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, "plug": {:hex, :plug, "1.19.1", "09bac17ae7a001a68ae393658aa23c7e38782be5c5c00c80be82901262c394c0", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "560a0017a8f6d5d30146916862aaf9300b7280063651dd7e532b8be168511e62"}, "plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"}, + "req": {:hex, :req, "0.5.17", "0096ddd5b0ed6f576a03dde4b158a0c727215b15d2795e59e0916c6971066ede", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0b8bc6ffdfebbc07968e59d3ff96d52f2202d0536f10fef4dc11dc02a2a43e39"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "telemetry_metrics": {:hex, :telemetry_metrics, "1.1.0", "5bd5f3b5637e0abea0426b947e3ce5dd304f8b3bc6617039e2b5a008adc02f8f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e7b79e8ddfde70adb6db8a6623d1778ec66401f366e9a8f5dd0955c56bc8ce67"}, "telemetry_poller": {:hex, :telemetry_poller, "1.3.0", "d5c46420126b5ac2d72bc6580fb4f537d35e851cc0f8dbd571acf6d6e10f5ec7", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "51f18bed7128544a50f75897db9974436ea9bfba560420b646af27a9a9b35211"}, From c95d877e68db1666104878acc92d84b5b9964922 Mon Sep 17 00:00:00 2001 From: Pierre de Lacroix Date: Thu, 22 Jan 2026 19:35:01 +0100 Subject: [PATCH 2/2] add fundraising API --- lib/camp_api/grist/fundraising.ex | 14 ++++++++++++++ lib/camp_api_web/controllers/grist_controller.ex | 7 +++++++ lib/camp_api_web/controllers/grist_json.ex | 9 +++++++++ lib/camp_api_web/router.ex | 2 ++ 4 files changed, 32 insertions(+) create mode 100644 lib/camp_api/grist/fundraising.ex diff --git a/lib/camp_api/grist/fundraising.ex b/lib/camp_api/grist/fundraising.ex new file mode 100644 index 0000000..1c14dba --- /dev/null +++ b/lib/camp_api/grist/fundraising.ex @@ -0,0 +1,14 @@ +defmodule CampApi.Grist.Fundraising do + @moduledoc false + + alias CampApi.Grist + + @gauge_doc "wWacvVWE9QtQ" + @gauge_table "Dons" + + def get() do + {:ok, %{body: %{"records" => records}}} = Grist.get_records(@gauge_doc, @gauge_table) + + records + end +end diff --git a/lib/camp_api_web/controllers/grist_controller.ex b/lib/camp_api_web/controllers/grist_controller.ex index 0e7323f..3637cdf 100644 --- a/lib/camp_api_web/controllers/grist_controller.ex +++ b/lib/camp_api_web/controllers/grist_controller.ex @@ -3,6 +3,7 @@ defmodule CampApiWeb.GristController do alias CampApi.Grist alias CampApi.Grist.Gauge + alias CampApi.Grist.Fundraising action_fallback CampApiWeb.FallbackController @@ -11,4 +12,10 @@ defmodule CampApiWeb.GristController do render(conn, :gauge, gauge: gauge) end + + def fundraising(conn, _params) do + fundraising = Fundraising.get() + + render(conn, :fundraising, fundraising: fundraising) + end end diff --git a/lib/camp_api_web/controllers/grist_json.ex b/lib/camp_api_web/controllers/grist_json.ex index 746a4f3..d87143f 100644 --- a/lib/camp_api_web/controllers/grist_json.ex +++ b/lib/camp_api_web/controllers/grist_json.ex @@ -4,4 +4,13 @@ defmodule CampApiWeb.GristJSON do def gauge(%{gauge: gauge}) do %{gauge: gauge} end + + def fundraising(%{fundraising: fundraising}) do + total = + fundraising + |> Enum.map(fn record -> get_in(record, ["fields", "Montant"]) end) + |> Enum.sum() + + %{total: total} + end end diff --git a/lib/camp_api_web/router.ex b/lib/camp_api_web/router.ex index bb1804e..d2f0653 100644 --- a/lib/camp_api_web/router.ex +++ b/lib/camp_api_web/router.ex @@ -9,6 +9,8 @@ defmodule CampApiWeb.Router do pipe_through :api get "/gauge", GristController, :gauge + + get "/fundraising", GristController, :fundraising end # Enable LiveDashboard in development