diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java index 8703e3612117..cd09f521b621 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java @@ -220,7 +220,7 @@ public class CCCreateCourseArchive extends DumbAwareAction { @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") private static void generateJson(VirtualFile parentDir, Course course) { final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation(). - registerTypeAdapter(Task.class, new StudySerializationUtils.Json.TaskSerializer()).create(); + registerTypeAdapter(Task.class, new StudySerializationUtils.Json.TaskAdapter()).create(); final String json = gson.toJson(course); final File courseJson = new File(parentDir.getPath(), EduNames.COURSE_META_FILE); OutputStreamWriter outputStreamWriter = null; diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java index 11334cf12bdf..aa26e49c5bcc 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java @@ -70,7 +70,7 @@ public class CCFromCourseArchive extends DumbAwareAction { reader = new InputStreamReader(new FileInputStream(courseMetaFile)); Gson gson = new GsonBuilder() .registerTypeAdapter(Course.class, new StudySerializationUtils.Json.CourseTypeAdapter(courseMetaFile)) - .registerTypeAdapter(Task.class, new StudySerializationUtils.Json.TaskDeserializer()) + .registerTypeAdapter(Task.class, new StudySerializationUtils.Json.TaskAdapter()) .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create(); Course course = gson.fromJson(reader, Course.class); diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCGetCourseFromStepic.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCGetCourseFromStepic.java index 957e47954511..33a0417fcc42 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCGetCourseFromStepic.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCGetCourseFromStepic.java @@ -20,8 +20,8 @@ import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.CourseInfo; import com.jetbrains.edu.learning.courseFormat.Lesson; +import com.jetbrains.edu.learning.courseFormat.RemoteCourse; import com.jetbrains.edu.learning.courseFormat.TaskFile; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import com.jetbrains.edu.learning.courseGeneration.StudyGenerator; @@ -58,7 +58,7 @@ public class CCGetCourseFromStepic extends DumbAwareAction { private static void createCourse(Project project, String courseId) { final VirtualFile baseDir = project.getBaseDir(); - final CourseInfo info = CCStepicConnector.getCourseInfo(courseId); + final RemoteCourse info = CCStepicConnector.getCourseInfo(courseId); if (info == null) return; final Course course = EduStepicConnector.getCourse(project, info); diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCPushCourse.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCPushCourse.java index 156d2f477c4a..24807506c8a6 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCPushCourse.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCPushCourse.java @@ -14,8 +14,8 @@ import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.coursecreator.stepik.CCStepicConnector; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.CourseInfo; import com.jetbrains.edu.learning.courseFormat.Lesson; +import com.jetbrains.edu.learning.courseFormat.RemoteCourse; import com.jetbrains.edu.learning.statistics.EduUsagesCollector; import org.jetbrains.annotations.NotNull; @@ -33,11 +33,8 @@ public class CCPushCourse extends DumbAwareAction { presentation.setEnabledAndVisible(project != null && CCUtils.isCourseCreator(project)); if (project != null) { final Course course = StudyTaskManager.getInstance(project).getCourse(); - if (course != null) { - final int id = course.getId(); - if (id > 0) { - presentation.setText("Update Course on Stepik"); - } + if (course instanceof RemoteCourse) { + presentation.setText("Update Course on Stepik"); } } } @@ -53,7 +50,7 @@ public class CCPushCourse extends DumbAwareAction { if (course == null) { return; } - if (course.getId() > 0) { + if (course instanceof RemoteCourse) { ProgressManager.getInstance().run(new Task.Modal(project, "Updating Course", true) { @Override public void run(@NotNull ProgressIndicator indicator) { @@ -62,10 +59,9 @@ public class CCPushCourse extends DumbAwareAction { CCStepicConnector.updateLesson(project, lesson); } else { - final CourseInfo info = CourseInfo.fromCourse(course); final int lessonId = CCStepicConnector.postLesson(project, lesson); if (lessonId != -1) { - final List sections = info.getSections(); + final List sections = ((RemoteCourse)course).getSections(); final Integer sectionId = sections.get(sections.size() - 1); CCStepicConnector.postUnit(lessonId, lesson.getIndex(), sectionId); } diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCPushLesson.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCPushLesson.java index 1c203cf6e85c..234a136b4091 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCPushLesson.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCPushLesson.java @@ -15,8 +15,8 @@ import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.coursecreator.stepik.CCStepicConnector; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.CourseInfo; import com.jetbrains.edu.learning.courseFormat.Lesson; +import com.jetbrains.edu.learning.courseFormat.RemoteCourse; import com.jetbrains.edu.learning.stepic.EduStepicNames; import org.jetbrains.annotations.NotNull; @@ -36,7 +36,7 @@ public class CCPushLesson extends DumbAwareAction { return; } final Course course = StudyTaskManager.getInstance(project).getCourse(); - if (course == null) { + if (course == null || !(course instanceof RemoteCourse)) { return; } if (!course.getCourseMode().equals(CCUtils.COURSE_MODE)) return; @@ -45,7 +45,7 @@ public class CCPushLesson extends DumbAwareAction { return; } final Lesson lesson = course.getLesson(lessonDir.getName()); - if (lesson != null && course.getId() > 0) { + if (lesson != null && ((RemoteCourse)course).getId() > 0) { e.getPresentation().setEnabledAndVisible(true); if (lesson.getId() <= 0) { e.getPresentation().setText("Upload Lesson to Stepik"); @@ -61,7 +61,7 @@ public class CCPushLesson extends DumbAwareAction { return; } final Course course = StudyTaskManager.getInstance(project).getCourse(); - if (course == null) { + if (course == null || !(course instanceof RemoteCourse)) { return; } PsiDirectory lessonDir = DirectoryChooserUtil.getOrChooseDirectory(view); @@ -80,9 +80,8 @@ public class CCPushLesson extends DumbAwareAction { CCStepicConnector.updateLesson(project, lesson); } else { - final CourseInfo info = CourseInfo.fromCourse(course); final int lessonId = CCStepicConnector.postLesson(project, lesson); - final List sections = info.getSections(); + final List sections = ((RemoteCourse)course).getSections(); final Integer sectionId = sections.get(sections.size()-1); CCStepicConnector.postUnit(lessonId, lesson.getIndex(), sectionId); } diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCPushTask.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCPushTask.java index 7346b1286cf6..725c55e4ba05 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCPushTask.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCPushTask.java @@ -12,11 +12,12 @@ import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.coursecreator.stepik.CCStepicConnector; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; -import com.jetbrains.edu.coursecreator.stepik.CCStepicConnector; +import com.jetbrains.edu.learning.courseFormat.RemoteCourse; import com.jetbrains.edu.learning.stepic.EduStepicNames; import org.jetbrains.annotations.NotNull; @@ -34,7 +35,7 @@ public class CCPushTask extends DumbAwareAction { return; } final Course course = StudyTaskManager.getInstance(project).getCourse(); - if (course == null) { + if (course == null || !(course instanceof RemoteCourse)) { return; } if (!course.getCourseMode().equals(CCUtils.COURSE_MODE)) return; @@ -45,7 +46,7 @@ public class CCPushTask extends DumbAwareAction { final PsiDirectory lessonDir = taskDir.getParentDirectory(); if (lessonDir == null) return; final Lesson lesson = course.getLesson(lessonDir.getName()); - if (lesson != null && lesson.getId() > 0 && course.getId() > 0) { + if (lesson != null && lesson.getId() > 0 && ((RemoteCourse)course).getId() > 0) { e.getPresentation().setEnabledAndVisible(true); final com.jetbrains.edu.learning.courseFormat.tasks.Task task = lesson.getTask(taskDir.getName()); if (task.getStepId() <= 0) { diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/stepik/CCStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/stepik/CCStepicConnector.java index d052e1bbbe51..c5ac73922cb9 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/stepik/CCStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/stepik/CCStepicConnector.java @@ -10,11 +10,12 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.learning.StudySerializationUtils; +import com.jetbrains.edu.learning.StudyTaskManager; 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.CourseInfo; import com.jetbrains.edu.learning.courseFormat.Lesson; +import com.jetbrains.edu.learning.courseFormat.RemoteCourse; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import com.jetbrains.edu.learning.stepic.EduStepicAuthorizedClient; import com.jetbrains.edu.learning.stepic.EduStepicNames; @@ -43,7 +44,7 @@ public class CCStepicConnector { private CCStepicConnector() { } - public static CourseInfo getCourseInfo(String courseId) { + public static RemoteCourse getCourseInfo(String courseId) { final String url = EduStepicNames.COURSES + "/" + courseId; try { final StepicWrappers.CoursesContainer coursesContainer = @@ -103,8 +104,10 @@ public class CCStepicConnector { LOG.error("Failed to push " + responseString); return; } - final CourseInfo postedCourse = new Gson().fromJson(responseString, StepicWrappers.CoursesContainer.class).courses.get(0); - course.setId(postedCourse.getId()); + final RemoteCourse postedCourse = new Gson().fromJson(responseString, StepicWrappers.CoursesContainer.class).courses.get(0); + postedCourse.setLessons(course.getLessons(true)); + postedCourse.setAuthors(course.getAuthors()); + postedCourse.setCourseMode(CCUtils.COURSE_MODE); final int sectionId = postModule(postedCourse.getId(), 1, String.valueOf(postedCourse.getName())); int position = 1; for (Lesson lesson : course.getLessons()) { @@ -116,6 +119,7 @@ public class CCStepicConnector { position += 1; } ApplicationManager.getApplication().runReadAction(() -> postAdditionalFiles(course, project, postedCourse.getId())); + StudyTaskManager.getInstance(project).setCourse(postedCourse); } catch (IOException e) { LOG.error(e.getMessage()); @@ -241,7 +245,7 @@ public class CCStepicConnector { LOG.error("Failed to push " + responseString); return -1; } - final Lesson postedLesson = new Gson().fromJson(responseString, Course.class).getLessons().get(0); + final Lesson postedLesson = new Gson().fromJson(responseString, RemoteCourse.class).getLessons().get(0); for (Integer step : postedLesson.steps) { deleteTask(step); } @@ -279,7 +283,7 @@ public class CCStepicConnector { LOG.error("Failed to push " + responseString); return 0; } - final Lesson postedLesson = new Gson().fromJson(responseString, Course.class).getLessons().get(0); + final Lesson postedLesson = new Gson().fromJson(responseString, RemoteCourse.class).getLessons(true).get(0); lesson.setId(postedLesson.getId()); for (Task task : lesson.getTaskList()) { final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/StudyProjectComponent.java b/python/educational-core/src/com/jetbrains/edu/learning/StudyProjectComponent.java index 335857dfc4a0..9a7b90f2c48b 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/StudyProjectComponent.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/StudyProjectComponent.java @@ -146,10 +146,8 @@ public class StudyProjectComponent implements ProjectComponent { private void updateCourse() { final Course currentCourse = StudyTaskManager.getInstance(myProject).getCourse(); - final CourseInfo info = CourseInfo.fromCourse(currentCourse); - if (info == null) return; - - final Course course = EduStepicConnector.getCourse(myProject, info); + if (currentCourse == null || !(currentCourse instanceof RemoteCourse)) return; + final Course course = EduStepicConnector.getCourse(myProject, (RemoteCourse)currentCourse); if (course == null) return; course.initCourse(false); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/StudySerializationUtils.java b/python/educational-core/src/com/jetbrains/edu/learning/StudySerializationUtils.java index 1a8165ebcc16..dda547cebe20 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/StudySerializationUtils.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/StudySerializationUtils.java @@ -16,6 +16,7 @@ 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.RemoteCourse; import com.jetbrains.edu.learning.courseFormat.StudyStatus; import com.jetbrains.edu.learning.courseFormat.tasks.*; import com.jetbrains.edu.learning.stepic.EduStepicConnector; @@ -62,6 +63,7 @@ public class StudySerializationUtils { public static class Xml { public final static String COURSE_ELEMENT = "courseElement"; public final static String MAIN_ELEMENT = "StudyTaskManager"; + public final static String REMOTE_COURSE = "RemoteCourse"; public static final String MAP = "map"; public static final String KEY = "key"; public static final String VALUE = "value"; @@ -498,7 +500,7 @@ public class StudySerializationUtils { } } } - return new GsonBuilder().registerTypeAdapter(Task.class, new TaskDeserializer()).create().fromJson(json, Course.class); + return new GsonBuilder().registerTypeAdapter(Task.class, new TaskAdapter()).create().fromJson(json, Course.class); } private static void convertToAbsoluteOffset(Document document, JsonElement placeholder) { @@ -676,7 +678,23 @@ public class StudySerializationUtils { subtaskInfo.addProperty(POSSIBLE_ANSWER, placeholderObject.getAsJsonPrimitive(POSSIBLE_ANSWER).getAsString()); } - public static class TaskSerializer implements JsonSerializer { + public static class StepikCourseSerializer implements JsonSerializer, JsonDeserializer { + + @Override + public Course deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + return null; + } + + @Override + public JsonElement serialize(Course src, Type typeOfSrc, JsonSerializationContext context) { + if (src instanceof RemoteCourse) { + context.serialize(src, RemoteCourse.class); + } + return context.serialize(src); + } + } + + public static class TaskAdapter implements JsonSerializer, JsonDeserializer { @Override public JsonElement serialize(Task src, Type typeOfSrc, JsonSerializationContext context) { @@ -686,9 +704,6 @@ public class StudySerializationUtils { task.add(TASK_TYPE, new JsonPrimitive(src.getTaskType())); return task; } - } - - public static class TaskDeserializer implements JsonDeserializer { @Override public Task deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { diff --git a/python/educational-core/src/com/jetbrains/edu/learning/StudyTaskManager.java b/python/educational-core/src/com/jetbrains/edu/learning/StudyTaskManager.java index 8b981f97cc74..a6518bad3f00 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/StudyTaskManager.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/StudyTaskManager.java @@ -24,6 +24,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import static com.jetbrains.edu.learning.StudySerializationUtils.Xml.REMOTE_COURSE; + /** * Implementation of class which contains all the information * about study in context of current project @@ -115,10 +117,32 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb if (myCourse == null) { return null; } + + return serialize(); + } + + @NotNull + private Element serialize() { Element el = new Element("taskManager"); - Element courseElement = new Element(StudySerializationUtils.Xml.MAIN_ELEMENT); - XmlSerializer.serializeInto(this, courseElement); - el.addContent(courseElement); + Element taskManagerElement = new Element(StudySerializationUtils.Xml.MAIN_ELEMENT); + XmlSerializer.serializeInto(this, taskManagerElement); + + if (myCourse instanceof RemoteCourse) { + try { + Element course = new Element(REMOTE_COURSE); + //noinspection RedundantCast + XmlSerializer.serializeInto((RemoteCourse)myCourse, course); + + final Element xmlCourse = StudySerializationUtils.Xml.getChildWithName(taskManagerElement, StudySerializationUtils.COURSE); + xmlCourse.removeContent(); + xmlCourse.addContent(course); + } + catch (StudySerializationUtils.StudyUnrecognizedFormatException e) { + LOG.error("Failed to serialize remote course"); + } + } + + el.addContent(taskManagerElement); return el; } @@ -143,7 +167,7 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb //case 5: // state = StudySerializationUtils.Xml.convertToSixthVersion(state, myProject); } - XmlSerializer.deserializeInto(this, state.getChild(StudySerializationUtils.Xml.MAIN_ELEMENT)); + deserialize(state); VERSION = CURRENT_VERSION; if (myCourse != null) { myCourse.initCourse(true); @@ -154,6 +178,18 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb } } + private void deserialize(Element state) throws StudySerializationUtils.StudyUnrecognizedFormatException { + final Element taskManagerElement = state.getChild(StudySerializationUtils.Xml.MAIN_ELEMENT); + XmlSerializer.deserializeInto(this, taskManagerElement); + final Element xmlCourse = StudySerializationUtils.Xml.getChildWithName(taskManagerElement, StudySerializationUtils.COURSE); + final Element remoteCourseElement = xmlCourse.getChild(REMOTE_COURSE); + if (remoteCourseElement != null) { + final RemoteCourse remoteCourse = new RemoteCourse(); + XmlSerializer.deserializeInto(remoteCourse, remoteCourseElement); + myCourse = remoteCourse; + } + } + public static StudyTaskManager getInstance(@NotNull final Project project) { return ServiceManager.getService(project, StudyTaskManager.class); } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/Course.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/Course.java index 44976a6078dc..de5a18fd26f2 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/Course.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/Course.java @@ -8,32 +8,29 @@ import com.intellij.util.xmlb.XmlSerializer; import com.intellij.util.xmlb.annotations.Transient; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; -import com.jetbrains.edu.learning.courseFormat.tasks.Task; -import com.jetbrains.edu.learning.stepic.EduStepicConnector; import com.jetbrains.edu.learning.stepic.StepicUser; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Date; import java.util.List; import java.util.stream.Collectors; public class Course { - @Expose private List lessons = new ArrayList<>(); - @Expose private List authors = new ArrayList<>(); - @Expose private String description; - @Expose private String name; - @Expose private int id; - @Expose @SerializedName("update_date") private Date myUpdateDate; - @Expose private boolean isAdaptive = false; - @Expose @SerializedName("language") private String myLanguage = "Python"; + public static final Course INVALID_COURSE = new Course(); + + @Expose protected List lessons = new ArrayList<>(); + transient private List authors = new ArrayList<>(); + @Expose @SerializedName("summary") private String description; + @Expose @SerializedName("title") private String name; + + transient private String myLanguage = "Python"; //this field is used to distinguish ordinary and CheckIO projects, //"PyCharm" is used here for historical reasons private String courseType = EduNames.PYCHARM; - private String courseMode = EduNames.STUDY; //this field is used to distinguish study and course creator modes + protected String courseMode = EduNames.STUDY; //this field is used to distinguish study and course creator modes public Course() {} @@ -136,35 +133,10 @@ public class Course { } public boolean isUpToDate() { - if (id == 0) return true; - if (!EduNames.STUDY.equals(courseMode)) return true; - final Date date = EduStepicConnector.getCourseUpdateDate(id); - if (date == null) return true; - if (myUpdateDate == null) return true; - if (date.after(myUpdateDate)) return false; - for (Lesson lesson : lessons) { - if (!lesson.isUpToDate()) return false; - } return true; } - public void setUpdated() { - setUpdateDate(EduStepicConnector.getCourseUpdateDate(id)); - for (Lesson lesson : lessons) { - lesson.setUpdateDate(EduStepicConnector.getLessonUpdateDate(lesson.getId())); - for (Task task : lesson.getTaskList()) { - task.setUpdateDate(EduStepicConnector.getTaskUpdateDate(task.getStepId())); - } - } - } - - public void setUpdateDate(Date date) { - myUpdateDate = date; - } - - public Date getUpdateDate() { - return myUpdateDate; - } + public void setUpdated() {} public Language getLanguageById() { return Language.findLanguageByID(getLanguageID()); @@ -209,22 +181,6 @@ public class Course { this.courseType = courseType; } - public boolean isAdaptive() { - return isAdaptive; - } - - public void setAdaptive(boolean adaptive) { - isAdaptive = adaptive; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - public String getCourseMode() { return courseMode; } @@ -235,8 +191,17 @@ public class Course { public Course copy() { Element element = XmlSerializer.serialize(this); - Course copy = XmlSerializer.deserialize(element, Course.class); + Course copy = XmlSerializer.deserialize(element, getClass()); copy.initCourse(true); return copy; } + + public boolean isAdaptive() { + return false; + } + + @Override + public String toString() { + return getName(); + } } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/CourseInfo.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/CourseInfo.java deleted file mode 100644 index 89fe65b8941e..000000000000 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/CourseInfo.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.jetbrains.edu.learning.courseFormat; - -import com.google.gson.annotations.SerializedName; -import com.jetbrains.edu.learning.stepic.EduStepicConnector; -import com.jetbrains.edu.learning.stepic.StepicUser; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -/** - * Implementation of class which contains information to be shawn in course description in tool window - * and when project is being created - */ -public class CourseInfo { - public static final CourseInfo INVALID_COURSE = new CourseInfo(); - - @SerializedName("title") private String myName; - int id; - boolean isAdaptive; - @SerializedName("is_public") boolean isPublic; - List sections; - List instructors = new ArrayList<>(); - - List myAuthors = new ArrayList<>(); - @SerializedName("summary") private String myDescription; - @SerializedName("course_format") private String myType = "pycharm" + EduStepicConnector.CURRENT_VERSION + " Python"; //course type in format "pycharm " - @Nullable private String username; - - @SerializedName("update_date") private Date updateDate; - @SerializedName("is_idea_compatible") private boolean isCompatible = true; - - public String getName() { - return myName; - } - - @NotNull - public List getAuthors() { - return myAuthors; - } - - public String getDescription() { - return myDescription; - } - - public String getType() { - return myType; - } - - @Override - public String toString() { - return getName(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - CourseInfo that = (CourseInfo)o; - final String thatName = that.getName(); - final String thatDescription = that.getDescription(); - if (thatName == null && getName() == null && thatDescription == null && - getDescription() == null) { - return true; - } - if (thatName == null || thatDescription == null) { - return false; - } - return thatName.equals(getName()) - && thatDescription.equals(myDescription); - } - - @Override - public int hashCode() { - int result = getName() != null ? getName().hashCode() : 0; - result = 31 * result + (myDescription != null ? myDescription.hashCode() : 0); - return result; - } - - @Nullable - public String getUsername() { - return username; - } - - public void setUsername(@Nullable String username) { - this.username = username; - } - - public void setName(String name) { - myName = name; - } - - public void setAuthors(List authors) { - myAuthors = authors; - for (StepicUser author : authors) { - if (author.getId() > 0) { - instructors.add(author.getId()); - } - } - } - - public void addAuthor(StepicUser author) { - if (myAuthors == null) { - myAuthors = new ArrayList<>(); - } - myAuthors.add(author); - } - - public void setDescription(String description) { - myDescription = description; - } - - public void setType(String type) { - myType = type; - } - - public boolean isAdaptive() { - return isAdaptive; - } - - public void setAdaptive(boolean adaptive) { - isAdaptive = adaptive; - } - - public boolean isPublic() { - return isPublic; - } - - public void setPublic(boolean aPublic) { - isPublic = aPublic; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public Date getUpdateDate() { - return updateDate; - } - - public void setUpdateDate(Date updateDate) { - this.updateDate = updateDate; - } - - public static CourseInfo fromCourse(@Nullable final Course course) { - if (course == null) return null; - CourseInfo courseInfo = new CourseInfo(); - courseInfo.setName(course.getName()); - courseInfo.setDescription(course.getDescription()); - courseInfo.setAuthors(course.getAuthors()); - return courseInfo; - } - - public List getSections() { - return sections; - } - - public boolean isCompatible() { - return isCompatible; - } - - public void setCompatible(boolean compatible) { - isCompatible = compatible; - } - - public List getInstructors() { - return instructors; - } -} diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/RemoteCourse.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/RemoteCourse.java new file mode 100644 index 000000000000..01e764610e62 --- /dev/null +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/RemoteCourse.java @@ -0,0 +1,98 @@ +package com.jetbrains.edu.learning.courseFormat; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; +import com.jetbrains.edu.learning.core.EduNames; +import com.jetbrains.edu.learning.courseFormat.tasks.Task; +import com.jetbrains.edu.learning.stepic.EduStepicConnector; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class RemoteCourse extends Course { + //course type in format "pycharm " + @SerializedName("course_format") private String myType = "pycharm" + EduStepicConnector.CURRENT_VERSION + " Python"; + @SerializedName("is_idea_compatible") private boolean isCompatible = true; + List sections; + List instructors = new ArrayList<>(); + @Expose private int id; + @Expose @SerializedName("update_date") private Date myUpdateDate; + @Expose private boolean isAdaptive = false; + @SerializedName("is_public") boolean isPublic; + + public String getType() { + return myType; + } + + public List getSections() { + return sections; + } + + public void setSections(List sections) { + this.sections = sections; + } + + public void setInstructors(List instructors) { + this.instructors = instructors; + } + + public List getInstructors() { + return instructors; + } + + + public boolean isUpToDate() { + if (id == 0) return true; + if (!EduNames.STUDY.equals(courseMode)) return true; + final Date date = EduStepicConnector.getCourseUpdateDate(id); + if (date == null) return true; + if (myUpdateDate == null) return true; + if (date.after(myUpdateDate)) return false; + for (Lesson lesson : lessons) { + if (!lesson.isUpToDate()) return false; + } + return true; + } + + public void setUpdated() { + setUpdateDate(EduStepicConnector.getCourseUpdateDate(id)); + for (Lesson lesson : lessons) { + lesson.setUpdateDate(EduStepicConnector.getLessonUpdateDate(lesson.getId())); + for (Task task : lesson.getTaskList()) { + task.setUpdateDate(EduStepicConnector.getTaskUpdateDate(task.getStepId())); + } + } + } + + public void setUpdateDate(Date date) { + myUpdateDate = date; + } + + public Date getUpdateDate() { + return myUpdateDate; + } + + public boolean isAdaptive() { + return isAdaptive; + } + + public void setAdaptive(boolean adaptive) { + isAdaptive = adaptive; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public void copyCourseParameters(RemoteCourse course) { + setName(course.getName()); + + setUpdateDate(course.getUpdateDate()); + + } +} diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java b/python/educational-core/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java index 2eab0dba91b1..f57c22a5914a 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java @@ -23,7 +23,7 @@ import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.CourseInfo; +import com.jetbrains.edu.learning.courseFormat.RemoteCourse; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import com.jetbrains.edu.learning.statistics.EduUsagesCollector; import com.jetbrains.edu.learning.stepic.EduStepicConnector; @@ -41,12 +41,11 @@ import static com.jetbrains.edu.learning.StudyUtils.execCancelable; public class StudyProjectGenerator { private static final Logger LOG = Logger.getInstance(StudyProjectGenerator.class.getName()); private final List myListeners = ContainerUtil.newArrayList(); - private List myCourses = new ArrayList<>(); - private List myLocalCourses = new ArrayList<>(); + private List myCourses = new ArrayList<>(); private List myEnrolledCoursesIds = new ArrayList<>(); - protected CourseInfo mySelectedCourseInfo; + protected Course mySelectedCourse; - public void setCourses(List courses) { + public void setCourses(List courses) { myCourses = courses; } @@ -64,12 +63,12 @@ public class StudyProjectGenerator { return myEnrolledCoursesIds; } - public void setSelectedCourse(@NotNull final CourseInfo courseName) { - mySelectedCourseInfo = courseName; + public void setSelectedCourse(@NotNull final Course course) { + mySelectedCourse = course; } - public CourseInfo getSelectedCourseInfo() { - return mySelectedCourseInfo; + public Course getSelectedCourse() { + return mySelectedCourse; } public void generateProject(@NotNull final Project project, @NotNull final VirtualFile baseDir) { @@ -94,22 +93,18 @@ public class StudyProjectGenerator { @Nullable public Course getCourse(@NotNull final Project project) { - final CourseInfo info = mySelectedCourseInfo; - for (Course course : myLocalCourses) { - if (course.getName().equals(info.getName())){ - course.initCourse(false); - return course; - } - + if (mySelectedCourse instanceof RemoteCourse) { + return getCourseFromStepic(project, (RemoteCourse)mySelectedCourse); } - return getCourseFromStepic(project); + mySelectedCourse.initCourse(false); + return mySelectedCourse; } - private Course getCourseFromStepic(@NotNull Project project) { + private static RemoteCourse getCourseFromStepic(@NotNull Project project, RemoteCourse selectedCourse) { return ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> { ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true); return execCancelable(() -> { - final Course course = EduStepicConnector.getCourse(project, mySelectedCourseInfo); + final RemoteCourse course = EduStepicConnector.getCourse(project, selectedCourse); if (StudyUtils.isCourseValid(course)) { course.initCourse(false); } @@ -119,25 +114,25 @@ public class StudyProjectGenerator { } // Supposed to be called under progress - public List getCourses(boolean force) { + public List getCourses(boolean force) { if (force) { myCourses = execCancelable(() -> EduStepicConnector.getCourses(StepicUpdateSettings.getInstance().getUser())); } - if (myCourses == null || myCourses.isEmpty() || (myCourses.size() == 1 && myCourses.contains(CourseInfo.INVALID_COURSE))) { + if (myCourses == null || myCourses.isEmpty() || (myCourses.size() == 1 && myCourses.contains(Course.INVALID_COURSE))) { myCourses = Collections.singletonList(getBundledIntro()); } sortCourses(myCourses); return myCourses; } - public void sortCourses(List result) { + public void sortCourses(List result) { // sort courses so as to have non-adaptive courses in the beginning of the list Collections.sort(result, (c1, c2) -> { - if (mySelectedCourseInfo != null) { - if (mySelectedCourseInfo.equals(c1)) { + if (mySelectedCourse != null) { + if (mySelectedCourse.equals(c1)) { return -1; } - if (mySelectedCourseInfo.equals(c2)) { + if (mySelectedCourse.equals(c2)) { return 1; } } @@ -149,7 +144,7 @@ public class StudyProjectGenerator { } @NotNull - public List getCoursesUnderProgress(boolean force, @NotNull final String progressTitle, @NotNull final Project project) { + public List getCoursesUnderProgress(boolean force, @NotNull final String progressTitle, @NotNull final Project project) { try { return ProgressManager.getInstance() .runProcessWithProgressSynchronously(() -> { @@ -158,7 +153,7 @@ public class StudyProjectGenerator { }, progressTitle, true, project); } catch (RuntimeException e) { - return Collections.singletonList(CourseInfo.INVALID_COURSE); + return Collections.singletonList(Course.INVALID_COURSE); } } @@ -177,21 +172,21 @@ public class StudyProjectGenerator { } @Nullable - public CourseInfo getBundledIntro() { + public Course getBundledIntro() { final LanguageExtensionPoint[] extensions = Extensions.getExtensions(EduPluginConfigurator.EP_NAME, null); for (LanguageExtensionPoint extension : extensions) { final EduPluginConfigurator configurator = extension.getInstance(); final String path = configurator.getBundledCoursePath(); if (path != null) { - return getCourseInfo(path); + return getCourse(path); } } return null; } @Nullable - public CourseInfo addLocalCourse(String zipFilePath) { - final CourseInfo courseInfo = getCourseInfo(zipFilePath); + public Course addLocalCourse(String zipFilePath) { + final Course courseInfo = getCourse(zipFilePath); if (courseInfo != null) { myCourses.add(0, courseInfo); } @@ -199,22 +194,17 @@ public class StudyProjectGenerator { } @Nullable - public CourseInfo getCourseInfo(String zipFilePath) { + public Course getCourse(String zipFilePath) { try { final JBZipFile zipFile = new JBZipFile(zipFilePath); final JBZipEntry entry = zipFile.getEntry(EduNames.COURSE_META_FILE); byte[] bytes = entry.getData(); final String jsonText = new String(bytes, CharsetToolkit.UTF8_CHARSET); Gson gson = new GsonBuilder() - .registerTypeAdapter(Task.class, new StudySerializationUtils.Json.TaskDeserializer()) + .registerTypeAdapter(Task.class, new StudySerializationUtils.Json.TaskAdapter()) .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create(); - Course course = gson.fromJson(jsonText, Course.class); - final CourseInfo courseInfo = CourseInfo.fromCourse(course); - if (courseInfo != null) { - myLocalCourses.add(course); - } - return courseInfo; + return gson.fromJson(jsonText, Course.class); } catch (IOException e) { LOG.error("Failed to unzip course archive"); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseModuleBuilder.java b/python/educational-core/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseModuleBuilder.java index c630d13e910b..c6020344e10e 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseModuleBuilder.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/intellij/localCourses/EduCustomCourseModuleBuilder.java @@ -14,7 +14,6 @@ import com.intellij.openapi.util.InvalidDataException; import com.jetbrains.edu.learning.EduPluginConfigurator; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.CourseInfo; import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator; import com.jetbrains.edu.learning.intellij.generation.EduProjectGenerator; import org.jdom.JDOMException; @@ -27,7 +26,7 @@ import java.io.IOException; class EduCustomCourseModuleBuilder extends JavaModuleBuilder { private static final Logger LOG = Logger.getInstance(EduCustomCourseModuleBuilder.class); private EduProjectGenerator myGenerator = new EduProjectGenerator(); - private CourseInfo mySelectedCourse; + private Course mySelectedCourse; @Nullable @Override @@ -36,8 +35,7 @@ class EduCustomCourseModuleBuilder extends JavaModuleBuilder { if (module == null) { return null; } - String type = mySelectedCourse.getType(); - String languageName = type.substring("pycharm ".length()); + String languageName = mySelectedCourse.getLanguageID(); Language language = Language.findLanguageByID(languageName); if (language == null) { return module; @@ -87,7 +85,7 @@ class EduCustomCourseModuleBuilder extends JavaModuleBuilder { return ProjectWizardStepFactory.getInstance().createJavaSettingsStep(settingsStep, this, Conditions.alwaysTrue()); } - void setSelectedCourse(CourseInfo selectedCourse) { + void setSelectedCourse(Course selectedCourse) { mySelectedCourse = selectedCourse; } @@ -97,8 +95,7 @@ class EduCustomCourseModuleBuilder extends JavaModuleBuilder { throws InvalidDataException, IOException, ModuleWithNameAlreadyExists, JDOMException, ConfigurationException { Module baseModule = super.createModule(moduleModel); if (mySelectedCourse != null) { - String type = mySelectedCourse.getType(); - String languageName = type.substring("pycharm ".length()); + String languageName = mySelectedCourse.getLanguageID(); Language language = Language.findLanguageByID(languageName); if (language != null) { EduPluginConfigurator configurator = EduPluginConfigurator.INSTANCE.forLanguage(language); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/intellij/localCourses/EduLocalCoursePanel.java b/python/educational-core/src/com/jetbrains/edu/learning/intellij/localCourses/EduLocalCoursePanel.java index 35ac626e3230..790b2829865a 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/intellij/localCourses/EduLocalCoursePanel.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/intellij/localCourses/EduLocalCoursePanel.java @@ -2,7 +2,7 @@ package com.jetbrains.edu.learning.intellij.localCourses; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.ui.TextFieldWithBrowseButton; -import com.jetbrains.edu.learning.courseFormat.CourseInfo; +import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator; import com.jetbrains.edu.learning.ui.StudyNewProjectPanel; @@ -25,7 +25,7 @@ public class EduLocalCoursePanel { @Override public void actionPerformed(ActionEvent actionEvent) { String coursePath = myCourseArchivePath.getText(); - CourseInfo courseInfo = generator.addLocalCourse(coursePath); + Course courseInfo = generator.addLocalCourse(coursePath); if (courseInfo != null) { myBuilder.setSelectedCourse(courseInfo); myGenerator.setSelectedCourse(courseInfo); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java index 5bda69ff6384..3023bc9e6792 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java @@ -67,11 +67,12 @@ public class EduAdaptiveStepicConnector { private static final Logger LOG = Logger.getInstance(EduAdaptiveStepicConnector.class); private static final int CONNECTION_TIMEOUT = 60 * 1000; private static final String CODE_TASK_TYPE = "code"; + private static final String CODE_TASK_NAME = "code.py"; private static final String CHOICE_TYPE_TEXT = "choice"; private static final String TEXT_STEP_TYPE = "text"; @Nullable - public static Task getNextRecommendation(@NotNull Project project, @NotNull Course course) { + public static Task getNextRecommendation(@NotNull Project project, @NotNull RemoteCourse course) { try { final CloseableHttpClient client = EduStepicAuthorizedClient.getHttpClient(); if (client == null) { @@ -204,8 +205,8 @@ public class EduAdaptiveStepicConnector { private static void createMockTaskFile(@NotNull Task task, String editorText) { final TaskFile taskFile = new TaskFile(); taskFile.text = editorText; - taskFile.name = "code.py"; - task.taskFiles.put("code.py", taskFile); + taskFile.name = CODE_TASK_NAME; + task.taskFiles.put(CODE_TASK_NAME, taskFile); } @Nullable @@ -297,7 +298,7 @@ public class EduAdaptiveStepicConnector { int reaction) { final StudyEditor editor = StudyUtils.getSelectedStudyEditor(project); final Course course = StudyTaskManager.getInstance(project).getCourse(); - if (course == null || editor == null || editor.getTaskFile() == null) { + if (course == null || editor == null || editor.getTaskFile() == null || !(course instanceof RemoteCourse)) { return; } indicator.checkCanceled(); @@ -314,7 +315,7 @@ public class EduAdaptiveStepicConnector { String.valueOf(user.getId()), reaction); if (recommendationReaction) { indicator.checkCanceled(); - final Task task = getNextRecommendation(project, course); + final Task task = getNextRecommendation(project, (RemoteCourse)course); if (task != null) { task.initTask(lesson, false); @@ -438,11 +439,9 @@ public class EduAdaptiveStepicConnector { } } else { - final TaskFile taskFile = new TaskFile(); - taskFile.name = CODE_TASK_TYPE; final String templateForTask = getCodeTemplateForTask(project, task, step.options.codeTemplates); - taskFile.text = templateForTask == null ? "# write your answer here \n" : templateForTask; - task.taskFiles.put("code.py", taskFile); + String text = templateForTask == null ? "# write your answer here \n" : templateForTask; + createMockTaskFile(task, text); } return task; } @@ -662,11 +661,11 @@ public class EduAdaptiveStepicConnector { public static List getEnrolledCoursesIds(@NotNull StepicUser stepicUser) { try { final URI enrolledCoursesUri = new URIBuilder(EduStepicNames.COURSES).addParameter("enrolled", "true").build(); - final List courses = EduStepicAuthorizedClient.getFromStepic(enrolledCoursesUri.toString(), + final List courses = EduStepicAuthorizedClient.getFromStepic(enrolledCoursesUri.toString(), StepicWrappers.CoursesContainer.class, stepicUser).courses; final ArrayList ids = new ArrayList<>(); - for (CourseInfo course : courses) { + for (RemoteCourse course : courses) { ids.add(course.getId()); } return ids; diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicClient.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicClient.java index d81b6f8bd53c..d4ed1b144f15 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicClient.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicClient.java @@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import java.io.IOException; +import java.lang.reflect.Modifier; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.URI; @@ -70,6 +71,7 @@ public class EduStepicClient { static T deserializeStepicResponse(Class container, String responseString) { Gson gson = new GsonBuilder().registerTypeAdapter(StepicWrappers.StepOptions.class, new StudySerializationUtils.Json.StepicStepOptionsAdapter()). + excludeFieldsWithModifiers(Modifier.TRANSIENT). setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"). setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); return gson.fromJson(responseString, container); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java index 1931f7a2e768..1372bf1f9693 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java @@ -12,8 +12,8 @@ import com.intellij.openapi.vfs.VirtualFile; import com.jetbrains.edu.learning.StudySettings; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.CourseInfo; import com.jetbrains.edu.learning.courseFormat.Lesson; +import com.jetbrains.edu.learning.courseFormat.RemoteCourse; import com.jetbrains.edu.learning.courseFormat.TaskFile; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import com.jetbrains.edu.learning.courseFormat.tasks.TaskWithSubtasks; @@ -65,9 +65,9 @@ public class EduStepicConnector { } @NotNull - public static List getCourses(@Nullable StepicUser user) { + public static List getCourses(@Nullable StepicUser user) { try { - List result = new ArrayList<>(); + List result = new ArrayList<>(); int pageNumber = 1; while (addCoursesFromStepic(user, result, pageNumber)) { pageNumber += 1; @@ -77,13 +77,13 @@ public class EduStepicConnector { catch (IOException e) { LOG.warn("Cannot load course list " + e.getMessage()); } - return Collections.singletonList(CourseInfo.INVALID_COURSE); + return Collections.emptyList(); } public static Date getCourseUpdateDate(final int courseId) { final String url = EduStepicNames.COURSES + "/" + courseId; try { - final List courses = EduStepicClient.getFromStepic(url, StepicWrappers.CoursesContainer.class).courses; + final List courses = EduStepicClient.getFromStepic(url, StepicWrappers.CoursesContainer.class).courses; if (!courses.isEmpty()) { return courses.get(0).getUpdateDate(); } @@ -125,7 +125,7 @@ public class EduStepicConnector { return null; } - private static boolean addCoursesFromStepic(@Nullable StepicUser user, List result, int pageNumber) throws IOException { + private static boolean addCoursesFromStepic(@Nullable StepicUser user, List result, int pageNumber) throws IOException { final URI url; try { url = new URIBuilder(EduStepicNames.COURSES).addParameter("is_idea_compatible", "true"). @@ -146,27 +146,28 @@ public class EduStepicConnector { return coursesContainer.meta.containsKey("has_next") && coursesContainer.meta.get("has_next") == Boolean.TRUE; } - static void addAvailableCourses(List result, StepicWrappers.CoursesContainer coursesContainer) throws IOException { - final List courseInfos = coursesContainer.courses; - for (CourseInfo info : courseInfos) { + static void addAvailableCourses(List result, StepicWrappers.CoursesContainer coursesContainer) throws IOException { + final List courses = coursesContainer.courses; + for (RemoteCourse info : courses) { if (!info.isAdaptive() && StringUtil.isEmptyOrSpaces(info.getType())) continue; if (canBeOpened(info)) { + final ArrayList authors = new ArrayList<>(); for (Integer instructor : info.getInstructors()) { final StepicUser author = EduStepicClient.getFromStepic(EduStepicNames.USERS + String.valueOf(instructor), StepicWrappers.AuthorWrapper.class).users.get(0); - info.addAuthor(author); + authors.add(author); } + info.setAuthors(authors); if (info.isAdaptive()) { info.setDescription("This is a Stepik Adaptive course.\n\n" + info.getDescription() + ADAPTIVE_NOTE); } - result.add(info); } } } - static boolean canBeOpened(CourseInfo courseInfo) { + static boolean canBeOpened(RemoteCourse courseInfo) { if (courseInfo.isAdaptive()) { return true; } @@ -190,26 +191,19 @@ public class EduStepicConnector { } } - public static Course getCourse(@NotNull final Project project, @NotNull final CourseInfo info) { - final Course course = new Course(); - course.setAuthors(info.getAuthors()); - course.setDescription(info.getDescription()); - course.setAdaptive(info.isAdaptive()); - course.setId(info.getId()); - course.setUpdateDate(getCourseUpdateDate(info.getId())); - - if (!course.isAdaptive()) { - String courseType = info.getType(); - course.setName(info.getName()); + public static RemoteCourse getCourse(@NotNull final Project project, @NotNull final RemoteCourse course) { + final RemoteCourse remoteCourse = (RemoteCourse)course.copy(); + if (!remoteCourse.isAdaptive()) { + String courseType = remoteCourse.getType(); final int separator = courseType.indexOf(" "); assert separator != -1; final String language = courseType.substring(separator + 1); - course.setLanguage(language); + remoteCourse.setLanguage(language); try { - for (Integer section : info.getSections()) { - course.addLessons(getLessons(section)); + for (Integer section : remoteCourse.getSections()) { + remoteCourse.addLessons(getLessons(section)); } - return course; + return remoteCourse; } catch (IOException e) { LOG.error("IOException " + e.getMessage()); @@ -218,14 +212,13 @@ public class EduStepicConnector { else { final Lesson lesson = new Lesson(); lesson.setName("Adaptive"); - course.addLesson(lesson); - course.setName(info.getName()); + remoteCourse.addLesson(lesson); //TODO: more specific name? - final Task recommendation = EduAdaptiveStepicConnector.getNextRecommendation(project, course); + final Task recommendation = EduAdaptiveStepicConnector.getNextRecommendation(project, remoteCourse); if (recommendation != null) { lesson.addTask(recommendation); } - return course; + return remoteCourse; } return null; } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicUpdater.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicUpdater.java index f511b8547d25..d77b13c38bdd 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicUpdater.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicUpdater.java @@ -11,7 +11,8 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Alarm; import com.intellij.util.text.DateFormatUtil; import com.jetbrains.edu.learning.StudySettings; -import com.jetbrains.edu.learning.courseFormat.CourseInfo; +import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.courseFormat.RemoteCourse; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -50,13 +51,14 @@ public class EduStepicUpdater { private static ActionCallback updateCourseList() { ActionCallback callback = new ActionCallback(); ApplicationManager.getApplication().executeOnPooledThread(() -> { - final List courses = EduStepicConnector.getCourses(null); - StudySettings.getInstance().setLastTimeChecked(System.currentTimeMillis()); + final List courses = EduStepicConnector.getCourses(null); + StepicSettings.getInstance().setLastTimeChecked(System.currentTimeMillis()); if (!courses.isEmpty()) { - List updated = new ArrayList<>(); - for (CourseInfo course : courses) { - if (course.getUpdateDate().after(new Date(StepicUpdateSettings.getInstance().getLastTimeChecked()))) { + List updated = new ArrayList<>(); + for (Course course : courses) { + if (course instanceof RemoteCourse && ((RemoteCourse)course).getUpdateDate(). + after(new Date(StepicUpdateSettings.getInstance().getLastTimeChecked()))) { updated.add(course); } } @@ -69,7 +71,7 @@ public class EduStepicUpdater { } else { title = "New courses available"; - message = StringUtil.join(updated, CourseInfo::getName, ", "); + message = StringUtil.join(updated, Course::getName, ", "); } final Notification notification = new Notification("New.course", title, message, NotificationType.INFORMATION); notification.notify(null); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java index e3c20424e020..1690b383f063 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java @@ -11,8 +11,8 @@ import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.CourseInfo; import com.jetbrains.edu.learning.courseFormat.Lesson; +import com.jetbrains.edu.learning.courseFormat.RemoteCourse; import com.jetbrains.edu.learning.courseFormat.TaskFile; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import com.jetbrains.edu.learning.courseFormat.tasks.TaskWithSubtasks; @@ -171,7 +171,7 @@ public class StepicWrappers { } public static class CoursesContainer { - public List courses; + public List courses; public Map meta; } @@ -185,10 +185,10 @@ public class StepicWrappers { } public static class CourseWrapper { - CourseInfo course; + RemoteCourse course; public CourseWrapper(Course course) { - this.course = new CourseInfo(); + this.course = new RemoteCourse(); this.course.setName(course.getName()); this.course.setDescription(course.getDescription()); this.course.setAuthors(course.getAuthors()); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java b/python/educational-core/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java index 501beee24444..f7eb72f4b607 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java @@ -29,7 +29,6 @@ import com.intellij.util.ui.UIUtil; import com.jetbrains.edu.learning.StudySettings; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.CourseInfo; import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator; import com.jetbrains.edu.learning.stepic.EduAdaptiveStepicConnector; import com.jetbrains.edu.learning.stepic.EduStepicAuthorizedClient; @@ -52,9 +51,9 @@ import java.util.List; * data: 7/31/14. */ public class StudyNewProjectPanel extends JPanel implements PanelWithAnchor { - private List myAvailableCourses = new ArrayList<>(); + private List myAvailableCourses = new ArrayList<>(); private JButton myBrowseButton; - private ComboBox myCoursesComboBox; + private ComboBox myCoursesComboBox; private JButton myRefreshButton; private JLabel myAuthorLabel; private JPanel myInfoPanel; @@ -122,20 +121,20 @@ public class StudyNewProjectPanel extends JPanel implements PanelWithAnchor { private void initCoursesCombobox() { myAvailableCourses = myGenerator.getCoursesUnderProgress(!isLocal, "Getting Available Courses", ProjectManager.getInstance().getDefaultProject()); - if (myAvailableCourses.contains(CourseInfo.INVALID_COURSE)) { + if (myAvailableCourses.contains(Course.INVALID_COURSE)) { setError(CONNECTION_ERROR); } else { addCoursesToCombobox(myAvailableCourses); - final CourseInfo selectedCourse = StudyUtils.getFirst(myAvailableCourses); + final Course selectedCourse = StudyUtils.getFirst(myAvailableCourses); if (selectedCourse == null) return; setAuthors(selectedCourse); myDescriptionPane.setText(selectedCourse.getDescription()); myDescriptionPane.setEditable(false); //setting the first course in list as selected myGenerator.setSelectedCourse(selectedCourse); - if (myGenerator.getSelectedCourseInfo() != null) { - myCoursesComboBox.setSelectedItem(myGenerator.getSelectedCourseInfo()); + if (myGenerator.getSelectedCourse() != null) { + myCoursesComboBox.setSelectedItem(myGenerator.getSelectedCourse()); } if (selectedCourse.isAdaptive() && !myGenerator.isLoggedIn()) { setError(LOGIN_TO_STEPIC_MESSAGE); @@ -174,7 +173,7 @@ public class StudyNewProjectPanel extends JPanel implements PanelWithAnchor { file -> { String fileName = file.getPath(); int oldSize = myAvailableCourses.size(); - CourseInfo courseInfo = myGenerator.addLocalCourse(fileName); + Course courseInfo = myGenerator.addLocalCourse(fileName); if (courseInfo != null) { if (oldSize != myAvailableCourses.size()) { myCoursesComboBox.addItem(courseInfo); @@ -185,11 +184,11 @@ public class StudyNewProjectPanel extends JPanel implements PanelWithAnchor { else { setError(INVALID_COURSE); myCoursesComboBox.removeAllItems(); - myCoursesComboBox.addItem(CourseInfo.INVALID_COURSE); - for (CourseInfo course : myAvailableCourses) { + myCoursesComboBox.addItem(Course.INVALID_COURSE); + for (Course course : myAvailableCourses) { myCoursesComboBox.addItem(course); } - myCoursesComboBox.setSelectedItem(CourseInfo.INVALID_COURSE); + myCoursesComboBox.setSelectedItem(Course.INVALID_COURSE); } }); } @@ -221,8 +220,8 @@ public class StudyNewProjectPanel extends JPanel implements PanelWithAnchor { isComboboxInitialized = true; initCoursesCombobox(); } - CourseInfo selectedCourse = (CourseInfo)myCoursesComboBox.getSelectedItem(); - if (selectedCourse == null || selectedCourse.equals(CourseInfo.INVALID_COURSE)) { + Course selectedCourse = (Course)myCoursesComboBox.getSelectedItem(); + if (selectedCourse == null || selectedCourse.equals(Course.INVALID_COURSE)) { setError(CONNECTION_ERROR); } } @@ -256,9 +255,9 @@ public class StudyNewProjectPanel extends JPanel implements PanelWithAnchor { myAnchor = anchor; } - public void updateInfoPanel(@NotNull CourseInfo selectedCourseInfo) { - setAuthors(selectedCourseInfo); - myDescriptionPane.setText(selectedCourseInfo.getDescription()); + public void updateInfoPanel(@NotNull Course selectedCourse) { + setAuthors(selectedCourse); + myDescriptionPane.setText(selectedCourse.getDescription()); } /** @@ -269,15 +268,15 @@ public class StudyNewProjectPanel extends JPanel implements PanelWithAnchor { private class RefreshActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { - final List courses = + final List courses = myGenerator.getCoursesUnderProgress(true, "Refreshing Course List", DefaultProjectFactory.getInstance().getDefaultProject()); - if (!courses.contains(CourseInfo.INVALID_COURSE)) { + if (!courses.contains(Course.INVALID_COURSE)) { refreshCoursesList(courses); } } } - private void refreshCoursesList(@NotNull final List courses) { + private void refreshCoursesList(@NotNull final List courses) { if (courses.isEmpty()) { setError(CONNECTION_ERROR); return; @@ -285,7 +284,7 @@ public class StudyNewProjectPanel extends JPanel implements PanelWithAnchor { myCoursesComboBox.removeAllItems(); addCoursesToCombobox(courses); - final CourseInfo selectedCourse = StudyUtils.getFirst(courses); + final Course selectedCourse = StudyUtils.getFirst(courses); if (selectedCourse == null) return; myGenerator.setSelectedCourse(selectedCourse); @@ -293,8 +292,8 @@ public class StudyNewProjectPanel extends JPanel implements PanelWithAnchor { myAvailableCourses = courses; } - private void addCoursesToCombobox(@NotNull List courses) { - for (CourseInfo courseInfo : courses) { + private void addCoursesToCombobox(@NotNull List courses) { + for (Course courseInfo : courses) { myCoursesComboBox.addItem(courseInfo); } } @@ -309,15 +308,15 @@ public class StudyNewProjectPanel extends JPanel implements PanelWithAnchor { @Override public void actionPerformed(ActionEvent e) { JComboBox cb = (JComboBox)e.getSource(); - CourseInfo selectedCourse = (CourseInfo)cb.getSelectedItem(); - if (selectedCourse == null || selectedCourse.equals(CourseInfo.INVALID_COURSE)) { + Course selectedCourse = (Course)cb.getSelectedItem(); + if (selectedCourse == null || selectedCourse.equals(Course.INVALID_COURSE)) { myAuthorLabel.setText(""); myDescriptionPane.setText(""); setError(INVALID_COURSE); return; } updateInfoPanel(selectedCourse); - myCoursesComboBox.removeItem(CourseInfo.INVALID_COURSE); + myCoursesComboBox.removeItem(Course.INVALID_COURSE); myGenerator.setSelectedCourse(selectedCourse); setOK(); @@ -329,12 +328,12 @@ public class StudyNewProjectPanel extends JPanel implements PanelWithAnchor { } } - private void setAuthors(CourseInfo selectedCourse) { + private void setAuthors(Course selectedCourse) { final String authorsString = Course.getAuthorsString(selectedCourse.getAuthors()); myAuthorLabel.setText(!StringUtil.isEmptyOrSpaces(authorsString) ? "Author: " + authorsString : ""); } - public JComboBox getCoursesComboBox() { + public JComboBox getCoursesComboBox() { return myCoursesComboBox; } @@ -367,7 +366,7 @@ public class StudyNewProjectPanel extends JPanel implements PanelWithAnchor { stepicUser.setPassword(myLoginPanel.getPassword()); StudySettings.getInstance().setUser(stepicUser); myGenerator.setEnrolledCoursesIds(EduAdaptiveStepicConnector.getEnrolledCoursesIds(stepicUser)); - final List courses = myGenerator.getCourses(true); + final List courses = myGenerator.getCourses(true); if (courses != null && myRefreshCourseList) { ApplicationManager.getApplication().invokeLater(() -> refreshCoursesList(courses)); } diff --git a/python/educational-core/testSrc/com/jetbrains/edu/learning/stepic/StudyStepicFormatTest.java b/python/educational-core/testSrc/com/jetbrains/edu/learning/stepic/StudyStepicFormatTest.java index f524d01fdfe6..e7d6a4b112a3 100644 --- a/python/educational-core/testSrc/com/jetbrains/edu/learning/stepic/StudyStepicFormatTest.java +++ b/python/educational-core/testSrc/com/jetbrains/edu/learning/stepic/StudyStepicFormatTest.java @@ -8,7 +8,7 @@ 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.CourseInfo; +import com.jetbrains.edu.learning.courseFormat.RemoteCourse; import com.jetbrains.edu.learning.courseFormat.TaskFile; import org.jetbrains.annotations.NotNull; import org.junit.Test; @@ -65,9 +65,9 @@ public class StudyStepicFormatTest { EduStepicClient.deserializeStepicResponse(StepicWrappers.CoursesContainer.class, responseString); assertNotNull(container.courses); assertTrue("Incorrect number of courses", container.courses.size() == 4); - List filtered = ContainerUtil.filter(container.courses, info -> EduStepicConnector.canBeOpened(info)); + List filtered = ContainerUtil.filter(container.courses, info -> EduStepicConnector.canBeOpened(info)); assertEquals(ContainerUtil.newArrayList("Adaptive Python", "Introduction to Python", "format2"), - ContainerUtil.map(filtered, CourseInfo::getName)); + ContainerUtil.map(filtered, RemoteCourse::getName)); } @Test diff --git a/python/educational-python/Edu-Python/resources/courses/Introduction to Python.zip b/python/educational-python/Edu-Python/resources/courses/Introduction to Python.zip index a6293bc906a3..1b47952d554f 100644 Binary files a/python/educational-python/Edu-Python/resources/courses/Introduction to Python.zip and b/python/educational-python/Edu-Python/resources/courses/Introduction to Python.zip differ diff --git a/python/educational-python/Edu-Python/src/com/jetbrains/edu/coursecreator/CreateFromArchiveProjectStep.java b/python/educational-python/Edu-Python/src/com/jetbrains/edu/coursecreator/CreateFromArchiveProjectStep.java index de1889a84fce..ea4a9dafdab3 100644 --- a/python/educational-python/Edu-Python/src/com/jetbrains/edu/coursecreator/CreateFromArchiveProjectStep.java +++ b/python/educational-python/Edu-Python/src/com/jetbrains/edu/coursecreator/CreateFromArchiveProjectStep.java @@ -10,7 +10,6 @@ import com.jetbrains.edu.learning.PyStudyDirectoryProjectGenerator; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.CourseInfo; import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator; import com.jetbrains.python.newProject.steps.PyCharmNewProjectStep; import org.jetbrains.annotations.NotNull; @@ -44,10 +43,10 @@ class CreateFromArchiveProjectStep extends PyCharmNewProjectStep { @NotNull @Override protected DirectoryProjectGenerator createEmptyProjectGenerator() { - Course course = StudyTaskManager.getInstance(myProject).getCourse(); - if (course != null) { + Course currentCourse = StudyTaskManager.getInstance(myProject).getCourse(); + if (currentCourse != null) { VirtualFile folder = CCUtils.getGeneratedFilesFolder(myProject, myModule); - String zipName = FileUtil.sanitizeFileName(course.getName()); + String zipName = FileUtil.sanitizeFileName(currentCourse.getName()); if (zipName.isEmpty()) { zipName = EduNames.COURSE; } @@ -55,9 +54,9 @@ class CreateFromArchiveProjectStep extends PyCharmNewProjectStep { CCCreateCourseArchive.createCourseArchive(myProject, myModule, zipName, locationDir, false); String path = FileUtil.join(FileUtil.toSystemDependentName(folder.getPath()), zipName + ".zip"); StudyProjectGenerator generator = myGenerator.getGenerator(); - CourseInfo info = generator.addLocalCourse(path); - assert info != null; - generator.setSelectedCourse(info); + Course course = generator.addLocalCourse(path); + assert course != null; + generator.setSelectedCourse(course); } return myGenerator; } diff --git a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java index d26b7f640b04..c28aa9b9f3e5 100644 --- a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java +++ b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyDirectoryProjectGenerator.java @@ -25,7 +25,7 @@ import com.intellij.psi.PsiManager; import com.intellij.util.BooleanFunction; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.CourseInfo; +import com.jetbrains.edu.learning.courseFormat.RemoteCourse; import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator; import com.jetbrains.edu.learning.stepic.EduStepicConnector; import com.jetbrains.edu.learning.ui.StudyNewProjectPanel; @@ -87,7 +87,7 @@ public class PyStudyDirectoryProjectGenerator extends PythonProjectGenerator beforeProjectGenerated(@Nullable Sdk sdk) { return generator -> { final List enrolledCoursesIds = myGenerator.getEnrolledCoursesIds(); - final CourseInfo course = (CourseInfo)mySettingsPanel.getCoursesComboBox().getSelectedItem(); - if (course == null) return true; - if (course.getId() > 0 && !enrolledCoursesIds.contains(course.getId())) { + final Course course = (Course)mySettingsPanel.getCoursesComboBox().getSelectedItem(); + if (course == null || !(course instanceof RemoteCourse)) return true; + if (((RemoteCourse)course).getId() > 0 && !enrolledCoursesIds.contains(((RemoteCourse)course).getId())) { ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> { ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true); - return StudyUtils.execCancelable(() -> EduStepicConnector.enrollToCourse(course.getId(), - StudySettings.getInstance().getUser())); + return StudyUtils.execCancelable(() -> EduStepicConnector.enrollToCourse(((RemoteCourse)course).getId(), + StepicSettings.getInstance().getUser())); }, "Creating Course", true, ProjectManager.getInstance().getDefaultProject()); } diff --git a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/actions/PyStudyIntroductionCourseAction.java b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/actions/PyStudyIntroductionCourseAction.java index 413df2d68c63..e2f33e58221a 100644 --- a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/actions/PyStudyIntroductionCourseAction.java +++ b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/actions/PyStudyIntroductionCourseAction.java @@ -21,7 +21,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.jetbrains.edu.learning.EduPluginConfigurator; import com.jetbrains.edu.learning.PyStudyDirectoryProjectGenerator; -import com.jetbrains.edu.learning.courseFormat.CourseInfo; +import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.python.PythonLanguage; import com.jetbrains.python.newProject.steps.ProjectSpecificSettingsStep; import com.jetbrains.python.newProject.steps.PythonGenerateProjectCallback; @@ -64,7 +64,7 @@ public class PyStudyIntroductionCourseAction extends AnAction { final PyStudyDirectoryProjectGenerator generator = new PyStudyDirectoryProjectGenerator(true); final EduPluginConfigurator configurator = EduPluginConfigurator.INSTANCE.forLanguage(PythonLanguage.getInstance()); final String bundledCoursePath = configurator.getBundledCoursePath(); - CourseInfo introCourse = generator.getGenerator().getCourseInfo(bundledCoursePath); + Course introCourse = generator.getGenerator().getCourse(bundledCoursePath); if (introCourse == null) { return; }