feat: initial commit
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
@@ -0,0 +1 @@
|
||||
.idea
|
||||
@@ -0,0 +1,33 @@
|
||||
variables:
|
||||
DOCKER_HOST: tcp://docker:2375
|
||||
DOCKER_DRIVER: overlay2
|
||||
|
||||
stages:
|
||||
- build
|
||||
- deploy-prod
|
||||
|
||||
image: buildtool/build-tools:0.0.11
|
||||
services:
|
||||
- docker:dind
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- build
|
||||
- push
|
||||
artifacts:
|
||||
paths:
|
||||
- release/
|
||||
- coverage.html
|
||||
- k8s
|
||||
|
||||
deploy-prod:
|
||||
stage: deploy-prod
|
||||
before_script:
|
||||
- echo Deploy to prod
|
||||
script:
|
||||
- deploy prod
|
||||
only:
|
||||
- master
|
||||
environment:
|
||||
name: prod
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
FROM golang:1.12 as build
|
||||
ARG GITLAB_USER
|
||||
ARG GITLAB_TOKEN
|
||||
WORKDIR /build
|
||||
ENV CGO_ENABLED=0
|
||||
ENV GOPRIVATE=gitlab.com/unboundsoftware/shiny
|
||||
RUN git config --global url."https://${GITLAB_USER}:${GITLAB_TOKEN}@gitlab.com/unboundsoftware/shiny/".insteadOf "https://gitlab.com/unboundsoftware/shiny/"
|
||||
ADD . /build
|
||||
RUN if [ $(go mod tidy -v 2>&1 | grep -c unused) != 0 ]; then echo "Unused modules, please run 'go mod tidy'"; exit 1; fi
|
||||
RUN go fmt ./...
|
||||
RUN go vet ./...
|
||||
RUN CGO_ENABLED=1 go test -mod=readonly -race -coverprofile=.testCoverage.txt.tmp -covermode=atomic -coverpkg=$(go list ./... | tr '\n' , | sed 's/,$//') ./...
|
||||
RUN cat .testCoverage.txt.tmp | grep -v generated.go | grep -v _gen.go > .testCoverage.txt
|
||||
RUN go tool cover -html=.testCoverage.txt -o coverage.html
|
||||
RUN go tool cover -func=.testCoverage.txt
|
||||
|
||||
RUN GOOS=linux GOARCH=amd64 go build \
|
||||
-tags prod \
|
||||
-a -installsuffix cgo \
|
||||
-mod=readonly \
|
||||
-o /release/service \
|
||||
-ldflags '-w -s' \
|
||||
./cmd/service/service.go
|
||||
|
||||
FROM scratch
|
||||
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=build /release/service /
|
||||
COPY migrations /migrations
|
||||
CMD ["/service"]
|
||||
+5062
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
module gitlab.com/unboundsoftware/dancefinder/dancefinder_go
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/99designs/gqlgen v0.10.2
|
||||
github.com/agnivade/levenshtein v1.0.2 // indirect
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
||||
github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7
|
||||
github.com/codegangsta/negroni v1.0.0 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/go-sql-driver/mysql v1.4.1
|
||||
github.com/golang-migrate/migrate/v4 v4.7.1
|
||||
github.com/gorilla/mux v1.7.3 // indirect
|
||||
github.com/gorilla/websocket v1.4.0 // indirect
|
||||
github.com/jmoiron/sqlx v1.2.0
|
||||
github.com/mitchellh/mapstructure v1.1.2 // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/urfave/negroni v1.0.0
|
||||
github.com/vektah/gqlparser v1.2.0
|
||||
gitlab.com/sparetimecoders/goamqp v0.1.0
|
||||
google.golang.org/appengine v1.6.5 // indirect
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||
)
|
||||
@@ -0,0 +1,331 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
||||
github.com/99designs/gqlgen v0.10.2 h1:FfjCqIWejHDJeLpQTI0neoZo5vDO3sdo5oNCucet3A0=
|
||||
github.com/99designs/gqlgen v0.10.2/go.mod h1:aDB7oabSAyZ4kUHLEySsLxnWrBy3lA0A2gWKU+qoHwI=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/ClickHouse/clickhouse-go v1.3.12/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
|
||||
github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q=
|
||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
github.com/agnivade/levenshtein v1.0.2 h1:xKF7WlEzoa+ZVkzBxy0ukdzI2etYiWGlTPMNTBGncKI=
|
||||
github.com/agnivade/levenshtein v1.0.2/go.mod h1:JLvzGblJATanj48SD0YhHTEFGkWvw3ASLFWSiMIFXsE=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7 h1:irR1cO6eek3n5uquIVaRAsQmZnlsfPuHNz31cXo4eyk=
|
||||
github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM=
|
||||
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
||||
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/caarlos0/env v3.5.0+incompatible h1:Yy0UN8o9Wtr/jGHZDpCBLpNrzcFLLM2yixi/rBrKyJs=
|
||||
github.com/caarlos0/env v3.5.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
|
||||
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
|
||||
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
|
||||
github.com/containerd/containerd v1.2.7 h1:8lqLbl7u1j3MmiL9cJ/O275crSq7bfwUayvvatEupQk=
|
||||
github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
|
||||
github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg=
|
||||
github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc=
|
||||
github.com/cznic/internal v0.0.0-20180608152220-f44710a21d00/go.mod h1:olo7eAdKwJdXxb55TKGLiJ6xt1H0/tiiRCWKVLmtjY4=
|
||||
github.com/cznic/lldb v1.1.0/go.mod h1:FIZVUmYUVhPwRiPzL8nD/mpFcJ/G7SSXjjXYG4uRI3A=
|
||||
github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
|
||||
github.com/cznic/ql v1.2.0/go.mod h1:FbpzhyZrqr0PVlK6ury+PoW3T0ODUV22OeWIxcaOrSE=
|
||||
github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
|
||||
github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
|
||||
github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dhui/dktest v0.3.0 h1:kwX5a7EkLcjo7VpsPQSYJcKGbXBXdjI9FGjuUj1jn6I=
|
||||
github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc=
|
||||
github.com/docker/distribution v2.7.0+incompatible h1:neUDAlf3wX6Ml4HdqTrbcOHXtfRN0TFIwt6YFL7N9RU=
|
||||
github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v0.7.3-0.20190103212154-2b7e084dc98b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v0.7.3-0.20190817195342-4760db040282 h1:mzrx39dGtGq0VEnTHjnakmczd4uFbhx2cZU3BJDsLdc=
|
||||
github.com/docker/docker v0.7.3-0.20190817195342-4760db040282/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk=
|
||||
github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
|
||||
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang-migrate/migrate/v4 v4.7.1 h1:AkKizKQ+gkL1xk47xe6RDBLSZg3GITTXq6LbBt62NJw=
|
||||
github.com/golang-migrate/migrate/v4 v4.7.1/go.mod h1:2MAJMy62WLqWFu2X0UaGfqPuvy7iRhx8/QRn75lm1lo=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ=
|
||||
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
|
||||
github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
|
||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE=
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw=
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
|
||||
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
||||
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
|
||||
github.com/vektah/gqlparser v1.2.0 h1:ntkSCX7F5ZJKl+HIVnmLaO269MruasVpNiMOjX9kgo0=
|
||||
github.com/vektah/gqlparser v1.2.0/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74=
|
||||
github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
|
||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
||||
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
|
||||
gitlab.com/sparetimecoders/goamqp v0.1.0 h1:wyFS6kVMh9jSRFlCySPqkRciRBt6vC044pL8HsFt+OE=
|
||||
gitlab.com/sparetimecoders/goamqp v0.1.0/go.mod h1:Qef7S4y4fXW0GVjEodOXlIhiH1NWMTqEGH/BCcQCk5U=
|
||||
go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190426135247-a129542de9ae h1:mQLHiymj/JXKnnjc62tb7nD5pZLs940/sXJu+Xp3DBA=
|
||||
golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd h1:oMEQDWVXVNpceQoVd1JN3CQ7LYJJzs5qWqZIUcxXHHw=
|
||||
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb h1:i1Ppqkc3WQXikh8bXiwHqAN5Rv3/qDCcRk0/Otx73BY=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k=
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
# .gqlgen.yml example
|
||||
#
|
||||
# Refer to https://gqlgen.com/config/
|
||||
# for detailed .gqlgen.yml documentation.
|
||||
|
||||
schema:
|
||||
- schema.graphql
|
||||
exec:
|
||||
filename: generated.go
|
||||
model:
|
||||
filename: models_gen.go
|
||||
resolver:
|
||||
filename: resolver.go
|
||||
type: Resolver
|
||||
autobind: []
|
||||
#directives:
|
||||
# deprecated:
|
||||
# skip_runtime: true
|
||||
# include:
|
||||
# skip_runtime: true
|
||||
# skip:
|
||||
# skip_runtime: true
|
||||
models:
|
||||
Band:
|
||||
model: gitlab.com/unboundsoftware/dancefinder/dancefinder_go.Band
|
||||
DanceHall:
|
||||
model: gitlab.com/unboundsoftware/dancefinder/dancefinder_go.DanceHall
|
||||
Event:
|
||||
model: gitlab.com/unboundsoftware/dancefinder/dancefinder_go.Event
|
||||
LocalDate:
|
||||
model: gitlab.com/unboundsoftware/dancefinder/dancefinder_go.LocalDate
|
||||
LocalDateTime:
|
||||
model: gitlab.com/unboundsoftware/dancefinder/dancefinder_go.LocalDateTime
|
||||
@@ -0,0 +1,18 @@
|
||||
apiVersion: autoscaling/v2beta1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
labels:
|
||||
app: company-service
|
||||
name: company-service
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
name: company-service
|
||||
minReplicas: 2
|
||||
maxReplicas: 4
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
targetAverageUtilization: 60
|
||||
@@ -0,0 +1,87 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: dancefinder
|
||||
name: dancefinder
|
||||
annotations:
|
||||
kubernetes.io/change-cause: "${TIMESTAMP} Deployed commit id: ${COMMIT}"
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: dancefinder
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 1
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: dancefinder
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: "app"
|
||||
operator: In
|
||||
values:
|
||||
- dancefinder
|
||||
topologyKey: kubernetes.io/hostname
|
||||
containers:
|
||||
- name: dancefinder
|
||||
resources:
|
||||
limits:
|
||||
memory: "100Mi"
|
||||
requests:
|
||||
memory: "100Mi"
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 6080
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 5
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: registry.gitlab.com/unboundsoftware/dancefinder/dancefinder:${COMMIT}
|
||||
ports:
|
||||
- name: api
|
||||
containerPort: 6080
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: dancefinder
|
||||
- secretRef:
|
||||
name: rabbitmq
|
||||
optional: true
|
||||
env:
|
||||
- name: DB_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: dancefinder-db
|
||||
key: USERNAME
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: dancefinder-db
|
||||
key: PASSWORD
|
||||
restartPolicy: Always
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: dancefinder
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
name: api
|
||||
protocol: TCP
|
||||
targetPort: 6080
|
||||
selector:
|
||||
app: dancefinder
|
||||
type: ClusterIP
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ENVIRONMENT="${1?usage: secrets.sh <environment>}"
|
||||
LASTPASS_SHARE="envconfig\\${ENVIRONMENT}"
|
||||
|
||||
kube_cmd=$(kubecmd ${ENVIRONMENT})
|
||||
|
||||
SECRET_NAME="dancefinder"
|
||||
USERNAME=$(lpass show --name "${LASTPASS_SHARE}/${SECRET_NAME}" --username)
|
||||
PASSWORD=$(lpass show --name "${LASTPASS_SHARE}/${SECRET_NAME}" --password)
|
||||
DB_NAME=$(lpass show --name "${LASTPASS_SHARE}/${SECRET_NAME}" --field=Database)
|
||||
HOST=$(lpass show --name "${LASTPASS_SHARE}/${SECRET_NAME}" --field=Hostname)
|
||||
PORT=$(lpass show --name "${LASTPASS_SHARE}/${SECRET_NAME}" --field=Port)
|
||||
|
||||
$kube_cmd delete secret ${SECRET_NAME,,} &> /dev/null || true
|
||||
$kube_cmd create secret generic \
|
||||
${SECRET_NAME,,} \
|
||||
--from-literal=POSTGRES_URL="postgres://${USERNAME}:${PASSWORD}@${HOST}:${PORT}/${DB_NAME}?sslmode=disable"
|
||||
@@ -0,0 +1,17 @@
|
||||
drop table band;
|
||||
|
||||
drop table dance_hall;
|
||||
|
||||
drop table event;
|
||||
|
||||
drop table ignored_band;
|
||||
|
||||
drop table ignored_dance_hall;
|
||||
|
||||
drop table ignored_city;
|
||||
|
||||
drop table ignored_municipality;
|
||||
|
||||
drop table ignored_state;
|
||||
|
||||
drop table origin;
|
||||
@@ -0,0 +1,84 @@
|
||||
create table band
|
||||
(
|
||||
id bigserial primary key,
|
||||
name text unique,
|
||||
created timestamp
|
||||
);
|
||||
|
||||
create table dance_hall
|
||||
(
|
||||
id bigserial primary key,
|
||||
name text,
|
||||
city text,
|
||||
municipality text,
|
||||
state text,
|
||||
latitude float8,
|
||||
longitude float8,
|
||||
created timestamp,
|
||||
unique (name, city, municipality, state)
|
||||
);
|
||||
|
||||
create unique index if not exists dance_hall_ix
|
||||
on dance_hall (name, city, municipality, state);
|
||||
|
||||
create table event
|
||||
(
|
||||
id bigserial primary key,
|
||||
date date not null,
|
||||
time text,
|
||||
band_id bigint references band (id) on delete cascade,
|
||||
dance_hall_id bigint references dance_hall (id) on delete cascade,
|
||||
extra_info text,
|
||||
created timestamp
|
||||
);
|
||||
|
||||
create unique index if not exists event_ix
|
||||
on event (date, band_id, dance_hall_id);
|
||||
|
||||
create table ignored_band
|
||||
(
|
||||
id bigint references band (id) on delete cascade,
|
||||
subject text,
|
||||
created timestamp,
|
||||
primary key (id, subject)
|
||||
);
|
||||
|
||||
create table ignored_dance_hall
|
||||
(
|
||||
id bigint references dance_hall (id) on delete cascade,
|
||||
subject text,
|
||||
created timestamp,
|
||||
primary key (id, subject)
|
||||
);
|
||||
|
||||
create table ignored_city
|
||||
(
|
||||
city text,
|
||||
subject text,
|
||||
created timestamp,
|
||||
primary key (city, subject)
|
||||
);
|
||||
|
||||
create table ignored_municipality
|
||||
(
|
||||
municipality text,
|
||||
subject text,
|
||||
created timestamp,
|
||||
primary key (municipality, subject)
|
||||
);
|
||||
|
||||
create table ignored_state
|
||||
(
|
||||
state text,
|
||||
subject text,
|
||||
created timestamp,
|
||||
primary key (state, subject)
|
||||
);
|
||||
|
||||
create table origin
|
||||
(
|
||||
origin text,
|
||||
subject text,
|
||||
created timestamp,
|
||||
primary key (origin, subject)
|
||||
);
|
||||
@@ -0,0 +1,121 @@
|
||||
package dancefinder_go
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Band
|
||||
type Band struct {
|
||||
ID *int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Created LocalDateTime `json:"created"`
|
||||
}
|
||||
|
||||
// DanceHall
|
||||
type DanceHall struct {
|
||||
ID *int `json:"id"`
|
||||
Name *string `json:"name"`
|
||||
City *string `json:"city"`
|
||||
Municipality *string `json:"municipality"`
|
||||
State *string `json:"state"`
|
||||
Latitude *float64 `json:"latitude"`
|
||||
Longitude *float64 `json:"longitude"`
|
||||
Created LocalDateTime `json:"created"`
|
||||
}
|
||||
|
||||
// Event
|
||||
type Event struct {
|
||||
ID *int `json:"id"`
|
||||
// The date of the event
|
||||
Date LocalDate `json:"date"`
|
||||
// The time of the event
|
||||
Time *string `json:"time"`
|
||||
// Additional information regarding the event
|
||||
ExtraInfo *string `json:"extraInfo" db:"extra_info"`
|
||||
Created LocalDateTime `json:"created"`
|
||||
// The band of the event
|
||||
BandId *int `json:"band" db:"band_id"`
|
||||
// The place of the event
|
||||
DanceHallId *int `json:"danceHall" db:"dance_hall_id"`
|
||||
// The driving distances and driving durations to the event from the provided origins
|
||||
Distances []*DanceHallDistance `json:"distances"`
|
||||
Latitude *float64 `db:"latitude"`
|
||||
Longitude *float64 `db:"longitude"`
|
||||
}
|
||||
|
||||
type LocalDate struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
func (y *LocalDate) UnmarshalGQL(v interface{}) error {
|
||||
timeStr, ok := v.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("points must be strings")
|
||||
}
|
||||
|
||||
if parse, e := time.Parse("2006-01-02", timeStr); e != nil {
|
||||
return fmt.Errorf("unable to parse '%s' as date", timeStr)
|
||||
} else {
|
||||
y.Time = parse
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalGQL implements the graphql.Marshaller interface
|
||||
func (y LocalDate) MarshalGQL(w io.Writer) {
|
||||
timeStr := y.Time.Format("2006-01-02")
|
||||
_, _ = w.Write([]byte(fmt.Sprintf(`"%s"`, timeStr)))
|
||||
}
|
||||
|
||||
func (y *LocalDate) UnmarshalJSON(data []byte) error {
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err != nil {
|
||||
return fmt.Errorf("date should be a string, got %s", data)
|
||||
}
|
||||
if parse, e := time.Parse("2006-01-02", str); e != nil {
|
||||
return fmt.Errorf("unable to parse '%s' as date", str)
|
||||
} else {
|
||||
y.Time = parse
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (y *LocalDate) MarshalJSON() ([]byte, error) {
|
||||
timeStr := y.Time.Format(`"2006-01-02"`)
|
||||
return []byte(timeStr), nil
|
||||
}
|
||||
|
||||
func (y *LocalDate) Scan(value interface{}) error {
|
||||
if t, ok := value.(time.Time); ok {
|
||||
y.Time = t
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("provided value is not a time.Time: %+v", value)
|
||||
}
|
||||
|
||||
type LocalDateTime time.Time
|
||||
|
||||
func (y *LocalDateTime) UnmarshalGQL(v interface{}) error {
|
||||
timeStr, ok := v.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("points must be strings")
|
||||
}
|
||||
|
||||
if parse, e := time.Parse("2006-01-02T15:04:05.000", timeStr); e != nil {
|
||||
return fmt.Errorf("unable to parse '%s' as date", timeStr)
|
||||
} else {
|
||||
*y = LocalDateTime(parse)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalGQL implements the graphql.Marshaler interface
|
||||
func (y LocalDateTime) MarshalGQL(w io.Writer) {
|
||||
timeStr := time.Time(y).Format("2006-01-02T15:04:05.000")
|
||||
_, _ = w.Write([]byte(fmt.Sprintf(`"%s"`, timeStr)))
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
|
||||
|
||||
package dancefinder_go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// DanceHallDistance
|
||||
type DanceHallDistance struct {
|
||||
Origin string `json:"origin"`
|
||||
Distance int `json:"distance"`
|
||||
Duration string `json:"duration"`
|
||||
}
|
||||
|
||||
type Range string
|
||||
|
||||
const (
|
||||
RangeOneMonth Range = "ONE_MONTH"
|
||||
RangeOneYear Range = "ONE_YEAR"
|
||||
RangeTwoWeeks Range = "TWO_WEEKS"
|
||||
RangeOneQuarter Range = "ONE_QUARTER"
|
||||
RangeOneWeek Range = "ONE_WEEK"
|
||||
)
|
||||
|
||||
var AllRange = []Range{
|
||||
RangeOneMonth,
|
||||
RangeOneYear,
|
||||
RangeTwoWeeks,
|
||||
RangeOneQuarter,
|
||||
RangeOneWeek,
|
||||
}
|
||||
|
||||
func (e Range) IsValid() bool {
|
||||
switch e {
|
||||
case RangeOneMonth, RangeOneYear, RangeTwoWeeks, RangeOneQuarter, RangeOneWeek:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e Range) String() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
func (e *Range) UnmarshalGQL(v interface{}) error {
|
||||
str, ok := v.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("enums must be strings")
|
||||
}
|
||||
|
||||
*e = Range(str)
|
||||
if !e.IsValid() {
|
||||
return fmt.Errorf("%s is not a valid Range", str)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e Range) MarshalGQL(w io.Writer) {
|
||||
fmt.Fprint(w, strconv.Quote(e.String()))
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
jwtmiddleware "github.com/auth0/go-jwt-middleware"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/pkg/errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Response struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type Jwks struct {
|
||||
Keys []JSONWebKeys `json:"keys"`
|
||||
}
|
||||
|
||||
type JSONWebKeys struct {
|
||||
Kty string `json:"kty"`
|
||||
Kid string `json:"kid"`
|
||||
Use string `json:"use"`
|
||||
N string `json:"n"`
|
||||
E string `json:"e"`
|
||||
X5c []string `json:"x5c"`
|
||||
}
|
||||
|
||||
func Middleware() *jwtmiddleware.JWTMiddleware {
|
||||
jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
|
||||
ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
|
||||
// Verify 'aud' claim
|
||||
aud := "http://dancefinder.unbound.se"
|
||||
checkAud := token.Claims.(jwt.MapClaims).VerifyAudience(aud, false)
|
||||
if !checkAud {
|
||||
return token, errors.New("Invalid audience.")
|
||||
}
|
||||
// Verify 'iss' claim
|
||||
iss := "https://unbound.eu.auth0.com/"
|
||||
checkIss := token.Claims.(jwt.MapClaims).VerifyIssuer(iss, false)
|
||||
if !checkIss {
|
||||
return token, errors.New("Invalid issuer.")
|
||||
}
|
||||
|
||||
cert, err := getPemCert(token)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
result, _ := jwt.ParseRSAPublicKeyFromPEM([]byte(cert))
|
||||
return result, nil
|
||||
},
|
||||
CredentialsOptional: true,
|
||||
SigningMethod: jwt.SigningMethodRS256,
|
||||
})
|
||||
|
||||
return jwtMiddleware
|
||||
}
|
||||
|
||||
func ForContext(ctx context.Context) *jwt.Token {
|
||||
raw, _ := ctx.Value("user").(*jwt.Token)
|
||||
return raw
|
||||
}
|
||||
|
||||
func getPemCert(token *jwt.Token) (string, error) {
|
||||
cert := ""
|
||||
resp, err := http.Get("https://unbound.eu.auth0.com/.well-known/jwks.json")
|
||||
|
||||
if err != nil {
|
||||
return cert, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var jwks = Jwks{}
|
||||
err = json.NewDecoder(resp.Body).Decode(&jwks)
|
||||
|
||||
if err != nil {
|
||||
return cert, err
|
||||
}
|
||||
|
||||
for k, _ := range jwks.Keys {
|
||||
if token.Header["kid"] == jwks.Keys[k].Kid {
|
||||
cert = "-----BEGIN CERTIFICATE-----\n" + jwks.Keys[k].X5c[0] + "\n-----END CERTIFICATE-----"
|
||||
}
|
||||
}
|
||||
|
||||
if cert == "" {
|
||||
err := errors.New("Unable to find appropriate key.")
|
||||
return cert, err
|
||||
}
|
||||
|
||||
return cert, nil
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
package geo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
url2 "net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
GeoSvcUrl string
|
||||
}
|
||||
|
||||
func New(url string) *Client {
|
||||
return &Client{GeoSvcUrl:url}
|
||||
}
|
||||
|
||||
type LatLong struct {
|
||||
Latitude float64
|
||||
Longitude float64
|
||||
}
|
||||
|
||||
func (l *LatLong) String() string {
|
||||
return fmt.Sprintf("%f,%f", l.Latitude, l.Longitude)
|
||||
}
|
||||
|
||||
type Address struct {
|
||||
Address string
|
||||
}
|
||||
|
||||
func (r *Client) FetchAddress(latLong string) (string, error) {
|
||||
resp, err := http.Get(fmt.Sprintf("%s/address/%s", r.GeoSvcUrl, latLong))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
a := &Address{}
|
||||
if err := json.Unmarshal(data, a); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return a.Address, nil
|
||||
}
|
||||
|
||||
func (r *Client) FetchLatLong(address string) (*LatLong, error) {
|
||||
resp, err := http.Get(fmt.Sprintf("%s/latlong/%s", r.GeoSvcUrl, address))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a := &LatLong{}
|
||||
if err := json.Unmarshal(data, a); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (r *Client) FetchDistances(origins, destinations []string) (*distanceResponse, error) {
|
||||
url := fmt.Sprintf("%s/distance/?origins=%s&destinations=%s", r.GeoSvcUrl, url2.QueryEscape(strings.Join(origins, "|")), url2.QueryEscape(strings.Join(destinations, "|")))
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("error: %s", resp.Status)
|
||||
}
|
||||
var a distanceResponse
|
||||
if err := json.Unmarshal(data, &a); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &a, nil
|
||||
}
|
||||
|
||||
type distance struct {
|
||||
Text string `json:"text"`
|
||||
Value int `json:"value"`
|
||||
}
|
||||
|
||||
type duration struct {
|
||||
Text string `json:"text"`
|
||||
Value float64 `json:"value"`
|
||||
}
|
||||
|
||||
type Destination struct {
|
||||
Destination string `json:"destination"`
|
||||
Distance distance `json:"distance"`
|
||||
Duration duration `json:"duration"`
|
||||
}
|
||||
|
||||
type origin struct {
|
||||
Origin string `json:"origin"`
|
||||
Destinations []Destination `json:"destinations"`
|
||||
}
|
||||
|
||||
type distanceResponse struct {
|
||||
Origins []origin `json:"origins"`
|
||||
}
|
||||
+277
@@ -0,0 +1,277 @@
|
||||
package dancefinder_go
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"gitlab.com/unboundsoftware/dancefinder/dancefinder_go/pkg/geo"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type EventProcessor struct {
|
||||
DB *sqlx.DB
|
||||
GeoClient *geo.Client
|
||||
BandPublisher chan interface{}
|
||||
DanceHallPublisher chan interface{}
|
||||
EventPublisher chan interface{}
|
||||
}
|
||||
|
||||
func NewEventProcessor(db *sqlx.DB, geoClient *geo.Client) *EventProcessor {
|
||||
return &EventProcessor{
|
||||
DB: db,
|
||||
GeoClient: geoClient,
|
||||
BandPublisher: make(chan interface{}, 10),
|
||||
DanceHallPublisher: make(chan interface{}, 10),
|
||||
EventPublisher: make(chan interface{}, 10),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *EventProcessor) Process(msg interface{}) bool {
|
||||
switch ev := msg.(type) {
|
||||
case *DanceHallCreated:
|
||||
address := strings.Join(joinAddress(ev.Name, ev.City, ev.Municipality, ev.State), ",")
|
||||
latLng, err := p.GeoClient.FetchLatLong(address)
|
||||
if err != nil {
|
||||
fmt.Printf("unable to fetch lat/long for '%s': %v", address, err)
|
||||
return true
|
||||
}
|
||||
|
||||
_, err = p.DB.Exec("update dance_hall set latitude = $1, longitude = $2 where name = $3 and city = $4 and municipality = $5 and state = $6", latLng.Latitude, latLng.Longitude, ev.Name, ev.City, ev.Municipality, ev.State)
|
||||
if err != nil {
|
||||
fmt.Printf("unable to update lat/long for '%s, %s, %s, %s': %v", ev.Name, toStr(ev.City), toStr(ev.Municipality), toStr(ev.State), err)
|
||||
return true
|
||||
}
|
||||
return true
|
||||
case *BandCreated:
|
||||
return true
|
||||
case *EventCreated:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func toStr(s *string) string {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
return *s
|
||||
}
|
||||
|
||||
func joinAddress(place string, city, municipality, state *string) []string {
|
||||
result := []string{place}
|
||||
if city != nil {
|
||||
result = append(result, *city)
|
||||
}
|
||||
if municipality != nil {
|
||||
result = append(result, *municipality)
|
||||
}
|
||||
if state != nil {
|
||||
result = append(result, *state)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (p *EventProcessor) ProcessREST(w http.ResponseWriter, r *http.Request) {
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
_, _ = w.Write([]byte(fmt.Sprintf("Unable to read body: %v", err)))
|
||||
return
|
||||
}
|
||||
|
||||
result := &ApiEvents{}
|
||||
err = json.Unmarshal(data, result)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
_, _ = w.Write([]byte(fmt.Sprintf("Unable to parse body to expected type: %v", err)))
|
||||
return
|
||||
}
|
||||
|
||||
tx, err := p.DB.BeginTxx(context.Background(), nil)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
_, _ = w.Write([]byte(fmt.Sprintf("Unable to start transaction: %v", err)))
|
||||
return
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
// Fetch events since
|
||||
var existingEvents []*ApiEvent
|
||||
err = tx.Select(&existingEvents, "SELECT e.id, e.date, e.time, b.name as band, dh.name as place, dh.city, dh.municipality, dh.state, e.extra_info as extra FROM event e JOIN dance_hall dh ON e.dance_hall_id = dh.id JOIN band b ON e.band_id = b.id WHERE e.date >= $1 ORDER BY e.date, dh.name, b.name", result.Start.Time)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
_, _ = w.Write([]byte(fmt.Sprintf("Unable to fetch existing events: %v", err)))
|
||||
return
|
||||
}
|
||||
// Find events to delete
|
||||
toDelete := filterNot(existingEvents, result.Events)
|
||||
for _, e := range toDelete {
|
||||
_, err = tx.Exec("delete from event where id = $1", e.ID)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
_, _ = w.Write([]byte(fmt.Sprintf("Unable to delete event with id %d: %v", e.ID, err)))
|
||||
return
|
||||
}
|
||||
}
|
||||
now := time.Now()
|
||||
// Find events to add
|
||||
toAdd := filterNot(result.Events, existingEvents)
|
||||
for _, e := range toAdd {
|
||||
bandId, err := p.findOrCreateBand(tx, e.Band, now)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
_, _ = w.Write([]byte(fmt.Sprintf("Unable to find or create band %s: %v", e.Band, err)))
|
||||
return
|
||||
}
|
||||
hallId, err := p.findOrCreateDanceHall(tx, e.Place, e.City, e.Municipality, e.State, now)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
_, _ = w.Write([]byte(fmt.Sprintf("Unable to find or create dance hall %s, %s, %s, %s: %v", e.Place, e.City, e.Municipality, e.State, err)))
|
||||
return
|
||||
}
|
||||
_, err = tx.Exec("insert into event (date, time, band_id, dance_hall_id, extra_info, created) values ($1, $2, $3, $4, $5, $6)", e.Date.Time, e.Time, bandId, hallId, e.Extra, now)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
_, _ = w.Write([]byte(fmt.Sprintf("Unable to insert event (%v, %v, %s, %s): %v", e.Date.Time, e.Time, e.Band, e.Place, err)))
|
||||
return
|
||||
}
|
||||
p.EventPublisher <- &EventCreated{
|
||||
Date: LocalDate{e.Date.Time},
|
||||
Band: e.Band,
|
||||
Place: e.Place,
|
||||
City: &e.City,
|
||||
Municipality: &e.Municipality,
|
||||
State: &e.State,
|
||||
Created: now,
|
||||
}
|
||||
}
|
||||
// Find events to update
|
||||
toUpdate := updateWithId(filterNot(result.Events, toAdd), existingEvents)
|
||||
for _, e := range toUpdate {
|
||||
_, err = tx.Exec("update event set time = $1, extra_info = $2 where id = $3", e.Time, e.Extra, e.ID)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
_, _ = w.Write([]byte(fmt.Sprintf("Unable to update event (%d, %v, %v, %s, %s): %v", e.ID, e.Date.Time, e.Time, e.Band, e.Place, err)))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
_, _ = w.Write([]byte(fmt.Sprintf("Unable to commit transaction: %v", err)))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (p *EventProcessor) findOrCreateBand(tx *sqlx.Tx, name string, now time.Time) (int, error) {
|
||||
var id int
|
||||
if err := tx.QueryRowx("select id from band where name = $1", name).Scan(&id); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
err := tx.QueryRowx("insert into band (name, created) values ($1, $2) returning id", name, now).Scan(&id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
p.BandPublisher <- &BandCreated{
|
||||
Name: name,
|
||||
Created: now,
|
||||
}
|
||||
return id, err
|
||||
}
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (p *EventProcessor) findOrCreateDanceHall(tx *sqlx.Tx, name, city, municipality, state string, now time.Time) (int, error) {
|
||||
var id int
|
||||
if err := tx.QueryRowx("select id from dance_hall where name = $1 and city = $2 and municipality = $3 and state = $4", name, city, municipality, state).Scan(&id); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
err := tx.QueryRowx("insert into dance_hall (name, city, municipality, state, created) values ($1, $2, $3, $4, $5) returning id", name, city, municipality, state, now).Scan(&id)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
p.DanceHallPublisher <- &DanceHallCreated{
|
||||
Name: name,
|
||||
City: &city,
|
||||
Municipality: &municipality,
|
||||
State: &state,
|
||||
Created: now,
|
||||
}
|
||||
return id, err
|
||||
}
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func updateWithId(s1, s2 []*ApiEvent) []*ApiEvent {
|
||||
result := s1
|
||||
for _, x := range s1 {
|
||||
existing := find(x, s2)
|
||||
x.ID = existing.ID
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func filterNot(s1, s2 []*ApiEvent) []*ApiEvent {
|
||||
var result []*ApiEvent
|
||||
for _, x := range s1 {
|
||||
if find(x, s2) == nil {
|
||||
result = append(result, x)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func find(event *ApiEvent, events []*ApiEvent) *ApiEvent {
|
||||
for _, y := range events {
|
||||
if event.Date.Time.Equal(y.Date.Time) && event.Band == y.Band && event.Place == y.Place {
|
||||
return y
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ApiEvent struct {
|
||||
ID int64
|
||||
Date LocalDate
|
||||
Time *string
|
||||
Band string
|
||||
Place string
|
||||
City string
|
||||
Municipality string
|
||||
State string
|
||||
Extra *string
|
||||
}
|
||||
|
||||
type ApiEvents struct {
|
||||
Start LocalDate
|
||||
Events []*ApiEvent
|
||||
}
|
||||
|
||||
type BandCreated struct {
|
||||
Name string `json:"name"`
|
||||
Created time.Time `json:"created"`
|
||||
}
|
||||
|
||||
type DanceHallCreated struct {
|
||||
Name string `json:"name"`
|
||||
City *string `json:"city"`
|
||||
Municipality *string `json:"municipality"`
|
||||
State *string `json:"state"`
|
||||
Created time.Time `json:"created"`
|
||||
}
|
||||
|
||||
type EventCreated struct {
|
||||
Date LocalDate `json:"date"`
|
||||
Band string `json:"band"`
|
||||
Place string `json:"place"`
|
||||
City *string `json:"city"`
|
||||
Municipality *string `json:"municipality"`
|
||||
State *string `json:"state"`
|
||||
Created time.Time `json:"created"`
|
||||
}
|
||||
+457
@@ -0,0 +1,457 @@
|
||||
//go:generate go run github.com/99designs/gqlgen
|
||||
|
||||
package dancefinder_go
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"gitlab.com/unboundsoftware/dancefinder/dancefinder_go/pkg/auth"
|
||||
"gitlab.com/unboundsoftware/dancefinder/dancefinder_go/pkg/geo"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Resolver struct {
|
||||
Db *sqlx.DB
|
||||
GeoClient *geo.Client
|
||||
}
|
||||
|
||||
var _ ResolverRoot = &Resolver{}
|
||||
|
||||
func (r *Resolver) Mutation() MutationResolver {
|
||||
return &mutationResolver{r}
|
||||
}
|
||||
func (r *Resolver) Query() QueryResolver {
|
||||
return &queryResolver{r}
|
||||
}
|
||||
func (r *Resolver) Event() EventResolver {
|
||||
return &eventResolver{r}
|
||||
}
|
||||
|
||||
type mutationResolver struct{ *Resolver }
|
||||
|
||||
func (r *mutationResolver) ToggleIgnoreBand(ctx context.Context, name string) (bool, error) {
|
||||
subject, err := subjectFromContext(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var found int
|
||||
row := r.Db.QueryRowx("select 1 from ignored_band i join band b on i.id = b.id where i.subject = $1 and b.name = $2", subject, name)
|
||||
err = row.Scan(&found)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if found == 1 {
|
||||
result, err := r.Db.Exec("delete from ignored_band where subject = $1 and id = (select id from band where name = $2)", subject, name)
|
||||
return exactlyOneRowAffected(err, result)
|
||||
} else {
|
||||
var id int
|
||||
row = r.Db.QueryRowx("select id from band where name = $1", name)
|
||||
err = row.Scan(&id)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, err := r.Db.Exec("insert into ignored_band (id, subject, created) values ($1, $2, $3)", id, subject, time.Now())
|
||||
return exactlyOneRowAffected(err, result)
|
||||
}
|
||||
}
|
||||
|
||||
func exactlyOneRowAffected(err error, result sql.Result) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return rowsAffected == 1, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) ToggleIgnoreDanceHall(ctx context.Context, name string) (bool, error) {
|
||||
subject, err := subjectFromContext(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var found int
|
||||
row := r.Db.QueryRowx("select 1 from ignored_dance_hall i join dance_hall h on i.id = h.id where i.subject = $1 and h.name = $2", subject, name)
|
||||
err = row.Scan(&found)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if found == 1 {
|
||||
result, err := r.Db.Exec("delete from ignored_dance_hall where subject = $1 and id = (select id from dance_hall where name = $2)", subject, name)
|
||||
return exactlyOneRowAffected(err, result)
|
||||
} else {
|
||||
var id int
|
||||
row = r.Db.QueryRowx("select id from dance_hall where name = $1", name)
|
||||
err = row.Scan(&id)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
result, err := r.Db.Exec("insert into ignored_dance_hall (id, subject, created) values ($1, $2, $3)", id, subject, time.Now())
|
||||
return exactlyOneRowAffected(err, result)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *mutationResolver) ToggleIgnoreCity(ctx context.Context, name string) (bool, error) {
|
||||
subject, err := subjectFromContext(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var found int
|
||||
row := r.Db.QueryRowx("select 1 from ignored_city where subject = $1 and city = $2", subject, name)
|
||||
err = row.Scan(&found)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if found == 1 {
|
||||
result, err := r.Db.Exec("delete from ignored_city where subject = $1 and city = $2", subject, name)
|
||||
return exactlyOneRowAffected(err, result)
|
||||
} else {
|
||||
result, err := r.Db.Exec("insert into ignored_city (city, subject, created) values ($1, $2, $3)", name, subject, time.Now())
|
||||
return exactlyOneRowAffected(err, result)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *mutationResolver) ToggleIgnoreMunicipality(ctx context.Context, name string) (bool, error) {
|
||||
subject, err := subjectFromContext(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var found int
|
||||
row := r.Db.QueryRowx("select 1 from ignored_municipality where subject = $1 and municipality = $2", subject, name)
|
||||
err = row.Scan(&found)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if found == 1 {
|
||||
result, err := r.Db.Exec("delete from ignored_municipality where subject = $1 and municipality = $2", subject, name)
|
||||
return exactlyOneRowAffected(err, result)
|
||||
} else {
|
||||
result, err := r.Db.Exec("insert into ignored_municipality (municipality, subject, created) values ($1, $2, $3)", name, subject, time.Now())
|
||||
return exactlyOneRowAffected(err, result)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *mutationResolver) ToggleIgnoreState(ctx context.Context, name string) (bool, error) {
|
||||
subject, err := subjectFromContext(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var found int
|
||||
row := r.Db.QueryRowx("select 1 from ignored_state where subject = $1 and state = $2", subject, name)
|
||||
err = row.Scan(&found)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if found == 1 {
|
||||
result, err := r.Db.Exec("delete from ignored_state where subject = $1 and state = $2", subject, name)
|
||||
return exactlyOneRowAffected(err, result)
|
||||
} else {
|
||||
result, err := r.Db.Exec("insert into ignored_state (state, subject, created) values ($1, $2, $3)", name, subject, time.Now())
|
||||
return exactlyOneRowAffected(err, result)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *mutationResolver) SaveOrigin(ctx context.Context, origin string) (bool, error) {
|
||||
subject, err := subjectFromContext(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
result, err := r.Db.Exec("insert into origin (origin, subject, created) values ($1, $2, $3)", origin, subject, time.Now())
|
||||
return exactlyOneRowAffected(err, result)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) RemoveOrigin(ctx context.Context, origin string) (bool, error) {
|
||||
subject, err := subjectFromContext(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
result, err := r.Db.Exec("delete from origin where subject = $1 and origin = $2", subject, origin)
|
||||
return exactlyOneRowAffected(err, result)
|
||||
}
|
||||
|
||||
type queryResolver struct{ *Resolver }
|
||||
|
||||
func (r *queryResolver) Events(ctx context.Context, rangeArg *Range, origins []string) ([]*Event, error) {
|
||||
subject, _ := subjectFromContext(ctx)
|
||||
|
||||
ignoreFilter := ""
|
||||
if len(subject) > 0 {
|
||||
ignoreFilter = `
|
||||
AND dance_hall_id NOT IN (SELECT id FROM ignored_dance_hall WHERE subject = :subject)
|
||||
AND dance_hall_id NOT IN (SELECT id FROM dance_hall WHERE city IN (SELECT city FROM ignored_city WHERE subject = :subject))
|
||||
AND dance_hall_id NOT IN (SELECT id FROM dance_hall WHERE municipality IN (SELECT municipality FROM ignored_municipality WHERE subject = :subject))
|
||||
AND dance_hall_id NOT IN (SELECT id FROM dance_hall WHERE state IN (SELECT state FROM ignored_state WHERE subject = :subject))
|
||||
AND band_id NOT IN (SELECT id FROM ignored_band WHERE subject = :subject)
|
||||
`
|
||||
}
|
||||
var events []*Event
|
||||
|
||||
now := time.Now()
|
||||
start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
end := start.Add(time.Hour * 24 * 14)
|
||||
if rangeArg != nil {
|
||||
switch *rangeArg {
|
||||
case RangeOneWeek:
|
||||
end = start.AddDate(0, 0, 8)
|
||||
case RangeTwoWeeks:
|
||||
end = start.AddDate(0, 0, 15)
|
||||
case RangeOneMonth:
|
||||
end = start.AddDate(0, 1, 1)
|
||||
case RangeOneQuarter:
|
||||
end = start.AddDate(0, 3, 1)
|
||||
case RangeOneYear:
|
||||
end = start.AddDate(1, 0, 1)
|
||||
}
|
||||
}
|
||||
args := map[string]interface{}{
|
||||
"start": start,
|
||||
"end": end,
|
||||
"subject": subject,
|
||||
}
|
||||
statement, err := r.Db.PrepareNamed(fmt.Sprintf("SELECT e.*, dh.latitude, dh.longitude FROM event e JOIN dance_hall dh ON e.dance_hall_id = dh.id JOIN band b ON e.band_id = b.id WHERE e.date BETWEEN :start AND :end %s ORDER BY e.date, dh.name, b.name", ignoreFilter))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = statement.Select(&events, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(origins) == 0 && len(subject) > 0 {
|
||||
o, err := r.Origins(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
origins = o
|
||||
}
|
||||
|
||||
if len(origins) > 0 {
|
||||
destinations := uniqueDestinations(events)
|
||||
|
||||
distances := make(map[string]map[string]geo.Destination)
|
||||
for {
|
||||
var chunk []string
|
||||
if len(destinations) < 25 {
|
||||
chunk = destinations
|
||||
destinations = nil
|
||||
} else {
|
||||
chunk = destinations[:24]
|
||||
destinations = destinations[24:]
|
||||
}
|
||||
temp, err := r.GeoClient.FetchDistances(origins, chunk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, o := range temp.Origins {
|
||||
for _, d := range o.Destinations {
|
||||
if v, ok := distances[d.Destination]; ok {
|
||||
v[o.Origin] = d
|
||||
} else {
|
||||
distances[d.Destination] = map[string]geo.Destination{
|
||||
o.Origin: d,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(destinations) == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, e := range events {
|
||||
if e.Latitude != nil && e.Longitude != nil {
|
||||
if v, ok := distances[(&geo.LatLong{Latitude: *e.Latitude, Longitude: *e.Longitude}).String()]; ok {
|
||||
for _, o := range origins {
|
||||
if w, ok := v[o]; ok {
|
||||
e.Distances = append(e.Distances, &DanceHallDistance{
|
||||
Origin: o,
|
||||
Distance: w.Distance.Value,
|
||||
Duration: w.Duration.Text,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func uniqueDestinations(events []*Event) []string {
|
||||
var locations []geo.LatLong
|
||||
for _, event := range events {
|
||||
if !locationExists(event.Latitude, event.Longitude, locations) {
|
||||
locations = append(locations, geo.LatLong{Latitude: *event.Latitude, Longitude: *event.Longitude})
|
||||
}
|
||||
}
|
||||
result := make([]string, len(locations))
|
||||
for i, l := range locations {
|
||||
result[i] = l.String()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func locationExists(lat, long *float64, locations []geo.LatLong) bool {
|
||||
if lat == nil || long == nil {
|
||||
return true
|
||||
}
|
||||
for _, l := range locations {
|
||||
if l.Latitude == *lat && l.Longitude == *long {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *queryResolver) Bands(_ context.Context) ([]*Band, error) {
|
||||
var bands []*Band
|
||||
err := r.Db.Select(&bands, "select * from band order by name")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bands, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) DanceHalls(_ context.Context) ([]*DanceHall, error) {
|
||||
var halls []*DanceHall
|
||||
err := r.Db.Select(&halls, "select * from dance_hall order by name")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return halls, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Origins(ctx context.Context) ([]string, error) {
|
||||
subject, err := subjectFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var origins []string
|
||||
err = r.Db.Select(&origins, "select origin from origin where subject = $1 order by origin", subject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return origins, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) AddressFromLatLng(_ context.Context, latlng string) (string, error) {
|
||||
return r.GeoClient.FetchAddress(latlng)
|
||||
}
|
||||
|
||||
func (r *queryResolver) IgnoredBands(ctx context.Context) ([]string, error) {
|
||||
subject, err := subjectFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var bands []string
|
||||
err = r.Db.Select(&bands, "select b.name from ignored_band i join band b on i.id = b.id where i.subject = $1 order by b.name", subject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bands, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) IgnoredDanceHalls(ctx context.Context) ([]string, error) {
|
||||
subject, err := subjectFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var halls []string
|
||||
err = r.Db.Select(&halls, "select h.name from ignored_dance_hall i join dance_hall h on i.id = h.id where i.subject = $1 order by h.name", subject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return halls, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) IgnoredCities(ctx context.Context) ([]string, error) {
|
||||
subject, err := subjectFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var cities []string
|
||||
err = r.Db.Select(&cities, "select city from ignored_city i where i.subject = $1 order by city", subject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cities, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) IgnoredMunicipalities(ctx context.Context) ([]string, error) {
|
||||
subject, err := subjectFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var municipalities []string
|
||||
err = r.Db.Select(&municipalities, "select municipality from ignored_municipality i where i.subject = $1 order by municipality", subject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return municipalities, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) IgnoredStates(ctx context.Context) ([]string, error) {
|
||||
subject, err := subjectFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var states []string
|
||||
err = r.Db.Select(&states, "select state from ignored_state i where i.subject = $1 order by state", subject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return states, nil
|
||||
}
|
||||
|
||||
type eventResolver struct{ *Resolver }
|
||||
|
||||
func (r eventResolver) Band(_ context.Context, obj *Event) (*Band, error) {
|
||||
band := &Band{}
|
||||
if err := r.Db.Get(band, "SELECT * FROM band WHERE id = $1", obj.BandId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return band, nil
|
||||
}
|
||||
|
||||
func (r eventResolver) DanceHall(_ context.Context, obj *Event) (*DanceHall, error) {
|
||||
danceHall := &DanceHall{}
|
||||
if err := r.Db.Get(danceHall, "SELECT * FROM dance_hall WHERE id = $1", obj.DanceHallId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return danceHall, nil
|
||||
}
|
||||
|
||||
func subjectFromContext(ctx context.Context) (string, error) {
|
||||
token := auth.ForContext(ctx)
|
||||
if token == nil {
|
||||
return "", errors.New("not authenticated")
|
||||
}
|
||||
if subject, ok := token.Claims.(jwt.MapClaims)["sub"].(string); !ok {
|
||||
return "", errors.New("not authenticated")
|
||||
} else {
|
||||
return subject, nil
|
||||
}
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
# source: https://dancefinder.unbound.se/graph/
|
||||
# timestamp: Wed Jul 03 2019 13:36:10 GMT+0200 (Central European Summer Time)
|
||||
|
||||
"""Band"""
|
||||
type Band {
|
||||
id: Int
|
||||
name: String!
|
||||
created: LocalDateTime!
|
||||
}
|
||||
|
||||
"""DanceHall"""
|
||||
type DanceHall {
|
||||
id: Int
|
||||
name: String
|
||||
city: String
|
||||
municipality: String
|
||||
state: String
|
||||
latitude: Float
|
||||
longitude: Float
|
||||
created: LocalDateTime!
|
||||
}
|
||||
|
||||
"""DanceHallDistance"""
|
||||
type DanceHallDistance {
|
||||
origin: String!
|
||||
distance: Int!
|
||||
duration: String!
|
||||
}
|
||||
|
||||
"""Event"""
|
||||
type Event {
|
||||
id: Int
|
||||
|
||||
"""The date of the event"""
|
||||
date: LocalDate!
|
||||
|
||||
"""The time of the event"""
|
||||
time: String
|
||||
|
||||
"""Additional information regarding the event"""
|
||||
extraInfo: String
|
||||
created: LocalDateTime!
|
||||
|
||||
"""The band of the event"""
|
||||
band: Band
|
||||
|
||||
"""The place of the event"""
|
||||
danceHall: DanceHall
|
||||
|
||||
"""
|
||||
The driving distances and driving durations to the event from the provided origins
|
||||
"""
|
||||
distances: [DanceHallDistance!]!
|
||||
}
|
||||
|
||||
scalar LocalDate
|
||||
|
||||
scalar LocalDateTime
|
||||
|
||||
type Mutation {
|
||||
"""Toggle band in ignore list"""
|
||||
ToggleIgnoreBand(name: String!): Boolean!
|
||||
|
||||
"""Toggle dance hall in ignore list"""
|
||||
ToggleIgnoreDanceHall(name: String!): Boolean!
|
||||
|
||||
"""Toggle city in ignore list"""
|
||||
ToggleIgnoreCity(name: String!): Boolean!
|
||||
|
||||
"""Toggle municipality in ignore list"""
|
||||
ToggleIgnoreMunicipality(name: String!): Boolean!
|
||||
|
||||
"""Toggle state in ignore list"""
|
||||
ToggleIgnoreState(name: String!): Boolean!
|
||||
|
||||
"""Save provided origin for authenticated user"""
|
||||
SaveOrigin(origin: String!): Boolean!
|
||||
|
||||
"""Remove provided origin from authenticated user"""
|
||||
RemoveOrigin(origin: String!): Boolean!
|
||||
}
|
||||
|
||||
type Query {
|
||||
"""Find events given provided criteria"""
|
||||
Events(range: Range, origins: [String!]): [Event!]!
|
||||
|
||||
"""Find bands given provided criteria"""
|
||||
Bands: [Band!]!
|
||||
|
||||
"""Find dance halls given provided criteria"""
|
||||
DanceHalls: [DanceHall!]!
|
||||
|
||||
"""Fetch origins for authenticated user"""
|
||||
Origins: [String!]!
|
||||
|
||||
"""Fetch address for provided lat/long"""
|
||||
AddressFromLatLng(latlng: String!): String!
|
||||
|
||||
"""Fetch ignored bands for authenticated user"""
|
||||
IgnoredBands: [String!]!
|
||||
|
||||
"""Fetch ignored dance halls for authenticated user"""
|
||||
IgnoredDanceHalls: [String!]!
|
||||
|
||||
"""Fetch ignored cities for authenticated user"""
|
||||
IgnoredCities: [String!]!
|
||||
|
||||
"""Fetch ignored municipalities for authenticated user"""
|
||||
IgnoredMunicipalities: [String!]!
|
||||
|
||||
"""Fetch ignored states for authenticated user"""
|
||||
IgnoredStates: [String!]!
|
||||
}
|
||||
|
||||
enum Range {
|
||||
ONE_MONTH
|
||||
ONE_YEAR
|
||||
TWO_WEEKS
|
||||
ONE_QUARTER
|
||||
ONE_WEEK
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database/postgres"
|
||||
_ "github.com/golang-migrate/migrate/v4/source/file"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/negroni"
|
||||
"gitlab.com/sparetimecoders/goamqp"
|
||||
"gitlab.com/unboundsoftware/dancefinder/dancefinder_go/pkg/auth"
|
||||
"gitlab.com/unboundsoftware/dancefinder/dancefinder_go/pkg/geo"
|
||||
"log"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/99designs/gqlgen/handler"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"gitlab.com/unboundsoftware/dancefinder/dancefinder_go"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
port := kingpin.Flag("port", "Port used for serving GraphQL API").Envar("PORT").Default("8080").Int()
|
||||
url := kingpin.Flag("postgres-url", "URL to use to connect to Postgres").Envar("POSTGRES_URL").Default("postgres://postgres:postgres@:5432/dancefinder?sslmode=disable").String()
|
||||
amqpUrl := kingpin.Flag("amqp-url", "URL to use to connect to RabbitMQ").Envar("AMQP_URL").Default("amqp://user:password@localhost:5672/").String()
|
||||
geoServiceUrl := kingpin.Flag("geo-service-url", "URL where geo-service is found").Envar("GEO_SERVICE_URL").Default("http://geo-service").String()
|
||||
kingpin.Parse()
|
||||
|
||||
db, err := sqlx.Open("postgres", *url)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
db.SetMaxOpenConns(200)
|
||||
db.SetMaxIdleConns(10)
|
||||
db.SetConnMaxLifetime(10 * time.Minute)
|
||||
|
||||
if err := runMigrations(db); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
conn, err := goamqp.NewFromURL("dancefinder", *amqpUrl)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
geoClient := geo.New(*geoServiceUrl)
|
||||
resolver := &dancefinder_go.Resolver{
|
||||
Db: db,
|
||||
GeoClient: geoClient,
|
||||
}
|
||||
processor := dancefinder_go.NewEventProcessor(db, geoClient)
|
||||
err = conn.Start(
|
||||
goamqp.EventStreamPublisher("Band.Created", processor.BandPublisher),
|
||||
goamqp.EventStreamPublisher("DanceHall.Created", processor.DanceHallPublisher),
|
||||
goamqp.EventStreamPublisher("Event.Created", processor.EventPublisher),
|
||||
goamqp.EventStreamListener("Band.Created", processor.Process, reflect.TypeOf(dancefinder_go.BandCreated{})),
|
||||
goamqp.EventStreamListener("DanceHall.Created", processor.Process, reflect.TypeOf(dancefinder_go.DanceHallCreated{})),
|
||||
goamqp.EventStreamListener("Event.Created", processor.Process, reflect.TypeOf(dancefinder_go.EventCreated{})),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", handler.Playground("GraphQL playground", "/query"))
|
||||
mux.HandleFunc("/query", handler.GraphQL(dancefinder_go.NewExecutableSchema(dancefinder_go.Config{Resolvers: resolver})))
|
||||
mux.HandleFunc("/event", processor.ProcessREST)
|
||||
|
||||
n := negroni.Classic().With(negroni.HandlerFunc(auth.Middleware().HandlerWithNext))
|
||||
n.UseHandler(mux)
|
||||
|
||||
log.Printf("connect to http://localhost:%d/ for GraphQL playground", *port)
|
||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), n))
|
||||
}
|
||||
|
||||
func runMigrations(db *sqlx.DB) error {
|
||||
driver, err := postgres.WithInstance(db.DB, &postgres.Config{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not create the driver")
|
||||
}
|
||||
|
||||
m, err := migrate.NewWithDatabaseInstance("file://migrations", "postgres", driver)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not initiate the migrations")
|
||||
}
|
||||
|
||||
if err := m.Up(); err != nil {
|
||||
if err != migrate.ErrNoChange {
|
||||
return errors.Wrap(err, "Could not migrate")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user