public Problem[] getProblemsForUser(Course course, int userId) throws CloudCoderAuthenticationException { // Make sure user is authenticated User user = Database.getInstance().getUserGivenId(userId); List<Problem> resultList = Database.getInstance().getProblemsInCourse(user, course).getProblemList(); for (Problem p : resultList) { logger.warn(p.getTestname() + " - " + p.getBriefDescription()); } return resultList.toArray(new Problem[resultList.size()]); }
@Override public void startImportAllProblemsFromCourse(Course source, Course dest) throws CloudCoderAuthenticationException { User authenticatedUser = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); // Make sure that the authenticated user is registered as an instructor for // both the source and destination courses. boolean sourceInstructor = false, destInstructor = false; List<? extends Object[]> courses = Database.getInstance().getCoursesForUser(authenticatedUser); for (Object[] triple : courses) { CourseRegistration reg = (CourseRegistration) triple[2]; if (reg.getCourseId() == source.getId() && reg.getRegistrationType().isInstructor()) { sourceInstructor = true; } if (reg.getCourseId() == dest.getId() && reg.getRegistrationType().isInstructor()) { destInstructor = true; } } // Create a FutureImportCourseResult FutureImportCourseResult result = new FutureImportCourseResult(); getThreadLocalRequest() .getSession() .setAttribute(SessionAttributeKeys.FUTURE_IMPORT_COURSE_RESULT_KEY, result); if (!sourceInstructor || !destInstructor) { result.set(new OperationResult(false, "Permission denied (not an instructor)")); return; } // Start the actual operation result.start(source, dest, authenticatedUser); }
/* (non-Javadoc) * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#getCourseAndCourseRegistrations() */ @Override public CourseAndCourseRegistration[] getCourseAndCourseRegistrations() throws CloudCoderAuthenticationException { // make sure the client has authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); logger.info("Loading courses and registrations for user " + user.getUsername()); List<? extends Object[]> resultList = Database.getInstance().getCoursesForUser(user); CourseAndCourseRegistration[] result = new CourseAndCourseRegistration[resultList.size()]; int count = 0; for (Object[] tuple : resultList) { Course course = (Course) tuple[0]; Term term = (Term) tuple[1]; course.setTerm(term); CourseRegistration reg = (CourseRegistration) tuple[2]; CourseAndCourseRegistration obj = new CourseAndCourseRegistration(); obj.setCourse(course); obj.setCourseRegistration(reg); result[count++] = obj; } return result; }
@Override public SubmissionReceipt[] getAllSubmissionReceiptsForUser(Problem problem, User user) throws CloudCoderAuthenticationException { // Make sure user is authenticated User authenticatedUser = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); // Make sure authenticated user is an instructor CourseRegistrationList regList = Database.getInstance().findCourseRegistrations(authenticatedUser, problem.getCourseId()); if (!regList.isInstructor()) { return new SubmissionReceipt[0]; } return Database.getInstance().getAllSubmissionReceiptsForUser(problem, user); }
@Override public NamedTestResult[] getTestResultsForSubmission(Problem problem, SubmissionReceipt receipt) throws CloudCoderAuthenticationException { User authenticatedUser = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); return Database.getInstance().getTestResultsForSubmission(authenticatedUser, problem, receipt); }
/* (non-Javadoc) * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#startQuiz(org.cloudcoder.app.shared.model.Problem, int) */ @Override public Quiz startQuiz(Problem problem, int section) throws CloudCoderAuthenticationException { // Make sure user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); return Database.getInstance().startQuiz(user, problem, section); }
/* (non-Javadoc) * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#endQuiz(org.cloudcoder.app.shared.model.Quiz) */ @Override public Boolean endQuiz(Quiz quiz) throws CloudCoderAuthenticationException { // Make sure user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); return Database.getInstance().endQuiz(user, quiz); }
@Override public Integer[] getSectionsForCourse(Course course) throws CloudCoderAuthenticationException { // Make sure user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); return Database.getInstance().getSectionsForCourse(course, user); }
/* (non-Javadoc) * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#getTestCasesForProblem(int) */ @Override public TestCase[] getTestCasesForProblem(int problemId) throws CloudCoderAuthenticationException { // Make sure user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); return Database.getInstance().getTestCasesForProblem(user, true, problemId); }
/* (non-Javadoc) * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#setModuleName(org.cloudcoder.app.shared.model.Problem, java.lang.String) */ @Override public Module setModule(Problem problem, String moduleName) throws CloudCoderAuthenticationException { // Make sure user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); return Database.getInstance().setModule(user, problem, moduleName); }
@Override public OperationResult deleteProblem(Course course, Problem problem) throws CloudCoderAuthenticationException { // Make sure a user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); boolean result = Database.getInstance().deleteProblem(user, course, problem); return new OperationResult( result, result ? "Problem deleted successfully" : "Could not delete problem"); }
@Override public void submit(int problemId, String programText) throws CloudCoderAuthenticationException, SubmissionException { // Make sure that client is authenticated and has permission to edit the given problem User user = ServletUtil.checkClientIsAuthenticated(getThreadLocalRequest()); HttpSession session = getThreadLocalRequest().getSession(); // The Problem should be stored in the user's session Problem problem = (Problem) session.getAttribute(SessionAttributeKeys.PROBLEM_KEY); if (problem == null || problem.getProblemId() != problemId) { throw new CloudCoderAuthenticationException(); } // Insert a full-text change into the database. Change fullTextChange = new Change( ChangeType.FULL_TEXT, 0, 0, 0, 0, System.currentTimeMillis(), user.getId(), problem.getProblemId(), programText); Database.getInstance().storeChanges(new Change[] {fullTextChange}); // Get test cases. (TODO: cache them?) List<TestCase> testCaseList = Database.getInstance().getTestCasesForProblem(problemId); ISubmitService submitService = DefaultSubmitService.getInstance(); logger.info("Passing submission to submit service..."); IFutureSubmissionResult future = submitService.submitAsync(problem, testCaseList, programText); // Put the full-text Change and IFutureSubmissionResult in the user's session. addSessionObjects(session, fullTextChange, future); }
/* (non-Javadoc) * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#getBestSubmissionReceipts(org.cloudcoder.app.shared.model.Problem) */ @Override public UserAndSubmissionReceipt[] getBestSubmissionReceipts(Problem problem, int section) throws CloudCoderAuthenticationException { // Make sure user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); // Return best submission receipts for each user in course List<UserAndSubmissionReceipt> result = Database.getInstance().getBestSubmissionReceipts(problem, section, user); return result.toArray(new UserAndSubmissionReceipt[result.size()]); }
/* (non-Javadoc) * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#getTestCaseNamesForProblem(int) */ @Override public String[] getTestCaseNamesForProblem(int problemId) throws CloudCoderAuthenticationException { // Make sure user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); TestCase[] testCaseList = Database.getInstance().getTestCasesForProblem(user, false, problemId); String[] result = new String[testCaseList.length]; for (int i = 0; i < testCaseList.length; i++) { result[i] = testCaseList[i].getTestCaseName(); } return result; }
/* (non-Javadoc) * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#getModulesForCourse(org.cloudcoder.app.shared.model.Course) */ @Override public Module[] getModulesForCourse(Course course) throws CloudCoderAuthenticationException { // Make sure user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); Module[] modulesForCourse = Database.getInstance().getModulesForCourse(user, course); // Sort using ModuleNameComparator Arrays.sort(modulesForCourse, new ModuleNameComparator()); return modulesForCourse; }
@Override public TestCase[] getNonSecretTestCasesForProblem(int problemId) throws CloudCoderAuthenticationException { User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); TestCase[] testCases = Database.getInstance().getTestCasesForProblem(user, false, problemId); ArrayList<TestCase> nonSecretTestCases = new ArrayList<TestCase>(); for (TestCase tc : testCases) { if (!tc.isSecret()) { nonSecretTestCases.add(tc); } } return nonSecretTestCases.toArray(new TestCase[nonSecretTestCases.size()]); }
/* (non-Javadoc) * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#storeProblemAndTestCaseList(org.cloudcoder.app.shared.model.ProblemAndTestCaseList) */ @Override public ProblemAndTestCaseList storeProblemAndTestCaseList( ProblemAndTestCaseList problemAndTestCaseList, Course course) throws CloudCoderAuthenticationException { // Make sure user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); // Store in database Database.getInstance().storeProblemAndTestCaseList(problemAndTestCaseList, course, user); // Return updated object return problemAndTestCaseList; }
@Override public Problem[] getProblems(Course course) throws CloudCoderAuthenticationException { // Make sure user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); List<Problem> resultList = Database.getInstance().getProblemsInCourse(user, course).getProblemList(); for (Problem p : resultList) { logger.info(p.getTestname() + " - " + p.getBriefDescription()); } return resultList.toArray(new Problem[resultList.size()]); }
/* (non-Javadoc) * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#getProblemAndSubscriptionReceipts(org.cloudcoder.app.shared.model.Course) */ @Override public ProblemAndSubmissionReceipt[] getProblemAndSubscriptionReceipts( Course course, User forUser, Module module) throws CloudCoderAuthenticationException { // Make sure user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); logger.info( "getting problems/submission receipts for authenticated user " + user.getUsername()); List<ProblemAndSubmissionReceipt> resultList = Database.getInstance() .getProblemAndSubscriptionReceiptsInCourse(user, course, forUser, module); logger.info("Received " + resultList.size() + " problems/submission receipts"); return resultList.toArray(new ProblemAndSubmissionReceipt[resultList.size()]); }
/* (non-Javadoc) * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#findCurrentQuiz(org.cloudcoder.app.shared.model.Problem) */ @Override public Quiz findCurrentQuiz(Problem problem) throws CloudCoderAuthenticationException { // Make sure user is authenticated User user = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); // Find current quiz (if any) Quiz quiz = Database.getInstance().findCurrentQuiz(user, problem); if (quiz != null) { // Set the end time to the current time: this allows the client // to compute how long the quiz has been active quiz.setEndTime(System.currentTimeMillis()); } return quiz; }
/* (non-Javadoc) * @see org.cloudcoder.app.client.rpc.SubmitService#checkSubmission() */ @Override public SubmissionResult checkSubmission() throws CloudCoderAuthenticationException, SubmissionException { // Make sure user is authenticated User user = ServletUtil.checkClientIsAuthenticated(getThreadLocalRequest()); HttpSession session = getThreadLocalRequest().getSession(); // The Problem should be stored in the user's session Problem problem = (Problem) session.getAttribute(SessionAttributeKeys.PROBLEM_KEY); if (problem == null) { throw new CloudCoderAuthenticationException(); } // Retrieve session objects for submission IFutureSubmissionResult future = (IFutureSubmissionResult) session.getAttribute(SessionAttributeKeys.FUTURE_SUBMISSION_RESULT_KEY); Change fullTextChange = (Change) session.getAttribute(SessionAttributeKeys.FULL_TEXT_CHANGE_KEY); if (future == null) { throw new SubmissionException("No pending submission in session"); } if (fullTextChange == null) { throw new SubmissionException("No full-text change for pending submission in session"); } // See if the SubmissionResult is ready SubmissionResult result; try { result = future.poll(); } catch (SubmissionException e) { // If poll() throws an exception, the submission completed // with an error, but it did complete, so clear the session objects. clearSessionObjects(session); throw e; } if (result == null) { // submission result not ready yet return null; } // We are just trusting that the submission result is for the // correct problem... // Add a SubmissionReceipt to the database SubmissionReceipt receipt = createSubmissionReceipt(fullTextChange, result, user, problem); Database.getInstance().insertSubmissionReceipt(receipt, result.getTestResults()); int numResult = 0; if (result != null && result.getTestResults() != null) { numResult = result.getTestResults().length; } logger.info( "Compilation " + result.getCompilationResult() + ", received " + numResult + " TestResults"); // Clear session objects for submission clearSessionObjects(session); return result; }
/* (non-Javadoc) * @see org.cloudcoder.app.client.rpc.GetCoursesAndProblemsService#submitExercise(org.cloudcoder.app.shared.model.ProblemAndTestCaseList, java.lang.String, java.lang.String) */ @Override public OperationResult submitExercise( ProblemAndTestCaseList exercise, String repoUsername, String repoPassword) throws CloudCoderAuthenticationException { logger.warn("Sharing exercise: " + exercise.getProblem().getTestname()); // Only a course instructor may share an exercise. User authenticatedUser = ServletUtil.checkClientIsAuthenticated( getThreadLocalRequest(), GetCoursesAndProblemsServiceImpl.class); Course course = new Course(); course.setId(exercise.getProblem().getCourseId()); Database.getInstance().reloadModelObject(course); CourseRegistrationList regList = Database.getInstance().findCourseRegistrations(authenticatedUser, course); if (!regList.isInstructor()) { return new OperationResult(false, "You must be an instructor to share an exercise"); } // Get the exercise repository URL ConfigurationSetting repoUrlSetting = Database.getInstance().getConfigurationSetting(ConfigurationSettingName.PUB_REPOSITORY_URL); if (repoUrlSetting == null) { return new OperationResult(false, "URL of exercise repository is not configured"); } 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); // 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) { return new OperationResult(false, "Could not convert exercise to JSON: " + e.getMessage()); } 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); Database.getInstance().storeProblemAndTestCaseList(exercise, course, authenticatedUser); return new OperationResult( true, "Exercise successfully published to the repository - thank you!"); } else if (statusLine.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { return new OperationResult( false, "Authentication with repository failed - incorrect username/password?"); } else { return new OperationResult( false, "Failed to publish exercise to repository: " + statusLine.getReasonPhrase()); } } catch (ClientProtocolException e) { return new OperationResult(false, "Error sending exercise to repository: " + e.getMessage()); } catch (IOException e) { return new OperationResult(false, "Error sending exercise to repository: " + e.getMessage()); } finally { client.getConnectionManager().shutdown(); } }
@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; }
@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; }