ee5693424e560813ece15a283e282cad667c2d0a
[potlatch2.git] / net / systemeD / potlatch2 / BugConnection.as
1 package net.systemeD.potlatch2 {
2
3     import net.systemeD.halcyon.VectorLayer;
4     import net.systemeD.halcyon.Map;
5     import net.systemeD.halcyon.connection.*;
6     import net.systemeD.halcyon.connection.actions.*;
7     import flash.net.*;
8     import flash.events.*;
9     import flash.system.Security;
10     import com.adobe.serialization.json.JSON;
11
12     /** A VectorLayer that can be used to load and display bugs from MapDust-compatible APIs.
13         See utils/BugLoader.as for the corresponding loader. */
14
15     public class BugConnection extends Connection {
16
17         private var baseUrl:String;
18         private var apiKey:String;
19         private var detailsUrl:String;
20         /** A comma-separated list of statuses that we wish to fetch. But TBH we only want open ones. */
21         private var filter_status:String = BUG_STATUS_OPEN;
22         /** A comma-separated list of types of bugs. We don't want ones classed as routing problems, they are likely to be skobbler-app specific. */
23         /* Possible values: wrong_turn,bad_routing,oneway_road,blocked_street,missing_street,wrong_roundabout,missing_speedlimit,other */
24         private var filter_type:String = "wrong_turn,oneway_road,blocked_street,missing_street,wrong_roundabout,missing_speedlimit,other";
25         /** Type of comments. "idd = 0" means no comments with default description, "idd = 1" means only comments with default description.
26         * Use empty string (i.e. don't pass any parameter) to indicate all comments. */
27         private var commentType:String = "&idd=0";
28
29         // as strings, since that's how they are in tags and http calls
30         public static var BUG_STATUS_OPEN:String = "1";
31         public static var BUG_STATUS_FIXED:String = "2";
32         public static var BUG_STATUS_INVALID:String = "3"; // or 'non-reproduceable'
33         public static const status:Array = ["", "open", "fixed", "invalid"];
34
35         public function BugConnection(n:String, baseUrl:String, apiKey:String, detailsURL:String) {
36             this.baseUrl = baseUrl;
37             this.apiKey = apiKey;
38             this.detailsUrl = detailsURL;
39             super(n, baseUrl, baseUrl+"crossdomain.xml", null);
40         }
41
42         public function closeBug(m:Marker, nickname:String, comment:String, status:String = null):void {
43             var id:String = m.getTag('bug_id');
44             nickname ||= 'NoName';
45             // nicknames have length and character restictions. The character restrictions should be taken care of
46             // by the BugPanel.mxml restriction.
47             if (nickname.length < 3 || nickname.length > 16) {
48               nickname = 'NoName';
49             }
50             comment ||= 'No Comment';
51             if (comment.length > 1000) {
52               comment = comment.substr(0,1000); // that's index, length
53             }
54             status ||= BUG_STATUS_FIXED;
55             var urlReq:URLRequest = new URLRequest(baseUrl+"changeBugStatus?id="+id+"&status="+status+"&comment="+encodeURIComponent(comment)+"&nickname="+encodeURIComponent(nickname)+"&key="+apiKey);
56             urlReq.method = "POST";
57             urlReq.data = '    '; // dear Adobe, this is nuts, kthxbye (you can't POST with an empty payload)
58             var loader:URLLoader = new URLLoader();
59             loader.load(urlReq);
60             loader.addEventListener(Event.COMPLETE, function(e:Event):void { bugClosed(e, m, status); } );
61         }
62
63         private function bugClosed(event:Event, marker:Marker, s:String):void {
64             var action:UndoableEntityAction = new SetTagAction(marker, "status", status[int(s)]);
65             action.doAction(); // just do it, don't add to undo stack
66         }
67
68         public override function loadBbox(left:Number, right:Number,
69                                 top:Number, bottom:Number):void {
70
71             // Should be guarded against multiple calls really.
72             if (policyURL != "") { Security.loadPolicyFile(policyURL); }
73
74             var loader:URLLoader = new URLLoader();
75             loader.addEventListener(Event.COMPLETE, parseJSON);
76             loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, handleError);
77             loader.addEventListener(IOErrorEvent.IO_ERROR, handleError);
78             loader.load(new URLRequest(baseUrl+"getBugs?bbox="+left+","+bottom+","+right+","+top+"&key="+apiKey+"&filter_status="+filter_status+"&filter_type="+filter_type+commentType));
79         }
80
81                 private function handleError(event:Event):void {
82                 }
83
84         private function parseJSON(event:Event):void {
85             var result:String = String(event.target.data);
86             if (result) { // api returns 204 no content for no bugs, and the JSON parser treats '' as an error
87               var featureCollection:Object = JSON.decode(result);
88
89               for each (var feature:Object in featureCollection.features) {
90                 // geoJSON spec is x,y,z i.e. lon, lat, ele
91                 var lon:Number = feature.geometry.coordinates[0];
92                 var lat:Number = feature.geometry.coordinates[1];
93                 var tags:Object = {};
94                 tags["name"] = String(feature.properties.description).substr(0,10)+'...';
95                 tags["description"] = feature.properties.description;
96                 tags["bug_id"] = feature.id;
97                 tags["nickname"] = feature.properties.nickname;
98                 tags["type"] = feature.properties.type;
99                 tags["date_created"] = feature.properties.date_created;
100                 tags["date_updated"] = feature.properties.date_updated;
101                 tags["source"] = feature.properties.source;
102                 tags["status"] = status[int(feature.properties.status)];
103                 var marker:Marker = createMarker(tags, lat, lon, Number(feature.id));
104               }
105             }
106         }
107
108         public function bugDetailsUrl(m:Marker):String {
109             if (detailsUrl == '')
110               return null;
111             return detailsUrl+m.id;
112         }
113
114     }
115 }