Skip to content

Commit

Permalink
Prevent draft video resources from going live on YouTube (#2376)
Browse files Browse the repository at this point in the history
* Prevent draft video resources from going live on YouTube

* Toggle public/unlisted status with draft setting

* Updating test and video documentation

* Fixing test
  • Loading branch information
pt2302 authored Jan 15, 2025
1 parent b4481f6 commit 438861a
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 4 deletions.
2 changes: 1 addition & 1 deletion videos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ The [`TranscodeJobView` endpoint](/videos/views.py) listens for the webhook that

# YouTube Submission

Videos are uploaded to YouTube via the [`resumable_upload` function](/videos/youtube.py). The [YouTube upload success notification](/videos/templates/mail/youtube_upload_success/body.html) is sent by email when the [`update_youtube_statuses`](/videos/tasks.py) task is complete; exceptions in this task trigger the [YouTube upload failure notification](/videos/templates/mail/youtube_upload_failure/body.html). When the course is published to draft/staging, the video is set to private. However, when it is published to live/production, the video is made public on YouTube, via the [`update_youtube_metadata` function](/videos/youtube.py). When a video is made public on YouTube, all YouTube subscribers will be notified. There are nearly 5 million subscribers to the OCW YouTube channel, so be careful with this setting.
Videos are uploaded to YouTube via the [`resumable_upload` function](/videos/youtube.py). The [YouTube upload success notification](/videos/templates/mail/youtube_upload_success/body.html) is sent by email when the [`update_youtube_statuses`](/videos/tasks.py) task is complete; exceptions in this task trigger the [YouTube upload failure notification](/videos/templates/mail/youtube_upload_failure/body.html). When the course is published to draft/staging, the video is set to `unlisted`. However, when it is published to live/production, the video is made public on YouTube, via the [`update_youtube_metadata` function](/videos/youtube.py). When a video is made public on YouTube, all YouTube subscribers will be notified. There are nearly 5 million subscribers to the OCW YouTube channel, so be careful with this setting.

# Captioning and 3Play Transcript Request

Expand Down
7 changes: 6 additions & 1 deletion videos/youtube.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ def update_youtube_metadata(website: Website, version=VERSION_DRAFT):
return
youtube = YouTubeApi()
for video_resource in video_resources:
is_draft = get_dict_field(video_resource.metadata, "draft") is True
youtube_id = get_dict_field(video_resource.metadata, settings.YT_FIELD_ID)
# do not run this for any old imported videos
if VideoFile.objects.filter(
Expand All @@ -435,7 +436,11 @@ def update_youtube_metadata(website: Website, version=VERSION_DRAFT):
try:
youtube.update_video(
video_resource,
privacy=("public" if version == VERSION_LIVE else None),
privacy=(
"public"
if version == VERSION_LIVE and not is_draft
else "unlisted"
),
)
except: # pylint:disable=bare-except # noqa: E722
log.exception(
Expand Down
21 changes: 19 additions & 2 deletions videos/youtube_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
)
from websites.factories import WebsiteContentFactory, WebsiteFactory
from websites.models import WebsiteContent
from websites.utils import set_dict_field

pytestmark = pytest.mark.django_db

Expand Down Expand Up @@ -352,12 +353,15 @@ def test_mail_youtube_upload_success(settings, mock_mail):
)


@pytest.mark.parametrize(
("res_draft", "expected_privacy"), [(True, None), (False, "public")]
)
@pytest.mark.parametrize("video_file_exists", [True, False])
@pytest.mark.parametrize("youtube_enabled", [True, False])
@pytest.mark.parametrize("is_ocw", [True, False])
@pytest.mark.parametrize(
("version", "privacy"),
[[VERSION_DRAFT, None], [VERSION_LIVE, "public"]], # noqa: PT007
[[VERSION_DRAFT, "unlisted"], [VERSION_LIVE, "public"]], # noqa: PT007
)
def test_update_youtube_metadata( # pylint:disable=too-many-arguments # noqa: PLR0913
mocker,
Expand All @@ -368,6 +372,8 @@ def test_update_youtube_metadata( # pylint:disable=too-many-arguments # noqa:
is_ocw,
version,
privacy,
res_draft,
expected_privacy,
):
"""Check that youtube.update_video is called for appropriate resources and not others"""
mock_youtube = mocker.patch("videos.youtube.YouTubeApi")
Expand All @@ -381,19 +387,30 @@ def test_update_youtube_metadata( # pylint:disable=too-many-arguments # noqa:
destination=DESTINATION_YOUTUBE,
destination_id=youtube_id,
)
content = WebsiteContent.objects.get(
website=youtube_website,
metadata__video_metadata__youtube_id=youtube_id,
)
set_dict_field(content.metadata, "draft", res_draft)
content.save()
update_youtube_metadata(youtube_website, version=version)
if youtube_enabled and is_ocw:
mock_youtube.assert_called_once()
# Don't update metadata for imported ocw course videos except on production
if video_file_exists:
assert mock_update_video.call_count == 2
for youtube_id in ["abc123", "def456"]:
final_privacy = (
expected_privacy
if (version == VERSION_LIVE and not res_draft)
else "unlisted"
)
mock_update_video.assert_any_call(
WebsiteContent.objects.get(
website=youtube_website,
metadata__video_metadata__youtube_id=youtube_id,
),
privacy=privacy,
privacy=final_privacy,
)
else:
mock_update_video.assert_not_called()
Expand Down

0 comments on commit 438861a

Please sign in to comment.