Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
AntoineAugusti committed Jan 30, 2025
1 parent f7e359a commit 97cdd71
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 16 deletions.
4 changes: 4 additions & 0 deletions apps/transport/client/stylesheets/reuser_space.scss
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,7 @@ form.search-followed-datasets {
.align-right {
text-align: right;
}

form.full-width {
max-width: 100%;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,20 @@ defmodule TransportWeb.ReuserSpaceController do
|> render("index.html")
end

def datasets_edit(%Plug.Conn{} = conn, _), do: render(conn, "datasets_edit.html")
def datasets_edit(
%Plug.Conn{assigns: %{dataset: %DB.Dataset{} = dataset, contact: %DB.Contact{} = contact}} = conn,
_
) do
conn
|> assign(:contact, DB.Repo.preload(contact, :organizations))
|> assign(:dataset, DB.Repo.preload(dataset, :resources))
|> render("datasets_edit.html")
end

def add_improved_data(%Plug.Conn{} = conn, _) do
IO.inspect(conn)
conn |> text("Ok")
end

def unfavorite(%Plug.Conn{assigns: %{dataset: %DB.Dataset{} = dataset, contact: %DB.Contact{} = contact}} = conn, _) do
DB.DatasetFollower.unfollow!(contact, dataset)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ defmodule TransportWeb.CustomTagsLive do
%{
name: "experimental",
doc: "Ajoute sur la page du JDD une bannière indiquant que le jeu est expérimental"
},
%{
name: Application.fetch_env!(:transport, :data_sharing_pilot_dataset_custom_tag),
doc: "Indique que ce jeu de données est éligible à l'expérimentation du repartage de données améliorées"
}
]
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ defmodule TransportWeb.Plugs.CustomSecureBrowserHeaders do

def call(conn, _opts) do
nonce = generate_nonce()
csp_headers = csp_headers(Application.fetch_env!(:transport, :app_env), nonce)
csp_headers = csp_headers(Mix.env(), Application.fetch_env!(:transport, :app_env), nonce)
headers = Map.merge(csp_headers, %{"x-frame-options" => "DENY"})

conn
Expand All @@ -23,16 +23,16 @@ defmodule TransportWeb.Plugs.CustomSecureBrowserHeaders do
Returns content-security-policy headers for an app environment.
iex> nonce = "foo"
iex> match?(%{"content-security-policy" => _csp_content}, csp_headers(:production, nonce))
iex> match?(%{"content-security-policy" => _csp_content}, csp_headers(:prod, :production, nonce))
true
iex> match?(%{"content-security-policy" => _csp_content}, csp_headers(:staging, nonce))
iex> match?(%{"content-security-policy" => _csp_content}, csp_headers(:prod, :staging, nonce))
true
iex> csp_headers(:staging, nonce) != csp_headers(:production, nonce)
iex> csp_headers(:prod, :staging, nonce) != csp_headers(:prod, :production, nonce)
true
iex> String.contains?("report-uri", csp_headers(:dev, nonce) |> Map.fetch!("content-security-policy"))
iex> String.contains?("report-uri", csp_headers(:dev, :dev, nonce) |> Map.fetch!("content-security-policy"))
false
"""
def csp_headers(app_env, nonce) do
def csp_headers(mix_env, app_env, nonce) do
# https://github.com/vega/vega-embed/issues/1214#issuecomment-1670812445
vega_hash_values =
"'sha256-9uoGUaZm3j6W7+Fh2wfvjI8P7zXcclRw5tVUu3qKZa0=' 'sha256-MmUum7+PiN7Rz79EUMm0OmUFWjCx6NZ97rdjoIbTnAg='"
Expand All @@ -51,7 +51,7 @@ defmodule TransportWeb.Plugs.CustomSecureBrowserHeaders do
"report-uri" => ""
}
|> Enum.map(fn {directive, value} ->
extra = " #{additional_content(directive, app_env)}" |> String.trim()
extra = " #{additional_content(directive, mix_env, app_env) |> String.trim()}"
{directive, value <> extra}
end)
|> Enum.reject(fn {_, v} -> v == "" end)
Expand All @@ -60,15 +60,19 @@ defmodule TransportWeb.Plugs.CustomSecureBrowserHeaders do
%{"content-security-policy" => policy}
end

defp additional_content("img-src", :staging) do
"https://demo-static.data.gouv.fr https://demo.data.gouv.fr"
defp additional_content("img-src", mix_env, app_env) do
if mix_env == :dev or app_env == :staging do
"https://demo-static.data.gouv.fr https://demo.data.gouv.fr"
else
""
end
end

defp additional_content("report-uri", app_env) when app_env in [:production, :staging] do
defp additional_content("report-uri", _mix_env, app_env) when app_env in [:production, :staging] do
Application.fetch_env!(:sentry, :csp_url)
end

defp additional_content(_directive, _app_env) do
defp additional_content(_directive, _mix_env, _app_env) do
""
end
end
1 change: 1 addition & 0 deletions apps/transport/lib/transport_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ defmodule TransportWeb.Router do
pipe_through([:reuser_space])
get("/", ReuserSpaceController, :espace_reutilisateur)
get("/datasets/:dataset_id", ReuserSpaceController, :datasets_edit)
post("/datasets/:dataset_id/add_improved_data", ReuserSpaceController, :add_improved_data)
post("/datasets/:dataset_id/unfavorite", ReuserSpaceController, :unfavorite)

live_session :reuser_space, session: %{"role" => :reuser}, root_layout: {TransportWeb.LayoutView, :app} do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,51 @@
<h3><%= dgettext("reuser-space", "Manage notifications") %></h3>
<%= live_render(@conn, TransportWeb.Live.DatasetNotificationsLive, session: %{"dataset_id" => @dataset.id}) %>
</div>
<div class="panel">
<div id="data-sharing" class="panel">
<h3><%= dgettext("reuser-space", "Improved data sharing") %></h3>
<p class="notification">
<%= dgettext("reuser-space", "This feature is coming soon!") %>
</p>
<%= if data_sharing_pilot?(@dataset, @contact) do %>
<% [organization] = data_sharing_eligible_org(@contact) %>
<div class="align-right">
<img src={organization.logo_thumbnail} title={organization.name} />
</div>
<%= form_for @conn, reuser_space_path(@conn, :add_improved_data, @dataset.id), [class: "full-width"], fn f -> %>
<div class="ressources-list">
<%= for resource <- @dataset.resources |> Enum.filter(&DB.Resource.gtfs?/1) do %>
<div class="panel resource">
<h4>
<%= radio_button(f, :resource_id, resource.id, id: "resource-#{resource.id}", required: true) %>
<%= label f, resource.id, class: "label-inline", for: "resource-#{resource.id}" do %>
<%= resource.title %>
<% end %>
</h4>

<div class="resource-panel-bottom">
<div class="resource-actions">
<div class="resource-format" title={dgettext("page-dataset-details", "resource format")}>
<span class="label"><%= resource.format %></span>
</div>
</div>
</div>
</div>
<% end %>
</div>
<p class="small">
<%= dgettext("reuser-space", "Only GTFS files are eligible for now.") %>
</p>
<div class="form__group">
<%= label(f, :url, dgettext("reuser-space", "Your improved data URL")) %>
<%= text_input(f, :url, type: "url", required: true) %>
</div>
<%= submit(dgettext("reuser-space", "Share improved data"), class: "button") %>
<% end %>
<p class="notification">
<%= dgettext("reuser-space", "You will be able to share back your data soon!") %>
</p>
<% else %>
<p class="notification">
<%= dgettext("reuser-space", "This feature is coming soon!") %>
</p>
<% end %>
</div>
<div class="panel">
<h3><%= dgettext("reuser-space", "Discussions") %></h3>
Expand Down
25 changes: 25 additions & 0 deletions apps/transport/lib/transport_web/views/reuser_space_view.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,29 @@
defmodule TransportWeb.ReuserSpaceView do
use TransportWeb, :view
import TransportWeb.BreadCrumbs, only: [breadcrumbs: 1]

@doc """
Is the following dataset eligible for the data sharing pilot for this contact, member
of various organizations?
"""
@spec data_sharing_pilot?(DB.Dataset.t(), DB.Contact.t()) :: boolean()
def data_sharing_pilot?(%DB.Dataset{} = dataset, %DB.Contact{} = contact) do
eligible_dataset_type = dataset.type == "public-transit"
has_dataset_tag = DB.Dataset.has_custom_tag?(dataset, config_value(:dataset_custom_tag))
member_eligible_org = data_sharing_eligible_org(contact) |> Enum.count() == 1

Enum.all?([eligible_dataset_type, has_dataset_tag, member_eligible_org])
end

def data_sharing_eligible_org(%DB.Contact{organizations: organizations}) do
data_sharing_eligible_org(organizations)
end

def data_sharing_eligible_org(organizations) when is_list(organizations) do
Enum.filter(organizations, &(&1.id in config_value(:eligible_datagouv_organization_ids)))
end

defp config_value(key) do
Application.fetch_env!(:transport, :"data_sharing_pilot_#{key}")
end
end
4 changes: 4 additions & 0 deletions apps/transport/priv/gettext/en/LC_MESSAGES/reuser-space.po
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ msgstr ""
msgid "This feature is coming soon!"
msgstr ""

#, elixir-autogen, elixir-format
msgid "You will be able to share back your data soon!"
msgstr ""

#, elixir-autogen, elixir-format
msgid "Warning, you are going to remove \"%{dataset_title}\" from your favorites. You will lose any settings or actions you previously performed on this dataset."
msgstr ""
4 changes: 4 additions & 0 deletions apps/transport/priv/gettext/fr/LC_MESSAGES/reuser-space.po
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ msgstr "Gérer"
msgid "This feature is coming soon!"
msgstr "Cette fonctionnalité arrive bientôt !"

#, elixir-autogen, elixir-format
msgid "You will be able to share back your data soon!"
msgstr "Vous pourrez repartager vos données bientôt !"

#, elixir-autogen, elixir-format
msgid "Warning, you are going to remove \"%{dataset_title}\" from your favorites. You will lose any settings or actions you previously performed on this dataset."
msgstr "Attention, vous allez supprimer le jeu de données \"%{dataset_title}\" de vos favoris. Vous allez perdre tous les paramétrages ou actions que vous avez réalisés précédemment sur ce jeu de données."
4 changes: 4 additions & 0 deletions apps/transport/priv/gettext/reuser-space.pot
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ msgstr ""
msgid "This feature is coming soon!"
msgstr ""

#, elixir-autogen, elixir-format
msgid "You will be able to share back your data soon!"
msgstr ""

#, elixir-autogen, elixir-format
msgid "Warning, you are going to remove \"%{dataset_title}\" from your favorites. You will lose any settings or actions you previously performed on this dataset."
msgstr ""
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,29 @@ defmodule TransportWeb.ReuserSpaceControllerTest do
|> Floki.find(".reuser-space-section h2")
|> Floki.text() == dataset.custom_title
end

test "logged in, dataset is eligible for the data sharing pilot", %{conn: conn} do
# Google Maps org
organization = insert(:organization, id: "63fdfe4f4cd1c437ac478323")
dataset = insert(:dataset, custom_tags: ["repartage_donnees"], type: "public-transit")

contact =
insert_contact(%{
datagouv_user_id: Ecto.UUID.generate(),
organizations: [organization |> Map.from_struct()]
})

insert(:dataset_follower, contact_id: contact.id, dataset_id: dataset.id, source: :follow_button)

assert conn
|> Plug.Test.init_test_session(%{current_user: %{"id" => contact.datagouv_user_id}})
|> get(reuser_space_path(conn, :datasets_edit, dataset.id))
|> html_response(200)
|> Floki.parse_document!()
|> Floki.find("#data-sharing p.notification")
|> Floki.text()
|> String.trim() == "Vous pourrez repartager vos données bientôt !"
end
end

describe "unfavorite" do
Expand Down
30 changes: 30 additions & 0 deletions apps/transport/test/transport_web/views/reuser_space_view_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
defmodule TransportWeb.ReuserSpaceViewTest do
use ExUnit.Case, async: true
import TransportWeb.ReuserSpaceView

@google_maps_org_id "63fdfe4f4cd1c437ac478323"

setup do
Ecto.Adapters.SQL.Sandbox.checkout(DB.Repo)
end

describe "data_sharing_pilot?" do
test "contact is not a member of an eligible organization" do
dataset = %DB.Dataset{type: "public-transit", custom_tags: ["repartage_donnees"]}
contact = %DB.Contact{organizations: []}
refute data_sharing_pilot?(dataset, contact)
end

test "dataset does not have the required tag" do
dataset = %DB.Dataset{type: "public-transit", custom_tags: []}
contact = %DB.Contact{organizations: [%DB.Organization{id: @google_maps_org_id}]}
refute data_sharing_pilot?(dataset, contact)
end

test "dataset is eligible for contact" do
dataset = %DB.Dataset{type: "public-transit", custom_tags: ["repartage_donnees"]}
contact = %DB.Contact{organizations: [%DB.Organization{id: @google_maps_org_id}]}
assert data_sharing_pilot?(dataset, contact)
end
end
end
1 change: 1 addition & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -246,4 +246,5 @@ import_config "gtfs_validator.exs"
import_config "gbfs_validator.exs"
import_config "mail.exs"
import_config "mailchimp.exs"
import_config "data_sharing_pilot.exs"
import_config "#{config_env()}.exs"
14 changes: 14 additions & 0 deletions config/data_sharing_pilot.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Config

config :transport,
data_sharing_pilot_dataset_custom_tag: "repartage_donnees",
data_sharing_pilot_eligible_datagouv_organization_ids: [
# transport.data.gouv.fr
"5abca8d588ee386ee6ece479",
# Google Maps
"63fdfe4f4cd1c437ac478323",
# Transit
"5c9a6477634f4133c7a5fc01",
# Citymapper / Via
"5f7cade93fb405c7d8f6d554"
]

0 comments on commit 97cdd71

Please sign in to comment.