diff --git a/python/educational/course-creator/resources/META-INF/plugin.xml b/python/educational/course-creator/resources/META-INF/plugin.xml index 8e7935ce8336..ed6c1ef33d23 100644 --- a/python/educational/course-creator/resources/META-INF/plugin.xml +++ b/python/educational/course-creator/resources/META-INF/plugin.xml @@ -78,6 +78,11 @@ + + + + + \ No newline at end of file diff --git a/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java b/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java new file mode 100644 index 000000000000..2947e1f0f25b --- /dev/null +++ b/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java @@ -0,0 +1,211 @@ +package com.jetbrains.edu.coursecreator.actions; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; +import com.intellij.icons.AllIcons; +import com.intellij.ide.projectView.ProjectView; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileChooser.FileChooser; +import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.platform.templates.github.ZipUtil; +import com.jetbrains.edu.EduDocumentListener; +import com.jetbrains.edu.EduNames; +import com.jetbrains.edu.courseFormat.*; +import com.jetbrains.edu.coursecreator.CCProjectService; +import org.jetbrains.annotations.NotNull; + +import java.io.*; +import java.util.Map; + +public class CCFromCourseArchive extends DumbAwareAction { + private static final Logger LOG = Logger.getInstance(CCFromCourseArchive.class.getName()); + + public CCFromCourseArchive() { + super("Unpack Course Archive", "Unpack Course Archive", AllIcons.FileTypes.Archive); + } + + @Override + public void update(@NotNull AnActionEvent e) { + CCProjectService.setCCActionAvailable(e); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + final Project project = e.getData(CommonDataKeys.PROJECT); + if (project == null) { + return; + } + unpackCourseArchive(project); + } + + private static void unpackCourseArchive(final Project project) { + FileChooserDescriptor descriptor = new FileChooserDescriptor(true, true, true, true, true, true); + + final VirtualFile virtualFile = FileChooser.chooseFile(descriptor, project, null); + if (virtualFile == null) { + return; + } + final String basePath = project.getBasePath(); + if (basePath == null) return; + final CCProjectService service = CCProjectService.getInstance(project); + Reader reader; + try { + ZipUtil.unzip(null, new File(basePath), new File(virtualFile.getPath()), null, null, true); + reader = new InputStreamReader(new FileInputStream(new File(basePath, "course.json"))); + Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); + Course course = gson.fromJson(reader, Course.class); + service.setCourse(course); + project.getBaseDir().refresh(false, true); + int index = 1; + int taskIndex = 1; + for (Lesson lesson : course.getLessons()) { + final VirtualFile lessonDir = project.getBaseDir().findChild(EduNames.LESSON + String.valueOf(index)); + lesson.setIndex(index); + if (lessonDir == null) continue; + for (Task task : lesson.getTaskList()) { + final VirtualFile taskDir = lessonDir.findChild(EduNames.TASK + String.valueOf(taskIndex)); + task.setIndex(taskIndex); + if (taskDir == null) continue; + for (final Map.Entry entry : task.getTaskFiles().entrySet()) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + createAnswerFile(project, taskDir, taskDir, entry); + } + }); + } + taskIndex += 1; + } + index += 1; + taskIndex = 1; + } + } + catch (FileNotFoundException e) { + LOG.error(e.getMessage()); + } + catch (IOException e) { + LOG.error(e.getMessage()); + } + catch (JsonSyntaxException e) { + LOG.error(e.getMessage()); + } + synchronize(project); + } + + public static void createAnswerFile(@NotNull final Project project, + @NotNull final VirtualFile userFileDir, + @NotNull final VirtualFile answerFileDir, + @NotNull final Map.Entry taskFileEntry) { + final String name = taskFileEntry.getKey(); + final TaskFile taskFile = taskFileEntry.getValue(); + VirtualFile file = userFileDir.findChild(name); + assert file != null; + String answerFileName = file.getNameWithoutExtension() + ".answer." + file.getExtension(); + VirtualFile answerFile = answerFileDir.findChild(answerFileName); + if (answerFile != null) { + try { + answerFile.delete(project); + } + catch (IOException e) { + LOG.error(e); + } + } + try { + answerFile = userFileDir.createChildData(project, answerFileName); + } + catch (IOException e) { + LOG.error(e); + } + if (answerFile == null) return; + + final Document originDocument = FileDocumentManager.getInstance().getDocument(file); + if (originDocument == null) { + return; + } + final Document document = FileDocumentManager.getInstance().getDocument(answerFile); + if (document == null) return; + + CommandProcessor.getInstance().executeCommand(project, new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + document.replaceString(0, document.getTextLength(), originDocument.getCharsSequence()); + } + }); + } + }, "Create answer document", "Create answer document"); + EduDocumentListener listener = new EduDocumentListener(taskFile, false); + document.addDocumentListener(listener); + taskFile.sortAnswerPlaceholders(); + for (int i = taskFile.getAnswerPlaceholders().size() - 1; i >= 0; i--) { + final AnswerPlaceholder answerPlaceholder = taskFile.getAnswerPlaceholders().get(i); + replaceAnswerPlaceholder(project, document, answerPlaceholder); + } + CommandProcessor.getInstance().executeCommand(project, new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + FileDocumentManager.getInstance().saveDocument(document); + } + }); + } + }, "x", "qwe"); + document.removeDocumentListener(listener); + } + + private static void replaceAnswerPlaceholder(@NotNull final Project project, + @NotNull final Document document, + @NotNull final AnswerPlaceholder answerPlaceholder) { + final int offset = answerPlaceholder.getRealStartOffset(document); + CommandProcessor.getInstance().executeCommand(project, new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + final String text = document.getText(TextRange.create(offset, offset + answerPlaceholder.getLength())); + answerPlaceholder.setTaskText(text); + final VirtualFile hints = project.getBaseDir().findChild("hints"); + if (hints != null) { + final String hintFile = answerPlaceholder.getHint(); + final VirtualFile virtualFile = hints.findChild(hintFile); + if (virtualFile != null) { + final Document hintDocument = FileDocumentManager.getInstance().getDocument(virtualFile); + if (hintDocument != null) { + final String hintText = hintDocument.getText(); + answerPlaceholder.setHint(hintText); + } + } + } + + document.replaceString(offset, offset + answerPlaceholder.getLength(), answerPlaceholder.getPossibleAnswer()); + FileDocumentManager.getInstance().saveDocument(document); + } + }); + } + }, "x", "qwe"); + } + + private static void synchronize(@NotNull final Project project) { + VirtualFileManager.getInstance().refreshWithoutFileWatcher(true); + ProjectView.getInstance(project).refresh(); + } + +} \ No newline at end of file diff --git a/python/educational/src/com/jetbrains/edu/courseFormat/Lesson.java b/python/educational/src/com/jetbrains/edu/courseFormat/Lesson.java index 772b190bf289..e33ba3d397d5 100644 --- a/python/educational/src/com/jetbrains/edu/courseFormat/Lesson.java +++ b/python/educational/src/com/jetbrains/edu/courseFormat/Lesson.java @@ -19,7 +19,6 @@ public class Lesson { public List tags; @Transient Boolean is_public; - @SerializedName("title") @Expose private String name; @Expose