Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creates voiceover migration job #20165

Merged
merged 78 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from 77 commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
7c236f6
Adds flag to prevent voiceover contribution
Nik-09 Mar 10, 2024
4f3ee43
Adds feature flag to add voiceover with accent.
Nik-09 Mar 11, 2024
314dee5
Fixes lint issues
Nik-09 Mar 12, 2024
983b6aa
Fixes lint issues
Nik-09 Mar 12, 2024
1559ee2
Fixes merge conflict
Nik-09 Mar 19, 2024
ae3242e
Fixes lint, mypy, prettier, frontend, backend tests
Nik-09 Mar 20, 2024
c2521bd
updates variable name
Nik-09 Mar 20, 2024
0d21042
Updates UI
Nik-09 Mar 20, 2024
326e6b3
updates variable name
Nik-09 Mar 20, 2024
9a87a36
Fixes backend test
Nik-09 Mar 20, 2024
9ff7940
Removes platform param variable
Nik-09 Mar 22, 2024
aacd470
Removes redundant code.
Nik-09 Mar 22, 2024
7be470d
Updates flag name.
Nik-09 Mar 23, 2024
8e9d7c8
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Mar 24, 2024
50f301b
Fixes frontend tests
Nik-09 Mar 24, 2024
3008083
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Mar 26, 2024
53bd79b
Adds helper method to enable voiceover contribution feature flag.
Nik-09 Mar 26, 2024
dad1c6b
Fixes e2e test
Nik-09 Mar 26, 2024
2c11b65
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Mar 27, 2024
bf61246
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Mar 28, 2024
c7d8af1
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Apr 1, 2024
f7818be
Fixes e2e test
Nik-09 Apr 1, 2024
4992c34
Enabled video recording
Nik-09 Apr 1, 2024
853765f
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Apr 3, 2024
0c1c326
Fixes E2E test
Nik-09 Apr 3, 2024
3eed3ab
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Apr 9, 2024
aad85a5
Updates feature flag name from snake case to camel case
Nik-09 Apr 10, 2024
6914e8c
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Apr 10, 2024
23e20df
Updates feature flag for voiceovers
Nik-09 Apr 10, 2024
1e16a52
Enabled video recording for debugging e2e.
Nik-09 Apr 11, 2024
08be856
Merge branch 'develop' of https://github.com/Nik-09/oppia into flag_f…
Nik-09 Apr 12, 2024
2851e94
Disables video recording for e2e tests
Nik-09 Apr 15, 2024
8ef3b7c
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Apr 15, 2024
af6bc02
Creates voiceover migration job
Nik-09 Apr 15, 2024
d10688f
Updates beam job
Nik-09 Apr 16, 2024
98a91d6
Fixes backend tests
Nik-09 Apr 17, 2024
7f28b61
Fixes lint issues
Nik-09 Apr 17, 2024
9fffb74
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Apr 17, 2024
78e3ba8
Fixes mypy checks
Nik-09 Apr 17, 2024
69420db
Merge branch 'develop' of https://github.com/oppia/oppia into voiceov…
Nik-09 Apr 17, 2024
7968ab8
Adds test file in backend shard
Nik-09 Apr 18, 2024
f426cab
Adds backed tests
Nik-09 Apr 18, 2024
eabd921
Fixes lint issues.
Nik-09 Apr 18, 2024
134bcbe
Updates pipeline comment
Nik-09 Apr 18, 2024
b5f642f
Merge branch 'flag_for_voice_artists' of https://github.com/Nik-09/op…
Nik-09 Apr 18, 2024
4888794
Adds try-except block
Nik-09 Apr 19, 2024
0c5c612
Fixes lint issues
Nik-09 Apr 19, 2024
c3cbbe3
Fixes mypy checks
Nik-09 Apr 19, 2024
1c4cf4b
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Apr 19, 2024
e775de9
Removes waitfor method
Nik-09 Apr 19, 2024
c783946
Fixes backend tests
Nik-09 Apr 19, 2024
921bb98
Fixes mypy checks
Nik-09 Apr 19, 2024
c4e31e9
Fixes merge conflicts
Nik-09 Apr 20, 2024
8af0a5c
Fixes merge conflict
Nik-09 Apr 20, 2024
ab8c5bd
Fixes backend tests
Nik-09 Apr 21, 2024
3eb9910
Fixes backend tests
Nik-09 Apr 21, 2024
55ed41e
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Apr 21, 2024
b8dce8a
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Apr 22, 2024
9744ea0
Enables videos recording
Nik-09 Apr 23, 2024
dc25b69
Merge branch 'develop' of https://github.com/oppia/oppia into flag_fo…
Nik-09 Apr 25, 2024
a1415c6
Enables flag for recording voiceovers
Nik-09 Apr 26, 2024
e3744b5
Changes logged in username
Nik-09 Apr 27, 2024
6cb85c7
updates e2e test
Nik-09 Apr 27, 2024
66ffe50
Updates e2e test
Nik-09 Apr 28, 2024
7f9ab3a
Updates e2e tests
Nik-09 Apr 29, 2024
b10c7ae
Merge branch 'develop' of https://github.com/oppia/oppia into voiceov…
Nik-09 Apr 29, 2024
4f10fba
Fixes merge conflict
Nik-09 Apr 29, 2024
3167fd7
Fixes merge conflict
Nik-09 May 1, 2024
8cfc19d
Updates code as per review comments
Nik-09 May 1, 2024
cf6357b
Updates docstring
Nik-09 May 1, 2024
05288ab
Updates code docstring
Nik-09 May 1, 2024
19558a2
Fixes backend tests
Nik-09 May 2, 2024
f7f50eb
Updates beam job
Nik-09 May 3, 2024
599f118
Upates variable name
Nik-09 May 6, 2024
779b461
Adds service method
Nik-09 May 7, 2024
13220ff
Fixes typo
Nik-09 May 7, 2024
01839a9
Updates variable names
Nik-09 May 9, 2024
fdb8413
updates code docstring
Nik-09 May 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 67 additions & 32 deletions core/domain/voiceover_domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from core import utils
from core.domain import state_domain

