Initial commit for backend

This commit is contained in:
Valentin Brandl 2019-07-27 16:24:13 +02:00
parent 06bbc5b3ed
commit 9c13cb06bb
No known key found for this signature in database
GPG Key ID: 30D341DD34118D7D
6 changed files with 362 additions and 0 deletions

12
frontend/.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
# Created by https://www.gitignore.io/api/elm
# Edit at https://www.gitignore.io/?templates=elm
### Elm ###
# elm-package generated files
elm-stuff
# elm-repl generated files
repl-temp-*
# End of https://www.gitignore.io/api/elm
index.html

28
frontend/elm.json Normal file
View File

@ -0,0 +1,28 @@
{
"type": "application",
"source-directories": [
"src"
],
"elm-version": "0.19.0",
"dependencies": {
"direct": {
"elm/browser": "1.0.1",
"elm/core": "1.0.2",
"elm/html": "1.0.0"
},
"indirect": {
"elm/json": "1.1.3",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.2"
}
},
"test-dependencies": {
"direct": {
"elm-explorations/test": "1.2.2"
},
"indirect": {
"elm/random": "1.0.0"
}
}
}

45
frontend/src/Data.elm Normal file
View File

@ -0,0 +1,45 @@
module Data exposing (Provider(..), Url, pathSeparator, toHost, toUrl)
hostname : String
hostname =
"https://cdn.hitsofcode.com/"
type Provider
= GitHub
| Bitbucket
type alias Url =
{ prov : Provider
, user : String
, repo : String
, gitref : String
, file : String
}
toHost : Provider -> String
toHost prov =
case prov of
GitHub ->
"github/"
Bitbucket ->
"bitbucket/"
pathSeparator : Provider -> String
pathSeparator prov =
case prov of
GitHub ->
"blob"
Bitbucket ->
"src"
toUrl : Url -> String
toUrl { prov, user, repo, gitref, file } =
hostname ++ toHost prov ++ String.join "/" [ user, repo, pathSeparator prov, gitref, file ]

98
frontend/src/Main.elm Normal file
View File

@ -0,0 +1,98 @@
module Main exposing (Model, Msg(..), init, main, update, view)
import Browser
import Data exposing (Url, toHost, toUrl)
import Html exposing (Html, br, div, input, table, td, text, tr)
import Html.Attributes exposing (disabled, placeholder, style, value)
import Html.Events exposing (onInput)
import Parse exposing (parseUrl)
type Msg
= UrlChange String
type alias Model =
{ url : String
, parsed : Maybe Url
}
init : Model
init =
{ url = ""
, parsed = Nothing
}
update : Msg -> Model -> Model
update msg state =
case msg of
UrlChange newUrl ->
{ state | url = newUrl, parsed = parseUrl newUrl }
renderUrl : Url -> Html msg
renderUrl { prov, user, repo, file } =
div myStyle
[ table myStyle
[ tr myStyle
[ td myStyle [ text "host" ]
, td myStyle [ text (toHost prov) ]
]
, tr []
[ td myStyle [ text "user" ]
, td myStyle [ text user ]
]
, tr myStyle
[ td myStyle [ text "repo" ]
, td myStyle [ text repo ]
]
, tr myStyle
[ td myStyle [ text "file" ]
, td myStyle [ text file ]
]
]
]
renderMUrl : Maybe Url -> Html msg
renderMUrl mUrl =
mUrl
|> Maybe.map renderUrl
|> Maybe.withDefault (div myStyle [ text "Parse Error" ])
displayMUrl : Maybe Url -> String
displayMUrl mUrl =
mUrl
|> Maybe.map toUrl
|> Maybe.withDefault ""
myStyle : List (Html.Attribute msg)
myStyle =
[ style "width" "100%" ]
myStyle2 : List (Html.Attribute msg) -> List (Html.Attribute msg)
myStyle2 =
List.append myStyle
view : Model -> Html Msg
view state =
div myStyle
[ input (myStyle2 [ placeholder "URL to parse", value state.url, onInput UrlChange ]) []
, div myStyle
[ text "Parsed URL: "
, br [] []
, renderMUrl state.parsed
]
, input (myStyle2 [ placeholder "https://host/<service>/<user>/<repo>/<gitref>/<file>", disabled True, value (displayMUrl state.parsed) ]) []
]
main : Program () Model Msg
main =
Browser.sandbox { init = init, update = update, view = view }

87
frontend/src/Parse.elm Normal file
View File

