Skip to content

Commit ed0904f

Browse files
feat: Add Content Groups V2 JSON REST API
Implements a pure JSON REST API for fetching content group configurations, replacing the legacy HTML+JSON hybrid endpoint with a RESTful interface.
1 parent 2c53232 commit ed0904f

10 files changed

Lines changed: 881 additions & 24 deletions

File tree

cms/djangoapps/contentstore/course_group_config.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,19 @@
1212
from cms.djangoapps.contentstore.utils import reverse_usage_url
1313
from common.djangoapps.util.db import MYSQL_MAX_INT, generate_int_id
1414
from lms.lib.utils import get_parent_unit
15+
from openedx.core.djangoapps.course_groups.constants import (
16+
COHORT_SCHEME,
17+
CONTENT_GROUP_CONFIGURATION_DESCRIPTION,
18+
CONTENT_GROUP_CONFIGURATION_NAME,
19+
RANDOM_SCHEME,
20+
)
1521
from openedx.core.djangoapps.course_groups.partition_scheme import get_cohorted_user_partition
1622
from xmodule.partitions.partitions import MINIMUM_UNUSED_PARTITION_ID, ReadOnlyUserPartitionError, UserPartition # lint-amnesty, pylint: disable=wrong-import-order
1723
from xmodule.partitions.partitions_service import get_all_partitions_for_course # lint-amnesty, pylint: disable=wrong-import-order
1824
from xmodule.split_test_block import get_split_user_partitions # lint-amnesty, pylint: disable=wrong-import-order
1925

2026
MINIMUM_GROUP_ID = MINIMUM_UNUSED_PARTITION_ID
2127

22-
RANDOM_SCHEME = "random"
23-
COHORT_SCHEME = "cohort"
24-
ENROLLMENT_SCHEME = "enrollment_track"
25-
26-
CONTENT_GROUP_CONFIGURATION_DESCRIPTION = _(
27-
'The groups in this configuration can be mapped to cohorts in the Instructor Dashboard.'
28-
)
29-
30-
CONTENT_GROUP_CONFIGURATION_NAME = _('Content Groups')
31-
3228
log = logging.getLogger(__name__)
3329

3430

cms/djangoapps/contentstore/rest_api/v2/serializers/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
from cms.djangoapps.contentstore.rest_api.v2.serializers.home import CourseHomeTabSerializerV2
1010

1111
__all__ = [
12-
'CourseHomeTabSerializerV2',
1312
'ComponentLinksSerializer',
14-
'PublishableEntityLinkSerializer',
1513
'ContainerLinksSerializer',
14+
'CourseHomeTabSerializerV2',
15+
'PublishableEntityLinkSerializer',
1616
'PublishableEntityLinksSummarySerializer',
1717
]

