add graph endpoint
This commit is contained in:
parent
ea4cd09677
commit
91d1c62e06
|
@ -40,7 +40,9 @@ config :backend, :crawler,
|
|||
config :backend, Backend.Scheduler,
|
||||
jobs: [
|
||||
# At midnight every day
|
||||
{"@daily", {Backend.Scheduler, :prune_crawls, [1, "month"]}}
|
||||
{"@daily", {Backend.Scheduler, :prune_crawls, [1, "month"]}},
|
||||
# 00.15 daily
|
||||
{"15 0 * * *", {Backend.Scheduler, :generate_edges, []}}
|
||||
]
|
||||
|
||||
# Import environment specific config. This must remain at the bottom
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
defmodule Backend.Api do
|
||||
alias Backend.{Instance, Repo}
|
||||
alias Backend.{Crawl, Edge, Instance, Repo}
|
||||
import Ecto.Query
|
||||
|
||||
@spec list_instances() :: [Instance.t()]
|
||||
|
@ -14,4 +14,34 @@ defmodule Backend.Api do
|
|||
|> preload(:peers)
|
||||
|> Repo.get_by!(domain: domain)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns a list of instances that
|
||||
* have at least one successful crawl
|
||||
* have a user count (required to give the instance a size on the graph)
|
||||
"""
|
||||
@spec list_nodes() :: [Instance.t()]
|
||||
def list_nodes() do
|
||||
crawl_subquery =
|
||||
Crawl
|
||||
|> select([c], %{
|
||||
instance_domain: c.instance_domain,
|
||||
crawl_count: count(c.id)
|
||||
})
|
||||
|> where([c], is_nil(c.error))
|
||||
|> group_by([c], c.instance_domain)
|
||||
|
||||
Instance
|
||||
|> join(:inner, [i], c in subquery(crawl_subquery), on: i.domain == c.instance_domain)
|
||||
|> where([i, c], c.crawl_count > 0 and not is_nil(i.user_count))
|
||||
|> select([c], [:domain, :user_count, :x, :y])
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
@spec list_edges() :: [Edge.t()]
|
||||
def list_edges() do
|
||||
Edge
|
||||
|> select([e], [:id, :source_domain, :target_domain, :weight])
|
||||
|> Repo.all()
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
defmodule BackendWeb.GraphController do
|
||||
use BackendWeb, :controller
|
||||
|
||||
alias Backend.Api
|
||||
|
||||
action_fallback BackendWeb.FallbackController
|
||||
|
||||
def index(conn, _params) do
|
||||
nodes = Api.list_nodes()
|
||||
edges = Api.list_edges()
|
||||
render(conn, "index.json", nodes: nodes, edges: edges)
|
||||
end
|
||||
end
|
|
@ -9,5 +9,6 @@ defmodule BackendWeb.Router do
|
|||
pipe_through :api
|
||||
|
||||
resources "/instances", InstanceController, only: [:index, :show]
|
||||
resources "/graph", GraphController, only: [:index]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
defmodule BackendWeb.GraphView do
|
||||
use BackendWeb, :view
|
||||
alias BackendWeb.GraphView
|
||||
require Logger
|
||||
|
||||
def render("index.json", %{nodes: nodes, edges: edges}) do
|
||||
%{
|
||||
nodes: render_many(nodes, GraphView, "node.json"),
|
||||
edges: render_many(edges, GraphView, "edge.json")
|
||||
}
|
||||
end
|
||||
|
||||
def render("node.json", %{graph: node}) do
|
||||
Logger.info(inspect(node))
|
||||
|
||||
size =
|
||||
case node.user_count > 1 do
|
||||
true -> :math.log(node.user_count)
|
||||
false -> 1
|
||||
end
|
||||
|
||||
%{
|
||||
id: node.domain,
|
||||
label: node.domain,
|
||||
size: size,
|
||||
x: node.x,
|
||||
y: node.y
|
||||
}
|
||||
end
|
||||
|
||||
def render("edge.json", %{graph: edge}) do
|
||||
%{
|
||||
id: edge.id,
|
||||
source: edge.source_domain,
|
||||
target: edge.target_domain,
|
||||
size: edge.weight
|
||||
}
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
defmodule Backend.Repo.Migrations.AddInstanceCoords do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table(:instances) do
|
||||
add :x, :float
|
||||
add :y, :float
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,104 @@
|
|||
defmodule BackendWeb.GraphControllerTest do
|
||||
use BackendWeb.ConnCase
|
||||
|
||||
alias Backend.Api
|
||||
alias Backend.Api.Graph
|
||||
|
||||
@create_attrs %{
|
||||
id: "some id",
|
||||
label: "some label",
|
||||
size: 120.5,
|
||||
x: 120.5,
|
||||
y: 120.5
|
||||
}
|
||||
@update_attrs %{
|
||||
id: "some updated id",
|
||||
label: "some updated label",
|
||||
size: 456.7,
|
||||
x: 456.7,
|
||||
y: 456.7
|
||||
}
|
||||
@invalid_attrs %{id: nil, label: nil, size: nil, x: nil, y: nil}
|
||||
|
||||
def fixture(:graph) do
|
||||
{:ok, graph} = Api.create_graph(@create_attrs)
|
||||
graph
|
||||
end
|
||||
|
||||
setup %{conn: conn} do
|
||||
{:ok, conn: put_req_header(conn, "accept", "application/json")}
|
||||
end
|
||||
|
||||
describe "index" do
|
||||
test "lists all nodes", %{conn: conn} do
|
||||
conn = get(conn, Routes.graph_path(conn, :index))
|
||||
assert json_response(conn, 200)["data"] == []
|
||||
end
|
||||
end
|
||||
|
||||
describe "create graph" do
|
||||
test "renders graph when data is valid", %{conn: conn} do
|
||||
conn = post(conn, Routes.graph_path(conn, :create), graph: @create_attrs)
|
||||
assert %{"id" => id} = json_response(conn, 201)["data"]
|
||||
|
||||
conn = get(conn, Routes.graph_path(conn, :show, id))
|
||||
|
||||
assert %{
|
||||
"id" => id,
|
||||
"id" => "some id",
|
||||
"label" => "some label",
|
||||
"size" => 120.5,
|
||||
"x" => 120.5,
|
||||
"y" => 120.5
|
||||
} = json_response(conn, 200)["data"]
|
||||
end
|
||||
|
||||
test "renders errors when data is invalid", %{conn: conn} do
|
||||
conn = post(conn, Routes.graph_path(conn, :create), graph: @invalid_attrs)
|
||||
assert json_response(conn, 422)["errors"] != %{}
|
||||
end
|
||||
end
|
||||
|
||||
describe "update graph" do
|
||||
setup [:create_graph]
|
||||
|
||||
test "renders graph when data is valid", %{conn: conn, graph: %Graph{id: id} = graph} do
|
||||
conn = put(conn, Routes.graph_path(conn, :update, graph), graph: @update_attrs)
|
||||
assert %{"id" => ^id} = json_response(conn, 200)["data"]
|
||||
|
||||
conn = get(conn, Routes.graph_path(conn, :show, id))
|
||||
|
||||
assert %{
|
||||
"id" => id,
|
||||
"id" => "some updated id",
|
||||
"label" => "some updated label",
|
||||
"size" => 456.7,
|
||||
"x" => 456.7,
|
||||
"y" => 456.7
|
||||
} = json_response(conn, 200)["data"]
|
||||
end
|
||||
|
||||
test "renders errors when data is invalid", %{conn: conn, graph: graph} do
|
||||
conn = put(conn, Routes.graph_path(conn, :update, graph), graph: @invalid_attrs)
|
||||
assert json_response(conn, 422)["errors"] != %{}
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete graph" do
|
||||
setup [:create_graph]
|
||||
|
||||
test "deletes chosen graph", %{conn: conn, graph: graph} do
|
||||
conn = delete(conn, Routes.graph_path(conn, :delete, graph))
|
||||
assert response(conn, 204)
|
||||
|
||||
assert_error_sent 404, fn ->
|
||||
get(conn, Routes.graph_path(conn, :show, graph))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp create_graph(_) do
|
||||
graph = fixture(:graph)
|
||||
{:ok, graph: graph}
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue