diff --git a/apps/cf_graphql/lib/resolvers/videos.ex b/apps/cf_graphql/lib/resolvers/videos.ex index 141e8245..1e4c51a2 100644 --- a/apps/cf_graphql/lib/resolvers/videos.ex +++ b/apps/cf_graphql/lib/resolvers/videos.ex @@ -114,4 +114,27 @@ defmodule CF.Graphql.Resolvers.Videos do CF.LLMs.StatementsCreator.process_video!(video.id) {:ok, video} end + + def edit(_root, %{id: id, unlisted: unlisted}, %{ + context: %{user: user} + }) do + base_video = DB.Repo.get!(DB.Schema.Video, id) + changeset = Ecto.Changeset.change(base_video, %{unlisted: unlisted}) + + Ecto.Multi.new() + |> Ecto.Multi.update(:video, fn _repo -> + changeset + end) + |> Ecto.Multi.run(:action, fn _repo, %{video: video} -> + Repo.insert(CF.Actions.ActionCreator.action_update(user.id, changeset)) + end) + |> Repo.transaction() + |> case do + {:ok, %{video: video}} -> + {:ok, video} + + {:error, _} -> + {:error, "Failed to update video"} + end + end end diff --git a/apps/cf_graphql/lib/schema/schema.ex b/apps/cf_graphql/lib/schema/schema.ex index e3c55404..e0b1458e 100644 --- a/apps/cf_graphql/lib/schema/schema.ex +++ b/apps/cf_graphql/lib/schema/schema.ex @@ -99,5 +99,16 @@ defmodule CF.Graphql.Schema do resolve(&Resolvers.Videos.start_automatic_statements_extraction/3) end + + field :edit_video, :video do + middleware(Middleware.RequireAuthentication) + # MIN_REPUTATION_UPDATE_VIDEO + middleware(Middleware.RequireReputation, 75) + + arg(:id, non_null(:id)) + arg(:unlisted, non_null(:boolean)) + + resolve(&Resolvers.Videos.edit/3) + end end end diff --git a/apps/cf_graphql/lib/schema/types/video.ex b/apps/cf_graphql/lib/schema/types/video.ex index f61b5e4a..309f6397 100644 --- a/apps/cf_graphql/lib/schema/types/video.ex +++ b/apps/cf_graphql/lib/schema/types/video.ex @@ -38,6 +38,8 @@ defmodule CF.Graphql.Schema.Types.Video do field(:inserted_at, :string) @desc "Define if video has been added by a partner or a regular user" field(:is_partner, :boolean) + @desc "Define if video is unlisted" + field(:unlisted, non_null(:boolean)) @desc "List all non-removed speakers for this video" field :speakers, list_of(:speaker) do resolve(assoc(:speakers)) diff --git a/apps/cf_rest_api/lib/views/video_view.ex b/apps/cf_rest_api/lib/views/video_view.ex index b6e55b17..396c9e4d 100644 --- a/apps/cf_rest_api/lib/views/video_view.ex +++ b/apps/cf_rest_api/lib/views/video_view.ex @@ -43,7 +43,8 @@ defmodule CF.RestApi.VideoView do speakers: render_many(video.speakers, CF.RestApi.SpeakerView, "speaker.json"), language: video.language, is_partner: video.is_partner, - is_subscribed: is_subscribed + is_subscribed: is_subscribed, + unlisted: video.unlisted } end end diff --git a/apps/db/lib/db_schema/video.ex b/apps/db/lib/db_schema/video.ex index 68964fe1..fab12df6 100644 --- a/apps/db/lib/db_schema/video.ex +++ b/apps/db/lib/db_schema/video.ex @@ -151,13 +151,24 @@ defmodule DB.Schema.Video do |> cast(params, [:url, :title, :language]) |> validate_required([:url, :title]) |> parse_video_url() - |> validate_length(:title, min: 5, max: 120) + |> update_change(:title, &truncate_title/1) + |> validate_length(:title, min: 5, max: 130) |> unique_constraint(:videos_youtube_id_index) |> unique_constraint(:videos_facebook_id_index) # Change locales like "en-US" to "en" |> update_change(:language, &format_language/1) end + defp truncate_title(title) do + trimmed = String.trim(title) + + if String.length(trimmed) > 130 do + String.slice(trimmed, 0..128) <> "…" + else + trimmed + end + end + defp format_language("zxx"), do: nil defp format_language(locale) do diff --git a/apps/db/test/db_schema/video_test.exs b/apps/db/test/db_schema/video_test.exs index 1d62b602..1401dacb 100644 --- a/apps/db/test/db_schema/video_test.exs +++ b/apps/db/test/db_schema/video_test.exs @@ -34,14 +34,10 @@ defmodule DB.Schema.VideoTest do refute changeset.valid? end - test "title must be between 5 and 120 characters" do + test "title must be between 5 and 130 characters" do # Too short - attrs = %{title: "x"} + attrs = %{title: "x", url: "https://www.youtube.com/watch?v=zoP-XFuWstw"} assert {:title, "should be at least 5 character(s)"} in errors_on(%Video{}, attrs) - - # Too long - attrs = %{title: String.duplicate("x", 121)} - assert {:title, "should be at most 120 character(s)"} in errors_on(%Video{}, attrs) end test "unknown or invalid language gives nil values but aren't rejected" do diff --git a/mix.lock b/mix.lock index ef2b86b2..1b6419c2 100644 --- a/mix.lock +++ b/mix.lock @@ -93,7 +93,6 @@ "quantum": {:hex, :quantum, "2.3.3", "83f565de81ac43b8fda4dd4266b209eaed29545d1c41e17aa6b75b08736c80f6", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}], "hexpm", "01a63089a17f00f360ddad6c2f068c26d4e280999c2a6c2bce170d0bd6b2bd2e"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "req": {:hex, :req, "0.5.0", "6d8a77c25cfc03e06a439fb12ffb51beade53e3fe0e2c5e362899a18b50298b3", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "dda04878c1396eebbfdec6db6f3d4ca609e5c8846b7ee88cc56eb9891406f7a3"}, - "scout_apm": {:hex, :scout_apm, "1.0.7", "0ca260f2c7f3c29bf6a5b361e90339bdce0a5f3ae0cf7b0ce166bfb22eefb89c", [:mix], [{:approximate_histogram, "~>0.1.1", [hex: :approximate_histogram, repo: "hexpm", optional: false]}, {:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:plug, "~>1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 0.3.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "a4a3c8318fb84e4586e68fcd7e889c5bfe17c1caa218cc6f333fb0e4c0ff4ec1"}, "scrivener": {:hex, :scrivener, "2.7.2", "1d913c965ec352650a7f864ad7fd8d80462f76a32f33d57d1e48bc5e9d40aba2", [:mix], [], "hexpm", "7866a0ec4d40274efbee1db8bead13a995ea4926ecd8203345af8f90d2b620d9"}, "scrivener_ecto": {:hex, :scrivener_ecto, "2.7.0", "cf64b8cb8a96cd131cdbcecf64e7fd395e21aaa1cb0236c42a7c2e34b0dca580", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:scrivener, "~> 2.4", [hex: :scrivener, repo: "hexpm", optional: false]}], "hexpm", "e809f171687806b0031129034352f5ae44849720c48dd839200adeaf0ac3e260"}, "slugger": {:hex, :slugger, "0.3.0", "efc667ab99eee19a48913ccf3d038b1fb9f165fa4fbf093be898b8099e61b6ed", [:mix], [], "hexpm", "20d0ded0e712605d1eae6c5b4889581c3460d92623a930ddda91e0e609b5afba"},