Search in sources :

Example 1 with AnonymousUserDTO

use of uk.ac.cam.cl.dtg.isaac.dto.users.AnonymousUserDTO in project isaac-api by isaacphysics.

the class GameboardsFacadeTest method isaacEndPoint_checkEmptyGameboardCausesErrorNoUser_SegueErrorResponseShouldBeReturned.

/**
 * Verify that when an empty gameboard is noticed a 204 is returned.
 *
 * @throws NoUserLoggedInException
 * @throws ContentManagerException
 */
@Test
@PowerMockIgnore({ "javax.ws.*" })
public final void isaacEndPoint_checkEmptyGameboardCausesErrorNoUser_SegueErrorResponseShouldBeReturned() throws NoWildcardException, SegueDatabaseException, NoUserLoggedInException, ContentManagerException {
    GameboardsFacade gameboardFacade = new GameboardsFacade(dummyPropertiesLoader, dummyLogManager, dummyGameManager, questionManager, userManager, userAssociationManager, userBadgeManager, fastTrackManager);
    HttpServletRequest dummyRequest = createMock(HttpServletRequest.class);
    String subjects = "physics";
    String fields = "mechanics";
    String topics = "dynamics";
    String levels = "2,3,4";
    String concepts = "newtoni";
    String title = "Newton";
    String questionCategory = "problem_solving";
    String stages = "a_level";
    String difficulties = "practice_1";
    String examBoards = "wjec";
    expect(dummyGameManager.generateRandomGameboard(EasyMock.<String>anyObject(), EasyMock.<List<String>>anyObject(), EasyMock.<List<String>>anyObject(), EasyMock.<List<String>>anyObject(), EasyMock.<List<Integer>>anyObject(), EasyMock.<List<String>>anyObject(), EasyMock.<List<String>>anyObject(), EasyMock.<List<String>>anyObject(), EasyMock.<List<String>>anyObject(), EasyMock.<List<String>>anyObject(), EasyMock.<AbstractSegueUserDTO>anyObject())).andReturn(null).atLeastOnce();
    expect(userManager.getCurrentUser(dummyRequest)).andReturn(new AnonymousUserDTO("testID")).atLeastOnce();
    replay(dummyGameManager);
    Response r = gameboardFacade.generateTemporaryGameboard(dummyRequest, title, subjects, fields, topics, stages, difficulties, examBoards, levels, concepts, questionCategory);
    assertTrue(r.getStatus() == Status.NO_CONTENT.getStatusCode());
    verify(dummyGameManager);
}
Also used : HttpServletRequest(javax.servlet.http.HttpServletRequest) Response(javax.ws.rs.core.Response) GameboardsFacade(uk.ac.cam.cl.dtg.isaac.api.GameboardsFacade) List(java.util.List) AbstractSegueUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.AbstractSegueUserDTO) AnonymousUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.AnonymousUserDTO) Test(org.junit.Test) PowerMockIgnore(org.powermock.core.classloader.annotations.PowerMockIgnore)

Example 2 with AnonymousUserDTO

use of uk.ac.cam.cl.dtg.isaac.dto.users.AnonymousUserDTO in project isaac-api by isaacphysics.

the class PagesFacade method getQuestion.

/**
 * Rest end point that gets a single question page based on a given id.
 *
 * @param questionId
 *            to find as a string
 * @param request
 *            - so that we can do etag and cache resolution.
 * @param httpServletRequest
 *            - so that we can try and determine if the user is logged in. This will allow us to augment the
 *            question objects with any recorded state.
 * @return A Response object containing a question page object or a SegueErrorResponse.
 */
