Skip to content
10 changes: 10 additions & 0 deletions lib/cgrates_web_jsonapi/cdrs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ defmodule CgratesWebJsonapi.Cdrs do
|> Enum.map(&CdrsStats.new/1)
end

def extra do
request = "SELECT DISTINCT extra_fields
FROM (
SELECT jsonb_object_keys(extra_fields) AS extra_fields
FROM cdrs
) AS subquery"

request |> Repo.query() |> elem(1) |> Map.get(:rows) |> List.flatten()
end

defp group_by_created_at(q, :daily) do
q |> group_by([r], fragment("date_trunc('day', ?)", r.created_at))
end
Expand Down
46 changes: 46 additions & 0 deletions lib/cgrates_web_jsonapi/ets_cache.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
defmodule CgratesWebJsonapi.EtsCache do
@moduledoc """
Cache via ETS.
"""

@spec get(any, atom | :ets.tid(), any) :: list(any)
def get(args, table_name, opts \\ []) do
case lookup(args, table_name) do
nil ->
ttl = Keyword.get(opts, :ttl, 86400)
cache_apply(args.(), ttl)

result ->
result
end
end

defp lookup(args, table_name) do
maybe_create_table(table_name)

case :ets.lookup(table_name, [args]) do
[result | _] -> check_freshness(result)
[] -> nil
end
end

defp check_freshness({result, expiration}) do
cond do
expiration > :os.system_time(:seconds) -> result
:else -> nil
end
end

defp cache_apply(args, ttl) do
result = args
expiration = :os.system_time(:seconds) + ttl
:ets.insert(:extra_fields, {args, result, expiration})
result
end

defp maybe_create_table(table_name) do
if Enum.member?(:ets.all(), table_name) == false do
:ets.new(table_name, [:public, :named_table])
end
end
end
96 changes: 96 additions & 0 deletions lib/cgrates_web_jsonapi/tenants.ex
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,100 @@ defmodule CgratesWebJsonapi.Tenants do
def change_tenant(%Tenant{} = tenant, attrs \\ %{}) do
Tenant.update_changeset(tenant, attrs)
end

alias CgratesWebJsonapi.Tenants.Membership

@doc """
Returns the list of memberships.

## Examples

iex> list_memberships()
[%Membership{}, ...]

"""
def list_memberships do
Repo.all(Membership)
end

@doc """
Gets a single membership.

Raises `Ecto.NoResultsError` if the Membership does not exist.

## Examples

iex> get_membership!(123)
%Membership{}

iex> get_membership!(456)
** (Ecto.NoResultsError)

"""
def get_membership!(id), do: Repo.get!(Membership, id)

@doc """
Creates a membership.

## Examples

iex> create_membership(%{field: value})
{:ok, %Membership{}}

iex> create_membership(%{field: bad_value})
{:error, %Ecto.Changeset{}}

"""
def create_membership(attrs \\ %{}) do
%Membership{}
|> Membership.changeset(attrs)
|> Repo.insert()
end

@doc """
Updates a membership.

## Examples

iex> update_membership(membership, %{field: new_value})
{:ok, %Membership{}}

iex> update_membership(membership, %{field: bad_value})
{:error, %Ecto.Changeset{}}

"""
def update_membership(%Membership{} = membership, attrs) do
membership
|> Membership.changeset(attrs)
|> Repo.update()
end

@doc """
Deletes a membership.

## Examples

iex> delete_membership(membership)
{:ok, %Membership{}}

iex> delete_membership(membership)
{:error, %Ecto.Changeset{}}

"""
def delete_membership(%Membership{} = membership) do
Repo.delete(membership)
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking membership changes.

## Examples

iex> change_membership(membership)
%Ecto.Changeset{data: %Membership{}}