@ -0,0 +1,87 @@
module Parse exposing (parseUrl)
import Data exposing (Provider(..), Url, pathSeparator)
parseUrl : String -> Maybe Url
parseUrl url =
stripProtocol url
|> splitProvider
|> Maybe.andThen splitOfHead
|> Maybe.andThen splitOfHead
|> Maybe.andThen splitOfHead
|> Maybe.andThen splitOfHead
|> Maybe.andThen
(\( ( ( ( ( prov, user ), repo ), separator ), gitref ), file ) ->
if List.isEmpty file || (separator /= pathSeparator prov) then
Nothing
else
Just
{ prov = prov
, user = user
, repo = repo
, gitref = gitref
, file = String.join "/" file
}
)
splitOfHead : ( a, List b ) -> Maybe ( ( a, b ), List b )
splitOfHead ( head, tail ) =
splitPart tail
|> Maybe.map (\( h, t ) -> ( ( head, h ), t ))
stripProtocol : String -> String
stripProtocol url =
let
index =
String.indexes "://" url
|> List.head
|> Maybe.withDefault -3
in
String.dropLeft (index + 3) url
parseProvider : String -> Maybe Provider
parseProvider prov =
case String.toLower prov of
"github.com" ->
Just GitHub
"bitbucket.org" ->
Just Bitbucket
_ ->
Nothing
splitProvider : String -> Maybe ( Provider, List String )
splitProvider url =
let
split =
String.split "/" url
parts =
splitPart split
in
parts
|> Maybe.andThen
(\( head, tail ) ->
parseProvider head
|> Maybe.map (\prov -> ( prov, tail ))
)
splitPart : List a -> Maybe ( a, List a )
splitPart parts =
let
head =
List.head parts
tail =
List.tail parts
in
head
|> Maybe.andThen (\h -> Maybe.map (\t -> ( h, t )) tail)

View File

@ -0,0 +1,92 @@
module ParseTest exposing
( invalidHostInUrlBitbucket
, invalidHostInUrlGitHub
, invalidUrlBitbucket
, invalidUrlGitHub
, validHttpUrlBitbucket
, validHttpUrlGitHub
, validHttpsUrlBitbucket
, validHttpsUrlGitHub
, validUrlWithoutProtocolBitbucket
, validUrlWithoutProtocolGitHub
)
import Data exposing (Provider(..), Url)
import Expect
import Parse exposing (parseUrl)
import Test exposing (Test, test)
expectedUrl : Provider -> Url
expectedUrl prov =
{ prov = prov, user = "user", repo = "repo", gitref = "master", file = "README.md" }
expectedGitHubUrl : Url
expectedGitHubUrl =
expectedUrl GitHub
expectedBitbucketUrl : Url
expectedBitbucketUrl =
expectedUrl Bitbucket
validHttpsUrlGitHub : Test
validHttpsUrlGitHub =
test "Parsing Valid HTTPS URL for GitHub"
(\_ -> Expect.equal (Just expectedGitHubUrl) (parseUrl "https://GiThUb.CoM/user/repo/blob/master/README.md"))
validHttpUrlGitHub : Test
validHttpUrlGitHub =
test "Parsing Valid HTTP URL for GitHub"
(\_ -> Expect.equal (Just expectedGitHubUrl) (parseUrl "http://GiThUb.CoM/user/repo/blob/master/README.md"))
validUrlWithoutProtocolGitHub : Test
validUrlWithoutProtocolGitHub =
test "Parsing Valid URL without Protocol for GitHub"
(\_ -> Expect.equal (Just expectedGitHubUrl) (parseUrl "GiThUb.CoM/user/repo/blob/master/README.md"))
invalidUrlGitHub : Test
invalidUrlGitHub =
test "Parsing Invalid URL for GitHub"
(\_ -> Expect.equal Nothing (parseUrl "https://GiThUb.CoM/user"))
invalidHostInUrlGitHub : Test
invalidHostInUrlGitHub =
test "Parsing Invalid Host in URL for GitHub"
(\_ -> Expect.equal Nothing (parseUrl "https://example.com/user/repo/blob/master/README.md"))
validHttpsUrlBitbucket : Test
validHttpsUrlBitbucket =
test "Parsing Valid HTTPS URL for Bitbucket"
(\_ -> Expect.equal (Just expectedBitbucketUrl) (parseUrl "https://bItBuCkEt.OrG/user/repo/src/master/README.md"))
validHttpUrlBitbucket : Test
validHttpUrlBitbucket =
test "Parsing Valid HTTP URL for Bitbucket"
(\_ -> Expect.equal (Just expectedBitbucketUrl) (parseUrl "http://BiTbUcKeT.oRg/user/repo/src/master/README.md"))
validUrlWithoutProtocolBitbucket : Test
validUrlWithoutProtocolBitbucket =
test "Parsing Valid URL without Protocol for Bitbucket"
(\_ -> Expect.equal (Just expectedBitbucketUrl) (parseUrl "bitbucket.org/user/repo/src/master/README.md"))
invalidUrlBitbucket : Test
invalidUrlBitbucket =
test "Parsing Invalid URL for Bitbucket"
(\_ -> Expect.equal Nothing (parseUrl "https://bitBucket.ORG/user"))
invalidHostInUrlBitbucket : Test
invalidHostInUrlBitbucket =
test "Parsing Invalid Host in URL for Bitbucket"
(\_ -> Expect.equal Nothing (parseUrl "https://example.com/user/repo/blob/src/README.md"))