replace subtaskInfo map with list for stepik
authorliana.bakradze <liana.bakradze@jetbrains.com>
Thu, 10 Nov 2016 21:05:46 +0000 (00:05 +0300)
committerliana.bakradze <liana.bakradze@jetbrains.com>
Thu, 17 Nov 2016 14:08:43 +0000 (17:08 +0300)
python/educational-core/student/src/com/jetbrains/edu/learning/StudySerializationUtils.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/CCStepicConnector.java
python/educational-core/student/testData/stepic/2.json
python/educational-core/student/testData/stepic/3.json
python/educational-core/student/testData/stepic/placeholder.json [new file with mode: 0644]
python/educational-core/student/testSrc/com/jetbrains/edu/learning/stepic/StudyStepicFormatTest.java

index 46ba322b1e7fd22efc8bbc32133dcfe4bc912ad6..c7cb4f83c86ae78e96238ef6434543b5292d8830 100644 (file)
@@ -12,6 +12,7 @@ import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.containers.hash.HashMap;
 import com.jetbrains.edu.learning.core.EduNames;
+import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
 import com.jetbrains.edu.learning.courseFormat.Course;
 import com.jetbrains.edu.learning.courseFormat.StudyStatus;
 import com.jetbrains.edu.learning.stepic.EduStepicConnector;
@@ -391,6 +392,7 @@ public class StudySerializationUtils {
     public static final String HINTS = "hints";
     public static final String SUBTASK_INFOS = "subtask_infos";
     public static final String FORMAT_VERSION = "format_version";
+    public static final String INDEX = "index";
 
     private Json() {
     }
@@ -464,6 +466,7 @@ public class StudySerializationUtils {
             //case 2:
             //  stepOptionsJson = convertToThirdVersion(stepOptionsJson);
         }
+        convertSubtaskInfosToMap(stepOptionsJson);
         StepicWrappers.StepOptions stepOptions =
           new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()
             .fromJson(stepOptionsJson, StepicWrappers.StepOptions.class);
@@ -471,6 +474,30 @@ public class StudySerializationUtils {
         return stepOptions;
       }
 
+      private static JsonObject convertSubtaskInfosToMap(JsonObject stepOptionsJson) {
+        for (JsonElement taskFileElement : stepOptionsJson.getAsJsonArray(FILES)) {
+          JsonObject taskFileObject = taskFileElement.getAsJsonObject();
+          JsonArray placeholders = taskFileObject.getAsJsonArray(PLACEHOLDERS);
+          for (JsonElement placeholder : placeholders) {
+            JsonObject placeholderObject = placeholder.getAsJsonObject();
+            JsonArray infos = placeholderObject.getAsJsonArray(SUBTASK_INFOS);
+            Map<Integer, JsonObject> objectsToInsert = new HashMap<>();
+            for (JsonElement info : infos) {
+              JsonObject object = info.getAsJsonObject();
+              int index = object.getAsJsonPrimitive(INDEX).getAsInt();
+              objectsToInsert.put(index, object);
+            }
+            placeholderObject.remove(SUBTASK_INFOS);
+            JsonObject newInfos = new JsonObject();
+            placeholderObject.add(SUBTASK_INFOS, newInfos);
+            for (Map.Entry<Integer, JsonObject> entry : objectsToInsert.entrySet()) {
+              newInfos.add(entry.getKey().toString(), entry.getValue());
+            }
+          }
+        }
+        return stepOptionsJson;
+      }
+
       private static JsonObject convertToSecondVersion(JsonObject stepOptionsJson) {
         Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
         for (JsonElement taskFileElement : stepOptionsJson.getAsJsonArray(FILES)) {
@@ -527,18 +554,38 @@ public class StudySerializationUtils {
     }
 
     private static void convertToSubtaskInfo(JsonObject placeholderObject) {
-      JsonObject subtaskInfosObject = new JsonObject();
-      placeholderObject.add(SUBTASK_INFOS, subtaskInfosObject);
-      JsonObject subtaskInfo = new JsonObject();
-      subtaskInfosObject.add("0", subtaskInfo);
+      JsonArray subtaskInfos = new JsonArray();
+      placeholderObject.add(SUBTASK_INFOS, subtaskInfos);
       JsonArray hintsArray = new JsonArray();
       hintsArray.add(placeholderObject.getAsJsonPrimitive(HINT).getAsString());
       JsonArray additionalHints = placeholderObject.getAsJsonArray(ADDITIONAL_HINTS);
       if (additionalHints != null) {
         hintsArray.addAll(additionalHints);
       }
+      JsonObject subtaskInfo = new JsonObject();
+      subtaskInfos.add(subtaskInfo);
+      subtaskInfo.add(INDEX, new JsonPrimitive(0));
       subtaskInfo.add(HINTS, hintsArray);
       subtaskInfo.addProperty(POSSIBLE_ANSWER, placeholderObject.getAsJsonPrimitive(POSSIBLE_ANSWER).getAsString());
     }
+
+    public static class StepicAnswerPlaceholderAdapter implements JsonSerializer<AnswerPlaceholder> {
+      @Override
+      public JsonElement serialize(AnswerPlaceholder placeholder, Type typeOfSrc, JsonSerializationContext context) {
+        Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create();
+        JsonElement answerPlaceholderJson = gson.toJsonTree(placeholder);
+        JsonObject answerPlaceholderObject = answerPlaceholderJson.getAsJsonObject();
+        JsonObject subtaskInfos = answerPlaceholderObject.getAsJsonObject(SUBTASK_INFOS);
+        JsonArray infosArray = new JsonArray();
+        for (Map.Entry<String, JsonElement> entry : subtaskInfos.entrySet()) {
+          JsonObject subtaskInfo = entry.getValue().getAsJsonObject();
+          subtaskInfo.add(INDEX, new JsonPrimitive(Integer.valueOf(entry.getKey())));
+          infosArray.add(subtaskInfo);
+        }
+        answerPlaceholderObject.remove(SUBTASK_INFOS);
+        answerPlaceholderObject.add(SUBTASK_INFOS, infosArray);
+        return answerPlaceholderJson;
+      }
+    }
   }
 }
index c25955f2bc5d3afb65e5d5a741820a90a2595757..3821f4bc8af50e5e6e677f77d78928b987727b2b 100644 (file)
@@ -12,8 +12,10 @@ import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.openapi.vfs.VfsUtil;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.vfs.VirtualFileFilter;
+import com.jetbrains.edu.learning.StudySerializationUtils;
 import com.jetbrains.edu.learning.core.EduNames;
 import com.jetbrains.edu.learning.core.EduUtils;
+import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
 import com.jetbrains.edu.learning.courseFormat.Course;
 import com.jetbrains.edu.learning.courseFormat.Lesson;
 import com.jetbrains.edu.learning.courseFormat.Task;
@@ -118,7 +120,7 @@ public class CCStepicConnector {
       public boolean accept(VirtualFile file) {
         final String name = file.getName();
         return !name.contains(EduNames.LESSON) && !name.equals(EduNames.COURSE_META_FILE) && !name.equals(EduNames.HINTS) &&
-          !"pyc".equals(file.getExtension()) && !file.isDirectory() && !name.equals(EduNames.TEST_HELPER) && !name.startsWith(".");
+               !"pyc".equals(file.getExtension()) && !file.isDirectory() && !name.equals(EduNames.TEST_HELPER) && !name.startsWith(".");
       }
     });
 
