diff --git a/python/edu/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java b/python/edu/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java index e4ea96ad67de..4ab1edea86b6 100644 --- a/python/edu/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java +++ b/python/edu/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java @@ -55,17 +55,17 @@ public class PyCCProjectGenerator extends PythonProjectGenerator implements Dire public void generateProject(@NotNull final Project project, @NotNull final VirtualFile baseDir, @Nullable Object settings, @NotNull Module module) { generateProject(project, baseDir, mySettingsPanel.getName(), - mySettingsPanel.getAuthor(), mySettingsPanel.getDescription()); + mySettingsPanel.getAuthors(), mySettingsPanel.getDescription()); } public static void generateProject(@NotNull final Project project, @NotNull final VirtualFile baseDir, - @NotNull final String name, @NotNull final String author, + @NotNull final String name, @NotNull final String[] authors, @NotNull final String description) { final CCProjectService service = CCProjectService.getInstance(project); final Course course = new Course(); course.setName(name); - course.setAuthor(author); + course.setAuthors(authors); course.setDescription(description); course.setLanguage("Python"); service.setCourse(course); @@ -93,7 +93,7 @@ public class PyCCProjectGenerator extends PythonProjectGenerator implements Dire public ValidationResult validate(@NotNull String s) { String message = ""; message = mySettingsPanel.getDescription().isEmpty() ? "Enter description" : message; - message = mySettingsPanel.getAuthor().isEmpty() ? "Enter author name" : message; + message = mySettingsPanel.getAuthors().length == 0 ? "Enter author name" : message; message = mySettingsPanel.getName().isEmpty() ? "Enter course name" : message; return message.isEmpty() ? ValidationResult.OK : new ValidationResult(message); } diff --git a/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java b/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java index 1625f6361c16..e2588978df95 100644 --- a/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java +++ b/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java @@ -78,12 +78,12 @@ public class CCChangeCourseInfo extends DumbAwareAction { if (directory != null && !project.getBaseDir().equals(directory.getVirtualFile())) { return; } - CCNewProjectPanel panel = new CCNewProjectPanel(course.getName(), course.getAuthor(), course.getDescription()); + CCNewProjectPanel panel = new CCNewProjectPanel(course.getName(), Course.getAuthorsString(course.getAuthors()), course.getDescription()); ChangeCourseInfoDialog changeCourseInfoDialog = new ChangeCourseInfoDialog(project, panel); changeCourseInfoDialog.show(); if (changeCourseInfoDialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { - course.setAuthor(panel.getAuthor()); + course.setAuthors(panel.getAuthors()); course.setName(panel.getName()); course.setDescription(panel.getDescription()); ProjectView.getInstance(project).refresh(); diff --git a/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCNewProjectPanel.java b/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCNewProjectPanel.java index b5800fcf96d0..5e7de6356b55 100644 --- a/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCNewProjectPanel.java +++ b/python/educational/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCNewProjectPanel.java @@ -51,8 +51,8 @@ public class CCNewProjectPanel { } @NotNull - public String getAuthor() { - return StringUtil.notNullize(myAuthorField.getText()); + public String[] getAuthors() { + return StringUtil.splitByLines(StringUtil.notNullize(myAuthorField.getText())); } public void registerValidators(FacetValidatorsManager manager) { diff --git a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java index 7fab45e5f3d8..63e90f5967a5 100644 --- a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java +++ b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java @@ -211,10 +211,13 @@ public class StudyProjectGenerator { } writer = new PrintWriter(cashFile); for (CourseInfo courseInfo : myCourses) { - String line = String - .format("name=%s author=%s description=%s", courseInfo.getName(), courseInfo.getAuthor(), - courseInfo.getDescription()); - writer.println(line); + final List instructors = courseInfo.getInstructors(); + StringBuilder builder = new StringBuilder("name=").append(courseInfo.getName()).append("description=").append( + courseInfo.getDescription()); + for (CourseInfo.Instructor instructor : instructors) { + builder.append("instructor=").append(instructor.getName()); + } + writer.println(builder.toString()); } } catch (FileNotFoundException e) { diff --git a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java index 49fcf50203a0..afa2484d96a6 100644 --- a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java +++ b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java @@ -3,6 +3,7 @@ package com.jetbrains.edu.learning.ui; import com.intellij.facet.ui.FacetValidatorsManager; import com.intellij.facet.ui.ValidationResult; import com.intellij.icons.AllIcons; +import com.jetbrains.edu.courseFormat.Course; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator; import com.jetbrains.edu.stepic.CourseInfo; @@ -42,7 +43,7 @@ public class StudyNewProjectPanel{ for (CourseInfo courseInfo : myAvailableCourses) { myCoursesComboBox.addItem(courseInfo); } - myAuthorLabel.setText("Author: " + StudyUtils.getFirst(myAvailableCourses).getAuthor()); + myAuthorLabel.setText("Author: " + Course.getAuthorsString(StudyUtils.getFirst(myAvailableCourses).getInstructors())); myDescriptionLabel.setText(StudyUtils.getFirst(myAvailableCourses).getDescription()); //setting the first course in list as selected myGenerator.setSelectedCourse(StudyUtils.getFirst(myAvailableCourses)); @@ -126,7 +127,7 @@ public class StudyNewProjectPanel{ myDescriptionLabel.setText(""); return; } - myAuthorLabel.setText("Author: " + selectedCourse.getAuthor()); + myAuthorLabel.setText("Author: " + Course.getAuthorsString(selectedCourse.getInstructors())); myCoursesComboBox.removeItem(CourseInfo.INVALID_COURSE); myDescriptionLabel.setText(selectedCourse.getDescription()); myGenerator.setSelectedCourse(selectedCourse); diff --git a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/ui/StudyToolWindowFactory.java b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/ui/StudyToolWindowFactory.java index 739954cee6d5..0539c68a9965 100644 --- a/python/educational/interactive-learning/src/com/jetbrains/edu/learning/ui/StudyToolWindowFactory.java +++ b/python/educational/interactive-learning/src/com/jetbrains/edu/learning/ui/StudyToolWindowFactory.java @@ -36,8 +36,7 @@ public class StudyToolWindowFactory implements ToolWindowFactory, DumbAware { } String courseName = UIUtil.toHtml("

" + course.getName() + "

", 10); String description = UIUtil.toHtml(course.getDescription(), 5); - String author = taskManager.getCourse().getAuthor(); - String authorLabel = UIUtil.toHtml("Author: " + author, 5); + String authorLabel = UIUtil.toHtml("Author: " + Course.getAuthorsString(course.getAuthors()), 5); contentPanel.add(new JLabel(courseName)); contentPanel.add(new JLabel(authorLabel)); contentPanel.add(Box.createRigidArea(new Dimension(0, 10))); diff --git a/python/educational/src/com/jetbrains/edu/courseFormat/Course.java b/python/educational/src/com/jetbrains/edu/courseFormat/Course.java index 0bde12d2c6ad..36498e4a528b 100644 --- a/python/educational/src/com/jetbrains/edu/courseFormat/Course.java +++ b/python/educational/src/com/jetbrains/edu/courseFormat/Course.java @@ -3,8 +3,11 @@ package com.jetbrains.edu.courseFormat; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; import com.intellij.lang.Language; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.Function; import com.jetbrains.edu.EduNames; import com.jetbrains.edu.EduUtils; +import com.jetbrains.edu.stepic.CourseInfo; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -17,7 +20,7 @@ public class Course { @Expose private String description; @Expose private String name; private String myCourseDirectory = ""; - @Expose private String author=""; + @Expose private List authors = new ArrayList(); private boolean myUpToDate; @Expose @SerializedName("language") @@ -56,12 +59,25 @@ public class Course { return lessons.get(lessonIndex); } - public String getAuthor() { - return author; + @NotNull + public List getAuthors() { + return authors; } - public void setAuthor(String author) { - this.author = author; + public static String getAuthorsString(@NotNull List authors) { + return StringUtil.join(authors, new Function() { + @Override + public String fun(CourseInfo.Instructor instructor) { + return instructor.getName(); + } + }, ", "); + } + + public void setAuthors(String[] authors) { + this.authors = new ArrayList(); + for (String name : authors) { + this.authors.add(new CourseInfo.Instructor(name)); + } } public String getName() { @@ -107,4 +123,8 @@ public class Course { public void setLanguage(@NotNull final String language) { myLanguage = language; } + + public void setAuthors(List instructors) { + this.authors = instructors; + } } diff --git a/python/educational/src/com/jetbrains/edu/stepic/CourseInfo.java b/python/educational/src/com/jetbrains/edu/stepic/CourseInfo.java index 38815badc45b..19f8898a3509 100644 --- a/python/educational/src/com/jetbrains/edu/stepic/CourseInfo.java +++ b/python/educational/src/com/jetbrains/edu/stepic/CourseInfo.java @@ -1,7 +1,9 @@ package com.jetbrains.edu.stepic; import com.google.gson.annotations.SerializedName; +import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; import java.util.List; /** @@ -19,22 +21,18 @@ public class CourseInfo { //course type in format "pycharm " private String myType; - private String myAuthor; - public static CourseInfo INVALID_COURSE = new CourseInfo("", "", "", ""); + @SerializedName("instructors") + List myInstructors = new ArrayList(); - public CourseInfo(String name, String author, String description, String type) { - myName = name; - myAuthor = author; - myDescription = description; - myType = type; - } + public static CourseInfo INVALID_COURSE = new CourseInfo(); public String getName() { return myName; } - public String getAuthor() { - return myAuthor; + @NotNull + public List getInstructors() { + return myInstructors; } public String getDescription() { @@ -55,15 +53,27 @@ public class CourseInfo { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CourseInfo that = (CourseInfo)o; - return that.getName().equals(myName) && that.getAuthor().equals(myAuthor) + if (that.getName() == null || that.getDescription() == null) return false; + return that.getName().equals(myName) && that.getDescription().equals(myDescription); } @Override public int hashCode() { int result = myName != null ? myName.hashCode() : 0; - result = 31 * result + (myAuthor != null ? myAuthor.hashCode() : 0); result = 31 * result + (myDescription != null ? myDescription.hashCode() : 0); return result; } + + public static class Instructor { + String name; + + public Instructor(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } } diff --git a/python/educational/src/com/jetbrains/edu/stepic/EduStepicConnector.java b/python/educational/src/com/jetbrains/edu/stepic/EduStepicConnector.java index 564226d9a06c..f4314caca004 100644 --- a/python/educational/src/com/jetbrains/edu/stepic/EduStepicConnector.java +++ b/python/educational/src/com/jetbrains/edu/stepic/EduStepicConnector.java @@ -8,6 +8,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.io.HttpRequests; import com.intellij.util.net.ssl.CertificateManager; @@ -42,7 +43,7 @@ public class EduStepicConnector { private static String ourSessionId = "524iethiwju2tjywaqmf7tbwx0p0jk1b"; private static String ourCSRFToken = "LJ9n6OyLVA7hxU94dlYWUu65MF51Nx37"; //this prefix indicates that course can be opened by educational plugin - public static final String PYCHARM_PREFIX = "pycharm "; + public static final String PYCHARM_PREFIX = "pycharm"; private EduStepicConnector() { } @@ -61,36 +62,40 @@ public class EduStepicConnector { @NotNull public static List getCourses() { try { - return getFromStepic("courses/99", CoursesContainer.class).courses; + List result = new ArrayList(); + final List courseInfos = + HttpRequests.request(stepicApiUrl + "courses").connect(new HttpRequests.RequestProcessor>() { + + @Override + public List process(@NotNull HttpRequests.Request request) throws IOException { + final BufferedReader reader = request.getReader(); + Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); + return gson.fromJson(reader, CoursesContainer.class).courses; + } + }); + for (CourseInfo info : courseInfos) { + final String courseType = info.getType(); + if (StringUtil.isEmptyOrSpaces(courseType)) continue; + final List typeLanguage = StringUtil.split(courseType, " "); + if (typeLanguage.size() == 2 && PYCHARM_PREFIX.equals(typeLanguage.get(0))) { + result.add(info); + } + } + return result; } catch (IOException e) { - LOG.error("IOException " + e.getMessage()); + LOG.error("Cannot load course list " + e.getMessage()); } return Collections.emptyList(); - /*try { // TODO: uncomment - return HttpRequests.request(stepicApiUrl + "courses").connect(new HttpRequests.RequestProcessor>() { - - @Override - public List process(@NotNull HttpRequests.Request request) throws IOException { - final BufferedReader reader = request.getReader(); - Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); - return gson.fromJson(reader, CoursesContainer.class).courses; - } - }); - } - catch (IOException e) { - LOG.error("IOException " + e.getMessage()); - } - return null;*/ } public static Course getCourse(@NotNull final CourseInfo info) { final Course course = new Course(); - course.setAuthor(info.getAuthor()); + course.setAuthors(info.getInstructors()); course.setDescription(info.getDescription()); course.setName(info.getName()); String courseType = info.getType(); - course.setLanguage(courseType.substring(PYCHARM_PREFIX.length())); + course.setLanguage(courseType.substring(PYCHARM_PREFIX.length() + 1)); course.setUpToDate(true); // TODO: get from stepic try { for (Integer section : info.sections) { @@ -128,7 +133,7 @@ public class EduStepicConnector { private static void createTask(Lesson lesson, Integer s) throws IOException { final Step step = getStep(s); final Task task = new Task(); - task.setName(step.name); + task.setName(step.options != null ? step.options.title : PYCHARM_PREFIX); task.setText(step.text); for (TestFileWrapper wrapper : step.options.test) { task.setTestsTexts(wrapper.name, wrapper.text);