diff --git a/config/config.exs b/config/config.exs index 14b9539..64c6d44 100644 --- a/config/config.exs +++ b/config/config.exs @@ -14,7 +14,7 @@ config :schema_server, SchemaWeb.Endpoint, config :logger, :console, handle_otp_reports: true, handle_sasl_reports: true, - format: "$time $metadata[$level] $message\n", + format: "$date $time [$level] $metadata $message\n", metadata: [:request_id] # Use Jason for JSON parsing in Phoenix diff --git a/config/dev.exs b/config/dev.exs index a353ee4..f1c0b68 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -29,8 +29,7 @@ config :schema_server, SchemaWeb.Endpoint, config :logger, :console, level: :debug, - format: "[$level] $message\n $metadata\n", - # metadata: [:pid, :mfa, :line] + format: "[$level] $metadata $message\n", metadata: [:mfa, :line] # Set a higher stacktrace during development. Avoid configuring such diff --git a/config/prod.exs b/config/prod.exs index 9cfa924..53f0dcf 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -2,6 +2,6 @@ import Config # Do not print debug messages in production config :logger, - level: :info + level: :warning config :phoenix, :serve_endpoints, true diff --git a/lib/schema/graph.ex b/lib/schema/graph.ex index 32fef11..22baf41 100644 --- a/lib/schema/graph.ex +++ b/lib/schema/graph.ex @@ -35,17 +35,15 @@ defmodule Schema.Graph do end defp build_nodes(nodes, class) do - name = class.name - Map.get(class, :objects) |> Enum.reduce(nodes, fn {_name, obj}, acc -> - # avoid recursive calls - if name != obj.name do - node = %{ - id: make_id(obj.name, obj[:extension]), - label: obj.caption - } + node = %{ + id: make_id(obj.name, obj[:extension]), + label: obj.caption + } + # Don't add class/object that is already added (present infinite loop) + if not nodes_member?(nodes, node) do [node | acc] else acc @@ -56,12 +54,15 @@ defmodule Schema.Graph do defp make_id(name, nil) do name end - + defp make_id(name, ext) do - # name Path.join(ext, name) end - + + defp nodes_member?(nodes, node) do + Enum.any?(nodes, fn n -> n.id == node.id end) + end + defp build_edges(class) do objects = Map.new(class.objects) build_edges([], class, objects) @@ -72,20 +73,26 @@ defmodule Schema.Graph do |> Enum.reduce(edges, fn {name, obj}, acc -> case obj.type do "object_t" -> - edge = %{ - source: Atom.to_string(obj[:_source]), - group: obj[:group], - requirement: obj[:requirement] || "optional", - from: make_id(class.name, class[:extension]), - to: obj.object_type, - label: Atom.to_string(name) - } - |> add_profile(obj[:profile]) + # For a recursive definition, we need to add the edge, creating the looping edge + # and then we don't want to continue searching this path. + recursive? = edges_member?(acc, obj) + + edge = + %{ + source: Atom.to_string(obj[:_source]), + group: obj[:group], + requirement: obj[:requirement] || "optional", + from: make_id(class.name, class[:extension]), + to: obj.object_type, + label: Atom.to_string(name) + } + |> add_profile(obj[:profile]) acc = [edge | acc] - # avoid recursive links - if class.name != obj.object_type do + # For recursive definitions, we've already added the edge creating the loop in the graph. + # There's no need to recurse further (avoid infinite loops). + if not recursive? do o = objects[String.to_atom(obj.object_type)] build_edges(acc, o, objects) else @@ -98,9 +105,14 @@ defmodule Schema.Graph do end) end + defp edges_member?(edges, obj) do + Enum.any?(edges, fn edge -> obj.object_type == edge.to end) + end + defp add_profile(edge, nil) do edge end + defp add_profile(edge, profile) do Map.put(edge, :profile, profile) end diff --git a/lib/schema_web/controllers/page_controller.ex b/lib/schema_web/controllers/page_controller.ex index 566ec98..a986151 100644 --- a/lib/schema_web/controllers/page_controller.ex +++ b/lib/schema_web/controllers/page_controller.ex @@ -15,57 +15,38 @@ defmodule SchemaWeb.PageController do alias SchemaWeb.SchemaController - # TODO: guidelines.html is missing (route is also commented out) - # @spec guidelines(Plug.Conn.t(), any) :: Plug.Conn.t() - # def guidelines(conn, params) do - # render(conn, "guidelines.html", - # extensions: Schema.extensions(), - # profiles: SchemaController.get_profiles(params) - # ) - # end - @spec class_graph(Plug.Conn.t(), any) :: Plug.Conn.t() def class_graph(conn, %{"id" => id} = params) do - # try do - # case SchemaWeb.SchemaController.class_ex(id, params) do - # nil -> - # send_resp(conn, 404, "Not Found: #{id}") - - # class -> - # data = Schema.Graph.build(class) - - # render(conn, "class_graph.html", - # extensions: Schema.extensions(), - # profiles: SchemaController.get_profiles(params), - # data: data - # ) - # end - # rescue - # e -> send_resp(conn, 400, "Bad Request: #{inspect(e)}") - # end - send_resp(conn, 501, "The graph feature is temporarily disabled and will return soon.") + case SchemaWeb.SchemaController.class_ex(id, params) do + nil -> + send_resp(conn, 404, "Not Found: #{id}") + + class -> + data = Schema.Graph.build(class) + + render(conn, "class_graph.html", + extensions: Schema.extensions(), + profiles: SchemaController.get_profiles(params), + data: data + ) + end end @spec object_graph(Plug.Conn.t(), any) :: Plug.Conn.t() def object_graph(conn, %{"id" => id} = params) do - # try do - # case SchemaWeb.SchemaController.object_ex(id, params) do - # nil -> - # send_resp(conn, 404, "Not Found: #{id}") - - # obj -> - # data = Schema.Graph.build(obj) - - # render(conn, "object_graph.html", - # extensions: Schema.extensions(), - # profiles: SchemaController.get_profiles(params), - # data: data - # ) - # end - # rescue - # e -> send_resp(conn, 400, "Bad Request: #{inspect(e)}") - # end - send_resp(conn, 501, "The graph feature is temporarily disabled and will return soon.") + case SchemaWeb.SchemaController.object_ex(id, params) do + nil -> + send_resp(conn, 404, "Not Found: #{id}") + + obj -> + data = Schema.Graph.build(obj) + + render(conn, "object_graph.html", + extensions: Schema.extensions(), + profiles: SchemaController.get_profiles(params), + data: data + ) + end end @doc """ @@ -93,22 +74,18 @@ defmodule SchemaWeb.PageController do extension -> "#{extension}/#{id}" end - try do - data = SchemaController.get_profiles(params) + data = SchemaController.get_profiles(params) - case Map.get(data, name) do - nil -> - send_resp(conn, 404, "Not Found: #{name}") + case Map.get(data, name) do + nil -> + send_resp(conn, 404, "Not Found: #{name}") - profile -> - render(conn, "profile.html", - extensions: Schema.extensions(), - profiles: data, - data: sort_attributes(profile) - ) - end - rescue - e -> send_resp(conn, 400, "Bad Request: #{inspect(e)}") + profile -> + render(conn, "profile.html", + extensions: Schema.extensions(), + profiles: data, + data: sort_attributes(profile) + ) end end @@ -127,22 +104,18 @@ defmodule SchemaWeb.PageController do """ @spec categories(Plug.Conn.t(), map) :: Plug.Conn.t() def categories(conn, %{"id" => id} = params) do - try do - case SchemaController.category_classes(params) do - nil -> - send_resp(conn, 404, "Not Found: #{id}") - - data -> - classes = sort_by(data[:classes], :uid) - - render(conn, "category.html", - extensions: Schema.extensions(), - profiles: SchemaController.get_profiles(params), - data: Map.put(data, :classes, classes) - ) - end - rescue - e -> send_resp(conn, 400, "Bad Request: #{inspect(e)}") + case SchemaController.category_classes(params) do + nil -> + send_resp(conn, 404, "Not Found: #{id}") + + data -> + classes = sort_by(data[:classes], :uid) + + render(conn, "category.html", + extensions: Schema.extensions(), + profiles: SchemaController.get_profiles(params), + data: Map.put(data, :classes, classes) + ) end end @@ -189,25 +162,21 @@ defmodule SchemaWeb.PageController do def classes(conn, %{"id" => id} = params) do extension = params["extension"] - try do - case Schema.class(extension, id) do - nil -> - send_resp(conn, 404, "Not Found: #{id}") - - data -> - data = - data - |> sort_attributes() - |> Map.put(:key, Schema.Utils.to_uid(extension, id)) - - render(conn, "class.html", - extensions: Schema.extensions(), - profiles: SchemaController.get_profiles(params), - data: data - ) - end - rescue - e -> send_resp(conn, 400, "Bad Request: #{inspect(e)}") + case Schema.class(extension, id) do + nil -> + send_resp(conn, 404, "Not Found: #{id}") + + data -> + data = + data + |> sort_attributes() + |> Map.put(:key, Schema.Utils.to_uid(extension, id)) + + render(conn, "class.html", + extensions: Schema.extensions(), + profiles: SchemaController.get_profiles(params), + data: data + ) end end @@ -226,25 +195,21 @@ defmodule SchemaWeb.PageController do """ @spec objects(Plug.Conn.t(), map) :: Plug.Conn.t() def objects(conn, %{"id" => id} = params) do - try do - case SchemaController.object(params) do - nil -> - send_resp(conn, 404, "Not Found: #{id}") - - data -> - data = - data - |> sort_attributes() - |> Map.put(:key, Schema.Utils.to_uid(params["extension"], id)) - - render(conn, "object.html", - extensions: Schema.extensions(), - profiles: SchemaController.get_profiles(params), - data: data - ) - end - rescue - e -> send_resp(conn, 400, "Bad Request: #{inspect(e)}") + case SchemaController.object(params) do + nil -> + send_resp(conn, 404, "Not Found: #{id}") + + data -> + data = + data + |> sort_attributes() + |> Map.put(:key, Schema.Utils.to_uid(params["extension"], id)) + + render(conn, "object.html", + extensions: Schema.extensions(), + profiles: SchemaController.get_profiles(params), + data: data + ) end end diff --git a/lib/schema_web/router.ex b/lib/schema_web/router.ex index c5681f7..1f81f54 100644 --- a/lib/schema_web/router.ex +++ b/lib/schema_web/router.ex @@ -53,8 +53,6 @@ defmodule SchemaWeb.Router do get "/object/graph/:extension/:id", PageController, :object_graph get "/data_types", PageController, :data_types - # TODO: guidelines.html is missing (also commented out in PageController) - # get "/guidelines", PageController, :guidelines end # Other scopes may use custom stacks. diff --git a/mix.exs b/mix.exs index 7a5fab0..f0f9da3 100644 --- a/mix.exs +++ b/mix.exs @@ -10,7 +10,7 @@ defmodule Schema.MixProject do use Mix.Project - @version "2.70.3" + @version "2.70.4" def project do build = System.get_env("GITHUB_RUN_NUMBER") || "SNAPSHOT"