From 97d5e9e9c225f2beb07cfbfd4f758758407e5d8e Mon Sep 17 00:00:00 2001 From: Christine Dodrill Date: Wed, 30 Dec 2020 23:23:12 -0500 Subject: [PATCH] sina: package tracking via orangeconnex Signed-off-by: Christine Dodrill --- .../src/api/package_tracking/orangeconnex.rs | 20 +++- backend/src/main.rs | 5 +- backend/src/models.rs | 4 +- backend/src/web/orange_connex.rs | 2 +- sina/src/Layout.elm | 7 +- sina/src/Main.elm | 36 ++++++++ sina/src/Mi/PackageTracking/OrangeConnex.elm | 64 +++++++++++++ sina/src/Model.elm | 11 +++ sina/src/Page/OrangeConnex.elm | 92 +++++++++++++++++++ sina/src/Page/Packages.elm | 17 ++++ sina/src/Route.elm | 20 ++-- 11 files changed, 261 insertions(+), 17 deletions(-) create mode 100644 sina/src/Mi/PackageTracking/OrangeConnex.elm create mode 100644 sina/src/Page/OrangeConnex.elm create mode 100644 sina/src/Page/Packages.elm diff --git a/backend/src/api/package_tracking/orangeconnex.rs b/backend/src/api/package_tracking/orangeconnex.rs index a0f586a..137a146 100644 --- a/backend/src/api/package_tracking/orangeconnex.rs +++ b/backend/src/api/package_tracking/orangeconnex.rs @@ -22,6 +22,21 @@ pub fn track(conn: MainDatabase, tn: StringBody, tok: paseto::Token) -> Result Result>> { + use schema::orangeconnex_packages; + + Ok(Json( + orangeconnex_packages::table + .load::(&*conn) + .map_err(Error::Database)?, + )) +} + #[get("/packages/orangeconnex/status?")] #[instrument(skip(conn), err)] pub fn status( @@ -29,10 +44,11 @@ pub fn status( tn: String, tok: paseto::Token, ) -> Result>> { - use schema::orangeconnex_traces; + use schema::orangeconnex_traces::dsl::*; Ok(Json( - orangeconnex_traces::table + orangeconnex_traces + .filter(tracking_number.eq(tn)) .load::(&*conn) .map_err(Error::Database)?, )) diff --git a/backend/src/main.rs b/backend/src/main.rs index 5b4744f..4a9ba50 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -70,9 +70,10 @@ fn main() -> Result<()> { .mount( "/api", routes![ - api::package_tracking::orangeconnex::track, - api::package_tracking::orangeconnex::status, + api::package_tracking::orangeconnex::list, api::package_tracking::orangeconnex::recieved, + api::package_tracking::orangeconnex::status, + api::package_tracking::orangeconnex::track, api::posse::notify, api::posse::refresh_blog, api::switch::current_front, diff --git a/backend/src/models.rs b/backend/src/models.rs index a273288..9e5b093 100644 --- a/backend/src/models.rs +++ b/backend/src/models.rs @@ -73,7 +73,7 @@ pub struct Blogpost { pub title: String, } -#[derive(Queryable, Associations, Insertable, AsChangeset)] +#[derive(Queryable, Associations, Insertable, AsChangeset, Serialize)] #[table_name = "orangeconnex_packages"] pub struct OrangeConnexPackage { pub tracking_number: String, @@ -104,7 +104,7 @@ impl OrangeConnexTrace { country: t.opr_country, time_recorded: t.opr_time, time_zone: t.opr_time_zone, - ts: t.opr_timestamp, + ts: t.opr_timestamp.try_into().unwrap_or(1337), } } } diff --git a/backend/src/web/orange_connex.rs b/backend/src/web/orange_connex.rs index 6c0b693..713bf5c 100644 --- a/backend/src/web/orange_connex.rs +++ b/backend/src/web/orange_connex.rs @@ -66,7 +66,7 @@ pub struct Trace { pub opr_country: String, pub opr_time: String, pub opr_time_zone: String, - pub opr_timestamp: i32, + pub opr_timestamp: i64, } #[derive(Deserialize, Serialize, Clone, Debug)] diff --git a/sina/src/Layout.elm b/sina/src/Layout.elm index 15eb02b..66bf600 100644 --- a/sina/src/Layout.elm +++ b/sina/src/Layout.elm @@ -38,9 +38,10 @@ template title body = , a [ href "/posse" ] [ text "POSSE" ] , text " - " , a [ href "/switches" ] [ text "Switches" ] - - --, text " - " - --, a [ href "/webmentions" ] [ text "WebMentions" ] + , text " - " + , a [ href "/packages" ] [ text "Packages" ] + , text " - " + , a [ href "/webmentions" ] [ text "WebMentions" ] ] , h1 [] [ text title ] ] diff --git a/sina/src/Main.elm b/sina/src/Main.elm index e28af5e..d2a1767 100644 --- a/sina/src/Main.elm +++ b/sina/src/Main.elm @@ -9,11 +9,14 @@ import Http import Json.Decode import Layout import Mi +import Mi.PackageTracking.OrangeConnex import Mi.Switch import Mi.WebMention import Model exposing (Model, Msg(..), get, init) import Page.Index import Page.Login +import Page.OrangeConnex +import Page.Packages import Page.SwitchInfo import Page.Switches import Route exposing (Route(..), routeParser) @@ -73,6 +76,20 @@ update msg model = Json.Decode.list Mi.Switch.decoder ) + FetchOCPackages -> + ( model + , get model Mi.PackageTracking.OrangeConnex.packageListURL <| + Mi.expectJson ValidateOCPackages <| + Json.Decode.list Mi.PackageTracking.OrangeConnex.decodePackage + ) + + FetchOCTraces trackingID -> + ( { model | ocTrackingID = Just trackingID } + , get model (Mi.PackageTracking.OrangeConnex.packageStatusURL trackingID) <| + Mi.expectJson ValidateOCTraces <| + Json.Decode.list Mi.PackageTracking.OrangeConnex.decodeTrace + ) + ValidateSwitchByID result -> if_okay result <| \data -> @@ -95,6 +112,16 @@ update msg model = , Nav.pushUrl model.navKey "/" ) + ValidateOCPackages result -> + if_okay result <| + \data -> + ( { model | ocPackages = Just data }, Cmd.none ) + + ValidateOCTraces result -> + if_okay result <| + \data -> + ( { model | ocTraces = Just data }, Cmd.none ) + ClickLink urlRequest -> case urlRequest of Internal url -> @@ -124,6 +151,15 @@ view model = SwitchID _ -> Page.SwitchInfo.view model + Packages -> + Page.Packages.view + + OCPackages -> + Page.OrangeConnex.viewList model + + OCPackage packageID -> + Page.OrangeConnex.viewPackage { model | ocTrackingID = Just packageID } + _ -> Layout.template "Oh noes" [ p [] [ text "todo: implement this 404 page" ] ] diff --git a/sina/src/Mi/PackageTracking/OrangeConnex.elm b/sina/src/Mi/PackageTracking/OrangeConnex.elm new file mode 100644 index 0000000..8bed31f --- /dev/null +++ b/sina/src/Mi/PackageTracking/OrangeConnex.elm @@ -0,0 +1,64 @@ +module Mi.PackageTracking.OrangeConnex exposing (..) + +import Json.Decode as D +import Json.Encode as E +import Url.Builder as UB + + +type alias Package = + { tracking_number : String + , recieved : Bool + } + + +decodePackage : D.Decoder Package +decodePackage = + D.map2 Package + (D.field "tracking_number" D.string) + (D.field "recieved" D.bool) + + +type alias Trace = + { id : String + , tracking_number : String + , description : String + , city : Maybe String + , country : String + , time_recorded : String + , time_zone : String + , ts : Int + } + + +decodeTrace : D.Decoder Trace +decodeTrace = + D.map8 Trace + (D.field "id" D.string) + (D.field "tracking_number" D.string) + (D.field "description" D.string) + (D.field "city" (D.nullable D.string)) + (D.field "country" D.string) + (D.field "time_recorded" D.string) + (D.field "time_zone" D.string) + (D.field "ts" D.int) + + +packageListURL : String +packageListURL = + UB.absolute + [ "api", "packages", "orangeconnex" ] + [] + + +packageStatusURL : String -> String +packageStatusURL trackingNumber = + UB.absolute + [ "api", "packages", "orangeconnex", "status" ] + [ UB.string "tn" trackingNumber ] + + +markRecievedURL : String -> String +markRecievedURL trackingNumber = + UB.absolute + [ "api", "packages", "orangeconnex", "delivered" ] + [ UB.string "tn" trackingNumber ] diff --git a/sina/src/Model.elm b/sina/src/Model.elm index 8e85936..a7a1624 100644 --- a/sina/src/Model.elm +++ b/sina/src/Model.elm @@ -5,6 +5,7 @@ import Browser.Navigation as Nav import Http import Mi import Mi.POSSE +import Mi.PackageTracking.OrangeConnex as OrangeConnex import Mi.Switch exposing (Switch) import Mi.WebMention exposing (WebMention) import Route exposing (Route, routeParser) @@ -26,6 +27,9 @@ type alias Model = , switchByID : Maybe Switch , webMentionByID : Maybe WebMention , post : Mi.POSSE.Post + , ocTrackingID : Maybe String + , ocPackages : Maybe (List OrangeConnex.Package) + , ocTraces : Maybe (List OrangeConnex.Trace) } @@ -47,10 +51,14 @@ type Msg | FetchSwitch String | NextSwitchesPage | PrevSwitchesPage + | FetchOCPackages + | FetchOCTraces String | ValidateToken (Result Http.Error Mi.TokenData) | ValidateSwitchByID (Result Http.Error Switch) | ValidateFront (Result Http.Error Switch) | ValidateSwitches (Result Http.Error (List Switch)) + | ValidateOCPackages (Result Http.Error (List OrangeConnex.Package)) + | ValidateOCTraces (Result Http.Error (List OrangeConnex.Trace)) | ClearError @@ -69,6 +77,9 @@ init _ url key = , switchByID = Nothing , webMentionByID = Nothing , post = Mi.POSSE.init + , ocTrackingID = Nothing + , ocPackages = Nothing + , ocTraces = Nothing } , Nav.pushUrl key "/login" ) diff --git a/sina/src/Page/OrangeConnex.elm b/sina/src/Page/OrangeConnex.elm new file mode 100644 index 0000000..99ad805 --- /dev/null +++ b/sina/src/Page/OrangeConnex.elm @@ -0,0 +1,92 @@ +module Page.OrangeConnex exposing (viewList, viewPackage) + +import Browser exposing (Document) +import Html exposing (a, br, button, h2, img, p, span, table, td, text, th, tr) +import Html.Attributes exposing (height, href, src, style, width) +import Html.Events exposing (onClick) +import Iso8601 +import Layout exposing (template) +import Mi.PackageTracking.OrangeConnex exposing (Package, Trace) +import Model exposing (Msg(..)) + + +type alias Model a = + { a + | ocTrackingID : Maybe String + , ocPackages : Maybe (List Package) + , ocTraces : Maybe (List Trace) + } + + +viewList : Model a -> Document Msg +viewList { ocPackages } = + case ocPackages of + Nothing -> + Layout.template "Loading" [ text "please wait..." ] + + Just packages -> + let + heading = + tr + [] + [ th [] [ text "ID" ] + , th [] [ text "recieved" ] + ] + + stringFromBool value = + if value then + "True" + + else + "False" + + rowify data = + tr + [] + [ td + [] + [ a + [ href <| "/packages/orangeconnex/" ++ data.tracking_number, onClick <| FetchOCTraces data.tracking_number ] + [ text data.tracking_number ] + ] + , td [] [ text <| stringFromBool data.recieved ] + ] + + contents = + List.map rowify packages + in + Layout.template "OrangeConnex Packages" + [ table [] <| [ heading ] ++ contents ] + + +viewPackage : Model a -> Document Msg +viewPackage { ocTraces, ocTrackingID } = + case ocTraces of + Nothing -> + Layout.template "Loading..." [ span [] [] ] + + Just traces -> + let + heading = + tr + [] + [ th [] [ text "Message" ] + , th [] [ text "City" ] + , th [] [ text "Country" ] + ] + + rowify data = + tr + [] + [ td [] [ text data.description ] + , td [] [ text <| Maybe.withDefault "" data.city ] + , td [] [ text data.country ] + ] + + contents = + List.map rowify traces + + title = + "Info on package " ++ Maybe.withDefault "" ocTrackingID + in + Layout.template title [ table [] <| [ heading ] ++ contents ] diff --git a/sina/src/Page/Packages.elm b/sina/src/Page/Packages.elm new file mode 100644 index 0000000..e3bb738 --- /dev/null +++ b/sina/src/Page/Packages.elm @@ -0,0 +1,17 @@ +module Page.Packages exposing (view) + +import Browser exposing (Document) +import Html exposing (a, text) +import Html.Attributes exposing (href) +import Html.Events exposing (onClick) +import Iso8601 +import Layout exposing (basic, template) +import Mi +import Model exposing (Msg(..)) + + +view : Document Msg +view = + template + "Package Deliveries" + [ a [ href "/packages/orangeconnex", onClick FetchOCPackages ] [ text "OrangeConnex" ] ] diff --git a/sina/src/Route.elm b/sina/src/Route.elm index 6519e47..194efca 100644 --- a/sina/src/Route.elm +++ b/sina/src/Route.elm @@ -12,16 +12,22 @@ type Route | MakeSwitch | WebMentionLog | WebMentionID String + | Packages + | OCPackages + | OCPackage String routeParser : Parser (Route -> a) a routeParser = oneOf - [ map Index (s "") - , map Login (s "login") - , map SwitchLog (s "switches") - , map SwitchID (s "switches" string) - , map MakeSwitch (s "switches" s "log") - , map WebMentionLog (s "webmentions") - , map WebMentionID (s "webmentions" string) + [ map Index <| s "" + , map Login <| s "login" + , map SwitchLog <| s "switches" + , map SwitchID <| s "switches" string + , map MakeSwitch <| s "switches" s "log" + , map WebMentionLog <| s "webmentions" + , map WebMentionID <| s "webmentions" string + , map Packages <| s "packages" + , map OCPackages <| s "packages" s "orangeconnex" + , map OCPackage <| s "packages" s "orangeconnex" string ]