package pt.ist.internalBilling.api;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import org.fenixedu.bennu.InternalBillingConfiguration;
import org.fenixedu.bennu.InternalBillingConfiguration.ConfigurationProperties;
import org.fenixedu.bennu.core.domain.User;
import org.fenixedu.bennu.core.domain.UserProfile;
import org.fenixedu.bennu.core.security.Authenticate;
import org.joda.time.DateTime;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import module.finance.util.Money;
import pt.ist.expenditureTrackingSystem.domain.organization.Unit;
import pt.ist.internalBilling.BillingInformationHook;
import pt.ist.internalBilling.domain.Billable;
import pt.ist.internalBilling.domain.BillableService;
import pt.ist.internalBilling.domain.BillableStatus;
import pt.ist.internalBilling.domain.CurrentBillableHistory;
import pt.ist.internalBilling.domain.PrintService;
import pt.ist.internalBilling.domain.UserBeneficiary;
@Path("/internalBilling/v1")
public class InternalBillingAPIv1 {
public final static String JSON_UTF8 = "application/json; charset=utf-8";
@GET
@Produces(JSON_UTF8)
@Path("print/user/{username}/info")
public String userInfo(final @PathParam("username") String username, final @QueryParam("token") String token) {
checkAppCredentials(token);
final User user = User.findByUsername(username);
return toJson(user).toString();
}
@POST
@Produces(JSON_UTF8)
@Path("print/user/{username}/setUnit/{unitId}")
public String setUnit(final @PathParam("username") String username, final @PathParam("unitId") String unitId, final @QueryParam("token") String token) {
checkAppCredentials(token);
final User user = User.findByUsername(username);
if (user != null) {
try {
Authenticate.mock(user);
final UserBeneficiary beneficiary = user.getUserBeneficiary();
if (beneficiary != null) {
beneficiary.getBillableSet().stream()
.filter(b -> b.getBillableStatus() == BillableStatus.AUTHORIZED)
.filter(b -> b.getUnit().getExternalId().equals(unitId))
.filter(b -> b.getBillableService() instanceof PrintService)
.peek(b -> BillingInformationHook.HOOKS.forEach(h -> h.signalUnitChange(user, b.getUnit())))
.forEach(b -> b.setUserFromCurrentBillable(user)); // only 1 o 0 ... but this will do the job
;
}
} finally {
Authenticate.unmock();
}
}
return toJson(user).toString();
}
private JsonObject toJson(final User user) {
final JsonObject jo = new JsonObject();
if (user != null) {
final UserProfile profile = user.getProfile();
jo.addProperty("username", user.getUsername());
jo.addProperty("avatarUrl", profile.getAvatarUrl());
jo.addProperty("name", profile.getDisplayName());
final JsonObject currentBillingUnit = toJson(currentBillingUnitFor(user));
jo.add("currentBillingUnit", currentBillingUnit);
final JsonArray billingUnits = billingUnitsFor(user);
jo.add("billingUnits", billingUnits);
BillingInformationHook.HOOKS.forEach(h -> h.addInfoFor(jo, user));
}
return jo;
}
private JsonArray billingUnitsFor(final User user) {
final JsonArray result = new JsonArray();
if (user != null) {
final UserBeneficiary beneficiary = user.getUserBeneficiary();
if (beneficiary != null) {
beneficiary.getBillableSet().stream()
.filter(b -> b.getBillableStatus() == BillableStatus.AUTHORIZED)
.filter(b -> b.getBillableService() instanceof PrintService)
.forEach(b -> result.add(toJson(b)));
}
}
return result;
}
private Billable currentBillingUnitFor(final User user) {
final CurrentBillableHistory currentBillableHistory = user.getCurrentBillableHistory();
if (currentBillableHistory != null) {
final Billable billable = currentBillableHistory.getBillable();
if (billable != null) {
final BillableStatus status = billable.getBillableStatus();
if (status == BillableStatus.AUTHORIZED) {
final BillableService service = billable.getBillableService();
if (service instanceof PrintService) {
return billable;
}
}
}
}
return null;
}
private JsonObject toJson(final Billable billable) {
if (billable != null) {
final JsonObject jo = billable.getConfigurationAsJson();
final Unit unit = billable.getUnit();
jo.addProperty("id", unit.getExternalId());
jo.addProperty("shortIdentifier", unit.getShortIdentifier());
jo.addProperty("name", unit.getName());
jo.addProperty("presentationName", unit.getPresentationName());
final DateTime dt = new DateTime();
final Money value = billable.getBillableTransactionSet().stream()
.filter(tx -> tx.getTxDate().getYear() == dt.getYear() && tx.getTxDate().getMonthOfYear() == dt.getMonthOfYear())
.map(tx -> tx.getValue())
.reduce(Money.ZERO, Money::add);
jo.addProperty("consumptionForCurrentMonth", value.exportAsString());
BillingInformationHook.HOOKS.forEach(h -> h.addInfoFor(jo, billable));
return jo;
}
return null;
}
private void checkAppCredentials(final String token) {
final ConfigurationProperties confifg = InternalBillingConfiguration.getConfiguration();
final String printAppToken = confifg.printAppToken();
if (printAppToken == null || printAppToken.isEmpty() || !printAppToken.equals(token)) {
JsonObject errorObject = new JsonObject();
errorObject.addProperty("error", "not.authorized");
errorObject.addProperty("description", "You are not authorized to access this endpoint. Check your credentials.");
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).entity(errorObject.toString()).build());
}
}
}