init
This commit is contained in:
commit
c034dbdae0
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
vendor
|
||||
20
.golangci.yml
Normal file
20
.golangci.yml
Normal file
@ -0,0 +1,20 @@
|
||||
# https://golangci-lint.run/usage/configuration/#config-file
|
||||
|
||||
run:
|
||||
allow-parallel-runners: true
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- megacheck
|
||||
- govet
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- lll
|
||||
- exportloopref
|
||||
disable-all: false
|
||||
disable:
|
||||
- scopelint
|
||||
presets:
|
||||
- bugs
|
||||
- unused
|
||||
fast: false
|
||||
36
docker-compose.yml
Normal file
36
docker-compose.yml
Normal file
@ -0,0 +1,36 @@
|
||||
version: "3"
|
||||
services:
|
||||
cassandra:
|
||||
container_name: cassandra
|
||||
environment:
|
||||
- CASSANDRA_KEYSPACE=userprofileservice
|
||||
- TABLE_NAME=users
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./docker/db/Dockerfile
|
||||
command: /cassandra-init.sh
|
||||
ports:
|
||||
- 9042:9042
|
||||
service:
|
||||
container_name: service
|
||||
environment:
|
||||
- CASSANDRA_HOST=cassandra
|
||||
- CASSANDRA_PORT=9042
|
||||
- CASSANDRA_KEYSPACE=userprofileservice
|
||||
- CASSANDRA_CONSISTANCY=LOCAL_QUORUM
|
||||
- TABLE_NAME=users
|
||||
- BIDN_SERVICE=:8080
|
||||
- AWS_REGION=fake-region
|
||||
- AWS_ACCESS_KEY_ID=fake-key
|
||||
- AWS_SECRET_ACCESS_KEY=fake-secret
|
||||
- BUCKET_NAME=fake-bucket
|
||||
- AWS_ACL=public-read
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./docker/api/Dockerfile
|
||||
ports:
|
||||
- "8080:8080"
|
||||
networks:
|
||||
- default
|
||||
depends_on:
|
||||
- cassandra
|
||||
12
docker/api/Dockerfile
Normal file
12
docker/api/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM golang as builder
|
||||
RUN mkdir -p /build/src
|
||||
WORKDIR /build
|
||||
COPY ./src/. /build/src/
|
||||
COPY ./go.mod /build/
|
||||
RUN go mod vendor && go test ./src/ && CGO_ENABLED=0 GOOS=linux go build -o apiservice ./src/main.go
|
||||
|
||||
FROM alpine
|
||||
ENV TZ=Europe/Helsinki
|
||||
RUN apk add --no-cache tzdata && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
COPY --from=builder /build/apiservice .
|
||||
ENTRYPOINT [ "./apiservice" ]
|
||||
3
docker/db/Dockerfile
Normal file
3
docker/db/Dockerfile
Normal file
@ -0,0 +1,3 @@
|
||||
FROM cassandra
|
||||
COPY docker/db/cassandra-init.sh /cassandra-init.sh
|
||||
RUN chmod +x /cassandra-init.sh
|
||||
10
docker/db/cassandra-init.sh
Normal file
10
docker/db/cassandra-init.sh
Normal file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
cat >/import.cql <<EOF
|
||||
CREATE keyspace IF NOT EXISTS ${CASSANDRA_KEYSPACE} with replication = {'class':'SimpleStrategy', 'replication_factor' : 1};
|
||||
USE ${CASSANDRA_KEYSPACE};
|
||||
CREATE TABLE IF NOT EXISTS ${TABLE_NAME}(id TIMEUUID, firstname TEXT, lastname TEXT, birthday date, currentlocation TEXT, userpicture TEXT, certificate TEXT, PRIMARY KEY(id));
|
||||
EOF
|
||||
|
||||
bash -c 'sleep 60; cqlsh -f /import.cql;' &
|
||||
exec /docker-entrypoint.sh "$@";
|
||||
|
||||
15
go.mod
Normal file
15
go.mod
Normal file
@ -0,0 +1,15 @@
|
||||
module userprofileservice
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||
github.com/aws/aws-sdk-go v1.38.37
|
||||
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible
|
||||
github.com/gocql/gocql v0.0.0-20210504150947-558dfae50b5d
|
||||
github.com/golang/mock v1.5.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/swaggo/http-swagger v1.0.0
|
||||
github.com/swaggo/swag v1.7.0
|
||||
)
|
||||
154
go.sum
Normal file
154
go.sum
Normal file
@ -0,0 +1,154 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
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/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.38.37 h1:Eh3/jog9t2NhGcOi086NRfRqVKduRXkaH6svI8yF1Jg=
|
||||
github.com/aws/aws-sdk-go v1.38.37/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY=
|
||||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.19.4 h1:3Vw+rh13uq2JFNxgnMTGE1rnoieU9FmyE1gvnyylsYg=
|
||||
github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/spec v0.19.14 h1:r4fbYFo6N4ZelmSX8G6p+cv/hZRXzcuqQIADGT1iNKM=
|
||||
github.com/go-openapi/spec v0.19.14/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA=
|
||||
github.com/go-openapi/spec v0.20.0 h1:HGLc8AJ7ynOxwv0Lq4TsnwLsWMawHAYiJIFzbcML86I=
|
||||
github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.11 h1:RFTu/dlFySpyVvJDfp/7674JY4SDglYWKztbiIGFpmc=
|
||||
github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY=
|
||||
github.com/go-openapi/swag v0.19.12 h1:Bc0bnY2c3AoF7Gc+IMIAQQsD8fLHjHpc19wXvYuayQI=
|
||||
github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M=
|
||||
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/GeYW1cILu7Nuuj1N3BBkE=
|
||||
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU=
|
||||
github.com/gocql/gocql v0.0.0-20210504150947-558dfae50b5d h1:QbC6FK7LDUrgkZPYdtaKiXGCIw41fdk39H+vrTgHFMs=
|
||||
github.com/gocql/gocql v0.0.0-20210504150947-558dfae50b5d/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY=
|
||||
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049 h1:K9KHZbXKpGydfDN0aZrsoHpLJlZsBrGMFWbgLDGnPZk=
|
||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
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 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
|
||||
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/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.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/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM=
|
||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
|
||||
github.com/swaggo/http-swagger v1.0.0 h1:ksYgVBCYmAaxFsGVGojlPROgYfiQQSllETTWMtHJHTo=
|
||||
github.com/swaggo/http-swagger v1.0.0/go.mod h1:cKIcshBU9yEAnfWv6ZzVKSsEf8h5ozxB8/zHQWyOQ/8=
|
||||
github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E=
|
||||
github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo=
|
||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201207224615-747e23833adb h1:xj2oMIbduz83x7tzglytWT7spn6rP+9hvKjTpro6/pM=
|
||||
golang.org/x/net v0.0.0-20201207224615-747e23833adb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e h1:aZzprAO9/8oim3qStq3wc1Xuxx4QmAGriC4VU4ojemQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e h1:t96dS3DO8DGjawSLJL/HIdz8CycAd2v07XxqB3UPTi0=
|
||||
golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208062317-e652b2f42cc7 h1:2OSu5vYyX4LVqZAtqZXnFEcN26SDKIJYlEVIRl1tj8U=
|
||||
golang.org/x/tools v0.0.0-20201208062317-e652b2f42cc7/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
21
readme.md
Normal file
21
readme.md
Normal file
@ -0,0 +1,21 @@
|
||||
# INIT SERVICE
|
||||
|
||||
docker-compose up --build
|
||||
|
||||
# AFTER STARTING WILL BE AVAILABLE POINTS
|
||||
|
||||
GET http://localhost:8080/user/e2bb359d-b347-11eb-b01c-0242ac120003 - with parameter will return user info, url parameter [uuid]
|
||||
|
||||
POST http://localhost:8080/user - add or change user, request in json format
|
||||
- {
|
||||
- "firstname":"John",
|
||||
- "lastname":"Dou",
|
||||
- "birthday":"1972-10-06",
|
||||
- "currentlocation":"Helsinki"
|
||||
- }
|
||||
with id UUID in request user will be changed
|
||||
|
||||
POST http://localhost:8080/upload/userpicture - add image or document to user record with form-data request, url parameter [userpicture|certificate]
|
||||
|
||||
# SWAGGER
|
||||
http://localhost:8080/swagger/
|
||||
68
src/aws/aws.go
Normal file
68
src/aws/aws.go
Normal file
@ -0,0 +1,68 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"io"
|
||||
"userprofileservice/src/utils"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
)
|
||||
|
||||
type AWS struct {
|
||||
aws_region string
|
||||
aws_access_key_id string
|
||||
aws_secret_ascess_key string
|
||||
bucket_name string
|
||||
acl string
|
||||
Session *session.Session
|
||||
}
|
||||
|
||||
// InitDB create ClusterConfig and init DB struct
|
||||
func InitAWS() *AWS {
|
||||
aws := &AWS{
|
||||
aws_region: utils.GetEnv("AWS_REGION", "fake-region"),
|
||||
aws_access_key_id: utils.GetEnv("AWS_ACCESS_KEY_ID ", "fake-key"),
|
||||
aws_secret_ascess_key: utils.GetEnv("AWS_SECRET_ACCESS_KEY ", "fake-secret"),
|
||||
bucket_name: utils.GetEnv("BUCKET_NAME ", "fake-bucket"),
|
||||
acl: utils.GetEnv("AWS_ACL ", "public-read"),
|
||||
}
|
||||
|
||||
aws.connectAWS()
|
||||
return aws
|
||||
}
|
||||
|
||||
// connectAWS connect to AWS if not connected
|
||||
// Comment in for the test and not connect to AWS
|
||||
func (a *AWS) connectAWS() {
|
||||
// if a.Session == nil {
|
||||
// sess, err := session.NewSession(
|
||||
// &aws.Config{
|
||||
// Region: aws.String(a.aws_region),
|
||||
// Credentials: credentials.NewStaticCredentials(
|
||||
// a.aws_access_key_id,
|
||||
// a.aws_secret_ascess_key,
|
||||
// "", // a token will be created when the session it's used.
|
||||
// ),
|
||||
// })
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// a.Session = sess
|
||||
// }
|
||||
}
|
||||
|
||||
// uploadFile upload file to AWS and return filename
|
||||
// comment in for fake upload
|
||||
func (a *AWS) UploadFile(file io.Reader, filename string) (string, error) {
|
||||
// uploader := s3manager.NewUploader(a.Session)
|
||||
// _, err := uploader.Upload(&s3manager.UploadInput{
|
||||
// Bucket: aws.String(a.bucket_name),
|
||||
// ACL: aws.String(a.acl),
|
||||
// Key: aws.String(filename),
|
||||
// Body: file,
|
||||
// })
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
filepath := "https://" + a.bucket_name + "." + "s3-" + a.aws_region + ".amazonaws.com/" + filename
|
||||
return filepath, nil
|
||||
}
|
||||
23
src/controller/controller.go
Normal file
23
src/controller/controller.go
Normal file
@ -0,0 +1,23 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"userprofileservice/src/model"
|
||||
"userprofileservice/src/structs"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
)
|
||||
|
||||
//go:generate mockgen -source=controller.go -destination=mocks/mock.go
|
||||
|
||||
type IController interface {
|
||||
CreateUser(user *structs.USER) error
|
||||
GetUser(id gocql.UUID) (*structs.USER, error)
|
||||
}
|
||||
|
||||
type Controller struct {
|
||||
IController
|
||||
}
|
||||
|
||||
func NewController(model *model.Model) *Controller {
|
||||
return &Controller{IController: NewUserController(model)}
|
||||
}
|
||||
65
src/controller/mocks/mock.go
Normal file
65
src/controller/mocks/mock.go
Normal file
@ -0,0 +1,65 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: controller.go
|
||||
|
||||
// Package mock_controller is a generated GoMock package.
|
||||
package mock_controller
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
structs "userprofileservice/src/structs"
|
||||
|
||||
gocql "github.com/gocql/gocql"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockIController is a mock of IController interface.
|
||||
type MockIController struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockIControllerMockRecorder
|
||||
}
|
||||
|
||||
// MockIControllerMockRecorder is the mock recorder for MockIController.
|
||||
type MockIControllerMockRecorder struct {
|
||||
mock *MockIController
|
||||
}
|
||||
|
||||
// NewMockIController creates a new mock instance.
|
||||
func NewMockIController(ctrl *gomock.Controller) *MockIController {
|
||||
mock := &MockIController{ctrl: ctrl}
|
||||
mock.recorder = &MockIControllerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockIController) EXPECT() *MockIControllerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// CreateUser mocks base method.
|
||||
func (m *MockIController) CreateUser(user *structs.USER) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateUser", user)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CreateUser indicates an expected call of CreateUser.
|
||||
func (mr *MockIControllerMockRecorder) CreateUser(user interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUser", reflect.TypeOf((*MockIController)(nil).CreateUser), user)
|
||||
}
|
||||
|
||||
// GetUser mocks base method.
|
||||
func (m *MockIController) GetUser(id gocql.UUID) (*structs.USER, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetUser", id)
|
||||
ret0, _ := ret[0].(*structs.USER)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetUser indicates an expected call of GetUser.
|
||||
func (mr *MockIControllerMockRecorder) GetUser(id interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUser", reflect.TypeOf((*MockIController)(nil).GetUser), id)
|
||||
}
|
||||
24
src/controller/usercontroller.go
Normal file
24
src/controller/usercontroller.go
Normal file
@ -0,0 +1,24 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"userprofileservice/src/model"
|
||||
"userprofileservice/src/structs"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
)
|
||||
|
||||
type UserController struct {
|
||||
model *model.Model
|
||||
}
|
||||
|
||||
func NewUserController(model *model.Model) *UserController {
|
||||
return &UserController{model: model}
|
||||
}
|
||||
|
||||
func (u *UserController) CreateUser(user *structs.USER) error {
|
||||
return u.model.CreateUser(user)
|
||||
}
|
||||
|
||||
func (u *UserController) GetUser(id gocql.UUID) (*structs.USER, error) {
|
||||
return u.model.GetUser(id)
|
||||
}
|
||||
314
src/docs/docs.go
Normal file
314
src/docs/docs.go
Normal file
@ -0,0 +1,314 @@
|
||||
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
// This file was generated by swaggo/swag
|
||||
|
||||
package docs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/template"
|
||||
"github.com/swaggo/swag"
|
||||
)
|
||||
|
||||
var doc = `{
|
||||
"schemes": {{ marshal .Schemes }},
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "{{.Description}}",
|
||||
"title": "{{.Title}}",
|
||||
"contact": {},
|
||||
"version": "{{.Version}}"
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/upload/{field}": {
|
||||
"post": {
|
||||
"description": "upload file for user, one by one",
|
||||
"consumes": [
|
||||
"multipart/form-data"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"uploadfile"
|
||||
],
|
||||
"summary": "Upload File",
|
||||
"operationId": "upload-file",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "User struct field",
|
||||
"name": "field",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "UUID",
|
||||
"name": "id",
|
||||
"in": "formData",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "File name",
|
||||
"name": "file_name",
|
||||
"in": "formData",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"description": "File data",
|
||||
"name": "input",
|
||||
"in": "formData",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.USER"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user": {
|
||||
"post": {
|
||||
"description": "create or update user",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"createuser"
|
||||
],
|
||||
"summary": "Create User",
|
||||
"operationId": "create-user",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "User data",
|
||||
"name": "input",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.USER"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.USER"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/{id}": {
|
||||
"get": {
|
||||
"description": "get user by uuid",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"getuser"
|
||||
],
|
||||
"summary": "Get User by UID",
|
||||
"operationId": "get-user-by-uid",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "User ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.USER"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"structs.ANSWERAPI": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"additional": {
|
||||
"type": "string"
|
||||
},
|
||||
"data": {
|
||||
"type": "object"
|
||||
},
|
||||
"error": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"structs.USER": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"birthday": {
|
||||
"type": "string"
|
||||
},
|
||||
"certificate": {
|
||||
"type": "string"
|
||||
},
|
||||
"currentlocation": {
|
||||
"type": "string"
|
||||
},
|
||||
"firstname": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"lastname": {
|
||||
"type": "string"
|
||||
},
|
||||
"userpicture": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
type swaggerInfo struct {
|
||||
Version string
|
||||
Host string
|
||||
BasePath string
|
||||
Schemes []string
|
||||
Title string
|
||||
Description string
|
||||
}
|
||||
|
||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = swaggerInfo{
|
||||
Version: "0.1",
|
||||
Host: "localhost:8080",
|
||||
BasePath: "/",
|
||||
Schemes: []string{},
|
||||
Title: "User Profile Service API",
|
||||
Description: "API Server for User Profile Service",
|
||||
}
|
||||
|
||||
type s struct{}
|
||||
|
||||
func (s *s) ReadDoc() string {
|
||||
sInfo := SwaggerInfo
|
||||
sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1)
|
||||
|
||||
t, err := template.New("swagger_info").Funcs(template.FuncMap{
|
||||
"marshal": func(v interface{}) string {
|
||||
a, _ := json.Marshal(v)
|
||||
return string(a)
|
||||
},
|
||||
}).Parse(doc)
|
||||
if err != nil {
|
||||
return doc
|
||||
}
|
||||
|
||||
var tpl bytes.Buffer
|
||||
if err := t.Execute(&tpl, sInfo); err != nil {
|
||||
return doc
|
||||
}
|
||||
|
||||
return tpl.String()
|
||||
}
|
||||
|
||||
func init() {
|
||||
swag.Register(swag.Name, &s{})
|
||||
}
|
||||
252
src/docs/swagger.json
Normal file
252
src/docs/swagger.json
Normal file
@ -0,0 +1,252 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "API Server for User Profile Service",
|
||||
"title": "User Profile Service API",
|
||||
"contact": {},
|
||||
"version": "0.1"
|
||||
},
|
||||
"host": "localhost:8080",
|
||||
"basePath": "/",
|
||||
"paths": {
|
||||
"/upload/{field}": {
|
||||
"post": {
|
||||
"description": "upload file for user, one by one",
|
||||
"consumes": [
|
||||
"multipart/form-data"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"uploadfile"
|
||||
],
|
||||
"summary": "Upload File",
|
||||
"operationId": "upload-file",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "User struct field",
|
||||
"name": "field",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "UUID",
|
||||
"name": "id",
|
||||
"in": "formData",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "File name",
|
||||
"name": "file_name",
|
||||
"in": "formData",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"description": "File data",
|
||||
"name": "input",
|
||||
"in": "formData",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.USER"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user": {
|
||||
"post": {
|
||||
"description": "create or update user",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"createuser"
|
||||
],
|
||||
"summary": "Create User",
|
||||
"operationId": "create-user",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "User data",
|
||||
"name": "input",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.USER"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.USER"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/{id}": {
|
||||
"get": {
|
||||
"description": "get user by uuid",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"getuser"
|
||||
],
|
||||
"summary": "Get User by UID",
|
||||
"operationId": "get-user-by-uid",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "User ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.USER"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/structs.ANSWERAPI"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"structs.ANSWERAPI": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"additional": {
|
||||
"type": "string"
|
||||
},
|
||||
"data": {
|
||||
"type": "object"
|
||||
},
|
||||
"error": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"structs.USER": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"birthday": {
|
||||
"type": "string"
|
||||
},
|
||||
"certificate": {
|
||||
"type": "string"
|
||||
},
|
||||
"currentlocation": {
|
||||
"type": "string"
|
||||
},
|
||||
"firstname": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"lastname": {
|
||||
"type": "string"
|
||||
},
|
||||
"userpicture": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
168
src/docs/swagger.yaml
Normal file
168
src/docs/swagger.yaml
Normal file
@ -0,0 +1,168 @@
|
||||
basePath: /
|
||||
definitions:
|
||||
structs.ANSWERAPI:
|
||||
properties:
|
||||
additional:
|
||||
type: string
|
||||
data:
|
||||
type: object
|
||||
error:
|
||||
type: string
|
||||
status:
|
||||
type: boolean
|
||||
type: object
|
||||
structs.USER:
|
||||
properties:
|
||||
birthday:
|
||||
type: string
|
||||
certificate:
|
||||
type: string
|
||||
currentlocation:
|
||||
type: string
|
||||
firstname:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
lastname:
|
||||
type: string
|
||||
userpicture:
|
||||
type: string
|
||||
type: object
|
||||
host: localhost:8080
|
||||
info:
|
||||
contact: {}
|
||||
description: API Server for User Profile Service
|
||||
title: User Profile Service API
|
||||
version: "0.1"
|
||||
paths:
|
||||
/upload/{field}:
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
description: upload file for user, one by one
|
||||
operationId: upload-file
|
||||
parameters:
|
||||
- description: User struct field
|
||||
in: path
|
||||
name: field
|
||||
required: true
|
||||
type: string
|
||||
- description: UUID
|
||||
in: formData
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- description: File name
|
||||
in: formData
|
||||
name: file_name
|
||||
required: true
|
||||
type: string
|
||||
- description: File data
|
||||
in: formData
|
||||
name: input
|
||||
required: true
|
||||
type: file
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/structs.USER'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/structs.ANSWERAPI'
|
||||
"404":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/structs.ANSWERAPI'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/structs.ANSWERAPI'
|
||||
default:
|
||||
description: ""
|
||||
schema:
|
||||
$ref: '#/definitions/structs.ANSWERAPI'
|
||||
summary: Upload File
|
||||
tags:
|
||||
- uploadfile
|
||||
/user:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: create or update user
|
||||
operationId: create-user
|
||||
parameters:
|
||||
- description: User data
|
||||
in: body
|
||||
name: input
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/structs.USER'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/structs.USER'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/structs.ANSWERAPI'
|
||||
"404":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/structs.ANSWERAPI'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/structs.ANSWERAPI'
|
||||
default:
|
||||
description: ""
|
||||
schema:
|
||||
$ref: '#/definitions/structs.ANSWERAPI'
|
||||
summary: Create User
|
||||
tags:
|
||||
- createuser
|
||||
/user/{id}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: get user by uuid
|
||||
operationId: get-user-by-uid
|
||||
parameters:
|
||||
- description: User ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/structs.USER'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/structs.ANSWERAPI'
|
||||
"404":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/structs.ANSWERAPI'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/structs.ANSWERAPI'
|
||||
default:
|
||||
description: ""
|
||||
schema:
|
||||
$ref: '#/definitions/structs.ANSWERAPI'
|
||||
summary: Get User by UID
|
||||
tags:
|
||||
- getuser
|
||||
swagger: "2.0"
|
||||
30
src/main.go
Normal file
30
src/main.go
Normal file
@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"userprofileservice/src/controller"
|
||||
"userprofileservice/src/model"
|
||||
"userprofileservice/src/utils"
|
||||
"userprofileservice/src/view"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// catch panic
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println("Recovered in f ", r)
|
||||
}
|
||||
}()
|
||||
|
||||
db := model.NewCassandra()
|
||||
model := model.NewModel(db)
|
||||
controller := controller.NewController(model)
|
||||
view := view.NewView(controller)
|
||||
|
||||
bind := utils.GetEnv("BIDN_SERVICE", ":8080")
|
||||
log.Printf("start service on port %s", bind)
|
||||
if err := http.ListenAndServe(bind, view.InitRouting()); err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
61
src/main_test.go
Normal file
61
src/main_test.go
Normal file
@ -0,0 +1,61 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
"userprofileservice/src/controller"
|
||||
mock_controller "userprofileservice/src/controller/mocks"
|
||||
"userprofileservice/src/structs"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
var (
|
||||
uid = gocql.TimeUUID()
|
||||
user = &structs.USER{
|
||||
Firstname: "Sergey",
|
||||
Lastname: "Melnikov",
|
||||
Birthday: "1972-10-06",
|
||||
}
|
||||
)
|
||||
|
||||
func TestCreateUser(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
mocklUserController := mock_controller.NewMockIController(ctrl)
|
||||
|
||||
mocklUserController.
|
||||
EXPECT().
|
||||
CreateUser(user).
|
||||
Return(nil)
|
||||
testCreateUser(mocklUserController)
|
||||
}
|
||||
|
||||
func testCreateUser(c controller.IController) {
|
||||
err := c.CreateUser(user)
|
||||
if err != nil {
|
||||
log.Fatalf("Wrong added user %v", err)
|
||||
}
|
||||
log.Printf("User added %v", user)
|
||||
}
|
||||
|
||||
func TestGetUser(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
mocklUserController := mock_controller.NewMockIController(ctrl)
|
||||
|
||||
mocklUserController.
|
||||
EXPECT().
|
||||
GetUser(uid).
|
||||
Return(user, nil)
|
||||
testGetUser(mocklUserController)
|
||||
}
|
||||
|
||||
func testGetUser(c controller.IController) {
|
||||
u, err := c.GetUser(uid)
|
||||
if err != nil {
|
||||
log.Fatalf("Wrong get user %v", err)
|
||||
}
|
||||
log.Printf("Get user %v", u)
|
||||
}
|
||||
42
src/model/cassandra.go
Normal file
42
src/model/cassandra.go
Normal file
@ -0,0 +1,42 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
"userprofileservice/src/utils"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
)
|
||||
|
||||
func NewCassandra() *gocql.Session {
|
||||
conf := gocql.NewCluster(utils.GetEnv("CASSANDRA_HOST", "cassandra"))
|
||||
conf.Port = utils.ParsePort(utils.GetEnv("CASSANDRA_PORT", "9042"))
|
||||
conf.Keyspace = utils.GetEnv("CASSANDRA_KEYSPACE", "userprofileservice")
|
||||
conf.Consistency = gocql.ParseConsistency(utils.GetEnv("CASSANDRA_CONSISTANCY", "LOCAL_QUORUM"))
|
||||
sess, err := conf.CreateSession()
|
||||
if err != nil {
|
||||
log.Printf("waiting for cassandra session, %s", err.Error())
|
||||
// added ticker for long cassandra initializing
|
||||
ticker := time.NewTicker(time.Second * 10)
|
||||
defer ticker.Stop()
|
||||
timeout := time.Second * 120
|
||||
|
||||
timeoutExceeded := time.After(timeout)
|
||||
for {
|
||||
select {
|
||||
case <-timeoutExceeded:
|
||||
log.Panicf("cassandra connection failed after %s timeout", timeout)
|
||||
|
||||
case <-ticker.C:
|
||||
sess, err = conf.CreateSession()
|
||||
if err != nil {
|
||||
log.Printf("waiting for cassandra session, %s", err.Error())
|
||||
} else {
|
||||
log.Printf("cassandra session init")
|
||||
return sess
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sess
|
||||
}
|
||||
22
src/model/model.go
Normal file
22
src/model/model.go
Normal file
@ -0,0 +1,22 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"userprofileservice/src/structs"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
)
|
||||
|
||||
type IModel interface {
|
||||
CreateUser(user *structs.USER) error
|
||||
GetUser(id gocql.UUID) (*structs.USER, error)
|
||||
}
|
||||
|
||||
type Model struct {
|
||||
IModel
|
||||
}
|
||||
|
||||
func NewModel(db *gocql.Session) *Model {
|
||||
return &Model{
|
||||
IModel: NewUserModel(db),
|
||||
}
|
||||
}
|
||||
89
src/model/user_model.go
Normal file
89
src/model/user_model.go
Normal file
@ -0,0 +1,89 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"userprofileservice/src/structs"
|
||||
"userprofileservice/src/utils"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
)
|
||||
|
||||
type ModelCassandra struct {
|
||||
db *gocql.Session
|
||||
TableName string
|
||||
}
|
||||
|
||||
func NewUserModel(db *gocql.Session) *ModelCassandra {
|
||||
return &ModelCassandra{
|
||||
db: db,
|
||||
TableName: utils.GetEnv("TABLE_NAME", "users"),
|
||||
}
|
||||
}
|
||||
|
||||
// CreateUser create or update user
|
||||
func (c *ModelCassandra) CreateUser(user *structs.USER) error {
|
||||
var query *gocql.Query
|
||||
// if user ID empty - create new user, else update user fields
|
||||
if user.Id.Clock() == 0 {
|
||||
user.Id = gocql.TimeUUID()
|
||||
query = c.db.Query(`
|
||||
INSERT INTO `+c.TableName+` (
|
||||
id,
|
||||
firstname,
|
||||
lastname,
|
||||
birthday,
|
||||
currentlocation,
|
||||
userpicture,
|
||||
certificate
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
`,
|
||||
user.Id,
|
||||
user.Firstname,
|
||||
user.Lastname,
|
||||
user.Birthday,
|
||||
user.Currentlocation,
|
||||
user.Userpicture,
|
||||
user.Certificate)
|
||||
} else {
|
||||
query = c.db.Query(`
|
||||
UPDATE `+c.TableName+` SET
|
||||
firstname = ?,
|
||||
lastname = ?,
|
||||
birthday = ?,
|
||||
currentlocation = ?,
|
||||
userpicture = ?,
|
||||
certificate = ?
|
||||
WHERE id = ?
|
||||
IF EXISTS
|
||||
`,
|
||||
user.Firstname,
|
||||
user.Lastname,
|
||||
user.Birthday,
|
||||
user.Currentlocation,
|
||||
user.Userpicture,
|
||||
user.Certificate,
|
||||
user.Id)
|
||||
}
|
||||
err := query.Exec()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// GetUser return user data by id
|
||||
func (c *ModelCassandra) GetUser(id gocql.UUID) (*structs.USER, error) {
|
||||
q := `SELECT id, firstname, lastname, currentlocation, birthday, userpicture, certificate
|
||||
FROM ` + c.TableName + ` WHERE id = ? LIMIT 1`
|
||||
|
||||
user := &structs.USER{}
|
||||
err := c.db.Query(q, id).Consistency(gocql.One).Scan(
|
||||
&user.Id,
|
||||
&user.Firstname,
|
||||
&user.Lastname,
|
||||
&user.Currentlocation,
|
||||
&user.Birthday,
|
||||
&user.Userpicture,
|
||||
&user.Certificate,
|
||||
)
|
||||
|
||||
return user, err
|
||||
}
|
||||
44
src/structs/structs.go
Normal file
44
src/structs/structs.go
Normal file
@ -0,0 +1,44 @@
|
||||
package structs
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
valid "github.com/go-ozzo/ozzo-validation"
|
||||
"github.com/gocql/gocql"
|
||||
)
|
||||
|
||||
// User struct for user
|
||||
type USER struct {
|
||||
Id gocql.UUID `cql:"id" json:"id,omitempty"`
|
||||
Firstname string `cql:"firstname" json:"firstname"`
|
||||
Lastname string `cql:"lastname" json:"lastname"`
|
||||
Birthday string `cql:"birthday" json:"birthday"`
|
||||
Currentlocation string `cql:"currentlocation" json:"currentlocation"`
|
||||
Userpicture string `cql:"userpicture" json:"userpicture"`
|
||||
Certificate string `cql:"certificate" json:"certificate"`
|
||||
}
|
||||
|
||||
// Validate check Birthday for format yyyy-mm-dd
|
||||
func (u *USER) Validate() error {
|
||||
var fieldRules []*valid.FieldRules
|
||||
fieldRules = append(fieldRules, valid.Field(&u.Birthday, valid.Date("2006-01-02")))
|
||||
return valid.ValidateStruct(u, fieldRules...)
|
||||
}
|
||||
|
||||
// ANSWERAPI struct for api answer
|
||||
type ANSWERAPI struct {
|
||||
STATUS bool `json:"status"`
|
||||
DATA interface{} `json:"data"`
|
||||
ERROR string `json:"error"`
|
||||
ADDITIONAL string `json:"additional"`
|
||||
}
|
||||
|
||||
// Prepare to bool and uppercase errors
|
||||
func (a *ANSWERAPI) Prepare() {
|
||||
if a.ERROR != "" {
|
||||
a.STATUS = false
|
||||
} else {
|
||||
a.STATUS = true
|
||||
}
|
||||
a.ERROR = strings.ToUpper(a.ERROR)
|
||||
}
|
||||
45
src/utils/utils.go
Normal file
45
src/utils/utils.go
Normal file
@ -0,0 +1,45 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"userprofileservice/src/structs"
|
||||
)
|
||||
|
||||
// GetEnv look up ENV settings
|
||||
func GetEnv(key, fallback string) string {
|
||||
if value, ok := os.LookupEnv(key); ok {
|
||||
return value
|
||||
}
|
||||
|
||||
return fallback
|
||||
}
|
||||
|
||||
// ParsePort return port for cassandra
|
||||
func ParsePort(p string) int {
|
||||
i, err := strconv.Atoi(p)
|
||||
if err != nil {
|
||||
return 9042
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// AvailableField check field struct and add value
|
||||
func AvailableAndAddValue(v *structs.USER, field, link string) bool {
|
||||
s := reflect.ValueOf(v).Elem()
|
||||
typeOfT := s.Type()
|
||||
|
||||
for i := 0; i < s.NumField(); i++ {
|
||||
name := typeOfT.Field(i).Name
|
||||
if strings.ToLower(name) == field {
|
||||
if link != "" {
|
||||
reflect.ValueOf(v).Elem().FieldByName(name).SetString(link)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
255
src/view/api.go
Normal file
255
src/view/api.go
Normal file
@ -0,0 +1,255 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"userprofileservice/src/aws"
|
||||
"userprofileservice/src/controller"
|
||||
"userprofileservice/src/structs"
|
||||
"userprofileservice/src/utils"
|
||||
|
||||
_ "userprofileservice/src/docs"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/gorilla/mux"
|
||||
httpSwagger "github.com/swaggo/http-swagger"
|
||||
)
|
||||
|
||||
type API struct {
|
||||
services *controller.Controller
|
||||
aws *aws.AWS
|
||||
}
|
||||
|
||||
func NewView(controller *controller.Controller) *API {
|
||||
a := &API{
|
||||
services: controller,
|
||||
aws: aws.InitAWS(),
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *API) InitRouting() *mux.Router {
|
||||
routing := mux.NewRouter()
|
||||
routing.PathPrefix("/swagger").Handler(httpSwagger.WrapHandler)
|
||||
routing.HandleFunc("/", a.handleRoot()).Methods("GET")
|
||||
routing.HandleFunc("/user/{id:[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}}",
|
||||
a.getUser()).Methods("GET")
|
||||
routing.HandleFunc("/user", a.createUser()).Methods("POST")
|
||||
routing.HandleFunc("/upload/{field:\\w+}", a.uploadFiles()).Methods("POST")
|
||||
|
||||
routing.NotFoundHandler = http.HandlerFunc(a.notFound)
|
||||
routing.MethodNotAllowedHandler = http.HandlerFunc(a.notAllowed)
|
||||
return routing
|
||||
}
|
||||
|
||||
// swag init -g src/view/api.go -o src/docs/
|
||||
|
||||
// @title User Profile Service API
|
||||
// @version 0.1
|
||||
// @description API Server for User Profile Service
|
||||
// @host localhost:8080
|
||||
// @BasePath /
|
||||
|
||||
// @Summary Get User by UID
|
||||
// @Tags getuser
|
||||
// @Description get user by uuid
|
||||
// @ID get-user-by-uid
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "User ID"
|
||||
// @Success 200 {object} structs.USER
|
||||
// @Failure 400,404 {object} structs.ANSWERAPI
|
||||
// @Failure 500 {object} structs.ANSWERAPI
|
||||
// @Failure default {object} structs.ANSWERAPI
|
||||
// @Router /user/{id} [get]
|
||||
// getUser return one user data in json
|
||||
func (a *API) getUser() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
uid, err := gocql.ParseUUID(vars["id"])
|
||||
if err != nil {
|
||||
a.respond(w, r, http.StatusBadRequest, nil, err, "")
|
||||
return
|
||||
}
|
||||
user, err := a.services.GetUser(uid)
|
||||
if err != nil {
|
||||
a.respond(w, r, http.StatusInternalServerError, nil, err, "")
|
||||
return
|
||||
}
|
||||
a.respond(w, r, http.StatusOK, user, nil, "")
|
||||
}
|
||||
}
|
||||
|
||||
// @Summary Create User
|
||||
// @Tags createuser
|
||||
// @Description create or update user
|
||||
// @ID create-user
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param input body structs.USER true "User data"
|
||||
// @Success 200 {object} structs.USER
|
||||
// @Failure 400,404 {object} structs.ANSWERAPI
|
||||
// @Failure 500 {object} structs.ANSWERAPI
|
||||
// @Failure default {object} structs.ANSWERAPI
|
||||
// @Router /user [post]
|
||||
// writeUser gets json request and write to nosql, without id - create new user
|
||||
// {
|
||||
// "firstname":"username",
|
||||
// "lastname":"username",
|
||||
// "birthday":"1972-06-10",
|
||||
// "currentlocation":"Location"
|
||||
// }
|
||||
func (a *API) createUser() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var user *structs.USER
|
||||
err := json.NewDecoder(r.Body).Decode(&user)
|
||||
if err != nil {
|
||||
a.respond(w, r, http.StatusBadRequest, nil, err, "")
|
||||
return
|
||||
}
|
||||
err = user.Validate()
|
||||
if err != nil {
|
||||
a.respond(w, r, http.StatusBadRequest, nil, err, "")
|
||||
return
|
||||
}
|
||||
err = a.services.CreateUser(user)
|
||||
if err != nil {
|
||||
a.respond(w, r, http.StatusInternalServerError, nil, err, "")
|
||||
return
|
||||
}
|
||||
a.respond(w, r, http.StatusOK, user, nil, "")
|
||||
}
|
||||
}
|
||||
|
||||
// @Summary Upload File
|
||||
// @Tags uploadfile
|
||||
// @Description upload file for user, one by one
|
||||
// @ID upload-file
|
||||
// @Accept mpfd
|
||||
// @Produce json
|
||||
// @Param field path string true "User struct field"
|
||||
// @Param id formData string true "UUID"
|
||||
// @Param file_name formData string true "File name"
|
||||
// @Param input formData file true "File data"
|
||||
// @Success 200 {object} structs.USER
|
||||
// @Failure 400,404 {object} structs.ANSWERAPI
|
||||
// @Failure 500 {object} structs.ANSWERAPI
|
||||
// @Failure default {object} structs.ANSWERAPI
|
||||
// @Router /upload/{field} [post]
|
||||
// uploadFiles get form-data request
|
||||
// params:
|
||||
// url /upload/<field of user struct> e.g. /upload/userpicture
|
||||
// uid - User UUID
|
||||
// file - file data
|
||||
// file_name - e.g. 1234.jpg
|
||||
func (a *API) uploadFiles() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
file_field := vars["field"]
|
||||
// get uuid from request
|
||||
uid, err := gocql.ParseUUID(r.FormValue("id"))
|
||||
if err != nil {
|
||||
a.respond(w, r, http.StatusBadRequest, nil, err, "")
|
||||
return
|
||||
}
|
||||
// find user by uuid
|
||||
user, err := a.services.GetUser(uid)
|
||||
if err != nil {
|
||||
a.respond(w, r, http.StatusNotFound, nil, err, "")
|
||||
return
|
||||
}
|
||||
// check available field in struct
|
||||
if !utils.AvailableAndAddValue(user, file_field, "") {
|
||||
a.respond(w, r, http.StatusBadRequest, nil, errors.New("wrong url parameter"), "")
|
||||
return
|
||||
}
|
||||
|
||||
file_name := r.FormValue("file_name")
|
||||
fileUrl, err := a.fileHandler(r, file_name)
|
||||
if err != nil {
|
||||
a.respond(w, r, http.StatusInternalServerError, nil, err, file_name)
|
||||
return
|
||||
}
|
||||
// add aws url to struct user
|
||||
utils.AvailableAndAddValue(user, file_field, fileUrl)
|
||||
err = a.services.CreateUser(user)
|
||||
if err != nil {
|
||||
a.respond(w, r, http.StatusInternalServerError, nil, err, "")
|
||||
return
|
||||
}
|
||||
a.respond(w, r, http.StatusOK, user, nil, "")
|
||||
}
|
||||
}
|
||||
|
||||
// fileHandler get data from MultipartForm and send to AWS S3
|
||||
func (a *API) fileHandler(r *http.Request, filename string) (string, error) {
|
||||
// total of maxMemory bytes
|
||||
err := r.ParseMultipartForm(10 << 20)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// file upload as form-data
|
||||
m := r.MultipartForm
|
||||
fileUrl := ""
|
||||
|
||||
for _, v := range m.File {
|
||||
for _, f := range v {
|
||||
file, err := f.Open()
|
||||
if err != nil {
|
||||
return fileUrl, err
|
||||
}
|
||||
defer file.Close()
|
||||
// upload file to aws
|
||||
fileUrl, err = a.aws.UploadFile(file, filename)
|
||||
if err != nil {
|
||||
return fileUrl, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fileUrl, nil
|
||||
}
|
||||
|
||||
// handleRoot paga page
|
||||
func (a *API) handleRoot() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
a.respond(w, r, http.StatusOK, nil, nil, "")
|
||||
}
|
||||
}
|
||||
|
||||
// notFound page not found
|
||||
func (a *API) notFound(w http.ResponseWriter, r *http.Request) {
|
||||
a.respond(w, r, http.StatusNotFound, nil, errors.New("page not found"), "")
|
||||
}
|
||||
|
||||
// notAllowed return custom method method not allowed
|
||||
func (a *API) notAllowed(w http.ResponseWriter, r *http.Request) {
|
||||
a.respond(w, r, http.StatusMethodNotAllowed, nil, errors.New("method not allowed"), "")
|
||||
}
|
||||
|
||||
// setAnswer set api's answer
|
||||
func setAnswer(data interface{}, e error, add string) *structs.ANSWERAPI {
|
||||
err := ""
|
||||
if e != nil {
|
||||
err = e.Error()
|
||||
}
|
||||
a := &structs.ANSWERAPI{
|
||||
DATA: data,
|
||||
ERROR: err,
|
||||
ADDITIONAL: add,
|
||||
}
|
||||
a.Prepare()
|
||||
return a
|
||||
}
|
||||
|
||||
// respond generate http response for api
|
||||
func (a *API) respond(w http.ResponseWriter, r *http.Request, code int, data interface{}, e error, add string) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
|
||||
w.WriteHeader(code)
|
||||
if r.Method == "OPTIONS" {
|
||||
return
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(setAnswer(data, e, add))
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user