Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Data Visualization Endpoints #35

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.codeforcommunity.api.authenticated;

import com.codeforcommunity.auth.JWTData;
import com.codeforcommunity.dto.data.MetricsCountryResponse;
import com.codeforcommunity.dto.data.MetricsSchoolResponse;
import com.codeforcommunity.enums.Country;

public interface IProtectedDataProcessor {

MetricsCountryResponse getFixedCountryMetrics(JWTData userData, Country country);

MetricsSchoolResponse getFixedSchoolMetrics(JWTData userData, int schoolId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.codeforcommunity.dto.data;

public class MetricsCountryResponse {
private Integer countSchools;
private Integer countVolunteerAccounts;
private Integer countAdminAccounts;
private Float avgCountBooksPerStudent;
private Float avgCountStudentLibrariansPerSchool;
private Float percentSchoolsWithLibraries;

public MetricsCountryResponse(
Integer countSchools,
Integer countVolunteerAccounts,
Integer countAdminAccounts,
Float avgCountBooksPerStudent,
Float avgCountStudentLibrariansPerSchool,
Float percentSchoolsWithLibraries) {
this.countSchools = countSchools;
this.countVolunteerAccounts = countVolunteerAccounts;
this.countAdminAccounts = countAdminAccounts;
this.avgCountBooksPerStudent = avgCountBooksPerStudent;
this.avgCountStudentLibrariansPerSchool = avgCountStudentLibrariansPerSchool;
this.percentSchoolsWithLibraries = percentSchoolsWithLibraries;
}

public Integer getCountSchools() {
return countSchools;
}

public void setCountSchools(Integer countSchools) {
this.countSchools = countSchools;
}

public Integer getCountVolunteerAccounts() {
return countVolunteerAccounts;
}

public void setCountVolunteerAccounts(Integer countVolunteerAccounts) {
this.countVolunteerAccounts = countVolunteerAccounts;
}

public Integer getCountAdminAccounts() {
return countAdminAccounts;
}

public void setCountAdminAccounts(Integer countAdminAccounts) {
this.countAdminAccounts = countAdminAccounts;
}

public Float getAvgCountBooksPerStudent() {
return avgCountBooksPerStudent;
}

public void setAvgCountBooksPerStudent(Float avgCountBooksPerStudent) {
this.avgCountBooksPerStudent = avgCountBooksPerStudent;
}

public Float getAvgCountStudentLibrariansPerSchool() {
return avgCountStudentLibrariansPerSchool;
}

public void setAvgCountStudentLibrariansPerSchool(Float avgCountStudentLibrariansPerSchool) {
this.avgCountStudentLibrariansPerSchool = avgCountStudentLibrariansPerSchool;
}

public Float getPercentSchoolsWithLibraries() {
return percentSchoolsWithLibraries;
}

public void setPercentSchoolsWithLibraries(Float percentSchoolsWithLibraries) {
this.percentSchoolsWithLibraries = percentSchoolsWithLibraries;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.codeforcommunity.dto.data;

public class MetricsSchoolResponse {
private Float countBooksPerStudent;
private Integer countStudents;
private Integer countStudentLibrarians;
private Integer netBooksInOut;

public MetricsSchoolResponse(
Float countBooksPerStudent,
Integer countStudents,
Integer countStudentLibrarians,
Integer netBooksInOut) {
this.countBooksPerStudent = countBooksPerStudent;
this.countStudents = countStudents;
this.countStudentLibrarians = countStudentLibrarians;
this.netBooksInOut = netBooksInOut;
}

public Float getCountBooksPerStudent() {
return countBooksPerStudent;
}

public void setCountBooksPerStudent(Float countBooksPerStudent) {
this.countBooksPerStudent = countBooksPerStudent;
}

public Integer getCountStudents() {
return countStudents;
}

public void setCountStudents(Integer countStudents) {
this.countStudents = countStudents;
}

public Integer getCountStudentLibrarians() {
return countStudentLibrarians;
}

public void setCountStudentLibrarians(Integer countStudentLibrarians) {
this.countStudentLibrarians = countStudentLibrarians;
}

public Integer getNetBooksInOut() {
return netBooksInOut;
}

public void setNetBooksInOut(Integer netBooksInOut) {
this.netBooksInOut = netBooksInOut;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.codeforcommunity.enums.Country;
import com.codeforcommunity.enums.LibraryStatus;
import java.util.ArrayList;
import java.util.List;

public class School {
Expand Down
8 changes: 7 additions & 1 deletion api/src/main/java/com/codeforcommunity/rest/ApiRouter.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.codeforcommunity.rest;

import com.codeforcommunity.api.authenticated.IProtectedCountryProcessor;
import com.codeforcommunity.api.authenticated.IProtectedDataProcessor;
import com.codeforcommunity.api.authenticated.IProtectedSchoolProcessor;
import com.codeforcommunity.api.authenticated.IProtectedUserProcessor;
import com.codeforcommunity.api.unauthenticated.IAuthProcessor;
import com.codeforcommunity.auth.JWTAuthorizer;
import com.codeforcommunity.rest.subrouter.CommonRouter;
import com.codeforcommunity.rest.subrouter.authenticated.ProtectedCountryRouter;
import com.codeforcommunity.rest.subrouter.authenticated.ProtectedDataRouter;
import com.codeforcommunity.rest.subrouter.authenticated.ProtectedSchoolRouter;
import com.codeforcommunity.rest.subrouter.authenticated.ProtectedUserRouter;
import com.codeforcommunity.rest.subrouter.unauthenticated.AuthRouter;
Expand All @@ -20,18 +22,21 @@ public class ApiRouter implements IRouter {
private final ProtectedUserRouter protectedUserRouter;
private final ProtectedCountryRouter protectedCountryRouter;
private final ProtectedSchoolRouter protectedSchoolRouter;
private final ProtectedDataRouter protectedDataRouter;

public ApiRouter(
JWTAuthorizer jwtAuthorizer,
IAuthProcessor authProcessor,
IProtectedUserProcessor protectedUserProcessor,
IProtectedCountryProcessor protectedCountryProcessor,
IProtectedSchoolProcessor protectedSchoolProcessor) {
IProtectedSchoolProcessor protectedSchoolProcessor,
IProtectedDataProcessor protectedDataProcessor) {
this.commonRouter = new CommonRouter(jwtAuthorizer);
this.authRouter = new AuthRouter(authProcessor);
this.protectedUserRouter = new ProtectedUserRouter(protectedUserProcessor);
this.protectedCountryRouter = new ProtectedCountryRouter(protectedCountryProcessor);
this.protectedSchoolRouter = new ProtectedSchoolRouter(protectedSchoolProcessor);
this.protectedDataRouter = new ProtectedDataRouter(protectedDataProcessor);
}

/** Initialize a router and register all route handlers on it. */
Expand All @@ -57,6 +62,7 @@ private Router defineProtectedRoutes(Vertx vertx) {
protectedSubRouter.mountSubRouter("/user", protectedUserRouter.initializeRouter(vertx));
protectedSubRouter.mountSubRouter("/countries", protectedCountryRouter.initializeRouter(vertx));
protectedSubRouter.mountSubRouter("/schools", protectedSchoolRouter.initializeRouter(vertx));
protectedSubRouter.mountSubRouter("/data", protectedDataRouter.initializeRouter(vertx));

return protectedSubRouter;
}
Expand Down
22 changes: 12 additions & 10 deletions api/src/main/java/com/codeforcommunity/rest/FailureHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ public void handleMissingParameter(RoutingContext ctx, MissingParameterException
}

public void handleNoReportFound(RoutingContext ctx, NoReportFoundException e) {
String message = String.format("Report not found for school with id %d", e.getSchoolId());
String message = String.format("Report not found for school with ID %d", e.getSchoolId());
end(ctx, message, 404);
}

public void handleNoReportByIdFound(RoutingContext ctx, NoReportByIdFoundException e) {
String message = String.format("Report not found for report with id %d", e.getReportId());
String message = String.format("Report not found for report with ID %d", e.getReportId());
end(ctx, message, 404);
}

Expand All @@ -64,15 +64,16 @@ public void handleAdminOnlyRoute(RoutingContext ctx) {

public void handleEmailAlreadyInUse(RoutingContext ctx, EmailAlreadyInUseException exception) {
String message =
String.format("Error creating new user, given email %s already used", exception.getEmail());
String.format(
"Error creating new user, given email '%s' already used", exception.getEmail());

end(ctx, message, 409);
}

public void handleSchoolAlreadyExists(RoutingContext ctx, SchoolAlreadyExistsException e) {
String message =
String.format(
"School '%s' already exists in '%s'", e.getSchoolName(), e.getSchoolCountry());
"School '%s' already exists in country '%s'", e.getSchoolName(), e.getSchoolCountry());
end(ctx, message, 409);
}

Expand Down Expand Up @@ -175,15 +176,15 @@ public void handleMalformedParameter(RoutingContext ctx, MalformedParameterExcep
}

public void handleUnknownCountry(RoutingContext ctx, UnknownCountryException exception) {
String message = String.format("Unknown country given: %s", exception.getUnknownCountry());
String message = String.format("No country found with name %s", exception.getUnknownCountry());
end(ctx, message, 400);
}

public void handleUnknownSchoolContact(
RoutingContext ctx, SchoolContactDoesNotExistException exception) {
String message =
String.format(
"Unknown contact with id '%d' given for school with id '%d'",
"Unknown contact with ID %d given for school with ID %d",
exception.getContactId(), exception.getSchoolId());
end(ctx, message, 400);
}
Expand All @@ -194,23 +195,24 @@ public void handleBadImageRequest(RoutingContext ctx) {
}

public void handleS3FailedUpload(RoutingContext ctx, String exceptionMessage) {
String message = "The given file could not be uploaded to AWS S3: " + exceptionMessage;
String message =
"The given file could not be uploaded to AWS S3 with error: " + exceptionMessage;
end(ctx, message, 502);
}

public void handleSchoolDoesNotExist(RoutingContext ctx, SchoolDoesNotExistException e) {
String message = String.format("No school found with given id: %d", e.getSchoolId());
String message = String.format("No school found with ID %d", e.getSchoolId());
end(ctx, message, 400);
}

public void handleBookLogDoesNotExist(RoutingContext ctx, BookLogDoesNotExistException e) {
String message = String.format("No book log found with given id: %d", e.getBookId());
String message = String.format("No book log found with ID %d", e.getBookId());
end(ctx, message, 400);
}

public void handleCsvSerializer(RoutingContext ctx, CsvSerializerException e) {
String message =
String.format("Report with id: %d was unable to be converted to CSV", e.getReportId());
String.format("Report with ID %d was unable to be converted to CSV", e.getReportId());
end(ctx, message, 500);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.codeforcommunity.rest.subrouter.authenticated;

import static com.codeforcommunity.rest.ApiRouter.end;

import com.codeforcommunity.api.authenticated.IProtectedDataProcessor;
import com.codeforcommunity.auth.JWTData;
import com.codeforcommunity.dto.data.MetricsCountryResponse;
import com.codeforcommunity.dto.data.MetricsSchoolResponse;
import com.codeforcommunity.enums.Country;
import com.codeforcommunity.rest.IRouter;
import com.codeforcommunity.rest.RestFunctions;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;

public class ProtectedDataRouter implements IRouter {

private final IProtectedDataProcessor processor;

public ProtectedDataRouter(IProtectedDataProcessor processor) {
this.processor = processor;
}

@Override
public Router initializeRouter(Vertx vertx) {
Router router = Router.router(vertx);

registerGetFixedCountryMetrics(router);
registerGetFixedSchoolyMetrics(router);

return router;
}

private void registerGetFixedCountryMetrics(Router router) {
Route getCountryMetricsRoute = router.get("/country/:country");
getCountryMetricsRoute.handler(this::handleGetFixedCountryMetrics);
}

private void registerGetFixedSchoolyMetrics(Router router) {
Route getSchoolMetricsRoute = router.get("/school/:school_id");
getSchoolMetricsRoute.handler(this::handleGetFixedSchoolMetrics);
}

private void handleGetFixedCountryMetrics(RoutingContext ctx) {
JWTData userData = ctx.get("jwt_data");

Country country = RestFunctions.getCountryFromString(ctx.pathParam("country"));
MetricsCountryResponse response = processor.getFixedCountryMetrics(userData, country);

end(ctx.response(), 200, JsonObject.mapFrom(response).toString());
}

private void handleGetFixedSchoolMetrics(RoutingContext ctx) {
JWTData userData = ctx.get("jwt_data");

int schoolId = RestFunctions.getPathParamAsInt(ctx, "school_id");
MetricsSchoolResponse response = processor.getFixedSchoolMetrics(userData, schoolId);

end(ctx.response(), 200, JsonObject.mapFrom(response).toString());
}
}
10 changes: 9 additions & 1 deletion service/src/main/java/com/codeforcommunity/ServiceMain.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.codeforcommunity;

import com.codeforcommunity.api.authenticated.IProtectedCountryProcessor;
import com.codeforcommunity.api.authenticated.IProtectedDataProcessor;
import com.codeforcommunity.api.authenticated.IProtectedSchoolProcessor;
import com.codeforcommunity.api.authenticated.IProtectedUserProcessor;
import com.codeforcommunity.api.unauthenticated.IAuthProcessor;
Expand All @@ -9,6 +10,7 @@
import com.codeforcommunity.auth.JWTHandler;
import com.codeforcommunity.logger.SLogger;
import com.codeforcommunity.processor.authenticated.ProtectedCountryProcessorImpl;
import com.codeforcommunity.processor.authenticated.ProtectedDataProcessorImpl;
import com.codeforcommunity.processor.authenticated.ProtectedSchoolProcessorImpl;
import com.codeforcommunity.processor.authenticated.ProtectedUserProcessorImpl;
import com.codeforcommunity.processor.unauthenticated.AuthProcessorImpl;
Expand Down Expand Up @@ -89,11 +91,17 @@ private void initializeServer() {
IProtectedUserProcessor protectedUserProc = new ProtectedUserProcessorImpl(this.db, emailer);
IProtectedCountryProcessor protectedCountryProc = new ProtectedCountryProcessorImpl(this.db);
IProtectedSchoolProcessor protectedSchoolProc = new ProtectedSchoolProcessorImpl(this.db);
IProtectedDataProcessor protectedDataProc = new ProtectedDataProcessorImpl(this.db);

// Create the API router and start the HTTP server
ApiRouter router =
new ApiRouter(
jwtAuthorizer, authProc, protectedUserProc, protectedCountryProc, protectedSchoolProc);
jwtAuthorizer,
authProc,
protectedUserProc,
protectedCountryProc,
protectedSchoolProc,
protectedDataProc);
startApiServer(router, vertx);
}

Expand Down
Loading