package de.superx.bianalysis.rest; import java.io.ByteArrayOutputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import java.util.Base64; import java.util.Date; import org.apache.log4j.Logger; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import de.superx.bianalysis.ExcelSheetBuilder; import de.superx.bianalysis.ReportDefinition; import de.superx.bianalysis.StoredReport; import de.superx.bianalysis.jasper.JasperReportJsonWrapper; import de.superx.bianalysis.metadata.Identifier; import de.superx.bianalysis.models.Dimension; import de.superx.bianalysis.models.DimensionAttribute; import de.superx.bianalysis.models.FactTable; import de.superx.bianalysis.models.Measure; import de.superx.bianalysis.models.Right; import de.superx.bianalysis.repository.dto.MeasureDto; import de.superx.bianalysis.service.BiAnalysisManager; import de.superx.bianalysis.service.BiAnalysisRightService; import de.superx.bianalysis.service.DbMetaAdapter; import de.superx.bianalysis.service.JasperReportExport; import de.superx.common.NotYetImplementedException; import de.superx.rest.RestControllerBase; import de.superx.rest.model.Download; import de.superx.rest.model.Result; import de.superx.rest.model.ResultType; import de.superx.rest.model.Row; @RestController @RequestMapping("/api/bianalysis") public class BiAnalysisApi extends RestControllerBase { /* Autor: Robin Wübbeling * Achtung: Code ist schnell und unschön zusammengestellt, für einen ersten Entwurf * TODO: Filter * TODO: Berechnete Kennzahlen * TODO: Kennzahlenfilter momentan nur über 1 Dimensionsattribut möglich * TODO: Strings schöner durch "Platzhalter" * */ static Logger logger = Logger.getLogger(BiAnalysisApi.class); @Autowired DbMetaAdapter dbAdapter; @Autowired BiAnalysisRightService rightsService; @Autowired BiAnalysisManager biAnalysisManager; @Autowired JasperReportExport jasperReportExport; @Override protected Logger getLogger() { return logger; } @RequestMapping(method = RequestMethod.GET, path = "/facttables") public List listFactTables() throws NotYetImplementedException { List facts = dbAdapter.getFactTables(); return facts; } @RequestMapping(method = RequestMethod.GET, path = "/dimensions") public List listDimensions(@RequestParam(value = "facttable_id") String facttable_id) { return dbAdapter.getDimensionsWithoutHidden(new Identifier(facttable_id)); } // TODO: zeig in benamung does es sich vllt. um eine reduzierte liste handelt // granted vs allowed // umstellen auf camel case @RequestMapping(method = RequestMethod.GET, path = "/dimensionAttributeValues") public List listAttributeValues(@RequestParam(value = "attribute_id") List ids, @RequestParam(value = "facts") List facts) { List attributes = dbAdapter.getDimensionAttributeByIds(ids, facts); return dbAdapter.getDimensionAttributeValues(attributes, facts); } @RequestMapping(method = RequestMethod.GET, path = "/measures") public List listMeasures(@RequestParam(value = "facttable_id") String factId) { return dbAdapter.findMeasuresByFactTableId(new Identifier(factId)); } @RequestMapping(method = RequestMethod.GET, path = "/rolePlayingDimensions") public List listRolePlayingDimensions(@RequestParam(value = "primaryFactId") Identifier primaryFactId, @RequestParam(value = "secondaryFactId") Identifier secondaryFactId) { return dbAdapter.findRolePlayingDimensionsByFacttables(primaryFactId, secondaryFactId); } @RequestMapping(method = RequestMethod.GET, path = "/rolePlayingDimensionsForFacttable") public List listRolePlayingDimensions(@RequestParam(value = "factId") Identifier factId) { return this.dbAdapter.findConformedDimensionsWithAtLeastTwoOccurences(factId); } @RequestMapping(method = RequestMethod.GET, path = "/findReportDefinition") public List findReportDefinition( @RequestParam(value = "title") Optional title, @RequestParam(value = "sach") Optional sach, @RequestParam(value = "facts") Optional> facts) { rightsService.checkCreateOrViewRights(); return dbAdapter.findStoredReports(title, sach, facts); } @RequestMapping(method = RequestMethod.GET, path = "/getStoredReport") public StoredReport getStoredReport(@RequestParam(value = "id") int id) { Optional storedReportOpt = dbAdapter.findById(id); if(storedReportOpt.isPresent()) { StoredReport storedReport = storedReportOpt.get(); checkCreateOrViewRightForLeadingFactTable(storedReport.reportDefinition.factTableId); try { storedReport.exportedResult = biAnalysisManager.createResult(storedReport.reportDefinition, dbAdapter); } catch (Exception e) { logger.error("Couldn't create report", e); e.printStackTrace(); } storedReport.isReadOnly = Boolean.valueOf(!this.rightsService.isCreateRight()); return storedReport; } return null; } @RequestMapping(method = RequestMethod.POST, path = "/report") public Result getReport(@RequestBody final ReportDefinition reportDefinition) throws Exception { Identifier factTableId = reportDefinition.factTableId; checkCreateRightForLeadingFactTable(factTableId); return biAnalysisManager.createResult(reportDefinition, dbAdapter); } @RequestMapping(method = RequestMethod.POST, path = "/persistReportDefinition") public int persistReportDefinition(@RequestBody final StoredReport storedReport) throws Exception { StoredReport.setReportDefinitionJson(storedReport); Identifier factTableId = (Identifier) storedReport.reportDefinition.factTableId; checkCreateRightForLeadingFactTable(factTableId); return dbAdapter.saveReportDefinition(storedReport); } @RequestMapping(value = "/report/download", method = RequestMethod.POST) public Download getFile(@RequestBody final StoredReport storedReport) throws Exception { checkCreateOrViewRightForLeadingFactTable(storedReport.reportDefinition.factTableId); Date date = new Date(); String fileName = "BI-Analyse_"; if(storedReport.id != 0) { fileName += dbAdapter.findById(storedReport.id).get().name + "_"; if(fileName.length() > 206) { fileName = fileName.substring(0, 160); } fileName = fileName.replaceAll("[^a-zA-Z0-9äöüÄÖÜß_]+", "_"); } fileName += new SimpleDateFormat("yyyyMMdd_HHmmss").format(date); if(!storedReport.exportedResult.resultType.equals(ResultType.FlatTable)) { Row totalRow = storedReport.exportedResult.getTotalRow(); storedReport.exportedResult.rows = (BiAnalysisManager.hierarchyToRows(storedReport.hierarchy)); storedReport.exportedResult.rows.add(totalRow); } XSSFWorkbook workbook = new ExcelSheetBuilder(storedReport.exportedResult) .withFileName(fileName) .withReportName(storedReport.name) .withDescription(storedReport.description) .withDate(date) .build(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); workbook.write(bos); String base64String = Base64.getEncoder().encodeToString(bos.toByteArray()); String contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; return new Download(fileName, contentType, base64String); } @RequestMapping(method = RequestMethod.POST, path = "/deleteReportDefinition") public boolean deleteReportDefinition(@RequestBody final int id) throws Exception { try { Optional reportOpt = dbAdapter.findById(id); if(reportOpt.isEmpty()) { throw new Exception("FEHLER: Berichtskonfiguration konnte nicht gefunden werden."); } checkCreateRightForLeadingFactTable(reportOpt.get().reportDefinition.factTableId); rightsService.checkDeleteRights(); dbAdapter.deleteById(id); return true; } catch(Exception e) { throw new Exception("FEHLER: Berichtskonfiguration konnte nicht gelöscht werden.", e); } } @RequestMapping(method = RequestMethod.GET, path = "/reportDefinitions") public List listReportDefinitions() throws Exception { rightsService.checkCreateOrViewRights(); List storedReports = null; try { storedReports = dbAdapter.findAllStoredReports(); // TODO mit Marnie abklären, für überschreiben notwendig? } catch (Exception e) { e.printStackTrace(); if (e.getCause().getMessage().contains("FEHLER: Relation »metadata.rw_report_definitions« existiert nicht")) { throw new NotYetImplementedException("Bitte installieren Sie zuerst die Komponente 'BI-Analyse-Daten' und führen Sie anschließend den Konnektor aus."); } throw e; } return storedReports; } private void checkCreateOrViewRightForLeadingFactTable(Identifier factTableId) { int sachgebiet = dbAdapter.getSachgebietByFactTableId(factTableId.composedId); rightsService.checkSachgebiet(sachgebiet, Right.CREATE_ANALYSIS, Right.VIEW_REPORT); rightsService.checkFactTable(factTableId, Right.CREATE_ANALYSIS, Right.VIEW_REPORT); } private void checkCreateRightForLeadingFactTable(Identifier factTableId) { int sachgebiet = dbAdapter.getSachgebietByFactTableId(factTableId.composedId); rightsService.checkSachgebiet(sachgebiet, Right.CREATE_ANALYSIS); rightsService.checkFactTable(factTableId, Right.CREATE_ANALYSIS); } @RequestMapping(method = RequestMethod.GET, path = "/jasper/datasource") public JasperReportJsonWrapper getJasperJsonDatasource(@RequestParam(value = "stored_report_id") int storedReportId) throws Exception { StoredReport storedReport = getStoredReport(storedReportId); return jasperReportExport.getJasperReportJsonWrapper(storedReport); } @RequestMapping(method = RequestMethod.GET, path = "/jasper/template") public Download getJasperTemplate(@RequestParam(value = "stored_report_id") int storedReportId) throws Exception { StoredReport storedReport = getStoredReport(storedReportId); jasperReportExport.createJson(storedReport); jasperReportExport.createJasperReport(storedReport); Download export = jasperReportExport.createZip(); return export; } }