cms/djangoapps/contentstore/utils.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2173,8 +2173,11 @@ def get_group_configurations_context(course, store):
21732173
It is used for both DRF and django views.
21742174
"""
21752175

2176-
from cms.djangoapps.contentstore.course_group_config import (
2177-
COHORT_SCHEME, ENROLLMENT_SCHEME, GroupConfiguration, RANDOM_SCHEME
2176+
from cms.djangoapps.contentstore.course_group_config import GroupConfiguration
2177+
from openedx.core.djangoapps.course_groups.constants import (
2178+
COHORT_SCHEME,
2179+
ENROLLMENT_SCHEME,
2180+
RANDOM_SCHEME,
21782181
)
21792182
from cms.djangoapps.contentstore.views.course import (
21802183
are_content_experiments_enabled

cms/djangoapps/contentstore/views/tests/test_group_configurations.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
import ddt
1212

1313
from cms.djangoapps.contentstore import toggles
14-
from cms.djangoapps.contentstore.course_group_config import (
14+
from cms.djangoapps.contentstore.course_group_config import GroupConfiguration
15+
from cms.djangoapps.contentstore.tests.utils import CourseTestCase
16+
from openedx.core.djangoapps.course_groups.constants import (
1517
CONTENT_GROUP_CONFIGURATION_NAME,
1618
ENROLLMENT_SCHEME,
17-
GroupConfiguration
1819
)
19-
from cms.djangoapps.contentstore.tests.utils import CourseTestCase
2020
from cms.djangoapps.contentstore.utils import reverse_course_url, reverse_usage_url
2121
from openedx.features.content_type_gating.helpers import CONTENT_GATING_PARTITION_ID
2222
from openedx.features.content_type_gating.partitions import CONTENT_TYPE_GATING_SCHEME
Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
swagger: '2.0'
2+
3+
info:
4+
title: Content Groups API
5+
version: 2.0.0
6+
description: |
7+
RESTful API for retrieving content groups (user partitions with cohort scheme) in courses.
8+
9+
Content groups enable course creators to assign different course content to different learner cohorts.
10+
This API allows instructors and staff to retrieve content group configurations for their courses.
11+
12+
**Note**: This is the v2 JSON-only API endpoint in the Instructor Dashboard API.
13+
The legacy v1 endpoint returns HTML with embedded JSON.
14+
15+
**Current Status**: This is a read-only API. Write operations (POST/PUT/DELETE) are not yet implemented.
16+
17+
host: edx.example.com
18+
basePath: /api/instructor/v2
19+
schemes:
20+
- https
21+
22+
securityDefinitions:
23+
jwt:
24+
type: apiKey
25+
name: Authorization
26+
in: header
27+
description: "JWT token format: Bearer <token>"
28+
session:
29+
type: basic
30+
description: Session-based authentication for staff users
31+
32+
security:
33+
- jwt: []
34+
- session: []
35+
36+
tags:
37+
- name: Content Groups
38+
description: Retrieve content group configurations for courses
39+
40+
paths:
41+
/courses/{course_id}/group_configurations:
42+
get:
43+
tags:
44+
- Content Groups
45+
summary: List all content groups for a course
46+
description: |
47+
Retrieves all content group configurations (user partitions with scheme='cohort') for a specified course.
48+
49+
Content groups are used to organize learners into cohorts and assign differentiated course content.
50+
This endpoint returns only cohort-scheme partitions; other partition types (enrollment_track, experiments) are excluded.
51+
52+
If no content group exists, an empty content group partition is automatically created.
53+
operationId: listContentGroups
54+
produces:
55+
- application/json
56+
parameters:
57+
- $ref: '#/parameters/CourseId'
58+
responses:
59+
200:
60+
description: Successfully retrieved content groups
61+
schema:
62+
$ref: '#/definitions/ContentGroupsListResponse'
63+
examples:
64+
application/json:
65+
all_group_configurations:
66+
- id: 50
67+
name: Content Groups
68+
scheme: cohort
69+
description: The groups in this configuration can be mapped to cohorts in the Instructor Dashboard.
70+
parameters: {}
71+
groups:
72+
- id: 1
73+
name: Content Group A
74+
version: 1
75+
usage: []
76+
- id: 2
77+
name: Content Group B
78+
version: 1
79+
usage: []
80+
- id: 3
81+
name: Test
82+
version: 1
83+
usage: []
84+
active: true
85+
version: 3
86+
read_only: false
87+
should_show_enrollment_track: false
88+
should_show_experiment_groups: true
89+
context_course: null
90+
group_configuration_url: /api/instructor/v2/courses/course-v1:org+course+run/group_configurations
91+
course_outline_url: /api/contentstore/v1/courses/course-v1:org+course+run/outline
92+
400:
93+
$ref: '#/responses/BadRequest'
94+
401:
95+
$ref: '#/responses/Unauthorized'
96+
403:
97+
$ref: '#/responses/Forbidden'
98+
404:
99+
$ref: '#/responses/CourseNotFound'
100+
101+
/courses/{course_id}/group_configurations/{configuration_id}:
102+
get:
103+
tags:
104+
- Content Groups
105+
summary: Retrieve a specific content group configuration
106+
description: |
107+
Retrieves the details of a single content group configuration by its ID.
108+
109+
Returns all metadata including groups, partition scheme, and usage information.
110+
operationId: getContentGroup
111+
produces:
112+
- application/json
113+
parameters:
114+
- $ref: '#/parameters/CourseId'
115+
- $ref: '#/parameters/ConfigurationId'
116+
responses:
117+
200:
118+
description: Content group configuration details
119+
schema:
120+
$ref: '#/definitions/ContentGroupResponse'
121+
401:
122+
$ref: '#/responses/Unauthorized'
123+
403:
124+
$ref: '#/responses/Forbidden'
125+
404:
126+
$ref: '#/responses/ContentGroupNotFound'
127+
128+
parameters:
129+
CourseId:
130+
name: course_id
131+
in: path
132+
required: true
133+
type: string
134+
format: opaque-key
135+
description: "The course key (e.g., course-v1:org+course+run)"
136+
example: "course-v1:edX+DemoX+Demo_2024"
137+
138+
ConfigurationId:
139+
name: configuration_id
140+
in: path
141+
required: true
142+
type: integer
143+
description: The ID of the content group configuration
144+
example: 50
145+
146+
responses:
147+
BadRequest:
148+
description: Invalid request parameters or body
149+
schema:
150+
$ref: '#/definitions/ErrorResponse'
151+
examples:
152+
application/json:
153+
error: "Invalid parameters"
154+
155+
Unauthorized:
156+
description: Authentication required
157+
schema:
158+
$ref: '#/definitions/ErrorResponse'
159+
examples:
160+
application/json:
161+
error: "Authentication credentials were not provided"
162+
163+
Forbidden:
164+
description: User does not have permission to access this resource
165+
schema:
166+
$ref: '#/definitions/ErrorResponse'
167+
examples:
168+
application/json:
169+
error: "You do not have permission to perform this action"
170+
171+
CourseNotFound:
172+
description: Course not found
173+
schema:
174+
$ref: '#/definitions/ErrorResponse'
175+
examples:
176+
application/json:
177+
error: "Course not found"
178+
179+
ContentGroupNotFound:
180+
description: Content group configuration not found
181+
schema:
182+
$ref: '#/definitions/ErrorResponse'
183+
examples:
184+
application/json:
185+
error: "Content group configuration not found"
186+
187+
definitions:
188+
ContentGroupsListResponse:
189+
type: object
190+
description: Response containing all content groups for a course
191+
required:
192+
- all_group_configurations
193+
- should_show_enrollment_track
194+
- should_show_experiment_groups
195+
properties:
196+
all_group_configurations:
197+
type: array
198+
description: List of content group configurations (only scheme='cohort' partitions)
199+
items:
200+
$ref: '#/definitions/ContentGroupResponse'
201+
should_show_enrollment_track:
202+
type: boolean
203+
description: Whether enrollment track groups should be displayed
204+
should_show_experiment_groups:
205+
type: boolean
206+
description: Whether experiment groups should be displayed
207+
context_course:
208+
type: object
209+
nullable: true
210+
description: Course context object (null in API responses)
211+
group_configuration_url:
212+
type: string
213+
description: Base URL for accessing individual group configurations
214+
course_outline_url:
215+
type: string
216+
description: URL to the course outline page
217+
218+
ContentGroupResponse:
219+
type: object
220+
description: A single content group configuration with all its metadata
221+
required:
222+
- id
223+
- name
224+
- scheme
225+
- description
226+
- groups
227+
- active
228+
- version
229+
- parameters
230+
- read_only
231+
properties:
232+
id:
233+
type: integer
234+
description: Unique identifier for this content group configuration
235+
example: 50
236+
name:
237+
type: string
238+
description: Human-readable name of the configuration
239+
example: "Content Groups"
240+
scheme:
241+
type: string
242+
enum:
243+
- cohort
244+
description: Partition scheme (always 'cohort' for content groups)
245+
description:
246+
type: string
247+
description: Detailed description of how this group is used
248+
example: "The groups in this configuration can be mapped to cohorts in the Instructor Dashboard."
249+
groups:
250+
type: array
251+
description: List of groups (cohorts) in this configuration
252+
items:
253+
$ref: '#/definitions/Group'
254+
active:
255+
type: boolean
256+
description: Whether this configuration is active
257+
example: true
258+
version:
259+
type: integer
260+
description: Configuration version number (always 3 for current UserPartition format)
261+
example: 3
262+
parameters:
263+
type: object
264+
description: Additional partition parameters (usually empty for cohort scheme)
265+
example: {}
266+
read_only:
267+
type: boolean
268+
description: Whether this configuration is read-only (system-managed)
269+
example: false
270+
271+
Group:
272+
type: object
273+
description: A single group (cohort) within a content group configuration
274+
required:
275+
- id
276+
- name
277+
- version
278+
- usage
279+
properties:
280+
id:
281+
type: integer
282+
description: Unique identifier for this group within the configuration
283+
example: 1
284+
name:
285+
type: string
286+
description: Human-readable name of the group
287+
example: "Content Group A"
288+
version:
289+
type: integer
290+
description: Group version number (always 1 for current Group format)
291+
example: 1
292+
usage:
293+
type: array
294+
description: List of course units using this group for content restriction
295+
items:
296+
type: string
297+
example: []
298+
299+
ErrorResponse:
300+
type: object
301+
description: Standard error response
302+
required:
303+
- error
304+
properties:
305+
error:
306+
type: string
307+
description: Human-readable error message
308+
error_code:
309+
type: string
310+
description: Machine-readable error code (optional)
311+
details:
312+
type: object
313+
description: Additional error details (optional)

0 commit comments

Comments
 (0)