Skip to content

Commit

Permalink
Activity log endpoint (#2739)
Browse files Browse the repository at this point in the history
* Implements context function

* Implements the view

* Implements the controller

* Adds an entry to the router

* Adds tests

* Fixes field value in view

* Fixes type signature

* Make credo  happy

Small fixes about parentheses of zero arity functions and ordering of aliases in alphabetical order.

* Fixes tests; renames openapi spec tags

* Addresses PR comments

- Single view file, instead of two
- Adds title field in spec

* Renames field in schema

According to PR comment

* Fixes spelling

* Fixes more spellings
  • Loading branch information
gagandeepb authored Jul 4, 2024
1 parent c75617d commit bc874f1
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 2 deletions.
9 changes: 7 additions & 2 deletions lib/trento/activity_log.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ defmodule Trento.ActivityLog do
require Logger

require Trento.ActivityLog.RetentionPeriodUnit, as: RetentionPeriodUnit

alias Trento.ActivityLog.ActivityLog
alias Trento.ActivityLog.Settings

alias Trento.Repo

@spec get_settings() ::
Expand Down Expand Up @@ -38,6 +37,12 @@ defmodule Trento.ActivityLog do
end
end

@spec list_activity_log() :: list(ActivityLog.t())
def list_activity_log do
# This will be made filterable/paginatable in a later PR
Repo.all(ActivityLog)
end

defp log_error({:error, _} = error, message) do
Logger.error("#{message}: #{inspect(error)}")
error
Expand Down
2 changes: 2 additions & 0 deletions lib/trento/activity_logging/activity_log.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ defmodule Trento.ActivityLog.ActivityLog do
use Ecto.Schema
import Ecto.Changeset

@type t() :: %__MODULE__{}

@primary_key {:id, :binary_id, autogenerate: true}
schema "activity_logs" do
field :type, :string
Expand Down
25 changes: 25 additions & 0 deletions lib/trento_web/controllers/v1/activity_log_controller.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
defmodule TrentoWeb.V1.ActivityLogController do
use TrentoWeb, :controller
use OpenApiSpex.ControllerSpecs

alias Trento.ActivityLog
alias TrentoWeb.OpenApi.V1.Schema

plug OpenApiSpex.Plug.CastAndValidate, json_render_error_v2: true
action_fallback TrentoWeb.FallbackController

operation :get_activity_log,
summary: "Fetches the Activity Log entries.",
tags: ["Platform"],
responses: [
ok: {"Activity Log settings fetched successfully", "application/json", Schema.ActivityLog}
]

def get_activity_log(conn, _) do
with activity_log_entries <- ActivityLog.list_activity_log() do
render(conn, "activity_log.json", %{
activity_log: activity_log_entries
})
end
end
end
35 changes: 35 additions & 0 deletions lib/trento_web/openapi/v1/schema/activity_log.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
defmodule TrentoWeb.OpenApi.V1.Schema.ActivityLog do
@moduledoc false

require OpenApiSpex
alias OpenApiSpex.Schema

OpenApiSpex.schema(%{
title: "ActivityLog",
description: "Activity Log for the current installation.",
type: :array,
items: %Schema{
title: "ActivityLogEntry",
type: :object,
additionalProperties: false,
properties: %{
type: %Schema{
type: :string,
description: "Type of Activity Log entry."
},
actor: %Schema{
type: :string,
description: "Actor causing an Activity Log entry. E.g. System or a specific user."
},
metadata: %Schema{
type: :object
},
occurred_on: %Schema{
type: :string,
description: "Timestamp upon Activity Log entry insertion."
}
},
required: [:type, :actor, :metadata, :occurred_on]
}
})
end
2 changes: 2 additions & 0 deletions lib/trento_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ defmodule TrentoWeb.Router do

get "/about", AboutController, :info

get "/activity_log", ActivityLogController, :get_activity_log

get "/installation/api-key", InstallationController, :get_api_key

get "/hosts", HostController, :list
Expand Down
17 changes: 17 additions & 0 deletions lib/trento_web/views/v1/activity_log_view.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
defmodule TrentoWeb.V1.ActivityLogView do
use TrentoWeb, :view

def render("activity_log.json", %{activity_log: entries}) do
render_many(entries, __MODULE__, "activity_log_entry.json", as: :entries)
end

def render("activity_log_entry.json", %{entries: entry}) do
%{
type: entry.type,
actor: entry.actor,
metadata: entry.metadata,
# Time of occurrence approximated by time of insertion in DB.
occurred_on: entry.inserted_at
}
end
end
9 changes: 9 additions & 0 deletions test/support/factory.ex
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ defmodule Trento.Factory do
InstallationSettings
}

alias Trento.ActivityLog.ActivityLog, as: ActivityLogEntry
alias Trento.ActivityLog.RetentionTime
alias Trento.ActivityLog.Settings, as: ActivityLogSettings

Expand Down Expand Up @@ -1025,6 +1026,14 @@ defmodule Trento.Factory do
}
end

def activity_log_entry_factory do
%ActivityLogEntry{
type: Faker.Pokemon.name(),
actor: Enum.random(["user", "system"]),
metadata: %{}
}
end

def user_factory do
password = Faker.Pokemon.name()

Expand Down
43 changes: 43 additions & 0 deletions test/trento_web/controllers/v1/activity_log_controller_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
defmodule TrentoWeb.V1.ActivityLogControllerTest do
use TrentoWeb.ConnCase, async: true

import Trento.Factory
import OpenApiSpex.TestAssertions

alias TrentoWeb.OpenApi.V1.ApiSpec

describe "ActivityLogController" do
setup do
%{api_spec: ApiSpec.spec()}
end

test "should return activity logs after inserting a few entries.", %{
conn: conn,
api_spec: api_spec
} do
insert(:activity_log_entry)
insert(:activity_log_entry)

resp =
conn
|> get("/api/v1/activity_log")
|> json_response(200)

assert length(resp) == 2
assert_schema(resp, "ActivityLog", api_spec)
end

test "should return valid response (empty list) if no activity logs entries exist", %{
conn: conn,
api_spec: api_spec
} do
resp =
conn
|> get("/api/v1/activity_log")
|> json_response(200)

assert resp == []
assert_schema(resp, "ActivityLog", api_spec)
end
end
end

0 comments on commit bc874f1

Please sign in to comment.