diff --git a/core/assets/js/app.js b/core/assets/js/app.js index c66003216e..740b920846 100644 --- a/core/assets/js/app.js +++ b/core/assets/js/app.js @@ -32,6 +32,7 @@ import { PythonUploader } from "./python_uploader"; import { Clipboard } from "./clipboard"; import { DataDonationHook } from "./data_donation_hook"; import { Port } from "./port"; +import { FeldsparApp } from "./feldspar_app"; window.registerAPNSDeviceToken = registerAPNSDeviceToken; @@ -105,6 +106,7 @@ let Hooks = { PythonUploader, DataDonationHook, Port, + FeldsparApp, }; let liveSocket = new LiveSocket("/live", Socket, { diff --git a/core/assets/js/feldspar_app.js b/core/assets/js/feldspar_app.js new file mode 100644 index 0000000000..88ca67428d --- /dev/null +++ b/core/assets/js/feldspar_app.js @@ -0,0 +1,27 @@ +export const FeldsparApp = { + mounted() { + const iframe = this.getIframe(); + if (iframe.contentDocument.readyState === "complete") { + this.onFrameLoaded(); + } + else { + iframe.contentDocument.addEventListener("load", ()=>{ this.onFrameLoaded() }); + } + }, + + getIframe() { + return this.el.querySelector("iframe"); + }, + + onFrameLoaded() { + this.channel = new MessageChannel(); + this.channel.port1.onmessage = (e) => { + this.handleMessage(e); + }; + this.getIframe().contentWindow.postMessage("init", "*", [this.channel.port2]); + }, + + handleMessage(e) { + this.pushEvent("app_event", e.data); + } +}; diff --git a/core/config/dev.exs b/core/config/dev.exs index dd7d818537..0107ccb1f4 100644 --- a/core/config/dev.exs +++ b/core/config/dev.exs @@ -71,13 +71,14 @@ config :core, Systems.Email.Mailer, config :core, :apns_backend, Core.APNS.LoggingBackend -config :core, - :static_path, +static_path = File.cwd!() |> Path.join("tmp") |> Path.join("uploads") |> tap(&File.mkdir_p!/1) +config :core, :static_path, static_path + config :core, :admins, ["e.vanderveen@eyra.co"] @@ -96,6 +97,10 @@ config :ex_aws, access_key_id: "my_access_key", secret_access_key: "a_super_secret" +config :core, :feldspar, + backend: Systems.Feldspar.LocalFS, + local_fs_root_path: static_path + try do import_config "dev.secret.exs" rescue diff --git a/core/config/test.exs b/core/config/test.exs index adf1a82d41..dbdb03dd2d 100644 --- a/core/config/test.exs +++ b/core/config/test.exs @@ -54,3 +54,7 @@ config :core, Core.SurfConext, oidc_module: Core.SurfConext.FakeOIDC config :core, :bundle, :next config :core, :banking_backend, Systems.Banking.Dummy + +config :core, :feldspar, + backend: Systems.Feldspar.LocalFS, + local_fs_root_path: "/tmp" diff --git a/core/lib/core/authorization.ex b/core/lib/core/authorization.ex index 6083e29796..a0d6100340 100644 --- a/core/lib/core/authorization.ex +++ b/core/lib/core/authorization.ex @@ -61,6 +61,7 @@ defmodule Core.Authorization do grant_access(Systems.Project.ItemContentPage, [:researcher, :owner]) grant_access(Systems.Benchmark.ToolPage, [:owner]) grant_access(Systems.Benchmark.LeaderboardPage, [:visitor, :member]) + grant_access(Systems.Feldspar.AppPage, [:visitor, :member]) grant_access(CoreWeb.User.Signin, [:visitor]) grant_access(CoreWeb.User.Signup, [:visitor]) diff --git a/core/lib/core_web/endpoint.ex b/core/lib/core_web/endpoint.ex index 80779e6b90..2c7a050f83 100644 --- a/core/lib/core_web/endpoint.ex +++ b/core/lib/core_web/endpoint.ex @@ -1,5 +1,6 @@ defmodule CoreWeb.Endpoint do use Phoenix.Endpoint, otp_app: :core + require Systems.Feldspar.Plug # The session will be stored in the cookie and signed, # this means its contents can be read but not tampered with. @@ -33,6 +34,8 @@ defmodule CoreWeb.Endpoint do ) end + Systems.Feldspar.Plug.setup() + # Serve at "/" the static files from "priv/static" directory. # # You should set gzip to true if you are running phx.digest diff --git a/core/systems/feldspar/_public.ex b/core/systems/feldspar/_public.ex new file mode 100644 index 0000000000..c87cc867a0 --- /dev/null +++ b/core/systems/feldspar/_public.ex @@ -0,0 +1,15 @@ +defmodule Systems.Feldspar.Public do + import Systems.Feldspar.Internal, only: [get_backend: 0] + + def store(zip_file) do + get_backend().store(zip_file) + end + + def get_public_url(id) do + get_backend().get_public_url(id) + end + + def remove(id) do + get_backend().remove(id) + end +end diff --git a/core/systems/feldspar/_routes.ex b/core/systems/feldspar/_routes.ex new file mode 100644 index 0000000000..e2136d1d15 --- /dev/null +++ b/core/systems/feldspar/_routes.ex @@ -0,0 +1,10 @@ +defmodule Systems.Feldspar.Routes do + defmacro routes() do + quote do + scope "/apps", Systems.Feldspar do + pipe_through([:browser]) + live("/:id", AppPage) + end + end + end +end diff --git a/core/systems/feldspar/app_page.ex b/core/systems/feldspar/app_page.ex new file mode 100644 index 0000000000..444a593b5c --- /dev/null +++ b/core/systems/feldspar/app_page.ex @@ -0,0 +1,37 @@ +defmodule Systems.Feldspar.AppPage do + use CoreWeb, :live_view + alias CoreWeb.Endpoint + + @impl true + def mount(%{"id" => app_id}, _session, socket) do + app_url = Endpoint.static_url() <> Endpoint.static_path("/images/" <> app_id <> "/index.html") + + {:ok, assign(socket, app_url: app_url, error: nil)} + end + + @impl true + def handle_uri(socket), do: socket + + @impl true + def render(assigns) do + ~H""" +