Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-val
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-val
Commits
eee4c2f0
Commit
eee4c2f0
authored
Jan 19, 2018
by
Qubad786
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
make Video an explicit foreign key and fix utils/views/tests
parent
7d5c04df
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
72 additions
and
62 deletions
+72
-62
edxval/admin.py
+1
-1
edxval/api.py
+17
-32
edxval/migrations/0010_add_video_as_foreign_key.py
+31
-0
edxval/models.py
+9
-17
edxval/serializers.py
+7
-1
edxval/tests/constants.py
+0
-8
edxval/tests/test_api.py
+0
-0
edxval/tests/test_views.py
+7
-3
No files found.
edxval/admin.py
View file @
eee4c2f0
...
@@ -69,7 +69,7 @@ class CourseVideoAdmin(admin.ModelAdmin):
...
@@ -69,7 +69,7 @@ class CourseVideoAdmin(admin.ModelAdmin):
class
VideoTranscriptAdmin
(
admin
.
ModelAdmin
):
class
VideoTranscriptAdmin
(
admin
.
ModelAdmin
):
list_display
=
(
'video
_id
'
,
'language_code'
,
'provider'
,
'file_format'
)
list_display
=
(
'video'
,
'language_code'
,
'provider'
,
'file_format'
)
model
=
VideoTranscript
model
=
VideoTranscript
...
...
edxval/api.py
View file @
eee4c2f0
...
@@ -192,7 +192,7 @@ def is_transcript_available(video_id, language_code=None):
...
@@ -192,7 +192,7 @@ def is_transcript_available(video_id, language_code=None):
video_id: it can be an edx_video_id or an external_id extracted from external sources in a video component.
video_id: it can be an edx_video_id or an external_id extracted from external sources in a video component.
language_code: it will the language code of the requested transcript.
language_code: it will the language code of the requested transcript.
"""
"""
filter_attrs
=
{
'video_id'
:
video_id
}
filter_attrs
=
{
'video_
_edx_video_
id'
:
video_id
}
if
language_code
:
if
language_code
:
filter_attrs
[
'language_code'
]
=
language_code
filter_attrs
[
'language_code'
]
=
language_code
...
@@ -200,22 +200,6 @@ def is_transcript_available(video_id, language_code=None):
...
@@ -200,22 +200,6 @@ def is_transcript_available(video_id, language_code=None):
return
transcript_set
.
exists
()
return
transcript_set
.
exists
()
def
get_video_transcripts
(
video_id
):
"""
Get a video's transcripts
Arguments:
video_id: it can be an edx_video_id or an external_id extracted from external sources in a video component.
"""
transcripts_set
=
VideoTranscript
.
objects
.
filter
(
video_id
=
video_id
)
transcripts
=
[]
if
transcripts_set
.
exists
():
transcripts
=
TranscriptSerializer
(
transcripts_set
,
many
=
True
)
.
data
return
transcripts
def
get_video_transcript
(
video_id
,
language_code
):
def
get_video_transcript
(
video_id
,
language_code
):
"""
"""
Get video transcript info
Get video transcript info
...
@@ -245,7 +229,7 @@ def get_video_transcript_data(video_ids, language_code):
...
@@ -245,7 +229,7 @@ def get_video_transcript_data(video_ids, language_code):
transcript_data
=
None
transcript_data
=
None
for
video_id
in
video_ids
:
for
video_id
in
video_ids
:
try
:
try
:
video_transcript
=
VideoTranscript
.
objects
.
get
(
video_id
=
video_id
,
language_code
=
language_code
)
video_transcript
=
VideoTranscript
.
objects
.
get
(
video_
_edx_video_
id
=
video_id
,
language_code
=
language_code
)
transcript_data
=
dict
(
transcript_data
=
dict
(
file_name
=
video_transcript
.
filename
,
file_name
=
video_transcript
.
filename
,
content
=
video_transcript
.
transcript
.
file
.
read
()
content
=
video_transcript
.
transcript
.
file
.
read
()
...
@@ -276,7 +260,7 @@ def get_available_transcript_languages(video_ids):
...
@@ -276,7 +260,7 @@ def get_available_transcript_languages(video_ids):
A list containing unique transcript language codes for the video ids.
A list containing unique transcript language codes for the video ids.
"""
"""
available_languages
=
VideoTranscript
.
objects
.
filter
(
available_languages
=
VideoTranscript
.
objects
.
filter
(
video_id__in
=
video_ids
video_
_edx_video_
id__in
=
video_ids
)
.
values_list
(
)
.
values_list
(
'language_code'
,
flat
=
True
'language_code'
,
flat
=
True
)
)
...
@@ -324,7 +308,12 @@ def create_or_update_video_transcript(video_id, language_code, metadata, file_da
...
@@ -324,7 +308,12 @@ def create_or_update_video_transcript(video_id, language_code, metadata, file_da
if
provider
and
provider
not
in
dict
(
TranscriptProviderType
.
CHOICES
)
.
keys
():
if
provider
and
provider
not
in
dict
(
TranscriptProviderType
.
CHOICES
)
.
keys
():
raise
InvalidTranscriptProvider
(
'{} transcript provider is not supported'
.
format
(
provider
))
raise
InvalidTranscriptProvider
(
'{} transcript provider is not supported'
.
format
(
provider
))
video_transcript
,
__
=
VideoTranscript
.
create_or_update
(
video_id
,
language_code
,
metadata
,
file_data
)
try
:
# Video should be present in edxval in order to attach transcripts to it.
video
=
Video
.
objects
.
get
(
edx_video_id
=
video_id
)
video_transcript
,
__
=
VideoTranscript
.
create_or_update
(
video
,
language_code
,
metadata
,
file_data
)
except
Video
.
DoesNotExist
:
return
None
return
video_transcript
.
url
()
return
video_transcript
.
url
()
...
@@ -338,7 +327,7 @@ def delete_video_transcript(video_id, language_code):
...
@@ -338,7 +327,7 @@ def delete_video_transcript(video_id, language_code):
language_code: language code of a video transcript
language_code: language code of a video transcript
"""
"""
try
:
try
:
video_transcript
=
VideoTranscript
.
objects
.
get
(
video_id
=
video_id
,
language_code
=
language_code
)
video_transcript
=
VideoTranscript
.
objects
.
get
(
video_
_edx_video_
id
=
video_id
,
language_code
=
language_code
)
# delete the actual transcript file from storage
# delete the actual transcript file from storage
video_transcript
.
transcript
.
delete
()
video_transcript
.
transcript
.
delete
()
# delete the record from db
# delete the record from db
...
@@ -775,10 +764,9 @@ def export_to_xml(video_ids, course_id=None, external=False):
...
@@ -775,10 +764,9 @@ def export_to_xml(video_ids, course_id=None, external=False):
Raises:
Raises:
ValVideoNotFoundError: if the video does not exist
ValVideoNotFoundError: if the video does not exist
"""
"""
#
val does not store external videos, so construct transcripts information only.
#
TODO: This will be removed as a part of EDUCATOR-1789
if
external
:
if
external
:
video_el
=
Element
(
'video_asset'
)
return
Element
(
'video_asset'
)
return
create_transcripts_xml
(
video_ids
,
video_el
)
# for an internal video, first video id must be edx_video_id
# for an internal video, first video id must be edx_video_id
video_id
=
video_ids
[
0
]
video_id
=
video_ids
[
0
]
...
@@ -824,7 +812,7 @@ def create_transcripts_xml(video_ids, video_el):
...
@@ -824,7 +812,7 @@ def create_transcripts_xml(video_ids, video_el):
Returns:
Returns:
lxml Element object with transcripts information
lxml Element object with transcripts information
"""
"""
video_transcripts
=
VideoTranscript
.
objects
.
filter
(
video_
id__in
=
video_ids
)
video_transcripts
=
VideoTranscript
.
objects
.
filter
(
video_
_edx_video_id__in
=
video_ids
)
.
order_by
(
'language_code'
)
# create transcripts node only when we have transcripts for a video
# create transcripts node only when we have transcripts for a video
if
video_transcripts
.
exists
():
if
video_transcripts
.
exists
():
transcripts_el
=
SubElement
(
video_el
,
'transcripts'
)
transcripts_el
=
SubElement
(
video_el
,
'transcripts'
)
...
@@ -836,7 +824,7 @@ def create_transcripts_xml(video_ids, video_el):
...
@@ -836,7 +824,7 @@ def create_transcripts_xml(video_ids, video_el):
transcripts_el
,
transcripts_el
,
'transcript'
,
'transcript'
,
{
{
'video_id'
:
video_transcript
.
video_id
,
'video_id'
:
video_transcript
.
video
.
edx_video
_id
,
'file_name'
:
video_transcript
.
transcript
.
name
,
'file_name'
:
video_transcript
.
transcript
.
name
,
'language_code'
:
video_transcript
.
language_code
,
'language_code'
:
video_transcript
.
language_code
,
'file_format'
:
video_transcript
.
file_format
,
'file_format'
:
video_transcript
.
file_format
,
...
@@ -866,9 +854,9 @@ def import_from_xml(xml, edx_video_id, course_id=None):
...
@@ -866,9 +854,9 @@ def import_from_xml(xml, edx_video_id, course_id=None):
if
xml
.
tag
!=
'video_asset'
:
if
xml
.
tag
!=
'video_asset'
:
raise
ValCannotCreateError
(
'Invalid XML'
)
raise
ValCannotCreateError
(
'Invalid XML'
)
#
if edx_video_id does not exist then create video transcripts only
#
TODO this will be moved as a part of EDUCATOR-2173
if
not
edx_video_id
:
if
not
edx_video_id
:
return
create_transcript_objects
(
xml
)
return
# If video with edx_video_id already exists, associate it with the given course_id.
# If video with edx_video_id already exists, associate it with the given course_id.
try
:
try
:
...
@@ -885,9 +873,6 @@ def import_from_xml(xml, edx_video_id, course_id=None):
...
@@ -885,9 +873,6 @@ def import_from_xml(xml, edx_video_id, course_id=None):
if
image_file_name
:
if
image_file_name
:
VideoImage
.
create_or_update
(
course_video
,
image_file_name
)
VideoImage
.
create_or_update
(
course_video
,
image_file_name
)
# import transcripts
create_transcript_objects
(
xml
)
return
return
except
ValidationError
as
err
:
except
ValidationError
as
err
:
logger
.
exception
(
err
.
message
)
logger
.
exception
(
err
.
message
)
...
@@ -934,7 +919,7 @@ def create_transcript_objects(xml):
...
@@ -934,7 +919,7 @@ def create_transcript_objects(xml):
"""
"""
for
transcript
in
xml
.
findall
(
'.//transcripts/transcript'
):
for
transcript
in
xml
.
findall
(
'.//transcripts/transcript'
):
try
:
try
:
VideoTranscript
.
create_or_update
(
create_or_update_video_transcript
(
transcript
.
attrib
[
'video_id'
],
transcript
.
attrib
[
'video_id'
],
transcript
.
attrib
[
'language_code'
],
transcript
.
attrib
[
'language_code'
],
metadata
=
dict
(
metadata
=
dict
(
...
...
edxval/migrations/0010_add_video_as_foreign_key.py
0 → 100644
View file @
eee4c2f0
# -*- coding: utf-8 -*-
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'edxval'
,
'0009_auto_20171127_0406'
),
]
operations
=
[
migrations
.
AlterUniqueTogether
(
name
=
'videotranscript'
,
unique_together
=
set
([(
'language_code'
,)]),
),
migrations
.
RemoveField
(
model_name
=
'videotranscript'
,
name
=
'video_id'
,
),
migrations
.
AddField
(
model_name
=
'videotranscript'
,
name
=
'video'
,
field
=
models
.
ForeignKey
(
related_name
=
'video_transcripts'
,
to
=
'edxval.Video'
,
null
=
True
),
),
migrations
.
AlterUniqueTogether
(
name
=
'videotranscript'
,
unique_together
=
set
([(
'video'
,
'language_code'
)]),
),
]
edxval/models.py
View file @
eee4c2f0
...
@@ -404,7 +404,7 @@ class VideoTranscript(TimeStampedModel):
...
@@ -404,7 +404,7 @@ class VideoTranscript(TimeStampedModel):
"""
"""
Transcript for a video
Transcript for a video
"""
"""
video
_id
=
models
.
CharField
(
max_length
=
255
,
help_text
=
'It can be an edx_video_id or an external video id'
)
video
=
models
.
ForeignKey
(
Video
,
related_name
=
'video_transcripts'
,
null
=
True
)
transcript
=
CustomizableFileField
()
transcript
=
CustomizableFileField
()
language_code
=
models
.
CharField
(
max_length
=
50
,
db_index
=
True
)
language_code
=
models
.
CharField
(
max_length
=
50
,
db_index
=
True
)
provider
=
models
.
CharField
(
provider
=
models
.
CharField
(
...
@@ -415,27 +415,19 @@ class VideoTranscript(TimeStampedModel):
...
@@ -415,27 +415,19 @@ class VideoTranscript(TimeStampedModel):
file_format
=
models
.
CharField
(
max_length
=
20
,
db_index
=
True
,
choices
=
TranscriptFormat
.
CHOICES
)
file_format
=
models
.
CharField
(
max_length
=
20
,
db_index
=
True
,
choices
=
TranscriptFormat
.
CHOICES
)
class
Meta
:
class
Meta
:
unique_together
=
(
'video
_id
'
,
'language_code'
)
unique_together
=
(
'video'
,
'language_code'
)
@property
@property
def
filename
(
self
):
def
filename
(
self
):
"""
"""
Returns readable filename for a transcript
Returns readable filename for a transcript
"""
"""
try
:
client_id
,
__
=
os
.
path
.
splitext
(
self
.
video
.
client_video_id
)
video
=
Video
.
objects
.
get
(
edx_video_id
=
self
.
video_id
)
client_id
,
__
=
os
.
path
.
splitext
(
video
.
client_video_id
)
file_name
=
u'{name}-{language}.{format}'
.
format
(
file_name
=
u'{name}-{language}.{format}'
.
format
(
name
=
client_id
,
name
=
client_id
,
language
=
self
.
language_code
,
language
=
self
.
language_code
,
format
=
self
.
file_format
format
=
self
.
file_format
)
)
except
Video
.
DoesNotExist
:
file_name
=
u'{name}-{language}.{format}'
.
format
(
name
=
self
.
video_id
,
language
=
self
.
language_code
,
format
=
self
.
file_format
)
return
file_name
return
file_name
...
@@ -449,19 +441,19 @@ class VideoTranscript(TimeStampedModel):
...
@@ -449,19 +441,19 @@ class VideoTranscript(TimeStampedModel):
language_code(unicode): language of the requested transcript
language_code(unicode): language of the requested transcript
"""
"""
try
:
try
:
transcript
=
cls
.
objects
.
get
(
video_id
=
video_id
,
language_code
=
language_code
)
transcript
=
cls
.
objects
.
get
(
video_
_edx_video_
id
=
video_id
,
language_code
=
language_code
)
except
cls
.
DoesNotExist
:
except
cls
.
DoesNotExist
:
transcript
=
None
transcript
=
None
return
transcript
return
transcript
@classmethod
@classmethod
def
create_or_update
(
cls
,
video
_id
,
language_code
,
metadata
,
file_data
=
None
):
def
create_or_update
(
cls
,
video
,
language_code
,
metadata
,
file_data
=
None
):
"""
"""
Create or update Transcript object.
Create or update Transcript object.
Arguments:
Arguments:
video
_id (str): unique id for a video
video
(Video): Video for which transcript is going to be saved.
language_code (str): language code for (to be created/updated) transcript
language_code (str): language code for (to be created/updated) transcript
metadata (dict): A dict containing (to be overwritten) properties
metadata (dict): A dict containing (to be overwritten) properties
file_data (InMemoryUploadedFile): File data to be saved
file_data (InMemoryUploadedFile): File data to be saved
...
@@ -469,7 +461,7 @@ class VideoTranscript(TimeStampedModel):
...
@@ -469,7 +461,7 @@ class VideoTranscript(TimeStampedModel):
Returns:
Returns:
Returns a tuple of (video_transcript, created).
Returns a tuple of (video_transcript, created).
"""
"""
video_transcript
,
created
=
cls
.
objects
.
get_or_create
(
video
_id
=
video_id
,
language_code
=
language_code
)
video_transcript
,
created
=
cls
.
objects
.
get_or_create
(
video
=
video
,
language_code
=
language_code
)
for
prop
,
value
in
metadata
.
iteritems
():
for
prop
,
value
in
metadata
.
iteritems
():
if
prop
in
[
'language_code'
,
'file_format'
,
'provider'
]:
if
prop
in
[
'language_code'
,
'file_format'
,
'provider'
]:
...
@@ -489,7 +481,7 @@ class VideoTranscript(TimeStampedModel):
...
@@ -489,7 +481,7 @@ class VideoTranscript(TimeStampedModel):
try
:
try
:
video_transcript
.
transcript
.
save
(
file_name
,
transcript_file_data
)
video_transcript
.
transcript
.
save
(
file_name
,
transcript_file_data
)
except
Exception
:
except
Exception
:
logger
.
exception
(
'VAL: Transcript save failed to storage for video_id [
%
s]'
,
video_id
)
logger
.
exception
(
'VAL: Transcript save failed to storage for video_id [
%
s]'
,
video
.
edx_video
_id
)
raise
raise
video_transcript
.
save
()
video_transcript
.
save
()
...
@@ -503,7 +495,7 @@ class VideoTranscript(TimeStampedModel):
...
@@ -503,7 +495,7 @@ class VideoTranscript(TimeStampedModel):
return
storage
.
url
(
self
.
transcript
.
name
)
return
storage
.
url
(
self
.
transcript
.
name
)
def
__unicode__
(
self
):
def
__unicode__
(
self
):
return
u'{lang} Transcript for {video}'
.
format
(
lang
=
self
.
language_code
,
video
=
self
.
video_id
)
return
u'{lang} Transcript for {video}'
.
format
(
lang
=
self
.
language_code
,
video
=
self
.
video
.
edx_video
_id
)
class
Cielo24Turnaround
(
object
):
class
Cielo24Turnaround
(
object
):
...
...
edxval/serializers.py
View file @
eee4c2f0
...
@@ -57,11 +57,17 @@ class TranscriptSerializer(serializers.ModelSerializer):
...
@@ -57,11 +57,17 @@ class TranscriptSerializer(serializers.ModelSerializer):
"""
"""
class
Meta
:
# pylint: disable=C1001, C0111
class
Meta
:
# pylint: disable=C1001, C0111
model
=
VideoTranscript
model
=
VideoTranscript
lookup_field
=
'video_id'
fields
=
(
'video_id'
,
'url'
,
'language_code'
,
'provider'
,
'file_format'
)
fields
=
(
'video_id'
,
'url'
,
'language_code'
,
'provider'
,
'file_format'
)
video_id
=
serializers
.
SerializerMethodField
()
url
=
serializers
.
SerializerMethodField
()
url
=
serializers
.
SerializerMethodField
()
def
get_video_id
(
self
,
transcript
):
"""
Returns an edx video ID for the related video.
"""
return
transcript
.
video
.
edx_video_id
def
get_url
(
self
,
transcript
):
def
get_url
(
self
,
transcript
):
"""
"""
Retrieves the transcript url.
Retrieves the transcript url.
...
...
edxval/tests/constants.py
View file @
eee4c2f0
...
@@ -378,14 +378,6 @@ VIDEO_TRANSCRIPT_3PLAY = dict(
...
@@ -378,14 +378,6 @@ VIDEO_TRANSCRIPT_3PLAY = dict(
file_format
=
TranscriptFormat
.
SJSON
,
file_format
=
TranscriptFormat
.
SJSON
,
)
)
VIDEO_TRANSCRIPT_CUSTOM
=
dict
(
video_id
=
'external_video_id'
,
language_code
=
'de'
,
transcript
=
'wow.srt'
,
provider
=
TranscriptProviderType
.
CUSTOM
,
file_format
=
TranscriptFormat
.
SRT
,
)
TRANSCRIPT_PREFERENCES_CIELO24
=
dict
(
TRANSCRIPT_PREFERENCES_CIELO24
=
dict
(
course_id
=
'edX/DemoX/Demo_Course'
,
course_id
=
'edX/DemoX/Demo_Course'
,
provider
=
TranscriptProviderType
.
CIELO24
,
provider
=
TranscriptProviderType
.
CIELO24
,
...
...
edxval/tests/test_api.py
View file @
eee4c2f0
This diff is collapsed.
Click to expand it.
edxval/tests/test_views.py
View file @
eee4c2f0
...
@@ -3,7 +3,6 @@
...
@@ -3,7 +3,6 @@
Tests for Video Abstraction Layer views
Tests for Video Abstraction Layer views
"""
"""
import
json
import
json
import
unittest
from
ddt
import
data
,
ddt
,
unpack
from
ddt
import
data
,
ddt
,
unpack
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
...
@@ -821,13 +820,18 @@ class VideoTranscriptViewTest(APIAuthTestCase):
...
@@ -821,13 +820,18 @@ class VideoTranscriptViewTest(APIAuthTestCase):
serialized_data
=
TranscriptSerializer
(
VideoTranscript
.
objects
.
first
())
.
data
serialized_data
=
TranscriptSerializer
(
VideoTranscript
.
objects
.
first
())
.
data
post_transcript_data
[
'url'
]
=
post_transcript_data
.
pop
(
'name'
)
post_transcript_data
[
'url'
]
=
post_transcript_data
.
pop
(
'name'
)
self
.
assertEqual
(
serialized_data
,
post_transcript_data
)
self
.
assert
Dict
Equal
(
serialized_data
,
post_transcript_data
)
def
test_update_existing_transcript
(
self
):
def
test_update_existing_transcript
(
self
):
"""
"""
Tests updating existing transcript works as expected.
Tests updating existing transcript works as expected.
"""
"""
VideoTranscript
.
objects
.
create
(
**
self
.
transcript_data
)
VideoTranscript
.
objects
.
create
(
video
=
self
.
video
,
language_code
=
self
.
transcript_data
[
'language_code'
],
file_format
=
self
.
transcript_data
[
'file_format'
],
provider
=
self
.
transcript_data
[
'provider'
],
)
post_transcript_data
=
dict
(
self
.
transcript_data
)
post_transcript_data
=
dict
(
self
.
transcript_data
)
post_transcript_data
[
'name'
]
=
post_transcript_data
.
pop
(
'transcript'
)
post_transcript_data
[
'name'
]
=
post_transcript_data
.
pop
(
'transcript'
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment