Skip to content

Commit

Permalink
update feed
Browse files Browse the repository at this point in the history
  • Loading branch information
its-felix committed Nov 6, 2024
1 parent 8a060b0 commit c4dc459
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 27 deletions.
16 changes: 9 additions & 7 deletions go/api/data/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"slices"
"strconv"
"strings"
"time"
)

var metroAreaMapping = map[string][2]string{
Expand Down Expand Up @@ -366,27 +367,28 @@ func (h *Handler) FlightSchedule(ctx context.Context, fn common.FlightNumber) (*
})
}

func (h *Handler) Flight(ctx context.Context, fn common.FlightNumber, departureDateUTC xtime.LocalDate, departureAirport string, allowCodeShare bool) (*common.Flight, error) {
func (h *Handler) Flight(ctx context.Context, fn common.FlightNumber, departureDateUTC xtime.LocalDate, departureAirport string, allowCodeShare bool) (*common.Flight, time.Time, error) {
var flights []*common.Flight
if err := adapt.S3GetJson(ctx, h.s3c, h.bucket, "processed/flights/"+departureDateUTC.Time(nil).Format("2006/01/02")+".json", &flights); err != nil {
lastModified, err := adapt.S3GetJsonWithLastModified(ctx, h.s3c, h.bucket, "processed/flights/"+departureDateUTC.Time(nil).Format("2006/01/02")+".json", &flights)
if err != nil {
if adapt.IsS3NotFound(err) {
return nil, nil
return nil, lastModified, nil
} else {
return nil, err
return nil, lastModified, err
}
}

for _, f := range flights {
if f.DepartureAirport == departureAirport {
if f.Number() == fn {
return f, nil
return f, lastModified, nil
} else if _, ok := f.CodeShares[fn]; allowCodeShare && ok {
return f, nil
return f, lastModified, nil
}
}
}

return nil, nil
return nil, lastModified, nil
}

func (h *Handler) FlightNumbers(ctx context.Context, prefix string, limit int) ([]common.FlightNumber, error) {
Expand Down
58 changes: 39 additions & 19 deletions go/api/web/feed.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,22 @@ import (
"io"
"maps"
"net/http"
"net/url"
"slices"
"strings"
"time"
)

func NewFlightUpdateFeedEndpoint(dh *data.Handler, contentType string, writer func(*feeds.Feed, io.Writer) error) echo.HandlerFunc {
feedContent := func(f *common.Flight) string {
buildFeedId := func(fn common.FlightNumber, departureDateUtc xtime.LocalDate, departureAirport string) string {
q := make(url.Values)
q.Set("departure_airport", departureAirport)
q.Set("departure_date_utc", departureDateUtc.String())

return fmt.Sprintf("https://explore.flights/flight/%s?%s", fn.String(), q.Encode())
}

buildFeedContent := func(f *common.Flight) string {
content := fmt.Sprintf(
`
Flight %s from %s to %s
Expand Down Expand Up @@ -54,42 +63,53 @@ Codeshares: %+v
return echo.NewHTTPError(http.StatusBadRequest, err)
}

feedId := baseUrl(c) + fmt.Sprintf("/%s/%s/%s", fn.String(), departureDate.String(), departureAirport)
link := &feeds.Link{Href: fmt.Sprintf("https://explore.flights/flight/%s", fn.String())}
feedId := buildFeedId(fn, departureDate, departureAirport)
link := &feeds.Link{
Href: feedId,
Rel: "self",
Type: "text/html",
}

feed := &feeds.Feed{
Id: feedId,
Title: fmt.Sprintf("Flight %s from %s on %s (UTC)", fn.String(), departureAirport, departureDate.String()),
Link: link,
}

f, err := dh.Flight(c.Request().Context(), fn, departureDate, departureAirport, true)
f, lastModified, err := dh.Flight(c.Request().Context(), fn, departureDate, departureAirport, true)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError)
}

if f == nil {
now := time.Now()
created := time.Date(2024, time.May, 1, 0, 0, 0, 0, time.UTC)

feed.Created = now
feed.Updated = now
feed.Created = created
feed.Updated = lastModified
feed.Items = append(feed.Items, &feeds.Item{
Id: feedId,
Title: "Flight no longer available",
Link: link,
Created: now,
Updated: now,
Content: "The flight is no longer available",
Id: feedId,
IsPermaLink: "false",
Title: "Flight no longer available",
Link: link,
Created: created,
Updated: lastModified,
Content: "The flight is no longer available",
Description: "The flight is no longer available",
})
} else {
feed.Created = f.Metadata.CreationTime
feed.Updated = f.Metadata.UpdateTime

content := buildFeedContent(f)
feed.Items = append(feed.Items, &feeds.Item{
Id: feedId,
Title: fmt.Sprintf("Flight %s from %s to %s on %s (local) updated", fn.String(), f.DepartureAirport, f.ArrivalAirport, f.DepartureTime.Format(time.DateOnly)),
Link: link,
Created: f.Metadata.CreationTime,
Updated: f.Metadata.UpdateTime,
Content: feedContent(f),
Id: feedId,
IsPermaLink: "false",
Title: fmt.Sprintf("Flight %s from %s to %s on %s (local) updated", fn.String(), f.DepartureAirport, f.ArrivalAirport, f.DepartureTime.Format(time.DateOnly)),
Link: link,
Created: f.Metadata.CreationTime,
Updated: f.Metadata.UpdateTime,
Content: content,
Description: content,
})
}

Expand Down
20 changes: 20 additions & 0 deletions go/common/adapt/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
"io"
"time"
)

type S3Getter interface {
Expand All @@ -25,6 +26,10 @@ func S3GetJson(ctx context.Context, s3c S3Getter, bucket, key string, v any) err
return S3Get(ctx, s3c, bucket, key, readJson(v))
}

func S3GetJsonWithLastModified(ctx context.Context, s3c S3Getter, bucket, key string, v any) (time.Time, error) {
return S3GetWithLastModified(ctx, s3c, bucket, key, readJson(v))
}

func S3GetRaw(ctx context.Context, s3c S3Getter, bucket, key string) ([]byte, error) {
var b []byte
return b, S3Get(ctx, s3c, bucket, key, readRaw(&b))
Expand All @@ -44,6 +49,21 @@ func S3Get(ctx context.Context, s3c S3Getter, bucket, key string, fn func(r io.R
return fn(resp.Body)
}

func S3GetWithLastModified(ctx context.Context, s3c S3Getter, bucket, key string, fn func(r io.Reader) error) (time.Time, error) {
resp, err := s3c.GetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})

if err != nil {
var def time.Time
return def, err
}

defer resp.Body.Close()
return *resp.LastModified, fn(resp.Body)
}

func S3PutJson(ctx context.Context, s3c S3Putter, bucket, key string, v any) error {
b, err := json.Marshal(v)
if err != nil {
Expand Down
12 changes: 11 additions & 1 deletion ui/src/pages/flight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,12 @@ function TableFilter({ query, setQuery, summary }: TableFilterProps) {
propertyLabel: 'Operating Day',
groupValuesLabel: 'Operating Day values',
},
{
key: 'departure_date_utc',
operators: ['=', '>=', '>', '<=', '<'].map((op) => buildDateOperator(op)),
propertyLabel: 'Departure Date UTC',
groupValuesLabel: 'Departure Date UTC values',
},
]}
/>
);
Expand Down Expand Up @@ -801,6 +807,10 @@ function evaluateTokenSingle(flight: ScheduledFlight, propertyKey: string, opera
case 'operating_day':
cmpResult = flight.departureTime.weekday.toString(10).localeCompare(filterValue);
break;

case 'departure_date_utc':
cmpResult = flight.departureTime.toUTC().toISODate().localeCompare(filterValue);
break;
}

switch (operator) {
Expand Down Expand Up @@ -828,7 +838,7 @@ function evaluateTokenSingle(flight: ScheduledFlight, propertyKey: string, opera

function parseSearchParams(v: URLSearchParams): PropertyFilterProps.Query | null {
const tokens: Array<PropertyFilterProps.Token> = [];
for (const prop of ['departure_time', 'aircraft_type', 'aircraft_configuration_version', 'departure_airport', 'arrival_airport', 'operating_day']) {
for (const prop of ['departure_time', 'aircraft_type', 'aircraft_configuration_version', 'departure_airport', 'arrival_airport', 'operating_day', 'departure_date_utc']) {
const values = v.getAll(prop);
if (values.length >= 1) {
if (values.length === 1) {
Expand Down

0 comments on commit c4dc459

Please sign in to comment.