@GET
@Path("/questions/{question_page_id}")
@Produces(MediaType.APPLICATION_JSON)
@GZIP
@ApiOperation(value = "Get a question page object by ID.")
public final Response getQuestion(@Context final Request request, @Context final HttpServletRequest httpServletRequest, @PathParam("question_page_id") final String questionId) {
    Map<String, List<String>> fieldsToMatch = Maps.newHashMap();
    fieldsToMatch.put("type", Arrays.asList(QUESTION_TYPE, FAST_TRACK_QUESTION_TYPE));
    if (null == questionId || questionId.isEmpty()) {
        return new SegueErrorResponse(Status.BAD_REQUEST, "You must provide a valid question id.").toResponse();
    }
    // options
    fieldsToMatch.put(ID_FIELDNAME + "." + UNPROCESSED_SEARCH_FIELD_SUFFIX, Arrays.asList(questionId));
    try {
        AbstractSegueUserDTO user = userManager.getCurrentUser(httpServletRequest);
        Map<String, Map<String, List<QuestionValidationResponse>>> userQuestionAttempts;
        userQuestionAttempts = questionManager.getQuestionAttemptsByUser(user);
        // Calculate the ETag
        EntityTag etag = new EntityTag(questionId.hashCode() + userQuestionAttempts.toString().hashCode() + "");
        Response cachedResponse = generateCachedResponse(request, etag, NEVER_CACHE_WITHOUT_ETAG_CHECK);
        if (cachedResponse != null) {
            return cachedResponse;
        }
        Response response = this.findSingleResult(fieldsToMatch, userQuestionAttempts);
        if (response.getEntity() != null && response.getEntity() instanceof IsaacQuestionPageDTO) {
            SeguePageDTO content = (SeguePageDTO) response.getEntity();
            Map<String, String> logEntry = ImmutableMap.of(QUESTION_ID_LOG_FIELDNAME, content.getId(), CONTENT_VERSION_FIELDNAME, this.contentManager.getCurrentContentSHA());
            String userIdForRandomisation;
            if (user instanceof AnonymousUserDTO) {
                userIdForRandomisation = ((AnonymousUserDTO) user).getSessionId();
            } else {
                userIdForRandomisation = ((RegisteredUserDTO) user).getId().toString();
            }
            content = this.questionManager.augmentQuestionObjects(content, userIdForRandomisation, userQuestionAttempts);
            // the request log
            getLogManager().logEvent(user, httpServletRequest, IsaacServerLogType.VIEW_QUESTION, logEntry);
            // return augmented content.
            return Response.ok(content).cacheControl(getCacheControl(NEVER_CACHE_WITHOUT_ETAG_CHECK, false)).tag(etag).build();
        } else {
            String error = "Unable to locate a question with the id specified: " + questionId;
            log.warn(error);
            return SegueErrorResponse.getResourceNotFoundResponse(error);
        }
    } catch (SegueDatabaseException e) {
        String message = "SegueDatabaseException whilst trying to retrieve user data";
        log.error(message, e);
        return new SegueErrorResponse(Status.INTERNAL_SERVER_ERROR, message).toResponse();
    }
}
Also used : SegueDatabaseException(uk.ac.cam.cl.dtg.segue.dao.SegueDatabaseException) AbstractSegueUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.AbstractSegueUserDTO) Response(javax.ws.rs.core.Response) QuestionValidationResponse(uk.ac.cam.cl.dtg.isaac.dos.QuestionValidationResponse) SegueErrorResponse(uk.ac.cam.cl.dtg.isaac.dto.SegueErrorResponse) SegueErrorResponse(uk.ac.cam.cl.dtg.isaac.dto.SegueErrorResponse) RegisteredUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.RegisteredUserDTO) IsaacQuestionPageDTO(uk.ac.cam.cl.dtg.isaac.dto.IsaacQuestionPageDTO) List(java.util.List) ArrayList(java.util.ArrayList) EntityTag(javax.ws.rs.core.EntityTag) SeguePageDTO(uk.ac.cam.cl.dtg.isaac.dto.content.SeguePageDTO) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) HashMap(java.util.HashMap) QuestionValidationResponse(uk.ac.cam.cl.dtg.isaac.dos.QuestionValidationResponse) AnonymousUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.AnonymousUserDTO) Path(javax.ws.rs.Path) Produces(javax.ws.rs.Produces) GET(javax.ws.rs.GET) ApiOperation(io.swagger.annotations.ApiOperation) GZIP(org.jboss.resteasy.annotations.GZIP)

Example 3 with AnonymousUserDTO

