wip mifosx-195 runreports api now used for running reports instead of reports - updated in api-docs along with report maintenance apis
This commit is contained in:
+210
-38
@@ -1271,14 +1271,22 @@
|
||||
<tr>
|
||||
<td><a href="#reports">Report</a></td>
|
||||
<td>reports</td>
|
||||
<td></td>
|
||||
<td><a href="#reports_create">Create a Report</a></td>
|
||||
<td><a href="#reports_list">List Reports</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="alt">
|
||||
<td></td>
|
||||
<td>reports/{reportName}</td>
|
||||
<td>reports/{id}</td>
|
||||
<td></td>
|
||||
<td><a href="#reports_retrieve">Retrieve a Report</a></td>
|
||||
<td><a href="#reports_update">Update a Report</a></td>
|
||||
<td><a href="#reports_delete">Delete a Report</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#runreports">Run Report</a></td>
|
||||
<td>runreports/{reportName}</td>
|
||||
<td></td>
|
||||
<td><a href="#report_run">Run a Report</a></td>
|
||||
<td></td>
|
||||
@@ -8045,6 +8053,13 @@ Content-Type: application/json
|
||||
|
||||
|
||||
<!-- Fund starts here -->
|
||||
<a id="funds" name="funds" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h3>Funds</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="funds_create" name="funds_create" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
@@ -10634,10 +10649,63 @@ No Request Body:
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h3>Reports</h3>
|
||||
<p>
|
||||
Non-core reports can be added, updated and deleted.
|
||||
</p>
|
||||
<p>
|
||||
Core reports (supplied at installation/upgrade time) can only have their "useReport" updated.
|
||||
"useReport" is used, for example, in the reference UI report page to 'show'/'not show' reports.
|
||||
Reports that have useReport set to false can still be run.
|
||||
Reports only used for workflow purposes are examples of reports that would have their useReport set to false.
|
||||
</p>
|
||||
<p>
|
||||
Placeholders can be put in the reportSql to act as parameters. They have the format ${paramName}.
|
||||
The runreports api will translate the value of any query parameter beginning R_ with the equivalent placeholder.<br>
|
||||
e.g. query parameter R_myName=john will replace ${myName} with john
|
||||
</p>
|
||||
<p>
|
||||
There is a special 'automatic' placeholder ${currentUserHierarchy} - if this is included in reportSql
|
||||
it gets replaced by the requesting users' office hierarchy value. This enables data scoping.<br>
|
||||
Usage example "where o.hierarchy like CONCAT('${currentUserHierarchy}', '%')"
|
||||
</p>
|
||||
<p>
|
||||
Note: <br>
|
||||
The reports api allows parameters (not just placeholders in reportSql) to be associated with reports.
|
||||
These associated parameters are only required to allow the reference UI reporting functionality implement
|
||||
user-friendly parameter input.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<a id="reports_create" name="reports_create" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Create a Report</h4>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
POST https://DomainName/api/v1/reports
|
||||
</code>
|
||||
<code class="method-request">
|
||||
POST reports
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{
|
||||
reportName: "myReport",
|
||||
reportType: "Table",
|
||||
reportCategory: "My Category",
|
||||
description: "sample non-core report",
|
||||
reportSql: "select 'hello'",
|
||||
useReport: false
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"resourceId": 100
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="reports_list" name="reports_list" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
@@ -10709,6 +10777,106 @@ GET https://DomainName/api/v1/reports
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<a id="reports_retrieve" name="reports_retrieve" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Retrieve a Report</h4>
|
||||
<p>Example Requests:</p>
|
||||
<div class=apiClick>reports/1</div>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
GET https://DomainName/api/v1/reports/{id}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"id": 1,
|
||||
"reportName": "Client Listing",
|
||||
"reportType": "Table",
|
||||
"reportCategory": "Client",
|
||||
"description": "Individual Client Report\r\n\r\nLists the small number of defined fields on the client table. Would expect to copy this \n\nreport and add any \u0027one to one\u0027 additional data for specific tenant needs.\r\n\r\nCan be run for any size MFI but you\u0027d expect it only to be run within a branch for \n\nlarger ones. Depending on how many columns are displayed, there is probably is a limit of about 20/50k clients returned for html display (export to excel doesn\u0027t \n\nhave that client browser/memory impact).",
|
||||
"reportSql": "select \r\nconcat(repeat(\"..\", \r\n ((LENGTH(ounder.`hierarchy`) - LENGTH(REPLACE(ounder.`hierarchy`, \u0027.\u0027, \u0027\u0027)) - 1))), ounder.`name`) as \"Office/Branch\",\r\n c.account_no as \"Client Account No.\", \r\nc.display_name as \"Name\", \n\nc.joined_date as \"Joined\", c.external_id as \"External Id\"\r\nfrom m_office o \r\njoin m_office ounder on ounder.hierarchy like concat(o.hierarchy, \u0027%\u0027)\r\nand \n\nounder.hierarchy like concat(\u0027${currentUserHierarchy}\u0027, \u0027%\u0027)\r\njoin m_client c on c.office_id \u003d ounder.id\r\nwhere o.id \u003d ${officeId}\r\nand c.is_deleted\u003d0\r\n\n\norder by ounder.hierarchy, c.account_no",
|
||||
"coreReport": true,
|
||||
"useReport": true,
|
||||
"reportParameters": [
|
||||
{
|
||||
"id": 5,
|
||||
"parameterName": "OfficeIdSelectOne"
|
||||
}
|
||||
]
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="reports_update" name="reports_update" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Update a Report</h4>
|
||||
<p>
|
||||
Only the useReport value can be updated for core reports.
|
||||
</p>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
PUT https://DomainName/api/v1/reports/{id}
|
||||
</code>
|
||||
<code class="method-request">
|
||||
PUT reports/100
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{
|
||||
reportCategory: "My Category updated",
|
||||
useReport: true
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"resourceId": 100,
|
||||
"changes": {
|
||||
"reportCategory": "My Category updated",
|
||||
"useReport": true
|
||||
}
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<a id="reports_delete" name="reports_delete" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Delete a Report</h4>
|
||||
<p>
|
||||
Only non-core reports can be deleted.
|
||||
</p>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
DELETE https://DomainName/api/v1/reports/{id}
|
||||
</code>
|
||||
<code class="method-request">
|
||||
DELETE reports/100
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"resourceId": 100
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- start of runreports api docs -->
|
||||
<a id="runreports" name="runreports" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h3>Run Reports</h3>
|
||||
</div>
|
||||
</div>
|
||||
<a id="report_run" name="report_run" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
@@ -10767,36 +10935,32 @@ GET https://DomainName/api/v1/reports
|
||||
<dd>Only applies to Pentaho reports.</dd>
|
||||
</dl>
|
||||
<p>Example Requests:</p>
|
||||
<div class=apiClick>reports/Client%20Listing?R_officeId=1</div>
|
||||
<div class=apiClick>runreports/Client%20Listing?R_officeId=1</div>
|
||||
<br>
|
||||
<br>
|
||||
<div class=apiClick>reports/Client%20Listing?R_officeId=1&exportCSV=true</div>
|
||||
<div class=apiClick>runreports/Client%20Listing?R_officeId=1&exportCSV=true</div>
|
||||
<br>
|
||||
<br>
|
||||
<div class=apiClick>reports/selectOfficeId?R_officeId=1&parameterType=true</div>
|
||||
<div class=apiClick>runreports/OfficeIdSelectOne?R_officeId=1&parameterType=true</div>
|
||||
<br>
|
||||
<br>
|
||||
<div class=apiClick>reports/selectOfficeId?R_officeId=1&parameterType=true&exportCSV=true</div>
|
||||
<div class=apiClick>runreports/OfficeIdSelectOne?R_officeId=1&parameterType=true&exportCSV=true</div>
|
||||
<br>
|
||||
<br>
|
||||
<div class=apiClick>reports/Client Listing
|
||||
(Pentaho)?output-type=HTML&R_officeId=1</div>
|
||||
<div class=apiClick>runreports/Expected%20Payments%20By%20Date%20-%20Formatted?R_endDate=2013-04-30&R_loanOfficerId=-1&R_officeId=1&R_startDate=2013-04-16&output-type=HTML&R_officeId=1</div>
|
||||
<br>
|
||||
<br>
|
||||
<div class=apiClick>reports/Client Listing
|
||||
(Pentaho)?output-type=XLS&R_officeId=1</div>
|
||||
<div class=apiClick>runreports/Expected%20Payments%20By%20Date%20-%20Formatted?R_endDate=2013-04-30&R_loanOfficerId=-1&R_officeId=1&R_startDate=2013-04-16&output-type=XLS&R_officeId=1</div>
|
||||
<br>
|
||||
<br>
|
||||
<div class=apiClick>reports/Client Listing
|
||||
(Pentaho)?output-type=CSV&R_officeId=1</div>
|
||||
<div class=apiClick>runreports/Expected%20Payments%20By%20Date%20-%20Formatted?R_endDate=2013-04-30&R_loanOfficerId=-1&R_officeId=1&R_startDate=2013-04-16&output-type=CSV&R_officeId=1</div>
|
||||
<br>
|
||||
<br>
|
||||
<div class=apiClick>reports/Client Listing
|
||||
(Pentaho)?output-type=PDF&R_officeId=1</div>
|
||||
<div class=apiClick>runreports/Expected%20Payments%20By%20Date%20-%20Formatted?R_endDate=2013-04-30&R_loanOfficerId=-1&R_officeId=1&R_startDate=2013-04-16&output-type=PDF&R_officeId=1</div>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
GET https://DomainName/api/v1/reports/{reportName}
|
||||
GET https://DomainName/api/v1/runreports/{reportName}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
@@ -13356,23 +13520,31 @@ GET https://DomainName/api/v1/search?query=000000111
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#reports">Report</a></td>
|
||||
<td>reports</td>
|
||||
<td></td>
|
||||
<td><a href="#reports_list">List Reports</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#reports">Report</a></td>
|
||||
<td>reports</td>
|
||||
<td><a href="#reports_create">Create a Report</a></td>
|
||||
<td><a href="#reports_list">List Reports</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="alt">
|
||||
<td></td>
|
||||
<td>reports/{id}</td>
|
||||
<td></td>
|
||||
<td><a href="#reports_retrieve">Retrieve a Report</a></td>
|
||||
<td><a href="#reports_update">Update a Report</a></td>
|
||||
<td><a href="#reports_delete">Delete a Report</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#runreports">Run Report</a></td>
|
||||
<td>runreports/{reportName}</td>
|
||||
<td></td>
|
||||
<td><a href="#report_run">Run a Report</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="alt">
|
||||
<td></td>
|
||||
<td>reports/{reportName}</td>
|
||||
<td></td>
|
||||
<td><a href="#report_run">Run a Report</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#authentication">Authentication</a></td>
|
||||
<td>authentication</td>
|
||||
<td><a href="#authenticate_request">Verify Authentication</a></td>
|
||||
@@ -13380,7 +13552,7 @@ GET https://DomainName/api/v1/search?query=000000111
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="alt">
|
||||
<tr>
|
||||
<td><a href="#users">User</a></td>
|
||||
<td>users</td>
|
||||
<td><a href="#users_create">Create a User</a></td>
|
||||
@@ -13388,7 +13560,7 @@ GET https://DomainName/api/v1/search?query=000000111
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr class="alt">
|
||||
<td></td>
|
||||
<td>users/{userId}</td>
|
||||
<td></td>
|
||||
@@ -13396,7 +13568,7 @@ GET https://DomainName/api/v1/search?query=000000111
|
||||
<td><a href="#users_update">Update a User</a></td>
|
||||
<td><a href="#users_delete">Delete a User</a></td>
|
||||
</tr>
|
||||
<tr class="alt">
|
||||
<tr>
|
||||
<td><a href="#roles">Role</a></td>
|
||||
<td>roles</td>
|
||||
<td><a href="#roles_create">Create a New Role</a></td>
|
||||
@@ -13404,7 +13576,7 @@ GET https://DomainName/api/v1/search?query=000000111
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr class="alt">
|
||||
<td></td>
|
||||
<td>roles/{roleId}</td>
|
||||
<td></td>
|
||||
@@ -13412,7 +13584,7 @@ GET https://DomainName/api/v1/search?query=000000111
|
||||
<td><a href="#roles_update">Update a Role</a></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="alt">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>roles/{roleId}/permissions</td>
|
||||
<td></td>
|
||||
@@ -13422,7 +13594,7 @@ GET https://DomainName/api/v1/search?query=000000111
|
||||
Permissions</a></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr class="alt">
|
||||
<td><a href="#permissions">Permission</a></td>
|
||||
<td>permissions</td>
|
||||
<td></td>
|
||||
|
||||
+2
-156
@@ -5,12 +5,9 @@
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.dataqueries.api;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
@@ -23,27 +20,18 @@ import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.ResponseBuilder;
|
||||
import javax.ws.rs.core.StreamingOutput;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ReportData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.service.GenericDataService;
|
||||
import org.mifosplatform.infrastructure.dataqueries.service.ReadReportingService;
|
||||
import org.mifosplatform.infrastructure.security.exception.NoAuthorizationException;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -58,11 +46,10 @@ public class ReportsApiResource {
|
||||
"reportCategory", "description", "reportSql", "coreReport",
|
||||
"useReport", "reportParameters"));
|
||||
|
||||
private final String resourceNameForPermissions = "FUND";
|
||||
private final String resourceNameForPermissions = "REPORT";
|
||||
private final PlatformSecurityContext context;
|
||||
private final ToApiJsonSerializer<ReportData> toApiJsonSerializer;
|
||||
private final ReadReportingService readExtraDataAndReportingService;
|
||||
private final GenericDataService genericDataService;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
|
||||
@@ -70,13 +57,11 @@ public class ReportsApiResource {
|
||||
public ReportsApiResource(
|
||||
final PlatformSecurityContext context,
|
||||
final ReadReportingService readExtraDataAndReportingService,
|
||||
final GenericDataService genericDataService,
|
||||
final ToApiJsonSerializer<ReportData> toApiJsonSerializer,
|
||||
PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||
final ApiRequestParameterHelper apiRequestParameterHelper) {
|
||||
this.context = context;
|
||||
this.readExtraDataAndReportingService = readExtraDataAndReportingService;
|
||||
this.genericDataService = genericDataService;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
||||
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||
@@ -100,7 +85,7 @@ public class ReportsApiResource {
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("wip/{id}")
|
||||
@Path("{id}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveReport(@PathParam("id") final Long id,
|
||||
@@ -163,143 +148,4 @@ public class ReportsApiResource {
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{reportName}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON, "application/x-msdownload",
|
||||
"application/vnd.ms-excel", "application/pdf", "text/html" })
|
||||
public Response runReport(
|
||||
@PathParam("reportName") final String reportName,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
MultivaluedMap<String, String> queryParams = uriInfo
|
||||
.getQueryParameters();
|
||||
|
||||
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo
|
||||
.getQueryParameters());
|
||||
boolean exportCsv = ApiParameterHelper.exportCsv(uriInfo
|
||||
.getQueryParameters());
|
||||
boolean parameterType = ApiParameterHelper.parameterType(uriInfo
|
||||
.getQueryParameters());
|
||||
boolean exportPdf = ApiParameterHelper.exportPdf(uriInfo
|
||||
.getQueryParameters());
|
||||
|
||||
checkUserPermissionForReport(reportName, parameterType);
|
||||
|
||||
String parameterTypeValue = null;
|
||||
if (!parameterType) {
|
||||
parameterTypeValue = "report";
|
||||
if (this.readExtraDataAndReportingService.getReportType(reportName)
|
||||
.equalsIgnoreCase("Pentaho")) {
|
||||
Map<String, String> reportParams = getReportParams(queryParams,
|
||||
true);
|
||||
return this.readExtraDataAndReportingService
|
||||
.processPentahoRequest(reportName,
|
||||
queryParams.getFirst("output-type"),
|
||||
reportParams);
|
||||
}
|
||||
} else {
|
||||
parameterTypeValue = "parameter";
|
||||
}
|
||||
|
||||
// PDF format
|
||||
|
||||
if (exportPdf) {
|
||||
Map<String, String> reportParams = getReportParams(queryParams,
|
||||
false);
|
||||
String pdfFileName = this.readExtraDataAndReportingService
|
||||
.retrieveReportPDF(reportName, parameterTypeValue,
|
||||
reportParams);
|
||||
|
||||
File file = new File(pdfFileName);
|
||||
|
||||
ResponseBuilder response = Response.ok(file);
|
||||
response.header("Content-Disposition", "attachment; filename=\""
|
||||
+ pdfFileName + "\"");
|
||||
response.header("content-Type", "application/pdf");
|
||||
|
||||
return response.build();
|
||||
|
||||
}
|
||||
|
||||
if (!exportCsv) {
|
||||
Map<String, String> reportParams = getReportParams(queryParams,
|
||||
false);
|
||||
|
||||
GenericResultsetData result = this.readExtraDataAndReportingService
|
||||
.retrieveGenericResultset(reportName, parameterTypeValue,
|
||||
reportParams);
|
||||
|
||||
String json = "";
|
||||
final boolean genericResultSetIsPassed = ApiParameterHelper
|
||||
.genericResultSetPassed(uriInfo.getQueryParameters());
|
||||
final boolean genericResultSet = ApiParameterHelper
|
||||
.genericResultSet(uriInfo.getQueryParameters());
|
||||
if (genericResultSetIsPassed) {
|
||||
if (genericResultSet) {
|
||||
json = this.toApiJsonSerializer.serializePretty(
|
||||
prettyPrint, result);
|
||||
} else {
|
||||
json = this.genericDataService
|
||||
.generateJsonFromGenericResultsetData(result);
|
||||
}
|
||||
} else {
|
||||
json = this.toApiJsonSerializer.serializePretty(prettyPrint,
|
||||
result);
|
||||
}
|
||||
|
||||
return Response.ok().entity(json).type(MediaType.APPLICATION_JSON)
|
||||
.build();
|
||||
}
|
||||
|
||||
// CSV Export
|
||||
Map<String, String> reportParams = getReportParams(queryParams, false);
|
||||
StreamingOutput result = this.readExtraDataAndReportingService
|
||||
.retrieveReportCSV(reportName, parameterTypeValue, reportParams);
|
||||
|
||||
return Response
|
||||
.ok()
|
||||
.entity(result)
|
||||
.type("application/x-msdownload")
|
||||
.header("Content-Disposition",
|
||||
"attachment;filename=" + reportName.replaceAll(" ", "")
|
||||
+ ".csv").build();
|
||||
}
|
||||
|
||||
private void checkUserPermissionForReport(final String reportName,
|
||||
final boolean parameterType) {
|
||||
|
||||
// Anyone can run a 'report' that is simply getting possible parameter
|
||||
// (dropdown listbox) values.
|
||||
if (!parameterType) {
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
if (currentUser.hasNotPermissionForReport(reportName)) {
|
||||
throw new NoAuthorizationException(
|
||||
"Not authorised to run report: " + reportName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> getReportParams(
|
||||
final MultivaluedMap<String, String> queryParams,
|
||||
final Boolean isPentaho) {
|
||||
|
||||
Map<String, String> reportParams = new HashMap<String, String>();
|
||||
Set<String> keys = queryParams.keySet();
|
||||
String pKey;
|
||||
String pValue;
|
||||
for (String k : keys) {
|
||||
|
||||
if (k.startsWith("R_")) {
|
||||
if (isPentaho)
|
||||
pKey = k.substring(2);
|
||||
else
|
||||
pKey = "${" + k.substring(2) + "}";
|
||||
|
||||
pValue = queryParams.get(k).get(0);
|
||||
reportParams.put(pKey, pValue);
|
||||
}
|
||||
}
|
||||
return reportParams;
|
||||
}
|
||||
}
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.dataqueries.api;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.ResponseBuilder;
|
||||
import javax.ws.rs.core.StreamingOutput;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ReportData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.service.GenericDataService;
|
||||
import org.mifosplatform.infrastructure.dataqueries.service.ReadReportingService;
|
||||
import org.mifosplatform.infrastructure.security.exception.NoAuthorizationException;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/runreports")
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class RunreportsApiResource {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final ToApiJsonSerializer<ReportData> toApiJsonSerializer;
|
||||
private final ReadReportingService readExtraDataAndReportingService;
|
||||
private final GenericDataService genericDataService;
|
||||
|
||||
@Autowired
|
||||
public RunreportsApiResource(final PlatformSecurityContext context,
|
||||
final ReadReportingService readExtraDataAndReportingService,
|
||||
final GenericDataService genericDataService,
|
||||
final ToApiJsonSerializer<ReportData> toApiJsonSerializer) {
|
||||
this.context = context;
|
||||
this.readExtraDataAndReportingService = readExtraDataAndReportingService;
|
||||
this.genericDataService = genericDataService;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{reportName}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON, "application/x-msdownload",
|
||||
"application/vnd.ms-excel", "application/pdf", "text/html" })
|
||||
public Response runReport(@PathParam("reportName") final String reportName,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
MultivaluedMap<String, String> queryParams = uriInfo
|
||||
.getQueryParameters();
|
||||
|
||||
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo
|
||||
.getQueryParameters());
|
||||
boolean exportCsv = ApiParameterHelper.exportCsv(uriInfo
|
||||
.getQueryParameters());
|
||||
boolean parameterType = ApiParameterHelper.parameterType(uriInfo
|
||||
.getQueryParameters());
|
||||
boolean exportPdf = ApiParameterHelper.exportPdf(uriInfo
|
||||
.getQueryParameters());
|
||||
|
||||
checkUserPermissionForReport(reportName, parameterType);
|
||||
|
||||
String parameterTypeValue = null;
|
||||
if (!parameterType) {
|
||||
parameterTypeValue = "report";
|
||||
if (this.readExtraDataAndReportingService.getReportType(reportName)
|
||||
.equalsIgnoreCase("Pentaho")) {
|
||||
Map<String, String> reportParams = getReportParams(queryParams,
|
||||
true);
|
||||
return this.readExtraDataAndReportingService
|
||||
.processPentahoRequest(reportName,
|
||||
queryParams.getFirst("output-type"),
|
||||
reportParams);
|
||||
}
|
||||
} else {
|
||||
parameterTypeValue = "parameter";
|
||||
}
|
||||
|
||||
// PDF format
|
||||
|
||||
if (exportPdf) {
|
||||
Map<String, String> reportParams = getReportParams(queryParams,
|
||||
false);
|
||||
String pdfFileName = this.readExtraDataAndReportingService
|
||||
.retrieveReportPDF(reportName, parameterTypeValue,
|
||||
reportParams);
|
||||
|
||||
File file = new File(pdfFileName);
|
||||
|
||||
ResponseBuilder response = Response.ok(file);
|
||||
response.header("Content-Disposition", "attachment; filename=\""
|
||||
+ pdfFileName + "\"");
|
||||
response.header("content-Type", "application/pdf");
|
||||
|
||||
return response.build();
|
||||
|
||||
}
|
||||
|
||||
if (!exportCsv) {
|
||||
Map<String, String> reportParams = getReportParams(queryParams,
|
||||
false);
|
||||
|
||||
GenericResultsetData result = this.readExtraDataAndReportingService
|
||||
.retrieveGenericResultset(reportName, parameterTypeValue,
|
||||
reportParams);
|
||||
|
||||
String json = "";
|
||||
final boolean genericResultSetIsPassed = ApiParameterHelper
|
||||
.genericResultSetPassed(uriInfo.getQueryParameters());
|
||||
final boolean genericResultSet = ApiParameterHelper
|
||||
.genericResultSet(uriInfo.getQueryParameters());
|
||||
if (genericResultSetIsPassed) {
|
||||
if (genericResultSet) {
|
||||
json = this.toApiJsonSerializer.serializePretty(
|
||||
prettyPrint, result);
|
||||
} else {
|
||||
json = this.genericDataService
|
||||
.generateJsonFromGenericResultsetData(result);
|
||||
}
|
||||
} else {
|
||||
json = this.toApiJsonSerializer.serializePretty(prettyPrint,
|
||||
result);
|
||||
}
|
||||
|
||||
return Response.ok().entity(json).type(MediaType.APPLICATION_JSON)
|
||||
.build();
|
||||
}
|
||||
|
||||
// CSV Export
|
||||
Map<String, String> reportParams = getReportParams(queryParams, false);
|
||||
StreamingOutput result = this.readExtraDataAndReportingService
|
||||
.retrieveReportCSV(reportName, parameterTypeValue, reportParams);
|
||||
|
||||
return Response
|
||||
.ok()
|
||||
.entity(result)
|
||||
.type("application/x-msdownload")
|
||||
.header("Content-Disposition",
|
||||
"attachment;filename=" + reportName.replaceAll(" ", "")
|
||||
+ ".csv").build();
|
||||
}
|
||||
|
||||
private void checkUserPermissionForReport(final String reportName,
|
||||
final boolean parameterType) {
|
||||
|
||||
// Anyone can run a 'report' that is simply getting possible parameter
|
||||
// (dropdown listbox) values.
|
||||
if (!parameterType) {
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
if (currentUser.hasNotPermissionForReport(reportName)) {
|
||||
throw new NoAuthorizationException(
|
||||
"Not authorised to run report: " + reportName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> getReportParams(
|
||||
final MultivaluedMap<String, String> queryParams,
|
||||
final Boolean isPentaho) {
|
||||
|
||||
Map<String, String> reportParams = new HashMap<String, String>();
|
||||
Set<String> keys = queryParams.keySet();
|
||||
String pKey;
|
||||
String pValue;
|
||||
for (String k : keys) {
|
||||
|
||||
if (k.startsWith("R_")) {
|
||||
if (isPentaho)
|
||||
pKey = k.substring(2);
|
||||
else
|
||||
pKey = "${" + k.substring(2) + "}";
|
||||
|
||||
pValue = queryParams.get(k).get(0);
|
||||
reportParams.put(pKey, pValue);
|
||||
}
|
||||
}
|
||||
return reportParams;
|
||||
}
|
||||
}
|
||||
+1
-24
@@ -185,30 +185,7 @@ public class ReadReportingServiceImpl implements ReadReportingService {
|
||||
long startTime = System.currentTimeMillis();
|
||||
logger.info("STARTING REPORT: " + name + " Type: " + type);
|
||||
|
||||
String sql;
|
||||
if (name.equals(".")) {
|
||||
// this is to support api /reports - which isn't an important
|
||||
// call. It isn't used in the default reporting UI. But there is a
|
||||
// need to provide an api that does bring back 'permitted' reports
|
||||
// PERMITTED REPORTS SQL
|
||||
sql = "select r.report_id, r.report_name, r.report_type, r.report_subtype, r.report_category,"
|
||||
+ " rp.parameter_id, rp.report_parameter_name, p.parameter_name"
|
||||
+ " from stretchy_report r"
|
||||
+ " left join stretchy_report_parameter rp on rp.report_id = r.report_id"
|
||||
+ " left join stretchy_parameter p on p.parameter_id = rp.parameter_id"
|
||||
+ " where exists"
|
||||
+ " (select 'f'"
|
||||
+ " from m_appuser_role ur "
|
||||
+ " join m_role r on r.id = ur.role_id"
|
||||
+ " left join m_role_permission rp on rp.role_id = r.id"
|
||||
+ " left join m_permission p on p.id = rp.permission_id"
|
||||
+ " where ur.appuser_id = "
|
||||
+ context.authenticatedUser().getId()
|
||||
+ " and (p.code in ('ALL_FUNCTIONS', 'ALL_FUNCTIONS_READ') or p.code = concat('READ_', r.report_name))) "
|
||||
+ " order by r.report_name, rp.parameter_id";
|
||||
} else {
|
||||
sql = getSQLtoRun(name, type, queryParams);
|
||||
}
|
||||
String sql = getSQLtoRun(name, type, queryParams);
|
||||
|
||||
GenericResultsetData result = genericDataService
|
||||
.fillGenericResultSet(sql);
|
||||
|
||||
Reference in New Issue
Block a user