-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ability to get flights of exact date (#2)
- Loading branch information
Showing
8 changed files
with
765 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
name: CI | ||
|
||
on: | ||
push: | ||
branches: | ||
- '**' | ||
tags-ignore: | ||
- '**' | ||
|
||
jobs: | ||
integration_test: | ||
name: Run tests | ||
runs-on: ubuntu-22.04 | ||
steps: | ||
- name: Set up toolchain | ||
uses: actions/setup-go@v3 | ||
with: | ||
go-version: 1.20.1 | ||
id: go | ||
|
||
- name: Check out repository code | ||
uses: actions/checkout@v3 | ||
|
||
- name: Run integration test | ||
run: | | ||
go test ./... -v |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
package api | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"strings" | ||
"time" | ||
|
||
"golang.org/x/net/html" | ||
"golang.org/x/text/currency" | ||
) | ||
|
||
type flight struct { | ||
Departure string | ||
Arrival string | ||
Price string | ||
} | ||
|
||
func readLine(body *bufio.Reader) ([]byte, error) { | ||
bytesToDecode, isPrefix, err := body.ReadLine() | ||
if err != nil { | ||
return nil, err | ||
} | ||
if !isPrefix { | ||
return bytesToDecode, nil | ||
} | ||
bytesToDecodeFinal := make([]byte, len(bytesToDecode)) | ||
copy(bytesToDecodeFinal, bytesToDecode) | ||
for isPrefix { | ||
bytesToDecode, isPrefix, err = body.ReadLine() | ||
if err != nil { | ||
return bytesToDecode, err | ||
} | ||
bytesToDecodeFinal = append(bytesToDecodeFinal, bytesToDecode...) | ||
} | ||
return bytesToDecodeFinal, nil | ||
} | ||
|
||
func contains(s []currency.Unit, str currency.Unit) bool { | ||
for _, v := range s { | ||
if v == str { | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} | ||
|
||
var supportedCurrency = []currency.Unit{currency.USD, currency.PLN} | ||
|
||
func parse(htmlToParse string) [][]string { | ||
tokenizer := html.NewTokenizer(strings.NewReader(htmlToParse)) | ||
|
||
val := []string{} | ||
vals := [][]string{} | ||
isLi := false | ||
|
||
for { | ||
tt := tokenizer.Next() | ||
if tt == html.ErrorToken { | ||
if tokenizer.Err() == io.EOF { | ||
return vals | ||
} | ||
fmt.Printf("Error: %v", tokenizer.Err()) | ||
return vals | ||
} | ||
tag, hasAttr := tokenizer.TagName() | ||
if tt == html.StartTagToken && string(tag) == "li" { | ||
isLi = true | ||
val = []string{} | ||
} | ||
if tt == html.EndTagToken && string(tag) == "li" { | ||
isLi = false | ||
vals = append(vals, val) | ||
} | ||
if hasAttr { | ||
for { | ||
_, attrValue, moreAttr := tokenizer.TagAttr() | ||
|
||
if isLi { | ||
val = append(val, string(attrValue)) | ||
} | ||
|
||
if !moreAttr { | ||
break | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
func isSupportedCurrency(unit currency.Unit) bool { | ||
fmt.Println(supportedCurrency) | ||
return contains(supportedCurrency, unit) | ||
} | ||
|
||
func getPriceSuffix(unit currency.Unit) string { | ||
if unit == currency.USD { | ||
return "US dollars" | ||
} | ||
if unit == currency.PLN { | ||
return "Polish zlotys" | ||
} | ||
return "" | ||
} | ||
|
||
func GetFlights( | ||
departureDate time.Time, | ||
returnDate time.Time, | ||
departureCity string, | ||
arivalCity string, | ||
unit currency.Unit, | ||
) ([]flight, error) { | ||
if !isSupportedCurrency(unit) { | ||
return nil, fmt.Errorf(unit.String() + " is not supproted yet") | ||
} | ||
|
||
url, err := CreateFullURL(departureDate, returnDate, departureCity, arivalCity) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
fmt.Println(url) | ||
|
||
url = url + "&curr=" + unit.String() | ||
url = url + "&hl=en-US" | ||
|
||
flights := []flight{} | ||
|
||
req, err := http.NewRequest(http.MethodGet, url, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
req.Header.Set("authority", "www.google.com") | ||
req.Header.Set("accept", "*/*") | ||
req.Header.Set("accept-language", "en-US,en;q=0.9") | ||
req.Header.Set("cache-control", "no-cache") | ||
req.Header.Set("content-type", "application/x-www-form-urlencoded;charset=UTF-8") | ||
req.Header.Set("cookie", "CONSENT=YES+srp.gws-20211208-0-RC2.pl+FX+371") | ||
req.Header.Set("origin", "https://www.google.com") | ||
req.Header.Set("pragma", "no-cache") | ||
req.Header.Set("sec-ch-ua", "\"Google Chrome\";v=\"113\", \"Chromium\";v=\"113\", \"Not-A.Brand\";v=\"24\"") | ||
req.Header.Set("sec-ch-ua-arch", "\"x86\"") | ||
req.Header.Set("sec-ch-ua-bitness", "\"64\"") | ||
req.Header.Set("sec-ch-ua-full-version", "\"113.0.5672.92\"") | ||
req.Header.Set("sec-ch-ua-full-version-list", "\"Google Chrome\";v=\"113.0.5672.92\", \"Chromium\";v=\"113.0.5672.92\", \"Not-A.Brand\";v=\"24.0.0.0\"") | ||
req.Header.Set("sec-ch-ua-mobile", "?0") | ||
req.Header.Set("sec-ch-ua-model", "") | ||
req.Header.Set("sec-ch-ua-platform", "Linux") | ||
req.Header.Set("sec-ch-ua-platform-version", "5.19.0") | ||
req.Header.Set("sec-ch-ua-wow64", "?0") | ||
req.Header.Set("sec-fetch-dest", "empty") | ||
req.Header.Set("sec-fetch-mode", "cors") | ||
req.Header.Set("sec-fetch-site", "same-origin") | ||
req.Header.Set("user-agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36") | ||
req.Header.Set("x-same-domain", "1") | ||
client := http.Client{ | ||
Timeout: 30 * time.Second, | ||
} | ||
resp, err := client.Do(req) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer resp.Body.Close() | ||
|
||
body, err := io.ReadAll(resp.Body) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
data := parse(string(body)) | ||
|
||
priceSuffix := getPriceSuffix(unit) | ||
|
||
for _, i := range data { | ||
departure := "" | ||
arrival := "" | ||
price := "" | ||
for _, j := range i { | ||
if strings.Contains(j, "Departure") && departure == "" { | ||
departure = j | ||
} | ||
if strings.Contains(j, "Arrival") && arrival == "" { | ||
arrival = j | ||
} | ||
if strings.HasSuffix(j, priceSuffix) && price == "" { | ||
price = j | ||
} | ||
} | ||
if departure != "" && arrival != "" && price != "" { | ||
flights = append(flights, flight{departure, arrival, price}) | ||
} | ||
} | ||
return flights, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package api | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"golang.org/x/text/currency" | ||
) | ||
|
||
func TestGetFlightsPLN(t *testing.T) { | ||
departureDate, err := time.Parse("2006-01-02", "2023-10-01") | ||
if err != nil { | ||
t.Fatalf("Error while creating departure date") | ||
} | ||
returnDate, err := time.Parse("2006-01-02", "2023-10-08") | ||
if err != nil { | ||
t.Fatalf("Error while creating return date") | ||
} | ||
|
||
flights, err := GetFlights(departureDate, returnDate, "Wrocław", "Madryt", currency.PLN) | ||
if err != nil { | ||
t.Fatalf(err.Error()) | ||
} | ||
|
||
if len(flights) < 5 { | ||
t.Fatalf("received flights array contains less than 5 flights: %d", len(flights)) | ||
} | ||
} | ||
|
||
func TestGetFlightsUSD(t *testing.T) { | ||
departureDate, err := time.Parse("2006-01-02", "2023-10-01") | ||
if err != nil { | ||
t.Fatalf("Error while creating departure date") | ||
} | ||
returnDate, err := time.Parse("2006-01-02", "2023-10-08") | ||
if err != nil { | ||
t.Fatalf("Error while creating return date") | ||
} | ||
|
||
flights, err := GetFlights(departureDate, returnDate, "Wrocław", "Madryt", currency.USD) | ||
if err != nil { | ||
t.Fatalf(err.Error()) | ||
} | ||
|
||
if len(flights) < 5 { | ||
t.Fatalf("received flights array contains less than 5 flights: %d", len(flights)) | ||
} | ||
} |
Oops, something went wrong.