use of uk.ac.cam.cl.dtg.isaac.dto.users.AnonymousUserDTO in project isaac-api by isaacphysics.

the class LogEventFacade method postLog.

/**
 * Method to allow clients to log front-end specific behaviour in the database.
 *
 * @param httpRequest
 *            - to enable retrieval of session information.
 * @param eventJSON
 *            - the event information to record as a json map <String, String>.
 * @return 200 for success or 400 for failure.
 */
@POST
@Path("/")
@Consumes(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Record a new log event from the current user.", notes = "The 'type' field must be provided and must not be a reserved value.")
public Response postLog(@Context final HttpServletRequest httpRequest, final Map<String, Object> eventJSON) {
    if (null == eventJSON || eventJSON.get(TYPE_FIELDNAME) == null) {
        log.error("Error during log operation, no event type specified. Event: " + eventJSON);
        return new SegueErrorResponse(Status.BAD_REQUEST, "Unable to record log message as the log has no " + TYPE_FIELDNAME + " property.").toResponse();
    }
    String eventType = (String) eventJSON.get(TYPE_FIELDNAME);
    // To maintain data integrity - don't allow the client to report events reserved for the server
    if (SEGUE_SERVER_LOG_TYPES.contains(eventType) || ISAAC_SERVER_LOG_TYPES.contains(eventType)) {
        return new SegueErrorResponse(Status.FORBIDDEN, "Unable to record log message, restricted '" + TYPE_FIELDNAME + "' value.").toResponse();
    }
    // After a few weeks we should fail on the case where it is an unknown type.
    if (!ISAAC_CLIENT_LOG_TYPES.contains(eventType)) {
        log.error(String.format("Warning: Log Event '%s' is not included in ISAAC_CLIENT_LOG_TYPES", eventType));
    }
    try {
        // implement arbitrary log size limit.
        AbstractSegueUserDTO currentUser = userManager.getCurrentUser(httpRequest);
        String uid;
        if (currentUser instanceof AnonymousUserDTO) {
            uid = ((AnonymousUserDTO) currentUser).getSessionId();
        } else {
            uid = ((RegisteredUserDTO) currentUser).getId().toString();
        }
        try {
            misuseMonitor.notifyEvent(uid, LogEventMisuseHandler.class.getSimpleName(), httpRequest.getContentLength());
        } catch (SegueResourceMisuseException e) {
            log.error(String.format("Logging Event Failed - log event requested (%s bytes) " + "and would exceed daily limit size limit (%s bytes) ", httpRequest.getContentLength(), Constants.MAX_LOG_REQUEST_BODY_SIZE_IN_BYTES));
            return SegueErrorResponse.getRateThrottledResponse(String.format("Log event request (%s bytes) would exceed limit for this endpoint.", httpRequest.getContentLength()));
        }
        // remove the type information as we don't need it.
        eventJSON.remove(TYPE_FIELDNAME);
        this.getLogManager().logExternalEvent(this.userManager.getCurrentUser(httpRequest), httpRequest, eventType, eventJSON);
        return Response.ok().cacheControl(getCacheControl(NEVER_CACHE_WITHOUT_ETAG_CHECK, false)).build();
    } catch (SegueDatabaseException e) {
        SegueErrorResponse error = new SegueErrorResponse(Status.INTERNAL_SERVER_ERROR, "Database error while looking up user information.", e);
        log.error(error.getErrorMessage(), e);
        return error.toResponse();
    }
}
Also used : SegueErrorResponse(uk.ac.cam.cl.dtg.isaac.dto.SegueErrorResponse) RegisteredUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.RegisteredUserDTO) SegueDatabaseException(uk.ac.cam.cl.dtg.segue.dao.SegueDatabaseException) LogEventMisuseHandler(uk.ac.cam.cl.dtg.segue.api.monitors.LogEventMisuseHandler) SegueResourceMisuseException(uk.ac.cam.cl.dtg.segue.api.managers.SegueResourceMisuseException) AbstractSegueUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.AbstractSegueUserDTO) AnonymousUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.AnonymousUserDTO) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes) ApiOperation(io.swagger.annotations.ApiOperation)

