From 45dabb0a497e595d3f4a6fc18fa0cb1847adb97d Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Tue, 21 Jun 2016 17:52:34 +0300 Subject: [PATCH] Fix according to review IDEA-CR-11509: 1) Don't post attempts to Stepic in Course creator projects 2) Add progress for getting course from stepic in project generator 3) Set timeout for stepic requests 4) Don't cache adaptive courses with no recommendations --- .../edu/learning/checker/StudyCheckTask.java | 6 ++- .../StudyProjectGenerator.java | 40 ++++++++++++------- .../stepic/EduAdaptiveStepicConnector.java | 39 ++++++++++++++++++ .../learning/stepic/EduStepicConnector.java | 6 ++- 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java index 62374bff0467..fd98e1690139 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java @@ -17,6 +17,7 @@ import com.jetbrains.edu.learning.StudyState; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.actions.StudyAfterCheckAction; +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.StudyStatus; @@ -95,7 +96,10 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun onTaskFailed(testsOutput.getMessage()); } runAfterTaskCheckedActions(); - postAttemptToStepic(testsOutput); + final Course course = StudyTaskManager.getInstance(myProject).getCourse(); + if (course != null && EduNames.STUDY.equals(course.getCourseMode())) { + postAttemptToStepic(testsOutput); + } } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java index 8c2db07be964..5f86fc96212c 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java @@ -11,6 +11,7 @@ import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; @@ -59,7 +60,7 @@ public class StudyProjectGenerator { private final List myListeners = ContainerUtil.newArrayList(); public StepicUser myUser; private List myCourses = new ArrayList<>(); - private List myEnrolledCoursesIds = new ArrayList<>(); + private List myEnrolledCoursesIds = new ArrayList<>(); protected CourseInfo mySelectedCourseInfo; public void setCourses(List courses) { @@ -69,7 +70,7 @@ public class StudyProjectGenerator { public boolean isLoggedIn() { return myUser != null && !StringUtil.isEmptyOrSpaces(myUser.getPassword()) && !StringUtil.isEmptyOrSpaces(myUser.getEmail()); } - + public void setEnrolledCoursesIds(@NotNull final List coursesIds) { myEnrolledCoursesIds = coursesIds; } @@ -88,21 +89,23 @@ public class StudyProjectGenerator { final Course course = getCourse(project); if (course == null) { LOG.warn("Course is null"); + Messages.showWarningDialog("Some problems occurred while creating the course", "Error in Course Creation"); return; } final File courseDirectory = StudyUtils.getCourseDirectory(project, course); StudyTaskManager.getInstance(project).setCourse(course); ApplicationManager.getApplication().runWriteAction(() -> { - StudyGenerator.createCourse(course, baseDir, courseDirectory, project); - course.setCourseDirectory(courseDirectory.getAbsolutePath()); - VirtualFileManager.getInstance().refreshWithoutFileWatcher(true); - StudyProjectComponent.getInstance(project).registerStudyToolWindow(course); - openFirstTask(course, project); - }); + StudyGenerator.createCourse(course, baseDir, courseDirectory, project); + course.setCourseDirectory(courseDirectory.getAbsolutePath()); + VirtualFileManager.getInstance().refreshWithoutFileWatcher(true); + StudyProjectComponent.getInstance(project).registerStudyToolWindow(course); + openFirstTask(course, project); + }); } @Nullable protected Course getCourse(@NotNull final Project project) { + final File courseFile = new File(new File(OUR_COURSES_DIR, mySelectedCourseInfo.getName()), EduNames.COURSE_META_FILE); if (courseFile.exists()) { return readCourseFromCache(courseFile, false); @@ -115,12 +118,21 @@ public class StudyProjectGenerator { return readCourseFromCache(adaptiveCourseFile, true); } } - final Course course = EduStepicConnector.getCourse(project, mySelectedCourseInfo); - if (course != null) { - flushCourse(project, course); - course.initCourse(false); - } - return course; + return ProgressManager.getInstance().runProcessWithProgressSynchronously(new ThrowableComputable() { + @Override + public Course compute() throws RuntimeException { + ProgressManager.getInstance().getProgressIndicator().setIndeterminate(true); + return execCancelable(() -> { + + final Course course = EduStepicConnector.getCourse(project, mySelectedCourseInfo); + if (course != null) { + flushCourse(project, course); + course.initCourse(false); + } + return course; + }); + } + }, "Creating Course", true, project); } @Nullable diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java index 642b0a160b3b..fd50ea62cf7f 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java @@ -10,6 +10,9 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.ui.popup.Balloon; +import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -28,6 +31,7 @@ import com.jetbrains.edu.learning.ui.StudyToolWindow; import org.apache.http.HttpEntity; import org.apache.http.HttpStatus; import org.apache.http.StatusLine; +import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; @@ -55,6 +59,7 @@ public class EduAdaptiveStepicConnector { public static final String PYTHON27 = "python27"; public static final String PYTHON3 = "python3"; private static final Logger LOG = Logger.getInstance(EduAdaptiveStepicConnector.class); + private static final int CONNECTION_TIMEOUT = 60 * 1000; @Nullable public static Task getNextRecommendation(@NotNull final Project project, @NotNull Course course) { @@ -65,6 +70,7 @@ public class EduAdaptiveStepicConnector { .build(); final HttpGet request = new HttpGet(uri); setHeaders(request, EduStepicNames.CONTENT_TYPE_APPL_JSON); + setTimeout(request); final CloseableHttpResponse response = client.execute(request); final StatusLine statusLine = response.getStatusLine(); @@ -106,6 +112,17 @@ public class EduAdaptiveStepicConnector { } catch (IOException e) { LOG.warn(e.getMessage()); + + final String connectionMessages = "Connection problems, Please, try again"; + final Balloon balloon = + JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(connectionMessages, MessageType.ERROR, null) + .createBalloon(); + ApplicationManager.getApplication().invokeLater(() -> { + if (StudyUtils.getSelectedEditor(project) != null) { + StudyUtils.showCheckPopUp(project, balloon); + } + }); + } catch (URISyntaxException e) { LOG.warn(e.getMessage()); @@ -113,6 +130,24 @@ public class EduAdaptiveStepicConnector { return null; } + private static void setTimeout(HttpGet request) { + final RequestConfig requestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(CONNECTION_TIMEOUT) + .setConnectTimeout(CONNECTION_TIMEOUT) + .setSocketTimeout(CONNECTION_TIMEOUT) + .build(); + request.setConfig(requestConfig); + } + + private static void setTimeout(HttpPost request) { + final RequestConfig requestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(CONNECTION_TIMEOUT) + .setConnectTimeout(CONNECTION_TIMEOUT) + .setSocketTimeout(CONNECTION_TIMEOUT) + .build(); + request.setConfig(requestConfig); + } + private static void viewAllSteps(CloseableHttpClient client, int lessonId) throws URISyntaxException, IOException { final URI unitsUrl = new URIBuilder(EduStepicNames.UNITS).addParameter(EduNames.LESSON, String.valueOf(lessonId)).build(); final StepicWrappers.UnitContainer unitContainer = getFromStepic(unitsUrl.toString(), StepicWrappers.UnitContainer.class); @@ -152,6 +187,7 @@ public class EduAdaptiveStepicConnector { post.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON)); final CloseableHttpClient client = getHttpClient(project); setHeaders(post, EduStepicNames.CONTENT_TYPE_APPL_JSON); + setTimeout(post); try { final CloseableHttpResponse execute = client.execute(post); return execute.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED; @@ -405,6 +441,7 @@ public class EduAdaptiveStepicConnector { new StepicWrappers.SubmissionToPostWrapper(String.valueOf(attemptId), language, text); final HttpPost httpPost = new HttpPost(EduStepicNames.STEPIC_API_URL + EduStepicNames.SUBMISSIONS); setHeaders(httpPost, EduStepicNames.CONTENT_TYPE_APPL_JSON); + setTimeout(httpPost); try { httpPost.setEntity(new StringEntity(new Gson().toJson(submissionToPostWrapper))); } @@ -435,6 +472,7 @@ public class EduAdaptiveStepicConnector { .build(); final HttpGet httpGet = new HttpGet(submissionURI); setHeaders(httpGet, EduStepicNames.CONTENT_TYPE_APPL_JSON); + setTimeout(httpGet); final CloseableHttpResponse httpResponse = client.execute(httpGet); final String entity = EntityUtils.toString(httpResponse.getEntity()); wrapper = new Gson().fromJson(entity, StepicWrappers.ResultSubmissionWrapper.class); @@ -481,6 +519,7 @@ public class EduAdaptiveStepicConnector { final CloseableHttpClient client = getHttpClient(project); setHeaders(post, EduStepicNames.CONTENT_TYPE_APPL_JSON); + setTimeout(post); final CloseableHttpResponse httpResponse = client.execute(post); final String entity = EntityUtils.toString(httpResponse.getEntity()); final StepicWrappers.AttemptContainer container = diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java index 081081923c8f..a70a18bb8c3f 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java @@ -334,9 +334,11 @@ public class EduStepicConnector { final Task recommendation = EduAdaptiveStepicConnector.getNextRecommendation(project, course); if (recommendation != null) { lesson.addTask(recommendation); + return course; + } + else { + return null; } - - return course; } return null; }