Store stepic settings in project settings Cache adaptive course for every user
authorValentina Kiryushkina <valentina.kiryushkina@jetbrains.com>
Fri, 22 Apr 2016 13:12:27 +0000 (16:12 +0300)
committerValentina Kiryushkina <valentina.kiryushkina@jetbrains.com>
Fri, 22 Apr 2016 13:15:06 +0000 (16:15 +0300)
14 files changed:
python/educational-core/student/resources/META-INF/plugin.xml
python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java
python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java
python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshAnswerPlaceholder.java
python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java
python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java
python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/LoginDialog.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicStudyOptions.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StepicUser.java
python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StudySettings.java [deleted file]
python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyNewProjectPanel.java

index 9cd1dc9e0b1b9d31eba8d422c6ff6f059e73853e..2d5b272bd2bbe9c17f394fc357a123db49c6fe12 100644 (file)
@@ -82,8 +82,6 @@
     <applicationConfigurable groupId="tools" instance="com.jetbrains.edu.learning.settings.StudyConfigurable"
                              id="com.jetbrains.edu.learning.settings.StudyConfigurable"
                              displayName="Education"/>
-    <applicationService serviceInterface="com.jetbrains.edu.learning.stepic.StudySettings"
-                        serviceImplementation="com.jetbrains.edu.learning.stepic.StudySettings"/>
 
     <toolWindow id="Task Description" anchor="right" factoryClass="com.jetbrains.edu.learning.ui.StudyToolWindowFactory" conditionClass="com.jetbrains.edu.learning.ui.StudyCondition"/>
     <toolWindow id="Course Progress" anchor="left" factoryClass="com.jetbrains.edu.learning.ui.StudyProgressToolWindowFactory" conditionClass="com.jetbrains.edu.learning.ui.StudyCondition"/>
index 6d682f4af732026e68fc77505dea6f972be53754..40da8f72175ca1b5cde4c91767077d99496bed2a 100644 (file)
@@ -14,6 +14,7 @@ import com.intellij.util.xmlb.XmlSerializer;
 import com.jetbrains.edu.learning.core.EduUtils;
 import com.jetbrains.edu.learning.courseFormat.*;
 import com.jetbrains.edu.learning.oldCourseFormat.OldCourse;
+import com.jetbrains.edu.learning.stepic.StepicUser;
 import org.jdom.Element;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -33,6 +34,7 @@ public class StudyTaskManager implements PersistentStateComponent<Element>, Dumb
   private Course myCourse;
   private OldCourse myOldCourse;
   public int VERSION = 2;
+  public StepicUser myUser;
   public Map<AnswerPlaceholder, StudyStatus> myStudyStatusMap = new HashMap<>();
   public Map<TaskFile, StudyStatus> myTaskStatusMap = new HashMap<>();
   public Map<Task, List<UserTest>> myUserTests = new HashMap<>();
@@ -70,7 +72,7 @@ public class StudyTaskManager implements PersistentStateComponent<Element>, Dumb
   @NotNull
   public List<UserTest> getUserTests(@NotNull final Task task) {
     final List<UserTest> userTests = myUserTests.get(task);
-    return userTests != null ? userTests : Collections.<UserTest>emptyList();
+    return userTests != null ? userTests : Collections.emptyList();
   }
 
   public void removeUserTest(@NotNull final Task task, @NotNull final UserTest userTest) {
@@ -207,6 +209,7 @@ public class StudyTaskManager implements PersistentStateComponent<Element>, Dumb
         myInvisibleFiles = taskManager.myInvisibleFiles;
         myTaskStatusMap = taskManager.myTaskStatusMap;
         myStudyStatusMap = taskManager.myStudyStatusMap;
+        myUser = taskManager.getUser();
       }
     }
     final Element oldCourseElement = state.getChild(COURSE_ELEMENT);
@@ -250,4 +253,38 @@ public class StudyTaskManager implements PersistentStateComponent<Element>, Dumb
   public boolean isInvisibleFile(String path) {
     return myInvisibleFiles.contains(path);
   }
+
+  public String getLogin() {
+    if (myUser != null) {
+      return myUser.getEmail();
+    }
+    return "";
+  }
+
+  public String getPassword() {
+    if (myUser != null) {
+      return myUser.getPassword();
+    }
+    return "";
+  }
+
+  public void setLogin(String login) {
+    if (myUser != null) {
+      myUser.setEmail(login);
+    }
+  }
+
+  public void setPassword(String password) {
+    if (myUser != null) {
+      myUser.setPassword(password);
+    }
+  }
+
+  public StepicUser getUser() {
+    return myUser;
+  }
+
+  public void setUser(StepicUser user) {
+    myUser = user;
+  }
 }
index 8ed23fb768d30df81e0a300c1e6164fdf618492f..6a233d40602c3750a4d654d1f28699c26bfc82f6 100644 (file)
@@ -21,6 +21,7 @@ import com.intellij.openapi.fileEditor.FileEditor;
 import com.intellij.openapi.fileEditor.FileEditorManager;
 import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
 import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
 import com.intellij.openapi.projectRoots.Sdk;
 import com.intellij.openapi.ui.popup.Balloon;
 import com.intellij.openapi.util.Disposer;
@@ -43,6 +44,7 @@ import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter;
 import com.jetbrains.edu.learning.core.EduNames;
 import com.jetbrains.edu.learning.core.EduUtils;
 import com.jetbrains.edu.learning.courseFormat.*;
