Skip to content

Commit 62b0362

Browse files
committed
Progress
1 parent 7eb865a commit 62b0362

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1145
-482
lines changed

shared/langsSchema.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
// VERSION=0.38.0
2-
// https://raw.githubusercontent.com/rage/tmc-langs-rust/0.38.0/crates/tmc-langs-cli/bindings.d.ts
3-
41
export type Locale = string;
52

63
export type CliOutput =
@@ -17,16 +14,10 @@ export type DataKind =
1714
"output-data-kind": "exercise-packaging-configuration";
1815
"output-data": ExercisePackagingConfiguration;
1916
}
20-
| { "output-data-kind": "local-tmc-exercises"; "output-data": Array<LocalTmcExercise> }
21-
| { "output-data-kind": "local-mooc-exercises"; "output-data": Array<LocalMoocExercise> }
2217
| { "output-data-kind": "refresh-result"; "output-data": RefreshData }
2318
| { "output-data-kind": "test-result"; "output-data": RunResult }
2419
| { "output-data-kind": "exercise-desc"; "output-data": ExerciseDesc }
2520
| { "output-data-kind": "updated-exercises"; "output-data": Array<UpdatedExercise> }
26-
| {
27-
"output-data-kind": "tmc-exercise-download";
28-
"output-data": DownloadOrUpdateTmcCourseExercisesResult;
29-
}
3021
| {
3122
"output-data-kind": "mooc-exercise-download";
3223
"output-data": DownloadOrUpdateMoocCourseExercisesResult;
@@ -50,9 +41,17 @@ export type DataKind =
5041
}
5142
| { "output-data-kind": "submission-finished"; "output-data": SubmissionFinished }
5243
| { "output-data-kind": "config-value"; "output-data": ConfigValue }
53-
| { "output-data-kind": "tmc-config"; "output-data": TmcConfig }
5444
| { "output-data-kind": "compressed-project-hash"; "output-data": string }
5545
| { "output-data-kind": "submission-sandbox"; "output-data": string }
46+
| { "output-data-kind": "local-tmc-exercises"; "output-data": Array<LocalTmcExercise> }
47+
| {
48+
"output-data-kind": "tmc-exercise-download";
49+
"output-data": DownloadOrUpdateTmcCourseExercisesResult;
50+
}
51+
| { "output-data-kind": "tmc-config"; "output-data": TmcConfig }
52+
| { "output-data-kind": "mooc-updated-exercises"; "output-data": Array<string> }
53+
| { "output-data-kind": "local-mooc-exercises"; "output-data": Array<LocalMoocExercise> }
54+
| { "output-data-kind": "mooc-course-instance"; "output-data": CourseInstance }
5655
| { "output-data-kind": "mooc-course-instances"; "output-data": Array<CourseInstance> }
5756
| { "output-data-kind": "mooc-exercise-slides"; "output-data": Array<TmcExerciseSlide> }
5857
| { "output-data-kind": "mooc-exercise-slide"; "output-data": TmcExerciseSlide }
@@ -276,7 +275,7 @@ export type TmcExerciseDownload = {
276275
path: string;
277276
};
278277

279-
export type MoocExerciseDownload = { id: string; path: string };
278+
export type MoocExerciseDownload = { "task-id": string; path: string };
280279