from typing import Dict, Tuple, TypedDict
from typing import Dict, Optional, Tuple, TypedDict


class EntityVoiceoversDict(TypedDict):
Expand All @@ -34,7 +34,8 @@ class EntityVoiceoversDict(TypedDict):
entity_type: str
entity_version: int
language_accent_code: str
voiceovers: Dict[str, Dict[str, state_domain.VoiceoverDict]]
voiceovers_mapping: Dict[str, Dict[
feconf.VoiceoverType.value, Optional[state_domain.VoiceoverDict]]]


ContentIdToVoiceoverMappingType = Dict[
Expand All @@ -55,8 +56,8 @@ class EntityVoiceovers:
entity_version: str. The version of the corresponding entity.
language_accent_code: str. The language-accent code in which the
voiceover is stored.
voiceovers: dict(str, dict(VoiceoverType, VoiceoverDict)). A dict
containing content IDs as keys and nested dicts as values.
voiceovers_mapping: dict(str, dict(VoiceoverType, VoiceoverDict)). A
dict containing content IDs as keys and nested dicts as values.
Each nested dict contains VoiceoverType as keys and VoiceoverDict
as values.
"""
Expand All @@ -67,8 +68,8 @@ def __init__(
entity_type: str,
entity_version: int,
language_accent_code: str,
voiceovers: Dict[str, Dict[
feconf.VoiceoverType, state_domain.Voiceover]]
voiceovers_mapping: Dict[str, Dict[
feconf.VoiceoverType, Optional[state_domain.Voiceover]]]
) -> None:
"""Constructs an EntityVoiceovers domain object.

Expand All @@ -78,16 +79,16 @@ def __init__(
entity_version: int. The version of the entity.
language_accent_code: str. The language-accent code of the
given voiceover.
voiceovers: dict(str, dict(VoiceoverType, VoiceoverDict)). A dict
containing content IDs as keys and nested dicts as values.
voiceovers_mapping: dict(str, dict(VoiceoverType, VoiceoverDict)). A
dict containing content IDs as keys and nested dicts as values.
Each nested dict contains VoiceoverType as keys and
VoiceoverDict as values.
"""
self.entity_id = entity_id
self.entity_type = entity_type
self.entity_version = entity_version
self.language_accent_code = language_accent_code
self.voiceovers = voiceovers
self.voiceovers_mapping = voiceovers_mapping

def to_dict(self) -> EntityVoiceoversDict:
"""Returns the dict representation of the EntityVoiceovers object.
Expand All @@ -96,19 +97,26 @@ def to_dict(self) -> EntityVoiceoversDict:
EntityVoiceoversDict. The dict representation of the
EntityVoiceovers object.
"""
voiceovers_dict = {}
for content_id, voiceover_type_to_voiceover in self.voiceovers.items():
voiceovers_dict[content_id] = {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the implementation, because now we are allowing automatic voiceovers to be None. And we need to check before applying to_dict() method on the Voiceover domain instance.

voiceover_type.value: voiceover_type_to_voiceover[
voiceover_type].to_dict()
for voiceover_type in feconf.VoiceoverType
}
content_id_to_voiceovers_dict: Dict[str, Dict[
feconf.VoiceoverType.value, Optional[state_domain.VoiceoverDict]]
] = {}

for content_id, voiceover_type_to_voiceover in (
self.voiceovers_mapping.items()):
content_id_to_voiceovers_dict[content_id] = {}
for voiceover_type in feconf.VoiceoverType:
voiceover = voiceover_type_to_voiceover[voiceover_type]
voiceover_dict = (
None if voiceover is None else voiceover.to_dict())

content_id_to_voiceovers_dict[content_id][
voiceover_type.value] = voiceover_dict
return {
'entity_id': self.entity_id,
'entity_type': self.entity_type,
'entity_version': self.entity_version,
'language_accent_code': self.language_accent_code,
'voiceovers': voiceovers_dict
'voiceovers_mapping': content_id_to_voiceovers_dict
}

@classmethod
Expand All @@ -125,14 +133,21 @@ def from_dict(
EntityVoiceovers. The EntityVoiceovers instance created using the
given dict.
"""
content_id_to_voiceovers = {}
content_id_to_voiceovers: Dict[str, Dict[
feconf.VoiceoverType, Optional[state_domain.Voiceover]]] = {}
for content_id, voiceover_type_to_voiceover_dict in (
entity_voiceovers_dict['voiceovers'].items()):
content_id_to_voiceovers[content_id] = {
voiceover_type: state_domain.Voiceover.from_dict(
voiceover_type_to_voiceover_dict[voiceover_type.value])
for voiceover_type in feconf.VoiceoverType
}
entity_voiceovers_dict['voiceovers_mapping'].items()):
content_id_to_voiceovers[content_id] = {}
for voiceover_type in feconf.VoiceoverType:
voiceover_dict = voiceover_type_to_voiceover_dict[
voiceover_type.value]
voiceover = (
None if voiceover_dict is None
else state_domain.Voiceover.from_dict(voiceover_dict))

content_id_to_voiceovers[content_id][
voiceover_type] = voiceover

return cls(
entity_voiceovers_dict['entity_id'],
entity_voiceovers_dict['entity_type'],
Expand Down Expand Up @@ -163,7 +178,8 @@ def validate(self) -> None:
'language_accent_code must be formatted as '
'{{language}}-{{accent}}, received %s' %
self.language_accent_code)
for content_id, voiceover_type_to_voiceover in self.voiceovers.items():
for content_id, voiceover_type_to_voiceover in (
self.voiceovers_mapping.items()):
if not isinstance(content_id, str):
raise utils.ValidationError(
'content_id must be a string, received %s' % content_id)
Expand All @@ -173,13 +189,32 @@ def validate(self) -> None:
raise utils.ValidationError(
'voiceover type must be VoiceoverType, received %s' %
voiceover_type)
voiceover.validate()
if voiceover is not None:
voiceover.validate()

def add_new_content_id_without_voiceovers(
self,
content_id: str
) -> None:
"""Adds a new content ID for which manual and automatic voiceovers
can be added. Initially, both voiceover fields will be empty (None),
and they will later be populated with their respective values using the
add_voiceover method.

Args:
content_id: str. The new content ID for which voiceovers should be
added.
"""
self.voiceovers_mapping[content_id] = {
feconf.VoiceoverType.MANUAL: None,
feconf.VoiceoverType.AUTO: None
}

def add_voiceover(
self,
content_id: str,
voiceover_type: feconf.VoiceoverType,
voiceover: state_domain.Voiceover
voiceovers_mapping: state_domain.Voiceover
) -> None:
"""Adds voiceover to the entity voiceover instance.

Expand All @@ -188,10 +223,10 @@ def add_voiceover(
being added.
voiceover_type: VoiceoverType. The voiceover type of the given
voiceover.
voiceover: Voiceover. The voiceover instance to be added to the
entity voiceovers object.
voiceovers_mapping: Voiceover. The voiceover instance to be added to
the entity voiceovers object.
"""
self.voiceovers[content_id][voiceover_type] = voiceover
self.voiceovers_mapping[content_id][voiceover_type] = voiceovers_mapping

def remove_voiceover(
self,
Expand All @@ -206,7 +241,7 @@ def remove_voiceover(
voiceover_type: VoiceoverType. The voiceover type of the given
voiceover.
"""
del self.voiceovers[content_id][voiceover_type]
del self.voiceovers_mapping[content_id][voiceover_type]

@classmethod
def create_empty(
Expand All @@ -222,4 +257,4 @@ def create_empty(
entity_type=entity_type,
entity_version=entity_version,
language_accent_code=language_accent_code,
voiceovers={})
voiceovers_mapping={})
77 changes: 56 additions & 21 deletions core/domain/voiceover_domain_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def setUp(self) -> None:
entity_type=feconf.ENTITY_TYPE_EXPLORATION,
entity_version=1,
language_accent_code='en-US',
voiceovers={
voiceovers_mapping={
'content_id_0': {
feconf.VoiceoverType.MANUAL: (
state_domain.Voiceover.from_dict(
Expand All @@ -68,7 +68,7 @@ def test_to_dict_method_of_entity_voiceovers_class(self) -> None:
'entity_type': 'exploration',
'entity_version': 1,
'language_accent_code': 'en-US',
'voiceovers': {
'voiceovers_mapping': {
'content_id_0': {
'manual': self.dummy_manual_voiceover_dict,
'auto': self.dummy_autogenerated_voiceover_dict
Expand All @@ -85,7 +85,7 @@ def test_from_dict_method_of_entity_voiceovers_class(self) -> None:
'entity_type': 'exploration',
'entity_version': 1,
'language_accent_code': 'en-US',
'voiceovers': {
'voiceovers_mapping': {
'content_id_0': {
'manual': self.dummy_manual_voiceover_dict,
'auto': self.dummy_autogenerated_voiceover_dict
Expand Down Expand Up @@ -140,9 +140,10 @@ def test_validate_datatype_of_voiceover_type(self) -> None:
utils.ValidationError,
'voiceover type must be VoiceoverType'
):
self.entity_voiceovers_instance.voiceovers['content_id_0'][1] = ( # type: ignore[index]
self.entity_voiceovers_instance.voiceovers['content_id_0'][
feconf.VoiceoverType.MANUAL])
self.entity_voiceovers_instance.voiceovers_mapping[
'content_id_0'][1] = ( # type: ignore[index]
self.entity_voiceovers_instance.voiceovers_mapping[
'content_id_0'][feconf.VoiceoverType.MANUAL])
self.entity_voiceovers_instance.validate()

def test_validate_language_accent_code(self) -> None:
Expand Down Expand Up @@ -181,7 +182,7 @@ def test_validate_content_id(self) -> None:
utils.ValidationError,
'content_id must be a string'
):
self.entity_voiceovers_instance.voiceovers[1] = None # type: ignore[index, assignment]
self.entity_voiceovers_instance.voiceovers_mapping[1] = None # type: ignore[index, assignment]
self.entity_voiceovers_instance.validate()

def test_add_voiceovers_correctly(self) -> None:
Expand All @@ -193,27 +194,32 @@ def test_add_voiceovers_correctly(self) -> None:
}
new_voiceover_object = state_domain.Voiceover.from_dict(
dummy_new_voiceover_dict)
manual_voiceover = self.entity_voiceovers_instance.voiceovers_mapping[
'content_id_0'][feconf.VoiceoverType.MANUAL]
assert isinstance(manual_voiceover, state_domain.Voiceover)
self.assertDictEqual(
self.entity_voiceovers_instance.voiceovers['content_id_0'][
feconf.VoiceoverType.MANUAL].to_dict(),
manual_voiceover.to_dict(),
self.dummy_manual_voiceover_dict
)

self.entity_voiceovers_instance.add_voiceover(
content_id='content_id_0',
voiceover_type=feconf.VoiceoverType.MANUAL,
voiceover=new_voiceover_object)
voiceovers_mapping=new_voiceover_object)

manual_voiceover = self.entity_voiceovers_instance.voiceovers_mapping[
'content_id_0'][feconf.VoiceoverType.MANUAL]
assert isinstance(manual_voiceover, state_domain.Voiceover)
self.assertDictEqual(
self.entity_voiceovers_instance.voiceovers['content_id_0'][
feconf.VoiceoverType.MANUAL].to_dict(),
manual_voiceover.to_dict(),
dummy_new_voiceover_dict
)

def test_removes_voiceover_correctly(self) -> None:
self.assertIn(
feconf.VoiceoverType.MANUAL,
self.entity_voiceovers_instance.voiceovers['content_id_0'].keys())
self.entity_voiceovers_instance.voiceovers_mapping[
'content_id_0'].keys())

self.entity_voiceovers_instance.remove_voiceover(
content_id='content_id_0',
Expand All @@ -222,17 +228,46 @@ def test_removes_voiceover_correctly(self) -> None:

self.assertNotIn(
feconf.VoiceoverType.MANUAL,
self.entity_voiceovers_instance.voiceovers['content_id_0'].keys())
self.entity_voiceovers_instance.voiceovers_mapping[
'content_id_0'].keys())

def test_create_empty_entity_voiceovers_object(self) -> None:
empty_entity_voiceovers_object = (
def test_create_empty_entity_voiceovers(self) -> None:
empty_entity_voiceovers = (
voiceover_domain.EntityVoiceovers.create_empty(
'exp_id', 'exploration', 1, 'en-US'))

self.assertEqual(empty_entity_voiceovers_object.entity_id, 'exp_id')
self.assertEqual(empty_entity_voiceovers_object.entity_version, 1)
self.assertEqual(empty_entity_voiceovers.entity_id, 'exp_id')
self.assertEqual(empty_entity_voiceovers.entity_version, 1)
self.assertEqual(
empty_entity_voiceovers_object.entity_type, 'exploration')
empty_entity_voiceovers.entity_type, 'exploration')
self.assertEqual(
empty_entity_voiceovers_object.language_accent_code, 'en-US')
self.assertEqual(empty_entity_voiceovers_object.voiceovers, {})
empty_entity_voiceovers.language_accent_code, 'en-US')
self.assertEqual(empty_entity_voiceovers.voiceovers_mapping, {})

def test_should_be_able_to_add_new_content_id(self) -> None:
entity_voiceovers_object = (
voiceover_domain.EntityVoiceovers.create_empty(
'exp_id', 'exploration', 1, 'en-US'))

self.assertEqual(entity_voiceovers_object.entity_id, 'exp_id')
self.assertEqual(entity_voiceovers_object.entity_version, 1)
self.assertEqual(
entity_voiceovers_object.entity_type, 'exploration')
self.assertEqual(
entity_voiceovers_object.language_accent_code, 'en-US')
self.assertEqual(entity_voiceovers_object.voiceovers_mapping, {})

entity_voiceovers_object.add_new_content_id_without_voiceovers(
'content_1')
entity_voiceovers_object.add_voiceover(
'content_1',
feconf.VoiceoverType.MANUAL,
state_domain.Voiceover.from_dict(self.dummy_manual_voiceover_dict))

manual_voiceover = entity_voiceovers_object.voiceovers_mapping[
'content_1'][feconf.VoiceoverType.MANUAL]
assert isinstance(manual_voiceover, state_domain.Voiceover)

self.assertDictEqual(
manual_voiceover.to_dict(),
self.dummy_manual_voiceover_dict)
Loading
Loading