+import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator;
 import com.jetbrains.edu.learning.editor.StudyEditor;
 import com.jetbrains.edu.learning.ui.StudyProgressToolWindowFactory;
 import com.jetbrains.edu.learning.ui.StudyToolWindow;
@@ -354,12 +356,12 @@ public class StudyUtils {
   }
 
   @Nullable
-  public static Document getPatternDocument(@NotNull final TaskFile taskFile, String name) {
+  public static Document getPatternDocument(@NotNull final Project project, @NotNull final TaskFile taskFile, String name) {
     Task task = taskFile.getTask();
     String lessonDir = EduNames.LESSON + String.valueOf(task.getLesson().getIndex());
     String taskDir = EduNames.TASK + String.valueOf(task.getIndex());
     Course course = task.getLesson().getCourse();
-    File resourceFile = new File(course.getCourseDirectory());
+    File resourceFile = getCourseDirectory(project, course);
     if (!resourceFile.exists()) {
       return  null;
     }
@@ -502,4 +504,30 @@ public class StudyUtils {
   public static boolean isStudyProject(@NotNull Project project) {
     return StudyTaskManager.getInstance(project).getCourse() != null;
   }
+
+  @Nullable
+  public static Project getStudyProject() {
+    Project studyProject = null;
+    Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
+    for (Project project : openProjects) {
+      if (StudyTaskManager.getInstance(project).getCourse() != null) {
+         studyProject = project;
+      }
+    }
+    return studyProject;
+  }
+
+  @NotNull
+  public static File getCourseDirectory(@NotNull Project project, Course course) {
+    final File courseDirectory;
+    if (course.isAdaptive()) {
+      courseDirectory = new File(StudyProjectGenerator.ourCoursesDir,
+                                 StudyProjectGenerator.ADAPTIVE_COURSE_PREFIX + course.getName()
+                                 + "_" + StudyTaskManager.getInstance(project).getUser().getEmail());
+    }
+    else {
+      courseDirectory = new File(StudyProjectGenerator.ourCoursesDir, course.getName());
+    }
+    return courseDirectory;
+  }
 }
index 42a7674c384bd40afdb5011bdc0c58dde3457ee6..163610e5607933d66ba937783c3feeda86c59730 100644 (file)
@@ -9,10 +9,10 @@ import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.project.DumbAwareAction;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.TextRange;
-import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
-import com.jetbrains.edu.learning.courseFormat.TaskFile;
 import com.jetbrains.edu.learning.StudyState;
 import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
+import com.jetbrains.edu.learning.courseFormat.TaskFile;
 import com.jetbrains.edu.learning.editor.StudyEditor;
 import org.jetbrains.annotations.Nullable;
 
@@ -36,7 +36,7 @@ public class StudyRefreshAnswerPlaceholder extends DumbAwareAction {
     }
     StudyEditor studyEditor = StudyUtils.getSelectedStudyEditor(project);
     final StudyState studyState = new StudyState(studyEditor);
-    Document patternDocument = StudyUtils.getPatternDocument(answerPlaceholder.getTaskFile(), studyState.getVirtualFile().getName());
+    Document patternDocument = StudyUtils.getPatternDocument(project, answerPlaceholder.getTaskFile(), studyState.getVirtualFile().getName());
     if (patternDocument == null) {
       return;
     }
index 110feeee370f5c124c1c4c1c66a6d12e9058ebb2..e68daec279962517b2f8efc2ff24ac7a24f01463 100644 (file)
@@ -19,13 +19,13 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
 import com.intellij.openapi.util.Disposer;
 import com.intellij.openapi.wm.IdeFocusManager;
 import com.intellij.problems.WolfTheProblemSolver;
+import com.jetbrains.edu.learning.StudyState;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
 import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter;
 import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
 import com.jetbrains.edu.learning.courseFormat.StudyStatus;
 import com.jetbrains.edu.learning.courseFormat.TaskFile;
-import com.jetbrains.edu.learning.StudyState;
-import com.jetbrains.edu.learning.StudyTaskManager;
-import com.jetbrains.edu.learning.StudyUtils;
 import com.jetbrains.edu.learning.editor.StudyEditor;
 import com.jetbrains.edu.learning.navigation.StudyNavigator;
 import org.jetbrains.annotations.NotNull;
@@ -89,7 +89,7 @@ public class StudyRefreshTaskFileAction extends StudyToolbarAction {
                                        @NotNull final Project project,
                                        TaskFile taskFile,
                                        String name) {
-    if (!resetDocument(document, taskFile, name)) {
+    if (!resetDocument(project, document, taskFile, name)) {
       return false;
     }
     resetAnswerPlaceholders(taskFile, project);
@@ -117,10 +117,10 @@ public class StudyRefreshTaskFileAction extends StudyToolbarAction {
   }
 
 
-  private static boolean resetDocument(@NotNull final Document document,
+  private static boolean resetDocument(@NotNull final Project project, @NotNull final Document document,
                                        @NotNull final TaskFile taskFile,
                                        String fileName) {
-    final Document patternDocument = StudyUtils.getPatternDocument(taskFile, fileName);
+    final Document patternDocument = StudyUtils.getPatternDocument(project, taskFile, fileName);
     if (patternDocument == null) {
       return false;
     }
index 4db6ae23182384b2cef49518ca734e16860c2aba..29a4011c9306296f956019b18160ec2a190bb2b3 100644 (file)
@@ -24,7 +24,6 @@ import com.jetbrains.edu.learning.courseFormat.StudyStatus;
 import com.jetbrains.edu.learning.courseFormat.Task;
 import com.jetbrains.edu.learning.stepic.EduAdaptiveStepicConnector;
 import com.jetbrains.edu.learning.stepic.EduStepicConnector;
-import com.jetbrains.edu.learning.stepic.StudySettings;
 import org.jetbrains.annotations.NotNull;
 
 public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroundable {
@@ -122,7 +121,7 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun
     ProgressManager.getInstance().runProcessWithProgressAsynchronously(new Backgroundable(myProject, "Checking Task") {
       @Override
       public void run(@NotNull ProgressIndicator indicator) {
-        final Pair<Boolean, String> pair = EduAdaptiveStepicConnector.checkTask(myTask, myProject);
+        final Pair<Boolean, String> pair = EduAdaptiveStepicConnector.checkTask(myProject, myTask);
         if (pair != null) {
           final String checkMessage = pair.getSecond();
           if (pair.getFirst()) {
@@ -171,7 +170,7 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun
   }
 
   protected void postAttemptToStepic(StudyTestsOutputParser.TestsOutput testsOutput) {
-    final StudySettings studySettings = StudySettings.getInstance();
+    final StudyTaskManager studySettings = StudyTaskManager.getInstance(myProject);
     final String login = studySettings.getLogin();
     final String password = StringUtil.isEmptyOrSpaces(login) ? "" : studySettings.getPassword();
     EduStepicConnector.postAttempt(myTask, testsOutput.isSuccess(), login, password);
index a1afc0290bc5a0ec20bc8905b69bb2c14a0fe506..66c9c0152e3c5503b55524ef4e830275c7864f70 100644 (file)
@@ -45,16 +45,18 @@ import java.util.List;
 import java.util.Map;
 
 public class StudyProjectGenerator {
+  public static final String AUTHOR_ATTRIBUTE = "authors";
+  public static final String LANGUAGE_ATTRIBUTE = "language";
+  public static final String ADAPTIVE_COURSE_PREFIX = "__AdaptivePyCharmPython__";
+  public static final File ourCoursesDir = new File(PathManager.getConfigPath(), "courses");
   private static final Logger LOG = Logger.getInstance(StudyProjectGenerator.class.getName());
-  private final List<SettingsListener> myListeners = ContainerUtil.newArrayList();
-  protected static final File ourCoursesDir = new File(PathManager.getConfigPath(), "courses");
+  private static final String COURSE_NAME_ATTRIBUTE = "name";
+  private static final String COURSE_DESCRIPTION = "description";
   private static final String CACHE_NAME = "courseNames.txt";
+  private final List<SettingsListener> myListeners = ContainerUtil.newArrayList();
+  public StepicUser myUser;
   private List<CourseInfo> myCourses = new ArrayList<>();
   protected CourseInfo mySelectedCourseInfo;
-  private static final String COURSE_NAME_ATTRIBUTE = "name";
-  private static final String COURSE_DESCRIPTION = "description";
-  public static final String AUTHOR_ATTRIBUTE = "authors";
-  public static final String LANGUAGE_ATTRIBUTE = "language";
 
   public void setCourses(List<CourseInfo> courses) {
     myCourses = courses;
@@ -65,7 +67,8 @@ public class StudyProjectGenerator {
   }
 
   public void generateProject(@NotNull final Project project, @NotNull final VirtualFile baseDir) {
-    final Course course = getCourse();
+    StudyTaskManager.getInstance(project).setUser(myUser);
+    final Course course = getCourse(project);
     if (course == null) {
       LOG.warn("Course is null");
       return;
@@ -75,8 +78,8 @@ public class StudyProjectGenerator {
       () -> DumbService.allowStartingDumbModeInside(DumbModePermission.MAY_START_BACKGROUND,
                                                     () -> ApplicationManager.getApplication().runWriteAction(() -> {
                                                       course.initCourse(false);
-                                                      final File courseDirectory = new File(ourCoursesDir, course.getName());
-                                                      StudyGenerator.createCourse(course, baseDir, courseDirectory, project);
+                                                      StudyGenerator.createCourse(course, baseDir, StudyUtils
+                                                        .getCourseDirectory(project, course), project);
                                                       course.setCourseDirectory(new File(ourCoursesDir, mySelectedCourseInfo.getName()).getAbsolutePath());
                                                       VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
                                                       StudyProjectComponent.getInstance(project).registerStudyToolWindow(course);
@@ -84,7 +87,7 @@ public class StudyProjectGenerator {
                                                     })));
   }
 
-  protected Course getCourse() {
+  protected Course getCourse(@NotNull final Project project) {
     Reader reader = null;
     try {
       final File courseFile = new File(new File(ourCoursesDir, mySelectedCourseInfo.getName()), EduNames.COURSE_META_FILE);
@@ -102,9 +105,9 @@ public class StudyProjectGenerator {
     finally {
       StudyUtils.closeSilently(reader);
     }
-    final Course course = EduStepicConnector.getCourse(mySelectedCourseInfo);
+    final Course course = EduStepicConnector.getCourse(project, mySelectedCourseInfo, myUser.getEmail());
     if (course != null) {
-      flushCourse(course);
+      flushCourse(project, course);
     }
     return course;
   }
@@ -143,8 +146,8 @@ public class StudyProjectGenerator {
     }
   }
 
-  public void flushCourse(@NotNull final Course course) {
-    final File courseDirectory = new File(ourCoursesDir, course.getName());
+  public void flushCourse(@NotNull final Project project, @NotNull final Course course) {
+    final File courseDirectory = StudyUtils.getCourseDirectory(project, course);
     FileUtil.createDirectory(courseDirectory);
     flushCourseJson(course, courseDirectory);
 
@@ -361,7 +364,9 @@ public class StudyProjectGenerator {
           while ((line = reader.readLine()) != null) {
             Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
             final CourseInfo courseInfo = gson.fromJson(line, CourseInfo.class);
-            courses.add(courseInfo);
+            if (!courseInfo.isAdaptive()) {
+              courses.add(courseInfo);
+            }
           }
         }
         catch (IOException | JsonSyntaxException e) {
@@ -395,7 +400,9 @@ public class StudyProjectGenerator {
       CourseInfo courseName = addCourse(myCourses, courseDir);
       flushCache(myCourses);
       if (courseName != null && !courseName.getName().equals(unzippedName)) {
+        //noinspection ResultOfMethodCallIgnored
         courseDir.renameTo(new File(ourCoursesDir, courseName.getName()));
+        //noinspection ResultOfMethodCallIgnored
         courseDir.delete();
       }
       return courseName;
@@ -471,8 +478,8 @@ public class StudyProjectGenerator {
         for (JsonElement author : courseAuthors) {
           final JsonObject authorAsJsonObject = author.getAsJsonObject();
           final StepicUser stepicUser = new StepicUser();
-          stepicUser.setFirst_name(authorAsJsonObject.get("first_name").getAsString());
-          stepicUser.setLast_name(authorAsJsonObject.get("last_name").getAsString());
+          stepicUser.setFirstName(authorAsJsonObject.get("first_name").getAsString());
+          stepicUser.setLastName(authorAsJsonObject.get("last_name").getAsString());
           authors.add(stepicUser);
         }
         courseInfo.setAuthors(authors);
index 2b87cfc5b479fa5b2e5f29ab656190308284e574..01e3a63290e2dbfadbd52d43d1733f79693d8213 100644 (file)
@@ -55,15 +55,13 @@ public class EduAdaptiveStepicConnector {
   private static final String CONTENT_TYPE_APPL_JSON = "application/json";
   private static final String LESSON_URL = "lessons/";
   private static final String RECOMMENDATION_REACTIONS_URL = "recommendation-reactions";
-  private static final String LESSON_DEFAULT_NAME = "Adaptive";
   private static final String ATTEMPTS_URL = "attempts";
   private static final String SUBMISSION_URL = "submissions";
 
   @Nullable
-  public static Task getNextRecommendation(@NotNull Course course) {
-
+  public static Task getNextRecommendation(@NotNull final Project project, @NotNull Course course) {
     try {
-      final CloseableHttpClient client = getHttpClient();
+      final CloseableHttpClient client = getHttpClient(project);
       final URI uri = new URIBuilder(STEPIC_API_URL + RECOMMENDATIONS_URL).addParameter("course", String.valueOf(course.getId())).build();
       final HttpGet request = new HttpGet(uri);
       setHeaders(request, CONTENT_TYPE_APPL_JSON);
@@ -106,13 +104,14 @@ public class EduAdaptiveStepicConnector {
     return null;
   }
 
-  public static boolean postRecommendationReaction(int reaction, @NotNull final String user, @NotNull final String lessonId) {
+  public static boolean postRecommendationReaction(@NotNull final Project project, @NotNull final String lessonId, 
+                                                   @NotNull final String user,int reaction) {
 
     final HttpPost post = new HttpPost(STEPIC_API_URL + RECOMMENDATION_REACTIONS_URL);
     final String json = new Gson()
       .toJson(new StepicWrappers.RecommendationReactionWrapper(new StepicWrappers.RecommendationReaction(reaction, user, lessonId)));
     post.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON));
-    final CloseableHttpClient client = getHttpClient();
+    final CloseableHttpClient client = getHttpClient(project);
     setHeaders(post, CONTENT_TYPE_APPL_JSON);
     try {
       final CloseableHttpResponse execute = client.execute(post);
@@ -124,15 +123,16 @@ public class EduAdaptiveStepicConnector {
     return false;
   }
 
-  public static void addNextRecommendedTask(@NotNull Project project, int reaction) {
+  public static void addNextRecommendedTask(@NotNull final Project project, int reaction) {
     final StudyEditor editor = StudyUtils.getSelectedStudyEditor(project);
     final Course course = StudyTaskManager.getInstance(project).getCourse();
     if (course != null && editor != null && editor.getTaskFile() != null) {
       // TODO: get user from settings
-      final StepicUser user = StudySettings.getInstance().getUser();
+      final StepicUser user = StudyTaskManager.getInstance(project).getUser();
       if (user != null &&
-          postRecommendationReaction(reaction, String.valueOf(user.id), String.valueOf(editor.getTaskFile().getTask().getLesson().id))) {
-        final Task task = getNextRecommendation(course);
+          postRecommendationReaction(project, String.valueOf(editor.getTaskFile().getTask().getLesson().id), 
+                                     String.valueOf(user.id), reaction)) {
+        final Task task = getNextRecommendation(project, course);
 
         if (task != null) {
           final Lesson adaptive = course.getLessons().get(0);
@@ -213,9 +213,9 @@ public class EduAdaptiveStepicConnector {
   }
 
   @Nullable
-  public static Pair<Boolean, String> checkTask(@NotNull final Task task, @NotNull final Project project) {
+  public static Pair<Boolean, String> checkTask(@NotNull final Project project, @NotNull final Task task) {
     try {
-      final int attemptId = getAttemptId(task, ATTEMPTS_URL);
+      final int attemptId = getAttemptId(project, task, ATTEMPTS_URL);
       final Editor editor = StudyUtils.getSelectedEditor(project);
       String language = getLanguageString(task, project);
       if (editor != null && language != null) {
@@ -223,13 +223,13 @@ public class EduAdaptiveStepicConnector {
           new StepicWrappers.SubmissionToPostWrapper(String.valueOf(attemptId), "python3", editor.getDocument().getText());
         final HttpPost httpPost = new HttpPost(STEPIC_API_URL + SUBMISSION_URL);
         httpPost.setEntity(new StringEntity(new Gson().toJson(submissionToPostWrapper)));
-        final CloseableHttpClient client = getHttpClient();
+        final CloseableHttpClient client = getHttpClient(project);
         setHeaders(httpPost, CONTENT_TYPE_APPL_JSON);
         final CloseableHttpResponse execute = client.execute(httpPost);
         StepicWrappers.ResultSubmissionWrapper wrapper =
           new Gson().fromJson(EntityUtils.toString(execute.getEntity()), StepicWrappers.ResultSubmissionWrapper.class);
 
-        final StepicUser user = StudySettings.getInstance().getUser();
+        final StepicUser user = StudyTaskManager.getInstance(project).getUser();
         if (user != null) {
           final int id = user.getId();
           while (wrapper.submissions.length == 1 && wrapper.submissions[0].status.equals("evaluation")) {
@@ -244,8 +244,10 @@ public class EduAdaptiveStepicConnector {
             final CloseableHttpResponse httpResponse = client.execute(httpGet);
             wrapper = new Gson().fromJson(EntityUtils.toString(httpResponse.getEntity()), StepicWrappers.ResultSubmissionWrapper.class);
           }
-          final boolean isSolved = wrapper.submissions.length == 1 && !wrapper.submissions[0].status.equals("wrong");
-          return Pair.create(isSolved, wrapper.submissions[0].hint);
+          if (wrapper.submissions.length == 1) {
+            final boolean isSolved = !wrapper.submissions[0].status.equals("wrong");
+            return Pair.create(isSolved, wrapper.submissions[0].hint);
+          }
         }
       }
     }
@@ -281,13 +283,13 @@ public class EduAdaptiveStepicConnector {
     return null;
   }
 
-  private static int getAttemptId(@NotNull Task task, String attempts) throws IOException {
+  private static int getAttemptId(@NotNull final Project project, @NotNull Task task, @NotNull final String attempts) throws IOException {
     final StepicWrappers.AttemptToPostWrapper attemptWrapper = new StepicWrappers.AttemptToPostWrapper(task.getStepicId());
 
     final HttpPost post = new HttpPost(STEPIC_API_URL + attempts);
     post.setEntity(new StringEntity(new Gson().toJson(attemptWrapper)));
 
-    final CloseableHttpClient client = getHttpClient();
+    final CloseableHttpClient client = getHttpClient(project);
     setHeaders(post, CONTENT_TYPE_APPL_JSON);
     final CloseableHttpResponse httpResponse = client.execute(post);
     final StepicWrappers.AttemptContainer container =
index 5e36808a8c0d1ff2a780f92bbc2a5dd95e228f53..7e331d940a9cfaec1ab6752cba6f2b65fa1f3075 100644 (file)
@@ -16,6 +16,7 @@ import com.intellij.openapi.vfs.VfsUtil;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.vfs.VirtualFileFilter;
 import com.intellij.util.net.ssl.CertificateManager;
+import com.jetbrains.edu.learning.StudyTaskManager;
 import com.jetbrains.edu.learning.core.EduNames;
 import com.jetbrains.edu.learning.core.EduUtils;
 import com.jetbrains.edu.learning.courseFormat.Course;
@@ -51,12 +52,13 @@ import java.security.cert.X509Certificate;
 import java.util.*;
 
 public class EduStepicConnector {
+  private static final Logger LOG = Logger.getInstance(EduStepicConnector.class.getName());
   private static final String stepicUrl = "https://stepic.org/";
   private static final String stepicApiUrl = stepicUrl + "api/";
-  private static final Logger LOG = Logger.getInstance(EduStepicConnector.class.getName());
   private static String ourCSRFToken = "";
   private static CloseableHttpClient ourClient;
 
+
   //this prefix indicates that course can be opened by educational plugin
   public static final String PYCHARM_PREFIX = "pycharm";
   private static BasicCookieStore ourCookieStore;
@@ -64,17 +66,15 @@ public class EduStepicConnector {
   private EduStepicConnector() {
   }
 
-  public static boolean login(@NotNull final String username, @NotNull final String password) {
+  public static StepicUser login(@NotNull final String username, @NotNull final String password) {
     initializeClient();
     if (postCredentials(username, password)) {
       final StepicWrappers.AuthorWrapper stepicUserWrapper = getCurrentUser();
       if (stepicUserWrapper != null && stepicUserWrapper.users.size() == 1) {
-        final StepicUser user = stepicUserWrapper.users.get(0);
-        StudySettings.getInstance().setUser(user);
+        return stepicUserWrapper.users.get(0);
       }
-      return true;
     }
-    return false;
+    return null;
   }
 
   @Nullable
@@ -210,9 +210,9 @@ public class EduStepicConnector {
   }
   
   @NotNull
-  public static CloseableHttpClient getHttpClient() {
+  public static CloseableHttpClient getHttpClient(@NotNull final Project project) {
     if (ourClient == null) {
-      login();
+      login(project);
       initializeClient();
     }
     return ourClient;
@@ -242,9 +242,8 @@ public class EduStepicConnector {
       final String courseType = info.getType();
       if (!info.isAdaptive() && StringUtil.isEmptyOrSpaces(courseType)) continue;
       final List<String> typeLanguage = StringUtil.split(courseType, " ");
-      // TODO: should adaptive course be of PyCharmType
+      // TODO: should adaptive course be of PyCharmType ?
       if (info.isAdaptive() || (typeLanguage.size() == 2 && PYCHARM_PREFIX.equals(typeLanguage.get(0)))) {
-
         for (Integer instructor : info.instructors) {
           final StepicUser author = getFromStepic("users/" + String.valueOf(instructor), StepicWrappers.AuthorWrapper.class).users.get(0);
           info.addAuthor(author);
@@ -256,17 +255,17 @@ public class EduStepicConnector {
     return coursesContainer.meta.containsKey("has_next") && coursesContainer.meta.get("has_next") == Boolean.TRUE;
   }
 
-  public static Course getCourse(@NotNull final CourseInfo info) {
+  public static Course getCourse(@NotNull final Project project, @NotNull final CourseInfo info, @NotNull final String username) {
     final Course course = new Course();
     course.setAuthors(info.getAuthors());
     course.setDescription(info.getDescription());
-    course.setName(info.getName());
     course.setAdaptive(info.isAdaptive());
     course.setId(info.id);
     course.setUpToDate(true);  // TODO: get from stepic
     
     if (!course.isAdaptive()) {
       String courseType = info.getType();
+      course.setName(info.getName());
       course.setLanguage(courseType.substring(PYCHARM_PREFIX.length() + 1));
       try {
         for (Integer section : info.sections) {
@@ -280,10 +279,11 @@ public class EduStepicConnector {
     }
     else {
       final Lesson lesson = new Lesson();
+      course.setName(info.getName());
       //TODO: more specific name?
       lesson.setName("Adaptive");
       course.addLesson(lesson);
-      final Task recommendation = EduAdaptiveStepicConnector.getNextRecommendation(course);
+      final Task recommendation = EduAdaptiveStepicConnector.getNextRecommendation(project, course);
       if (recommendation != null) {
         lesson.addTask(recommendation);
       }
@@ -364,8 +364,7 @@ public class EduStepicConnector {
         return;
       }
       else {
-        final boolean success = login(login, password);
-        if (!success) return;
+        if (login(login, password) == null) return;
       }
     }
 
@@ -428,7 +427,7 @@ public class EduStepicConnector {
     indicator.setText("Uploading course to " + stepicUrl);
     final HttpPost request = new HttpPost(stepicApiUrl + "courses");
     if (ourClient == null || !relogin) {
-      if (!login()) return;
+      if (!login(project)) return;
     }
     final StepicWrappers.AuthorWrapper user = getCurrentUser();
     if (user != null) {
@@ -446,7 +445,7 @@ public class EduStepicConnector {
       final StatusLine line = response.getStatusLine();
       if (line.getStatusCode() != HttpStatus.SC_CREATED) {
         if (!relogin) {
-          login();
+          login(project);
           postCourse(project, course, true, indicator);
         }
         LOG.error("Failed to push " + responseString);
@@ -474,14 +473,13 @@ public class EduStepicConnector {
     }
   }
 
-  private static boolean login() {
-    final String login = StudySettings.getInstance().getLogin();
+  private static boolean login(@NotNull final Project project) {
+    final String login = StudyTaskManager.getInstance(project).getLogin();
     if (StringUtil.isEmptyOrSpaces(login)) {
       return showLoginDialog();
     }
     else {
-      boolean success = login(login, StudySettings.getInstance().getPassword());
-      if (!success) {
+      if (login(login, StudyTaskManager.getInstance(project).getPassword()) == null) {
         return showLoginDialog();
       }
     }
@@ -586,10 +584,10 @@ public class EduStepicConnector {
     return -1;
   }
 
-  public static int updateLesson(Project project, @NotNull final Lesson lesson, ProgressIndicator indicator) {
+  public static int updateLesson(@NotNull final Project project, @NotNull final Lesson lesson, ProgressIndicator indicator) {
     final HttpPut request = new HttpPut(stepicApiUrl + "lessons/" + String.valueOf(lesson.id));
     if (ourClient == null) {
-      if (!login()) {
+      if (!login(project)) {
         LOG.error("Failed to push lesson");
         return 0;
       }
@@ -625,10 +623,10 @@ public class EduStepicConnector {
     return -1;
   }
 
-  public static int postLesson(Project project, @NotNull final Lesson lesson, ProgressIndicator indicator) {
+  public static int postLesson(@NotNull final Project project, @NotNull final Lesson lesson, ProgressIndicator indicator) {
     final HttpPost request = new HttpPost(stepicApiUrl + "lessons");
     if (ourClient == null) {
-      login();
+      login(project);
     }
 
     setHeaders(request, "application/json");
index bb95494d1540d6c92a5d5c7e579abd3d3e662ca8..c4805500fe09d7dc8d0d5634d0c5dcef6f22b8b8 100644 (file)
@@ -40,14 +40,12 @@ public class LoginDialog extends DialogWrapper {
   @Override
   protected void doOKAction() {
     AuthDataHolder authData = myLoginPanel.getAuthData();
-    final boolean success = EduStepicConnector.login(authData.email, authData.password);
-    if (!success) {
-      setErrorText("Login failed");
+    final StepicUser user = EduStepicConnector.login(authData.email, authData.password);
+    if (user != null) {
+      super.doOKAction();
     }
     else {
-      StudySettings.getInstance().setLogin(authData.email);
-      StudySettings.getInstance().setPassword(authData.password);
-      super.doOKAction();
+      setErrorText("Login failed");
     }
   }
 
index c3994496fef7e53570cfe926afcfa0db3f825719..097c4a64ef9c4aca23f9976388209a5cae5b1199 100644 (file)
  */
 package com.jetbrains.edu.learning.stepic;
 
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.ui.DocumentAdapter;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
 import com.jetbrains.edu.learning.settings.StudyOptionsProvider;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -31,6 +35,7 @@ import java.awt.event.FocusListener;
 
 public class StepicStudyOptions implements StudyOptionsProvider {
   private static final String DEFAULT_PASSWORD_TEXT = "************";
+  private static final Logger LOG = Logger.getInstance(StepicStudyOptions.class);
   private JTextField myLoginTextField;
   private JPasswordField myPasswordField;
   private JPanel myPane;
@@ -98,13 +103,19 @@ public class StepicStudyOptions implements StudyOptionsProvider {
     myPasswordField.setText(StringUtil.isEmpty(password) ? null : password);
   }
 
-  
+  @Override
   public void reset() {
-    final StudySettings studySettings = StudySettings.getInstance();
-    setLogin(studySettings.getLogin());
-    setPassword(DEFAULT_PASSWORD_TEXT);
+    Project project = StudyUtils.getStudyProject();
+    if (project != null) {
+      final StudyTaskManager studySettings = StudyTaskManager.getInstance(project);
+      setLogin(studySettings.getLogin());
+      setPassword(DEFAULT_PASSWORD_TEXT);
 
-    resetCredentialsModification();
+      resetCredentialsModification();
+    }
+    else {
+      LOG.warn("No study object is opened");
+    }
   }
 
   @Override
@@ -112,13 +123,20 @@ public class StepicStudyOptions implements StudyOptionsProvider {
 
   }
 
+  @Override
   public void apply() {
     if (myCredentialsModified) {
-      final StudySettings studySettings = StudySettings.getInstance();
-      studySettings.setLogin(getLogin());
-      studySettings.setPassword(getPassword());
-      if (!StringUtil.isEmptyOrSpaces(getLogin()) && !StringUtil.isEmptyOrSpaces(getPassword())) {
-        EduStepicConnector.login(getLogin(), getPassword());
+      final Project project = StudyUtils.getStudyProject();
+      if (project != null) {
+        final StudyTaskManager studyTaskManager = StudyTaskManager.getInstance(project);
+        studyTaskManager.setLogin(getLogin());
+        studyTaskManager.setPassword(getPassword());
+        if (!StringUtil.isEmptyOrSpaces(getLogin()) && !StringUtil.isEmptyOrSpaces(getPassword())) {
+          EduStepicConnector.login(getLogin(), getPassword());
+        }
+      }
+      else {
+        LOG.warn("No study object is opened");
       }
     }
     resetCredentialsModification();
index 05365f40ae8efadb6f0c05a2a510d91b2c1170fe..ff40e3428d37003c0021b907b152eee17ecdfa6e 100644 (file)
@@ -1,28 +1,25 @@
 package com.jetbrains.edu.learning.stepic;
 
+import com.intellij.ide.passwordSafe.PasswordSafe;
+import com.intellij.ide.passwordSafe.PasswordSafeException;
+import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.util.text.StringUtil;
+import com.jetbrains.edu.learning.StudyTaskManager;
 
 public class StepicUser {
+  private static final String STEPIC_SETTINGS_PASSWORD_KEY = "STEPIC_SETTINGS_PASSWORD_KEY";
+  private static final Logger LOG = Logger.getInstance(StepicUser.class);
   int id;
-  String first_name;
+  String firstName;
   String last_name;
   String email;
-  String password;
 
-  public StepicUser(int id, String first_name, String last_name, String email, String password) {
-    this.id = id;
-    this.first_name = first_name;
-    this.last_name = last_name;
-    this.email = email;
-    this.password = password;
+  public StepicUser() {
   }
-
+  
   public StepicUser(String email, String password) {
     this.email = email;
-    this.password = password;
-  }
-
-  public StepicUser() {
+    setPassword(password);
   }
 
   public int getId() {
@@ -33,19 +30,19 @@ public class StepicUser {
     this.id = id;
   }
 
-  public String getFirst_name() {
-    return first_name;
+  public String getFirstName() {
+    return firstName;
   }
 
-  public void setFirst_name(String first_name) {
-    this.first_name = first_name;
+  public void setFirstName(String firstName) {
+    this.firstName = firstName;
   }
 
-  public String getLast_name() {
+  public String getLastName() {
     return last_name;
   }
 
-  public void setLast_name(String last_name) {
+  public void setLastName(String last_name) {
     this.last_name = last_name;
   }
 
@@ -58,14 +55,31 @@ public class StepicUser {
   }
 
   public String getPassword() {
-    return password;
+    final String login = getEmail();
+    if (StringUtil.isEmptyOrSpaces(login)) return "";
+
+    String password;
+    try {
+      password = PasswordSafe.getInstance().getPassword(null, StudyTaskManager.class, STEPIC_SETTINGS_PASSWORD_KEY + login);
+    }
+    catch (PasswordSafeException e) {
+      LOG.info("Couldn't get password for key [" + STEPIC_SETTINGS_PASSWORD_KEY + "]", e);
+      password = "";
+    }
+
+    return StringUtil.notNullize(password);
   }
 
   public void setPassword(String password) {
-    this.password = password;
+    try {
+      PasswordSafe.getInstance().storePassword(null, StudyTaskManager.class, STEPIC_SETTINGS_PASSWORD_KEY + getEmail(), password);
+    }
+    catch (PasswordSafeException e) {
+      LOG.info("Couldn't set password for key [" + STEPIC_SETTINGS_PASSWORD_KEY + getEmail() + "]", e);
+    }
   }
 
   public String getName() {
-    return StringUtil.join(new String[]{first_name, last_name}, " ");
+    return StringUtil.join(new String[]{firstName, last_name}, " ");
   }
 }
diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StudySettings.java b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/StudySettings.java
deleted file mode 100644 (file)
index c072798..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2000-2015 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.edu.learning.stepic;
-
-import com.intellij.ide.passwordSafe.PasswordSafe;
-import com.intellij.ide.passwordSafe.PasswordSafeException;
-import com.intellij.openapi.components.PersistentStateComponent;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.components.State;
-import com.intellij.openapi.components.Storage;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.text.StringUtil;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-@SuppressWarnings("MethodMayBeStatic")
-@State(name = "StudySettings", storages = @Storage("stepic_settings.xml"))
-public class StudySettings implements PersistentStateComponent<StudySettings.State> {
-
-  private State myState = new State();
-
-  public static class State {
-    @Nullable public String LOGIN = null;
-    @Nullable public StepicUser myUser = null;
-  }
-
-  private static final String STEPIC_SETTINGS_PASSWORD_KEY = "STEPIC_SETTINGS_PASSWORD_KEY";
-  private static final Logger LOG = Logger.getInstance(StudySettings.class.getName());
-
-  public static StudySettings getInstance() {
-    return ServiceManager.getService(StudySettings.class);
-  }
-
-  @NotNull
-  public String getPassword() {
-    final String login = getLogin();
-    if (StringUtil.isEmptyOrSpaces(login)) return "";
-
-    String password;
-    try {
-      password = PasswordSafe.getInstance().getPassword(null, StudySettings.class, STEPIC_SETTINGS_PASSWORD_KEY);
-    }
-    catch (PasswordSafeException e) {
-      LOG.info("Couldn't get password for key [" + STEPIC_SETTINGS_PASSWORD_KEY + "]", e);
-      password = "";
-    }
-
-    return StringUtil.notNullize(password);
-  }
-
-  public void setPassword(@NotNull String password) {
-    try {
-      PasswordSafe.getInstance().storePassword(null, StudySettings.class, STEPIC_SETTINGS_PASSWORD_KEY, password);
-    }
-    catch (PasswordSafeException e) {
-      LOG.info("Couldn't set password for key [" + STEPIC_SETTINGS_PASSWORD_KEY + "]", e);
-    }
-  }
-
-  @Nullable
-  public String getLogin() {
-    return myState.LOGIN;
-  }
-
-  public void setLogin(@Nullable String login) {
-    myState.LOGIN = login;
-  }
-  
-  @Nullable
-  public StepicUser getUser() {
-    return myState.myUser;
-  }
-  
-  public void setUser(@NotNull final StepicUser user) {
-    myState.myUser = user;
-  }
-  
-  @Nullable
-  @Override
-  public StudySettings.State getState() {
-    return myState;
-  }
-
-  @Override
-  public void loadState(StudySettings.State state) {
-    myState = state;
-  }
-}
\ No newline at end of file
index c9bc67faaae6a50ff190c8a94afe11e439cd9827..2c8ee7708bb1d00433367302cb78ea7150ce7683 100644 (file)
@@ -22,7 +22,7 @@ import com.jetbrains.edu.learning.courseFormat.Course;
 import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator;
 import com.jetbrains.edu.learning.stepic.CourseInfo;
 import com.jetbrains.edu.learning.stepic.EduStepicConnector;
-import com.jetbrains.edu.learning.stepic.StudySettings;
+import com.jetbrains.edu.learning.stepic.StepicUser;
 import icons.InteractiveLearningIcons;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -277,10 +277,10 @@ public class StudyNewProjectPanel {
       super.doOKAction();
       final ProgressManager progressManager = ProgressManager.getInstance();
       progressManager.runProcessWithProgressSynchronously(() -> {
-        final Future<Boolean> future = ApplicationManager.getApplication().executeOnPooledThread(
-          new Callable<Boolean>() {
+        final Future<StepicUser> future = ApplicationManager.getApplication().executeOnPooledThread(
+          new Callable<StepicUser>() {
             @Override
-            public Boolean call() throws Exception {
+            public StepicUser call() throws Exception {
               return EduStepicConnector.login(myRemoteCourse.getLogin(), myRemoteCourse.getPassword());
             }
           });
@@ -296,15 +296,15 @@ public class StudyNewProjectPanel {
         }
 
         try {
-          final boolean isSuccess = future.get();
-
-          if (!isSuccess) {
-            setError("Failed to log in");
+          final StepicUser stepicUser = future.get();
+          if (stepicUser != null) {
+            stepicUser.setEmail(myRemoteCourse.getLogin());
+            stepicUser.setPassword(myRemoteCourse.getPassword());
+            myGenerator.myUser = stepicUser;
+            ApplicationManager.getApplication().invokeLater(StudyNewProjectPanel.this::refreshCoursesList);
           }
           else {
-            StudySettings.getInstance().setLogin(myRemoteCourse.getLogin());
-            StudySettings.getInstance().setPassword(myRemoteCourse.getPassword());
-            ApplicationManager.getApplication().invokeLater(StudyNewProjectPanel.this::refreshCoursesList);
+            setError("Failed to log in");
           }
         }
         catch (InterruptedException e) {