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; }