ctf-server

old server for hosting capture-the-flag

git clone https://9o.is/git/ctf-server.git

MapUtil.scala

(6905B)


      1 package com.jcabrra
      2 package snippet
      3 
      4 import model._
      5 import net.liftweb._
      6 import http._
      7 import js._
      8 import JsCmds._
      9 import JE._
     10 import util._
     11 import util.Helpers._
     12 import xml.NodeSeq
     13 import net.liftmodules.extras._
     14 
     15 /**
     16  * TODO Future: Use MVVM and clean this up
     17  */
     18 object MapUtil {
     19   val (long,lat) = (
     20       Props.get("center.long") openOr "-73.989015", 
     21       Props.get("center.lat") openOr "40.752459")
     22   val zoomLevel = Props.get("center.zoomlevel") openOr "15"
     23   val container = "map"
     24   
     25   def genMap = {
     26     type GPS = (Double, Double)
     27     val challenges: Map[Challenge, GPS] = Challenge.findAll.map(c => (c, (c.long.get, c.lat.get))).toMap
     28     val capturedFlags = User.currentUser.map(_.capturedFlags.toList) openOr Nil
     29     
     30     val flags: Map[Flag, GPS] = Flag.findAll.map(f => (f, {
     31       if(capturedFlags.exists(_.id == f.id)) (f.long.get, f.lat.get)
     32       else f.genNearbyGPS
     33     })).toMap
     34     
     35     val unlockedFlags = 
     36       capturedFlags.flatMap(_.unlocks).flatMap(_.flags) ::: 
     37       flags.map(_._1).filter(_.prerequisite.isEmpty).toList
     38       
     39     val winningFlags = flags.map(_._1).filter(_.winner.get)
     40     		
     41     S.appendJs(JsRaw(s"""
     42         var po = org.polymaps;
     43         var map = po.map().container(
     44     		document.getElementById("$container").appendChild(po.svg("svg")))
     45 				.center({
     46 					lat : $lat,
     47 					lon : $long
     48 				}).zoom($zoomLevel).add(po.drag());
     49 		map.add(po.image().url(
     50 			po.url(
     51 				"http://{S}tile.cloudmade.com"
     52 					+ "/1a1b06b230af4efdbb989ea99e9841af"
     53 					+ "/999/256/{Z}/{X}/{Y}.png").hosts(
     54 					[ "a.", "b.", "c.", "" ])));
     55 		map.add(po.geoJson().features([${
     56     		// Generate Paths  		
     57     		val paths = flags.map { x => 
     58     		  val flag = x._1
     59     		  val (longA, latA) = x._2
     60     		  flag.prerequisite.map { preFlag => 
     61     		    
     62     		    val (longB, latB) = flags.get(preFlag).getOrElse((0,0))
     63     		    s"""{"geometry":{"coordinates":[[$longA,$latA],[$longB,$latB]],"type":"LineString"}}"""
     64     		  } mkString ","
     65     		}.foldLeft("")((a,b) => if(a.isEmpty || b.isEmpty) a+b else a+","+b)
     66     		    		
     67     		paths
     68     	}]).on("load", loadFlagPaths));
     69     
     70     	function loadFlagPaths(e) {
     71 			${
     72 			  val ids = flags.flatMap(_._1.prerequisite).map(_.id.get).toList
     73 			  var ret = ""
     74 			  for (i <- 0 until ids.size) {
     75 			    val captured = User.currentUser.exists(_.capturedFlags.exists(_.id.get == ids(i)))
     76 			    ret += s"""
     77             e.features[$i].element.id = "map-path${ids(i)}";
     78 			      e.features[$i].element.addClass("${if(captured) "captured" else ""}");
     79 			    """			  
     80 			  }
     81 			  ret
     82 			}
     83 		}
     84     
     85     	map.add(po.geoJson().features([${
     86     		// Generate flag points  		
     87     		val points = flags.map { x =>
     88     		    val (nearLong, nearLat) = x._2
     89     		    s"""{"geometry":{"coordinates":[$nearLong,$nearLat],"type":"Point"}}"""
     90     		} mkString ","
     91     		
     92     		points
     93     	}]).on("load", loadFlagPoints));
     94     	
     95     	function loadFlagPoints(e) {
     96 			${
     97 			  val ids = flags.map(_._1.id.get).toList
     98 			  var ret = ""
     99 			  for (i <- 0 until flags.size) {
    100 			    val captured = capturedFlags.exists(_.id.get == ids(i))
    101 			    val unlocked = unlockedFlags.exists(_.id.get == ids(i))
    102 			    val winner = winningFlags.exists(_.id.get == ids(i))
    103 			    
    104 			    ret += s"""
    105 			      e.features[$i].element.id = "map-flag${ids(i)}";
    106 			      e.features[$i].element.addClass("${if(captured) "captured" else ""}");
    107 			      e.features[$i].element.addClass("${if(!captured && unlocked) "unlocked" else ""}");
    108 			      e.features[$i].element.addClass("${if(winner) "winner" else ""}");
    109 			  	  e.features[$i].element.setAttribute("r", "${if(winner) "15" else "8"}");
    110 			    """			  
    111 			  }
    112 			  ret
    113 			}
    114 		}
    115 			
    116 		map.add(po.geoJson().features([${
    117     		// Generate challenge points  		
    118     		val points = challenges.map { x =>
    119     		    val (nearLong, nearLat) = x._2
    120     		    s"""{"geometry":{"coordinates":[$nearLong,$nearLat],"type":"Point"}}"""
    121     		} mkString ","
    122     		
    123     		points
    124     	}]).on("load", loadChallengePoints));
    125     	
    126     	function loadChallengePoints(e) {
    127 			${
    128 			  val ids = challenges.map(_._1.id.get).toList
    129 			  val radius = challenges.map(_._1.radius.get).toList
    130 			  var ret = ""
    131 			  for (i <- 0 until challenges.size) {
    132 			    ret += s"""
    133 			      e.features[$i].element.id = "map-challenge${ids(i)}";
    134 			  	  e.features[$i].element.setAttribute("r", "${radius(i)}");
    135 			    """			  
    136 			  }
    137 			  ret
    138 			}
    139 		}
    140 			
    141     	${
    142     	  // Generate Popovers
    143     	  challenges.map {
    144     	    c =>
    145     	      val challenge = c._1
    146     	      
    147     	      def capturedBy: NodeSeq = challenge.flags.flatMap(_.capturedBy).map {
    148     	        user => <img width='25' height='25' src={user.image.get}></img>
    149     	      }
    150     	      
    151     	      "$('#map-challenge"+challenge.id+"').popover({" + 
    152     	      s"""
    153     	      	"title" : "${challenge.name}",
    154     	      	"content" : "${
    155     	      	  
    156     	      	  def escDoubleQuote(str: String): String = {
    157     	      	    str.toList.map(_.toString).map(ch =>
    158     	      	    if (ch == "\"") "\\\"" else ch).mkString
    159     	      	  }
    160     	      	  
    161     	      	  val cont = User.currentUser.map {
    162     	      	    user =>
    163     	      	      
    164     	      	      def process(guess: String): JsCmd = {
    165     	      	        Challenges.processResponse(guess, user, challenge)
    166     	      	        SetValById(challenge.name+"-input", "")
    167     	      	      }
    168     	      	      
    169     	      	      def capturedFlags: NodeSeq = challenge.capturedFlags(user).map {
    170     	      	        flag => <p class='text-success'>{flag.answer}</p>
    171     	      	      }
    172 
    173     	      	      def input: NodeSeq = 
    174     	      	        if(challenge.fullySolvedBy(user)) NodeSeq.Empty 
    175     	      	        else SHtml.ajaxText("", false, process _, 
    176     	      	            "id" -> (challenge.name+"-input"), "placeholder" -> "guess")
    177     	      	        
    178     	      	      if(challenge.meetsPrerequisite(user)) {
    179     	      	        capturedFlags ++ <p>{challenge.hint}</p> ++ input ++ <p>{capturedBy}</p>
    180     	      	      } else {
    181     	      	        <p class='text-danger'>LOCKED!</p> ++ capturedBy
    182     	      	      }
    183     	      	  }.openOr(<p><a href='/login'>Join The Fun!</a></p> ++ capturedBy)  
    184     	      	  escDoubleQuote(cont.toString)
    185     	      	}",
    186     	      	"container" : "#$container",
    187     	      	"placement" : "bottom",
    188     	      	"html" : true
    189     	      	});
    190     	      	
    191     	      	window.onload = function() {
    192     	      		var unlockedOpacity;
    193     	      		setInterval(function() {
    194     	      			unlockedOpacity = unlockedOpacity === '1' ? '0.5' : '1';
    195           				jQuery(".unlocked").css("fill-opacity", unlockedOpacity);
    196     	      			po.geoJson().reload;
    197     	      		}, 500);
    198     	      	};
    199     	      	
    200     	      	map.on("move", function() {
    201     	      		jQuery(".popover").hide();
    202     	      	});
    203     	      """ 
    204     	  }.mkString
    205     	}
    206     """).cmd)
    207     "*" #> NodeSeq.Empty
    208   }
    209 }