add format version to stepic format
[idea/community.git] / python / educational-core / student / src / com / jetbrains / edu / learning / stepic / StepicWrappers.java
1 package com.jetbrains.edu.learning.stepic;
2
3 import com.google.gson.annotations.Expose;
4 import com.google.gson.annotations.SerializedName;
5 import com.intellij.openapi.application.ApplicationManager;
6 import com.intellij.openapi.diagnostic.Logger;
7 import com.intellij.openapi.project.Project;
8 import com.intellij.openapi.util.Pair;
9 import com.intellij.openapi.util.io.FileUtil;
10 import com.intellij.openapi.vfs.VirtualFile;
11 import com.jetbrains.edu.learning.core.EduNames;
12 import com.jetbrains.edu.learning.core.EduUtils;
13 import com.jetbrains.edu.learning.courseFormat.Course;
14 import com.jetbrains.edu.learning.courseFormat.Lesson;
15 import com.jetbrains.edu.learning.courseFormat.Task;
16 import com.jetbrains.edu.learning.courseFormat.TaskFile;
17 import org.apache.commons.codec.binary.Base64;
18 import org.jetbrains.annotations.NotNull;
19 import org.jetbrains.annotations.Nullable;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.*;
24
25 public class StepicWrappers {
26   private static final Logger LOG = Logger.getInstance(StepOptions.class);
27
28   static class StepContainer {
29     List<StepSource> steps;
30   }
31
32   public static class Step {
33     @Expose StepOptions options;
34     @Expose String text;
35     @Expose String name = "pycharm";
36     @Expose StepOptions source;
37
38     public static Step fromTask(Project project, @NotNull final Task task) {
39       final Step step = new Step();
40       step.text = task.getTaskText(project);
41       step.source = StepOptions.fromTask(project, task);
42       return step;
43     }
44   }
45
46   public static class StepOptions {
47     @Expose List<TestFileWrapper> test;
48     @Expose String title;
49     @Expose List<TaskFile> files;
50     @Expose String text;
51     @Expose List<List<String>> samples;
52     @Expose Integer executionMemoryLimit;
53     @Expose Integer executionTimeLimit;
54     @Expose CodeTemplatesWrapper codeTemplates;
55     @SerializedName("format_version")
56     @Expose public int formatVersion = 2;
57     @SerializedName("last_subtask_index")
58     @Expose int lastSubtaskIndex = 0;
59
60     public static StepOptions fromTask(final Project project, @NotNull final Task task) {
61       final StepOptions source = new StepOptions();
62       task.setLastSubtaskIndex(source.lastSubtaskIndex);
63       setTests(task, source, project);
64       source.files = new ArrayList<>();
65       source.title = task.getName();
66       for (final Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
67         ApplicationManager.getApplication().runWriteAction(() -> {
68           final VirtualFile taskDir = task.getTaskDir(project);
69           assert taskDir != null;
70           VirtualFile ideaDir = project.getBaseDir().findChild(".idea");
71           assert ideaDir != null;
72           String stepic = "stepic";
73           VirtualFile stepicDir = ideaDir.findChild(stepic);
74           if (stepicDir == null) {
75             try {
76               stepicDir = ideaDir.createChildDirectory(StepicWrappers.class, stepic);
77             }
78             catch (IOException e) {
79               LOG.info("Failed to create idea/stepic directory", e);
80             }
81           }
82           if (stepicDir == null) {
83             return;
84           }
85           String name = entry.getKey();
86           VirtualFile answerFile = taskDir.findChild(name);
87           Pair<VirtualFile, TaskFile> pair = EduUtils.createStudentFile(StepicWrappers.class, project, answerFile, stepicDir, null, 0);
88           if (pair == null) {
89             return;
90           }
91           VirtualFile virtualFile = pair.getFirst();
92           TaskFile taskFile = pair.getSecond();
93           try {
94             InputStream stream = virtualFile.getInputStream();
95             taskFile.text =
96               EduUtils.isImage(name) ? Base64.encodeBase64URLSafeString(FileUtil.loadBytes(stream)) : FileUtil.loadTextAndClose(stream);
97           }
98           catch (IOException e) {
99             LOG.error("Can't find file " + virtualFile.getPath());
100           }
101           source.files.add(taskFile);
102         });
103       }
104       return source;
105     }
106
107     private static void setTests(@NotNull final Task task, @NotNull final StepOptions source, @NotNull final Project project) {
108       final Map<String, String> testsText = task.getTestsText();
109       if (testsText.isEmpty()) {
110         ApplicationManager.getApplication().runReadAction(() -> {
111           source.test = Collections.singletonList(new TestFileWrapper(EduNames.TESTS_FILE, task.getTestsText(project)));
112         });
113       }
114       else {
115         source.test = new ArrayList<>();
116         for (Map.Entry<String, String> entry : testsText.entrySet()) {
117           source.test.add(new TestFileWrapper(entry.getKey(), entry.getValue()));
118         }
119       }
120     }
121   }
122
123   static class CodeTemplatesWrapper {
124     String python3;
125     String python27;
126
127     @Nullable
128     public String getTemplateForLanguage(@NotNull final String language) {
129       if (language.equals(EduAdaptiveStepicConnector.PYTHON2)) {
130         return python27;
131       }
132
133       if (language.equals(EduAdaptiveStepicConnector.PYTHON3)) {
134         return python3;
135       }
136
137       return null;
138     }
139   }
140
141   static class CoursesContainer {
142     public List<CourseInfo> courses;
143     public Map meta;
144   }
145
146   static class StepSourceWrapper {
147     @Expose
148     StepSource stepSource;
149
150     public StepSourceWrapper(Project project, Task task, int lessonId) {
151       stepSource = new StepSource(project, task, lessonId);
152     }
153   }
154
155   static class CourseWrapper {
156     CourseInfo course;
157
158     public CourseWrapper(Course course) {
159       this.course = new CourseInfo();
160       this.course.setName(course.getName());
161       this.course.setDescription(course.getDescription());
162       this.course.setAuthors(course.getAuthors());
163     }
164   }
165
166   static class LessonWrapper {
167     Lesson lesson;
168
169     public LessonWrapper(Lesson lesson) {
170       this.lesson = new Lesson();
171       this.lesson.setName(lesson.getName());
172       this.lesson.setId(lesson.getId());
173       this.lesson.steps = new ArrayList<>();
174     }
175   }
176
177   static class LessonContainer {
178     List<Lesson> lessons;
179   }
180
181   static class StepSource {
182     @Expose Step block;
183     @Expose int position = 0;
184     @Expose int lesson = 0;
185     Date update_date;
186
187     public StepSource(Project project, Task task, int lesson) {
188       this.lesson = lesson;
189       position = task.getIndex();
190       block = Step.fromTask(project, task);
191     }
192   }
193
194   static class TestFileWrapper {
195     @Expose public final String name;
196     @Expose public final String text;
197
198     public TestFileWrapper(String name, String text) {
199       this.name = name;
200       this.text = text;
201     }
202   }
203
204   static class Section {
205     List<Integer> units;
206     int course;
207     String title;
208     int position;
209     int id;
210   }
211
212   static class SectionWrapper {
213     Section section;
214   }
215
216   static class SectionContainer {
217     List<Section> sections;
218     List<Lesson> lessons;
219
220     List<Unit> units;
221   }
222
223   static class Unit {
224     int id;
225     int section;
226     int lesson;
227     int position;
228     List<Integer> assignments;
229   }
230
231   static class UnitContainer {
232
233     List<Unit> units;
234   }
235
236   static class UnitWrapper {
237     Unit unit;
238   }
239
240   static class AttemptWrapper {
241     static class Attempt {
242       public Attempt(int step) {
243         this.step = step;
244       }
245
246       int step;
247       int id;
248     }
249
250     public AttemptWrapper(int step) {
251       attempt = new Attempt(step);
252     }
253
254     Attempt attempt;
255   }
256
257   static class AttemptToPostWrapper {
258     static class Attempt {
259       int step;
260       String dataset_url;
261       String status;
262       String time;
263       String time_left;
264       String user;
265       String user_id;
266
267       public Attempt(int step) {
268         this.step = step;
269       }
270     }
271
272     public AttemptToPostWrapper(int step) {
273       attempt = new Attempt(step);
274     }
275
276     Attempt attempt;
277   }
278
279   static class AttemptContainer {
280     List<AttemptWrapper.Attempt> attempts;
281   }
282
283   static class SolutionFile {
284     String name;
285     String text;
286
287     public SolutionFile(String name, String text) {
288       this.name = name;
289       this.text = text;
290     }
291   }
292
293   static class AuthorWrapper {
294     List<StepicUser> users;
295   }
296
297   static class SubmissionWrapper {
298     Submission submission;
299
300
301     public SubmissionWrapper(int attempt, String score, ArrayList<SolutionFile> files) {
302       submission = new Submission(score, attempt, files);
303     }
304
305     static class Submission {
306       int attempt;
307       private final Reply reply;
308
309       public Submission(String score, int attempt, ArrayList<SolutionFile> files) {
310         reply = new Reply(files, score);
311         this.attempt = attempt;
312       }
313
314       static class Reply {
315         String score;
316         List<SolutionFile> solution;
317
318         public Reply(ArrayList<SolutionFile> files, String score) {
319           this.score = score;
320           solution = files;
321         }
322       }
323     }
324   }
325
326   static class UserWrapper {
327     StepicUser user;
328
329     public UserWrapper(String user, String password) {
330       this.user = new StepicUser(user, password);
331     }
332   }
333
334   static class RecommendationReaction {
335     int reaction;
336     String user;
337     String lesson;
338
339     public RecommendationReaction(int reaction, String user, String lesson) {
340       this.reaction = reaction;
341       this.user = user;
342       this.lesson = lesson;
343     }
344   }
345
346   static class RecommendationReactionWrapper {
347     RecommendationReaction recommendationReaction;
348
349     public RecommendationReactionWrapper(RecommendationReaction recommendationReaction) {
350       this.recommendationReaction = recommendationReaction;
351     }
352   }
353
354   static class RecommendationWrapper {
355     Recommendation[] recommendations;
356   }
357
358   static class Recommendation {
359     String id;
360     String lesson;
361   }
362
363
364   static class SubmissionToPostWrapper {
365     Submission submission;
366
367     public SubmissionToPostWrapper(@NotNull String attemptId, @NotNull String language, @NotNull String code) {
368       submission = new Submission(attemptId, new Submission.Reply(language, code));
369     }
370
371     static class Submission {
372       String attempt;
373       Reply reply;
374
375       public Submission(String attempt, Reply reply) {
376         this.attempt = attempt;
377         this.reply = reply;
378       }
379
380       static class Reply {
381         String language;
382         String code;
383
384         public Reply(String language, String code) {
385           this.language = language;
386           this.code = code;
387         }
388       }
389     }
390   }
391
392   static class ResultSubmissionWrapper {
393     ResultSubmission[] submissions;
394
395     static class ResultSubmission {
396       int id;
397       String status;
398       String hint;
399     }
400   }
401
402   static class AssignmentsWrapper {
403     List<Assignment> assignments;
404   }
405
406   static class Assignment {
407     int id;
408     int step;
409   }
410
411   static class ViewsWrapper {
412     View view;
413
414     public ViewsWrapper(final int assignment, final int step) {
415       this.view = new View(assignment, step);
416     }
417   }
418
419   static class View {
420     int assignment;
421     int step;
422
423     public View(int assignment, int step) {
424       this.assignment = assignment;
425       this.step = step;
426     }
427   }
428
429   static class Enrollment {
430     String course;
431
432     public Enrollment(String courseId) {
433       course = courseId;
434     }
435   }
436
437   static class EnrollmentWrapper {
438     Enrollment enrollment;
439
440     public EnrollmentWrapper(@NotNull final String courseId) {
441       enrollment = new Enrollment(courseId);
442     }
443   }
444
445   static class TokenInfo {
446     @Expose String accessToken;
447     @Expose String refreshToken;
448     @Expose String tokenType;
449     @Expose String scope;
450     @Expose int expiresIn;
451
452     public TokenInfo() {
453       accessToken = "";
454       refreshToken = "";
455     }
456
457     public String getAccessToken() {
458       return accessToken;
459     }
460
461     public String getRefreshToken() {
462       return refreshToken;
463     }
464   }
465 }