1 package com.jetbrains.edu.learning.stepic;
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;
21 import java.io.IOException;
22 import java.io.InputStream;
25 public class StepicWrappers {
26 private static final Logger LOG = Logger.getInstance(StepOptions.class);
28 static class StepContainer {
29 List<StepSource> steps;
32 public static class Step {
33 @Expose StepOptions options;
35 @Expose String name = "pycharm";
36 @Expose StepOptions source;
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);
46 public static class StepOptions {
47 @Expose List<TestFileWrapper> test;
49 @Expose List<TaskFile> files;
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;
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) {
76 stepicDir = ideaDir.createChildDirectory(StepicWrappers.class, stepic);
78 catch (IOException e) {
79 LOG.info("Failed to create idea/stepic directory", e);
82 if (stepicDir == null) {
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);
91 VirtualFile virtualFile = pair.getFirst();
92 TaskFile taskFile = pair.getSecond();
94 InputStream stream = virtualFile.getInputStream();
96 EduUtils.isImage(name) ? Base64.encodeBase64URLSafeString(FileUtil.loadBytes(stream)) : FileUtil.loadTextAndClose(stream);
98 catch (IOException e) {
99 LOG.error("Can't find file " + virtualFile.getPath());
101 source.files.add(taskFile);
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)));
115 source.test = new ArrayList<>();
116 for (Map.Entry<String, String> entry : testsText.entrySet()) {
117 source.test.add(new TestFileWrapper(entry.getKey(), entry.getValue()));
123 static class CodeTemplatesWrapper {
128 public String getTemplateForLanguage(@NotNull final String language) {
129 if (language.equals(EduAdaptiveStepicConnector.PYTHON2)) {
133 if (language.equals(EduAdaptiveStepicConnector.PYTHON3)) {
141 static class CoursesContainer {
142 public List<CourseInfo> courses;
146 static class StepSourceWrapper {
148 StepSource stepSource;
150 public StepSourceWrapper(Project project, Task task, int lessonId) {
151 stepSource = new StepSource(project, task, lessonId);
155 static class CourseWrapper {
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());
166 static class LessonWrapper {
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<>();
177 static class LessonContainer {
178 List<Lesson> lessons;
181 static class StepSource {
183 @Expose int position = 0;
184 @Expose int lesson = 0;
187 public StepSource(Project project, Task task, int lesson) {
188 this.lesson = lesson;
189 position = task.getIndex();
190 block = Step.fromTask(project, task);
194 static class TestFileWrapper {
195 @Expose public final String name;
196 @Expose public final String text;
198 public TestFileWrapper(String name, String text) {
204 static class Section {
212 static class SectionWrapper {
216 static class SectionContainer {
217 List<Section> sections;
218 List<Lesson> lessons;
228 List<Integer> assignments;
231 static class UnitContainer {
236 static class UnitWrapper {
240 static class AttemptWrapper {
241 static class Attempt {
242 public Attempt(int step) {
250 public AttemptWrapper(int step) {
251 attempt = new Attempt(step);
257 static class AttemptToPostWrapper {
258 static class Attempt {
267 public Attempt(int step) {
272 public AttemptToPostWrapper(int step) {
273 attempt = new Attempt(step);
279 static class AttemptContainer {
280 List<AttemptWrapper.Attempt> attempts;
283 static class SolutionFile {
287 public SolutionFile(String name, String text) {
293 static class AuthorWrapper {
294 List<StepicUser> users;
297 static class SubmissionWrapper {
298 Submission submission;
301 public SubmissionWrapper(int attempt, String score, ArrayList<SolutionFile> files) {
302 submission = new Submission(score, attempt, files);
305 static class Submission {
307 private final Reply reply;
309 public Submission(String score, int attempt, ArrayList<SolutionFile> files) {
310 reply = new Reply(files, score);
311 this.attempt = attempt;
316 List<SolutionFile> solution;
318 public Reply(ArrayList<SolutionFile> files, String score) {
326 static class UserWrapper {
329 public UserWrapper(String user, String password) {
330 this.user = new StepicUser(user, password);
334 static class RecommendationReaction {
339 public RecommendationReaction(int reaction, String user, String lesson) {
340 this.reaction = reaction;
342 this.lesson = lesson;
346 static class RecommendationReactionWrapper {
347 RecommendationReaction recommendationReaction;
349 public RecommendationReactionWrapper(RecommendationReaction recommendationReaction) {
350 this.recommendationReaction = recommendationReaction;
354 static class RecommendationWrapper {
355 Recommendation[] recommendations;
358 static class Recommendation {
364 static class SubmissionToPostWrapper {
365 Submission submission;
367 public SubmissionToPostWrapper(@NotNull String attemptId, @NotNull String language, @NotNull String code) {
368 submission = new Submission(attemptId, new Submission.Reply(language, code));
371 static class Submission {
375 public Submission(String attempt, Reply reply) {
376 this.attempt = attempt;
384 public Reply(String language, String code) {
385 this.language = language;
392 static class ResultSubmissionWrapper {
393 ResultSubmission[] submissions;
395 static class ResultSubmission {
402 static class AssignmentsWrapper {
403 List<Assignment> assignments;
406 static class Assignment {
411 static class ViewsWrapper {
414 public ViewsWrapper(final int assignment, final int step) {
415 this.view = new View(assignment, step);
423 public View(int assignment, int step) {
424 this.assignment = assignment;
429 static class Enrollment {
432 public Enrollment(String courseId) {
437 static class EnrollmentWrapper {
438 Enrollment enrollment;
440 public EnrollmentWrapper(@NotNull final String courseId) {
441 enrollment = new Enrollment(courseId);
445 static class TokenInfo {
446 @Expose String accessToken;
447 @Expose String refreshToken;
448 @Expose String tokenType;
449 @Expose String scope;
450 @Expose int expiresIn;
457 public String getAccessToken() {
461 public String getRefreshToken() {