func DisplayCalculatePage(w http.ResponseWriter, r *http.Request, googleQPXExpressCredentials string) { // we need this in order to get POST form data r.ParseMultipartForm(15485760) postFormData := []byte(r.PostFormValue("flightQueries")) flightQueries = make([]data.FlightQuery, 0) error := json.Unmarshal(postFormData, &flightQueries) utils.CheckErr(error, "Unable to cast received post form data to FlightQueries !") // create, initialize and use the template uninitializedTemplate := template.New("submit calculation template") initializedTempalte, err := uninitializedTemplate.Parse(submitDataHtmlData) utils.CheckErr(err, "problem while parsing template") err = initializedTempalte.Execute(w, nil) utils.CheckErr(err, "problem while executing template") for _, query := range flightQueries { go performQuery(query, googleQPXExpressCredentials) // there is a limit of 10 queries/second/user for QPX Express FREE // if we do about 1 query/second/user then it should work ! time.Sleep(time.Second) } }
func DisplayPage( w http.ResponseWriter, arguments *DataEntryDisplayArgs) { // create, initialize and use the template uninitializedTemplate := template.New("Data entry template") initializedTempalte, err := uninitializedTemplate.Parse(dataHtmlData) utils.CheckErr(err, "problem while parsing template") err = initializedTempalte.Execute(w, arguments) utils.CheckErr(err, "problem while executing template") }
func retrieveValueFromPostForm(homepage string, postValues url.Values) []byte { resp, err := http.PostForm(homepage, postValues) utils.CheckErr(err, "problem while retrieving value from post form") buf := new(bytes.Buffer) buf.ReadFrom(resp.Body) return buf.Bytes() }
func createAiportsHtmls(name, shortName string, items *[]geoinfo.AirportData) template.HTML { arguments := selectionData{ Name: name, ShortName: shortName, Items: items, } // create, initialize and use the template uninitializedTemplate := template.New("valid airports entry template") initializedTempalte, err := uninitializedTemplate.Parse(validAirportsHtmlData) utils.CheckErr(err, "problem while parsing template") var stringBuffer bytes.Buffer err = initializedTempalte.Execute(&stringBuffer, arguments) utils.CheckErr(err, "problem while executing template") resultString := stringBuffer.String() unescapable := template.HTML(resultString) return unescapable }
func DisplayRefreshPagePage(w http.ResponseWriter, r *http.Request) { toDisplay := make([]queryDisplayData, 0) for _, element := range flightQueries { startDateString := utils.DateToString(element.StartDate) endDateString := utils.DateToString(element.BackDate) duration := countDays(element.StartDate, element.BackDate) costLockMutex.Lock() price, ok := costLock[element] costLockMutex.Unlock() priceString := "???" if ok { priceString = price } displayData := queryDisplayData{ Description: fmt.Sprintf("From %v to %v (%v days) - %v to %v", startDateString, endDateString, duration, element.StartAirport, element.DestAirport), Cost: priceString, } toDisplay = append(toDisplay, displayData) } // create, initialize and use the template uninitializedTemplate := template.New("query calculation template") initializedTempalte, err := uninitializedTemplate.Parse(dataHtmlData) utils.CheckErr(err, "problem while parsing template") arguments := pageArgumentsData{ Results: toDisplay, } err = initializedTempalte.Execute(w, arguments) utils.CheckErr(err, "problem while executing template") }
func retrieveAirportIds(startLat, startLng, startRange float32, geonameAccount string) []geonameContainer { homepage := "http://api.geonames.org/findNearbyJSON" postValues := url.Values{ "lat": {fmt.Sprintf("%v", startLat)}, "lng": {fmt.Sprintf("%v", startLng)}, "fcode": {"AIRP"}, "radius": {fmt.Sprintf("%v", startRange/1000)}, "maxRows": {"100"}, "username": {geonameAccount}} data := retrieveValueFromPostForm(homepage, postValues) value := geonamesContainer{} unmarshallError := json.Unmarshal(data, &value) utils.CheckErr(unmarshallError, "error while unmarshaling geo airports") return value.Geonames }
func performQuery(query data.FlightQuery, googleQPXExpressCredentials string) { client := &http.Client{ Transport: &transport.APIKey{Key: googleQPXExpressCredentials}} service, err := qpxexpress.New(client) if err != nil { panic(err) } tripRequest := qpxexpress.TripsSearchRequest{} trip1 := qpxexpress.SliceInput{} trip1.Date = utils.DateToString(query.StartDate) trip1.Destination = query.DestAirport trip1.Origin = query.StartAirport trip2 := qpxexpress.SliceInput{} trip2.Date = utils.DateToString(query.BackDate) trip2.Destination = query.StartAirport trip2.Origin = query.DestAirport trips := []*qpxexpress.SliceInput{} trips = append(trips, &trip1) trips = append(trips, &trip2) tripRequest.Request = &qpxexpress.TripOptionsRequest{} tripRequest.Request.Slice = trips tripRequest.Request.Refundable = false tripRequest.Request.Passengers = &qpxexpress.PassengerCounts{} tripRequest.Request.Passengers.AdultCount = 1 // we only need one solution (it is already the cheapest one) tripRequest.Request.Solutions = 1 result, err := service.Trips.Search(&tripRequest).Do() utils.CheckErr(err, "unable to retrieve trips from Google QPX Express") costLockMutex.Lock() // the first trip is already the cheapest one ! if len(result.Trips.TripOption) == 0 { costLock[query] = "not found !" } else { costLock[query] = result.Trips.TripOption[0].SaleTotal } costLockMutex.Unlock() }
func retrieveAirportNames(geonameId geonameContainer, geonameAccount string) (iata, name string) { homepage := "http://api.geonames.org/getJSON" postValues := url.Values{ "geonameId": {fmt.Sprintf("%v", geonameId.GeonameId)}, "username": {geonameAccount}} data := retrieveValueFromPostForm(homepage, postValues) value := geonameInfos{} unmarshallError := json.Unmarshal(data, &value) utils.CheckErr(unmarshallError, "error while unmarshaling geo names") for _, alternateName := range value.AlternateNames { if alternateName.Lang == "iata" { iata = alternateName.Name } if alternateName.Lang == "en" { name = alternateName.Name } } return iata, name }
func DisplayDataVerification(w http.ResponseWriter, r *http.Request, googleMapsApiCredentials string) { arguments := CreateArguments(r, googleMapsApiCredentials, "", false, "Find Cheap Flights - data verification") arguments.SubmitButtonText = "Change Data" result := parseFormValues(r) error := "" // the verification already assumes that the data // has been received by the correct homepage // --> submitting incorrect data in the post form will just throw an exception // without feedback to the user (no need to handle blatantly incorrect usage) error = error + verifyAirports(&result) error = error + verifyDates(&result) if error == "" { possibleQueries := calculatePossibleQueries(&result) possibleQueriesCount := len(possibleQueries) if possibleQueriesCount <= 50 { arguments.DataToAddBeforeSubmitButton = arguments.DataToAddBeforeSubmitButton + template.HTML(fmt.Sprintf("<b>Found <font color=\"green\">%v</font> queries</b></br>", possibleQueriesCount)) data, error := json.Marshal(possibleQueries) utils.CheckErr(error, "Problem when trying to marshall queries !") arguments.DataToAddAfterSubmitForm = template.HTML("<form action=\"/calculate\" method=\"post\"><div><input type=\"hidden\" id=\"flightQueries\" name=\"flightQueries\" value=\"" + template.HTMLEscapeString(string(data)) + "\"><input type=\"submit\" value=\"Calculate\"></div></form>") } else { arguments.DataToAddBeforeSubmitButton = arguments.DataToAddBeforeSubmitButton + template.HTML(fmt.Sprintf("<b>Only 50 queries are supported but there were <font color=\"red\">%v</font></b></br>", possibleQueriesCount)) } } else { arguments.DataToAddBeforeSubmitButton = template.HTML("<font color=\"red\"><b>" + error + "</b></font>") } // TODO : MARSHAL queries to JSON and transmit that to the calculate page ! // TODO : OR pass an ID and keep the queries internally in a map or so DisplayPage(w, arguments) }
func GetAirports(startLat, startLng, startRange float32, geonameAccount string) []AirportData { geonamesIds := retrieveAirportIds(startLat, startLng, startRange, geonameAccount) airportData := make([]AirportData, 0) for _, geonameId := range geonamesIds { iata, name := retrieveAirportNames(geonameId, geonameAccount) distance, err := strconv.ParseFloat(geonameId.Distance, 32) utils.CheckErr(err, "problem while retrieving from post form") airportDataElement := AirportData{ Distance: float32(distance), Iata: iata, Name: name, } // only add the aiport if it has correct names if (iata != "") && (name != "") { airportData = append(airportData, airportDataElement) } } return airportData }