Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-video-pipeline
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-video-pipeline
Commits
77964646
Commit
77964646
authored
Sep 29, 2017
by
Mushtaq Ali
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Save transcript credentials - EDUCATOR-1335
parent
62910040
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
407 additions
and
16 deletions
+407
-16
VEDA/urls.py
+6
-0
VEDA_OS01/tests/test_transcripts.py
+5
-1
VEDA_OS01/tests/test_views.py
+214
-0
VEDA_OS01/transcripts.py
+4
-1
VEDA_OS01/views.py
+170
-8
control/tests/test_deliver_cielo.py
+4
-3
control/veda_deliver_cielo.py
+4
-3
No files found.
VEDA/urls.py
View file @
77964646
...
...
@@ -31,6 +31,12 @@ urlpatterns = [
url
(
r'^accounts/logout/$'
,
'django.contrib.auth.views.logout'
),
url
(
r'^o/'
,
include
(
'oauth2_provider.urls'
,
namespace
=
'oauth2_provider'
)),
url
(
r'^api/'
,
include
(
router
.
urls
)),
# Transcript credentials handler view
url
(
regex
=
r'^api/transcript_credentials/$'
,
view
=
views
.
TranscriptCredentialsView
.
as_view
(),
name
=
'transcript_credentials'
),
url
(
r'^api-auth/'
,
include
(
'rest_framework.urls'
,
namespace
=
'rest_framework'
)),
# Cheap auth server
url
(
r'^veda_auth/'
,
views
.
token_auth
),
...
...
VEDA_OS01/tests/test_transcripts.py
View file @
77964646
...
...
@@ -238,7 +238,11 @@ class Cielo24TranscriptTests(APITestCase):
# verify requests
self
.
assertTrue
(
responses
.
calls
[
0
]
.
request
.
url
,
'http://api.cielo24.com/job/get_caption?api_token=i_am_key&job_id=
%28100%2
C
%29
&caption_format=SRT&v=1'
(
'http://api.cielo24.com/job/get_caption'
'?api_token=i_am_key&job_id=
%28100%2
C
%29
&caption_format=SRT&v={cielo_api_version}'
)
.
format
(
cielo_api_version
=
transcripts
.
CIELO24_API_VERSION
)
)
self
.
assertEqual
(
responses
.
calls
[
2
]
.
request
.
url
,
CONFIG_DATA
[
'val_transcript_create_url'
])
...
...
VEDA_OS01/tests/test_views.py
0 → 100644
View file @
77964646
""" Views tests """
import
json
import
responses
from
ddt
import
data
,
ddt
,
unpack
from
django.contrib.auth.models
import
User
from
django.core.urlresolvers
import
reverse
from
mock
import
patch
from
rest_framework
import
status
from
rest_framework.test
import
APITestCase
from
VEDA_OS01.models
import
TranscriptCredentials
,
TranscriptProvider
from
VEDA_OS01.views
import
CIELO24_LOGIN_URL
@ddt
class
TranscriptCredentialsTest
(
APITestCase
):
"""
Transcript credentials tests
"""
def
setUp
(
self
):
"""
Tests setup.
"""
super
(
TranscriptCredentialsTest
,
self
)
.
setUp
()
self
.
url
=
reverse
(
'transcript_credentials'
)
self
.
user
=
User
.
objects
.
create_user
(
'test_user'
,
'test@user.com'
,
'test'
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
'test'
)
def
test_transcript_credentials_get_not_allowed
(
self
):
"""
Tests that GET method is not allowed.
"""
response
=
self
.
client
.
get
(
self
.
url
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_405_METHOD_NOT_ALLOWED
)
def
test_transcript_credentials_unauthorized
(
self
):
"""
Tests that if user is not logged in we get Unauthorized response.
"""
# Logout client if previously logged in.
self
.
client
.
logout
()
# Try to send post without being authorized / logged in.
response
=
self
.
client
.
post
(
self
.
url
,
data
=
json
.
dumps
({
'org'
:
'test'
}),
content_type
=
'application/json'
)
response_status_code
=
response
.
status_code
response
=
json
.
loads
(
response
.
content
)
self
.
assertEqual
(
response_status_code
,
status
.
HTTP_401_UNAUTHORIZED
)
@data
(
{},
{
'provider'
:
'unsupported-provider'
},
{
'org'
:
'test'
,
'api_key'
:
'test-api-key'
}
)
def
test_transcript_credentials_invalid_provider
(
self
,
post_data
):
"""
Test that post crednetials gives proper error in case of invalid provider.
"""
# Verify that transcript credentials are not present for this org and provider.
provider
=
post_data
.
get
(
'provider'
)
response
=
self
.
client
.
post
(
self
.
url
,
data
=
json
.
dumps
(
post_data
),
content_type
=
'application/json'
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_400_BAD_REQUEST
)
response
=
json
.
loads
(
response
.
content
)
self
.
assertEqual
(
response
[
'message'
],
'Invalid provider {provider}.'
.
format
(
provider
=
provider
))
@data
(
(
{
'provider'
:
TranscriptProvider
.
CIELO24
},
'org and api_key and username'
),
(
{
'provider'
:
TranscriptProvider
.
THREE_PLAY
},
'org and api_key and api_secret_key'
),
(
{
'provider'
:
TranscriptProvider
.
CIELO24
,
'org'
:
'test-org'
},
'api_key and username'
),
(
{
'provider'
:
TranscriptProvider
.
CIELO24
,
'org'
:
'test-org'
,
'api_key'
:
'test-api-key'
},
'username'
),
(
{
'org'
:
'test'
,
'provider'
:
TranscriptProvider
.
THREE_PLAY
,
'api_key'
:
'test-api-key'
},
'api_secret_key'
)
)
@unpack
def
test_transcript_credentials_error
(
self
,
post_data
,
missing_keys
):
"""
Test that post credentials gives proper error in case of invalid input.
"""
provider
=
post_data
.
get
(
'provider'
)
error_message
=
'{missing} must be specified for {provider}.'
.
format
(
provider
=
provider
,
missing
=
missing_keys
)
response
=
self
.
client
.
post
(
self
.
url
,
data
=
json
.
dumps
(
post_data
),
content_type
=
'application/json'
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_400_BAD_REQUEST
)
response
=
json
.
loads
(
response
.
content
)
self
.
assertEqual
(
response
[
'message'
],
error_message
)
@data
(
{
'org'
:
'test'
,
'provider'
:
TranscriptProvider
.
CIELO24
,
'api_key'
:
'test-api-key'
,
'username'
:
'test-cielo-user'
},
{
'org'
:
'test'
,
'provider'
:
TranscriptProvider
.
THREE_PLAY
,
'api_key'
:
'test-api-key'
,
'api_secret_key'
:
'test-secret-key'
}
)
@responses.activate
def
test_transcript_credentials_success
(
self
,
post_data
):
"""
Test that post credentials works as expected.
"""
# Mock get_cielo_token_mock to return token
responses
.
add
(
responses
.
GET
,
CIELO24_LOGIN_URL
,
body
=
'{"ApiToken": "cielo-api-token"}'
,
status
=
status
.
HTTP_200_OK
)
# Verify that transcript credentials are not present for this org and provider.
transcript_credentials
=
TranscriptCredentials
.
objects
.
filter
(
org
=
post_data
.
get
(
'org'
),
provider
=
post_data
.
get
(
'provider'
)
)
self
.
assertFalse
(
transcript_credentials
.
exists
())
response
=
self
.
client
.
post
(
self
.
url
,
data
=
json
.
dumps
(
post_data
),
content_type
=
'application/json'
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_201_CREATED
)
transcript_credentials
=
TranscriptCredentials
.
objects
.
filter
(
org
=
post_data
.
get
(
'org'
),
provider
=
post_data
.
get
(
'provider'
)
)
self
.
assertTrue
(
transcript_credentials
.
exists
())
@patch
(
'VEDA_OS01.views.LOGGER'
)
@responses.activate
def
test_cielo24_error
(
self
,
mock_logger
):
"""
Test that when invalid cielo credentials are supplied, we get correct response.
"""
# Mock get_cielo_token_response.
error_message
=
'Invalid credentials supplied.'
responses
.
add
(
responses
.
GET
,
CIELO24_LOGIN_URL
,
body
=
json
.
dumps
({
'error'
:
error_message
}),
status
=
status
.
HTTP_400_BAD_REQUEST
)
post_data
=
{
'org'
:
'test'
,
'provider'
:
TranscriptProvider
.
CIELO24
,
'api_key'
:
'test-api-key'
,
'username'
:
'test-cielo-user'
,
'api_secret_key'
:
''
}
response
=
self
.
client
.
post
(
self
.
url
,
data
=
json
.
dumps
(
post_data
),
content_type
=
'application/json'
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_400_BAD_REQUEST
)
response
=
json
.
loads
(
response
.
content
)
self
.
assertEqual
(
response
[
'message'
],
error_message
)
mock_logger
.
warning
.
assert_called_with
(
'[Transcript Credentials] Unable to get api token -- response
%
s -- status
%
s.'
,
json
.
dumps
({
'error'
:
error_message
}),
status
.
HTTP_400_BAD_REQUEST
)
VEDA_OS01/transcripts.py
View file @
77964646
...
...
@@ -39,6 +39,9 @@ CIELO24_TRANSCRIPT_COMPLETED = django.dispatch.Signal(providing_args=[
])
CONFIG
=
get_config
()
# Cielo24 API version
CIELO24_API_VERSION
=
1
# Cielo24 API URLs
CIELO24_GET_CAPTION_URL
=
build_url
(
CONFIG
[
'cielo24_api_base_url'
],
...
...
@@ -210,7 +213,7 @@ def cielo24_transcript_callback(sender, **kwargs):
try
:
srt_data
=
fetch_srt_data
(
CIELO24_GET_CAPTION_URL
,
v
=
1
,
v
=
CIELO24_API_VERSION
,
job_id
=
job_id
,
api_token
=
api_key
,
caption_format
=
'SRT'
...
...
VEDA_OS01/views.py
View file @
77964646
"""views"""
import
json
import
logging
import
requests
from
django.http
import
HttpResponse
from
django.http
import
HttpResponseRedirect
from
django.views.decorators.csrf
import
csrf_exempt
from
rest_framework
import
renderers
from
rest_framework
import
viewsets
from
rest_framework
import
filters
,
renderers
,
status
,
viewsets
from
rest_framework.decorators
import
detail_route
from
rest_framework
import
filters
from
rest_framework.response
import
Response
from
rest_framework.views
import
APIView
from
api
import
token_finisher
from
VEDA_OS01.models
import
Course
,
Video
,
URL
,
Encode
from
VEDA_OS01.serializers
import
CourseSerializer
from
VEDA_OS01.serializers
import
VideoSerializer
from
VEDA_OS01.serializers
import
EncodeSerializer
from
VEDA_OS01.serializers
import
URLSerializer
from
VEDA
import
utils
from
VEDA_OS01.models
import
Course
,
Video
,
URL
,
Encode
,
TranscriptCredentials
,
TranscriptProvider
from
VEDA_OS01.serializers
import
CourseSerializer
,
EncodeSerializer
,
VideoSerializer
,
URLSerializer
from
VEDA_OS01.transcripts
import
CIELO24_API_VERSION
LOGGER
=
logging
.
getLogger
(
__name__
)
CONFIG
=
utils
.
get_config
()
CIELO24_LOGIN_URL
=
utils
.
build_url
(
CONFIG
[
'cielo24_api_base_url'
],
'/account/login'
)
class
CourseViewSet
(
viewsets
.
ModelViewSet
):
queryset
=
Course
.
objects
.
all
()
...
...
@@ -96,6 +108,156 @@ class URLViewSet(viewsets.ModelViewSet):
serializer
.
save
()
class
TranscriptCredentialsView
(
APIView
):
"""
A Transcript credentials View, used by platform to create/update transcript credentials.
"""
def
get_cielo_token_response
(
self
,
username
,
api_secure_key
):
"""
Returns Cielo24 api token.
Arguments:
username(str): Cielo24 username
api_securekey(str): Cielo24 api key
Returns:
Response : Http response object
"""
return
requests
.
get
(
CIELO24_LOGIN_URL
,
params
=
{
'v'
:
CIELO24_API_VERSION
,
'username'
:
username
,
'securekey'
:
api_secure_key
})
def
get_api_token
(
self
,
username
,
api_key
):
"""
Returns api token if valid credentials are provided.
"""
response
=
self
.
get_cielo_token_response
(
username
=
username
,
api_secure_key
=
api_key
)
if
not
response
.
ok
:
api_token
=
None
LOGGER
.
warning
(
'[Transcript Credentials] Unable to get api token -- response
%
s -- status
%
s.'
,
response
.
text
,
response
.
status_code
,
)
else
:
api_token
=
json
.
loads
(
response
.
content
)[
'ApiToken'
]
return
api_token
def
validate_missing_attributes
(
self
,
provider
,
attributes
,
credentials
):
"""
Returns error message if provided attributes are not presents in credentials.
"""
error_message
=
None
missing
=
[
attr
for
attr
in
attributes
if
attr
not
in
credentials
]
if
missing
:
error_message
=
u'{missing} must be specified for {provider}.'
.
format
(
provider
=
provider
,
missing
=
' and '
.
join
(
missing
)
)
return
error_message
def
validate_transcript_credentials
(
self
,
provider
,
**
credentials
):
"""
Validates transcript credentials.
Validations:
Providers must be either 3PlayMedia or Cielo24.
In case of:
3PlayMedia - 'api_key' and 'api_secret_key' are required.
Cielo24 - Valid 'api_key' and 'username' are required.
"""
error_message
,
validated_credentials
=
''
,
{}
if
provider
in
[
TranscriptProvider
.
CIELO24
,
TranscriptProvider
.
THREE_PLAY
]:
if
provider
==
TranscriptProvider
.
CIELO24
:
must_have_props
=
(
'org'
,
'api_key'
,
'username'
)
error_message
=
self
.
validate_missing_attributes
(
provider
,
must_have_props
,
credentials
)
if
not
error_message
:
# Get cielo api token and store it in api_key.
api_token
=
self
.
get_api_token
(
credentials
[
'username'
],
credentials
[
'api_key'
])
if
api_token
:
validated_credentials
.
update
({
'org'
:
credentials
[
'org'
],
'api_key'
:
api_token
})
else
:
error_message
=
u'Invalid credentials supplied.'
else
:
must_have_props
=
(
'org'
,
'api_key'
,
'api_secret_key'
)
error_message
=
self
.
validate_missing_attributes
(
provider
,
must_have_props
,
credentials
)
if
not
error_message
:
validated_credentials
.
update
({
'org'
:
credentials
[
'org'
],
'api_key'
:
credentials
[
'api_key'
],
'api_secret'
:
credentials
[
'api_secret_key'
]
})
else
:
error_message
=
u'Invalid provider {provider}.'
.
format
(
provider
=
provider
)
return
error_message
,
validated_credentials
def
post
(
self
,
request
):
"""
Creates or updates the org-specific transcript credentials with the given information.
Arguments:
request: A WSGI request.
**Example Request**
POST /api/transcript_credentials {
"provider": "3PlayMedia",
"org": "test.x",
"api_key": "test-api-key",
"api_secret_key": "test-api-secret-key"
}
**POST Parameters**
A POST request can include the following parameters.
* provider: A string representation of provider.
* org: A string representing the organizaton code.
* api_key: A string representing the provider api key.
* api_secret_key: (Required for 3Play only). A string representing the api secret key.
* username: (Required for Cielo only). A string representing the cielo username.
**Example POST Response**
In case of success:
Returns an empty response with 201 status code (HTTP 201 Created).
In case of error:
Return response with error message and 400 status code (HTTP 400 Bad Request).
{
"message": "Error message."
}
"""
# Validate credentials
provider
=
request
.
data
.
pop
(
'provider'
,
None
)
error_message
,
validated_credentials
=
self
.
validate_transcript_credentials
(
provider
=
provider
,
**
request
.
data
)
if
error_message
:
return
Response
(
status
=
status
.
HTTP_400_BAD_REQUEST
,
data
=
dict
(
message
=
error_message
)
)
TranscriptCredentials
.
objects
.
update_or_create
(
org
=
validated_credentials
.
pop
(
'org'
),
provider
=
provider
,
defaults
=
validated_credentials
)
return
Response
(
status
=
status
.
HTTP_201_CREATED
)
@csrf_exempt
def
token_auth
(
request
):
"""
...
...
control/tests/test_deliver_cielo.py
View file @
77964646
...
...
@@ -12,6 +12,7 @@ from VEDA_OS01.models import (Cielo24Fidelity, Cielo24Turnaround, Course,
TranscriptProcessMetadata
,
TranscriptStatus
,
Video
)
from
VEDA.utils
import
build_url
from
VEDA_OS01.transcripts
import
CIELO24_API_VERSION
VIDEO_DATA
=
{
'studio_id'
:
'12345'
,
...
...
@@ -120,7 +121,7 @@ class Cielo24TranscriptTests(TestCase):
{
'url'
:
build_url
(
'https://sandbox.cielo24.com/api/job/new'
,
v
=
1
,
v
=
CIELO24_API_VERSION
,
job_name
=
'12345'
,
language
=
'en'
,
# A job's language.
api_token
=
'cielo24_api_key'
,
...
...
@@ -131,7 +132,7 @@ class Cielo24TranscriptTests(TestCase):
{
'url'
:
build_url
(
'https://sandbox.cielo24.com/api/job/add_media'
,
v
=
1
,
v
=
CIELO24_API_VERSION
,
job_id
=
'000-111-222'
,
api_token
=
'cielo24_api_key'
,
media_url
=
'https://s3.amazonaws.com/bkt/video.mp4'
,
...
...
@@ -142,7 +143,7 @@ class Cielo24TranscriptTests(TestCase):
{
'url'
:
build_url
(
'https://sandbox.cielo24.com/api/job/perform_transcription'
,
v
=
1
,
v
=
CIELO24_API_VERSION
,
job_id
=
'000-111-222'
,
target_language
=
'TARGET_LANG'
,
callback_url
=
build_url
(
...
...
control/veda_deliver_cielo.py
View file @
77964646
...
...
@@ -11,6 +11,7 @@ from requests.packages.urllib3.exceptions import InsecurePlatformWarning
from
VEDA_OS01.models
import
(
TranscriptProcessMetadata
,
TranscriptProvider
,
TranscriptStatus
)
from
VEDA.utils
import
build_url
from
VEDA_OS01.transcripts
import
CIELO24_API_VERSION
requests
.
packages
.
urllib3
.
disable_warnings
(
InsecurePlatformWarning
)
...
...
@@ -129,7 +130,7 @@ class Cielo24Transcript(object):
build_url
(
self
.
cielo24_api_base_url
,
self
.
cielo24_perform_transcription
,
v
=
1
,
v
=
CIELO24_API_VERSION
,
job_id
=
job_id
,
target_language
=
lang_code
,
callback_url
=
callback_url
,
...
...
@@ -171,7 +172,7 @@ class Cielo24Transcript(object):
build_url
(
self
.
cielo24_api_base_url
,
self
.
cielo24_add_media
,
v
=
1
,
v
=
CIELO24_API_VERSION
,
job_id
=
job_id
,
api_token
=
self
.
api_key
,
media_url
=
self
.
s3_video_url
...
...
@@ -205,7 +206,7 @@ class Cielo24Transcript(object):
create_job_url
=
build_url
(
self
.
cielo24_api_base_url
,
self
.
cielo24_new_job
,
v
=
1
,
v
=
CIELO24_API_VERSION
,
language
=
self
.
video
.
source_language
,
api_token
=
self
.
api_key
,
job_name
=
self
.
video
.
studio_id
...
...
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