Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
course-discovery
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
course-discovery
Commits
9f0899a3
Commit
9f0899a3
authored
Oct 06, 2017
by
christopher lee
Committed by
Christopher Lee
Oct 17, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Clean up Subject and SubjectTranslation models
parent
0a0d285b
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
120 additions
and
54 deletions
+120
-54
.travis/docker.mk
+1
-1
course_discovery/apps/api/serializers.py
+0
-3
course_discovery/apps/api/tests/test_serializers.py
+3
-3
course_discovery/apps/course_metadata/admin.py
+3
-4
course_discovery/apps/course_metadata/data_loaders/marketing_site.py
+3
-3
course_discovery/apps/course_metadata/data_loaders/tests/test_marketing_site.py
+8
-8
course_discovery/apps/course_metadata/migrations/0061_migrate_subjects_data.py
+1
-2
course_discovery/apps/course_metadata/migrations/0063_auto_20171005_1931.py
+63
-0
course_discovery/apps/course_metadata/models.py
+8
-9
course_discovery/apps/course_metadata/tests/factories.py
+2
-2
course_discovery/apps/course_metadata/tests/test_models.py
+12
-14
course_discovery/apps/publisher/forms.py
+1
-1
course_discovery/conf/locale/en/LC_MESSAGES/django.mo
+0
-0
course_discovery/conf/locale/en/LC_MESSAGES/django.po
+1
-1
course_discovery/conf/locale/en/LC_MESSAGES/djangojs.mo
+0
-0
course_discovery/conf/locale/en/LC_MESSAGES/djangojs.po
+1
-1
course_discovery/conf/locale/eo/LC_MESSAGES/django.mo
+0
-0
course_discovery/conf/locale/eo/LC_MESSAGES/django.po
+1
-1
course_discovery/conf/locale/eo/LC_MESSAGES/djangojs.mo
+0
-0
course_discovery/conf/locale/eo/LC_MESSAGES/djangojs.po
+1
-1
course_discovery/settings/devstack.py
+11
-0
No files found.
.travis/docker.mk
View file @
9f0899a3
...
...
@@ -7,7 +7,7 @@ travis_start: ## Start containers stopped by `travis_stop`
docker-compose
-f
.travis/docker-compose-travis.yml start
travis_test
:
##
Run tests on Docker containers
,
as on Travis CI
docker
exec
-it
course-
discovery env
TERM
=
$(TERM)
/edx/app/discovery/discovery/.travis/run_tests.sh
docker
exec
-it
discovery env
TERM
=
$(TERM)
/edx/app/discovery/discovery/.travis/run_tests.sh
travis_stop
:
##
Stop running containers created by `travis_up` without removing them
docker-compose
-f
.travis/docker-compose-travis.yml stop
...
...
course_discovery/apps/api/serializers.py
View file @
9f0899a3
...
...
@@ -191,9 +191,6 @@ class FAQSerializer(serializers.ModelSerializer):
class
SubjectSerializer
(
serializers
.
ModelSerializer
):
"""Serializer for the ``Subject`` model."""
name
=
serializers
.
CharField
(
source
=
'name_t'
)
subtitle
=
serializers
.
CharField
(
source
=
'subtitle_t'
)
description
=
serializers
.
CharField
(
source
=
'description_t'
)
@classmethod
def
prefetch_queryset
(
cls
):
...
...
course_discovery/apps/api/tests/test_serializers.py
View file @
9f0899a3
...
...
@@ -963,11 +963,11 @@ class SubjectSerializerTests(TestCase):
serializer
=
SubjectSerializer
(
subject
)
expected
=
{
'name'
:
subject
.
name
_t
,
'description'
:
subject
.
description
_t
,
'name'
:
subject
.
name
,
'description'
:
subject
.
description
,
'banner_image_url'
:
subject
.
banner_image_url
,
'card_image_url'
:
subject
.
card_image_url
,
'subtitle'
:
subject
.
subtitle
_t
,
'subtitle'
:
subject
.
subtitle
,
'slug'
:
subject
.
slug
,
'uuid'
:
str
(
subject
.
uuid
),
}
...
...
course_discovery/apps/course_metadata/admin.py
View file @
9f0899a3
...
...
@@ -224,12 +224,11 @@ class OrganizationAdmin(admin.ModelAdmin):
@admin.register
(
Subject
)
class
SubjectAdmin
(
TranslatableAdmin
):
# These fields are excluded here because they will be removed in favor of the translated fields.
exclude
=
(
'name'
,
'subtitle'
,
'description'
)
list_display
=
(
'uuid'
,
'name_t'
,
'slug'
,)
exclude
=
(
'name_t'
,
'subtitle_t'
,
'description_t'
)
# TODO Remove in the clean up phase LEARNER-2617
list_display
=
(
'uuid'
,
'name'
,
'slug'
,)
list_filter
=
(
'partner'
,)
readonly_fields
=
(
'uuid'
,)
search_fields
=
(
'uuid'
,
'name
_t
'
,
'slug'
,)
search_fields
=
(
'uuid'
,
'name'
,
'slug'
,)
@admin.register
(
Person
)
...
...
course_discovery/apps/course_metadata/data_loaders/marketing_site.py
View file @
9f0899a3
...
...
@@ -143,9 +143,9 @@ class SubjectMarketingSiteDataLoader(AbstractMarketingSiteDataLoader):
slug
=
data
[
'field_subject_url_slug'
]
defaults
=
{
'uuid'
:
data
[
'uuid'
],
'name
_t
'
:
data
[
'title'
],
'description
_t
'
:
self
.
clean_html
(
data
[
'body'
][
'value'
]),
'subtitle
_t
'
:
self
.
clean_html
(
data
[
'field_subject_subtitle'
][
'value'
]),
'name'
:
data
[
'title'
],
'description'
:
self
.
clean_html
(
data
[
'body'
][
'value'
]),
'subtitle'
:
self
.
clean_html
(
data
[
'field_subject_subtitle'
][
'value'
]),
'card_image_url'
:
self
.
_get_nested_url
(
data
.
get
(
'field_subject_card_image'
)),
# NOTE (CCB): This is not a typo. Yes, the banner image for subjects is in a field with xseries in the name.
'banner_image_url'
:
self
.
_get_nested_url
(
data
.
get
(
'field_xseries_banner_image'
))
...
...
course_discovery/apps/course_metadata/data_loaders/tests/test_marketing_site.py
View file @
9f0899a3
...
...
@@ -146,9 +146,9 @@ class SubjectMarketingSiteDataLoaderTests(AbstractMarketingSiteDataLoaderTestMix
subject
=
Subject
.
objects
.
get
(
slug
=
slug
,
partner
=
self
.
partner
)
expected_values
=
{
'uuid'
:
UUID
(
data
[
'uuid'
]),
'name
_t
'
:
data
[
'title'
],
'description
_t
'
:
self
.
loader
.
clean_html
(
data
[
'body'
][
'value'
]),
'subtitle
_t
'
:
self
.
loader
.
clean_html
(
data
[
'field_subject_subtitle'
][
'value'
]),
'name'
:
data
[
'title'
],
'description'
:
self
.
loader
.
clean_html
(
data
[
'body'
][
'value'
]),
'subtitle'
:
self
.
loader
.
clean_html
(
data
[
'field_subject_subtitle'
][
'value'
]),
'card_image_url'
:
data
[
'field_subject_card_image'
][
'url'
],
'banner_image_url'
:
data
[
'field_xseries_banner_image'
][
'url'
],
}
...
...
@@ -157,7 +157,7 @@ class SubjectMarketingSiteDataLoaderTests(AbstractMarketingSiteDataLoaderTestMix
self
.
assertEqual
(
getattr
(
subject
,
field
),
value
)
@responses.activate
def
test_ingest
(
self
):
def
test_ingest
_create
(
self
):
self
.
mock_login_response
()
api_data
=
self
.
mock_api
()
...
...
@@ -167,15 +167,15 @@ class SubjectMarketingSiteDataLoaderTests(AbstractMarketingSiteDataLoaderTestMix
self
.
assert_subject_loaded
(
datum
)
@responses.activate
def
test_ingest
2
(
self
):
def
test_ingest
_update
(
self
):
self
.
mock_login_response
()
api_data
=
self
.
mock_api
()
for
data
in
api_data
:
subject_data
=
{
'uuid'
:
UUID
(
data
[
'uuid'
]),
'name
_t
'
:
data
[
'title'
],
'description
_t
'
:
self
.
loader
.
clean_html
(
data
[
'body'
][
'value'
]),
'subtitle
_t
'
:
self
.
loader
.
clean_html
(
data
[
'field_subject_subtitle'
][
'value'
]),
'name'
:
data
[
'title'
],
'description'
:
self
.
loader
.
clean_html
(
data
[
'body'
][
'value'
]),
'subtitle'
:
self
.
loader
.
clean_html
(
data
[
'field_subject_subtitle'
][
'value'
]),
'card_image_url'
:
data
[
'field_subject_card_image'
][
'url'
],
'banner_image_url'
:
data
[
'field_xseries_banner_image'
][
'url'
],
}
...
...
course_discovery/apps/course_metadata/migrations/0061_migrate_subjects_data.py
View file @
9f0899a3
...
...
@@ -31,7 +31,7 @@ def backwards_func(apps, schema_editor):
for
subject
in
Subject
.
objects
.
all
():
try
:
translation
=
SubjectTranslation
.
objects
.
filter
(
master_id
=
subject
.
pk
)
translation
=
SubjectTranslation
.
objects
.
get
(
master_id
=
subject
.
pk
,
language_code
=
settings
.
LANGUAGE_CODE
)
subject
.
name
=
translation
.
name_t
subject
.
subtitle
=
translation
.
subtitle_t
subject
.
description
=
translation
.
description_t
...
...
@@ -40,7 +40,6 @@ def backwards_func(apps, schema_editor):
# nothing to migrate
logger
.
exception
(
'Migrating data from SubjectTranslation for master_id={} DoesNotExist'
.
format
(
subject
.
pk
))
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'course_metadata'
,
'0060_create_subjecttranslations_models'
),
...
...
course_discovery/apps/course_metadata/migrations/0063_auto_20171005_1931.py
0 → 100644
View file @
9f0899a3
# -*- coding: utf-8 -*-
# Generated by Django 1.11.3 on 2017-10-05 19:31
from
__future__
import
unicode_literals
import
django_extensions.db.fields
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'course_metadata'
,
'0062_courserun_license'
),
]
operations
=
[
migrations
.
RemoveField
(
model_name
=
'subject'
,
name
=
'description'
,
),
migrations
.
RemoveField
(
model_name
=
'subject'
,
name
=
'name'
,
),
migrations
.
RemoveField
(
model_name
=
'subject'
,
name
=
'subtitle'
,
),
migrations
.
AddField
(
model_name
=
'subjecttranslation'
,
name
=
'description'
,
field
=
models
.
TextField
(
blank
=
True
,
null
=
True
),
),
migrations
.
AddField
(
model_name
=
'subjecttranslation'
,
name
=
'name'
,
field
=
models
.
CharField
(
blank
=
True
,
max_length
=
255
),
),
migrations
.
AddField
(
model_name
=
'subjecttranslation'
,
name
=
'subtitle'
,
field
=
models
.
CharField
(
blank
=
True
,
max_length
=
255
,
null
=
True
),
),
migrations
.
AlterField
(
model_name
=
'subject'
,
name
=
'slug'
,
field
=
django_extensions
.
db
.
fields
.
AutoSlugField
(
blank
=
True
,
editable
=
False
,
help_text
=
'Leave this field blank to have the value generated automatically.'
,
populate_from
=
'name'
),
),
migrations
.
RunSQL
(
[
"UPDATE course_metadata_subjecttranslation SET name = name_t"
,
"UPDATE course_metadata_subjecttranslation SET description = description_t"
,
"UPDATE course_metadata_subjecttranslation SET subtitle = subtitle_t"
],
[
"UPDATE course_metadata_subjecttranslation SET name_t = name"
,
"UPDATE course_metadata_subjecttranslation SET description_t = description"
,
"UPDATE course_metadata_subjecttranslation SET subtitle_t = subtitle"
],
),
migrations
.
AlterField
(
model_name
=
'subjecttranslation'
,
name
=
'name'
,
field
=
models
.
CharField
(
max_length
=
255
),
),
]
course_discovery/apps/course_metadata/models.py
View file @
9f0899a3
...
...
@@ -116,13 +116,11 @@ class LevelType(AbstractNamedModel):
class
Subject
(
TranslatableModel
,
TimeStampedModel
):
""" Subject model. """
uuid
=
models
.
UUIDField
(
blank
=
False
,
null
=
False
,
default
=
uuid4
,
editable
=
False
,
verbose_name
=
_
(
'UUID'
))
name
=
models
.
CharField
(
max_length
=
255
,
blank
=
False
,
null
=
False
)
subtitle
=
models
.
CharField
(
max_length
=
255
,
blank
=
True
,
null
=
True
)
description
=
models
.
TextField
(
blank
=
True
,
null
=
True
)
banner_image_url
=
models
.
URLField
(
blank
=
True
,
null
=
True
)
card_image_url
=
models
.
URLField
(
blank
=
True
,
null
=
True
)
slug
=
AutoSlugField
(
populate_from
=
'name
_t
'
,
editable
=
True
,
blank
=
True
,
slug
=
AutoSlugField
(
populate_from
=
'name'
,
editable
=
True
,
blank
=
True
,
help_text
=
_
(
'Leave this field blank to have the value generated automatically.'
))
partner
=
models
.
ForeignKey
(
Partner
)
def
__str__
(
self
):
...
...
@@ -137,20 +135,21 @@ class Subject(TranslatableModel, TimeStampedModel):
def
validate_unique
(
self
,
*
args
,
**
kwargs
):
super
(
Subject
,
self
)
.
validate_unique
(
*
args
,
**
kwargs
)
qs
=
Subject
.
objects
.
filter
(
partner
=
self
.
partner_id
)
if
qs
.
filter
(
translations__name
_t
=
self
.
name_t
)
.
exists
():
raise
ValidationError
({
'name
_t
'
:
[
'Subject with this Name and Partner already exists'
,
]})
if
qs
.
filter
(
translations__name
=
self
.
name
)
.
exclude
(
pk
=
self
.
pk
)
.
exists
():
raise
ValidationError
({
'name'
:
[
'Subject with this Name and Partner already exists'
,
]})
class
SubjectTranslation
(
TranslatedFieldsModel
):
master
=
models
.
ForeignKey
(
Subject
,
related_name
=
'translations'
,
null
=
True
)
name
=
models
.
CharField
(
max_length
=
255
,
blank
=
False
,
null
=
False
)
subtitle
=
models
.
CharField
(
max_length
=
255
,
blank
=
True
,
null
=
True
)
description
=
models
.
TextField
(
blank
=
True
,
null
=
True
)
name_t
=
models
.
CharField
(
max_length
=
255
,
blank
=
False
,
null
=
False
)
subtitle_t
=
models
.
CharField
(
max_length
=
255
,
blank
=
True
,
null
=
True
)
description_t
=
models
.
TextField
(
blank
=
True
,
null
=
True
)
def
__str__
(
self
):
return
self
.
name_t
class
Meta
:
unique_together
=
(
'language_code'
,
'master'
)
verbose_name
=
_
(
'Subject model translations'
)
...
...
course_discovery/apps/course_metadata/tests/factories.py
View file @
9f0899a3
...
...
@@ -41,8 +41,8 @@ class SubjectFactory(factory.DjangoModelFactory):
class
Meta
:
model
=
Subject
name
_t
=
FuzzyText
()
# TODO Switch to 'name' when 'name_t' is renamed.
description
_t
=
FuzzyText
()
name
=
FuzzyText
()
description
=
FuzzyText
()
banner_image_url
=
FuzzyURL
()
card_image_url
=
FuzzyURL
()
partner
=
factory
.
SubFactory
(
PartnerFactory
)
...
...
course_discovery/apps/course_metadata/tests/test_models.py
View file @
9f0899a3
...
...
@@ -996,26 +996,24 @@ class FAQTests(TestCase):
class
SubjectTests
(
SiteMixin
,
TestCase
):
""" Tests of the Multilingual Subject model. """
""" Tests of the Multilingual Subject
(and SubjectTranslation)
model. """
def
test_partner_name_t_uniqueness
(
self
):
dummy_url
=
"http://www.example.com"
Subject
.
objects
.
create
(
def
test_validate_unique
(
self
):
subject
=
Subject
.
objects
.
create
(
name
=
"name1"
,
name_t
=
"aaa"
,
partner_id
=
self
.
partner
.
id
,
banner_image_url
=
dummy_url
,
card_image_url
=
dummy_url
)
banner_image_url
=
"http://www.example.com"
,
card_image_url
=
"http://www.example.com"
)
self
.
assertIsNone
(
subject
.
full_clean
())
invalid_subject
=
Subject
(
name
=
"name2"
,
name_t
=
"aaa"
,
duplicate_subject
=
Subject
(
name
=
"name1"
,
partner_id
=
self
.
partner
.
id
,
banner_image_url
=
dummy_url
,
card_image_url
=
dummy_url
)
banner_image_url
=
"http://www.example.com"
,
card_image_url
=
"http://www.example.com"
)
with
self
.
assertRaises
(
ValidationError
)
as
validation_error
:
invalid
_subject
.
full_clean
()
duplicate
_subject
.
full_clean
()
self
.
assertEqual
(
str
(
validation_error
.
exception
),
"{'name
_t
': ['Subject with this Name and Partner already exists']}"
)
"{'name': ['Subject with this Name and Partner already exists']}"
)
course_discovery/apps/publisher/forms.py
View file @
9f0899a3
...
...
@@ -103,7 +103,7 @@ class CourseForm(BaseForm):
label
=
_
(
'Organization Course Admin'
),
)
subjects
=
Subject
.
objects
.
all
()
.
order_by
(
'name'
)
subjects
=
Subject
.
objects
.
all
()
.
order_by
(
"translations__name"
)
primary_subject
=
forms
.
ModelChoiceField
(
queryset
=
subjects
,
label
=
_
(
'Primary'
),
...
...
course_discovery/conf/locale/en/LC_MESSAGES/django.mo
View file @
9f0899a3
No preview for this file type
course_discovery/conf/locale/en/LC_MESSAGES/django.po
View file @
9f0899a3
...
...
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-10-1
2 11:27+05
00\n"
"POT-Creation-Date: 2017-10-1
6 17:29+00
00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
...
...
course_discovery/conf/locale/en/LC_MESSAGES/djangojs.mo
View file @
9f0899a3
No preview for this file type
course_discovery/conf/locale/en/LC_MESSAGES/djangojs.po
View file @
9f0899a3
...
...
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-10-1
2 11:27+05
00\n"
"POT-Creation-Date: 2017-10-1
6 17:29+00
00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
...
...
course_discovery/conf/locale/eo/LC_MESSAGES/django.mo
View file @
9f0899a3
No preview for this file type
course_discovery/conf/locale/eo/LC_MESSAGES/django.po
View file @
9f0899a3
...
...
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-10-1
2 11:27+05
00\n"
"POT-Creation-Date: 2017-10-1
6 17:29+00
00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
...
...
course_discovery/conf/locale/eo/LC_MESSAGES/djangojs.mo
View file @
9f0899a3
No preview for this file type
course_discovery/conf/locale/eo/LC_MESSAGES/djangojs.po
View file @
9f0899a3
...
...
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-10-1
2 11:27+05
00\n"
"POT-Creation-Date: 2017-10-1
6 17:29+00
00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
...
...
course_discovery/settings/devstack.py
View file @
9f0899a3
...
...
@@ -22,6 +22,17 @@ DEFAULT_PARTNER_ID = 1
COMPRESS_OFFLINE
=
False
COMPRESS_ENABLED
=
False
PARLER_LANGUAGES
=
{
1
:
(
{
'code'
:
LANGUAGE_CODE
,
},
{
'code'
:
'es'
,
},
),
'default'
:
{
'fallbacks'
:
[
PARLER_DEFAULT_LANGUAGE_CODE
],
'hide_untranslated'
:
False
,
}
}
#####################################################################
# Lastly, see if the developer has any local overrides.
if
os
.
path
.
isfile
(
join
(
dirname
(
abspath
(
__file__
)),
'private.py'
)):
...
...
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