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)
	}
}
Example #2
0
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)
}
Example #10
0
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
}