11
11
from django .db import transaction
12
12
from django .shortcuts import reverse
13
13
from edx_api .client import EdxApi
14
+ from edx_api .course_runs .exceptions import CourseRunAPIError
14
15
from edx_api .course_runs .models import CourseRun , CourseRunList
15
16
from mitol .common .utils import (
16
17
find_object_with_matching_attr ,
@@ -1140,7 +1141,7 @@ def update_edx_course( # noqa: PLR0913
1140
1141
)
1141
1142
1142
1143
1143
- def process_course_run_clone (target_id : int , * , base_id : int | str | None = None ):
1144
+ def process_course_run_clone (target_id : int , * , base_id : int | str | None = None ):
1144
1145
"""
1145
1146
Clone a course run, using details from CourseRun objects in MITx Online.
1146
1147
@@ -1152,5 +1153,66 @@ def process_course_run_clone(target_id: int, *, base_id: int|str|None = None):
1152
1153
etc.) and the URL will be backfilled into the CourseRun.
1153
1154
1154
1155
If a different course run needs to be used as the base course, you can
1155
- set that.
1156
+ set that. Pass either the PK of the course or the readable ID. If a readable
1157
+ ID is passed, it will be supplied verbatim to the clone API. (In other words,
1158
+ it can be a course that MITx Online doesn't know about.)
1159
+
1160
+ Args:
1161
+ - target_id (int): The PK of the target course (i.e. the one we're creating)
1162
+ - base_id (int|str): The PK or readable ID of the base course to clone.
1163
+ Returns:
1164
+ bool, whether or not it worked
1156
1165
"""
1166
+ edx_client = get_edx_api_jwt_client (
1167
+ settings .OPENEDX_COURSES_SERVICE_WORKER_CLIENT_ID ,
1168
+ settings .OPENEDX_COURSES_SERVICE_WORKER_CLIENT_SECRET ,
1169
+ use_studio = True ,
1170
+ )
1171
+
1172
+ target_course = courses .models .CourseRun .objects .get (pk = target_id )
1173
+ base_course = target_course .course .readable_id
1174
+
1175
+ if base_id :
1176
+ if base_id is int :
1177
+ if courses .models .Course .objects .filter (pk = base_id ).exists ():
1178
+ base_course = courses .models .Course .objects .get (pk = base_id ).readable_id
1179
+ elif courses .models .CourseRun .objects .filter (pk = base_id ).exists ():
1180
+ base_course = courses .models .CourseRun .objects .get (
1181
+ pk = base_id
1182
+ ).readable_id
1183
+ else :
1184
+ msg = f"Specified base course { base_id } doesn't exist."
1185
+ raise ValueError (msg )
1186
+ else :
1187
+ base_course = str (base_id )
1188
+
1189
+ get_edx_course (base_course , client = edx_client )
1190
+
1191
+ try :
1192
+ get_edx_course (target_course .readable_id , client = edx_client )
1193
+
1194
+ msg = f"Course ID { target_course .readable_id } was found in edX. Can't continue."
1195
+ raise ValueError (msg )
1196
+ except CourseRunAPIError :
1197
+ # An HTTP error is good in this case. We don't want the target course to exist.
1198
+ pass
1199
+
1200
+ resp = clone_edx_course (base_course , target_course .readable_id , client = edx_client )
1201
+
1202
+ if not resp :
1203
+ msg = f"Couldn't clone { base_course } to { target_course .readable_id } ."
1204
+ raise ValueError (msg )
1205
+
1206
+ # We should have the target course in edX now. We need to update it with the
1207
+ # data from our course run.
1208
+
1209
+ resp = update_edx_course (
1210
+ target_course .readable_id ,
1211
+ target_course .title ,
1212
+ "self_paced" if target_course .is_self_paced else "instructor_paced" ,
1213
+ target_course .start_date ,
1214
+ target_course .end_date ,
1215
+ target_course .enrollment_start ,
1216
+ target_course .enrollment_end ,
1217
+ client = edx_client ,
1218
+ )
0 commit comments