@Override public ProblemAndTestCaseList importExercise(Course course, String exerciseHash) throws CloudCoderAuthenticationException { if (course == null || exerciseHash == null) { throw new IllegalArgumentException(); } // Make sure a user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); // Find user's registration in the course: if user is not instructor, // import is not allowed CourseRegistrationList reg = Database.getInstance().findCourseRegistrations(user, course); if (!reg.isInstructor()) { throw new CloudCoderAuthenticationException( "Only an instructor can import a problem in a course"); } // Attempt to load the problem from the exercise repository. ConfigurationSetting repoUrlSetting = Database.getInstance().getConfigurationSetting(ConfigurationSettingName.PUB_REPOSITORY_URL); if (repoUrlSetting == null) { logger.error("Repository URL configuration setting is not set"); return null; } // GET the exercise from the repository HttpGet get = new HttpGet(repoUrlSetting.getValue() + "/exercisedata/" + exerciseHash); ProblemAndTestCaseList exercise = null; HttpClient client = new DefaultHttpClient(); try { HttpResponse response = client.execute(get); HttpEntity entity = response.getEntity(); ContentType contentType = ContentType.getOrDefault(entity); Reader reader = new InputStreamReader(entity.getContent(), contentType.getCharset()); exercise = new ProblemAndTestCaseList(); exercise.setTestCaseList(new TestCase[0]); JSONConversion.readProblemAndTestCaseData( exercise, ReflectionFactory.forClass(Problem.class), ReflectionFactory.forClass(TestCase.class), reader); // Set the course id exercise.getProblem().setCourseId(course.getId()); } catch (IOException e) { logger.error("Error importing exercise from repository", e); return null; } finally { client.getConnectionManager().shutdown(); } // Set "when assigned" and "when due" to reasonable default values long now = System.currentTimeMillis(); exercise.getProblem().setWhenAssigned(now); exercise.getProblem().setWhenDue(now + 48L * 60L * 60L * 1000L); // Set problem authorship as IMPORTED exercise.getProblem().setProblemAuthorship(ProblemAuthorship.IMPORTED); // For IMPORTED problems, parent_hash is actually the hash of the problem // itself. If the problem is modified (and the authorship changed // to IMPORTED_AND_MODIFIED), then the (unchanged) parent_hash value // really does reflect the "parent" problem. exercise.getProblem().setParentHash(exerciseHash); // Store the exercise in the database exercise = Database.getInstance().storeProblemAndTestCaseList(exercise, course, user); return exercise; }
@Override public ShareExercisesResult submitExercises( Problem[] problems, String repoUsername, String repoPassword) throws CloudCoderAuthenticationException { logger.warn("Sharing " + problems.length + " exercises"); // create the result place holder ShareExercisesResult result = new ShareExercisesResult(problems.length); if (problems.length == 0) { result.failAll("No problems to be shared!"); return result; } // Only a course instructor may share an exercise. User authenticatedUser = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); Course course = new Course(); course.setId(problems[0].getCourseId()); Database.getInstance().reloadModelObject(course); CourseRegistrationList regList = Database.getInstance().findCourseRegistrations(authenticatedUser, course); if (!regList.isInstructor()) { result.failAll("You must be an instructor to share an exercise"); return result; } // Get the exercise repository URL ConfigurationSetting repoUrlSetting = Database.getInstance().getConfigurationSetting(ConfigurationSettingName.PUB_REPOSITORY_URL); if (repoUrlSetting == null) { result.failAll("URL of exercise repository is not configured"); return result; } String repoUrl = repoUrlSetting.getValue(); if (repoUrl.endsWith("/")) { repoUrl = repoUrl.substring(0, repoUrl.length() - 1); } HttpPost post = new HttpPost(repoUrl + "/exercisedata"); // Encode an Authorization header using the provided repository username and password. String authHeaderValue = "Basic " + DatatypeConverter.printBase64Binary( (repoUsername + ":" + repoPassword).getBytes(Charset.forName("UTF-8"))); // System.out.println("Authorization: " + authHeaderValue); post.addHeader("Authorization", authHeaderValue); // Now go through and upload each problem // For now, we do this one at a time // In the future we could send problems and test cases // to the repo in bulk, and add a new web service to handle it for (Problem p : problems) { // Look up the test cases List<TestCase> testCaseList = Database.getInstance().getTestCasesForProblem(p.getProblemId()); ProblemAndTestCaseList exercise = new ProblemAndTestCaseList(); exercise.setProblem(p); exercise.setTestCaseList(testCaseList); // Convert the exercise to a JSON string StringEntity entity; StringWriter sw = new StringWriter(); try { JSONConversion.writeProblemAndTestCaseData(exercise, sw); entity = new StringEntity(sw.toString(), ContentType.create("application/json", "UTF-8")); } catch (IOException e) { // fail remaining test cases and return our results thus far // some exercises may have been successfully shared result.failRemaining("Could not convert exercise to JSON: " + e.getMessage()); return result; } post.setEntity(entity); // POST the exercise to the repository HttpClient client = new DefaultHttpClient(); try { HttpResponse response = client.execute(post); StatusLine statusLine = response.getStatusLine(); if (statusLine.getStatusCode() == HttpStatus.SC_OK) { // Update the exercise's shared flag so we have a record that it was shared. exercise.getProblem().setShared(true); exercise.getProblem().setProblemAuthorship(ProblemAuthorship.IMPORTED); Database.getInstance().storeProblemAndTestCaseList(exercise, course, authenticatedUser); result.success(); } else if (statusLine.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { result.failRemaining( "Authentication with repository failed - incorrect username/password?"); return result; } else { result.failRemaining( "Failed to publish exercise to repository: " + statusLine.getReasonPhrase()); return result; } } catch (ClientProtocolException e) { result.failRemaining("Error sending exercise to repository: " + e.getMessage()); return result; } catch (IOException e) { result.failRemaining("Error sending exercise to repository: " + e.getMessage()); return result; } finally { client.getConnectionManager().shutdown(); } } result.allSucceeded( "Successfully uploaded " + problems.length + " exercise to repository. Thanks!"); return result; }