Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
ecommerce
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
ecommerce
Commits
0409a481
Commit
0409a481
authored
Aug 11, 2015
by
Renzo Lucioni
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #269 from edx/renzo/remove-slugs
Eliminate use of product slugs as unique selectors
parents
13a121cc
a5c0a717
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
42 additions
and
26 deletions
+42
-26
ecommerce/courses/models.py
+25
-26
ecommerce/courses/tests/test_models.py
+17
-0
No files found.
ecommerce/courses/models.py
View file @
0409a481
...
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
...
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
import
logging
import
logging
from
django.db
import
models
,
transaction
from
django.db
import
models
,
transaction
from
django.
utils.text
import
slugify
from
django.
db.models
import
Q
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
oscar.core.loading
import
get_model
from
oscar.core.loading
import
get_model
from
simple_history.models
import
HistoricalRecords
from
simple_history.models
import
HistoricalRecords
...
@@ -35,15 +35,14 @@ class Course(models.Model):
...
@@ -35,15 +35,14 @@ class Course(models.Model):
def
_create_parent_seat
(
self
):
def
_create_parent_seat
(
self
):
""" Create the parent seat product if it does not already exist. """
""" Create the parent seat product if it does not already exist. """
slug
=
'parent-cs-{}'
.
format
(
slugify
(
unicode
(
self
.
id
)))
parent
,
created
=
self
.
products
.
get_or_create
(
defaults
=
{
course
=
self
,
'is_discountable'
:
True
,
structure
=
Product
.
PARENT
,
'structure'
:
Product
.
PARENT
,
product_class
=
ProductClass
.
objects
.
get
(
slug
=
'seat'
),
'product_class'
:
ProductClass
.
objects
.
get
(
slug
=
'seat'
)
)
}
parent
,
created
=
self
.
products
.
get_or_create
(
slug
=
slug
,
defaults
=
defaults
)
ProductCategory
.
objects
.
get_or_create
(
category
=
Category
.
objects
.
get
(
name
=
'Seats'
),
product
=
parent
)
ProductCategory
.
objects
.
get_or_create
(
category
=
Category
.
objects
.
get
(
name
=
'Seats'
),
product
=
parent
)
parent
.
title
=
'Seat in {}'
.
format
(
self
.
name
)
parent
.
title
=
'Seat in {}'
.
format
(
self
.
name
)
parent
.
is_discountable
=
True
parent
.
attr
.
course_key
=
self
.
id
parent
.
attr
.
course_key
=
self
.
id
parent
.
save
()
parent
.
save
()
...
@@ -98,8 +97,8 @@ class Course(models.Model):
...
@@ -98,8 +97,8 @@ class Course(models.Model):
@property
@property
def
seat_products
(
self
):
def
seat_products
(
self
):
""" Returns a
lis
t of course seat Products related to this course. """
""" Returns a
queryse
t of course seat Products related to this course. """
return
list
(
self
.
parent_seat_product
.
children
.
all
()
.
prefetch_related
(
'stockrecords'
)
)
return
self
.
parent_seat_product
.
children
.
all
()
.
prefetch_related
(
'stockrecords'
)
def
_get_course_seat_name
(
self
,
certificate_type
,
id_verification_required
):
def
_get_course_seat_name
(
self
,
certificate_type
,
id_verification_required
):
""" Returns the name for a course seat. """
""" Returns the name for a course seat. """
...
@@ -124,22 +123,23 @@ class Course(models.Model):
...
@@ -124,22 +123,23 @@ class Course(models.Model):
certificate_type
=
certificate_type
.
lower
()
certificate_type
=
certificate_type
.
lower
()
course_id
=
unicode
(
self
.
id
)
course_id
=
unicode
(
self
.
id
)
slugs
=
[]
if
certificate_type
==
self
.
certificate_type_for_mode
(
'audit'
):
slug
=
'child-cs-{}-{}'
.
format
(
certificate_type
,
slugify
(
course_id
))
# Yields a match if attribute names do not include 'certificate_type'.
certificate_type_query
=
~
Q
(
attributes__name
=
'certificate_type'
)
# Note (CCB): Our previous method of slug generation did not account for ID verification. By using a list
else
:
# we can update these seats. This should be removed after the courses have been re-migrated.
# Yields a match if attribute with name 'certificate_type' matches provided value.
if
certificate_type
==
'verified'
:
certificate_type_query
=
Q
(
slugs
.
append
(
slug
)
attributes__name
=
'certificate_type'
,
attribute_values__value_text
=
certificate_type
)
i
f
id_verification_required
:
i
d_verification_required_query
=
Q
(
slug
+=
'-id-verified'
attributes__name
=
'id_verification_required'
,
slugs
.
append
(
slug
)
attribute_values__value_boolean
=
id_verification_required
slugs
=
set
(
slugs
)
)
try
:
try
:
seat
=
Product
.
objects
.
get
(
slug__in
=
slugs
)
seat
=
self
.
seat_products
.
filter
(
certificate_type_query
)
.
get
(
id_verification_required_query
)
seat
.
slug
=
slug
logger
.
info
(
logger
.
info
(
'Retrieved course seat child product with certificate type [
%
s] for [
%
s] from database.'
,
'Retrieved course seat child product with certificate type [
%
s] for [
%
s] from database.'
,
...
@@ -147,7 +147,7 @@ class Course(models.Model):
...
@@ -147,7 +147,7 @@ class Course(models.Model):
course_id
course_id
)
)
except
Product
.
DoesNotExist
:
except
Product
.
DoesNotExist
:
seat
=
Product
(
slug
=
slug
)
seat
=
Product
()
logger
.
info
(
logger
.
info
(
'Course seat product with certificate type [
%
s] for [
%
s] does not exist. Instantiated a new instance.'
,
'Course seat product with certificate type [
%
s] for [
%
s] does not exist. Instantiated a new instance.'
,
certificate_type
,
certificate_type
,
...
@@ -155,16 +155,15 @@ class Course(models.Model):
...
@@ -155,16 +155,15 @@ class Course(models.Model):
)
)
seat
.
course
=
self
seat
.
course
=
self
seat
.
structure
=
Product
.
CHILD
seat
.
parent
=
self
.
parent_seat_product
seat
.
parent
=
self
.
parent_seat_product
seat
.
is_discountable
=
True
seat
.
is_discountable
=
True
seat
.
structure
=
Product
.
CHILD
seat
.
title
=
self
.
_get_course_seat_name
(
certificate_type
,
id_verification_required
)
seat
.
title
=
self
.
_get_course_seat_name
(
certificate_type
,
id_verification_required
)
seat
.
expires
=
expires
seat
.
expires
=
expires
# If a ProductAttribute is saved with a value of None or the empty string, the ProductAttribute is deleted.
# If a ProductAttribute is saved with a value of None or the empty string, the ProductAttribute is deleted.
# As a consequence, Seats derived from a migrated "audit" mode do not have a certificate_type attribute.
# As a consequence, Seats derived from a migrated "audit" mode do not have a certificate_type attribute.
seat
.
attr
.
certificate_type
=
certificate_type
seat
.
attr
.
certificate_type
=
certificate_type
seat
.
attr
.
course_key
=
course_id
seat
.
attr
.
course_key
=
course_id
seat
.
attr
.
id_verification_required
=
id_verification_required
seat
.
attr
.
id_verification_required
=
id_verification_required
...
...
ecommerce/courses/tests/test_models.py
View file @
0409a481
...
@@ -133,6 +133,23 @@ class CourseTests(CourseCatalogTestMixin, TestCase):
...
@@ -133,6 +133,23 @@ class CourseTests(CourseCatalogTestMixin, TestCase):
seat
,
course
,
certificate_type
,
id_verification_required
,
price
,
credit_provider
,
credit_hours
=
credit_hours
seat
,
course
,
certificate_type
,
id_verification_required
,
price
,
credit_provider
,
credit_hours
=
credit_hours
)
)
def
test_collision_avoidance
(
self
):
"""
Sanity check verifying that course IDs which produced collisions due to a
lossy slug generation process no longer do so.
"""
dotted_course
=
Course
.
objects
.
create
(
id
=
'a/...course.../id'
)
regular_course
=
Course
.
objects
.
create
(
id
=
'a/course/id'
)
certificate_type
=
'honor'
id_verification_required
=
False
price
=
0
dotted_course
.
create_or_update_seat
(
certificate_type
,
id_verification_required
,
price
)
regular_course
.
create_or_update_seat
(
certificate_type
,
id_verification_required
,
price
)
child_products
=
Product
.
objects
.
filter
(
structure
=
Product
.
CHILD
)
.
count
()
self
.
assertEqual
(
child_products
,
2
)
def
test_type
(
self
):
def
test_type
(
self
):
""" Verify the property returns a type value corresponding to the available products. """
""" Verify the property returns a type value corresponding to the available products. """
course
=
Course
.
objects
.
create
(
id
=
'a/b/c'
,
name
=
'Test Course'
)
course
=
Course
.
objects
.
create
(
id
=
'a/b/c'
,
name
=
'Test Course'
)
...
...
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