Example 4 with AnonymousUserDTO

use of uk.ac.cam.cl.dtg.isaac.dto.users.AnonymousUserDTO in project isaac-api by isaacphysics.

the class UserManagerTest method authenticateCallback_checkNewUserIsAuthenticated_createInternalUserAccount.

/**
 * Check that a new (unseen) user is registered when seen with 3rd party authenticator.
 *
 * @throws Exception
 *             -
 */
@Test
public final void authenticateCallback_checkNewUserIsAuthenticated_createInternalUserAccount() throws Exception {
    IOAuth2Authenticator dummyAuth = createMock(FacebookAuthenticator.class);
    UserAccountManager userManager = buildTestUserManager(AuthenticationProvider.TEST, dummyAuth);
    UserAuthenticationManager authManager = buildTestAuthenticationManager(AuthenticationProvider.TEST, dummyAuth);
    // method param setup for method under test
    HttpSession dummySession = createMock(HttpSession.class);
    HttpServletRequest request = createMock(HttpServletRequest.class);
    HttpServletResponse response = createMock(HttpServletResponse.class);
    String someDomain = "http://www.somedomain.com/";
    String someClientId = "someClientId";
    String someAuthCode = "someAuthCode";
    String someState = "someState";
    StringBuffer sb = new StringBuffer(someDomain + "?state=" + someState + "&code=" + someAuthCode);
    String validQueryStringFromProvider = "client_id=" + someClientId + "&redirect_uri=" + someDomain;
    String fullResponseUrlFromProvider = someDomain + "?state=" + someState + "&code=" + someAuthCode + "?client_id=" + someClientId + "&redirect_uri=" + someDomain;
    String someProviderGeneratedLookupValue = "MYPROVIDERREF";
    String someProviderUniqueUserId = "USER-1";
    Long someSegueUserId = 533L;
    String someSegueAnonymousUserId = "9284723987anonymous83924923";
    AnonymousUser au = new AnonymousUser();
    au.setSessionId(someSegueAnonymousUserId);
    expect(this.dummyUserCache.storeAnonymousUser(au)).andReturn(au).atLeastOnce();
    expect(this.dummyUserCache.getById(au.getSessionId())).andReturn(au).atLeastOnce();
    AnonymousUserDTO someAnonymousUserDTO = new AnonymousUserDTO();
    someAnonymousUserDTO.setSessionId(someSegueAnonymousUserId);
    String validOAuthProvider = "test";
    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.SECOND, 500);
    String validDateString = sdf.format(calendar.getTime());
    expect(request.getSession()).andReturn(dummySession).atLeastOnce();
    // empty as not logged in.
    Cookie[] cookieWithoutSessionInfo = {};
    expect(request.getCookies()).andReturn(cookieWithoutSessionInfo).times(2);
    // session
    expect(dummySession.getAttribute(Constants.ANONYMOUS_USER)).andReturn(someSegueAnonymousUserId).atLeastOnce();
    // id
    // Mock CSRF checks
    expect(dummySession.getAttribute(Constants.STATE_PARAM_NAME)).andReturn(CSRF_TEST_VALUE).atLeastOnce();
    expect(request.getParameter(Constants.STATE_PARAM_NAME)).andReturn(CSRF_TEST_VALUE).atLeastOnce();
    // Mock URL params extract stuff
    expect(request.getQueryString()).andReturn(validQueryStringFromProvider).atLeastOnce();
    expect(request.getRequestURL()).andReturn(sb);
    // Mock extract auth code call
    expect(dummyAuth.extractAuthCode(fullResponseUrlFromProvider)).andReturn(someAuthCode);
    // Mock exchange code for token call
    expect(dummyAuth.exchangeCode(someAuthCode)).andReturn(someProviderGeneratedLookupValue).atLeastOnce();
    expect(((IFederatedAuthenticator) dummyAuth).getAuthenticationProvider()).andReturn(AuthenticationProvider.TEST).atLeastOnce();
    // User object back from provider
    UserFromAuthProvider providerUser = new UserFromAuthProvider(someProviderUniqueUserId, "TestFirstName", "TestLastName", "test@test.com", EmailVerificationStatus.VERIFIED, Role.STUDENT, new Date(), Gender.MALE);
    // Mock get User Information from provider call
    expect(((IFederatedAuthenticator) dummyAuth).getUserInfo(someProviderGeneratedLookupValue)).andReturn(providerUser).atLeastOnce();
    // Expect this to be a new user and to register them (i.e. return null
    // from database)
    expect(dummyDatabase.getByLinkedAccount(AuthenticationProvider.TEST, someProviderUniqueUserId)).andReturn(null).atLeastOnce();
    RegisteredUser mappedUser = new RegisteredUser(null, "TestFirstName", "testLastName", "test@test.com", Role.STUDENT, new Date(), Gender.MALE, new Date(), null, null, null, null);
    mappedUser.setSessionToken(0);
    expect(dummyDatabase.getAuthenticationProvidersByUsers(Collections.singletonList(mappedUser))).andReturn(new HashMap<RegisteredUser, List<AuthenticationProvider>>() {

        {
            put(mappedUser, Lists.newArrayList(AuthenticationProvider.GOOGLE));
        }
    }).atLeastOnce();
    expect(dummyDatabase.getSegueAccountExistenceByUsers(Collections.singletonList(mappedUser))).andReturn(ImmutableMap.of(mappedUser, false)).atLeastOnce();
    RegisteredUserDTO mappedUserDTO = new RegisteredUserDTO();
    expect(dummyMapper.map(providerUser, RegisteredUser.class)).andReturn(mappedUser).atLeastOnce();
    expect(dummyMapper.map(mappedUser, RegisteredUserDTO.class)).andReturn(mappedUserDTO).atLeastOnce();
    expect(dummyMapper.map(au, AnonymousUserDTO.class)).andReturn(someAnonymousUserDTO).anyTimes();
    // handle duplicate account check.
    expect(dummyDatabase.getByEmail(providerUser.getEmail())).andReturn(null).once();
    // A main part of the test is to check the below call happens
    expect(dummyDatabase.registerNewUserWithProvider(mappedUser, AuthenticationProvider.TEST, someProviderUniqueUserId)).andReturn(mappedUser).atLeastOnce();
    mappedUser.setId(someSegueUserId);
    expect(dummyDatabase.getById(someSegueUserId)).andReturn(mappedUser);
    Map<String, String> sessionInformation = getSessionInformationAsAMap(authManager, someSegueUserId.toString(), validDateString, mappedUser.getSessionToken());
    Cookie[] cookieWithSessionInfo = getCookieArray(sessionInformation);
    // Expect a session to be created
    response.addCookie(cookieWithSessionInfo[0]);
    expectLastCall().once();
    expect(request.getCookies()).andReturn(cookieWithSessionInfo).anyTimes();
    dummyQuestionDatabase.mergeAnonymousQuestionAttemptsIntoRegisteredUser(someAnonymousUserDTO, mappedUserDTO);
    expectLastCall().once();
    expect(dummyQueue.getEmailTemplateDTO("email-template-registration-confirmation-federated")).andReturn(new EmailTemplateDTO()).once();
    dummyQueue.sendTemplatedEmailToUser(anyObject(), anyObject(), anyObject(), anyObject());
    expectLastCall().once();
    replay(dummySession, request, dummyAuth, dummyQuestionDatabase, dummyMapper, dummyDatabase, dummyLocalAuth, dummyQueue, dummyUserCache);
    // Act
    RegisteredUserDTO u = userManager.authenticateCallback(request, response, validOAuthProvider, false);
    // Assert
    verify(dummySession, request, dummyAuth, dummyQuestionDatabase);
    assertTrue(u instanceof RegisteredUserDTO);
}
Also used : Cookie(javax.servlet.http.Cookie) HashMap(java.util.HashMap) HttpSession(javax.servlet.http.HttpSession) Calendar(java.util.Calendar) AuthenticationProvider(uk.ac.cam.cl.dtg.segue.auth.AuthenticationProvider) HttpServletResponse(javax.servlet.http.HttpServletResponse) IOAuth2Authenticator(uk.ac.cam.cl.dtg.segue.auth.IOAuth2Authenticator) Date(java.util.Date) RegisteredUser(uk.ac.cam.cl.dtg.isaac.dos.users.RegisteredUser) HttpServletRequest(javax.servlet.http.HttpServletRequest) EmailTemplateDTO(uk.ac.cam.cl.dtg.isaac.dto.content.EmailTemplateDTO) RegisteredUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.RegisteredUserDTO) UserFromAuthProvider(uk.ac.cam.cl.dtg.isaac.dos.users.UserFromAuthProvider) AnonymousUser(uk.ac.cam.cl.dtg.isaac.dos.users.AnonymousUser) AnonymousUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.AnonymousUserDTO) Test(org.junit.Test)

