66import edu .cmu .oli .content .models .persistance .entities .ContentPackage ;
77import edu .cmu .oli .content .models .persistance .entities .ErrorLevel ;
88import edu .cmu .oli .content .models .persistance .entities .Resource ;
9+ import edu .cmu .oli .content .resource .builders .Xml2Json ;
910import org .apache .tika .Tika ;
1011import org .apache .xml .resolver .tools .CatalogResolver ;
1112import org .jdom2 .Attribute ;
2223import javax .json .JsonValue ;
2324import javax .naming .InitialContext ;
2425import javax .naming .NamingException ;
25-
26+ import javax .ws .rs .client .ClientBuilder ;
27+ import javax .ws .rs .client .Entity ;
28+ import javax .ws .rs .client .WebTarget ;
29+ import javax .ws .rs .core .MediaType ;
30+ import javax .ws .rs .core .Response ;
2631import java .io .*;
2732import java .nio .file .Files ;
2833import java .nio .file .Path ;
2934import java .security .MessageDigest ;
3035import java .security .NoSuchAlgorithmException ;
3136import java .security .SecureRandom ;
32- import java .util .ArrayList ;
33- import java .util .HashMap ;
34- import java .util .List ;
35- import java .util .Map ;
36- import java .util .Optional ;
37- import java .util .Random ;
38- import java .util .UUID ;
37+ import java .util .*;
38+ import java .util .concurrent .ConcurrentHashMap ;
3939import java .util .stream .Collectors ;
40- import edu .cmu .oli .content .resource .builders .Xml2Json ;
4140
4241/**
4342 * @author Raphael Gachuhi
@@ -92,7 +91,7 @@ public static String inputStreamToString(InputStream input) throws IOException {
9291 }
9392
9493 public static void addToPackageError (ContentPackage contentPackage , String message , String source ,
95- ErrorLevel level ) {
94+ ErrorLevel level ) {
9695 if (contentPackage .getErrors () == null ) {
9796 JsonObject errors = new JsonObject ();
9897 errors .addProperty ("contentPackageErrors" , contentPackage .getId () + "_" + contentPackage .getVersion ());
@@ -129,13 +128,13 @@ public static void addToResourceError(Resource resource, String message, String
129128
130129 private static boolean isQuestionWithParts (Element element ) {
131130 if (element .getName ().equals ("multiple_choice" )
132- || element .getName ().equals ("ordering" )
133- || element .getName ().equals ("short_answer" )
134- || element .getName ().equals ("essay" )
135- || element .getName ().equals ("numeric" )
136- || element .getName ().equals ("text" )
137- || element .getName ().equals ("fill_in_the_blank" )
138- || element .getName ().equals ("question" )) {
131+ || element .getName ().equals ("ordering" )
132+ || element .getName ().equals ("short_answer" )
133+ || element .getName ().equals ("essay" )
134+ || element .getName ().equals ("numeric" )
135+ || element .getName ().equals ("text" )
136+ || element .getName ().equals ("fill_in_the_blank" )
137+ || element .getName ().equals ("question" )) {
139138 return true ;
140139 }
141140
@@ -169,8 +168,8 @@ private static String getQuestionLabel(Element question) {
169168
170169 switch (question .getName ()) {
171170 case "multiple_choice" :
172- if (question .getAttribute ("select" ) != null
173- && question .getAttribute ("select" ).getValue ().equals ("single" )) {
171+ if (question .getAttribute ("select" ) != null
172+ && question .getAttribute ("select" ).getValue ().equals ("single" )) {
174173 return "Multiple Choice" ;
175174 }
176175 return "Check All That Apply" ;
@@ -219,16 +218,16 @@ public static int countPoolQuestions(Element element) {
219218 if (element .getName ().equals ("pool" )) {
220219 for (Element c : element .getChildren ()) {
221220 switch (c .getName ()) {
222- case "multiple_choice" :
223- case "ordering" :
224- case "short_answer" :
225- case "essay" :
226- case "numeric" :
227- case "text" :
228- case "fill_in_the_blank" :
229- case "question" :
230- count = count + 1 ;
231- default :
221+ case "multiple_choice" :
222+ case "ordering" :
223+ case "short_answer" :
224+ case "essay" :
225+ case "numeric" :
226+ case "text" :
227+ case "fill_in_the_blank" :
228+ case "question" :
229+ count = count + 1 ;
230+ default :
232231 }
233232 }
234233 }
@@ -368,29 +367,26 @@ public enum EmbedActivityType {
368367 UNKNOWN ("UNKNOWN" );
369368
370369 private String type ;
371-
370+
372371 EmbedActivityType (String type ) {
373372 this .type = type ;
374373 }
375-
374+
376375 public String getAsString () {
377376 return type ;
378377 }
379-
378+
380379 private static final Map <String , EmbedActivityType > reverseLookup = new HashMap <>();
381-
380+
382381 // Populate the reverse lookup table on loading time
383- static
384- {
385- for (EmbedActivityType activityType : EmbedActivityType .values ())
386- {
382+ static {
383+ for (EmbedActivityType activityType : EmbedActivityType .values ()) {
387384 reverseLookup .put (activityType .getAsString (), activityType );
388385 }
389386 }
390-
387+
391388 //This method can be used for reverse lookup purpose
392- public static EmbedActivityType fromString (String type )
393- {
389+ public static EmbedActivityType fromString (String type ) {
394390 return reverseLookup .get (type );
395391 }
396392 }
@@ -399,7 +395,7 @@ public static EmbedActivityType inferEmbedActivityType(JsonObject embedActivity)
399395 // use activity_type property or infer type based on content
400396 if (embedActivity .has ("@activity_type" )) {
401397 // use activity_type attribute to determine type
402- switch (embedActivity .get ("@activity_type" ).getAsString ().toLowerCase ()) {
398+ switch (embedActivity .get ("@activity_type" ).getAsString ().toLowerCase ()) {
403399 case "repl" :
404400 return EmbedActivityType .REPL ;
405401 default :
@@ -424,7 +420,7 @@ public static EmbedActivityType inferEmbedActivityType(JsonObject embedActivity)
424420 String source = itemObj .get ("source" ).getAsJsonObject ().get ("#text" ).getAsString ();
425421 if (source .endsWith ("activity.js" ) || source .endsWith ("repl.js" )) {
426422 flags = flags | 0b1;
427-
423+
428424 if (flags == REPL_FLAGS ) {
429425 return EmbedActivityType .REPL ;
430426 }
@@ -467,7 +463,52 @@ public static EmbedActivityType inferEmbedActivityType(JsonObject embedActivity)
467463 }
468464
469465 }
470-
466+
471467 return EmbedActivityType .UNKNOWN ;
472468 }
469+
470+ private static Map <String , Long > delayedSlackMessages ;
471+ static {
472+ delayedSlackMessages = new ConcurrentHashMap <>();
473+ long sleepTimeInMilli = 1000L * 60 * 1 ; // 1 minutes
474+ Timer timer = new Timer (true );
475+ TimerTask timerTask = new TimerTask () {
476+ @ Override
477+ public void run () {
478+ delayedSlackMessagesClear ();
479+ }
480+ };
481+ timer .scheduleAtFixedRate (timerTask , sleepTimeInMilli , sleepTimeInMilli );
482+ }
483+
484+ private static void delayedSlackMessagesClear (){
485+ Iterator <Map .Entry <String , Long >> it = delayedSlackMessages .entrySet ().iterator ();
486+ while (it .hasNext ()){
487+ Map .Entry <String , Long > next = it .next ();
488+ // Remove entry after 15 minutes
489+ if ((System .currentTimeMillis () - next .getValue ()) > (1000L * 60 * 15 )){
490+ delayedSlackMessages .remove (next .getKey ());
491+ }
492+ }
493+ }
494+
495+ public static Response .Status sendSlackAlert (JsonObject message ) {
496+ String slackHook = System .getenv ().get ("slack_alert_hook" );
497+ if (slackHook == null || slackHook .isEmpty () || slackHook .equalsIgnoreCase ("none" )) {
498+ return Response .Status .FORBIDDEN ;
499+ }
500+ String messageString = AppUtils .gsonBuilder ().create ().toJson (message );
501+ if (delayedSlackMessages .containsKey (messageString )){
502+ // Same message already dispatched less than 15 minutes ago; ignore this one
503+ return Response .Status .OK ;
504+ }
505+
506+ delayedSlackMessages .put (messageString , System .currentTimeMillis ());
507+ WebTarget target = ClientBuilder .newClient ().target (slackHook );
508+ Response response = target .request (MediaType .APPLICATION_JSON )
509+ .post (Entity .json (messageString ));
510+ log .info ("response code " + response .getStatusInfo () + " code " + response .getStatus ());
511+
512+ return Response .Status .fromStatusCode (response .getStatus ());
513+ }
473514}
0 commit comments