@@ -328,7 +330,8 @@ public class CCStepicConnector {
 
   public static void postTask(final Project project, @NotNull final Task task, final int lessonId) {
     final HttpPost request = new HttpPost(EduStepicNames.STEPIC_API_URL + "/step-sources");
-    final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create();
+    final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().
+      registerTypeAdapter(AnswerPlaceholder.class, new StudySerializationUtils.Json.StepicAnswerPlaceholderAdapter()).create();
     ApplicationManager.getApplication().invokeLater(() -> {
       final String requestBody = gson.toJson(new StepicWrappers.StepSourceWrapper(project, task, lessonId));
       request.setEntity(new StringEntity(requestBody, ContentType.APPLICATION_JSON));
index facaedf765b32b9e3e3fd8434a82cf04d994d446..ad4485b852b865ded90e33509ec8af87f254933b 100644 (file)
                   "hint": "[\"Type your name here.\"]",
                   "offset": 32,
                   "length": 14,
-                  "subtask_infos": {
-                    "0": {
+                  "subtask_infos": [{
+                      "index" : 0,
                       "hints": ["Type your name here."],
                       "possible_answer": "Liana"
                     }
-                  }
+                  ]
                 }
               ],
               "text": "print(\"Hello, world! My name is type your name\")\n",
index e8ac7887c10ec0f05ca32dbdc37e8898886f59bc..147620c7efefd96aa241eb06e490b6806ef7c088 100644 (file)
                   "hint": "[\"Type your name here.\"]",
                   "offset": 32,
                   "length": 14,
-                  "subtask_infos": {
-                    "0": {
-                      "hints": ["Type your name here."],
+                  "subtask_infos": [
+                    {
+                      "index": 0,
+                      "hints": [
+                        "Type your name here."
+                      ],
                       "possible_answer": "Liana"
                     },
-                    "1": {
-                      "hints":[],
+                    {
+                      "index": 1,
+                      "hints": [],
                       "possible_answer": "miss X"
                     }
-                  }
+                  ]
                 }
               ],
               "text": "print(\"Hello, world! My name is type your name\")\n",
diff --git a/python/educational-core/student/testData/stepic/placeholder.json b/python/educational-core/student/testData/stepic/placeholder.json
new file mode 100644 (file)
index 0000000..0c4799b
--- /dev/null
@@ -0,0 +1,28 @@
+{
+  "offset": 1,
+  "length": 10,
+  "subtask_infos": [
+    {
+      "hints": [
+        "hint 1",
+        "hint 2"
+      ],
+      "possible_answer": "answer1",
+      "placeholder_text": "type here",
+      "has_frame": true,
+      "need_insert_text": true,
+      "index": 0
+    },
+    {
+      "hints": [
+        "hint 11",
+        "hint 22"
+      ],
+      "possible_answer": "answer2",
+      "placeholder_text": "type here1",
+      "has_frame": true,
+      "need_insert_text": true,
+      "index": 1
+    }
+  ]
+}
\ No newline at end of file
index 313303990950da5f14683e278f20e2122fe5b05c..f333d28933c5d4e05d315068896d0c206a1335e0 100644 (file)
@@ -1,8 +1,11 @@
 package com.jetbrains.edu.learning.stepic;
 
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.testFramework.PlatformTestUtil;
 import com.intellij.util.containers.ContainerUtil;
+import com.jetbrains.edu.learning.StudySerializationUtils;
 import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
 import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholderSubtaskInfo;
 import com.jetbrains.edu.learning.courseFormat.TaskFile;
@@ -62,7 +65,33 @@ public class StudyStepicFormatTest {
     assertNotNull(container.courses);
     assertTrue("Incorrect number of courses", container.courses.size() == 4);
     List<CourseInfo> filtered = ContainerUtil.filter(container.courses, info -> EduStepicConnector.canBeOpened(info));
-    assertEquals(ContainerUtil.newArrayList("Adaptive Python", "Introduction to Python", "format2"), ContainerUtil.map(filtered, CourseInfo::getName));
+    assertEquals(ContainerUtil.newArrayList("Adaptive Python", "Introduction to Python", "format2"),
+                 ContainerUtil.map(filtered, CourseInfo::getName));
+  }
+
+  @Test
+  public void placeholderSerialization() throws IOException {
+    final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().
+      registerTypeAdapter(AnswerPlaceholder.class, new StudySerializationUtils.Json.StepicAnswerPlaceholderAdapter()).create();
+    AnswerPlaceholder answerPlaceholder = new AnswerPlaceholder();
+    answerPlaceholder.setOffset(1);
+    answerPlaceholder.setLength(10);
+    AnswerPlaceholderSubtaskInfo info1 = createSubtaskInfo("type here", "answer1", ContainerUtil.list("hint 1", "hint 2"));
+    AnswerPlaceholderSubtaskInfo info2 = createSubtaskInfo("type here1", "answer2", ContainerUtil.list("hint 11", "hint 22"));
+    answerPlaceholder.setSubtaskInfos(ContainerUtil.newHashMap(ContainerUtil.list(0, 1), ContainerUtil.list(info1, info2)));
+    final String placeholderSerialization = gson.toJson(answerPlaceholder);
+    String expected = FileUtil.loadFile(new File(getTestDataPath(), "placeholder.json"));
+    assertEquals(expected, placeholderSerialization);
+
+  }
+
+  private static AnswerPlaceholderSubtaskInfo createSubtaskInfo(String placeholderText, String possibleAnswer, List<String> hints) {
+    AnswerPlaceholderSubtaskInfo info = new AnswerPlaceholderSubtaskInfo();
+    info.setPlaceholderText(placeholderText);
+    info.setPossibleAnswer(possibleAnswer);
+    info.setHints(hints);
+    info.setNeedInsertText(true);
+    return info;
   }
 
   @NotNull