Example 5 with AnonymousUserDTO

use of uk.ac.cam.cl.dtg.isaac.dto.users.AnonymousUserDTO in project isaac-api by isaacphysics.

the class QuestionManager method recordQuestionAttempt.

/**
 * Record a question attempt for a given user.
 * @param user - user that made the attempt.
 * @param questionResponse - the outcome of the attempt to be persisted.
 */
public void recordQuestionAttempt(final AbstractSegueUserDTO user, final QuestionValidationResponseDTO questionResponse) throws SegueDatabaseException {
    QuestionValidationResponse questionResponseDO = this.mapper.getAutoMapper().map(questionResponse, QuestionValidationResponse.class);
    String questionPageId = extractPageIdFromQuestionId(questionResponse.getQuestionId());
    if (user instanceof RegisteredUserDTO) {
        RegisteredUserDTO registeredUser = (RegisteredUserDTO) user;
        this.questionAttemptPersistenceManager.registerQuestionAttempt(registeredUser.getId(), questionPageId, questionResponse.getQuestionId(), questionResponseDO);
        log.debug("Question information recorded for user: " + registeredUser.getId());
    } else if (user instanceof AnonymousUserDTO) {
        AnonymousUserDTO anonymousUserDTO = (AnonymousUserDTO) user;
        this.questionAttemptPersistenceManager.registerAnonymousQuestionAttempt(anonymousUserDTO.getSessionId(), questionPageId, questionResponse.getQuestionId(), questionResponseDO);
    } else {
        log.error("Unexpected user type. Unable to record question response");
    }
}
Also used : RegisteredUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.RegisteredUserDTO) LightweightQuestionValidationResponse(uk.ac.cam.cl.dtg.isaac.dos.LightweightQuestionValidationResponse) QuestionValidationResponse(uk.ac.cam.cl.dtg.isaac.dos.QuestionValidationResponse) AnonymousUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.AnonymousUserDTO)