"""
def change_membership(%Membership{} = membership, attrs \\ %{}) do
Membership.changeset(membership, attrs)
end
end
22 changes: 22 additions & 0 deletions lib/cgrates_web_jsonapi/tenants/membership.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule CgratesWebJsonapi.Tenants.Membership do
use Ecto.Schema
import Ecto.Changeset

alias CgratesWebJsonapi.Tenants.Tenant
alias CgratesWebJsonapi.Auth.User

schema "memberships" do
field :role, :integer
belongs_to :tenant, Tenant, type: :string
belongs_to :user, User

timestamps()
end

@doc false
def changeset(membership, attrs) do
membership
|> cast(attrs, [:role])
|> validate_required([:role])
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule CgratesWebJsonapiWeb.CdrExtraFieldController do
use CgratesWebJsonapiWeb, :controller
use PhoenixSwagger

alias CgratesWebJsonapi.Cdrs
alias CgratesWebJsonapi.EtsCache

swagger_path :index do
get("/api/cdr-extra-fields")
CommonSwaggerParams.authorization()
CommonSwaggerParams.content_type()

description("An array of string values of used extra_fields")

response(200, "OK")
end

def index(conn, _) do
extra_fields = fn -> Cdrs.extra() end
render(conn, "extra_fields.json", data: EtsCache.get(extra_fields, :extra_fields))
end
end
42 changes: 42 additions & 0 deletions lib/cgrates_web_jsonapi_web/controllers/membership_controller.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
defmodule CgratesWebJsonapiWeb.MembershipController do
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add swagger docs plz

use CgratesWebJsonapiWeb, :controller

alias CgratesWebJsonapi.Tenants
alias CgratesWebJsonapi.Tenants.Membership

def index(conn, _params) do
memberships = Tenants.list_memberships()
render(conn, "index.json", memberships: memberships)
end

def create(conn, %{"membership" => membership_params}) do
with {:ok, %Membership{} = membership} <- Tenants.create_membership(membership_params) do
conn
|> put_status(:created)
|> put_resp_header("location", Routes.membership_path(conn, :show, membership))
|> render("show.json", membership: membership)
end
end

def show(conn, %{"id" => id}) do
membership = Tenants.get_membership!(id)
render(conn, "show.json", membership: membership)
end

def update(conn, %{"id" => id, "membership" => membership_params}) do
membership = Tenants.get_membership!(id)

with {:ok, %Membership{} = membership} <-
Tenants.update_membership(membership, membership_params) do
render(conn, "show.json", membership: membership)
end
end

def delete(conn, %{"id" => id}) do
membership = Tenants.get_membership!(id)

with {:ok, %Membership{}} <- Tenants.delete_membership(membership) do
send_resp(conn, :no_content, "")
end
end
end
2 changes: 2 additions & 0 deletions lib/cgrates_web_jsonapi_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,10 @@ defmodule CgratesWebJsonapiWeb.Router do
post("/tp-timings/delete_all", TpTimingController, :delete_all)
resources("/tp-timings", TpTimingController, except: [:new, :edit])
resources("/users", UserController, except: [:new, :edit])
resources("/cdr-extra-fields", CdrExtraFieldController, only: [:index])
resources("/cdr-stats", CdrStatController, only: [:index])
resources("/tenants", TenantController, only: [:show, :update])
resources("/memberships", MembershipController)
end

scope "/uploaders", CgratesWebJsonapiWeb do
Expand Down
6 changes: 6 additions & 0 deletions lib/cgrates_web_jsonapi_web/views/cdr_extra_field_view.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
defmodule CgratesWebJsonapiWeb.CdrExtraFieldView do
use CgratesWebJsonapiWeb, :view
use JaSerializer.PhoenixView

def render("extra_fields.json", %{data: data}), do: data
end
16 changes: 16 additions & 0 deletions lib/cgrates_web_jsonapi_web/views/membership_view.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
defmodule CgratesWebJsonapiWeb.MembershipView do
use CgratesWebJsonapiWeb, :view
alias CgratesWebJsonapiWeb.MembershipView

def render("index.json", %{memberships: memberships}) do
%{data: render_many(memberships, MembershipView, "membership.json")}
end

def render("show.json", %{membership: membership}) do
%{data: render_one(membership, MembershipView, "membership.json")}
end

def render("membership.json", %{membership: membership}) do
%{id: membership.id, role: membership.role}
end
end
16 changes: 16 additions & 0 deletions priv/repo/migrations/20210517174717_create_memberships.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
defmodule CgratesWebJsonapi.Repo.Migrations.CreateMemberships do
use Ecto.Migration

def change do
create table(:memberships) do
add(:role, :integer)
add(:tenant_id, references(:tenants, on_delete: :nothing, type: :string))
add(:user_id, references(:users, on_delete: :nothing))

timestamps()
end

create(index(:memberships, [:tenant_id]))
create(index(:memberships, [:user_id]))
end
end
27 changes: 27 additions & 0 deletions priv/static/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,33 @@
"Call"
]
}
},
"/api/cdr-extra-fields": {
"get": {
"description": "An array of string values of used extra_fields",
"operationId": "CgratesWebJsonapiWeb.CdrExtraFieldController.index",
"parameters": [
{
"description": "OAuth2 access token",
"in": "header",
"name": "Authorization",
"required": true,
"type": "string"
}
],
"produces": [
"application/vnd.api+json"
],
"responses": {
"200": {
"description": "OK"
}
},
"summary": "",
"tags": [
"CdrExtraField"
]
}
}
},
"swagger": "2.0",
Expand Down
Loading