Index: lams_bb_integration/WEB-INF/web.xml =================================================================== RCS file: /usr/local/cvsroot/lams_bb_integration/WEB-INF/web.xml,v diff -u -r1.19 -r1.20 --- lams_bb_integration/WEB-INF/web.xml 3 May 2017 15:44:32 -0000 1.19 +++ lams_bb_integration/WEB-INF/web.xml 23 May 2017 16:21:58 -0000 1.20 @@ -33,6 +33,10 @@ org.lamsfoundation.ld.integration.blackboard.GradebookSyncServlet + GradebookSyncFixServlet + org.lamsfoundation.ld.integration.blackboard.GradebookSyncFixServlet + + LessonManagerServlet org.lamsfoundation.ld.integration.blackboard.LessonManagerServlet @@ -88,8 +92,12 @@ GradebookSyncServlet /GradebookSync - + + GradebookSyncFixServlet + /GradebookSyncFix + + LessonManagerServlet /LessonManager Index: lams_bb_integration/src/org/lamsfoundation/ld/integration/blackboard/GradebookSyncFixServlet.java =================================================================== RCS file: /usr/local/cvsroot/lams_bb_integration/src/org/lamsfoundation/ld/integration/blackboard/GradebookSyncFixServlet.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lams_bb_integration/src/org/lamsfoundation/ld/integration/blackboard/GradebookSyncFixServlet.java 23 May 2017 16:21:58 -0000 1.1 @@ -0,0 +1,219 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + + +package org.lamsfoundation.ld.integration.blackboard; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.net.ConnectException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.lamsfoundation.ld.integration.Constants; +import org.lamsfoundation.ld.integration.util.LamsBuildingBlockException; +import org.lamsfoundation.ld.integration.util.LamsSecurityUtil; +import org.lamsfoundation.ld.integration.util.LineitemUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import blackboard.base.InitializationException; +import blackboard.data.course.CourseMembership; +import blackboard.data.gradebook.Lineitem; +import blackboard.data.gradebook.Score; +import blackboard.persist.Id; +import blackboard.persist.PersistenceException; +import blackboard.persist.course.CourseMembershipDbLoader; +import blackboard.persist.gradebook.ScoreDbLoader; +import blackboard.persist.gradebook.ScoreDbPersister; +import blackboard.platform.BbServiceException; +import blackboard.platform.BbServiceManager; +import blackboard.platform.context.Context; +import blackboard.platform.context.ContextManager; + +/** + * Fixes issues created by GradebookSyncServlet, namely, removes marks of users that had not completed the lesson. + */ +@SuppressWarnings("serial") +public class GradebookSyncFixServlet extends HttpServlet { + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + ContextManager ctxMgr = null; + int numberDeletedScores = 0; + + try { + // get Blackboard context + ctxMgr = (ContextManager) BbServiceManager.lookupService(ContextManager.class); + Context ctx = ctxMgr.setContext(request); + CourseMembershipDbLoader courseMemLoader = CourseMembershipDbLoader.Default.getInstance(); + ScoreDbLoader scoreLoader = ScoreDbLoader.Default.getInstance(); + ScoreDbPersister scorePersister = ScoreDbPersister.Default.getInstance(); + + // get Parameter values + String lamsLessonIdParam = request.getParameter(Constants.PARAM_LESSON_ID); + // validate method parameter + if (lamsLessonIdParam == null) { + throw new RuntimeException("Requred parameters missing. lsid=" + lamsLessonIdParam); + } + + Lineitem lineitem = LineitemUtil.getLineitem(ctx.getUserId(), lamsLessonIdParam, true); + if (lineitem == null) { + throw new ServletException("Lineitem was not found for userId:" + ctx.getUserId() + " and lamsLessonId:" + lamsLessonIdParam); + } + + String username = ctx.getUser().getUserName(); + String serviceURL = LamsSecurityUtil.getServerAddress() + "/services/xml/LessonManager?" + + LamsSecurityUtil.generateAuthenticateParameters(username) + + "&method=gradebookMarksLesson&lsId=" + lamsLessonIdParam; + + URL url = new URL(serviceURL); + URLConnection conn = url.openConnection(); + if (!(conn instanceof HttpURLConnection)) { + throw new RuntimeException("Unable to open connection to: " + serviceURL); + } + + HttpURLConnection httpConn = (HttpURLConnection) conn; + + if (httpConn.getResponseCode() != HttpURLConnection.HTTP_OK) { + String errorMsg = "HTTP Response Code: " + httpConn.getResponseCode() + ", HTTP Response Message: " + + httpConn.getResponseMessage(); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.getWriter().write(errorMsg); + return; + } + + InputStream is = conn.getInputStream(); + + // parse xml response + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document document = db.parse(is); + Node lesson = document.getDocumentElement().getFirstChild(); + NodeList learnerResults = lesson.getChildNodes(); + + //in order to reduce DB queries we get scores and courseMemberships all at once + List dbScores = scoreLoader.loadByLineitemId(lineitem.getId()); + List courseMemberships = courseMemLoader.loadByCourseId(lineitem.getCourseId(), null, true); + + //removes marks of users that had not completed the lesson + for (CourseMembership courseMembership: courseMemberships) { + Id courseMembershipId = courseMembership.getId(); + String userName = courseMembership.getUser().getUserName(); + + // find old score + Score currentScore = null; + for (Score dbScore : dbScores) { + if (dbScore.getCourseMembershipId().equals(courseMembershipId)) { + currentScore = dbScore; + break; + } + } + + // determine whether user had finished the lesson + boolean isUserHadFinishedLesson = false; + for (int i = 0; i < learnerResults.getLength(); i++) { + Node learnerResult = learnerResults.item(i); + + String extUsername = learnerResult.getAttributes().getNamedItem("extUsername").getNodeValue(); + + if (userName.equals(extUsername)) { + isUserHadFinishedLesson = true; + break; + } + } + + //remove marks of the user that had not completed the lesson. + if ((currentScore != null) && !isUserHadFinishedLesson) { + scorePersister.deleteById(currentScore.getId()); + + //calculate how many marks are removed + numberDeletedScores++; + } + } + + + } catch (LamsBuildingBlockException e) { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + out.write("Exception was thrown: " + e.getMessage()); + return; + + } catch (MalformedURLException e) { + throw new ServletException("Unable to get LAMS learning designs, bad URL: " + + ", please check lams.properties", e); + } catch (IllegalStateException e) { + throw new ServletException( + "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator", + e); + } catch (ConnectException e) { + throw new ServletException( + "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator", + e); + } catch (UnsupportedEncodingException e) { + throw new ServletException(e); + } catch (IOException e) { + throw new ServletException(e); + } catch (ParserConfigurationException e) { + throw new ServletException(e); + } catch (SAXException e) { + throw new ServletException(e); + } catch (PersistenceException e) { + throw new ServletException(e); + } catch (InitializationException e) { + throw new ServletException(e); + } catch (BbServiceException e) { + throw new ServletException(e); + } finally { + // make sure context is released + if (ctxMgr != null) { + ctxMgr.releaseContext(); + } + } + + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + out.write("Complete! " + numberDeletedScores + " marks have been removed from Blackboard Gradecenter."); + + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doGet(req, resp); + } + +}