From 2609dd06b4f05a7dfcec1c8e8f3fe4705b48e0b5 Mon Sep 17 00:00:00 2001 From: Mat Allen Date: Wed, 29 Apr 2020 21:05:24 -0500 Subject: [PATCH] Cleanup (#66) * minor correction to event log text (it was logging the card long ID twice in some cases) * cleaning up unused code & commenting methods and where they're used ready for refactoring --- .../java/com/redhat/sso/ninja/Backup.java | 70 ----- .../redhat/sso/ninja/ChartsController.java | 22 +- .../redhat/sso/ninja/ChatNotification.java | 15 +- .../java/com/redhat/sso/ninja/Config.java | 44 +-- .../java/com/redhat/sso/ninja/Database2.java | 8 +- .../redhat/sso/ninja/ExportController.java | 21 +- .../com/redhat/sso/ninja/GoogleDrive2.java | 192 ------------ .../com/redhat/sso/ninja/GoogleDrive3.java | 53 ++-- .../java/com/redhat/sso/ninja/Heartbeat2.java | 123 +++----- .../com/redhat/sso/ninja/InitServlet.java | 5 - .../sso/ninja/ManagementController.java | 195 ++++++------ .../com/redhat/sso/ninja/PointsAdder.java | 8 - .../java/com/redhat/sso/ninja/ScriptBase.java | 17 -- .../redhat/sso/ninja/SupportController.java | 54 ++-- .../com/redhat/sso/ninja/TasksController.java | 7 +- .../java/com/redhat/sso/ninja/TrelloSync.java | 255 ---------------- .../com/redhat/sso/ninja/UserController.java | 41 --- .../redhat/sso/ninja/chart/Chart2Json.java | 32 -- .../com/redhat/sso/ninja/chart/ChartJson.java | 8 +- ...Chart2LineJson.java => ChartLineJson.java} | 8 +- .../com/redhat/sso/ninja/chart/DataSet.java | 84 +++--- .../com/redhat/sso/ninja/chart/DataSet2.java | 63 ---- .../{DataSetLine2.java => DataSetLine.java} | 2 +- src/main/resources/calculatePoints.groovy | 11 - src/main/resources/config.json | 5 + src/main/resources/scripts/github-stats.py | 279 ------------------ src/main/resources/scripts/github-test.sh | 1 - src/main/resources/scripts/github-test.txt | 153 ---------- src/main/resources/scripts/rocketchat.py | 227 -------------- src/main/resources/scripts/trello-stats.py | 171 ----------- src/main/resources/scripts/trello-test.sh | 1 - src/main/resources/scripts/trello-test.txt | 24 -- src/main/webapp/WEB-INF/web.xml | 2 +- src/main/webapp/login.jsp | 1 - .../webapp/{ => mojo}/mojo-dashboard-card.jsp | 4 +- .../webapp/{ => mojo}/mojo-miniBeltWidget.jsp | 0 src/main/webapp/{ => mojo}/mojo-ninjaWall.jsp | 0 .../{ => mojo}/mojo-raceToBlack-graph.jsp | 0 .../mojo-raceToBlack-horizontal.jsp | 0 .../{ => mojo}/mojo-raceToBlack-vertical.jsp | 0 src/main/webapp/{ => mojo}/mojo-top10.jsp | 0 src/main/webapp/{ => mojo}/mojo.jsp | 0 42 files changed, 298 insertions(+), 1908 deletions(-) delete mode 100644 src/main/java/com/redhat/sso/ninja/Backup.java delete mode 100644 src/main/java/com/redhat/sso/ninja/GoogleDrive2.java delete mode 100644 src/main/java/com/redhat/sso/ninja/PointsAdder.java delete mode 100644 src/main/java/com/redhat/sso/ninja/ScriptBase.java delete mode 100644 src/main/java/com/redhat/sso/ninja/TrelloSync.java delete mode 100644 src/main/java/com/redhat/sso/ninja/UserController.java delete mode 100644 src/main/java/com/redhat/sso/ninja/chart/Chart2Json.java rename src/main/java/com/redhat/sso/ninja/chart/{Chart2LineJson.java => ChartLineJson.java} (66%) delete mode 100644 src/main/java/com/redhat/sso/ninja/chart/DataSet2.java rename src/main/java/com/redhat/sso/ninja/chart/{DataSetLine2.java => DataSetLine.java} (98%) delete mode 100644 src/main/resources/calculatePoints.groovy delete mode 100755 src/main/resources/scripts/github-stats.py delete mode 100755 src/main/resources/scripts/github-test.sh delete mode 100644 src/main/resources/scripts/github-test.txt delete mode 100755 src/main/resources/scripts/rocketchat.py delete mode 100755 src/main/resources/scripts/trello-stats.py delete mode 100755 src/main/resources/scripts/trello-test.sh delete mode 100644 src/main/resources/scripts/trello-test.txt rename src/main/webapp/{ => mojo}/mojo-dashboard-card.jsp (98%) rename src/main/webapp/{ => mojo}/mojo-miniBeltWidget.jsp (100%) rename src/main/webapp/{ => mojo}/mojo-ninjaWall.jsp (100%) rename src/main/webapp/{ => mojo}/mojo-raceToBlack-graph.jsp (100%) rename src/main/webapp/{ => mojo}/mojo-raceToBlack-horizontal.jsp (100%) rename src/main/webapp/{ => mojo}/mojo-raceToBlack-vertical.jsp (100%) rename src/main/webapp/{ => mojo}/mojo-top10.jsp (100%) rename src/main/webapp/{ => mojo}/mojo.jsp (100%) diff --git a/src/main/java/com/redhat/sso/ninja/Backup.java b/src/main/java/com/redhat/sso/ninja/Backup.java deleted file mode 100644 index d0b48ee9..00000000 --- a/src/main/java/com/redhat/sso/ninja/Backup.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.redhat.sso.ninja; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Timer; -import java.util.TimerTask; - -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; -import org.apache.log4j.Logger; - -public class Backup { - private static final Logger log = Logger.getLogger(Backup.class); - private static Timer t; - - public static void main(String[] asd){ - try{ - Backup.runOnce(); - }catch(Exception e){ - e.printStackTrace(); - } - } - - public static void runOnce(){ - new BackupRunnable(new String[]{Database2.STORAGE_AS_FILE.getAbsolutePath()}).run(); - } - - public static void start(long intervalInMs, String... paths) { - t = new Timer(Backup.class.getSimpleName()+"-timer", false); - t.scheduleAtFixedRate(new BackupRunnable(paths), 180000l, intervalInMs); - } - - public static void stop() { - t.cancel(); - } - - static class BackupRunnable extends TimerTask { -// static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); - static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); - private String[] paths; - - public BackupRunnable(String[] paths){ - this.paths=paths; - } - - @Override - public void run() { - log.info(Backup.class.getSimpleName()+ " fired"); - - for(String path:paths){ - File source=new File(path); - String newName=FilenameUtils.getBaseName(source.getName())+"-"+sdf.format(new Date())+"."+FilenameUtils.getExtension(source.getName()); - File newFile=new File(source.getParentFile(), newName); - - try{ - System.out.println("Copying from ["+source.getAbsolutePath()+"] to ["+newFile.getAbsolutePath()+"]"); - IOUtils.copy(new FileInputStream(source), new FileOutputStream(newFile)); - }catch(Exception e){ - e.printStackTrace(); - } - - } - - } - } - -} diff --git a/src/main/java/com/redhat/sso/ninja/ChartsController.java b/src/main/java/com/redhat/sso/ninja/ChartsController.java index ff9370a9..95709c76 100644 --- a/src/main/java/com/redhat/sso/ninja/ChartsController.java +++ b/src/main/java/com/redhat/sso/ninja/ChartsController.java @@ -24,8 +24,8 @@ import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.gdata.util.common.base.Pair; -import com.redhat.sso.ninja.chart.Chart2Json; -import com.redhat.sso.ninja.chart.DataSet2; +import com.redhat.sso.ninja.chart.ChartJson; +import com.redhat.sso.ninja.chart.DataSet; import com.redhat.sso.ninja.utils.Json; import com.redhat.sso.ninja.utils.LevelsUtil; import com.redhat.sso.ninja.utils.MapBuilder; @@ -33,6 +33,8 @@ @Path("/") public class ChartsController{ + + // Mojo UI: https://mojo.redhat.com/community/communities-at-red-hat/communities-of-practice-operations/giveback-ninja-program/ninja-wall/overview @GET @Path("/ninjas") public Response getNinjas() throws JsonGenerationException, JsonMappingException, IOException{ @@ -45,6 +47,7 @@ public Response getNinjas() throws JsonGenerationException, JsonMappingException .build(); } + // Mojo UI: "race to black belt" here: https://mojo.redhat.com/community/communities-at-red-hat/communities-of-practice-operations/giveback-ninja-program @GET @Path("/leaderboard/{max}") public Response getLeaderboard2(@PathParam("max") Integer max) throws JsonGenerationException, JsonMappingException, IOException{ @@ -64,7 +67,7 @@ static Integer total(Map points){ } return t; } - public Chart2Json getParticipants(Integer max) throws JsonGenerationException, JsonMappingException, IOException{ + public ChartJson getParticipants(Integer max) throws JsonGenerationException, JsonMappingException, IOException{ Database2 db=Database2.get(); Map> leaderboard=db.getLeaderboard(); Map totals=new HashMap(); @@ -89,8 +92,8 @@ public Chart2Json getParticipants(Integer max) throws JsonGenerationException, J sortedTotals.put(e.getKey(), e.getValue()); // Build Chart data structure - Chart2Json c=new Chart2Json(); - c.setDatasets(new ArrayList()); + ChartJson c=new ChartJson(); + c.setDatasets(new ArrayList()); int count=0; for(Entry e:sortedTotals.entrySet()){ Map userInfo=db.getUsers().get(e.getKey()); @@ -115,7 +118,7 @@ public Chart2Json getParticipants(Integer max) throws JsonGenerationException, J } c.getCustom2().add(Joiner.on(",").join(pastYearBadges)); - if (c.getDatasets().size()<=0) c.getDatasets().add(new DataSet2()); + if (c.getDatasets().size()<=0) c.getDatasets().add(new DataSet()); c.getDatasets().get(0).getData().add(e.getValue()); c.getDatasets().get(0).setBorderWidth(1); @@ -132,13 +135,14 @@ public Chart2Json getParticipants(Integer max) throws JsonGenerationException, J c.getDatasets().get(0).getBorderColor().add(colors.get(userInfo.get("level").toUpperCase()).getSecond()); count=count+1; - if (null!=max && count>=max) break; // hard maximum suppled as param + if (null!=max && count>=max) break; // hard maximum supplied as param } return c; } // UI call (user dashboard) - returns the payload to render a chart displaying the current points and points to the next level + // here: https://mojo.redhat.com/community/communities-at-red-hat/communities-of-practice-operations/giveback-ninja-program/dashboard/overview @GET @Path("/scorecard/nextlevel/{user}") public Response getUserNextLevel(@PathParam("user") String user) throws JsonGenerationException, JsonMappingException, IOException{ @@ -146,10 +150,10 @@ public Response getUserNextLevel(@PathParam("user") String user) throws JsonGene Database2 db=Database2.get(); boolean userExists=db.getScoreCards().containsKey(user); - Chart2Json chart=new Chart2Json(); + ChartJson chart=new ChartJson(); chart.getLabels().add("Earned"); chart.getLabels().add("To Next Level"); - chart.getDatasets().add(new DataSet2()); + chart.getDatasets().add(new DataSet()); chart.getDatasets().get(0).setBorderWidth(1); if (userExists){ diff --git a/src/main/java/com/redhat/sso/ninja/ChatNotification.java b/src/main/java/com/redhat/sso/ninja/ChatNotification.java index 1958a211..aabc2ed5 100644 --- a/src/main/java/com/redhat/sso/ninja/ChatNotification.java +++ b/src/main/java/com/redhat/sso/ninja/ChatNotification.java @@ -8,14 +8,17 @@ import com.redhat.sso.ninja.utils.Http.Response; import com.redhat.sso.ninja.utils.MapBuilder; +/** + * Integration with google chat boards, to push notifications of events such as user promotions, script failures etc.. + * @author mallen + */ public class ChatNotification{ public enum ChatEvent{onRegistration,onBeltPromotion,onScriptError} - public static void main(String[] asd){ - Config c=Config.get(); - System.out.println("googlehangoutschat.webhook.template="+c.getOptions().get("googlehangoutschat.webhook.template")); - - new ChatNotification().send(ChatEvent.onRegistration, " promoted to BLUE belt"); - } +// public static void main(String[] asd){ +// Config c=Config.get(); +// System.out.println("googlehangoutschat.webhook.template="+c.getOptions().get("googlehangoutschat.webhook.template")); +// new ChatNotification().send(ChatEvent.onRegistration, " promoted to BLUE belt"); +// } public void send(ChatEvent type, String notificationText){ Config c=Config.get(); diff --git a/src/main/java/com/redhat/sso/ninja/Config.java b/src/main/java/com/redhat/sso/ninja/Config.java index 298f6a16..d072cb6e 100644 --- a/src/main/java/com/redhat/sso/ninja/Config.java +++ b/src/main/java/com/redhat/sso/ninja/Config.java @@ -56,15 +56,6 @@ public Config(String json){ } } - // Config options to be able to configure - // - cycle/zero points every X weeks (or would you want a rolling total?) - // - multiple pools per user - // - each pool much have a configurable way of pulling the info (groovy?) - // - each pool points must have a configurable way of calculating the multiple pool values into a consolidated perception of score - // - Heartbeat to pull data from last time it was run - must be persistent and survive server restarts - - - public Map getOptions() {if (options==null) options=new HashMap(); return options;} public List> getScripts() {if (scripts==null) scripts=new ArrayList>(); return scripts;} @@ -106,37 +97,10 @@ public static Config get(){ if (!Config.STORAGE.getParentFile().exists()) Config.STORAGE.getParentFile().mkdirs(); // copy the default config over IOUtils.copy(Config.class.getClassLoader().getResourceAsStream(STORAGE.getName()), new FileOutputStream(STORAGE)); - } -// instance=new Config(); -// }else{ - log.info("Config loading (location="+Config.STORAGE.getAbsolutePath()+", size="+Config.STORAGE.length()+")"); - String toLoad=IOUtils2.toStringAndClose(new FileInputStream(Config.STORAGE)); - instance=Json.newObjectMapper(true).readValue(new ByteArrayInputStream(toLoad.getBytes()), Config.class); -// } -// UserController uc=new UserController(); -// GoogleAddressResolution gar=new CachedGoogleAddressResolution(false); -// boolean changed=false; -// for(Architect a:instance.getArchitects().values()){ -// if (a.getHome()==null || a.getHome().length()<=0){ -// changed=true; -// List userList=uc.search("uid", a.getUid()); -// if (userList.size()!=1) continue; // uncertain? dont do anything -// User user=userList.get(0); -// a.setName(user.getName()); -// String country=instance.countryCodeToName.get(user.getCountry()); -// if (country==null){ -// System.err.println("Unknown country code ["+user.getCountry()+"]"); -// continue; -// } -// Map formattedAddress=gar.getFormattedAddress(country); -// a.setHome(formattedAddress.get("longitude")+","+formattedAddress.get("latitude")); -// } -// } -// if (changed){ -// String str=Json.newObjectMapper(false).writeValueAsString(instance); -// IOUtils2.writeAndClose(str.getBytes(), new FileOutputStream(new File("config2.json"))); -// } + log.info("Config loading (location="+Config.STORAGE.getAbsolutePath()+", size="+Config.STORAGE.length()+")"); + String toLoad=IOUtils2.toStringAndClose(new FileInputStream(Config.STORAGE)); + instance=Json.newObjectMapper(true).readValue(new ByteArrayInputStream(toLoad.getBytes()), Config.class); }catch(Exception e){ e.printStackTrace(); @@ -152,8 +116,6 @@ public void setOptions(Map value) { @JsonIgnore public String getNextTaskNum(){ -// Config cfg=Config.get(); - if (!getValues().containsKey("lastTaskNum")){ getValues().put("lastTaskNum", 0); } diff --git a/src/main/java/com/redhat/sso/ninja/Database2.java b/src/main/java/com/redhat/sso/ninja/Database2.java index ad3bd55a..42af11a2 100644 --- a/src/main/java/com/redhat/sso/ninja/Database2.java +++ b/src/main/java/com/redhat/sso/ninja/Database2.java @@ -59,9 +59,9 @@ public static String buildLink(Map params){ return "([Trello card: "+params.get("linkId")+"|https://trello.com/c/"+params.get("linkId")+"] / "+params.get("id")+")"; }else if (params.get("id").startsWith("GH")){ if (params.get("pool").toLowerCase().contains("pull")){ - return "([Github card: "+params.get("linkId")+"|https://github.com/"+params.get("org")+"/"+params.get("board")+"/pull/"+params.get("linkId")+"])"; + return "([Github card: "+params.get("linkId")+"|https://github.com/"+params.get("org")+"/"+params.get("board")+"/pull/"+params.get("linkId")+"] / "+params.get("id")+")"; }else{ // assume "issues" - return "([Github card: "+params.get("linkId")+"|https://github.com/"+params.get("org")+"/"+params.get("board")+"/issues/"+params.get("linkId")+"])"; + return "([Github card: "+params.get("linkId")+"|https://github.com/"+params.get("org")+"/"+params.get("board")+"/issues/"+params.get("linkId")+"] / "+params.get("id")+")"; } //}else if (params.get("id").startsWith("GL")){ // return "([Gitlab card: "+params.get("linkId")+"|"+params.get("linkId")+"])"; @@ -91,10 +91,10 @@ public Database2 increment(String poolId, String userId, Integer increment, Map< scorecards.get(userId).put(poolId, scorecards.get(userId).get(poolId)+increment); if (params!=null && params.size()>1){ //because "id" is always added - addEvent("Points Increment", userId, increment+" point"+(increment<=1?"":"s")+" added to "+poolId+"("+params.get("id")+") "+buildLink(params)); + addEvent("Points Increment", userId, increment+" point"+(increment<=1?"":"s")+" added to "+poolId+" "+buildLink(params)); }else{ // no params & therefore no link - addEvent("Points Increment", userId, increment+" point"+(increment<=1?"":"s")+" added to "+poolId+"("+params.get("id")+")"); + addEvent("Points Increment", userId, increment+" point"+(increment<=1?"":"s")+" added to "+poolId+""); } }else{ diff --git a/src/main/java/com/redhat/sso/ninja/ExportController.java b/src/main/java/com/redhat/sso/ninja/ExportController.java index 7182b2b6..059723c0 100644 --- a/src/main/java/com/redhat/sso/ninja/ExportController.java +++ b/src/main/java/com/redhat/sso/ninja/ExportController.java @@ -34,19 +34,23 @@ import com.redhat.sso.ninja.utils.Json; import com.redhat.sso.ninja.utils.MapBuilder; +/** + * Rest controller that exposes methods to export data from the system (events, scorecards etc..) in various formats (csv, json etc...) + * @author mallen + */ + @Path("/") public class ExportController{ - 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() - ); - } +// 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{ @@ -69,10 +73,10 @@ public int getOrder(String hdr){ } + // Admin UI: Used to export the list of events for support purposes @GET @Path("/events/export/{format}") public Response exportEvents(@Context HttpServletRequest request, @PathParam("format") String format) throws IOException{ - List> data=new ManagementController().getAllEvents(); Set headerset=new HashSet(); @@ -91,6 +95,7 @@ public Response exportEvents(@Context HttpServletRequest request, @PathParam("fo } + // Admin UI: Used to export the list of user/scorecards support or reporting purposes @GET @Path("/scorecards/export/{format}") public Response exportScorecards(@Context HttpServletRequest request, @PathParam("format") String format) throws IOException{ diff --git a/src/main/java/com/redhat/sso/ninja/GoogleDrive2.java b/src/main/java/com/redhat/sso/ninja/GoogleDrive2.java deleted file mode 100644 index 3b44a316..00000000 --- a/src/main/java/com/redhat/sso/ninja/GoogleDrive2.java +++ /dev/null @@ -1,192 +0,0 @@ -package com.redhat.sso.ninja; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.attribute.PosixFilePermission; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.io.IOUtils; -import org.apache.log4j.Logger; -import org.apache.poi.xssf.usermodel.XSSFCell; -import org.apache.poi.xssf.usermodel.XSSFRow; -import org.apache.poi.xssf.usermodel.XSSFSheet; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; - -import com.redhat.sso.ninja.utils.DownloadFile; - -public class GoogleDrive2 { - private static Logger log=Logger.getLogger(GoogleDrive2.class); - - public static final String DEFAULT_EXECUTABLE="/home/%s/drive_linux"; -// public static final String DEFAULT_PULL_COMMAND=DEFAULT_EXECUTABLE+" pull -export xls -quiet=true --id %s"; //worked with 0.3.1 - public static final String DEFAULT_PULL_COMMAND=DEFAULT_EXECUTABLE+" pull -export xls -no-prompt --id %s"; // 0.3.7+ changed its output that we parse - public static final String DEFAULT_WORKING_FOLDER="/home/%s/google_drive"; - - private String googleSheetPullCommand; - private String googleSheetWorkingFolder; - - public static String getDefaultExecutable(){ - return String.format(DEFAULT_EXECUTABLE, System.getProperty("user.name")); - } - public static String getDefaultWorkingFolder(){ - return String.format(DEFAULT_WORKING_FOLDER, System.getProperty("user.name")); - } - - public GoogleDrive2(){ - this.googleSheetPullCommand=DEFAULT_PULL_COMMAND; - this.googleSheetWorkingFolder=DEFAULT_WORKING_FOLDER; - } - public GoogleDrive2(String googleSheetPullCommand, String googleSheetWorkingFolder){ - this.googleSheetPullCommand=googleSheetPullCommand; - this.googleSheetWorkingFolder=googleSheetWorkingFolder; - } - - public File downloadFile(String fileId) throws IOException, InterruptedException { - String command = String.format(googleSheetPullCommand, System.getProperty("user.name"), fileId); - - String googleDrivePath=String.format(googleSheetWorkingFolder, System.getProperty("user.name")); - File workingFolder=new File(googleDrivePath); - workingFolder.mkdirs(); // just in case it's not there - System.out.println("Using working folder: "+workingFolder.getAbsolutePath()); - System.out.println("Downloading google file: "+fileId); - System.out.println("Command: "+command); - - if (googleDrivePath.contains("google")){ - recursivelyDelete(workingFolder); - }else - System.out.println("Not cleaning working folder unless it contains the name 'google' - for safety reasons"); - - Process exec = Runtime.getRuntime().exec(command, null, workingFolder); - - exec.waitFor(); - String syserr = IOUtils.toString(exec.getErrorStream()); - String sysout = IOUtils.toString(exec.getInputStream()); - System.out.println("sysout=\""+sysout+"\"; syserr=\""+syserr+"\""); - if (!sysout.contains("Resolving...") && !sysout.contains("Everything is up-to-date")) - throw new RuntimeException("Error running google drive script: " + sysout); - if (!sysout.contains("Everything is up-to-date")) { - // System.out.println("Do Nothing"); - // return null; - // } else { - Pattern p = Pattern.compile("to '(.+)'$"); - Matcher matcher = p.matcher(sysout); - if (matcher.find()){ - String preFilePath = matcher.group(1); - // System.out.println("Process the file: " + preFilePath); - return new File(preFilePath); - } - } - return null; - // System.out.println(exec.exitValue()); - } - - public int getHeaderRow(){ - return 0; - } - - public boolean valid(Map entry){ - return true; - } - - public List> parseExcelDocument(File file) throws FileNotFoundException, IOException{ - SimpleDateFormat sdf=new SimpleDateFormat("MM/dd/yyyy HH:mm:ss"); - - // parse excel file using apache poi - // read out "tasks" and create/update solutions - // use timestamp (column A) as the unique identifier (if in doubt i'll hash it with the requester's username) - List> entries=new ArrayList>(); - FileInputStream in=null; - if (file==null || !file.exists()) return new ArrayList>(); - try{ - in=new FileInputStream(file); - XSSFWorkbook wb=new XSSFWorkbook(in); - XSSFSheet s=wb.getSheetAt(0); - int maxColumns=20; - - for(int iRow=getHeaderRow()+1;iRow<=s.getLastRowNum();iRow++){ - Map e=new HashMap(); - for(int iColumn=0;iColumn<=maxColumns;iColumn++){ - if (s.getRow(getHeaderRow()).getCell(iColumn)==null) continue; - String header=s.getRow(getHeaderRow()).getCell(iColumn).getStringCellValue(); - XSSFRow row = s.getRow(iRow); - if (row==null) break; // next line/row - XSSFCell cell=row.getCell(iColumn); - if (cell==null) continue; // try next cell/column - - try{ - e.put(header, cell.getStringCellValue()); - }catch(Exception ex){} - if (!e.containsKey(header)) - try{ - e.put(header, sdf.format(cell.getDateCellValue())); - }catch(Exception ex){} - - } - - if (valid(e)){ - e.put("ROW_#", String.valueOf(iRow)); - entries.add(e); - } - } - }finally{ - IOUtils.closeQuietly(in); - } - return entries; - } - - private void recursivelyDelete(File file){ - for(File f:file.listFiles()){ - if (!f.getName().startsWith(".") && f.isDirectory()) - recursivelyDelete(f); - if (!f.getName().startsWith(".")) - f.delete(); - } - } - - public static void initialise(){ //ie. download gdrive executable if necessary - if (!new File(GoogleDrive2.getDefaultExecutable()).exists()){ - // attempt to download it - File credsFile=new File(new File(GoogleDrive2.getDefaultWorkingFolder(), ".gd"), "credentials.json"); - try{ - String url="https://github.com/odeke-em/drive/releases/download/v0.3.9/drive_linux"; - - log.info("Downloading gdrive from: "+url); - new DownloadFile().get(url, new File(GoogleDrive2.getDefaultExecutable()).getParentFile(), PosixFilePermission.OTHERS_EXECUTE); - - credsFile.getParentFile().mkdirs(); - log.info("Deploying credentials.json in: "+credsFile); - - InputStream is=GoogleDrive2.class.getClassLoader().getResourceAsStream("/gd_credentials.json"); - if (null!=is){ - log.info("... from internal classloader path of '/gd_credentials.json'"); - IOUtils.copy(is, new FileOutputStream(credsFile)); - }else if (null!=System.getenv("GD_CREDENTIALS")){ - log.info("... from env variable 'GD_CREDENTIALS'"); - IOUtils.write(System.getenv("GD_CREDENTIALS").getBytes(), new FileOutputStream(credsFile)); - }else{ - log.error("no gdrive creds specified in either resources, or system props"); - } - log.info("drive credentials file contains: "+IOUtils.toString(new FileInputStream(credsFile))); - - }catch(Exception e){ - System.out.println("Failed to initialise gdrive and/or credentials, cleaning up exe and creds"); - credsFile.delete(); - new File(GoogleDrive2.getDefaultExecutable()).delete(); - e.printStackTrace(); - } - }else{ - log.info("gdrive already initialised. Existing binary is here: "+GoogleDrive2.getDefaultExecutable()); - } - } - -} diff --git a/src/main/java/com/redhat/sso/ninja/GoogleDrive3.java b/src/main/java/com/redhat/sso/ninja/GoogleDrive3.java index 83297c74..f4bed44d 100644 --- a/src/main/java/com/redhat/sso/ninja/GoogleDrive3.java +++ b/src/main/java/com/redhat/sso/ninja/GoogleDrive3.java @@ -38,7 +38,10 @@ import com.redhat.sso.ninja.utils.Json; import com.redhat.sso.ninja.utils.RegExHelper; - +/** + * Provides an API to download and parse (spreadsheets) from google drive, and manages the command line tools that provide this functionality (https://github.com/gdrive-org/gdrive) + * @author mallen + */ public class GoogleDrive3 { private static Logger log=Logger.getLogger(GoogleDrive3.class); @@ -62,38 +65,33 @@ public GoogleDrive3(long cacheExpiryInMs){ this.cacheExpiryInMs=cacheExpiryInMs; } -// private SimpleDateFormat dateFormatter; -// public void setDateFormatter(SimpleDateFormat dateFormatter){ -// this.dateFormatter=dateFormatter; -// } - interface HeaderRowFinder{ public int getHeaderRow(XSSFSheet s); } enum DriverType{drive,gdrive} - public static void main(String[] args) throws Exception{ - String PortfolioDatabase="1aPR0_uNRJCVLT9c8mqfEpNvQ2FZBdcD9pL0u6mksu2U"; - String FeedbackResponsesTeamDrive="1cyVtpYUMW26JBoqbVJJTD79ay--6F7EMAllEVKesn1Q"; - - - // Test using odeke's drive (no team drive capability) -// GoogleDrive3.initialise("/home/%s/drive_linux_odeke", DriverType.drive, "v0.3.9"); - - // Test using gdrive (with team drive capability) - GoogleDrive3.initialise("/home/%s/google_drive", DriverType.gdrive, "v2.1.1PreRelease"); - - GoogleDrive3 gd=new GoogleDrive3(); - File file=gd.downloadFile(FeedbackResponsesTeamDrive); - System.out.println("file exists="+(file!=null?file.exists():"Nope!")); - List> test=gd.parseExcelDocument(file, new HeaderRowFinder(){ - public int getHeaderRow(XSSFSheet s){ - return 0; - } - }, new SimpleDateFormat("dd-MM-yyyy")); - System.out.println(test); - } +// public static void main(String[] args) throws Exception{ +// String PortfolioDatabase="1aPR0_uNRJCVLT9c8mqfEpNvQ2FZBdcD9pL0u6mksu2U"; +// String FeedbackResponsesTeamDrive="1cyVtpYUMW26JBoqbVJJTD79ay--6F7EMAllEVKesn1Q"; +// +// +// // Test using odeke's drive (no team drive capability) +//// GoogleDrive3.initialise("/home/%s/drive_linux_odeke", DriverType.drive, "v0.3.9"); +// +// // Test using gdrive (with team drive capability) +// GoogleDrive3.initialise("/home/%s/google_drive", DriverType.gdrive, "v2.1.1PreRelease"); +// +// GoogleDrive3 gd=new GoogleDrive3(); +// File file=gd.downloadFile(FeedbackResponsesTeamDrive); +// System.out.println("file exists="+(file!=null?file.exists():"Nope!")); +// List> test=gd.parseExcelDocument(file, new HeaderRowFinder(){ +// public int getHeaderRow(XSSFSheet s){ +// return 0; +// } +// }, new SimpleDateFormat("dd-MM-yyyy")); +// System.out.println(test); +// } public static void initialise(String workingFolder, DriverType type, String version) { try{ @@ -235,7 +233,6 @@ public synchronized File downloadFile(String fileId) throws IOException, Interru return null; - // System.out.println(exec.exitValue()); } private static String getOS(){ diff --git a/src/main/java/com/redhat/sso/ninja/Heartbeat2.java b/src/main/java/com/redhat/sso/ninja/Heartbeat2.java index f75cf6c8..99b17713 100644 --- a/src/main/java/com/redhat/sso/ninja/Heartbeat2.java +++ b/src/main/java/com/redhat/sso/ninja/Heartbeat2.java @@ -52,39 +52,38 @@ public class Heartbeat2 { private static final Logger log = Logger.getLogger(Heartbeat2.class); private static Timer t; private static Timer tRunOnce; -// private static final long delay=30000l; - public static void main(String[] asd){ - try{ -// Heartbeat2.runOnceAsync(); - - Database2 db=Database2.get(new File("target/database-test1.json")); - String testScript="=== Statistics for GitHub Organization 'redhat-cop' ====\n" + - "\n" + - "== General PR's ==\n" + - "\n" + - "== Reviewed PR's ==\n" + - "\n" + - "Reviewed Pull Requests/GH1234567/fredbloggs/1 [org=redhat-cop, board=testing, linkId=1234]\n" + - "\n" + - "== Closed Issues ==\n" + - "Closed Issues/GH392748392/someoneelse/1 [org=redhat-cop, board=cert-utils-operator, linkId=35]\n"+ - ""; - Map script=new MapBuilder() - .put("name", "Github") - .put("source", "https://raw.githubusercontent.com/redhat-cop/ninja-points/v1.5/trello-stats.py -s ${LAST_RUN:yyyy-MM-dd} -o redhatcop") - .put("type", "python") - .build(); - File scriptFolder=new File("target/test"); - HeartbeatRunnable hbr=new HeartbeatRunnable(null); - Map poolToUserIdMapper=hbr.getUsersByPool(db, ((String)script.get("name")).split("\\.")[0].toLowerCase()+"Id");; - hbr.allocatePoints(db, (InputStream)new ByteArrayInputStream(testScript.getBytes()), script, scriptFolder, poolToUserIdMapper); - -// new HeartbeatRunnable().levelUpChecks(Database2.get()); - }catch(Exception e){ - e.printStackTrace(); - } - } +// public static void main(String[] asd){ +// try{ +//// Heartbeat2.runOnceAsync(); +// +// Database2 db=Database2.get(new File("target/database-test1.json")); +// String testScript="=== Statistics for GitHub Organization 'redhat-cop' ====\n" + +// "\n" + +// "== General PR's ==\n" + +// "\n" + +// "== Reviewed PR's ==\n" + +// "\n" + +// "Reviewed Pull Requests/GH1234567/fredbloggs/1 [org=redhat-cop, board=testing, linkId=1234]\n" + +// "\n" + +// "== Closed Issues ==\n" + +// "Closed Issues/GH392748392/someoneelse/1 [org=redhat-cop, board=cert-utils-operator, linkId=35]\n"+ +// ""; +// Map script=new MapBuilder() +// .put("name", "Github") +// .put("source", "https://raw.githubusercontent.com/redhat-cop/ninja-points/v1.5/trello-stats.py -s ${LAST_RUN:yyyy-MM-dd} -o redhatcop") +// .put("type", "python") +// .build(); +// File scriptFolder=new File("target/test"); +// HeartbeatRunnable hbr=new HeartbeatRunnable(null); +// Map poolToUserIdMapper=hbr.getUsersByPool(db, ((String)script.get("name")).split("\\.")[0].toLowerCase()+"Id");; +// hbr.allocatePoints(db, (InputStream)new ByteArrayInputStream(testScript.getBytes()), script, scriptFolder, poolToUserIdMapper); +// +//// new HeartbeatRunnable().levelUpChecks(Database2.get()); +// }catch(Exception e){ +// e.printStackTrace(); +// } +// } public static String convertLastRun(String command, Date lastRunDate) throws ParseException { Matcher m=Pattern.compile("(\\$\\{([^}]+)\\})").matcher(command); @@ -210,7 +209,6 @@ public HeartbeatRunnable(Timer t){ } public Map getUsersByPool(Database2 db, String key){ -// System.out.println("getting pool by id: "+key); Map result=new HashMap(); for(Entry> e:db.getUsers().entrySet()){ // support a default of your key id when no pool id is found @@ -270,24 +268,18 @@ public int getHeaderRow(XSSFSheet s){ return result; } -// public void getUsersFromRegistrationSheet(Config cfg){ -//// public Map> getUsersFromRegistrationSheet(Config cfg) throws IOException, InterruptedException{ -// } - public boolean addOrUpdateRegisteredUsers(Database2 db, Config cfg){ Map> dbUsers=db.getUsers(); UserService userService=new UserService(); boolean userServiceDown=false; try{ -// GoogleDrive2 drive=new GoogleDrive2(); GoogleDrive3 drive=new GoogleDrive3(); File file=drive.downloadFile(cfg.getOptions().get("googlesheets.registration.id")); List> rows=drive.parseExcelDocument(file, new GoogleDrive3.HeaderRowFinder(){ public int getHeaderRow(XSSFSheet s){ return 0; }}, new SimpleDateFormat("yyyy/MM/dd")); -// List> rows=drive.parseExcelDocument(file); for(Map r:rows){ Map userInfo=new HashMap(); for(Entry c:r.entrySet()){ @@ -344,8 +336,6 @@ public int getHeaderRow(XSSFSheet s){ String displayName=userInfo.containsKey("displayName")?userInfo.get("displayName"):userInfo.get("username"); new ChatNotification().send(ChatEvent.onRegistration, "New User Registered: "); -// }// /newUser - }else if (dbUsers.containsKey(userInfo.get("username"))){ log.debug("User already registered: "+userInfo.get("username")); @@ -420,7 +410,6 @@ public void run() { Matcher m=Pattern.compile("(\\+|\\-)(\\d+)(\\w+)").matcher(lastRun); if (m.find()){ Long numberOfDays=Long.parseLong(m.group(2)); -// TimeUnit unit=TimeUnit.valueOf(units.toUpperCase()); ChronoUnit unit=ChronoUnit.valueOf(m.group(3).toUpperCase()); lastRun2=java.sql.Date.valueOf(LocalDate.now().minus(numberOfDays, unit)); } @@ -439,38 +428,12 @@ public void run() { File scripts=new File("target/scripts"); if (!scripts.exists()) scripts.mkdirs(); - int i=0; for(Map script:config.getScripts()){ - i+=1; final Map poolToUserIdMapper=getUsersByPool(db, ((String)script.get("name")).split("\\.")[0].toLowerCase()+"Id"); long start=System.currentTimeMillis(); - if (Arrays.asList(new String[]{"java","class","javaclass"}).contains(((String)script.get("type")).toLowerCase())){ -// log.info("Executing script: "+script.get("source")); - try{ - - ScriptBase obj=(ScriptBase)Class.forName((String)script.get("source")).newInstance(); - obj.execute((String)script.get("name"), (Map)script.get("options"), daysFromLastRun, new PointsAdder(){ - public void addPoints(String user, String pool, Integer increment, Map params){ - if (user!=null && pool!=null){ - try{ - String userId=poolToUserIdMapper.get(user); - if (null!=userId){ - log.debug("addPoints:: Incrementing Points:: ["+pool+"/"+userId+"] = "+increment); - db.increment(pool, userId, increment, params); - }//else //its most likely an unregistered user - - }catch(Exception e){ - e.printStackTrace(); - } - } - } - }); - }catch(Exception sinkSinceTheresNothingWeCanDo){ - sinkSinceTheresNothingWeCanDo.printStackTrace(); - } - }else if ("sh".equalsIgnoreCase((String)script.get("type")) + if ("sh".equalsIgnoreCase((String)script.get("type")) || "bash".equalsIgnoreCase((String)script.get("type")) || "python".equalsIgnoreCase((String)script.get("type")) || "script".equalsIgnoreCase((String)script.get("type")) @@ -495,9 +458,6 @@ public void addPoints(String user, String pool, Integer increment, Map scri // log.info("Incrementing registered user "+poolUserId+" by "+inc); db.increment(pool, userId, inc, params);//.save(); }else{ - log.info("Unable to find '"+poolUserId+"' "+script.get("name")+" user - not registered? ("+params.get("id")+") "+Database2.buildLink(params)); - db.addEvent("Lost Points", poolUserId +"("+script.get("name")+")", script.get("name")+" user '"+poolUserId+"' was not found - not registered? ("+params.get("id")+") "+Database2.buildLink(params)); + log.info("Unable to find '"+poolUserId+"' "+script.get("name")+" user - not registered? "+Database2.buildLink(params)); + db.addEvent("Lost Points", poolUserId +"("+script.get("name")+")", script.get("name")+" user '"+poolUserId+"' was not found - not registered? "+Database2.buildLink(params)); } }else{ // it's a duplicate increment for that actionId & user, so ignore it diff --git a/src/main/java/com/redhat/sso/ninja/InitServlet.java b/src/main/java/com/redhat/sso/ninja/InitServlet.java index 9c7c2e39..e69563c7 100644 --- a/src/main/java/com/redhat/sso/ninja/InitServlet.java +++ b/src/main/java/com/redhat/sso/ninja/InitServlet.java @@ -1,7 +1,5 @@ package com.redhat.sso.ninja; -import java.util.concurrent.TimeUnit; - import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -12,20 +10,17 @@ public static void main(String[] asd){ GoogleDrive3.initialise("/home/%s/google_drive", com.redhat.sso.ninja.GoogleDrive3.DriverType.gdrive, "v2.1.1PreRelease"); } - @Override public void init(ServletConfig config) throws ServletException { super.init(config); GoogleDrive3.initialise("/home/%s/google_drive", com.redhat.sso.ninja.GoogleDrive3.DriverType.gdrive, "v2.1.1PreRelease"); Heartbeat2.start(Config.get()); - Backup.start(TimeUnit.DAYS.toMillis(1), Database2.STORAGE_AS_FILE.getAbsolutePath()); } @Override public void destroy() { super.destroy(); Heartbeat2.stop(); - Backup.stop(); } } diff --git a/src/main/java/com/redhat/sso/ninja/ManagementController.java b/src/main/java/com/redhat/sso/ninja/ManagementController.java index 865945f8..345e6019 100644 --- a/src/main/java/com/redhat/sso/ninja/ManagementController.java +++ b/src/main/java/com/redhat/sso/ninja/ManagementController.java @@ -41,8 +41,8 @@ import com.google.common.base.Splitter; import com.redhat.sso.ninja.Database2.EVENT_FIELDS; -import com.redhat.sso.ninja.chart.Chart2Json; -import com.redhat.sso.ninja.chart.DataSet2; +import com.redhat.sso.ninja.chart.ChartJson; +import com.redhat.sso.ninja.chart.DataSet; import com.redhat.sso.ninja.utils.Http; import com.redhat.sso.ninja.utils.IOUtils2; import com.redhat.sso.ninja.utils.Json; @@ -53,20 +53,21 @@ public class ManagementController { private static final Logger log=Logger.getLogger(ManagementController.class); - public static void main(String[] asd) throws JsonGenerationException, JsonMappingException, IOException, URISyntaxException{ - System.out.println(java.sql.Date.valueOf(LocalDate.now())); - System.out.println(java.sql.Date.valueOf(LocalDate.now().minus(365, ChronoUnit.DAYS))); - System.out.println((1000 * 60 * 60 * 24)); - System.out.println(TimeUnit.DAYS.toMillis(1)); -// System.out.println(new ManagementController().toNextLevel("BLUE", 7).toString()); - - new ManagementController().yearEnd(null, null, "FY20"); - } +// public static void main(String[] asd) throws JsonGenerationException, JsonMappingException, IOException, URISyntaxException{ +// System.out.println(java.sql.Date.valueOf(LocalDate.now())); +// System.out.println(java.sql.Date.valueOf(LocalDate.now().minus(365, ChronoUnit.DAYS))); +// System.out.println((1000 * 60 * 60 * 24)); +// System.out.println(TimeUnit.DAYS.toMillis(1)); +//// System.out.println(new ManagementController().toNextLevel("BLUE", 7).toString()); +// +// new ManagementController().yearEnd(null, null, "FY20"); +// } public static boolean isLoginEnabled(){ return "true".equalsIgnoreCase(Config.get().getOptions().get("login.enabled")); } + // common response created because post v79'ish of Chrome they introduced a SIGNED_EXCHANGE error without the following headers on every response private ResponseBuilder newResponse(int status){ return Response.status(status) .header("Access-Control-Allow-Origin", "*") @@ -138,6 +139,8 @@ private String getParameter(HttpServletRequest request, String name, String defa return defaultValue; } + + // support function api - it checks all users trello ids to see if they exist @GET @Path("/checkTrelloIDs") public Response checkTrelloIds(@Context HttpServletRequest request) throws JsonGenerationException, JsonMappingException, IOException, InterruptedException{ @@ -219,16 +222,16 @@ public Response logout(@Context HttpServletRequest request,@Context HttpServletR request.getSession().invalidate(); return Response.status(302).location(new URI("../index.jsp")).build(); } +// +// // This doenst work but would be a nice feature +// @GET +// @Path("/loglevel/{level}") +// public Response setLogLevel(@Context HttpServletRequest request,@Context HttpServletResponse response,@Context ServletContext servletContext, @PathParam("level") String level) throws JsonGenerationException, JsonMappingException, IOException{ +// LogManager.getRootLogger().setLevel(org.apache.log4j.Level.toLevel(level)); +// return Response.status(200).entity("{\"status\":\"DONE\", \"Message\":\"Changed Log level to: "+LogManager.getRootLogger().getLevel().toString()+"\"}").build(); +// } - // This doenst work but would be a nice feature - @GET - @Path("/loglevel/{level}") - public Response setLogLevel(@Context HttpServletRequest request,@Context HttpServletResponse response,@Context ServletContext servletContext, @PathParam("level") String level) throws JsonGenerationException, JsonMappingException, IOException{ - LogManager.getRootLogger().setLevel(org.apache.log4j.Level.toLevel(level)); - return Response.status(200).entity("{\"status\":\"DONE\", \"Message\":\"Changed Log level to: "+LogManager.getRootLogger().getLevel().toString()+"\"}").build(); - } - - // returns the config file contents (and yes, I shouldnt put the http method in the url, but that's a fix for later) + // returns the config file contents - used in admin UI & backup purposes @GET @Path("/config/get") public Response configGet(@Context HttpServletRequest request,@Context HttpServletResponse response,@Context ServletContext servletContext) throws JsonGenerationException, JsonMappingException, IOException{ @@ -268,6 +271,7 @@ public Response configSave(@Context HttpServletRequest request,@Context HttpServ return newResponse(200).entity(Json.newObjectMapper(true).writeValueAsString(Config.get())).build(); } + // Runs the scripts immediately - critical feature for supporting the system @GET @Path("/scripts/runNow") public Response runScriptsNow(@Context HttpServletRequest request, @Context HttpServletResponse response, @Context ServletContext servletContext){ @@ -277,7 +281,8 @@ public Response runScriptsNow(@Context HttpServletRequest request, @Context Http log.debug("Scripts run started - check logs for results"); return newResponse(200).entity("RUNNING").build(); } - + + // Pushes the current database graph data to the external cache to be accessible by end users mojo dashboard - critical for support @GET @Path("/scripts/publishGraphs") public Response pushGraphDataOnly(@Context HttpServletRequest request, @Context HttpServletResponse response, @Context ServletContext servletContext){ @@ -287,72 +292,75 @@ public Response pushGraphDataOnly(@Context HttpServletRequest request, @Context return newResponse(200).entity("RUNNING").build(); } - // manually (via rest) to register new users via a rest/json payload - @POST - @Path("/users/register") - public Response register( - @Context HttpServletRequest request - ,@Context HttpServletResponse response - ,@Context ServletContext servletContext - ,String raw - ){ - try{ - log.debug("/register called"); -// String raw=IOUtils.toString(request.getInputStream()); - mjson.Json x=mjson.Json.read(raw); - - Database2 db=Database2.get(); - for (mjson.Json user:x.asJsonList()){ - String username=user.at("username").asString(); - - if (db.getUsers().containsKey(username)) - db.getUsers().remove(username); // remove so we can overwrite the user details - - Map userInfo=new HashMap(); - for(Entry e:user.asMap().entrySet()) - userInfo.put(e.getKey(), (String)e.getValue()); - - userInfo.put("level", LevelsUtil.get().getBaseLevel().getRight()); - userInfo.put("levelChanged", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));// nextLevel.getRight()); - - db.getUsers().put(username, userInfo); - log.debug("New User Registered (via API): "+Json.newObjectMapper(true).writeValueAsString(userInfo)); - db.getScoreCards().put(username, new HashMap()); - - db.addEvent("New User Registered (via API)", username, ""); - } - - db.save(); - return Response.status(200).entity("{\"status\":\"DONE\"}").build(); - }catch(IOException e){ - e.printStackTrace(); - return Response.status(500).entity("{\"status\":\"ERROR\",\"message\":\""+e.getMessage()+"\"}").build(); - } - - } +// // manually (via rest) to register new users via a rest/json payload +// // this is how you current add users to the system +// // not used +// @POST +// @Path("/users/register") +// public Response register( +// @Context HttpServletRequest request +// ,@Context HttpServletResponse response +// ,@Context ServletContext servletContext +// ,String raw +// ){ +// try{ +// log.debug("/register called"); +//// String raw=IOUtils.toString(request.getInputStream()); +// mjson.Json x=mjson.Json.read(raw); +// +// Database2 db=Database2.get(); +// for (mjson.Json user:x.asJsonList()){ +// String username=user.at("username").asString(); +// +// if (db.getUsers().containsKey(username)) +// db.getUsers().remove(username); // remove so we can overwrite the user details +// +// Map userInfo=new HashMap(); +// for(Entry e:user.asMap().entrySet()) +// userInfo.put(e.getKey(), (String)e.getValue()); +// +// userInfo.put("level", LevelsUtil.get().getBaseLevel().getRight()); +// userInfo.put("levelChanged", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));// nextLevel.getRight()); +// +// db.getUsers().put(username, userInfo); +// log.debug("New User Registered (via API): "+Json.newObjectMapper(true).writeValueAsString(userInfo)); +// db.getScoreCards().put(username, new HashMap()); +// +// db.addEvent("New User Registered (via API)", username, ""); +// } +// +// db.save(); +// return Response.status(200).entity("{\"status\":\"DONE\"}").build(); +// }catch(IOException e){ +// e.printStackTrace(); +// return Response.status(500).entity("{\"status\":\"ERROR\",\"message\":\""+e.getMessage()+"\"}").build(); +// } +// } - // manually (via rest) to increment the points for a specific user and pool id - @GET - @Path("/points/{user}/{pool}/{increment}") - public Response incrementPool( - @Context HttpServletRequest request - ,@Context HttpServletResponse response - ,@Context ServletContext servletContext - ,@PathParam("user") String user - ,@PathParam("pool") String pool - ,@PathParam("increment") String increment - ){ - try{ - Database2 db=Database2.get(); - db.increment(pool, user, Integer.valueOf(increment), null).save(); - db.save(); - return Response.status(200).entity("{\"status\":\"DONE\"}").build(); - }catch(Exception e){ - return Response.status(500).entity("{\"status\":\"ERROR\",\"message\":\""+e.getMessage()+"\"}").build(); - } - } +// // manually (via rest) to increment the points for a specific user and pool id +// // intended for external scripts to update points, however there would be no event logging so lets deprecate for now +// // not used +// @GET +// @Path("/points/{user}/{pool}/{increment}") +// public Response incrementPool( +// @Context HttpServletRequest request +// ,@Context HttpServletResponse response +// ,@Context ServletContext servletContext +// ,@PathParam("user") String user +// ,@PathParam("pool") String pool +// ,@PathParam("increment") String increment +// ){ +// try{ +// Database2 db=Database2.get(); +// db.increment(pool, user, Integer.valueOf(increment), null).save(); +// db.save(); +// return Response.status(200).entity("{\"status\":\"DONE\"}").build(); +// }catch(Exception e){ +// return Response.status(500).entity("{\"status\":\"ERROR\",\"message\":\""+e.getMessage()+"\"}").build(); +// } +// } - // returns the database content + // returns the database content - used in admin UI & backup purposes @GET @Path("/database/get") public Response getDatabase() throws JsonGenerationException, JsonMappingException, IOException{ @@ -377,7 +385,7 @@ public Response databaseSave(@Context HttpServletRequest request,@Context HttpSe } - // UI call (edit user) - returns the scorecard and userInfo data for be able to display and edit one specific user + // Admin UI call (to edit the user) - returns the scorecard and userInfo data for be able to display and edit one specific user @GET @Path("/scorecard/{user}") public Response getScorecard(@PathParam("user") String user) throws JsonGenerationException, JsonMappingException, IOException{ @@ -404,15 +412,15 @@ public Response getScorecard(@PathParam("user") String user) throws JsonGenerati } - // UI call (user dashboard) - returns the payload to render a chart displaying the breakdown of how many points came from which pool (trello, github PR, github reviewed PR's etc..) + // User Dashboard UI call - returns the payload to render a chart displaying the breakdown of how many points came from which pool (trello, github PR, github reviewed PR's etc..) @GET @Path("/scorecard/breakdown/{user}") public Response getUserBreakdown(@PathParam("user") String user) throws JsonGenerationException, JsonMappingException, IOException{ Database2 db=Database2.get(); Map scorecard=db.getScoreCards().get(user); - Chart2Json chart=new Chart2Json(); - chart.getDatasets().add(new DataSet2()); + ChartJson chart=new ChartJson(); + chart.getDatasets().add(new DataSet()); chart.getDatasets().get(0).setBorderWidth(1); if (null!=scorecard){ for(Entry s:scorecard.entrySet()){ @@ -426,7 +434,7 @@ public Response getUserBreakdown(@PathParam("user") String user) throws JsonGene return newResponse(200).entity(Json.newObjectMapper(true).writeValueAsString(chart)).build(); } - // UI call (user dashboard) - returns user scorecard data to display the user dashboard + // User Dashboard UI call - returns user scorecard data to display the user dashboard (mojo) @GET @Path("/scorecard/summary/{user}") public Response getScorecardSummary(@PathParam("user") String user) throws JsonGenerationException, JsonMappingException, IOException{ @@ -465,7 +473,7 @@ public Response getScorecardSummary(@PathParam("user") String user) throws JsonG return newResponse(200).entity(payload).build(); } - // UI call (edit/update user) - updates an existing user with new values & points + // Admin UI call (edit/update user) - updates an existing user with new values & points @POST @Path("/scorecard/{user}") public Response saveScorecard( @@ -508,10 +516,11 @@ public Response saveScorecard( return newResponse(200).entity(Json.newObjectMapper(true).writeValueAsString("OK")).build(); } + // Admin/Support UI call to display all events, user events or specific types of events @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(); + return newResponse(200).entity(Json.newObjectMapper(true).writeValueAsString(getEvents(request.getParameter("user"), request.getParameter("event")))).build(); } public List> getAllEvents() throws JsonGenerationException, JsonMappingException, IOException{ return getEvents(null, null); @@ -531,7 +540,7 @@ public List> getEvents(String user, String event) throws Jso return result; } - + // Admin/Support UI call to list all users and their scorecards @GET @Path("/scorecards") public Response getScorecards() throws JsonGenerationException, JsonMappingException, IOException{ diff --git a/src/main/java/com/redhat/sso/ninja/PointsAdder.java b/src/main/java/com/redhat/sso/ninja/PointsAdder.java deleted file mode 100644 index 109a82e5..00000000 --- a/src/main/java/com/redhat/sso/ninja/PointsAdder.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.redhat.sso.ninja; - -import java.util.Map; - -public interface PointsAdder{ - public void addPoints(String username, String pool, Integer increment, Map params); -// public void execute(String copName, Integer daysFromLastRun); -} diff --git a/src/main/java/com/redhat/sso/ninja/ScriptBase.java b/src/main/java/com/redhat/sso/ninja/ScriptBase.java deleted file mode 100644 index a017b23a..00000000 --- a/src/main/java/com/redhat/sso/ninja/ScriptBase.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.redhat.sso.ninja; - -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -public abstract class ScriptBase{ - public abstract void execute(String name, Map options, Integer daysFromLastRun, PointsAdder adder); - - public Map getUsersBy(String key){ - Map result=new HashMap(); - for(Entry> e:Database2.get().getUsers().entrySet()){ - result.put(e.getValue().get(key), e.getKey()); - } - return result; - } -} diff --git a/src/main/java/com/redhat/sso/ninja/SupportController.java b/src/main/java/com/redhat/sso/ninja/SupportController.java index f9130525..b5b3bf0d 100644 --- a/src/main/java/com/redhat/sso/ninja/SupportController.java +++ b/src/main/java/com/redhat/sso/ninja/SupportController.java @@ -33,28 +33,36 @@ import com.redhat.sso.ninja.utils.MapBuilder; import com.redhat.sso.ninja.utils.RegExHelper; +/** + * Controller that provides features to triage support calls from end users + * @author mallen + */ @Path("/support") public class SupportController { private static final Logger log=Logger.getLogger(SupportController.class); - public static void main(String[] asd) throws JsonGenerationException, JsonMappingException, IOException, ParseException, URISyntaxException{ - - -// System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.getDefault()).parse("2019-09-17T20:11:17.091Z")); -// if (true) System.exit(0); - - SupportController test=new SupportController(){ - public String getTrelloApiKey(){return "xxx";} - public String getTrelloApiToken(){return "xxxx";} - }; - - -// test.trelloCard("mallen", "6ORZzITs", null, null); - System.out.println(test.trelloCards("mallen", "redhatcop", "Done", 281)); - - } - +// public static void main(String[] asd) throws JsonGenerationException, JsonMappingException, IOException, ParseException, URISyntaxException{ +// +// +//// System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.getDefault()).parse("2019-09-17T20:11:17.091Z")); +//// if (true) System.exit(0); +// +// SupportController test=new SupportController(){ +// public String getTrelloApiKey(){return "xxx";} +// public String getTrelloApiToken(){return "xxxx";} +// }; +// +// +//// test.trelloCard("mallen", "6ORZzITs", null, null); +// System.out.println(test.trelloCards("mallen", "redhatcop", "Done", 281)); +// +// } + /** + * Handy java client for accessing the trello api's we use + * + * @author mallen + */ class TrelloAPI{ private String key,token; private String _organizationId; @@ -249,19 +257,21 @@ public List getCards(String listNullForAll, int daysOld, String author){ } } + /** Representation of a Trello Activity, such as cards moved and when */ class Activity{ private boolean isDone; private String whenDone; public Boolean isDone(){ return isDone; } public String getWhenDone(){ return whenDone; } - } + /** Representation of a Trello Board */ class Board{ private String id; private String name; private String shortUrl; } + /** Representation of a Trello Card*/ class Card{ // public Card(String id, String name, String shortLink){ // this.id=id; this.name=name; this.shortLink=shortLink; @@ -492,13 +502,5 @@ public Response userSupport(@PathParam("userId") String redHatUserId, @Context H } } - @GET - @Path("/logout") - public Response logout(@Context HttpServletRequest request,@Context HttpServletResponse response) throws JsonGenerationException, JsonMappingException, IOException, URISyntaxException{ - log.info("/logout"); - request.getSession().setAttribute("x-access-token", null); - request.getSession().invalidate(); - return Response.status(302).location(new URI("../index.jsp")).build(); - } } diff --git a/src/main/java/com/redhat/sso/ninja/TasksController.java b/src/main/java/com/redhat/sso/ninja/TasksController.java index 91c1b337..9d96dc77 100644 --- a/src/main/java/com/redhat/sso/ninja/TasksController.java +++ b/src/main/java/com/redhat/sso/ninja/TasksController.java @@ -31,13 +31,14 @@ import com.redhat.sso.ninja.Database2.TASK_FIELDS; import com.redhat.sso.ninja.utils.Json; +/** + * Task management isnt being used so we can shelve this + * @author mallen + */ @Path("/") public class TasksController { private static final Logger log=Logger.getLogger(TasksController.class); - - - @POST @Path("/tasks") public Response newTask(@Context HttpServletRequest request,@Context HttpServletResponse response) throws JsonGenerationException, JsonMappingException, IOException, URISyntaxException{ diff --git a/src/main/java/com/redhat/sso/ninja/TrelloSync.java b/src/main/java/com/redhat/sso/ninja/TrelloSync.java deleted file mode 100644 index 6cf77faa..00000000 --- a/src/main/java/com/redhat/sso/ninja/TrelloSync.java +++ /dev/null @@ -1,255 +0,0 @@ -package com.redhat.sso.ninja; - -import static com.jayway.restassured.RestAssured.given; - -import java.io.File; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.lang3.StringUtils; -import org.apache.log4j.Logger; - -import com.jayway.restassured.specification.RequestSpecification; -import com.redhat.sso.ninja.utils.MapBuilder; - -import groovy.lang.GroovyClassLoader; -import mjson.Json; - - -/** - * - * THIS IS NOT USED, IT'S AN EXAMPLE OF HOW JAVA IMPLEMENTATION INTEGRATIONS COULD BE DONE - * - */ - -public class TrelloSync extends ScriptBase{ - private static final Logger log=Logger.getLogger(TrelloSync.class); - - /* - * - * Developed using these urls: - * https://developers.trello.com/reference/#search - * https://developers.trello.com/page/authorization - * https://github.com/redhat-cop/ninja-points/blob/master/trello-stats.py - * https://github.com/redhat-cop/ninja-points/blob/master/github-stats.py - * https://mojo.redhat.com/groups/paas-community-of-practice/projects/communities-of-practice-ninja-program - * - * Ninja Submission Form & sheet - * https://docs.google.com/spreadsheets/d/1E91hT_ZpySyvhnANxqZ7hcBSM2EEd9TqfQF-cavB8hQ/edit#gid=2111805875 - * - * - * also useful if we initiate with google sheet submissions - * http://thisdavej.com/consuming-json-web-data-using-google-sheets/ - * - */ - static String GET_ORGANIZATIONS="https://api.trello.com/1/organizations/%s"; // orgname - static String GET_ORGANIZATION_MEMBERS="https://api.trello.com/1/organizations/%s/members"; - static String GET_MEMBER="https://api.trello.com/1/members/%s"; - static String SEARCH_CARDS="https://api.trello.com/1/search"; - - - static String orgId="redhatcop"; - static String key="39cca1583d34154be24aa99ee024106d"; - static String token; -// static String POOL_NAME="Trello"; - - public static void main(String[] asd){ - new TrelloSync().execute("test", new MapBuilder().put("organizationName", "redhatcop").build(), 30, new PointsAdder(){ - public void addPoints(String username, String pool, Integer increment, Map params){ - System.out.println("AddPoints called ["+pool+"/"+username+"] Incrementing "+increment+" points"); - } - }); - } - - @Override - public void execute(String name, Map options, Integer daysFromLastRun, PointsAdder adder){ - - if (StringUtils.isEmpty(System.getenv("TRELLO_TOKEN"))){ - log.error("No \"TRELLO_TOKEN\" Environment property set"); - return; - } - token=System.getenv("TRELLO_TOKEN"); - -// TrelloSync ts=new TrelloSync(); - parse(options.get("organizationName"), daysFromLastRun, null); - -// System.out.println("CARD COUNT:"); - log.debug("Found cards for "+cardCount.size()+" individual people"); - for(Entry e:cardCount.entrySet()){ -// System.out.println("["+e.getKey()+"] = "+e.getValue()); - } -// System.out.println(""); -// System.out.println("POINTS:"); - -// Map trelloIdToUser=getUsersBy("trelloId"); - - log.debug("Found points statistics for "+pointsStats.size()+" individual people"); - for(Entry e:pointsStats.entrySet()){ - String trelloUserId=e.getKey(); -// String userId=trelloIdToUser.get(trelloUserId); -// log.debug("trelloId is "+trelloUserId+", dereferenced to "+userId); -// if (userId!=null){ // a null userid means they're most likely not registered - Integer increment=e.getValue(); -// log.debug("Before calling adder.addPoints('"+trelloUserId+"','"+name+"','"+increment+"')"); - adder.addPoints(trelloUserId, name, increment, null); - // System.out.println("["+e.getKey()+"] = "+e.getValue()); -// } - } - } - - private Map cardCount=new HashMap(); - private Map pointsStats=new HashMap(); - private Map memberIdMapping=new HashMap(); - - public void parse(String orgName, Integer days, String author){ -// TrelloSync s=new TrelloSync(); - String orgId=getOrganization(orgName).at("id").asString(); - log.debug("Found Trello organisation id: "+orgId); - for(Json member:getOrganisationMembers(orgId).asJsonList()) - memberIdMapping.put(member.at("id").asString(), member.at("username").asString()); - Json cards=searchCards(orgId, days, author); -// System.out.println("CARDS:\n"+cards.toString()); - - List cardsList=cards.at("cards").asJsonList(); - log.debug("Found "+cardsList.size()+" trello cards to process into points"); - for (Json card:cardsList){ - - String cardId=card.at("id").asString(); - String cardName=card.at("name").asString(); - - String boardName=card.at("board").at("name").asString(); - String boardOrganizationId=null; - if (!card.at("board").at("idOrganization").isNull()) - boardOrganizationId=card.at("board").at("idOrganization").asString(); - String boardId=card.at("board").at("id").asString(); - - for(Json member:card.at("idMembers").asJsonList()){ - String memberId=member.asString(); - - if (!memberIdMapping.containsKey(memberId)) // an on-demand grab for the user details for an userId that isn't in the orgs members list (for some reason users not in the private org can be on cards!?) - memberIdMapping.put(memberId, getMember(memberId).at("username").asString()); - - String memberUsername=memberIdMapping.get(memberId); - String userKey=memberUsername; - - if (!cardCount.containsKey(userKey)) cardCount.put(userKey, 0); - if (!pointsStats.containsKey(userKey)) pointsStats.put(userKey, 0); - - cardCount.put(userKey, cardCount.get(userKey)+1); -// pointsStats.put(userKey, pointsStats.get(userKey)+calculatePoints(cardName)); - - Integer points=calculatePoints(card); - if (points>0){ - log.debug("["+userKey+"] Awarded "+points+" points"); - pointsStats.put(userKey, pointsStats.get(userKey)+points); - } - - } - } - } - - @SuppressWarnings({ "unchecked", "resource", "rawtypes" }) - private Integer calculatePoints2(Json card){ - try{ -// Class scriptClass = new GroovyScriptEngine(".").loadScriptByName("calculatePoints.groovy") ; - - Class scriptClass = new GroovyClassLoader().parseClass( new File("src/main/resources/calculatePoints.groovy")); - Object scriptInstance = scriptClass.newInstance() ; - return (Integer)scriptClass.getDeclaredMethod("calculate", new Class[]{Json.class}).invoke( scriptInstance, new Json[]{card}); - }catch(Exception e){ - e.printStackTrace(); - } - return 0; - } - - private Integer calculatePoints(Json card){ - String cardName=card.at("name").asString(); - Matcher m=Pattern.compile("\\(([0-9]+)\\)").matcher(cardName); - if (m.find()){ - return Integer.parseInt(m.group(1)); - }else - return 1; - - } - - private RequestSpecification givenWithCredentials(){ - return given() - .param("key", key) - .param("token", token); - } - - private Json getMember(String userId){ - return - mjson.Json.read( - givenWithCredentials() - .get(String.format(GET_MEMBER, userId)).thenReturn().asString() - ) - ; - } - private Json getOrganisationMembers(String orgId){ - return - mjson.Json.read( - givenWithCredentials() - .get(String.format(GET_ORGANIZATION_MEMBERS, orgId)).thenReturn().asString() - ) - ; - } - - private Json getOrganization(String orgName){ - return - mjson.Json.read( - givenWithCredentials() - .get(String.format(GET_ORGANIZATIONS, orgName)).thenReturn().asString() - ) - ; - } - - private Json searchCards(String orgId, Integer days, String author){ - String query=String.format("list:Done edited:%s%s", days, author!=null && !"".equals(author)?" @"+author:""); - return - mjson.Json.read( - givenWithCredentials() - .param("query", query) - - .param("idOrganizations", orgId) - .param("modelTypes", "cards") - .param("board_fields", "name,idOrganization") - .param("card_fields", "name,idMembers") - .param("cards_limit", 1000) - .param("card_board", "true") - .param("organization_fields", "id,name,displayName") - -// .param("idOrganizations", orgId) -// .param("card_fields", "name,idMembers") -//// .param("board_fields", "name,idOrganization") -// .param("card_board", "true") -// .param("cards_limit", 1000) -//// .param("boards_limit", 1000) -// .param("cards_page", 1000) -//// .param("card_members", "true") - - .get(String.format(SEARCH_CARDS)).thenReturn().asString() - ) - ; - } - - -// public void run(){ -// Response response = -// givenWithCredentials() -// .when().auth().preemptive() -// .basic(username, password) -//// .basic("sa_solution_tracker", "17s*df8c7Q8cnD(d") -//// .header("sa_solution_tracker", "c2Ffc29sdXRpb25fdHJhY2tlcjoxN3MqZGY4YzdROGNuRChk") -// .get(url) -// .thenReturn() -// ; -// -// String strResponse=response.asString(); -// -// } -} diff --git a/src/main/java/com/redhat/sso/ninja/UserController.java b/src/main/java/com/redhat/sso/ninja/UserController.java deleted file mode 100644 index feff3960..00000000 --- a/src/main/java/com/redhat/sso/ninja/UserController.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.redhat.sso.ninja; - -import java.io.IOException; -import java.util.List; - -import javax.naming.NamingException; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; - -import org.codehaus.jackson.JsonGenerationException; -import org.codehaus.jackson.map.JsonMappingException; - -import com.redhat.sso.ninja.user.UserService; -import com.redhat.sso.ninja.utils.Json; - -@Path("/user") -public class UserController { - - - /** for example /api/user/user1 will return user1's LDAP details - * @throws NamingException */ - @GET - @Path("/{uid}") - public Response findByUid(@PathParam("uid") String uid) throws JsonGenerationException, JsonMappingException, IOException, NamingException{ - return find("uid", uid); - } - - @GET - @Path("/{field}/{value}") - public Response find(@PathParam("field") String field, @PathParam("value") String value) throws JsonGenerationException, JsonMappingException, IOException, NamingException{ - List result=search(field, value); - return Response.status(200).entity(Json.newObjectMapper(true).writeValueAsString(result)).build(); - } - - public List search(String field, String value) throws NamingException { - return new UserService().search(field, value); - } - -} diff --git a/src/main/java/com/redhat/sso/ninja/chart/Chart2Json.java b/src/main/java/com/redhat/sso/ninja/chart/Chart2Json.java deleted file mode 100644 index 77d88bea..00000000 --- a/src/main/java/com/redhat/sso/ninja/chart/Chart2Json.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.redhat.sso.ninja.chart; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -public class Chart2Json { - private Set labels=new LinkedHashSet(); // not sure this should be a Set, I think it should be a list since each corresponds to a dataset item. Sets would collapse identical text causing an unintended offset - private List custom1=new LinkedList(); - private List custom2=new LinkedList(); - private List datasets=new ArrayList(); - - public List getCustom1() {return custom1;} public void setCustom1(List value) { this.custom1=value; } - public List getCustom2() {return custom2;} public void setCustom2(List value) { this.custom2=value; } - - public Set getLabels() { - return labels; - } - public void setLabels(Set labels) { - this.labels=labels; - } - public List getDatasets() { - return datasets; - } - public void setDatasets(List datasets) { - this.datasets=datasets; - } - - -} diff --git a/src/main/java/com/redhat/sso/ninja/chart/ChartJson.java b/src/main/java/com/redhat/sso/ninja/chart/ChartJson.java index 6e6d55b7..c14bae24 100644 --- a/src/main/java/com/redhat/sso/ninja/chart/ChartJson.java +++ b/src/main/java/com/redhat/sso/ninja/chart/ChartJson.java @@ -2,13 +2,19 @@ import java.util.ArrayList; import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; import java.util.Set; public class ChartJson { - private Set labels=new LinkedHashSet(); + private Set labels=new LinkedHashSet(); // not sure this should be a Set, I think it should be a list since each corresponds to a dataset item. Sets would collapse identical text causing an unintended offset + private List custom1=new LinkedList(); + private List custom2=new LinkedList(); private List datasets=new ArrayList(); + public List getCustom1() {return custom1;} public void setCustom1(List value) { this.custom1=value; } + public List getCustom2() {return custom2;} public void setCustom2(List value) { this.custom2=value; } + public Set getLabels() { return labels; } diff --git a/src/main/java/com/redhat/sso/ninja/chart/Chart2LineJson.java b/src/main/java/com/redhat/sso/ninja/chart/ChartLineJson.java similarity index 66% rename from src/main/java/com/redhat/sso/ninja/chart/Chart2LineJson.java rename to src/main/java/com/redhat/sso/ninja/chart/ChartLineJson.java index 2c3e692c..aeb97b50 100644 --- a/src/main/java/com/redhat/sso/ninja/chart/Chart2LineJson.java +++ b/src/main/java/com/redhat/sso/ninja/chart/ChartLineJson.java @@ -5,9 +5,9 @@ import java.util.List; import java.util.Set; -public class Chart2LineJson { +public class ChartLineJson { private Set labels=new LinkedHashSet(); - private List datasets=new ArrayList(); + private List datasets=new ArrayList(); public Set getLabels() { return labels; @@ -15,10 +15,10 @@ public Set getLabels() { public void setLabels(Set labels) { this.labels=labels; } - public List getDatasets() { + public List getDatasets() { return datasets; } - public void setDatasets(List datasets) { + public void setDatasets(List datasets) { this.datasets=datasets; } diff --git a/src/main/java/com/redhat/sso/ninja/chart/DataSet.java b/src/main/java/com/redhat/sso/ninja/chart/DataSet.java index 04331e7d..325c9fff 100644 --- a/src/main/java/com/redhat/sso/ninja/chart/DataSet.java +++ b/src/main/java/com/redhat/sso/ninja/chart/DataSet.java @@ -4,45 +4,33 @@ import java.util.List; public class DataSet { - private String label; - private String fillColor; //ie "rgba(220,220,220,0.2)" - private String strokeColor; //ie "rgba(220,220,220,1)" - private String pointColor; //ie "rgba(220,220,220,1)" - private String pointStrokeColor; //ie "#fff" - private String pointHighlightFill; //ie "#fff" - private String pointHighlightStroke; //ie "rgba(220,220,220,1)" +// private String fillColor; //ie "rgba(220,220,220,0.2)" +// private String strokeColor; //ie "rgba(220,220,220,1)" + private List data; + private Integer borderWidth; private List backgroundColor; - public List getBackgroundColor() { - if (backgroundColor==null) backgroundColor=new ArrayList(); - return backgroundColor; - } private List borderColor; - public List getBorderColor() { - if (borderColor==null) borderColor=new ArrayList(); - return borderColor; - } - - private List data; + private String label; public String getLabel() { return label; } public void setLabel(String label) { - this.label=label; - } - public String getFillColor() { - return fillColor; - } - public void setFillColor(String fillColor) { - this.fillColor=fillColor; - } - public String getStrokeColor() { - return strokeColor; - } - public void setStrokeColor(String strokeColor) { - this.strokeColor=strokeColor; - } + this.label = label; + } + // public String getFillColor() { +// return fillColor; +// } +// public void setFillColor(String fillColor) { +// this.fillColor=fillColor; +// } +// public String getStrokeColor() { +// return strokeColor; +// } +// public void setStrokeColor(String strokeColor) { +// this.strokeColor=strokeColor; +// } public List getData() { if (data==null) data=new ArrayList(); return data; @@ -50,28 +38,26 @@ public List getData() { public void setData(List data) { this.data=data; } - public String getPointColor() { - return pointColor; + public Integer getBorderWidth() { + return borderWidth; } - public void setPointColor(String pointColor) { - this.pointColor = pointColor; + public void setBorderWidth(Integer borderWidth) { + this.borderWidth = borderWidth; } - public String getPointStrokeColor() { - return pointStrokeColor; - } - public void setPointStrokeColor(String pointStrokeColor) { - this.pointStrokeColor = pointStrokeColor; - } - public String getPointHighlightFill() { - return pointHighlightFill; + public List getBackgroundColor() { + if (backgroundColor==null) backgroundColor=new ArrayList(); + return backgroundColor; } - public void setPointHighlightFill(String pointHighlightFill) { - this.pointHighlightFill = pointHighlightFill; + public void setBackgroundColor(List backgroundColor) { + this.backgroundColor = backgroundColor; } - public String getPointHighlightStroke() { - return pointHighlightStroke; + public List getBorderColor() { + if (borderColor==null) borderColor=new ArrayList(); + return borderColor; } - public void setPointHighlightStroke(String pointHighlightStroke) { - this.pointHighlightStroke = pointHighlightStroke; + public void setBorderColor(List borderColor) { + this.borderColor = borderColor; } + + } diff --git a/src/main/java/com/redhat/sso/ninja/chart/DataSet2.java b/src/main/java/com/redhat/sso/ninja/chart/DataSet2.java deleted file mode 100644 index f2a71aa6..00000000 --- a/src/main/java/com/redhat/sso/ninja/chart/DataSet2.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.redhat.sso.ninja.chart; - -import java.util.ArrayList; -import java.util.List; - -public class DataSet2 { -// private String fillColor; //ie "rgba(220,220,220,0.2)" -// private String strokeColor; //ie "rgba(220,220,220,1)" - - private List data; - private Integer borderWidth; - private List backgroundColor; - private List borderColor; - private String label; - - public String getLabel() { - return label; - } - public void setLabel(String label) { - this.label = label; - } - // public String getFillColor() { -// return fillColor; -// } -// public void setFillColor(String fillColor) { -// this.fillColor=fillColor; -// } -// public String getStrokeColor() { -// return strokeColor; -// } -// public void setStrokeColor(String strokeColor) { -// this.strokeColor=strokeColor; -// } - public List getData() { - if (data==null) data=new ArrayList(); - return data; - } - public void setData(List data) { - this.data=data; - } - public Integer getBorderWidth() { - return borderWidth; - } - public void setBorderWidth(Integer borderWidth) { - this.borderWidth = borderWidth; - } - public List getBackgroundColor() { - if (backgroundColor==null) backgroundColor=new ArrayList(); - return backgroundColor; - } - public void setBackgroundColor(List backgroundColor) { - this.backgroundColor = backgroundColor; - } - public List getBorderColor() { - if (borderColor==null) borderColor=new ArrayList(); - return borderColor; - } - public void setBorderColor(List borderColor) { - this.borderColor = borderColor; - } - - -} diff --git a/src/main/java/com/redhat/sso/ninja/chart/DataSetLine2.java b/src/main/java/com/redhat/sso/ninja/chart/DataSetLine.java similarity index 98% rename from src/main/java/com/redhat/sso/ninja/chart/DataSetLine2.java rename to src/main/java/com/redhat/sso/ninja/chart/DataSetLine.java index d4c0c9a8..81e8feae 100644 --- a/src/main/java/com/redhat/sso/ninja/chart/DataSetLine2.java +++ b/src/main/java/com/redhat/sso/ninja/chart/DataSetLine.java @@ -3,7 +3,7 @@ import java.util.ArrayList; import java.util.List; -public class DataSetLine2 { +public class DataSetLine { // private String fillColor; //ie "rgba(220,220,220,0.2)" // private String strokeColor; //ie "rgba(220,220,220,1)" diff --git a/src/main/resources/calculatePoints.groovy b/src/main/resources/calculatePoints.groovy deleted file mode 100644 index f43e952e..00000000 --- a/src/main/resources/calculatePoints.groovy +++ /dev/null @@ -1,11 +0,0 @@ -import java.util.regex.*; -import mjson.Json; - -def calculate(Json card){ - def cardName=card.at("name").asString(); - Matcher m=Pattern.compile("\\(([0-9]+)\\)").matcher(cardName); - if (m.find()){ - return Integer.parseInt(m.group(1)); - }else - return 1; -} \ No newline at end of file diff --git a/src/main/resources/config.json b/src/main/resources/config.json index 66136f8b..9d63cf41 100644 --- a/src/main/resources/config.json +++ b/src/main/resources/config.json @@ -29,6 +29,11 @@ "name": "Gitlab.ServicesSupport", "source": "https://raw.githubusercontent.com/matallen/ninja-points/master/gitlab-stats.py -s ${LAST_RUN:yyyy-MM-dd} -p Merges -o kmo-consulting-engagment-reports -m .+-template$", "type": "python" + }, + { + "name": "Github.SAP.Github", + "source": "https://raw.githubusercontent.com/redhat-cop/ninja-points/v1.6/github-stats.py -s ${LAST_RUN:yyyy-MM-dd} -o redhat-sap -m '^sap\\-(s4hana-deployment|rhsm|hostagent|hana-control|netweaver-control|hana-deployment|hana-hsr|monitoring)$'", + "type": "python" } ], "options": { diff --git a/src/main/resources/scripts/github-stats.py b/src/main/resources/scripts/github-stats.py deleted file mode 100755 index 357adcf6..00000000 --- a/src/main/resources/scripts/github-stats.py +++ /dev/null @@ -1,279 +0,0 @@ -#!/usr/bin/env python - -import os, json, requests, sys, argparse -from datetime import datetime, timedelta -from dateutil.relativedelta import relativedelta - -# Fill in GitHub Token -GITHUB_API_TOKEN_NAME = 'GITHUB_API_TOKEN' -GITHUB_ORG = 'redhat-cop' -USER_AGENT= 'redhat-cop-stats' -DEFAULT_START_DATE_MONTH = '03' -DEFAULT_START_DATE_DAY = '01' -UNLABELED = 'unlabeled' - -def handle_pagination_items(session, url): -# print "pagination called: {}".format(url) - pagination_request = session.get(url) - pagination_request.raise_for_status() - - if 'next' in pagination_request.links and pagination_request.links['next']: - return pagination_request.json()['items'] + handle_pagination_items(session, pagination_request.links['next']['url']) - else: - return pagination_request.json()['items'] - -def generate_start_date(): - today_date = datetime.now() - target_start_date = datetime.strptime("{0}-{1}-{02}".format(today_date.year, DEFAULT_START_DATE_MONTH, DEFAULT_START_DATE_DAY), "%Y-%m-%d") - - if target_start_date.month < DEFAULT_START_DATE_MONTH: - target_start_date = target_start_date - relativedelta(years=1) - - return target_start_date - -def valid_date(s): - try: - return datetime.strptime(s, "%Y-%m-%d") - except ValueError: - msg = "Not a valid date: '{0}'.".format(s) - raise argparse.ArgumentTypeError(msg) - -def encode_text(text): - if text: - return text.encode("utf-8") - - return text - -def get_org_repos(session): - - return handle_pagination_items(session, "https://api.github.com/orgs/{0}/repos".format(GITHUB_ORG)) - -def get_org_members(session): - - return handle_pagination_items(session, "https://api.github.com/orgs/{0}/members".format(GITHUB_ORG)) - -def get_pr(session, url): - pr_request = session.get(url) - pr_request.raise_for_status() - - return pr_request.json() - -def get_reviews(session, url): - pr_request = session.get("{0}/reviews".format(url)) - pr_request.raise_for_status() - - return pr_request.json() - -def get_org_search_issues(session, start_date): - - query = "https://api.github.com/search/issues?q=user:{}+updated:>={}+archived:false+state:closed&per_page=50".format(GITHUB_ORG, start_date.date().isoformat()) - return handle_pagination_items(session, query) - -def process_labels(labels): - label_dict = {} - - if labels: - for x in labels.split(','): - label_dict[x.strip()] = None - - return label_dict - -def process_general_issues(issue, all_prs, label_prs): - - author_login = issue['user']['login'] - - if author_login not in label_prs: - all_author_prs = [] - else: - all_author_prs = label_prs[author_login] - - all_author_prs.append(issue) - label_prs[author_login] = all_author_prs - - return label_prs - -def show_label(label_items_key, input_labels): - - # Check if length of input labels is 0. If so, show all labels - if len(input_labels) == 0: - return True - - # Loop through input labels - for key in input_labels: - - # Check if label should be omitted - if key[-1] == "-": - if key[0:-1] == label_items_key: - return False - else: - return True - - # Check if label is found - if key == label_items_key: - return True - - return False - -parser = argparse.ArgumentParser(description='Gather GitHub Statistics.') -parser.add_argument("-s","--start-date", help="The start date to query from", type=valid_date) -parser.add_argument("-r","--human-readable", action="store_true", help="Human readable format") -parser.add_argument("-u","--username", help="Username to query") -parser.add_argument("-l","--labels", help="Comma separated list to display. Add '-' at end of each label to negate") -args = parser.parse_args() - -start_date = args.start_date -username = args.username -input_labels = args.labels - -human_readable=(args.human_readable==True) - -if start_date is None: - start_date = generate_start_date() - - -github_api_token = os.environ.get(GITHUB_API_TOKEN_NAME) - -if not github_api_token: - print "Error: GitHub API Key is Required!" - sys.exit(1) - -session = requests.Session() -session.headers = { - 'Accept': 'application/vnd.github.v3+json', - 'Authorization': 'Token {0}'.format(github_api_token), - 'User-Agent': USER_AGENT -} - -# Produce Label String -input_labels = process_labels(args.labels) - -# Initialize Collection Statistics -general_prs = {} -closed_issues = {} -reviewed_prs = {} - -org_search_issues = get_org_search_issues(session, start_date) - -for issue in org_search_issues: - -# print "{}:".format(issue['id']) - issue_author_id = issue['user']['id'] - issue_author_login = issue['user']['login'] - - # Check if Issue is a Pull Request - if 'pull_request' in issue: - is_pull_request = True - - pr_url = issue['pull_request']['url'] - - pr = get_pr(session, pr_url) - - # Check if PR Has Been Merged - if not pr['merged_at']: - continue - - # Check for Reviews - pr_reviews = get_reviews(session, pr_url) - - for review in pr_reviews: - review_author_login = review['user']['login'] - - #Filter out unwanted review users - if username is not None and review_author_login != username: - continue - - if review_author_login not in reviewed_prs: - review_author_prs = {} - else: - review_author_prs = reviewed_prs[review_author_login] - - if issue['id'] not in review_author_prs: - review_author_prs[issue['id']] = issue - - reviewed_prs[review_author_login] = review_author_prs - - #Filter out unwanted pr users - if username is not None and issue_author_login != username: - continue - - # Check if Label exists - if issue['labels']: - for label in issue['labels']: - - label_name = label['name'] - - # Determine is Label Exists - if label_name not in general_prs: - label_issues = {} - else: - label_issues = general_prs[label_name] - - general_prs[label_name] = process_general_issues(issue,general_prs, label_issues) - - else: - if UNLABELED not in general_prs: - label_issues = {} - else: - label_issues = general_prs[UNLABELED] - - general_prs[UNLABELED] = process_general_issues(issue,general_prs, label_issues) - - else: - - if issue['state'] == 'closed' and issue['assignee'] is not None: - - closed_issue_author_id = issue['assignee']['id'] - closed_issue_author_login = issue['assignee']['login'] - - #Filter out unwanted assignees - if username is not None and closed_issue_author_login != username: - continue - - # Ignore Self Assigned Issues - if issue_author_id == closed_issue_author_id: - continue - - if closed_issue_author_id not in closed_issues: - closed_issue_author = [] - else: - closed_issue_author = closed_issues[closed_issue_author_id] - - closed_issue_author.append(issue) - closed_issues[closed_issue_author_id] = closed_issue_author - -print "=== Statistics for GitHub Organization '{0}' ====".format(GITHUB_ORG) - - -print "\n== General PR's ==\n" -for key, value in general_prs.iteritems(): - # Determine whether to print out Label - if(show_label(key, input_labels)): - if (human_readable): - print "{}:".format(key) - for label_key, label_value in value.iteritems(): - if (human_readable): - print " {0} - {1}".format(label_key, len(label_value)) - for issue_value in label_value: - if (not human_readable): - print "Pull Requests/GH{0}/{1}/{2}".format(issue_value['id'], label_key, 1) - else: - print " {0} - {1}".format(encode_text(issue_value['repository_url'].split('/')[-1]), encode_text(issue_value['title'])) - -print "\n== Reviewed PR's ==\n" -for key, value in reviewed_prs.iteritems(): - if (not human_readable): - print "Reviewed Pull Requests/GH{0}/{1}/{2}".format(issue_value['id'], key, 1) - else: - print "{0} - {1}".format(key, len(value)) - for issue_key, issue_value in value.iteritems(): - print " {0} - {1}".format(encode_text(issue_value['repository_url'].split('/')[-1]), encode_text(issue_value['title'])) - -print "\n== Closed Issues ==\n" -for key, value in closed_issues.iteritems(): - if (not human_readable): - print "Closed Issues/GH{0}/{1}/{2}".format(key, value[0]['assignee']['login'], len(value)) - else: - print "{0} - {1}".format(value[0]['assignee']['login'], len(value)) - for issue_value in value: - print " {0} - {1}".format(encode_text(issue_value['repository_url'].split('/')[-1]), encode_text(issue_value['title'])) - diff --git a/src/main/resources/scripts/github-test.sh b/src/main/resources/scripts/github-test.sh deleted file mode 100755 index afaec3d9..00000000 --- a/src/main/resources/scripts/github-test.sh +++ /dev/null @@ -1 +0,0 @@ -cat src/main/resources/scripts/github-test.txt diff --git a/src/main/resources/scripts/github-test.txt b/src/main/resources/scripts/github-test.txt deleted file mode 100644 index b0e6a269..00000000 --- a/src/main/resources/scripts/github-test.txt +++ /dev/null @@ -1,153 +0,0 @@ -=== Statistics for GitHub Organization 'redhat-cop' ==== - -== General PR's == - -Pull Requests/GH376888472/raffaelespazzoli/1 -Pull Requests/GH366879868/raffaelespazzoli/1 -Pull Requests/GH374443189/Gl4di4torRr/1 -Pull Requests/GH350405799/Gl4di4torRr/1 -Pull Requests/GH377473163/bvkin/1 -Pull Requests/GH373613936/bvkin/1 -Pull Requests/GH371126503/bvkin/1 -Pull Requests/GH372787006/pabrahamsson/1 -Pull Requests/GH372510362/pabrahamsson/1 -Pull Requests/GH367039051/pabrahamsson/1 -Pull Requests/GH368356179/dmhumph/1 -Pull Requests/GH377197576/sabre1041/1 -Pull Requests/GH373766774/sabre1041/1 -Pull Requests/GH369104337/sabre1041/1 -Pull Requests/GH367439217/sabre1041/1 -Pull Requests/GH334889174/sabre1041/1 -Pull Requests/GH378347736/logandonley/1 -Pull Requests/GH378033989/logandonley/1 -Pull Requests/GH378021689/logandonley/1 -Pull Requests/GH371252996/rdebeasi/1 -Pull Requests/GH371247759/rdebeasi/1 -Pull Requests/GH371214267/rdebeasi/1 -Pull Requests/GH370334074/rdebeasi/1 -Pull Requests/GH365898210/ericzolf/1 -Pull Requests/GH364447813/jtudelag/1 -Pull Requests/GH374866131/tylerauerbeck/1 -Pull Requests/GH374423545/tylerauerbeck/1 -Pull Requests/GH368880255/huddlesj/1 -Pull Requests/GH372737520/franciosi/1 -Pull Requests/GH371332139/etsauer/1 -Pull Requests/GH370873260/etsauer/1 -Pull Requests/GH370767880/etsauer/1 -Pull Requests/GH370385263/etsauer/1 -Pull Requests/GH368880643/etsauer/1 -Pull Requests/GH368235962/etsauer/1 -Pull Requests/GH375169950/themoosman/1 -Pull Requests/GH376614901/oybed/1 -Pull Requests/GH375688230/oybed/1 -Pull Requests/GH375677738/oybed/1 -Pull Requests/GH371357229/oybed/1 -Pull Requests/GH371119296/oybed/1 -Pull Requests/GH370430649/oybed/1 -Pull Requests/GH368661861/oybed/1 -Pull Requests/GH362901946/oybed/1 -Pull Requests/GH336399945/oybed/1 -Pull Requests/GH305778816/oybed/1 -Pull Requests/GH293712202/oybed/1 -Pull Requests/GH292677750/oybed/1 -Pull Requests/GH292615746/oybed/1 -Pull Requests/GH292554817/oybed/1 -Pull Requests/GH292522928/oybed/1 -Pull Requests/GH272228203/oybed/1 -Pull Requests/GH268565058/oybed/1 -Pull Requests/GH267237693/oybed/1 -Pull Requests/GH260435527/oybed/1 -Pull Requests/GH258649872/oybed/1 -Pull Requests/GH248775943/oybed/1 -Pull Requests/GH247268206/oybed/1 -Pull Requests/GH237702882/oybed/1 -Pull Requests/GH374107487/oappiah/1 -Pull Requests/GH373453807/mluyo3414/1 -Pull Requests/GH356045458/etsauer/1 -Pull Requests/GH356045458/etsauer/1 -Pull Requests/GH371850988/duritong/1 -Pull Requests/GH371138804/Gl4di4torRr/1 -Pull Requests/GH372259794/bvkin/1 -Pull Requests/GH366164606/pabrahamsson/1 -Pull Requests/GH369263051/sabre1041/1 -Pull Requests/GH377543033/logandonley/1 -Pull Requests/GH371285193/logandonley/1 -Pull Requests/GH356322891/tylerauerbeck/1 -Pull Requests/GH366905392/etsauer/1 -Pull Requests/GH366892352/etsauer/1 -Pull Requests/GH356045458/etsauer/1 -Pull Requests/GH319103961/oybed/1 -Pull Requests/GH319070202/oybed/1 -Pull Requests/GH317341121/oybed/1 -Pull Requests/GH309968910/oybed/1 -Pull Requests/GH307432388/oybed/1 -Pull Requests/GH307010564/oybed/1 -Pull Requests/GH300755153/oybed/1 -Pull Requests/GH292502606/oybed/1 -Pull Requests/GH286545639/oybed/1 -Pull Requests/GH285807219/oybed/1 -Pull Requests/GH285517919/oybed/1 -Pull Requests/GH281672740/oybed/1 -Pull Requests/GH281658336/oybed/1 -Pull Requests/GH281386796/oybed/1 -Pull Requests/GH281368918/oybed/1 -Pull Requests/GH276258390/oybed/1 -Pull Requests/GH275473880/oybed/1 -Pull Requests/GH275391461/oybed/1 -Pull Requests/GH271561566/oybed/1 -Pull Requests/GH270173313/oybed/1 -Pull Requests/GH269486142/oybed/1 -Pull Requests/GH262245229/oybed/1 -Pull Requests/GH260103841/oybed/1 -Pull Requests/GH252958164/oybed/1 -Pull Requests/GH252354400/oybed/1 -Pull Requests/GH249218184/oybed/1 -Pull Requests/GH247897312/oybed/1 -Pull Requests/GH246235151/oybed/1 -Pull Requests/GH246225730/oybed/1 -Pull Requests/GH238030978/oybed/1 -Pull Requests/GH237367391/oybed/1 -Pull Requests/GH339625971/oybed/1 -Pull Requests/GH336067893/oybed/1 -Pull Requests/GH307427910/oybed/1 -Pull Requests/GH300840422/oybed/1 -Pull Requests/GH286511103/oybed/1 -Pull Requests/GH285817217/oybed/1 -Pull Requests/GH277887059/oybed/1 -Pull Requests/GH372259794/bvkin/1 -Pull Requests/GH377543033/logandonley/1 -Pull Requests/GH371285193/logandonley/1 -Pull Requests/GH319103961/oybed/1 -Pull Requests/GH319070202/oybed/1 -Pull Requests/GH307010564/oybed/1 - -== Reviewed PR's == - -Reviewed Pull Requests/GH307010564/duritong/1 -Reviewed Pull Requests/GH307010564/Gl4di4torRr/1 -Reviewed Pull Requests/GH307010564/pabrahamsson/1 -Reviewed Pull Requests/GH307010564/ericzolf/1 -Reviewed Pull Requests/GH307010564/makentenza/1 -Reviewed Pull Requests/GH307010564/sabre1041/1 -Reviewed Pull Requests/GH307010564/logandonley/1 -Reviewed Pull Requests/GH307010564/bbeaudoin/1 -Reviewed Pull Requests/GH307010564/rdebeasi/1 -Reviewed Pull Requests/GH307010564/trevorquinn/1 -Reviewed Pull Requests/GH307010564/matallen/1 -Reviewed Pull Requests/GH307010564/JaredBurck/1 -Reviewed Pull Requests/GH307010564/tylerauerbeck/1 -Reviewed Pull Requests/GH307010564/syvanen/1 -Reviewed Pull Requests/GH307010564/etsauer/1 -Reviewed Pull Requests/GH307010564/themoosman/1 -Reviewed Pull Requests/GH307010564/oybed/1 -Reviewed Pull Requests/GH307010564/bogdando/1 -Reviewed Pull Requests/GH307010564/day4skiing/1 - -== Closed Issues == - -Closed Issues/GH632932/JaredBurck/1 -Closed Issues/GH11966535/huddlesj/1 -Closed Issues/GH25939696/bvkin/1 -Closed Issues/GH4500758/etsauer/2 -Closed Issues/GH5749047/pabrahamsson/4 -Closed Issues/GH7549785/oybed/1 diff --git a/src/main/resources/scripts/rocketchat.py b/src/main/resources/scripts/rocketchat.py deleted file mode 100755 index 554ce0e5..00000000 --- a/src/main/resources/scripts/rocketchat.py +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/env python - -import os, json, requests, sys, argparse, collections, re, operator, csv -from datetime import datetime, timedelta -from dateutil.relativedelta import relativedelta - -ROCKETCHAT_SERVER_DEFAULT = 'chat.consulting.redhat.com' -ROCKETCHAT_USERNAME = 'ROCKETCHAT_USERNAME' -ROCKETCHAT_PASSWORD = 'ROCKETCHAT_PASSWORD' -ROCKETCHAT_AUTH_TOKEN = 'ROCKETCHAT_AUTH_TOKEN' -ROCKETCHAT_USER_ID = 'ROCKETCHAT_USER_ID' -ROCKETCHAT_MESSAGE_SEARCH_DEFAULT=7 -ROCKETCHAT_MESSAGE_COUNT=50 -ROCKETCHAT_TIME_FORMAT='%Y-%m-%dT%H:%M:%S.000Z' - -def login(session, server, username, password, authToken, userId): - if not authToken or not userId: - if not username or not password: - return "Error: No Rocketchat Authentication Details Provided" - - data = { "username": username, - "password": password } - - try: - login_request = session.post("https://{0}/api/v1/login".format(server), data=data) - except: - return "Error occurred during login process" - - response_json = login_request.json() - - if not 'status' in response_json.keys() or response_json['status'] != "success": - return "Invalid Login Response" - - authToken = login_request.json()['data']['authToken'] - userId = login_request.json()['data']['userId'] - - auth_headers = { - 'X-Auth-Token': authToken, - 'X-User-Id': userId, - 'Content-Type': 'application/json' - } - - session.headers.update(auth_headers) - - return None - -def get_channels(session, server): - channels = [] - count = 50 - passes = 0 - fetched = 0 - total = 0 - - while fetched <= total: - params = {'count': count, 'offset': fetched} - - channel_list = session.get("https://{0}/api/v1/channels.list".format(server), params=params) - - channel_list_json = channel_list.json() - - total = channel_list_json['total'] - - channels.extend(channel_list_json['channels']) - - passes += 1 - fetched = count * passes - - return channels - -def filter_channels(channels, channel_filter): - - for channel in reversed(channels): - if 'description' in channel: - if channel_filter not in channel['description']: - channels.remove(channel) - else: - channels.remove(channel) - -def process_item(final_dict, history_type, key): - if key in final_dict[history_type]: - final_dict[history_type][key] += 1 - else: - final_dict[history_type][key] = 1 - - final_dict['statistics'][history_type] += 1 - -def plural_items(text, obj): - if obj is not None and (isinstance(obj, collections.Iterable) and len(obj) == 1) or obj == 1: - return text[:-1] - else: - return text - - -def get_channel_history_stats(session, channel, newest_date, oldest_date): - formatted_oldest_date = oldest_date.strftime(ROCKETCHAT_TIME_FORMAT) - formatted_newest_date = newest_date.strftime(ROCKETCHAT_TIME_FORMAT) - return get_channel_history(session, channel, formatted_oldest_date, formatted_newest_date) - -def get_channel_history(session, channel, oldest_date, newest_date, current_latest_date=None, final_dict=None): - - if final_dict is None: - final_dict = {'messages': {}, 'joined': {}, 'removed': {}, 'statistics': {'messages': 0, 'joined': 0, 'removed': 0}} - - params = {'roomId': channel['_id'], 'oldest': oldest_date, 'count': ROCKETCHAT_MESSAGE_COUNT} - - if current_latest_date is not None: - params['latest'] = current_latest_date - - channel_history = session.get("https://{0}/api/v1/channels.history?".format(server), params=params) - - messages = channel_history.json()['messages'] - - for message in messages: - - if 't' in message: - if message['t'] == "uj": - process_item(final_dict, "joined",message['msg']) - elif message['t'] == "ru": - process_item(final_dict, "removed",message['msg']) - else: - process_item(final_dict, "messages",message['u']['username']) - - if len(messages) > 0: - return get_channel_history(session, channel, oldest_date, newest_date, messages[-1]['ts'], final_dict) - else: - return final_dict - -def write_ouput_file_record(filename, output_file_records, first_record=None): - - mode = 'a' if not first_record else 'w' - - with open(filename, mode) as f: - fieldnames = ['Chat Channel (ID)', 'Time Period', '# Users Joined', '# Messages', 'Individual User Data - % messages/channel/user'] - writer = csv.writer(f) - - if first_record is not None and first_record == True: - writer.writerow(fieldnames) - - writer.writerow(output_file_records) - - -rocketchat_username = os.environ.get(ROCKETCHAT_USERNAME) -rocketchat_password = os.environ.get(ROCKETCHAT_PASSWORD) -rocketchat_auth_token = os.environ.get(ROCKETCHAT_AUTH_TOKEN) -rocketchat_user_id = os.environ.get(ROCKETCHAT_USER_ID) - -parser = argparse.ArgumentParser(description='Gather Rocketchat Statistics.') -parser.add_argument("-f","--filter", help="Text in Channel Description to Filter On", required=True) -parser.add_argument("-d","--days", help="Number of Days to Search for Records", type=int) -parser.add_argument("-s","--server", help="Rocketchat Server") -parser.add_argument("-o","--output", help="Output File") -args = parser.parse_args() - -filtered_text = args.filter -server = args.server -days = args.days -output_file = args.output - -if not server: - server = ROCKETCHAT_SERVER_DEFAULT - -if not days: - days = ROCKETCHAT_MESSAGE_SEARCH_DEFAULT - -session = requests.Session() - -error = login(session, server, rocketchat_username, rocketchat_password, rocketchat_auth_token, rocketchat_user_id) - -if error is not None: - print error - sys.exit(1) - -channels = get_channels(session, server,) - -filter_channels(channels, filtered_text) - -newest_date = datetime.now().utcnow() -oldest_date = newest_date - relativedelta(days=days) - -formatted_time_period = "{0} - {1}".format(oldest_date.strftime("%m/%d/%Y"), newest_date.strftime("%m/%d/%Y")) - -print "=== Rocketchat Statistics For {0} ===\n".format(formatted_time_period) -if len(channels) > 0: - for channel_index, channel in enumerate(channels): - - output_file_row_records = [] - - channel_history_stats = get_channel_history_stats(session, channel, newest_date, oldest_date) - - formatted_channel_name = "#{0}".format(channel['name']) - users_joined = channel_history_stats['statistics']['joined'] - users_removed = channel_history_stats['statistics']['removed'] - total_messages = channel_history_stats['statistics']['messages'] - - print formatted_channel_name - print " {0} {1} Joined".format(users_joined, plural_items("Users", users_joined)) - print " {0} {1} Removed".format(users_removed, plural_items("Users", users_removed)) - print " {0} {1}".format(total_messages, plural_items("Messages", total_messages)) - - output_file_user_messages = "" - - for username, username_num_messages in sorted(channel_history_stats['messages'].iteritems(), key=lambda (k,v): (v,k), reverse=True): - - user_messages = "{0} - {1:.2f}% - {2} {3}".format(username, (float(username_num_messages)/float(total_messages)*100), username_num_messages, plural_items("Messages", username_num_messages)) - - print " * {0}".format(user_messages) - - if output_file_user_messages is not "": - output_file_user_messages += "\n" - - output_file_user_messages += user_messages - - if output_file is not None: - - output_file_row_records.append(formatted_channel_name) - output_file_row_records.append(formatted_time_period) - output_file_row_records.append(users_joined) - output_file_row_records.append(total_messages) - output_file_row_records.append(output_file_user_messages) - - if channel_index == 0: - write_ouput_file_record(output_file, output_file_row_records, True) - else: - write_ouput_file_record(output_file, output_file_row_records) - -else: - print "No Rocketchat Channels Match the description '{0}'".format(filtered_text) diff --git a/src/main/resources/scripts/trello-stats.py b/src/main/resources/scripts/trello-stats.py deleted file mode 100755 index 0ae6e89c..00000000 --- a/src/main/resources/scripts/trello-stats.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python - -import os, json, requests, sys, argparse, collections, re -from datetime import datetime, timedelta -from dateutil.relativedelta import relativedelta - -TRELLO_ORG_NAME = 'redhatcop' -TRELLO_API_KEY_NAME = 'TRELLO_API_KEY' -TRELLO_API_TOKEN_NAME = 'TRELLO_API_TOKEN' -DEFAULT_START_DATE_MONTH = '03' -DEFAULT_START_DATE_DAY = '01' -CARD_TITLE_POINTS_REGEX_PATTERN = re.compile(r"\(([0-9]+)\)") - -# Search for cards that are done and have been modified in the past ? days -TRELLO_SEARCH_QUERY = 'list:Done edited:{0} {1}' - -memberCache={} - -def valid_date(s): - try: - return datetime.strptime(s, "%Y-%m-%d") - except ValueError: - msg = "Not a valid date: '{0}'.".format(s) - raise argparse.ArgumentTypeError(msg) - -def generate_start_date(): - today_date = datetime.now() - target_start_date = datetime.strptime("{0}-{1}-{02}".format(today_date.year, DEFAULT_START_DATE_MONTH, DEFAULT_START_DATE_DAY), "%Y-%m-%d") - - if target_start_date.month < int(DEFAULT_START_DATE_MONTH): - target_start_date = target_start_date - relativedelta(years=1) - - return target_start_date - -def get_org_id(session): - - org_request = session.get("https://api.trello.com/1/organizations/{0}".format(TRELLO_ORG_NAME)) - org_request.raise_for_status() - - return org_request.json() - -def search_cards(session, org_id, days, author): - - author = "@{0}".format(author) if author is not None else "" - - query = TRELLO_SEARCH_QUERY.format(days, author) - - card_request = session.get("https://api.trello.com/1/search", params={'query': query, 'idOrganizations': org_id, 'card_fields': 'name,idMembers,idLabels,shortLink', 'board_fields': 'name,idOrganization', 'card_board': 'true', 'cards_limit': 1000}) - card_request.raise_for_status() - - return card_request.json() - -def get_member(session, member_id): - - if member_id not in memberCache: - member_request = session.get("https://api.trello.com/1/members/{0}".format(member_id)) - member_request.raise_for_status() - memberCache[member_id]=member_request.json() - - return memberCache.get(member_id) - - -def plural_items(text, obj): - if obj is not None and (isinstance(obj, collections.Iterable) and len(obj) == 1) or obj == 1: - return text[:-1] - else: - return text - -def calculate_points(text): - - matches = re.findall(CARD_TITLE_POINTS_REGEX_PATTERN, text) - if(len(matches) == 0): - return 1 - else: - return int(matches[-1]) - -def encode_text(text): - if text: - return text.encode("utf-8") - - return text - -def preload_member_cache(session, org_id): - members = session.get("https://api.trello.com/1/organizations/{0}/members".format(org_id)) - members.raise_for_status() - for member in members.json(): - memberCache[member['id']]=member - - -trello_api_key = os.environ.get(TRELLO_API_KEY_NAME) -trello_api_token = os.environ.get(TRELLO_API_TOKEN_NAME) - - -if not trello_api_key or not trello_api_token: - print "Error: Trello API Key and API Token are Required!" - sys.exit(1) - -parser = argparse.ArgumentParser(description='Gather Trello Statistics.') -parser.add_argument("-s","--start-date", help="The start date to query from", type=valid_date) -parser.add_argument("-u","--username", help="Username to query") -parser.add_argument("-r","--human-readable", action="store_true", help="Human readable format") -args = parser.parse_args() - -start_date = args.start_date -username = args.username - -if start_date is None: - start_date = generate_start_date() - -human_readable=(args.human_readable==True) - -days = (datetime.now() - start_date).days - -session = requests.Session() -session.params = { - 'key': trello_api_key, - 'token': trello_api_token, -} - -org_response = get_org_id(session) -org_id = org_response['id'] - -resp_cards = search_cards(session, org_id, days, username) - -cards = {} -members_items = {} - -preload_member_cache(session, org_id) - -for card in resp_cards['cards']: - - if not card['board']['idOrganization'] or card['board']['idOrganization'] != org_id: - continue - - card_id = card['id'] - cards[card_id] = card - - if 'idMembers' in card: - for member in card['idMembers']: - - member_id = member - - if member_id not in members_items: - member_items= {} - member_items['points'] = 0 - member_items['cards'] = [] - member_cards = [] - else: - member_items = members_items[member_id] - - member_items['cards'].append(card_id) - member_items['points'] += calculate_points(card['name']) - - members_items[member_id] = member_items - if (not human_readable): - print "Cards Closed/TR{0}/{1}/{2} [linkId={3}]".format(card_id, get_member(session, member_id)['username'], member_items['points'], card['shortLink']) - - -if (human_readable): - print "=== Statistics for Trello Team '{0}' ====\n".format(encode_text(org_response['displayName']) if 'displayName' in org_response else encode_text(org_response['name'])) - for key, value in members_items.iteritems(): - member = get_member(session, key) - value_points = value['points'] - value_cards = value['cards'] - - if username is not None and member['username'] != username: - continue - - print "{0} has {1} {2} - {3} {4}".format(encode_text(member['username']), len(value_cards), plural_items("cards", value_cards), value_points, plural_items("points", value_points)) - for card in value['cards']: - print " - Board: {0} | Card: {1}".format(encode_text(cards[card]['board']['name']), encode_text(cards[card]['name'])) diff --git a/src/main/resources/scripts/trello-test.sh b/src/main/resources/scripts/trello-test.sh deleted file mode 100755 index 89688b86..00000000 --- a/src/main/resources/scripts/trello-test.sh +++ /dev/null @@ -1 +0,0 @@ -cat src/main/resources/scripts/trello-test.txt diff --git a/src/main/resources/scripts/trello-test.txt b/src/main/resources/scripts/trello-test.txt deleted file mode 100644 index f40ad10f..00000000 --- a/src/main/resources/scripts/trello-test.txt +++ /dev/null @@ -1,24 +0,0 @@ -Cards Closed/TR5aca9abc18da43db6acedbe0/andrewblock/1 [linkId=1Jfd67Q1] -Cards Closed/TR5aca9abc18da43db6acedbe0/jlozadad1/1 [linkId=1Jfd67Q1] -Cards Closed/TR5bc4bb21700938426c91bb27/deangoedken/5 [linkId=oPyCaAlr] -Cards Closed/TR5b7bfce6fe0d132fc254c8b1/deangoedken/8 [linkId=xnZpLkGb] -Cards Closed/TR5bc4b38a2a3cad2dc7bfe255/briankuhta/5 [linkId=fjEJQFfg] -Cards Closed/TR5bc4b38a2a3cad2dc7bfe255/deangoedken/13 [linkId=fjEJQFfg] -Cards Closed/TR5a047eb0c8e8293a95ab9de9/eabrand/1 [linkId=t9lzCgcX] -Cards Closed/TR5a047eb0c8e8293a95ab9de9/rstroop/1 [linkId=t9lzCgcX] -Cards Closed/TR5ae9ff7535e94c6669d9f4a4/davidjoo1/1 [linkId=InJXj3g9] -Cards Closed/TR5b685d1a1ec1f34d75efcc97/romainchantereau/13 -Cards Closed/TR5b685d1a1ec1f34d75efcc97/jonathanjohnston2/5 -Cards Closed/TR5bace2438bf3255db2d3bb6a/stefanmattejiet/3 -Cards Closed/TR5bace2438bf3255db2d3bb6a/mjohanss/3 -Cards Closed/TR5bace2438bf3255db2d3bb6a/manfredmuth/8 -Cards Closed/TR5bace2438bf3255db2d3bb6a/timbeattie3/3 -Cards Closed/TR5bace2438bf3255db2d3bb6a/romainchantereau/16 -Cards Closed/TR5bace2438bf3255db2d3bb6a/irenapribova/18 -Cards Closed/TR5bace2438bf3255db2d3bb6a/kirstivanwessel/3 -Cards Closed/TR5bace2438bf3255db2d3bb6a/karishmavinayak/3 -Cards Closed/TR5bace2438bf3255db2d3bb6a/donalspring/3 -Cards Closed/TR5bace2438bf3255db2d3bb6a/nicolasfleurygobert/3 -Cards Closed/TR5bace2438bf3255db2d3bb6a/vkrissian/6 -Cards Closed/TR5b685c8bd806d32a25c340b7/annaciula/13 -Cards Closed/TR5b685c48f0a6607f7e6ced86/louisegoose/5 diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 2713a157..50fff830 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -9,7 +9,7 @@ resteasy.resources - com.redhat.sso.ninja.ManagementController,com.redhat.sso.ninja.ExportController,com.redhat.sso.ninja.UserController,com.redhat.sso.ninja.ChartsController,com.redhat.sso.ninja.TasksController,com.redhat.sso.ninja.SupportController + com.redhat.sso.ninja.ManagementController,com.redhat.sso.ninja.ExportController,com.redhat.sso.ninja.ChartsController,com.redhat.sso.ninja.TasksController,com.redhat.sso.ninja.SupportController diff --git a/src/main/webapp/login.jsp b/src/main/webapp/login.jsp index a742aa76..15f8a744 100644 --- a/src/main/webapp/login.jsp +++ b/src/main/webapp/login.jsp @@ -1,4 +1,3 @@ -<%@page import="com.redhat.sso.roxy.Controller"%> Communities of Practice diff --git a/src/main/webapp/mojo-dashboard-card.jsp b/src/main/webapp/mojo/mojo-dashboard-card.jsp similarity index 98% rename from src/main/webapp/mojo-dashboard-card.jsp rename to src/main/webapp/mojo/mojo-dashboard-card.jsp index bd9435bd..82943afc 100644 --- a/src/main/webapp/mojo-dashboard-card.jsp +++ b/src/main/webapp/mojo/mojo-dashboard-card.jsp @@ -19,7 +19,9 @@ diff --git a/src/main/webapp/mojo-miniBeltWidget.jsp b/src/main/webapp/mojo/mojo-miniBeltWidget.jsp similarity index 100% rename from src/main/webapp/mojo-miniBeltWidget.jsp rename to src/main/webapp/mojo/mojo-miniBeltWidget.jsp diff --git a/src/main/webapp/mojo-ninjaWall.jsp b/src/main/webapp/mojo/mojo-ninjaWall.jsp similarity index 100% rename from src/main/webapp/mojo-ninjaWall.jsp rename to src/main/webapp/mojo/mojo-ninjaWall.jsp diff --git a/src/main/webapp/mojo-raceToBlack-graph.jsp b/src/main/webapp/mojo/mojo-raceToBlack-graph.jsp similarity index 100% rename from src/main/webapp/mojo-raceToBlack-graph.jsp rename to src/main/webapp/mojo/mojo-raceToBlack-graph.jsp diff --git a/src/main/webapp/mojo-raceToBlack-horizontal.jsp b/src/main/webapp/mojo/mojo-raceToBlack-horizontal.jsp similarity index 100% rename from src/main/webapp/mojo-raceToBlack-horizontal.jsp rename to src/main/webapp/mojo/mojo-raceToBlack-horizontal.jsp diff --git a/src/main/webapp/mojo-raceToBlack-vertical.jsp b/src/main/webapp/mojo/mojo-raceToBlack-vertical.jsp similarity index 100% rename from src/main/webapp/mojo-raceToBlack-vertical.jsp rename to src/main/webapp/mojo/mojo-raceToBlack-vertical.jsp diff --git a/src/main/webapp/mojo-top10.jsp b/src/main/webapp/mojo/mojo-top10.jsp similarity index 100% rename from src/main/webapp/mojo-top10.jsp rename to src/main/webapp/mojo/mojo-top10.jsp diff --git a/src/main/webapp/mojo.jsp b/src/main/webapp/mojo/mojo.jsp similarity index 100% rename from src/main/webapp/mojo.jsp rename to src/main/webapp/mojo/mojo.jsp