@Override public String getUsername(Http.Context context) { System.out.println("auth_service ====/ getUserName called @ @ @"); try { JsonNode params = context.request().body().asJson(); String token = params.get("token").asText(); UserSessionModel model = UserSessionDao.getInstance().getUserSession(token); if (model != null) { return model.getToken(); } else { return super.getUsername(context); } } catch (Exception e) { LogUtil.printLogMessage("Auth service", "params error", e.getMessage()); e.printStackTrace(); return super.getUsername(context); } }
/** * Function called by the GitHub authentication flow which takes the resulting code as a parameter. * This function will take the code passed and exchange it for a client access token used to make * GitHub api requests. * @param code * @return */ public CompletionStage<Result> callback(String code) { final Http.Context context = Http.Context.current(); return wsClient.url("https://github.com/login/oauth/access_token") .setQueryParameter("client_id", configuration.getString("gh.id")) .setQueryParameter("client_secret", configuration.getString("gh.secret")) .setQueryParameter("code", code) .setHeader("accept", "application/json") .setRequestTimeout(10 * 1000) .post("") .thenApply(response -> { String accessToken = response.asJson().get("access_token").asText(); context.session().put(TOKEN_KEY, accessToken); return redirect("/configHelper"); }); }
@Override public CompletionStage<Optional<? extends Subject>> getSubject(final Http.Context context) { String token = BaseController.getToken(context).orElse(""); Session session = cache.get(BaseController.SITNET_CACHE_KEY + token); User user = session == null ? null : Ebean.find(User.class, session.getUserId()); // filter out roles not found in session if (user != null) { if (session.isTemporalStudent()) { user.getRoles().clear(); user.getRoles().add(Ebean.find(Role.class).where().eq("name", Role.Name.STUDENT.toString()).findUnique()); } else { user.setRoles(user.getRoles().stream() .filter((r) -> r.getName().equals(session.getLoginRole())) .collect(Collectors.toList())); } } return CompletableFuture.supplyAsync(() -> Optional.ofNullable(user)); }
@Override public CompletionStage<Boolean> isAllowed(String name, Optional<String> meta, DeadboltHandler deadboltHandler, Http.Context ctx) { if (meta.isPresent() && meta.get().matches("pattern=.+,role=.+,anyMatch=(true|false)")) { String[] config = meta.get().split(","); String pattern = config[0].substring(config[0].indexOf('=') + 1); String[] roles = {config[1].substring(config[1].indexOf('=') + 1)}; Boolean anyMatch = Boolean.valueOf(config[2].substring(config[2].indexOf('=') + 1)); return deadboltHandler.getSubject(ctx).thenApplyAsync(s -> { DeadboltAnalyzer da = new DeadboltAnalyzer(); if (anyMatch) { return da.checkPatternEquality(s, Optional.of(pattern)) || da.checkRole(s, roles); } else { return da.checkPatternEquality(s, Optional.of(pattern)) && da.checkRole(s, roles); } }); } else { return CompletableFuture.completedFuture(false); } }
@Restrict({@Group("ADMIN"), @Group("TEACHER")}) public Result importGrades() { Http.MultipartFormData<File> body = request().body().asMultipartFormData(); Http.MultipartFormData.FilePart<File> filePart = body.getFile("file"); if (filePart == null) { return notFound(); } File file = filePart.getFile(); User user = getLoggedUser(); boolean isAdmin = user.hasRole(Role.Name.ADMIN.toString(), getSession()); try { CsvBuilder.parseGrades(file, user, isAdmin ? Role.Name.ADMIN : Role.Name.TEACHER); } catch (IOException e) { Logger.error("Failed to parse CSV file. Stack trace follows"); e.printStackTrace(); return internalServerError("sitnet_internal_error"); } return ok(); }
@Override public Action createAction(Http.Request request, Method actionMethod) { String token = BaseController.getToken(request).orElse(""); Session session = cache.get(BaseController.SITNET_CACHE_KEY + token); boolean temporalStudent = session != null && session.isTemporalStudent(); User user = session == null ? null : Ebean.find(User.class, session.getUserId()); AuditLogger.log(request, user); // logout, no further processing if (request.path().equals("/app/logout")) { return propagateAction(); } return validateSession(session, token).orElseGet(() -> { updateSession(request, session, token); if ((user == null || !user.hasRole("STUDENT", session)) && !temporalStudent) { // propagate further right away return propagateAction(); } else { // requests are candidates for extra processing return propagateAction(getReservationHeaders(request, user)); } }); }
private Optional<Action> validateSession(Session session, String token) { if (session == null) { if (token == null) { Logger.debug("User not logged in"); } else { Logger.info("Session with token {} not found", token); } return Optional.of(propagateAction()); } else if (!session.getValid()) { Logger.warn("Session #{} is marked as invalid", token); return Optional.of(new Action.Simple() { @Override public CompletionStage<Result> call(final Http.Context ctx) { return CompletableFuture.supplyAsync(() -> { ctx.response().getHeaders().put(SITNET_FAILURE_HEADER_KEY, "Invalid token"); return Action.badRequest("Token has expired / You have logged out, please close all browser windows and login again."); } ); } }); } else { return Optional.empty(); } }
private Map<String, String> getReservationHeaders(Http.RequestHeader request, User user) { Map<String, String> headers = new HashMap<>(); Optional<ExamEnrolment> ongoingEnrolment = getNextEnrolment(user.getId(), 0); if (ongoingEnrolment.isPresent()) { handleOngoingEnrolment(ongoingEnrolment.get(), request, headers); } else { DateTime now = new DateTime(); int lookAheadMinutes = Minutes.minutesBetween(now, now.plusDays(1).withMillisOfDay(0)).getMinutes(); Optional<ExamEnrolment> upcomingEnrolment = getNextEnrolment(user.getId(), lookAheadMinutes); if (upcomingEnrolment.isPresent()) { handleUpcomingEnrolment(upcomingEnrolment.get(), request, headers); } else if (isOnExamMachine(request)) { // User is logged on an exam machine but has no exams for today headers.put("x-exam-upcoming-exam", "none"); } } return headers; }
@Override public CompletionStage<Result> onClientError(Http.RequestHeader request, int statusCode, String message) { return CompletableFuture.supplyAsync(() -> { Logger.warn("onClientError: URL: {}, status: {}, msg: {}", request.uri(), statusCode, message); if (statusCode == play.mvc.Http.Status.BAD_REQUEST) { return Results.badRequest(Json.toJson(new ApiError(message))); } if (statusCode == play.mvc.Http.Status.NOT_FOUND) { return Results.notFound(Json.toJson(new ApiError(message))); } if (statusCode == Http.Status.UNAUTHORIZED || statusCode == Http.Status.FORBIDDEN) { return Results.unauthorized(Json.toJson(new ApiError(message))); } return Results.internalServerError(Json.toJson(new ApiError(message))); }); }
@Override public CompletionStage<Result> onServerError(Http.RequestHeader request, Throwable exception) { return CompletableFuture.supplyAsync(() -> { Throwable cause = exception.getCause(); String errorMessage = cause == null ? exception.getMessage() : cause.getMessage(); Logger.error("onServerError: URL: {}, msg: {}", request.uri(), errorMessage); exception.printStackTrace(); if (cause != null) { if (cause instanceof MalformedDataException) { return Results.badRequest(Json.toJson(errorMessage)); } if (cause instanceof IllegalArgumentException) { return Results.badRequest(Json.toJson(new ApiError(errorMessage))); } if (cause instanceof OptimisticLockException) { return Results.badRequest("sitnet_error_data_has_changed"); } } return Results.internalServerError(Json.toJson(new ApiError(errorMessage))); }); }
@Override public CompletionStage<Result> call(Http.Context ctx) { return delegate.call(ctx).thenApply(result -> { if (result.status() <= HTTP_CREATED && result.body().contentType().orElse("").equals("application/json")) { result.body().consumeData(materializer).thenApplyAsync(body -> { JsonNode bodyJson = Json.parse(body.decodeString("UTF-8")); if (searchForSensitiveContent(bodyJson) != null) { Logger.error("!!!Sensitive data returned by action!!!"); throw new SecurityException(); } return result; }); } return result; }); }
public CompletionStage<Result> call(final Http.Context ctx) { String username = ctx.session().get("username"); Long postId = Long.parseLong(ctx.request().getQueryString("id")); Optional<PostDTO> optionalPost = postService.getPost(postId); if (!optionalPost.isPresent()) { // Post doesn't exists, return notFound return CompletableFuture.completedFuture(notFound()); } else if (!optionalPost.get().username.equals(username)) { // User is not the owner of Post, show him Login form Result login = unauthorized(views.html.login.render( loginDTOForm.withGlobalError("Please login with proper credentials to modify this post"))); return CompletableFuture.completedFuture(login); } else { // Post exists and User is the owner of Post, call delegate return delegate.call(ctx); } }
@Override public CompletionStage<Result> apply( Function<Http.RequestHeader, CompletionStage<Result>> nextFilter, Http.RequestHeader requestHeader) { long startTime = System.currentTimeMillis(); return nextFilter.apply(requestHeader).thenApply(result -> { long endTime = System.currentTimeMillis(); long requestTime = endTime - startTime; if (!requestHeader.uri().contains("assets")) { Logger.info("{} {} from {} took {}ms and returned {}", requestHeader.method(), requestHeader.uri(), requestHeader.remoteAddress(), requestTime, result.status()); } return result; }); }
/** * Fetches the list of viewed products according to what is stored in session * and saves it in {@code lastViewedProducts} class field. */ private CompletionStage<?> fetchAndSaveLastViewedProducts() { final List<String> skuList = findLastViewedProductsSkuInSession(Http.Context.current().session()); if (!skuList.isEmpty()) { final ProductProjectionSearch request = ProductProjectionSearch.ofCurrent() .withQueryFilters(product -> product.allVariants().sku().isIn(skuList)) .withPriceSelection(priceSelection); return sphereClient.execute(request) .thenApply(result -> { this.lastViewedProducts = sortProductsBySkuList(result.getResults(), skuList); return null; }).exceptionally(throwable -> { LOGGER.error("Could not fetch last viewed products", throwable); return null; }); } return completedFuture(null); }
@Override public CompletionStage<Optional<Result>> beforeAuthCheck(final Http.Context context) { if (this.auth.isLoggedIn(context.session())) { // user is logged in return CompletableFuture.completedFuture(Optional.empty()); } else { // user is not logged in // call this if you want to redirect your visitor to the page that // was requested before sending him to the login page // if you don't call this, the user will get redirected to the page // defined by your resolver final String originalUrl = this.auth.storeOriginalUrl(context); context.flash().put("error", "You need to log in first, to view '" + originalUrl + "'"); return CompletableFuture.completedFuture(Optional.ofNullable(redirect(this.auth.getResolver().login()))); } }
public String validate() { User user = UserUtil.authenticate(userDao.findUserByUsername(username), password); if (user == null) { return "Invalid username or password"; } else if (!user.isActive()) { return "User account is currently inactive. An admin will activate your account shortly."; } else { Http.Session session = Http.Context.current().session(); session.clear(); session.put("uid", Long.toString(user.getId())); session.put("user_role", user.getRoles().get(0).getName()); session.put("username", user.getUsername()); // TODO: token based auth and session timeout } return null; }
private File createWorkspaceFile(Map<String, Object> settings, Http.MultipartFormData.FilePart src) { String workspace = (String) settings.get("workspace"); if (workspace == null) { throw new RuntimeException("Workspace parameter not present in settings! Nowhere to put the inputfile."); } try { File workspaceFile = Paths.get(workspace, src.getFilename()).toFile(); FileUtils.copyFile((File) src.getFile(), workspaceFile); return workspaceFile; } catch (IOException e) { throw new RuntimeException("Error copying uploaded file to workspace: " + workspace, e); } }
public Result upload() { // Get the current logged in user User user = User.find.byId(Long.parseLong(session().get("uid"))); // Process form submission as multipart form data Http.MultipartFormData body = request().body().asMultipartFormData(); UserUpload userUpload = null; for (Object obj : body.getFiles()) { Http.MultipartFormData.FilePart filePart = (Http.MultipartFormData.FilePart) obj; userUpload = uploadFile(filePart, user); } if (userUpload != null) { return ok("{ 'filename' : " + userUpload.getFileName() + "}"); } else { return internalServerError("{ }"); } }
/** * Invoked in dev mode when a server error occurs. * * @param request The request that triggered the error. * @param exception The exception. */ protected CompletionStage<Result> onDevServerError(Http.RequestHeader request, UsefulException exception) { ObjectNode jsonError = Json.newObject(); final Throwable cause = exception.cause; final String description = exception.description; final String id = exception.id; final String title = exception.title; jsonError.put("description", description); jsonError.put("title", title); jsonError.put("id", id); jsonError.put("message", exception.getMessage()); jsonError.set("cause", causesToJson(cause)); return CompletableFuture.completedFuture(Results.internalServerError(jsonError)); }
@Test public void displayAmountsDue() { running(fakeApplication(new SsttpFrontendGlobal()), () -> { CalculatorController calculatorController = new CalculatorController(); calculatorController.keystoreConnector = mock(KeystoreConnector.class); when(calculatorController.keystoreConnector.getKey("1")).thenReturn(F.Promise.promise(() -> (tree))); Result result = callAction(routes.ref.CalculatorController.amountsDuePresent(), fakeRequest() .withHeader("referer", "/self-service-time-to-pay") .withSession("uuid", uuid).withSession("timestamp", timestamp)); String body = Helpers.contentAsString(result); assertThat(status(result), is(Http.Status.OK)); assertThat(body, containsString(Messages.get("ssttp.calculator.form.amounts_due.title"))); }); }
@Test public void displayPaymentTodayPresent() { running(fakeApplication(new SsttpFrontendGlobal()), () -> { CalculatorController calculatorController = new CalculatorController(); calculatorController.keystoreConnector = mock(KeystoreConnector.class); when(calculatorController.keystoreConnector.getKey("1")).thenReturn(F.Promise.promise(() -> (tree))); Result result = callAction(routes.ref.CalculatorController.paymentTodayPresent(), fakeRequest() .withHeader("referer", "/self-service-time-to-pay") .withSession("uuid", uuid).withSession("timestamp", timestamp)); String body = Helpers.contentAsString(result); assertThat(status(result), is(Http.Status.OK)); assertThat(body, containsString(Messages.get("ssttp.calculator.form.payment_today.title"))); }); }
@Test public void submitAmountsDuePageSingleLiabilityNoErrors() { running(fakeApplication(new SsttpFrontendGlobal()), () -> { Map<String, String> formData = Maps.newHashMap(); formData.put("amount[0]", "5000"); formData.put("dueByDay[0]", "30"); formData.put("dueByMonth[0]", "January"); formData.put("dueByYear[0]", "2016"); Result result = callAction(routes.ref.CalculatorController.amountsDueSubmit(), fakeRequest() .withSession("uuid", uuid).withSession("timestamp", timestamp) .withFormUrlEncodedBody(formData)); String redirectLocation = Helpers.headers(result).get("Location"); String expectedRedirectLocation = routes.CalculatorController.paymentTodayPresent().url(); // should redirect to payment today page assertThat(status(result), is(Http.Status.SEE_OTHER)); assertThat(redirectLocation.equals(expectedRedirectLocation), is(true)); }); }
@Test public void submitPaymentTodayErrors() { running(fakeApplication(new SsttpFrontendGlobal()), () -> { Map<String, String> formData = Maps.newHashMap(); formData.put("amount", ""); Result result = callAction(routes.ref.CalculatorController.paymentTodaySubmit(), fakeRequest() .withSession("uuid", uuid).withSession("timestamp", timestamp) .withFormUrlEncodedBody(formData)); String body = Helpers.contentAsString(result); // should stay on payment today page and display error assertThat(status(result), is(Http.Status.OK)); assertThat(body, containsString(Messages.get("ssttp.calculator.form.payment_today.amount.required"))); }); }
@Before public void setUp() throws Exception { Map<String, String> flashData = Collections.emptyMap(); Map<String, Object> argData = Collections.emptyMap(); Long id = 2L; play.api.mvc.RequestHeader header = new FakeRequest("GET", "/").getWrappedRequest(); Http.Request request = mock(Http.Request.class); Http.Context ctx = new Http.Context(id, header, request, flashData, flashData, argData); Http.Context.current.set(ctx); when(request.body()).thenReturn(new Http.RequestBody()); keyResponse = IOUtils.toString(SelfAssessmentConnectorTest.class.getResourceAsStream("/keystoreResponse.json")); calculatorResponse = IOUtils.toString(SelfAssessmentConnectorTest.class.getResourceAsStream("/calculatorResponse.json")); timestamp = LocalTime.now().toString(); uuid = "1"; ObjectMapper mapper = new ObjectMapper(); tree = mapper.readTree(keyResponse); calculatorResponseTree = mapper.readTree(calculatorResponse); }
@Test public void presentDebtTypePage() { running(fakeApplication(new SsttpFrontendGlobal()), () -> { Map<String, String> formData = Maps.newHashMap(); EligibilityController eligibility = new EligibilityController(); eligibility.keystoreConnector = mock(KeystoreConnector.class); when(eligibility.keystoreConnector.getKey("1")).thenReturn(F.Promise.promise(() -> (tree))); Result result = callAction(routes.ref.EligibilityController.debtTypePresent(), fakeRequest() .withSession("uuid", uuid).withSession("timestamp", timestamp) .withFormUrlEncodedBody(formData)); String body = Helpers.contentAsString(result); assertThat(status(result), is(Http.Status.OK)); assertThat(body, containsString(Messages.get("ssttp.eligibility.form.debt_type.title"))); }); }
@Test public void submitDebtTypePageErrors() { running(fakeApplication(new SsttpFrontendGlobal()), () -> { Map<String, String> formData = Maps.newHashMap(); formData.put("selfAssessmentDebt", "true"); formData.put("otherTaxDebt", ""); //formData.put("otherTaxDebt", "true"); // - 303 to call us page Result result = callAction(routes.ref.EligibilityController.debtTypeSubmit(), fakeRequest().withSession("uuid", uuid).withSession("timestamp", timestamp).withFormUrlEncodedBody(formData)); String body = Helpers.contentAsString(result); //should stay on the same page and display error assertThat(status(result), is(Http.Status.OK)); assertThat(body, containsString("error-notification")); }); }
@Test public void presentExistingTtpPage() { running(fakeApplication(new SsttpFrontendGlobal()), () -> { Map<String, String> formData = Maps.newHashMap(); EligibilityDebtType form = new EligibilityDebtType(true, false); EligibilityController eligibilityController = new EligibilityController(); eligibilityController.keystoreConnector = mock(KeystoreConnector.class); when(eligibilityController.keystoreConnector.getKey("1")).thenReturn(F.Promise.promise(() -> (tree))); Result result = callAction(routes.ref.EligibilityController.existingTtpPresent(), fakeRequest() .withSession("uuid", uuid).withSession("timestamp", timestamp) .withFormUrlEncodedBody(formData).withSession("uuid", uuid)); String body = Helpers.contentAsString(result); assertThat(status(result), is(Http.Status.OK)); assertThat(body, containsString(Messages.get("ssttp.eligibility.form.existing_ttp.title"))); }); }
@Override public CompletionStage<Result> call(Http.Context ctx) { if (configuration.value().length > 0) { int actions = configuration.value().length; List<Action<ApiBodyParam>> actionList = new ArrayList<>(); for (int i = 0; i < actions; i++) { ApiBodyParamAction apiBodyParamAction = new ApiBodyParamAction(); apiBodyParamAction.configuration = configuration.value()[i]; actionList.add(apiBodyParamAction); } actionList.get(actions - 1).delegate = delegate; for (int i = 0; i < actions - 1; i++) { actionList.get(i).delegate = actionList.get(i + 1); } return actionList.get(0).call(ctx); } else { return delegate.call(ctx); } }
@Override public CompletionStage<Result> call(Http.Context ctx) { Optional<String> contentType = ctx.request().contentType(); if (contentType.isPresent()) { if (contentType.get().contains("json")) { return handleJsonContentType(ctx); } else if (contentType.get().contains("multipart")) { return handleMultipartContentType(ctx); } else { Logger.warn("Content-type " + contentType.get() + " not implemented yet or unknown!"); return delegate.call(ctx); } } else { if (configuration.required()) { return CompletableFuture.completedFuture(badRequest("Content-type is needed when calling an endpoint with required body parameters")); } else { ctx.args.put(configuration.name(), Optional.empty()); return delegate.call(ctx); } } }
@Override public CompletionStage<Result> call(Http.Context ctx) { if (configuration.value().length > 0) { int actions = configuration.value().length; List<Action<SecureEndPoint>> actionList = new ArrayList<>(); for (int i = 0; i < actions; i++) { AuthorizationAction authorizationAction = new AuthorizationAction(injector, authorizationCheck); authorizationAction.configuration = configuration.value()[i]; actionList.add(authorizationAction); } actionList.get(actions - 1).delegate = delegate; for (int i = 0; i < actions - 1; i++) { actionList.get(i).delegate = actionList.get(i + 1); } return actionList.get(0).call(ctx); } else { return delegate.call(ctx); } }
@Override public CompletionStage<Result> call(Http.Context ctx) { return swagplashProvider.get() .thenCompose(swagplash -> { if (swagplash == null) { Logger.error("Could not load Swagplash definition"); return delegate.call(ctx); } else { String method = ctx.request().method(); if (method.equals("POST") || (method.equals("PUT"))) { Optional<Result> consumesError = checkConsumes(ctx, swagplash); if (consumesError.isPresent()) return CompletableFuture.completedFuture(consumesError.get()); } Optional<Result> producesError = checkProduces(ctx, swagplash); if (producesError.isPresent()) { return CompletableFuture.completedFuture(producesError.get()); } return delegate.call(ctx); } }); }
/** * Check consumes. * * @param ctx * @param swagplash * @return the error wrapped into an Optional. empty if none */ private Optional<Result> checkConsumes(Http.Context ctx, SPSwaggerDefinition swagplash) { if (!configuration.consumesNothing()) { List<String> consumes = new ArrayList<String>(); Collections.addAll(consumes, configuration.consumes()); if (consumes.isEmpty()) { consumes = swagplash.getConsumes(); } if (!consumes.isEmpty()) { Optional<String> contentType = ctx.request().contentType(); if (contentType.isPresent()) { String unwrapped = contentType.get(); if (!consumes.contains(unwrapped)) return Optional.of(badRequest("This endpoint can't consume " + unwrapped + ".This endpoint consumes the following content-type: " + String.join(", ", consumes))); } else { return Optional.of(badRequest("This endpoint consumes the following content-type: " + String.join(", ", consumes))); } } } return Optional.empty(); }
@Before public void setUp() throws Exception { Map<String, String> flashData = Collections.emptyMap(); Map<String, Object> argData = Collections.emptyMap(); Long id = 2L; play.api.mvc.RequestHeader header = mock(play.api.mvc.RequestHeader.class); Http.Context context = new Http.Context(id, header, request, flashData, flashData, argData); Http.Context.current.set(context); }
@Override public ResourceResponse<DocumentCollection> createCollectionIfNotExists(String databaseName, String id) throws Exception { DocumentCollection collectionInfo = new DocumentCollection(); RangeIndex index = Index.Range(DataType.String, -1); collectionInfo.setIndexingPolicy(new IndexingPolicy(new Index[]{index})); collectionInfo.setId(id); // Azure Cosmos DB collections can be reserved with throughput specified in request units/second. // Here we create a collection with 400 RU/s. RequestOptions requestOptions = new RequestOptions(); requestOptions.setOfferThroughput(400); String dbUrl = "/dbs/" + databaseName; String colUrl = dbUrl + "/colls/" + id; boolean create = false; ResourceResponse<DocumentCollection> response = null; try { response = this.client.readCollection(colUrl, requestOptions); } catch (DocumentClientException dcx) { if (dcx.getStatusCode() == Http.Status.NOT_FOUND) { create = true; } else { log.error("Error reading collection: {}. Exception: {}", id, dcx); } } if (create) { try { response = this.client.createCollection(dbUrl, collectionInfo, requestOptions); } catch (Exception ex) { log.error("Error creating collection. Id: {}, dbUrl: {}, collection: {}. Exception: {}", id, dbUrl, collectionInfo, ex); throw ex; } } return response; }
private void mockHttpContex() { Http.Request mockRequest = mock(Http.Request.class); when(mockRequest.body()).thenReturn(new Http.RequestBody(toJson(new AlarmStatus("open")))); Http.Context mockContext = mock(Http.Context.class); when(mockContext.request()).thenReturn(mockRequest); Http.Context.current.set(mockContext); }
private void setMockContext() { Http.Request mockRequest = mock(Http.Request.class); when(mockRequest.body()).thenReturn(new Http.RequestBody(toJson(new AlarmStatus("open")))); Http.Context mockContext = mock(Http.Context.class); when(mockContext.request()).thenReturn(mockRequest); Http.Context.current.set(mockContext); }