Skip to content

Commit

Permalink
Merge pull request #34 from matallen/master
Browse files Browse the repository at this point in the history
Export facilities cleanup
  • Loading branch information
matallen authored Jun 28, 2019
2 parents 89d3c3c + b235842 commit 476728e
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 134 deletions.
269 changes: 151 additions & 118 deletions src/main/java/com/redhat/sso/ninja/ExportController.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
Expand All @@ -30,148 +32,179 @@
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.redhat.sso.ninja.utils.Json;
import com.redhat.sso.ninja.utils.MapBuilder;

@Path("/")
public class ExportController{

enum Format{
csv,json,xls
};

public static void main(String[] asd) throws IOException{
System.out.println(
new ExportController().export(null, "xls").getEntity()
);
}

List<String> order = Lists.newArrayList("id","name","belt","total","points","github","gitlab","trello");
public int getHeaderOrder(String hdr){
for(String orderMatcher:order){
if (hdr.toLowerCase().contains(orderMatcher)){
return order.indexOf(orderMatcher);
}
}
return -1;
}

enum Format{
csv,json,xls
};

public static void main(String[] asd) throws IOException{
System.out.println(
// new ExportController().exportScorecards(null, "xls").getEntity()
new ExportController().exportEvents(null, "csv").getEntity()
);
}

/* Comparator to order the header and fields of the exported data */
class HeaderComparator implements Comparator<String>{
List<String> order;
public HeaderComparator(String[] orderOfItems){
order=Lists.newArrayList(orderOfItems);
}
public int compare(String o1, String o2){
if (!o1.equals(o2))
return getOrder(o1)-getOrder(o2);
return 0;
}
public int getOrder(String hdr){
for(String orderMatcher:order){
if (hdr.toLowerCase().contains(orderMatcher))
return order.indexOf(orderMatcher);
}
return -1;
}
}


@GET
@Path("/events/export/{format}")
public Response exportEvents(@Context HttpServletRequest request, @PathParam("format") String format) throws IOException{

List<Map<String, String>> data=new ManagementController().getAllEvents();

Set<String> headerset=new HashSet<String>();
for(Map<String, String> row:data)
headerset.addAll(row.keySet());
List<String> headers=new ArrayList<String>();
headers.addAll(headerset);

// Sort the data columns
headers.sort(new HeaderComparator(new String[]{"timestamp","type","text","user"}));

Map<String,String> dataHeaderMapping=new MapBuilder<String,String>().build();

// export the data
return writeExportFile("Events", format, headers, data, dataHeaderMapping);
}


@GET
@Path("/scorecards/export/{format}")
public Response export(@Context HttpServletRequest request, @PathParam("format") String format) throws IOException{
public Response exportScorecards(@Context HttpServletRequest request, @PathParam("format") String format) throws IOException{

if (!EnumUtils.isValidEnum(Format.class, format)) throw new RuntimeException("format must be in "+Joiner.on(",").join(EnumUtils.getEnumList(Format.class)));


if (!EnumUtils.isValidEnum(Format.class, format)) throw new RuntimeException("format must be in "+Joiner.on(",").join(EnumUtils.getEnumList(Format.class)));


List<String> headers=new ArrayList<String>();
String jsonToOutput=(String)new ManagementController().getScorecards().getEntity();

// Convert data back from datatables json format back to a flatter format for exporting
Map<String,List<Map<String, Object>>> result=Json.newObjectMapper(true).readValue(jsonToOutput, new TypeReference<Map<String, List<Map<String, Object>>>>(){});
List<Map<String, Object>> dataRaw=result.get("data");

// Manage Columns (and their data field name)
List<Map<String, Object>> columnsRaw=result.get("columns");
Map<String,String> columnFieldName=new HashMap<String, String>();
for(Map<String,Object> column:columnsRaw){
String header=(String)column.get("title");
columnFieldName.put(header, (String)column.get("data"));
headers.add(header);
}
headers.add("id");
List<String> headers=new ArrayList<String>();
String jsonToOutput=(String)new ManagementController().getScorecards().getEntity();

// Convert data back from datatables json format back to a flatter format for exporting
Map<String,List<Map<String, Object>>> result=Json.newObjectMapper(true).readValue(jsonToOutput, new TypeReference<Map<String, List<Map<String, Object>>>>(){});
List<Map<String, Object>> dataRaw=result.get("data");

// Manage Columns (and their data field name)
List<Map<String, Object>> columnsRaw=result.get("columns");
Map<String,String> dataHeaderMapping=new HashMap<String, String>();
for(Map<String,Object> column:columnsRaw){
String header=(String)column.get("title");
dataHeaderMapping.put(header, (String)column.get("data"));
headers.add(header);
}
headers.add("id");

// Sort the data columns
Collections.sort(headers, new Comparator<String>(){
public int compare(String o1, String o2){
if (!o1.equals(o2)){
return getHeaderOrder(o1)-getHeaderOrder(o2);
}
return 0;
}
});

// Normalize the data into a single map/row
// flatten the data from a Map of String->Object to String->String
List<Map<String,String>> data=new ArrayList<Map<String,String>>();
for(Map<String,Object> dataItem:dataRaw){
Map<String,String> entry=new HashMap<String, String>();
for(Entry<String, Object> die:dataItem.entrySet()){
entry.put(die.getKey(), String.valueOf(die.getValue()));
}
data.add(entry);
}

// Sort the data rows by Total Points
Collections.sort(data, new Comparator<Map<String,String>>(){
public int compare(Map<String, String> o1, Map<String, String> o2){
int i1=Integer.parseInt(o1.get("total"));
int i2=Integer.parseInt(o2.get("total"));
return i2-i1;
}
});


// export the data
File file=new File("export."+format.toLowerCase());
FileOutputStream fileOS=new FileOutputStream(file);
// Sort the data columns
Collections.sort(headers, new HeaderComparator(new String[]{"id","name","belt","total","points","github","gitlab","trello"}));

// Normalize the data into a single map/row
// flatten the data from a Map of String->Object to String->String
List<Map<String,String>> data=new ArrayList<Map<String,String>>();
for(Map<String,Object> dataItem:dataRaw){
Map<String,String> entry=new HashMap<String, String>();
for(Entry<String, Object> die:dataItem.entrySet()){
entry.put(die.getKey(), String.valueOf(die.getValue()));
}
data.add(entry);
}

// Sort the data rows by Total Points
Collections.sort(data, new Comparator<Map<String,String>>(){
public int compare(Map<String, String> o1, Map<String, String> o2){
return Integer.parseInt(o2.get("total"))-Integer.parseInt(o1.get("total"));
}
});

// export the data
return writeExportFile("Scorecards", format, headers, data, dataHeaderMapping);
}

private Response writeExportFile(String type, String format, List<String> headers, List<Map<String,String>> data, Map<String,String> dataHeaderMapping ){
File file=new File(type+"."+format.toLowerCase());
try{
switch(Format.valueOf(format)){
case json:
IOUtils.write(Json.newObjectMapper(true).writeValueAsString(data), fileOS);
IOUtils.closeQuietly(fileOS);
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
.build();
writeStringAndClose(Json.newObjectMapper(true).writeValueAsString(data), file);
break;

case csv:
StringBuffer sb=new StringBuffer();

for(String header:headers)
sb.append(header).append(",");
sb.append(header).append(",");
sb.append("\n");

for(Map<String,String> e:data){
for(String header:headers){
String headerName=columnFieldName.containsKey(header)?columnFieldName.get(header):header;
sb.append(e.containsKey(headerName)?e.get(headerName):"").append(",");
}
for(String header:headers){
String headerField=dataHeaderMapping.containsKey(header)?dataHeaderMapping.get(header):header;
sb.append(e.containsKey(headerField)?e.get(headerField):"").append(",");
}
sb.append("\n");
}
IOUtils.write(sb.toString(), fileOS);
IOUtils.closeQuietly(fileOS);
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
.build();

writeStringAndClose(sb.toString(), file);
break;

case xls:
HSSFWorkbook wb=new HSSFWorkbook();
HSSFSheet s=wb.createSheet("Scorecards");

HSSFRow row=s.createRow(0);
for(int i=0;i<headers.size();i++){
row.createCell(i, HSSFCell.CELL_TYPE_STRING).setCellValue(headers.get(i));
}

int rowCount=1;
for(Map<String,String> e:data){
row=s.createRow(rowCount);
for(int i=0;i<headers.size();i++){
String header=headers.get(i);
String headerName=columnFieldName.containsKey(header)?columnFieldName.get(header):header;
row.createCell(i, HSSFCell.CELL_TYPE_STRING).setCellValue(e.containsKey(headerName)?e.get(headerName):"");
}
rowCount=rowCount+1;
HSSFWorkbook wb=new HSSFWorkbook();
HSSFSheet s=wb.createSheet(type);

HSSFRow row=s.createRow(0);
for(int i=0;i<headers.size();i++){
row.createCell(i, HSSFCell.CELL_TYPE_STRING).setCellValue(headers.get(i));
}

wb.write(fileOS);
fileOS.flush();
fileOS.close();
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
.build();

int rowCount=1;
for(Map<String, String> e:data){
row=s.createRow(rowCount);
for(int i=0;i<headers.size();i++){
String header=headers.get(i);
String headerName=dataHeaderMapping.containsKey(header)?dataHeaderMapping.get(header):header;
row.createCell(i, HSSFCell.CELL_TYPE_STRING).setCellValue(e.containsKey(headerName)?e.get(headerName):"");
}
rowCount=rowCount+1;
}
}catch(Exception e){
e.printStackTrace();

FileOutputStream fileOS=new FileOutputStream(file);
wb.write(fileOS);
fileOS.flush();
fileOS.close();
break;
}
return Response.serverError().build();
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
.build();
}catch(Exception e){
e.printStackTrace();
}

return Response.serverError().build();
}


private File writeStringAndClose(String toWrite, File file) throws IOException{
FileOutputStream fileOS=new FileOutputStream(file);
IOUtils.write(toWrite, fileOS);
IOUtils.closeQuietly(fileOS);
return file;
}
}
22 changes: 12 additions & 10 deletions src/main/java/com/redhat/sso/ninja/ManagementController.java
Original file line number Diff line number Diff line change
Expand Up @@ -396,25 +396,27 @@ public Response saveScorecard(
return Response.status(200).entity(Json.newObjectMapper(true).writeValueAsString("OK")).build();
}


@GET
@Path("/events")
public Response getEvents(@Context HttpServletRequest request) throws JsonGenerationException, JsonMappingException, IOException{
return Response.status(200).entity(Json.newObjectMapper(true).writeValueAsString(getEvents(request.getParameter("user"), request.getParameter("event")))).build();
}
public List<Map<String, String>> getAllEvents() throws JsonGenerationException, JsonMappingException, IOException{
return getEvents(null, null);
}
public List<Map<String, String>> getEvents(String user, String event) throws JsonGenerationException, JsonMappingException, IOException{
Database2 db=Database2.get();
List<Map<String, String>> events=db.getEvents();
List<Map<String, String>> result=new ArrayList<Map<String,String>>();

if (1>=request.getParameterMap().size()){
result=events;
if (null==user && null==event){
result=db.getEvents();
}else{
for(Map<String, String> event:events){
if (event.get(EVENT_FIELDS.USER.v).equals(request.getParameter("user"))) result.add(event);
if (event.get(EVENT_FIELDS.TYPE.v).equals(request.getParameter("event"))) result.add(event);

for(Map<String, String> e:db.getEvents()){
if (e.get(EVENT_FIELDS.USER.v).equals(user)) result.add(e);
if (e.get(EVENT_FIELDS.TYPE.v).equals(event)) result.add(e);
}
}

return Response.status(200).entity(Json.newObjectMapper(true).writeValueAsString(result)).build();
return result;
}


Expand Down
37 changes: 37 additions & 0 deletions src/main/webapp/events.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ function loadDataTable(){
}}
]
} );
var btnExport=`
<div style="left:-20px;float:left;" class="dropdown export">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Export
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" href="api/events/export/csv">... as CSV</a><br/>
<a class="dropdown-item" href="api/events/export/xls">... as XLS</a><br/>
<a class="dropdown-item" href="api/events/export/json">... as JSON</a>
</div>
</div>
`;
document.getElementById("example_filter").innerHTML=btnExport+"&nbsp;"+document.getElementById("example_filter").innerHTML;
}
Expand All @@ -77,6 +92,28 @@ $(document).ready(function() {
<h2><span class="navbar-title-text">Events<span id="title-user"></span></span></h2>
</div>

<style>
table tr td:nth-child(1), table tr td:nth-child(2){
white-space: nowrap;
}
/*
table:nth-child(0), table:nth-child(1){
white-space: nowrap;
}
*/
.export button{
height: 26px;
padding: 0px;
padding-left: 11px;
padding-right: 12px;
}
.export div .dropdown-item{
padding-left: 10px;
}
</style>

<div id="solutions">
<div id="solutions-buttonbar">
</div>
Expand Down
Loading

0 comments on commit 476728e

Please sign in to comment.