From c28848d811b4af25e5d0e7bff5d4278ad66ae817 Mon Sep 17 00:00:00 2001 From: Stefan Haslinger Date: Tue, 22 Mar 2022 11:10:40 +0100 Subject: [PATCH] added weather tracker json endpoint including controller, changeset and context; removed swoosh, added decimal dependency --- config/config.exs | 25 ----------- config/dev.exs | 42 +----------------- lib/weather_tracker/mailer.ex | 3 -- lib/weather_tracker/weather_conditions.ex | 12 +++++ .../weather_conditions/weather_conditions.ex | 44 +++++++++++++++++++ .../weather_conditions_controller.ex | 30 +++++++++++++ lib/weather_tracker_web/router.ex | 13 +----- mix.exs | 17 +------ ...220322074939_set_up_weather_data_table.exs | 28 ++++++++++++ 9 files changed, 118 insertions(+), 96 deletions(-) delete mode 100644 lib/weather_tracker/mailer.ex create mode 100644 lib/weather_tracker/weather_conditions.ex create mode 100644 lib/weather_tracker/weather_conditions/weather_conditions.ex create mode 100644 lib/weather_tracker_web/controllers/weather_conditions_controller.ex create mode 100644 priv/repo/migrations/20220322074939_set_up_weather_data_table.exs diff --git a/config/config.exs b/config/config.exs index daa863f..516c0f6 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,36 +1,15 @@ -# This file is responsible for configuring your application -# and its dependencies with the aid of the Config module. -# -# This configuration file is loaded before any dependency and -# is restricted to this project. - -# General application configuration import Config config :weather_tracker, ecto_repos: [WeatherTracker.Repo], generators: [binary_id: true] -# Configures the endpoint config :weather_tracker, WeatherTrackerWeb.Endpoint, url: [host: "localhost"], render_errors: [view: WeatherTrackerWeb.ErrorView, accepts: ~w(json), layout: false], pubsub_server: WeatherTracker.PubSub, live_view: [signing_salt: "Fsg8to5A"] -# Configures the mailer -# -# By default it uses the "Local" adapter which stores the emails -# locally. You can see the emails in your browser, at "/dev/mailbox". -# -# For production it's recommended to configure a different adapter -# at the `config/runtime.exs`. -config :weather_tracker, WeatherTracker.Mailer, adapter: Swoosh.Adapters.Local - -# Swoosh API client is needed for adapters other than SMTP. -config :swoosh, :api_client, false - -# Configure esbuild (the version is required) config :esbuild, version: "0.14.0", default: [ @@ -40,14 +19,10 @@ config :esbuild, env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} ] -# Configures Elixir's Logger config :logger, :console, format: "$time $metadata[$level] $message\n", metadata: [:request_id] -# Use Jason for JSON parsing in Phoenix config :phoenix, :json_library, Jason -# 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/config/dev.exs b/config/dev.exs index a110117..611ff1f 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -1,6 +1,5 @@ import Config -# Configure your database config :weather_tracker, WeatherTracker.Repo, username: "postgres", password: "postgres", @@ -10,55 +9,16 @@ config :weather_tracker, WeatherTracker.Repo, show_sensitive_data_on_connection_error: true, pool_size: 10 -# For development, we disable any cache and enable -# debugging and code reloading. -# -# The watchers configuration can be used to run external -# watchers to your application. For example, we use it -# with esbuild to bundle .js and .css sources. config :weather_tracker, WeatherTrackerWeb.Endpoint, - # Binding to loopback ipv4 address prevents access from other machines. - # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. - http: [ip: {127, 0, 0, 1}, port: 4000], + http: [ip: {0, 0, 0, 0}, port: 4000], check_origin: false, code_reloader: true, debug_errors: true, secret_key_base: "B2lyyYo7TXCmYFhzSYG/oXfEnwIqUBu47pd53IT1HNSHzHqsdjQu5GXzFUPAjYgd", watchers: [ - # Start the esbuild watcher by calling Esbuild.install_and_run(:default, args) esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]} ] -# ## SSL Support -# -# In order to use HTTPS in development, a self-signed -# certificate can be generated by running the following -# Mix task: -# -# mix phx.gen.cert -# -# Note that this task requires Erlang/OTP 20 or later. -# Run `mix help phx.gen.cert` for more information. -# -# The `http:` config above can be replaced with: -# -# https: [ -# port: 4001, -# cipher_suite: :strong, -# keyfile: "priv/cert/selfsigned_key.pem", -# certfile: "priv/cert/selfsigned.pem" -# ], -# -# If desired, both `http:` and `https:` keys can be -# configured to run both http and https servers on -# different ports. - -# Do not include metadata nor timestamps in development logs config :logger, :console, format: "[$level] $message\n" - -# Set a higher stacktrace during development. Avoid configuring such -# in production as building large stacktraces may be expensive. config :phoenix, :stacktrace_depth, 20 - -# Initialize plugs at runtime for faster development compilation config :phoenix, :plug_init_mode, :runtime diff --git a/lib/weather_tracker/mailer.ex b/lib/weather_tracker/mailer.ex deleted file mode 100644 index 44320f6..0000000 --- a/lib/weather_tracker/mailer.ex +++ /dev/null @@ -1,3 +0,0 @@ -defmodule WeatherTracker.Mailer do - use Swoosh.Mailer, otp_app: :weather_tracker -end diff --git a/lib/weather_tracker/weather_conditions.ex b/lib/weather_tracker/weather_conditions.ex new file mode 100644 index 0000000..e2ee3a6 --- /dev/null +++ b/lib/weather_tracker/weather_conditions.ex @@ -0,0 +1,12 @@ +defmodule WeatherTracker.WeatherConditions do + alias WeatherTracker.{ + Repo, + WeatherConditions.WeatherCondition + } + + def create_entry(attrs) do + %WeatherCondition{} + |> WeatherCondition.create_changeset(attrs) + |> Repo.insert() + end +end diff --git a/lib/weather_tracker/weather_conditions/weather_conditions.ex b/lib/weather_tracker/weather_conditions/weather_conditions.ex new file mode 100644 index 0000000..31e5fab --- /dev/null +++ b/lib/weather_tracker/weather_conditions/weather_conditions.ex @@ -0,0 +1,44 @@ +defmodule WeatherTracker.WeatherConditions.WeatherCondition do + use Ecto.Schema + import Ecto.Changeset + + @allowed_fields [ + :altitude_m, + :pressure_pa, + :temperature_c, + :co2_eq_ppm, + :tvoc_ppb, + :uva_raw, + :uvb_raw, + :uvia, + :uvib, + :uvi + ] + + @derive {Jason.Encoder, only: @allowed_fields} + @primary_key false + schema "weather_conditions" do + field :timestamp, :naive_datetime + field :altitude_m, :decimal + field :pressure_pa, :decimal + field :temperature_c, :decimal + field :co2_eq_ppm, :decimal + field :tvoc_ppb, :decimal + field :uva_raw, :decimal + field :uvb_raw, :decimal + field :uvia, :decimal + field :uvib, :decimal + field :uvi, :decimal + end + + def create_changeset(weather_condition = %__MODULE__{}, attrs) do + timestamp = + NaiveDateTime.utc_now() + |> NaiveDateTime.truncate(:second) + + weather_condition + |> cast(attrs, @allowed_fields) + |> validate_required(@allowed_fields) + |> put_change(:timestamp, timestamp) + end +end diff --git a/lib/weather_tracker_web/controllers/weather_conditions_controller.ex b/lib/weather_tracker_web/controllers/weather_conditions_controller.ex new file mode 100644 index 0000000..1aed138 --- /dev/null +++ b/lib/weather_tracker_web/controllers/weather_conditions_controller.ex @@ -0,0 +1,30 @@ +defmodule WeatherTrackerWeb.WeatherConditionsController do + use WeatherTrackerWeb, :controller + + require Logger + + alias WeatherTracker.{ + WeatherConditions, + WeatherConditions.WeatherCondition + } + + def create(conn, params) do + IO.inspect(params) + + case WeatherConditions.create_entry(params) do + {:ok, weather_condition = %WeatherCondition{}} -> + Logger.debug("Successfully created a weather condition entry") + + conn + |> put_status(:created) + |> json(weather_condition) + + error -> + Logger.warn("Failed to create a weather entry: #{inspect(error)}") + + conn + |> put_status(:unprocessable_entity) + |> json(%{message: "Poorly formatted payload"}) + end + end +end diff --git a/lib/weather_tracker_web/router.ex b/lib/weather_tracker_web/router.ex index a077a38..e4cc60f 100644 --- a/lib/weather_tracker_web/router.ex +++ b/lib/weather_tracker_web/router.ex @@ -7,17 +7,6 @@ defmodule WeatherTrackerWeb.Router do scope "/api", WeatherTrackerWeb do pipe_through :api - end - - # Enables the Swoosh mailbox preview in development. - # - # Note that preview only shows emails that were sent by the same - # node running the Phoenix server. - if Mix.env() == :dev do - scope "/dev" do - pipe_through [:fetch_session, :protect_from_forgery] - - forward "/mailbox", Plug.Swoosh.MailboxPreview - end + post "/weather-conditions", WeatherConditionsController, :create end end diff --git a/mix.exs b/mix.exs index 453782e..b04fda6 100644 --- a/mix.exs +++ b/mix.exs @@ -14,9 +14,6 @@ defmodule WeatherTracker.MixProject do ] end - # Configuration for the OTP application. - # - # Type `mix help compile.app` for more information. def application do [ mod: {WeatherTracker.Application, []}, @@ -24,13 +21,9 @@ defmodule WeatherTracker.MixProject do ] end - # Specifies which paths to compile per environment. defp elixirc_paths(:test), do: ["lib", "test/support"] defp elixirc_paths(_), do: ["lib"] - # Specifies your project dependencies. - # - # Type `mix help deps` for examples and options. defp deps do [ {:phoenix, "~> 1.6.6"}, @@ -38,20 +31,14 @@ defmodule WeatherTracker.MixProject do {:ecto_sql, "~> 3.6"}, {:postgrex, ">= 0.0.0"}, {:esbuild, "~> 0.3", runtime: Mix.env() == :dev}, - {:swoosh, "~> 1.3"}, {:telemetry_metrics, "~> 0.6"}, {:telemetry_poller, "~> 1.0"}, {:jason, "~> 1.2"}, - {:plug_cowboy, "~> 2.5"} + {:plug_cowboy, "~> 2.5"}, + {:decimal, "~> 2.0.0"} ] end - # Aliases are shortcuts or tasks specific to the current project. - # For example, to install project dependencies and perform other setup tasks, run: - # - # $ mix setup - # - # See the documentation for `Mix` for more info on aliases. defp aliases do [ setup: ["deps.get", "ecto.setup"], diff --git a/priv/repo/migrations/20220322074939_set_up_weather_data_table.exs b/priv/repo/migrations/20220322074939_set_up_weather_data_table.exs new file mode 100644 index 0000000..482d086 --- /dev/null +++ b/priv/repo/migrations/20220322074939_set_up_weather_data_table.exs @@ -0,0 +1,28 @@ +defmodule WeatherTracker.Repo.Migrations.SetUpWeatherDataTable do + use Ecto.Migration + + def up do + execute("CREATE EXTENSION IF NOT EXISTS timescaledb") + + create table(:weather_conditions, primary_key: false) do + add :timestamp, :naive_datetime, null: false + add :altitude_m, :decimal, null: false + add :pressure_pa, :decimal, null: false + add :temperature_c, :decimal, null: false + add :co2_eq_ppm, :decimal, null: false + add :tvoc_ppb, :decimal, null: false + add :uva_raw, :decimal, null: false + add :uvb_raw, :decimal, null: false + add :uvia, :decimal, null: false + add :uvib, :decimal, null: false + add :uvi, :decimal, null: false + end + + execute("SELECT create_hypertable('weather_conditions', 'timestamp')") + end + + def down do + drop table(:weather_conditions) + execute("DROP EXTENSION IF EXISTS timescaledb") + end +end