281280
export type CombinedCourseData = {
282281
details: CourseDetails;
@@ -630,6 +629,7 @@ export type TmcExerciseTask = {
630629
assignment: unknown;
631630
public_spec: PublicSpec | null;
632631
model_solution_spec: ModelSolutionSpec | null;
632+
checksum: string;
633633
};
634634

635635
export type PublicSpec =

shared/lib.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ export interface LocalMoocCourseData {
3636
instanceId: string;
3737
courseName: string;
3838
instanceName: string | null;
39-
description: string;
39+
courseDescription: string | null;
40+
instanceDescription: string | null;
4041
awardedPoints: number;
4142
availablePoints: number;
4243
disabled: boolean;
@@ -621,6 +622,7 @@ export type WebviewToExtension =
621622
}
622623
| {
623624
type: "addMoocCourse";
625+
organizationSlug: string;
624626
courseId: string;
625627
instanceId: string;
626628
courseName: string;
@@ -868,6 +870,16 @@ type MoocKind = { kind: "mooc" };
868870

869871
export type Enum<Tmc, Mooc> = { kind: "tmc"; data: Tmc } | { kind: "mooc"; data: Mooc };
870872

873+
export namespace Enum {
874+
export function unwrap<A, B>(e: Enum<A, B>): A | B {
875+
return match(
876+
e,
877+
(e) => e,
878+
(e) => e,
879+
);
880+
}
881+
}
882+
871883
export type CourseIdentifier = Enum<{ courseId: number }, { instanceId: string }>;
872884

873885
export namespace CourseIdentifier {
@@ -941,6 +953,24 @@ export function match<A, B, C, D>(data: Enum<A, B>, tmc: (x: A) => C, mooc: (x:
941953
}
942954
}
943955

956+
export function matchBackend<A extends { backend: "tmc" | "mooc" }, B, C, D>(
957+
data: A,
958+
tmc: (x: A) => B,
959+
mooc: (x: A) => C,
960+
): B | C {
961+
switch (data.backend) {
962+
case "tmc": {
963+
return tmc(data);
964+
}
965+
case "mooc": {
966+
return mooc(data);
967+
}
968+
default: {
969+
assertUnreachable(data.backend);
970+
}
971+
}
972+
}
973+
944974
export function matchOption<A, B, T extends Enum<A, B> | undefined>(
945975
data: T,
946976
tmc: (x: T & TmcKind) => A,

src/actions/addNewCourse.ts

Lines changed: 81 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,101 @@
11
import { Err, Result } from "ts-results";
22

33
import { Logger } from "../utilities";
4-
import { combineApiExerciseData } from "../utilities/apiData";
4+
import { combineTmcApiExerciseData } from "../utilities/apiData";
55

66
import { refreshLocalExercises } from "./refreshLocalExercises";
77
import { ActionContext } from "./types";
8-
import {
9-
CourseIdentifier,
10-
LocalCourseData,
11-
LocalTmcCourseData,
12-
makeMoocKind,
13-
makeTmcKind,
14-
match,
15-
} from "../shared/shared";
8+
import { CourseIdentifier, LocalMoocCourseData, LocalTmcCourseData, match } from "../shared/shared";
169

1710
/**
18-
* Adds a new TMC course to user's courses.
11+
* Adds a new course to user's courses.
1912
*/
2013
export async function addNewCourse(
2114
actionContext: ActionContext,
22-
organization: string,
15+
organizationSlug: string,
2316
course: CourseIdentifier,
2417
): Promise<Result<void, Error>> {
25-
const { tmc, ui, userData, workspaceManager } = actionContext;
26-
if (!(tmc.ok && userData.ok && workspaceManager.ok)) {
18+
const { langs, ui, userData, workspaceManager } = actionContext;
19+
if (!(langs.ok && userData.ok && workspaceManager.ok)) {
2720
return new Err(new Error("Extension was not initialized properly"));
2821
}
2922
Logger.info("Adding new course");
3023

31-
const courseDataResult = await tmc.val.getCourseData(course);
32-
if (courseDataResult.err) {
33-
return courseDataResult;
34-
}
35-
const courseData = courseDataResult.val;
24+
return match(
25+
course,
26+
async (tmcCourse) => {
27+
const courseDataResult = await langs.val.getTmcCourseData(tmcCourse.courseId);
28+
if (courseDataResult.err) {
29+
return courseDataResult;
30+
}
31+
const courseData = courseDataResult.val;
32+
33+
let availablePoints = 0;
34+
let awardedPoints = 0;
35+
courseData.exercises.forEach((x) => {
36+
availablePoints += x.available_points.length;
37+
awardedPoints += x.awarded_points.length;
38+
});
3639

37-
let availablePoints = 0;
38-
let awardedPoints = 0;
39-
courseData.exercises.forEach((x) => {
40-
availablePoints += x.available_points.length;
41-
awardedPoints += x.awarded_points.length;
42-
});
40+
const localData: LocalTmcCourseData = {
41+
description: courseData.details.description || "",
42+
exercises: combineTmcApiExerciseData(
43+
courseData.details.exercises,
44+
courseData.exercises,
45+
),
46+
id: courseData.details.id,
47+
name: courseData.details.name,
48+
title: courseData.details.title,
49+
organization: organizationSlug,
50+
availablePoints: availablePoints,
51+
awardedPoints: awardedPoints,
52+
perhapsExamMode: courseData.settings.hide_submission_results,
53+
newExercises: [],
54+
notifyAfter: 0,
55+
disabled: courseData.settings.disabled_status === "enabled" ? false : true,
56+
materialUrl: courseData.settings.material_url,
57+
};
58+
userData.val.addCourse({ kind: "tmc", data: localData });
59+
ui.treeDP.addChildWithId("myCourses", localData.id, localData.title, {
60+
command: "tmc.courseDetails",
61+
title: "Go To Course Details",
62+
arguments: [CourseIdentifier.from(localData.id)],
63+
});
64+
workspaceManager.val.createWorkspaceFile(courseData.details.name);
65+
//await displayUserCourses(actionContext);
66+
return refreshLocalExercises(actionContext);
67+
},
68+
async (mooc) => {
69+
const courseInstanceRes = await langs.val.getMoocCourseInstanceData(mooc.instanceId);
70+
if (courseInstanceRes.err) {
71+
return courseInstanceRes;
72+
}
73+
const [courseInstance, _] = courseInstanceRes.val;
4374

44-
const localData: LocalTmcCourseData = {
45-
description: courseData.details.description || "",
46-
exercises: combineApiExerciseData(courseData.details.exercises, courseData.exercises)
47-
.filter((ex) => ex.kind === "tmc")
48-
.map((ex) => ex.data),
49-
id: courseData.details.id,
50-
name: courseData.details.name,
51-
title: courseData.details.title,
52-
organization: organization,
53-
availablePoints: availablePoints,
54-
awardedPoints: awardedPoints,
55-
perhapsExamMode: courseData.settings.hide_submission_results,
56-
newExercises: [],
57-
notifyAfter: 0,
58-
disabled: courseData.settings.disabled_status === "enabled" ? false : true,
59-
materialUrl: courseData.settings.material_url,
60-
};
61-
userData.val.addCourse({ kind: "tmc", data: localData });
62-
ui.treeDP.addChildWithId("myCourses", localData.id, localData.title, {
63-
command: "tmc.courseDetails",
64-
title: "Go To Course Details",
65-
arguments: [localData.id],
66-
});
67-
workspaceManager.val.createWorkspaceFile(courseData.details.name);
68-
//await displayUserCourses(actionContext);
69-
return refreshLocalExercises(actionContext);
75+
const localData: LocalMoocCourseData = {
76+
courseId: courseInstance.course_id,
77+
instanceId: courseInstance.id,
78+
courseName: courseInstance.course_name,
79+
instanceName: courseInstance.instance_name,
80+
courseDescription: courseInstance.course_description,
81+
instanceDescription: courseInstance.instance_description,
82+
awardedPoints: 0,
83+
availablePoints: 0,
84+
disabled: false,
85+
materialUrl: null,
86+
exercises: [],
87+
newExercises: [],
88+
notifyAfter: 0,
89+
perhapsExamMode: false,
90+
};
91+
userData.val.addCourse({ kind: "mooc", data: localData });
92+
ui.treeDP.addChildWithId("myCourses", localData.instanceId, localData.courseName, {
93+
command: "tmc.courseDetails",
94+
title: "Go To Course Details",
95+
arguments: [CourseIdentifier.from(localData.instanceId)],
96+
});
97+
workspaceManager.val.createWorkspaceFile(courseInstance.course_slug);
98+
return refreshLocalExercises(actionContext);
99+
},
100+
);
70101
}

src/actions/checkForExerciseUpdates.ts

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
import { flatten } from "lodash";
22
import { Err, Ok, Result } from "ts-results";
33

4-
import {
5-
assertUnreachable,
6-
CourseIdentifier,
7-
ExerciseIdentifier,
8-
makeTmcKind,
9-
} from "../shared/shared";
4+
import { assertUnreachable, CourseIdentifier, ExerciseIdentifier } from "../shared/shared";
105
import { Logger } from "../utilities";
116

127
import { ActionContext } from "./types";
@@ -29,35 +24,48 @@ export async function checkForExerciseUpdates(
2924
actionContext: ActionContext,
3025
options?: Options,
3126
): Promise<Result<OutdatedExercise[], Error>> {
32-
const { tmc, userData } = actionContext;
33-
if (!(tmc.ok && userData.ok)) {
27+
const { langs, userData } = actionContext;
28+
if (!(langs.ok && userData.ok)) {
3429
return new Err(new Error("Extension was not initialized properly"));
3530
}
3631
const forceRefresh = options?.forceRefresh ?? false;
3732
Logger.info("Checking for exercise updates, forced update:", forceRefresh);
3833

39-
const checkUpdatesResult = await tmc.val.checkExerciseUpdates({ forceRefresh });
40-
if (checkUpdatesResult.err) {
41-
return checkUpdatesResult;
34+
const tmcCheckUpdatesResult = await langs.val.checkTmcExerciseUpdates({ forceRefresh });
35+
if (tmcCheckUpdatesResult.err) {
36+
return tmcCheckUpdatesResult;
4237
}
4338

44-
const updateableExerciseIds = new Set<number>(checkUpdatesResult.val.map((x) => x.id));
39+
const moocCheckUpdatesResult = await langs.val.checkMoocExerciseUpdates({ forceRefresh });
40+
if (moocCheckUpdatesResult.err) {
41+
return moocCheckUpdatesResult;
42+
}
43+
44+
const tmcUpdateableExerciseIds = new Set<number>(tmcCheckUpdatesResult.val.map((x) => x.id));
45+
const moocUpdateableExerciseIds = new Set<string>(moocCheckUpdatesResult.val.map((x) => x));
4546
const outdatedExercisesByCourse = userData.val
4647
.getCourses()
4748
.map<OutdatedExercise[]>((course) => {
4849
switch (course.kind) {
4950
case "tmc": {
5051
const outdatedExercises = course.data.exercises.filter((x) =>
51-
updateableExerciseIds.has(x.id),
52+
tmcUpdateableExerciseIds.has(x.id),
5253
);
5354
return outdatedExercises.map((x) => ({
54-
courseId: makeTmcKind({ courseId: course.data.id }),
55-
exerciseId: makeTmcKind({ tmcExerciseId: x.id }),
55+
courseId: CourseIdentifier.from(course.data.id),
56+
exerciseId: ExerciseIdentifier.from(x.id),
5657
exerciseName: x.name,
5758
}));
5859
}
5960
case "mooc": {
60-
throw new Error("todo");
61+
const outdatedExercises = course.data.exercises.filter((x) =>
62+
moocUpdateableExerciseIds.has(x.id),
63+
);
64+
return outdatedExercises.map((x) => ({
65+
courseId: CourseIdentifier.from(course.data.instanceId),
66+
exerciseId: ExerciseIdentifier.from(x.id),
67+
exerciseName: x.slug,
68+
}));
6169
}
6270
default: {
6371
assertUnreachable(course);

0 commit comments

Comments
 (0)