Aggregations

AnonymousUserDTO (uk.ac.cam.cl.dtg.isaac.dto.users.AnonymousUserDTO)5 RegisteredUserDTO (uk.ac.cam.cl.dtg.isaac.dto.users.RegisteredUserDTO)4 AbstractSegueUserDTO (uk.ac.cam.cl.dtg.isaac.dto.users.AbstractSegueUserDTO)3 ApiOperation (io.swagger.annotations.ApiOperation)2 HashMap (java.util.HashMap)2 List (java.util.List)2 HttpServletRequest (javax.servlet.http.HttpServletRequest)2 Path (javax.ws.rs.Path)2 Response (javax.ws.rs.core.Response)2 Test (org.junit.Test)2 QuestionValidationResponse (uk.ac.cam.cl.dtg.isaac.dos.QuestionValidationResponse)2 SegueErrorResponse (uk.ac.cam.cl.dtg.isaac.dto.SegueErrorResponse)2 SegueDatabaseException (uk.ac.cam.cl.dtg.segue.dao.SegueDatabaseException)2 ImmutableMap (com.google.common.collect.ImmutableMap)1 ArrayList (java.util.ArrayList)1 Calendar (java.util.Calendar)1 Date (java.util.Date)1 Map (java.util.Map)1 Cookie (javax.servlet.http.Cookie)1 HttpServletResponse (javax.servlet.http.HttpServletResponse)1