Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 988479dc5d | |||
| 5a304f11ac | |||
| 44edb080d8 | |||
| 5540e02644 | |||
| 956fd3ee84 | |||
| 1ef015cd05 | |||
| ed325c7faa | |||
| 5279e34b2c | |||
| ad647fd1b0 | |||
| ee0b512bfe | |||
| e546d16222 | |||
| 40a7d841b8 | |||
| e97b232207 | |||
| 1e1cce9dc2 | |||
| e022d60b61 | |||
| 07dbe290f1 | |||
| 0321f7b767 | |||
| bd0929748c | |||
| 662a9b7ffd | |||
| 89b665c3d9 | |||
| 9ceea35b08 | |||
| a6b70410f5 | |||
| 060b6af9b3 | |||
| 748459c788 | |||
| 8469bd3f33 | |||
| cb6004f230 | |||
| ab961a8608 | |||
| b58b07f0ac | |||
| 50b2127bd7 | |||
| 52fc66e7a9 | |||
| bff728234b | |||
| 7adf6f1699 | |||
| 6a9c3e3d3c | |||
| 8e6b85541e | |||
| 7daeb3e38e | |||
| f8f390e425 | |||
| f978db83ee | |||
| ddbb8bea25 | |||
| ce20b2cc18 | |||
| 178ac59dca | |||
| d8e14eefe2 | |||
| 4bed682b5f | |||
| 8bd73873b9 | |||
| 3f341790c3 | |||
| 3518099b43 | |||
| 7f951cd42d | |||
| ac19e766cf | |||
| 13073daa38 | |||
| 85f03049d9 | |||
| a73f2b2921 | |||
| 71a43d17a1 | |||
| 1909744c79 | |||
| 380fe41d1a | |||
| 7adf3b9512 | |||
| cd9bbdfd75 | |||
| 90765beb35 | |||
| 167d067aed | |||
| 0a684d45f9 | |||
| 78418b230d | |||
| cff0644ccb | |||
| 653224943b | |||
| 09ecea4d1a | |||
| 38d7d1ab86 | |||
| 2e67274cc2 | |||
| 93e4cdaa74 | |||
| ec4164a9e2 | |||
| 6f7fdad944 |
@@ -1,2 +0,0 @@
|
||||
SERVER_IP=0.0.0.0
|
||||
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/egommerce
|
||||
25
.gitignore
vendored
25
.gitignore
vendored
@@ -1,19 +1,12 @@
|
||||
# ---> Go
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
deploy/.env
|
||||
!deploy/.env.dist
|
||||
deploy/.env.*
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
deploy/server
|
||||
deploy/scheduler
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
.env
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
vendor/
|
||||
!deploy/certs/.gitkeep
|
||||
deploy/certs/*
|
||||
|
||||
.vscode/
|
||||
__debug_bin
|
||||
25
Dockerfile
25
Dockerfile
@@ -1,25 +0,0 @@
|
||||
# Builder
|
||||
FROM golang:alpine AS builder
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
ARG MAIN_GO=cmd/main.go
|
||||
|
||||
COPY src ./
|
||||
|
||||
RUN go mod download && \
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /go/bin/app $MAIN_GO
|
||||
|
||||
# Destination image
|
||||
FROM gcr.io/distroless/base-debian10
|
||||
|
||||
LABEL author="Piotr Biernat"
|
||||
LABEL service="identity"
|
||||
LABEL vendor="Egommerce"
|
||||
LABEL version="1.0"
|
||||
|
||||
COPY --from=builder /go/bin/app /app
|
||||
COPY .env.dist /.env
|
||||
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/app"]
|
||||
15
Dockerfile.builder
Normal file
15
Dockerfile.builder
Normal file
@@ -0,0 +1,15 @@
|
||||
# Builder
|
||||
FROM golang:alpine
|
||||
|
||||
ARG BIN_OUTPUT=/go/bin
|
||||
ARG GO_SERVER=cmd/server/main.go
|
||||
ARG GO_CHRONOS=cmd/scheduler/main.go
|
||||
ARG GO_MIGRATE=cmd/migrate/main.go
|
||||
|
||||
WORKDIR /go/src/app
|
||||
COPY src/ ./
|
||||
|
||||
RUN export CGO_ENABLED=0 ; export GOOS=linux ; export GOARCH=amd64 && \
|
||||
go build -ldflags="-w -s" -o "$BIN_OUTPUT/server" $GO_SERVER && \
|
||||
go build -ldflags="-w -s" -o "$BIN_OUTPUT/scheduler" $GO_CHRONOS && \
|
||||
go build -ldflags="-w -s" -o "$BIN_OUTPUT/migrate" $GO_MIGRATE
|
||||
33
Dockerfile.target
Normal file
33
Dockerfile.target
Normal file
@@ -0,0 +1,33 @@
|
||||
# Builder
|
||||
ARG BUILDER_IMAGE
|
||||
FROM ${BUILDER_IMAGE} AS builder
|
||||
|
||||
# Destination image - server
|
||||
# FROM gcr.io/distroless/base-debian10
|
||||
FROM alpine:3.22
|
||||
|
||||
ARG SVC_NAME
|
||||
ARG SVC_VER
|
||||
ARG BUILD_TIME
|
||||
|
||||
LABEL dev.egommerce.image.author="Piotr Biernat"
|
||||
LABEL dev.egommerce.image.vendor="Egommerce"
|
||||
LABEL dev.egommerce.image.service=${SVC_NAME}
|
||||
LABEL dev.egommerce.image.version=${SVC_VER}
|
||||
LABEL dev.egommerce.image.build_time=${BUILD_TIME}
|
||||
|
||||
WORKDIR /
|
||||
|
||||
COPY --from=builder /go/bin/server /usr/local/bin/server
|
||||
COPY --from=builder /go/bin/migrate /usr/local/bin/migrate
|
||||
COPY --from=builder /go/bin/scheduler /usr/local/bin/scheduler
|
||||
|
||||
COPY deploy/.env.docker /.env
|
||||
COPY ./bin/* /usr/local/bin/
|
||||
|
||||
RUN chmod 755 /usr/local/bin/entrypoint.sh /usr/local/bin/migrate.sh
|
||||
|
||||
EXPOSE 443
|
||||
|
||||
ENTRYPOINT ["entrypoint.sh"]
|
||||
CMD ["sh", "-c", "/usr/local/bin/server"]
|
||||
173
LICENSE.md
Normal file
173
LICENSE.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
|
||||
|
||||
Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible.
|
||||
|
||||
**Using Creative Commons Public Licenses**
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses.
|
||||
|
||||
* __Considerations for licensors:__ Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. [More considerations for licensors](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors).
|
||||
|
||||
* __Considerations for the public:__ By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. [More considerations for the public](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees).
|
||||
|
||||
## Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.
|
||||
|
||||
### Section 1 – Definitions.
|
||||
|
||||
a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.
|
||||
|
||||
b. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. __BY-NC-SA Compatible License__ means a license listed at [creativecommons.org/compatiblelicenses](http://creativecommons.org/compatiblelicenses), approved by Creative Commons as essentially the equivalent of this Public License.
|
||||
|
||||
d. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
|
||||
|
||||
e. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.
|
||||
|
||||
f. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.
|
||||
|
||||
g. __License Elements__ means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution, NonCommercial, and ShareAlike.
|
||||
|
||||
h. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License.
|
||||
|
||||
i. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
j. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License.
|
||||
|
||||
k. __NonCommercial__ means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange.
|
||||
|
||||
l. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.
|
||||
|
||||
m. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.
|
||||
|
||||
n. __You__ means the individual or entity exercising the Licensed Rights under this Public License. __Your__ has a corresponding meaning.
|
||||
|
||||
### Section 2 – Scope.
|
||||
|
||||
a. ___License grant.___
|
||||
|
||||
1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and
|
||||
|
||||
B. produce, reproduce, and Share Adapted Material for NonCommercial purposes only.
|
||||
|
||||
2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.
|
||||
|
||||
3. __Term.__ The term of this Public License is specified in Section 6(a).
|
||||
|
||||
4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
|
||||
|
||||
5. __Downstream recipients.__
|
||||
|
||||
A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.
|
||||
|
||||
B. __Additional offer from the Licensor – Adapted Material.__ Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply.
|
||||
|
||||
C. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.
|
||||
|
||||
6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. ___Other rights.___
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes.
|
||||
|
||||
### Section 3 – License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the following conditions.
|
||||
|
||||
a. ___Attribution.___
|
||||
|
||||
1. If You Share the Licensed Material (including in modified form), You must:
|
||||
|
||||
A. retain the following if it is supplied by the Licensor with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
|
||||
|
||||
B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
|
||||
|
||||
C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.
|
||||
|
||||
3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.
|
||||
|
||||
b. ___ShareAlike.___
|
||||
|
||||
In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply.
|
||||
|
||||
1. The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC-SA Compatible License.
|
||||
|
||||
2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material.
|
||||
|
||||
3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply.
|
||||
|
||||
### Section 4 – Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only;
|
||||
|
||||
b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.
|
||||
|
||||
### Section 5 – Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__
|
||||
|
||||
b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
|
||||
|
||||
### Section 6 – Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
|
||||
|
||||
### Section 7 – Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.
|
||||
|
||||
### Section 8 – Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.
|
||||
|
||||
> Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses.
|
||||
>
|
||||
> Creative Commons may be contacted at creativecommons.org
|
||||
26
Makefile
Normal file
26
Makefile
Normal file
@@ -0,0 +1,26 @@
|
||||
DEPLOY_DIR := ./deploy
|
||||
SRC_DIR := ./src
|
||||
|
||||
build-image-dev:
|
||||
- sh ${DEPLOY_DIR}/image-build.sh dev
|
||||
|
||||
build-image-prod:
|
||||
- sh ${DEPLOY_DIR}/image-build.sh
|
||||
|
||||
push-image-dev:
|
||||
- sh ${DEPLOY_DIR}/image-push.sh dev
|
||||
|
||||
push-image-prod:
|
||||
- sh ${DEPLOY_DIR}/image-push.sh
|
||||
|
||||
build-local-server:
|
||||
- go build -C ${SRC_DIR} -o ../deploy/server cmd/server/main.go
|
||||
|
||||
run-local-server:
|
||||
- cd deploy/ && ./server
|
||||
|
||||
build-local-scheduler:
|
||||
- go build -C ${SRC_DIR} -o ../deploy/scheduler cmd/scheduler/main.go
|
||||
|
||||
run-local-scheduler:
|
||||
- cd deploy/ && ./scheduler
|
||||
30
README.md
30
README.md
@@ -2,8 +2,30 @@
|
||||
|
||||
Authentication & Authorization service
|
||||
|
||||
Budowanie obrazu:
|
||||
$ sh deploy/image-build.sh
|
||||
Prepare local dev environment
|
||||
|
||||
Opublikowanie obrazu:
|
||||
$ sh deploy/image-push.sh
|
||||
1. Add following entry to the /etc/hosts file
|
||||
|
||||
```127.0.0.1 egommerce.local```
|
||||
2. Modify and copy (or link) ```deploy/.env.local``` to the ```deploy/.env``` file
|
||||
3. Link the cert and key files from stack (./deploy/certs/identity-svc/) to the local ./deploy/certs dir:
|
||||
|
||||
```ln -s PATH_TO_THE_STACK_DIR/deploy/certs/identity-svc/identity-svc.crt deploy/certs/identity-svc.crt```
|
||||
|
||||
```ln -s PATH_TO_THE_STACK_DIR/deploy/certs/identity-svc/identity-svc.key deploy/certs/identity-svc.key```
|
||||
4. Build server app binary:
|
||||
```make build-local```
|
||||
5. Run server app:
|
||||
```make run-local```
|
||||
|
||||
Build prod image:
|
||||
$ make build-image-prod
|
||||
|
||||
Push prod image:
|
||||
$ make push-image-prod
|
||||
|
||||
Build dev image:
|
||||
$ make build-image-dev
|
||||
|
||||
Push dev image:
|
||||
$ make push-image-dev
|
||||
|
||||
6
bin/entrypoint.sh
Executable file
6
bin/entrypoint.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# run migrations
|
||||
migrate.sh
|
||||
|
||||
exec "$@"
|
||||
26
bin/migrate.sh
Normal file
26
bin/migrate.sh
Normal file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# ensure migrate env is initialized
|
||||
$(migrate version >/dev/null 2>&1)
|
||||
version=$?
|
||||
if [ $version != "0" ]
|
||||
then
|
||||
echo "Creating base table..."
|
||||
$(migrate init >/dev/null 2>&1)
|
||||
init=$?
|
||||
fi
|
||||
|
||||
# check again
|
||||
$(migrate version >/dev/null 2>&1)
|
||||
version=$?
|
||||
if [ $version != "0" ]
|
||||
then
|
||||
echo "Unable to run migrations."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# run migrations
|
||||
migrate up
|
||||
echo "Done."
|
||||
|
||||
exit $version
|
||||
16
deploy/.env.dist
Normal file
16
deploy/.env.dist
Normal file
@@ -0,0 +1,16 @@
|
||||
SERVER_ADDR=:443
|
||||
|
||||
APP_NAME=identity-svc
|
||||
APP_DOMAIN=identity.service.ego.io
|
||||
|
||||
API_DATABASE_URL=postgres://postgres:12345678@db-postgres:5432/egommerce
|
||||
API_CACHE_ADDR=api-cache:6379
|
||||
API_CACHE_USERNAME=default
|
||||
API_CACHE_PASSWORD=12345678
|
||||
API_MONGODB_URL=mongodb://mongodb:12345678@mongo-db:27017
|
||||
|
||||
JWT_ACCESS_TOKEN_SECRET_KEY=SomeFancySecretAndRandomString
|
||||
JWT_ACCESS_TOKEN_EXPIRE_TIME=1 # hours
|
||||
|
||||
JWT_REFRESH_TOKEN_SECRET_KEY=SomeFancySecretAndRandomStringAgain
|
||||
JWT_REFRESH_TOKEN_EXPIRE_TIME=7 # days
|
||||
0
deploy/certs/.gitkeep
Normal file
0
deploy/certs/.gitkeep
Normal file
@@ -1,6 +1,38 @@
|
||||
#!/bin/sh
|
||||
# RUN IN REPO ROOT DIR !!
|
||||
|
||||
export IMAGE_NAME="git.pbiernat.dev/egommerce/identity-svc"
|
||||
export IMAGE_PREFIX="git.ego.freeddns.org/egommerce/identity"
|
||||
export BUILDER_IMAGE="egommerce-builder:identity"
|
||||
export BUILD_TIME=$(date +"%Y%m%d%H%M%S")
|
||||
export SERVER_IMAGE="$IMAGE_PREFIX-svc"
|
||||
|
||||
docker build --rm --cache-from "$IMAGE_NAME:latest" -t "$IMAGE_NAME:latest" .
|
||||
TARGET=${1:-latest}
|
||||
|
||||
[ ! -d "src/vendor" ] && sh -c "cd src; go mod vendor"
|
||||
|
||||
echo "Building target $IMAGE_PREFIX images..."
|
||||
docker build --rm -t $BUILDER_IMAGE -f Dockerfile.builder .
|
||||
|
||||
if [ $TARGET = "latest" ]
|
||||
then
|
||||
# PROD
|
||||
docker build \
|
||||
--build-arg SVC_NAME=identity-service \
|
||||
--build-arg SVC_VER="1.0" \
|
||||
--build-arg BUILDER_IMAGE=$BUILDER_IMAGE \
|
||||
--build-arg BUILD_TIME \
|
||||
--rm --cache-from $SERVER_IMAGE:$TARGET \
|
||||
-t $SERVER_IMAGE:$TARGET \
|
||||
-f Dockerfile.target . > /dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET"
|
||||
else
|
||||
# DEV
|
||||
docker build \
|
||||
--build-arg SVC_NAME=identity-service \
|
||||
--build-arg SVC_VER="dev" \
|
||||
--build-arg BUILDER_IMAGE=$BUILDER_IMAGE \
|
||||
--build-arg BUILD_TIME \
|
||||
--rm --no-cache -t $SERVER_IMAGE:$TARGET \
|
||||
-f Dockerfile.target . > /dev/null 2>&1 && echo "Successfully tagged $SERVER_IMAGE:$TARGET"
|
||||
fi
|
||||
|
||||
echo "Done."
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
#!/bin/sh
|
||||
# RUN IN REPO ROOT DIR !!
|
||||
|
||||
export IMAGE_NAME="git.pbiernat.dev/egommerce/identity-svc"
|
||||
export IMAGE_PREFIX="git.ego.freeddns.org/egommerce/identity"
|
||||
export SERVER_IMAGE="$IMAGE_PREFIX-svc"
|
||||
|
||||
echo $DOCKER_PASSWORD | docker login git.pbiernat.dev -u $DOCKER_USERNAME --password-stdin
|
||||
docker push "$IMAGE_NAME:latest"
|
||||
TARGET=${1:-latest}
|
||||
|
||||
echo $DOCKER_PASSWORD | docker login git.ego.freeddns.org -u $DOCKER_USERNAME --password-stdin
|
||||
|
||||
docker push "$SERVER_IMAGE:$TARGET"
|
||||
|
||||
# Restart container
|
||||
# TODO
|
||||
18
src/.gitignore
vendored
Normal file
18
src/.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# ---> Go
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dlli
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
.env
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
vendor/
|
||||
40
src/app/app.go
Normal file
40
src/app/app.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
worker WorkerInterface
|
||||
}
|
||||
|
||||
func NewApp(worker WorkerInterface) *App {
|
||||
return &App{
|
||||
worker: worker,
|
||||
}
|
||||
}
|
||||
|
||||
func (app *App) Start(while chan struct{}) error {
|
||||
go func(while chan struct{}) {
|
||||
sigint := make(chan os.Signal, 1)
|
||||
signal.Notify(sigint, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sigint
|
||||
|
||||
log.Println("Received signal:", sigint)
|
||||
app.Shutdown()
|
||||
close(while)
|
||||
}(while)
|
||||
|
||||
return app.worker.Start()
|
||||
}
|
||||
|
||||
func (app *App) Shutdown() {
|
||||
app.worker.OnShutdown()
|
||||
}
|
||||
|
||||
func (app *App) RegisterPlugin(plugin Plugin) {
|
||||
app.worker.addPlugin(plugin.name, plugin.fn)
|
||||
}
|
||||
57
src/app/config.go
Normal file
57
src/app/config.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config"
|
||||
)
|
||||
|
||||
const (
|
||||
defName = "identity-svc"
|
||||
defNetAddr = ":443"
|
||||
defDomain = "identity-svc"
|
||||
defCacheAddr = "api-cache:6379"
|
||||
defCacheUsername = "default"
|
||||
defCachePassword = "12345678"
|
||||
defDbURL = "postgres://postgres:12345678@db-postgres:5432/egommerce"
|
||||
defMongoDbURL = "mongodb://mongodb:12345678@db-mongo:27017"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ID string
|
||||
Name string
|
||||
Domain string
|
||||
NetAddr string
|
||||
|
||||
IdleTimeout time.Duration // miliseconds
|
||||
ReadTimeout time.Duration // miliseconds
|
||||
WriteTimeout time.Duration // miliseconds
|
||||
|
||||
DbURL string `json:"db_url"`
|
||||
CacheAddr string `json:"cache_addr"`
|
||||
CacheUsername string `json:"cache_username"`
|
||||
CachePassword string `json:"cache_password"`
|
||||
MongoDbUrl string `json:"mongodb_url"`
|
||||
}
|
||||
|
||||
func NewConfig(name string) *Config {
|
||||
c := new(Config)
|
||||
|
||||
c.ID, _ = os.Hostname()
|
||||
c.Name = name
|
||||
c.Domain = cnf.GetEnv("APP_DOMAIN", defDomain)
|
||||
c.NetAddr = cnf.GetEnv("SERVER_ADDR", defNetAddr)
|
||||
c.CacheAddr = cnf.GetEnv("API_CACHE_ADDR", defCacheAddr)
|
||||
c.CacheUsername = cnf.GetEnv("API_CACHE_USERNAME", defCacheUsername)
|
||||
c.CachePassword = cnf.GetEnv("API_CACHE_PASSWORD", defCachePassword)
|
||||
c.DbURL = cnf.GetEnv("API_DATABASE_URL", defDbURL)
|
||||
c.MongoDbUrl = cnf.GetEnv("API_MONGO_URL", defMongoDbURL)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Config) getAppFullName() string {
|
||||
return fmt.Sprintf("%s_%s", c.Name, c.ID)
|
||||
}
|
||||
23
src/app/interface.go
Normal file
23
src/app/interface.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package app
|
||||
|
||||
type (
|
||||
Application interface {
|
||||
Start()
|
||||
RegisterPlugin(Plugin)
|
||||
Shutdown()
|
||||
}
|
||||
|
||||
WorkerInterface interface {
|
||||
Start() error
|
||||
OnShutdown()
|
||||
|
||||
addPlugin(name string, fn PluginFn)
|
||||
}
|
||||
|
||||
Plugin struct {
|
||||
name string
|
||||
fn PluginFn
|
||||
}
|
||||
|
||||
PluginFn func() any
|
||||
)
|
||||
64
src/app/plugins.go
Normal file
64
src/app/plugins.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
redis "github.com/go-redis/redis/v8"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
db "github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
type PluginManager struct {
|
||||
plugins map[string]any
|
||||
}
|
||||
|
||||
func NewPluginManager() *PluginManager {
|
||||
return &PluginManager{
|
||||
plugins: make(map[string]any),
|
||||
}
|
||||
}
|
||||
|
||||
func (pm *PluginManager) addPlugin(name string, fn PluginFn) {
|
||||
pm.plugins[name] = fn()
|
||||
}
|
||||
|
||||
func (pm *PluginManager) getCache() *redis.Client {
|
||||
return (pm.plugins["cache"]).(*redis.Client)
|
||||
}
|
||||
|
||||
func (pm *PluginManager) getDatabase() *pgxpool.Pool {
|
||||
return (pm.plugins["database"]).(*pgxpool.Pool)
|
||||
}
|
||||
|
||||
func CachePlugin(cnf *Config) Plugin {
|
||||
return Plugin{
|
||||
name: "cache",
|
||||
fn: func() any {
|
||||
return redis.NewClient(&redis.Options{
|
||||
Addr: cnf.CacheAddr,
|
||||
Username: cnf.CacheUsername,
|
||||
Password: cnf.CachePassword,
|
||||
DB: 0, // TODO
|
||||
DialTimeout: 100 * time.Millisecond, // TODO
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func DatabasePlugin(cnf *Config) Plugin {
|
||||
return Plugin{
|
||||
name: "database",
|
||||
fn: func() any {
|
||||
dbConn, err := db.New(context.Background(), cnf.DbURL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect to the Database: %s. Err: %v\n", cnf.DbURL, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return dbConn
|
||||
},
|
||||
}
|
||||
}
|
||||
44
src/app/scheduler.go
Normal file
44
src/app/scheduler.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/onatm/clockwerk"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/cli/scheduler"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
)
|
||||
|
||||
type Scheduler struct {
|
||||
*PluginManager
|
||||
}
|
||||
|
||||
func NewScheduler(c *Config) *Scheduler {
|
||||
return &Scheduler{
|
||||
PluginManager: NewPluginManager(),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Scheduler) Start() error { // STILL NEEDS REFACTORING ;)
|
||||
userRepo := repository.NewUserRepository(c.getDatabase())
|
||||
roleRepo := repository.NewRoleRepository(c.getDatabase())
|
||||
urlRepo := repository.NewURLAccessRepository(c.getDatabase())
|
||||
authSrv := service.NewAuthService(userRepo, c.getCache())
|
||||
guardSrv := service.NewGuardService(authSrv, c.getCache(), userRepo, roleRepo, urlRepo)
|
||||
|
||||
job := scheduler.NewCachePermissionsJob(guardSrv)
|
||||
sch := clockwerk.New()
|
||||
sch.Every(30 * time.Minute).Do(job)
|
||||
sch.Start()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Scheduler) OnShutdown() {
|
||||
log.Println("Scheduler is going down...")
|
||||
|
||||
c.getDatabase().Close()
|
||||
c.getCache().Close()
|
||||
}
|
||||
131
src/app/server.go
Normal file
131
src/app/server.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
jwt "github.com/gofiber/contrib/jwt"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
"github.com/google/uuid"
|
||||
|
||||
commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto"
|
||||
cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/http"
|
||||
)
|
||||
|
||||
var defaultCORS = cors.New(
|
||||
cors.Config{
|
||||
// DEV CONFIG
|
||||
AllowOrigins: "*",
|
||||
AllowMethods: "GET, POST, PATCH, PUT, DELETE, OPTIONS",
|
||||
AllowHeaders: "Accept, Authorization, Content-Type, Vary, X-Request-Id",
|
||||
// PROD CONFIG
|
||||
// AllowOrigins: "http://egommerce.io:3001", // client(reactjs) app url
|
||||
// AllowCredentials: true,
|
||||
// AllowMethods: "GET, POST, PATCH, PUT, DELETE",
|
||||
},
|
||||
)
|
||||
|
||||
type (
|
||||
Server struct {
|
||||
*fiber.App
|
||||
*PluginManager
|
||||
|
||||
ID string
|
||||
addr string // e.g. "127.0.0.1:443"
|
||||
}
|
||||
)
|
||||
|
||||
func NewServer(c *Config) *Server {
|
||||
return &Server{
|
||||
ID: c.ID,
|
||||
App: fiber.New(fiber.Config{
|
||||
AppName: c.ID,
|
||||
ServerHeader: c.getAppFullName(),
|
||||
ReadTimeout: c.ReadTimeout * time.Millisecond,
|
||||
WriteTimeout: c.WriteTimeout * time.Millisecond,
|
||||
IdleTimeout: c.IdleTimeout * time.Millisecond,
|
||||
}),
|
||||
PluginManager: NewPluginManager(),
|
||||
addr: c.NetAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
s.setupMiddleware()
|
||||
s.setupRouter()
|
||||
|
||||
crt, err := tls.LoadX509KeyPair("certs/identity-svc.crt", "certs/identity-svc.key")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
tlsCnf := &tls.Config{Certificates: []tls.Certificate{crt}}
|
||||
ln, _ := net.Listen("tcp", s.addr)
|
||||
ln = tls.NewListener(ln, tlsCnf)
|
||||
|
||||
return s.Listener(ln)
|
||||
}
|
||||
|
||||
func (s *Server) OnShutdown() {
|
||||
log.Printf("Server %s is going down...", s.ID)
|
||||
|
||||
s.getDatabase().Close()
|
||||
s.getCache().Close()
|
||||
|
||||
s.Shutdown()
|
||||
}
|
||||
|
||||
func (s *Server) setupRouter() {
|
||||
s.Options("*", defaultCORS)
|
||||
s.Use(defaultCORS)
|
||||
|
||||
s.Get("/health", http.HealthHandlerFn(s.getDatabase(), s.getCache()))
|
||||
|
||||
s.Group("/v1").
|
||||
Post("/login", http.LoginHandlerFn(s.getDatabase(), s.getCache())).
|
||||
Post("/refresh", http.RefreshHandlerFn(s.getDatabase(), s.getCache())). // add JWTProtected() and get token from Auth Bearer header not from the body?
|
||||
Post("/register", http.RegisterHandlerFn(s.getDatabase(), s.getCache())).
|
||||
Get("/access", JWTProtected(), http.AccessHandlerFn(s.getDatabase(), s.getCache()))
|
||||
}
|
||||
|
||||
func (s *Server) setupMiddleware() {
|
||||
s.Use(LoggingMiddleware())
|
||||
s.Use(XRequestIDMiddleware())
|
||||
}
|
||||
|
||||
func LoggingMiddleware() func(c *fiber.Ctx) error {
|
||||
return func(c *fiber.Ctx) error {
|
||||
log.Printf("Request: %s, remote: %s, via: %s",
|
||||
c.Request().URI().String(),
|
||||
c.Context().RemoteIP().String(),
|
||||
string(c.Context().UserAgent()),
|
||||
)
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func XRequestIDMiddleware() func(c *fiber.Ctx) error {
|
||||
return func(c *fiber.Ctx) error {
|
||||
c.Set("X-Request-ID", uuid.New().String())
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func JWTProtected() func(c *fiber.Ctx) error {
|
||||
secret := []byte(cnf.GetEnv("JWT_ACCESS_TOKEN_SECRET_KEY", "FallbackAccessTokenSecret"))
|
||||
|
||||
return jwt.New(jwt.Config{
|
||||
SigningKey: jwt.SigningKey{Key: secret},
|
||||
ContextKey: "jwt",
|
||||
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(commonDTO.ErrorResponseDTO{Error: "unauthorized"})
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"git.pbiernat.dev/egommerce/identity-service/internal/app"
|
||||
"git.pbiernat.dev/egommerce/identity-service/internal/app/config"
|
||||
"git.pbiernat.dev/egommerce/identity-service/internal/app/database"
|
||||
"git.pbiernat.dev/egommerce/identity-service/internal/app/handler"
|
||||
)
|
||||
|
||||
const (
|
||||
defHTTPIP = "0.0.0.0"
|
||||
defHTTPPort = "8080"
|
||||
defDbURL = "postgres://postgres:12345678@postgres_svc:5432/egommerce"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if config.ErrLoadingEnvs != nil {
|
||||
app.Panicf("Error loading .env file")
|
||||
}
|
||||
|
||||
httpAddr := net.JoinHostPort(config.GetEnv("SERVER_IP", defHTTPIP), defHTTPPort)
|
||||
dbConnStr := config.GetEnv("DATABASE_URL", defDbURL)
|
||||
|
||||
dbc, err := database.Connect(dbConnStr)
|
||||
if err != nil {
|
||||
app.Panicf("Unable to connect to database: %v\n", err)
|
||||
}
|
||||
|
||||
env := &handler.Env{Addr: httpAddr, DB: dbc}
|
||||
srv := app.NewServer(env)
|
||||
|
||||
go srv.Start()
|
||||
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
<-c
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
srv.Shutdown(ctx)
|
||||
os.Exit(0)
|
||||
}
|
||||
74
src/cmd/migrate/main.go
Normal file
74
src/cmd/migrate/main.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/go-pg/migrations/v8"
|
||||
"github.com/go-pg/pg/v10"
|
||||
|
||||
cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config"
|
||||
)
|
||||
|
||||
const (
|
||||
defMigrationsTableName = "identity.migrations"
|
||||
)
|
||||
|
||||
const usageText = `This program runs command on the db. Supported commands are:
|
||||
- init - creates version info table in the database
|
||||
- up - runs all available migrations.
|
||||
- up [target] - runs available migrations up to the target one.
|
||||
- down - reverts last migration.
|
||||
- reset - reverts all migrations.
|
||||
- version - prints current db version.
|
||||
- set_version [version] - sets db version without running migrations.
|
||||
Usage:
|
||||
go run cmd/migrate/main.go <command> [args]
|
||||
`
|
||||
|
||||
func main() {
|
||||
flag.Usage = func() {
|
||||
fmt.Print(usageText)
|
||||
flag.PrintDefaults()
|
||||
os.Exit(2)
|
||||
}
|
||||
flag.Parse()
|
||||
|
||||
if cnf.ErrLoadingEnvs != nil {
|
||||
log.Panicln(cnf.ErrLoadingEnvs)
|
||||
}
|
||||
|
||||
// c := cnf.NewConfig("migrator")
|
||||
|
||||
// dbURL := baseCnf.GetEnv("DATABASE_URL", defDbURL)
|
||||
|
||||
db := pg.Connect(&pg.Options{ // FIXME
|
||||
Addr: "db-postgres:5432",
|
||||
User: "postgres",
|
||||
Password: "12345678",
|
||||
Database: "egommerce",
|
||||
})
|
||||
defer db.Close()
|
||||
|
||||
mTbl := cnf.GetEnv("MIGRATIONS_TABLE_NAME", defMigrationsTableName)
|
||||
|
||||
mig := migrations.NewCollection()
|
||||
mig.SetTableName(mTbl)
|
||||
if err := mig.DiscoverSQLMigrations("./migrations"); err != nil {
|
||||
log.Printf("migration dicovery error: %#v\n", err)
|
||||
}
|
||||
|
||||
oldVersion, newVersion, err := mig.Run(db, flag.Args()...)
|
||||
if err != nil {
|
||||
log.Printf("migration runner error: %#v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if newVersion != oldVersion {
|
||||
log.Printf("migrated from version %d to %d\n", oldVersion, newVersion)
|
||||
} else {
|
||||
log.Printf("version is %d\n", oldVersion)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
33
src/cmd/scheduler/main.go
Normal file
33
src/cmd/scheduler/main.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/app"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if cnf.ErrLoadingEnvs != nil {
|
||||
log.Panicln(cnf.ErrLoadingEnvs)
|
||||
}
|
||||
|
||||
cnf := app.NewConfig("identity-scheduler")
|
||||
w := app.NewScheduler(cnf)
|
||||
a := app.NewApp(w)
|
||||
a.RegisterPlugin(app.CachePlugin(cnf))
|
||||
a.RegisterPlugin(app.DatabasePlugin(cnf))
|
||||
|
||||
while := make(chan struct{})
|
||||
err := a.Start(while)
|
||||
<-while
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to scheduler. Reason: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
33
src/cmd/server/main.go
Normal file
33
src/cmd/server/main.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/app"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if cnf.ErrLoadingEnvs != nil {
|
||||
log.Panicln(cnf.ErrLoadingEnvs.Error())
|
||||
}
|
||||
|
||||
cnf := app.NewConfig("identity-svc")
|
||||
w := app.NewServer(cnf)
|
||||
a := app.NewApp(w)
|
||||
a.RegisterPlugin(app.CachePlugin(cnf))
|
||||
a.RegisterPlugin(app.DatabasePlugin(cnf))
|
||||
|
||||
while := make(chan struct{})
|
||||
err := a.Start(while)
|
||||
<-while
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to start server. Reason: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
59
src/go.mod
59
src/go.mod
@@ -1,23 +1,54 @@
|
||||
module git.pbiernat.dev/egommerce/identity-service
|
||||
module git.ego.freeddns.org/egommerce/identity-service
|
||||
|
||||
go 1.18
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.24.1
|
||||
|
||||
require (
|
||||
git.ego.freeddns.org/egommerce/api-entities v0.3.34
|
||||
git.ego.freeddns.org/egommerce/go-api-pkg v0.5.3
|
||||
github.com/georgysavva/scany/v2 v2.1.4
|
||||
github.com/go-pg/migrations/v8 v8.1.0
|
||||
github.com/go-pg/pg/v10 v10.15.0
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/gofiber/contrib/jwt v1.1.2
|
||||
github.com/gofiber/fiber/v2 v2.52.9
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/jackc/pgx/v4 v4.17.2
|
||||
github.com/joho/godotenv v1.4.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/jackc/pgx/v5 v5.7.6
|
||||
github.com/onatm/clockwerk v1.1.0
|
||||
golang.org/x/crypto v0.43.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgconn v1.13.0 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/MicahParks/keyfunc/v2 v2.1.0 // indirect
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/clipperhouse/uax29/v2 v2.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-pg/zerochecker v0.2.0 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
||||
github.com/jackc/pgtype v1.12.0 // indirect
|
||||
github.com/jackc/puddle v1.3.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/klauspost/compress v1.18.1 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.19 // indirect
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.67.0 // indirect
|
||||
github.com/vmihailenco/bufpool v0.1.11 // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||
github.com/vmihailenco/tagparser v0.1.2 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
mellium.im/sasl v0.3.2 // indirect
|
||||
)
|
||||
|
||||
381
src/go.sum
381
src/go.sum
@@ -1,190 +1,257 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
git.ego.freeddns.org/egommerce/api-entities v0.3.34 h1:WftM9cvV3JmbS1DlHCIiV3tsYIpALj9IXo90mkgZNWQ=
|
||||
git.ego.freeddns.org/egommerce/api-entities v0.3.34/go.mod h1:IqynARw+06GOm4eZGZuepmbi7bUxWBnOB4jd5cI7jf8=
|
||||
git.ego.freeddns.org/egommerce/go-api-pkg v0.5.3 h1:so+OWWVJEg6JZ5XOSmCpfW7Pd7IL6ETH0QsC6zCwndo=
|
||||
git.ego.freeddns.org/egommerce/go-api-pkg v0.5.3/go.mod h1:T3ia8iprzlTRznPVXYCgEzQb/1UvIcdn9FHabE58vy0=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k=
|
||||
github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k=
|
||||
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
|
||||
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY=
|
||||
github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
||||
github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB05Ql//KWfeTFs=
|
||||
github.com/cockroachdb/cockroach-go/v2 v2.2.0/go.mod h1:u3MiKYGupPPjkn3ozknpMUpxPaNLTFWAya419/zv6eI=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
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/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/georgysavva/scany/v2 v2.1.4 h1:nrzHEJ4oQVRoiKmocRqA1IyGOmM/GQOEsg9UjMR5Ip4=
|
||||
github.com/georgysavva/scany/v2 v2.1.4/go.mod h1:fqp9yHZzM/PFVa3/rYEC57VmDx+KDch0LoqrJzkvtos=
|
||||
github.com/go-pg/migrations/v8 v8.1.0 h1:bc1wQwFoWRKvLdluXCRFRkeaw9xDU4qJ63uCAagh66w=
|
||||
github.com/go-pg/migrations/v8 v8.1.0/go.mod h1:o+CN1u572XHphEHZyK6tqyg2GDkRvL2bIoLNyGIewus=
|
||||
github.com/go-pg/pg/v10 v10.4.0/go.mod h1:BfgPoQnD2wXNd986RYEHzikqv9iE875PrFaZ9vXvtNM=
|
||||
github.com/go-pg/pg/v10 v10.15.0 h1:6DQwbaxJz/e4wvgzbxBkBLiL/Uuk87MGgHhkURtzx24=
|
||||
github.com/go-pg/pg/v10 v10.15.0/go.mod h1:FIn/x04hahOf9ywQ1p68rXqaDVbTRLYlu4MQR0lhoB8=
|
||||
github.com/go-pg/zerochecker v0.2.0 h1:pp7f72c3DobMWOb2ErtZsnrPaSvHd2W4o9//8HtF4mU=
|
||||
github.com/go-pg/zerochecker v0.2.0/go.mod h1:NJZ4wKL0NmTtz0GKCoJ8kym6Xn/EQzXRl2OnAe7MmDo=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/gofiber/contrib/jwt v1.1.2 h1:GmWnOqT4A15EkA8IPXwSpvNUXZR4u5SMj+geBmyLAjs=
|
||||
github.com/gofiber/contrib/jwt v1.1.2/go.mod h1:CpIwrkUQ3Q6IP8y9n3f0wP9bOnSKx39EDp2fBVgMFVk=
|
||||
github.com/gofiber/fiber/v2 v2.52.9 h1:YjKl5DOiyP3j0mO61u3NTmK7or8GzzWzCFzkboyP5cw=
|
||||
github.com/gofiber/fiber/v2 v2.52.9/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
|
||||
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
|
||||
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
|
||||
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
||||
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
|
||||
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
||||
github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
|
||||
github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
|
||||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
|
||||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
|
||||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
|
||||
github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
||||
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
||||
github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
|
||||
github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
||||
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
|
||||
github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
|
||||
github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
|
||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0=
|
||||
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
||||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
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/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
|
||||
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
|
||||
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
|
||||
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
|
||||
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onatm/clockwerk v1.1.0 h1:Ig2tTdZGtYWM1n5sDcf/LZ9zKe5l569G8jIPejHS0DM=
|
||||
github.com/onatm/clockwerk v1.1.0/go.mod h1:9R0U2KkwobOCqRvPtIAt0qHgaCWbo3kjvySmmMth2Ao=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
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/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
|
||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.67.0 h1:tqKlJMUP6iuNG8hGjK/s9J4kadH7HLV4ijEcPGsezac=
|
||||
github.com/valyala/fasthttp v1.67.0/go.mod h1:qYSIpqt/0XNmShgo/8Aq8E3UYWVVwNS2QYmzd8WIEPM=
|
||||
github.com/vmihailenco/bufpool v0.1.11 h1:gOq2WmBrq0i2yW5QJ16ykccQ4wH9UyEsgLm6czKAd94=
|
||||
github.com/vmihailenco/bufpool v0.1.11/go.mod h1:AFf/MOy3l2CFTKbxwt0mp2MwnqjNEs5H/UxrkA5jxTQ=
|
||||
github.com/vmihailenco/msgpack/v4 v4.3.11/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
|
||||
github.com/vmihailenco/msgpack/v5 v5.0.0-beta.1/go.mod h1:xlngVLeyQ/Qi05oQxhQ+oTuqa03RjMwMfk/7/TCs+QI=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc=
|
||||
github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
|
||||
golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/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-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
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-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-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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
||||
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201017003518-b09fb700fbb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
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-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-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
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=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7/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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
mellium.im/sasl v0.2.1/go.mod h1:ROaEDLQNuf9vjKqE1SrAfnsobm2YKXT1gnN1uDp1PjQ=
|
||||
mellium.im/sasl v0.3.2 h1:PT6Xp7ccn9XaXAnJ03FcEjmAn7kK1x7aoXV6F+Vmrl0=
|
||||
mellium.im/sasl v0.3.2/go.mod h1:NKXDi1zkr+BlMHLQjY3ofYuU4KSPFxknb8mfEu6SveY=
|
||||
|
||||
12
src/infra/repository/interface.go
Normal file
12
src/infra/repository/interface.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package repository
|
||||
|
||||
import entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity"
|
||||
|
||||
type UserRepositoryInterface interface {
|
||||
FindAll() ([]entity.User, error)
|
||||
FindByID(id string) (*entity.User, error)
|
||||
FindByUsername(login string) (*entity.User, error)
|
||||
Create(user *entity.User) (string, error) // FIXME types
|
||||
Update(user *entity.User) (*entity.User, error) // FIXME types
|
||||
Delete(id int64) (bool, error)
|
||||
}
|
||||
64
src/infra/repository/role_repository.go
Normal file
64
src/infra/repository/role_repository.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
type RoleRepository struct {
|
||||
db *pgxpool.Pool
|
||||
}
|
||||
|
||||
func NewRoleRepository(db *pgxpool.Pool) *RoleRepository {
|
||||
return &RoleRepository{db}
|
||||
}
|
||||
|
||||
func (r *RoleRepository) FindByID(id string) (*entity.Role, error) {
|
||||
var role entity.Role
|
||||
|
||||
sql := `SELECT id, name, display_name FROM identity.roles WHERE id=$1 LIMIT 1`
|
||||
err := r.db.QueryRow(context.Background(), sql, id).
|
||||
Scan(&role.ID, &role.Name, &role.DisplayName)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to fetch role from DB: " + err.Error())
|
||||
}
|
||||
|
||||
return &role, nil
|
||||
}
|
||||
|
||||
func (r *RoleRepository) Create(role *entity.Role) (string, error) {
|
||||
var id string
|
||||
|
||||
// sql := `INSERT INTO identity.users(email, username, password) VALUES($1, $2, $3) LIMIT 1 RETURNING id`
|
||||
// err := r.db.QueryRow(context.Background(), sql, user.Email, user.Username, user.Password).Scan(&id)
|
||||
// if err != nil {
|
||||
// if err = db.IsDuplicatedRow(err); err != nil {
|
||||
// return "", errors.New("username/email is already taken")
|
||||
// }
|
||||
|
||||
// return "", errors.New("db error: " + err.Error())
|
||||
// }
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (r *RoleRepository) Update(role *entity.Role) (*entity.Role, error) {
|
||||
return &entity.Role{}, nil
|
||||
}
|
||||
|
||||
func (r *RoleRepository) Delete(id int64) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (r *RoleRepository) GetUserRole(user *entity.User) *entity.Role {
|
||||
role := new(entity.Role)
|
||||
|
||||
sql := `SELECT r.id, r.name, r.display_name FROM identity.roles r JOIN identity.users_roles ur ON r.id = ur.role_id WHERE ur.user_id=$1 LIMIT 1`
|
||||
r.db.QueryRow(context.Background(), sql, user.ID).Scan(&role.ID, &role.Name, &role.DisplayName)
|
||||
|
||||
return role
|
||||
}
|
||||
102
src/infra/repository/url_access_repository.go
Normal file
102
src/infra/repository/url_access_repository.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity"
|
||||
|
||||
database "git.ego.freeddns.org/egommerce/go-api-pkg/client/postgresql"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
type URLAccessRepository struct {
|
||||
db *pgxpool.Pool
|
||||
}
|
||||
|
||||
func NewURLAccessRepository(db *pgxpool.Pool) *URLAccessRepository {
|
||||
return &URLAccessRepository{db}
|
||||
}
|
||||
|
||||
func (r *URLAccessRepository) FindByID(id string) (*entity.URLAccess, error) {
|
||||
var urlAccess entity.URLAccess
|
||||
|
||||
sql := `SELECT id, roles, url, service FROM identity.url_access WHERE id=$1 LIMIT 1`
|
||||
err := r.db.QueryRow(context.Background(), sql, id).
|
||||
Scan(&urlAccess.ID, &urlAccess.Roles, &urlAccess.URL, &urlAccess.Service)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to fetch url_access from DB: " + err.Error())
|
||||
}
|
||||
|
||||
return &urlAccess, nil
|
||||
}
|
||||
|
||||
func (r *URLAccessRepository) FindAll() ([]entity.URLAccess, error) {
|
||||
sql := "SELECT id, roles, url, service FROM identity.url_access ORDER BY service"
|
||||
rows, err := r.db.Query(context.Background(), sql)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var results []entity.URLAccess
|
||||
for rows.Next() {
|
||||
var url entity.URLAccess
|
||||
if err := rows.Scan(&url.ID, &url.Roles, &url.URL, &url.Service); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results = append(results, url)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (r *URLAccessRepository) Create(role *entity.URLAccess) (string, error) {
|
||||
var id string
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (r *URLAccessRepository) Update(role *entity.URLAccess) (entity.URLAccess, error) {
|
||||
return entity.URLAccess{}, nil
|
||||
}
|
||||
|
||||
func (r *URLAccessRepository) Delete(id int64) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (r *URLAccessRepository) FindByURLAndService(url, service string) (*entity.URLAccess, error) {
|
||||
var urlAccess entity.URLAccess
|
||||
|
||||
sql := `SELECT id, roles, url FROM identity.url_access WHERE url=$1 AND service=$2 LIMIT 1`
|
||||
err := r.db.QueryRow(context.Background(), sql, url, service).
|
||||
Scan(&urlAccess.ID, &urlAccess.Roles, &urlAccess.URL)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to fetch url_access from DB: " + err.Error())
|
||||
}
|
||||
|
||||
return &urlAccess, nil
|
||||
}
|
||||
|
||||
func (r *URLAccessRepository) FindByURLAndServiceForRole(url, service, role string) (*entity.URLAccess, error) {
|
||||
var entity entity.URLAccess
|
||||
|
||||
sql := fmt.Sprintf("SELECT id, roles, url, service FROM identity.url_access WHERE url=$1 AND service=$2 AND roles::jsonb @> '[\"%s\"]'::jsonb LIMIT 1", role)
|
||||
err := r.db.QueryRow(context.Background(), sql, url, service).
|
||||
Scan(&entity.ID, &entity.Roles, &entity.URL, &entity.Service)
|
||||
if err != nil {
|
||||
if err = database.NoRowsInQuerySet(err); err != nil {
|
||||
return nil, errors.New("no url found for: " + url + " and role: " + role)
|
||||
}
|
||||
|
||||
return nil, errors.New("failed to fetch url_access from DB: " + err.Error())
|
||||
}
|
||||
|
||||
return &entity, nil
|
||||
}
|
||||
|
||||
func (r *URLAccessRepository) FindForUser(user *entity.User) {
|
||||
|
||||
}
|
||||
85
src/infra/repository/user_repository.go
Normal file
85
src/infra/repository/user_repository.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity"
|
||||
|
||||
db "git.ego.freeddns.org/egommerce/go-api-pkg/client/postgresql"
|
||||
|
||||
"github.com/georgysavva/scany/v2/pgxscan"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
type UserRepository struct {
|
||||
db *pgxpool.Pool
|
||||
}
|
||||
|
||||
func NewUserRepository(db *pgxpool.Pool) *UserRepository {
|
||||
return &UserRepository{db}
|
||||
}
|
||||
|
||||
func (r *UserRepository) FindAll() ([]entity.User, error) {
|
||||
users := []entity.User{}
|
||||
|
||||
sql := `SELECT id, username, password, email, created_at, updated_at FROM identity.users`
|
||||
rows, err := r.db.Query(context.Background(), sql)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := pgxscan.ScanAll(&users, rows); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (r *UserRepository) FindByID(id string) (*entity.User, error) {
|
||||
user := new(entity.User)
|
||||
|
||||
sql := `SELECT id, username, password, email, created_at, updated_at FROM identity.users WHERE id=$1 LIMIT 1`
|
||||
err := pgxscan.Get(context.Background(), r.db, user, sql, id)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to fetch user from DB: " + err.Error())
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (r *UserRepository) FindByUsername(login string) (*entity.User, error) {
|
||||
user := new(entity.User)
|
||||
|
||||
sql := `SELECT id, username, password, email, created_at, updated_at FROM identity.users WHERE username=$1 LIMIT 1`
|
||||
err := pgxscan.Get(context.Background(), r.db, user, sql, login)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to fetch user from DB: " + err.Error())
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (r *UserRepository) Create(user *entity.User) (string, error) {
|
||||
var id string
|
||||
|
||||
sql := `INSERT INTO identity.users(email, username, password) VALUES($1, $2, $3) LIMIT 1 RETURNING id`
|
||||
err := r.db.QueryRow(context.Background(), sql, user.Email, user.Username, user.Password).Scan(&id)
|
||||
if err != nil {
|
||||
if err = db.IsDuplicatedRow(err); err != nil {
|
||||
return "", errors.New("username/email is already taken")
|
||||
}
|
||||
|
||||
return "", errors.New("db error: " + err.Error())
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (r *UserRepository) Update(user *entity.User) (*entity.User, error) {
|
||||
return &entity.User{}, nil
|
||||
}
|
||||
|
||||
func (r *UserRepository) Delete(id int64) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
var ErrLoadingEnvs error
|
||||
|
||||
func init() {
|
||||
ErrLoadingEnvs = godotenv.Load()
|
||||
}
|
||||
|
||||
func GetEnv(name, defVal string) string {
|
||||
env := os.Getenv(name)
|
||||
if env == "" {
|
||||
return defVal
|
||||
}
|
||||
|
||||
return env
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
)
|
||||
|
||||
func Connect(connStr string) (*pgxpool.Pool, error) {
|
||||
conn, err := pgxpool.Connect(context.Background(), connStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package definition
|
||||
|
||||
type AuthLoginRequest struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type AuthLoginResponse struct {
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package definition
|
||||
|
||||
type ErrorResponse struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
func Error(err string) *ErrorResponse {
|
||||
return &ErrorResponse{err}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package entity
|
||||
|
||||
import "time"
|
||||
|
||||
type User struct {
|
||||
ID int `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
CreateDate time.Time `json:"create_date"`
|
||||
ModifyDate time.Time `json:"modify_date"` // FIXME: zero-value issue
|
||||
}
|
||||
|
||||
var TestUser = &User{
|
||||
ID: 1,
|
||||
Username: "test",
|
||||
Password: "test",
|
||||
CreateDate: time.Now(),
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
def "git.pbiernat.dev/egommerce/identity-service/internal/app/definition"
|
||||
"git.pbiernat.dev/egommerce/identity-service/internal/app/service"
|
||||
)
|
||||
|
||||
var AuthLoginHandler *Handler
|
||||
|
||||
func init() {
|
||||
AuthLoginHandler = &Handler{
|
||||
Handle: AuthLoginHandlerFunc,
|
||||
Request: &def.AuthLoginRequest{},
|
||||
Response: &def.AuthLoginResponse{},
|
||||
}
|
||||
}
|
||||
|
||||
func AuthLoginHandlerFunc(h *Handler, w http.ResponseWriter) (interface{}, int, error) {
|
||||
var req = h.Request.(*def.AuthLoginRequest)
|
||||
// u := entity.TestUser
|
||||
|
||||
token, err := service.AuthService.Login(req)
|
||||
if err != nil {
|
||||
return nil, http.StatusForbidden, err
|
||||
}
|
||||
|
||||
service.AuthService.SetCookie(w, service.AuthService.TokenCookieName, token)
|
||||
// service.AuthService.SetCookie(w, service.AuthService.RefreshTokenCookieName, refreshTtoken)
|
||||
|
||||
// log.Println("user:", u, "req:", token, "err:", err)
|
||||
|
||||
return nil, http.StatusOK, nil
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type NotFoundHandler struct{}
|
||||
|
||||
func (NotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
encodeResponse(w, &response{http.StatusNotFound, ""}, errors.New("Path "+r.RequestURI+" not found"))
|
||||
}
|
||||
|
||||
type MethodNotAllowedHandler struct{}
|
||||
|
||||
func (MethodNotAllowedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
encodeResponse(w, &response{http.StatusMethodNotAllowed, ""}, errors.New("Method Not Allowed: "+r.Method))
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
def "git.pbiernat.dev/egommerce/identity-service/internal/app/definition"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
)
|
||||
|
||||
type Env struct {
|
||||
Addr string
|
||||
DB *pgxpool.Pool
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
*Env
|
||||
Handle HandlerFunc
|
||||
Request interface{}
|
||||
Response interface{}
|
||||
Params Set
|
||||
}
|
||||
|
||||
type HandlerFunc func(h *Handler, w http.ResponseWriter) (interface{}, int, error)
|
||||
|
||||
type Set map[string]string
|
||||
|
||||
type response struct {
|
||||
Status int
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
func Init(e *Env, h *Handler) *Handler {
|
||||
// return &Handler{e, h.Handle, h.Request, h.Response, Set{}}
|
||||
h.Env = e
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if err := decodeRequestData(r, h.Request); err != nil {
|
||||
log.Println("Decode request data error:", err.Error())
|
||||
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
h.Params = mux.Vars(r)
|
||||
res, code, err := h.Handle(h, w)
|
||||
|
||||
encodeResponse(w, &response{code, res}, err)
|
||||
}
|
||||
|
||||
func decodeRequestData(r *http.Request, v interface{}) error {
|
||||
buf, _ := io.ReadAll(r.Body)
|
||||
rdr := io.NopCloser(bytes.NewReader(buf))
|
||||
r.Body = io.NopCloser(bytes.NewReader(buf))
|
||||
|
||||
json.NewDecoder(rdr).Decode(&v)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeResponse(w http.ResponseWriter, res *response, e error) {
|
||||
if e != nil {
|
||||
encodeError(w, res.Status, e)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(res.Status)
|
||||
if res.Data != nil {
|
||||
json.NewEncoder(w).Encode(res.Data)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeError(w http.ResponseWriter, status int, e error) {
|
||||
w.WriteHeader(status)
|
||||
|
||||
json.NewEncoder(w).Encode(def.Error(e.Error()))
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var HealthCheckHandler *Handler
|
||||
|
||||
func init() {
|
||||
HealthCheckHandler = &Handler{
|
||||
Handle: HealthCheckHandlerFunc,
|
||||
Request: &HealthCheckRequest{},
|
||||
Response: &HealthCheckResponse{},
|
||||
}
|
||||
}
|
||||
|
||||
type HealthCheckRequest struct {
|
||||
}
|
||||
|
||||
type HealthCheckResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data *HealthCheckResponseBody `json:"data"`
|
||||
}
|
||||
|
||||
type HealthCheckResponseBody struct {
|
||||
Message string `json:"message,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func HealthCheckHandlerFunc(_ *Handler, w http.ResponseWriter) (interface{}, int, error) {
|
||||
return &HealthCheckResponseBody{
|
||||
Message: "This is welcome health message. Everything seems to be alright ;)",
|
||||
Status: "OK",
|
||||
}, http.StatusOK, nil
|
||||
|
||||
// return &HealthCheckResponse{
|
||||
// Status: http.StatusText(http.StatusOK),
|
||||
// Data: &HealthCheckResponseBody{
|
||||
// Message: "This is welcome health message. Everything seems to be alright ;)",
|
||||
// },
|
||||
// }, http.StatusOK, nil
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package app
|
||||
|
||||
import "log"
|
||||
|
||||
func Panic(v ...any) {
|
||||
log.Panicln(Name+":", v)
|
||||
}
|
||||
|
||||
func Panicf(format string, v ...any) {
|
||||
log.Panicf(Name+": "+format, v...)
|
||||
}
|
||||
|
||||
func Panicln(v ...any) {
|
||||
v = append([]any{Name + ":"}, v...)
|
||||
log.Panicln(v...)
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.pbiernat.dev/egommerce/identity-service/internal/app/handler"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func SetupRouter(env *handler.Env) *mux.Router {
|
||||
r := mux.NewRouter()
|
||||
r.NotFoundHandler = &handler.NotFoundHandler{}
|
||||
r.MethodNotAllowedHandler = &handler.MethodNotAllowedHandler{}
|
||||
|
||||
r.Use(PrepareHeadersMiddleware)
|
||||
r.Use(ValidateJsonBodyMiddleware) // probably not needed
|
||||
r.Use(LoggingMiddleware)
|
||||
|
||||
r.Handle("/health", handler.Init(env, handler.HealthCheckHandler)).Methods(http.MethodGet)
|
||||
r.Handle("/login", handler.Init(env, handler.AuthLoginHandler)).Methods(http.MethodPost)
|
||||
|
||||
return r
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
def "git.pbiernat.dev/egommerce/identity-service/internal/app/definition"
|
||||
"git.pbiernat.dev/egommerce/identity-service/internal/app/handler"
|
||||
)
|
||||
|
||||
const Name = "REST API Service"
|
||||
|
||||
type Server struct {
|
||||
*http.Server
|
||||
}
|
||||
|
||||
func NewServer(env *handler.Env) *Server {
|
||||
return &Server{
|
||||
&http.Server{
|
||||
Handler: SetupRouter(env),
|
||||
Addr: env.Addr,
|
||||
WriteTimeout: 15 * time.Second,
|
||||
ReadTimeout: 15 * time.Second,
|
||||
IdleTimeout: 60 * time.Second,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Start() {
|
||||
if os.Getenv("LISTEN_PID") == strconv.Itoa(os.Getpid()) {
|
||||
// systemd run
|
||||
f := os.NewFile(3, "from systemd")
|
||||
l, err := net.FileListener(f)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
log.Println("Server listening on " + l.Addr().String())
|
||||
s.Serve(l)
|
||||
} else {
|
||||
|
||||
log.Println("Server listening on " + s.Addr)
|
||||
log.Fatalln(s.ListenAndServe())
|
||||
}
|
||||
}
|
||||
|
||||
func PrepareHeadersMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.Header().Set("Connection", "keep-alive")
|
||||
w.Header().Set("Keep-Alive", "timeout=5")
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func ValidateJsonBodyMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
buf, _ := io.ReadAll(r.Body)
|
||||
r.Body = io.NopCloser(bytes.NewReader(buf)) // rollack *Request to original state
|
||||
|
||||
if len(buf) > 0 && !json.Valid(buf) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
json.NewEncoder(w).Encode(def.Error("Unable to parse JSON: " + string(buf)))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func LoggingMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Println("Request: " + r.RequestURI + " remote: " + r.RemoteAddr + " via: " + r.UserAgent())
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.pbiernat.dev/egommerce/identity-service/internal/app/config"
|
||||
def "git.pbiernat.dev/egommerce/identity-service/internal/app/definition"
|
||||
"github.com/golang-jwt/jwt"
|
||||
)
|
||||
|
||||
var (
|
||||
AuthService *Auth
|
||||
|
||||
ErrUserNotFound = errors.New("user not found")
|
||||
ErrTokenError = errors.New("failed to generate JWT token")
|
||||
)
|
||||
|
||||
func init() {
|
||||
expire, _ := strconv.Atoi(config.GetEnv("AUTH_TOKEN_EXPIRE_TIME", "5"))
|
||||
secret := []byte(config.GetEnv("AUTH_SECRET_HMAC", "B413IlIv9nKQfsMCXTE0Cteo4yHgUEfqaLfjg73sNlh"))
|
||||
|
||||
AuthService = &Auth{expire, "jwt_token", "jwt_token_refresh", secret}
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
ExpireTime int // token expire time in minutes
|
||||
TokenCookieName string
|
||||
RefreshTokenCookieName string
|
||||
|
||||
secret []byte // signing key
|
||||
}
|
||||
|
||||
func (a *Auth) Login(r *def.AuthLoginRequest) (string, error) {
|
||||
if r.Username == "admin" && r.Password == "secret" {
|
||||
token, err := a.createToken()
|
||||
if err != nil {
|
||||
return "", ErrTokenError
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
return "", ErrUserNotFound
|
||||
}
|
||||
|
||||
// SetCookie appends cookie header to response
|
||||
func (a *Auth) SetCookie(w http.ResponseWriter, name, token string) {
|
||||
c := &http.Cookie{
|
||||
Name: name,
|
||||
Value: token,
|
||||
MaxAge: a.ExpireTime * 60,
|
||||
Path: "/",
|
||||
}
|
||||
http.SetCookie(w, c)
|
||||
}
|
||||
|
||||
func (a Auth) createToken() (string, error) {
|
||||
// log.Println("now:", time.Now().Unix())
|
||||
// log.Println("expire at:", time.Now().Add(time.Duration(a.ExpireTime)*time.Minute).Unix())
|
||||
claims := &jwt.StandardClaims{
|
||||
ExpiresAt: time.Now().Add(time.Duration(a.ExpireTime) * time.Minute).Unix(),
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
return token.SignedString(a.secret)
|
||||
}
|
||||
|
||||
func (a *Auth) validateToken(tokenStr string) error {
|
||||
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
|
||||
// Don't forget to validate the alg is what you expect:
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
|
||||
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
|
||||
return a.secret, nil
|
||||
})
|
||||
|
||||
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
||||
log.Println(claims)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a Auth) ValidateUserTokenMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
cToken, err := r.Cookie(a.TokenCookieName)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
json.NewEncoder(w).Encode(def.Error("Missing JWT Token cookie"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if err := a.validateToken(cToken.Value); err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
json.NewEncoder(w).Encode(def.Error(err.Error()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
22
src/internal/cli/scheduler/cache_permissions_job.go
Normal file
22
src/internal/cli/scheduler/cache_permissions_job.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
)
|
||||
|
||||
type CachePermissionsJob struct {
|
||||
guard *service.GuardService
|
||||
}
|
||||
|
||||
func NewCachePermissionsJob(guard *service.GuardService) *CachePermissionsJob {
|
||||
return &CachePermissionsJob{guard: guard}
|
||||
}
|
||||
|
||||
func (j CachePermissionsJob) Run() {
|
||||
j.guard.CacheAllPermissions()
|
||||
|
||||
fmt.Println(time.Now().String() + " permission successfully cached")
|
||||
}
|
||||
34
src/internal/http/access_handler.go
Normal file
34
src/internal/http/access_handler.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto"
|
||||
identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/ui"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func AccessHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
userRepo := repository.NewUserRepository(db)
|
||||
roleRepo := repository.NewRoleRepository(db)
|
||||
urlRepo := repository.NewURLAccessRepository(db)
|
||||
authSrv := service.NewAuthService(userRepo, cache)
|
||||
guardSrv := service.NewGuardService(authSrv, cache, userRepo, roleRepo, urlRepo)
|
||||
|
||||
url, srvName := c.Query("q"), c.Query("srv")
|
||||
header := new(identityDTO.AuthorizationHeaderDTO)
|
||||
c.ReqHeaderParser(header)
|
||||
|
||||
if err := ui.NewAccessActionUI(guardSrv).Execute(header, url, srvName); err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(&commonDTO.ErrorResponseDTO{Error: err.Error()})
|
||||
}
|
||||
|
||||
return c.SendStatus(fiber.StatusNoContent)
|
||||
}
|
||||
}
|
||||
33
src/internal/http/health_handler.go
Normal file
33
src/internal/http/health_handler.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
type HealthResponse struct {
|
||||
Status string `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func HealthHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Only 404 indicate service as not-healthy
|
||||
err := db.Ping(context.Background())
|
||||
if err != nil {
|
||||
return c.SendStatus(http.StatusNotFound)
|
||||
}
|
||||
|
||||
err = cache.Ping(context.Background()).Err()
|
||||
if err != nil {
|
||||
return c.SendStatus(http.StatusNotFound)
|
||||
}
|
||||
|
||||
return c.JSON(&HealthResponse{
|
||||
Status: "OK",
|
||||
})
|
||||
}
|
||||
}
|
||||
35
src/internal/http/login_handler.go
Normal file
35
src/internal/http/login_handler.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
|
||||
commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto"
|
||||
identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/ui"
|
||||
)
|
||||
|
||||
func LoginHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
req := new(identityDTO.AuthLoginRequestDTO)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(&commonDTO.ErrorResponseDTO{Error: "error parsing input"})
|
||||
// return srv.Error(c, fiber.StatusBadRequest, "error parsing input")
|
||||
}
|
||||
|
||||
userRepo := repository.NewUserRepository(db)
|
||||
authSrv := service.NewAuthService(userRepo, cache)
|
||||
|
||||
token, err := ui.NewLoginActionUI(authSrv).Execute(req)
|
||||
if err != nil { // TODO: handle other response status codes -- add struct to decorate error with code and message
|
||||
return c.Status(fiber.StatusBadRequest).JSON(commonDTO.ErrorResponseDTO{Error: err.Error()})
|
||||
// return srv.Error(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(&identityDTO.AuthLoginResponseDTO{Token: token})
|
||||
}
|
||||
}
|
||||
35
src/internal/http/refresh_handler.go
Normal file
35
src/internal/http/refresh_handler.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto"
|
||||
identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/ui"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func RefreshHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
header := new(identityDTO.AuthorizationHeaderDTO)
|
||||
if err := c.ReqHeaderParser(header); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(commonDTO.ErrorResponseDTO{Error: "Error parsing headers"})
|
||||
// return srv.Error(c, fiber.StatusBadRequest, "Error parsing headers")
|
||||
}
|
||||
|
||||
repo := repository.NewUserRepository(db)
|
||||
authSrv := service.NewAuthService(repo, cache)
|
||||
|
||||
token, err := ui.NewRefreshTokenActionUI(authSrv).Execute(header)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(&commonDTO.ErrorResponseDTO{Error: err.Error()})
|
||||
// return srv.Error(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(&identityDTO.AuthRefreshTokenResponseDTO{Token: token})
|
||||
}
|
||||
}
|
||||
33
src/internal/http/register_handler.go
Normal file
33
src/internal/http/register_handler.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
commonDTO "git.ego.freeddns.org/egommerce/api-entities/common/dto"
|
||||
identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/ui"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func RegisterHandlerFn(db *pgxpool.Pool, cache *redis.Client) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
data := new(identityDTO.AuthRegisterRequestDTO)
|
||||
if err := c.BodyParser(data); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(commonDTO.ErrorResponseDTO{Error: "Error parsing input"})
|
||||
// return srv.Error(c, fiber.StatusBadRequest, "Error parsing input")
|
||||
}
|
||||
|
||||
repo := repository.NewUserRepository(db)
|
||||
|
||||
id, err := ui.NewRegisterActionUI(repo, cache).Execute(data)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(commonDTO.ErrorResponseDTO{Error: err.Error()})
|
||||
// return srv.Error(c, fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
return c.JSON(&identityDTO.AuthRegisterResponseDTO{ID: id})
|
||||
}
|
||||
}
|
||||
157
src/internal/service/auth.go
Normal file
157
src/internal/service/auth.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
dto "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
var (
|
||||
passSrv *PaswordService
|
||||
|
||||
ErrLoginIncorrect = errors.New("login incorrect")
|
||||
ErrUnableToCacheToken = errors.New("unable to save tokens in cache")
|
||||
ErrInvalidAccessToken = errors.New("invalid access token")
|
||||
ErrParsingAccessToken = errors.New("error while parsing access token")
|
||||
ErrUnableToCacheUserID = errors.New("unable to save User ID in cache")
|
||||
)
|
||||
|
||||
func init() {
|
||||
passSrv = NewPasswordService()
|
||||
}
|
||||
|
||||
type AuthService struct {
|
||||
userRepo repository.UserRepositoryInterface
|
||||
cache *redis.Client
|
||||
}
|
||||
|
||||
func NewAuthService(userRepo repository.UserRepositoryInterface, cache *redis.Client) *AuthService {
|
||||
return &AuthService{
|
||||
userRepo: userRepo,
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AuthService) Login(login, passwd string) (string, error) {
|
||||
user, err := a.userRepo.FindByUsername(login)
|
||||
if err != nil {
|
||||
// TODO place code below in better place...
|
||||
// if err = database.NoRowsInQuerySet(err); err != nil {
|
||||
// return "", errors.New("no user found")
|
||||
// }
|
||||
|
||||
return "", ErrLoginIncorrect
|
||||
}
|
||||
|
||||
if err = passSrv.Verify(passwd, user.Password); err != nil {
|
||||
return "", ErrLoginIncorrect
|
||||
}
|
||||
|
||||
accessToken, _ := jwtSrv.CreateAccessToken(user.ID)
|
||||
refreshToken, _ := jwtSrv.CreateRefreshToken(user.ID)
|
||||
if err = a.saveTokensToCache(user.ID, accessToken, refreshToken); err != nil {
|
||||
return "", ErrUnableToCacheToken
|
||||
}
|
||||
|
||||
// REFACTOR: save uid in cache under "user:$ACCES_TOKEN" key
|
||||
res := a.cache.Set(context.Background(), "user:"+accessToken, user.ID, accessTokenExpireTime)
|
||||
if err := res.Err(); err != nil {
|
||||
fmt.Println("failed to save user:$ACCESS_TOKEN in cache: ", err.Error())
|
||||
|
||||
return "", ErrUnableToCacheUserID
|
||||
}
|
||||
|
||||
return accessToken, nil
|
||||
}
|
||||
|
||||
func (a *AuthService) RefreshToken(accessToken string) (string, error) {
|
||||
// POSSIBLE BIG SECURITY ISSUE- WHEN REFRESH WITH ABANDONED (or EXPIRED)
|
||||
// ACCESS TOKEN WE GET NEW ACCESS TOKEN
|
||||
token, claims, err := jwtSrv.ValidateAccessToken(accessToken)
|
||||
if err != nil || !token.Valid {
|
||||
return "", ErrInvalidAccessToken
|
||||
}
|
||||
|
||||
userID := claims["sub"]
|
||||
|
||||
newAccessToken, _ := jwtSrv.CreateAccessToken(userID.(string))
|
||||
newRefreshToken, _ := jwtSrv.CreateRefreshToken(userID.(string))
|
||||
if err = a.saveTokensToCache(userID.(string), newAccessToken, newRefreshToken); err != nil {
|
||||
return "", ErrUnableToCacheToken
|
||||
}
|
||||
|
||||
// REFACTOR
|
||||
del := a.cache.Del(context.Background(), "user:"+accessToken)
|
||||
if err := del.Err(); err != nil {
|
||||
fmt.Println("failed to invalidate user:$ACCESS_TOKEN from cache: ", err.Error())
|
||||
}
|
||||
|
||||
// REFACTOR: save uid in cache under user:$ACCES_TOKEN key
|
||||
res := a.cache.Set(context.Background(), "user:"+newAccessToken, userID, accessTokenExpireTime)
|
||||
if err := res.Err(); err != nil {
|
||||
fmt.Println("failed to save user:$ACCESS_TOKEN in cache: ", err.Error())
|
||||
}
|
||||
|
||||
return newAccessToken, nil
|
||||
}
|
||||
|
||||
func (a *AuthService) Register(email, login, passwd string) (string, error) {
|
||||
passwd, _ = passSrv.Hash(passwd)
|
||||
|
||||
id, err := a.userRepo.Create(&entity.User{
|
||||
Email: email,
|
||||
Username: login,
|
||||
Password: passwd,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (a *AuthService) GetTokenFromAuthorizationHeader(header *dto.AuthorizationHeaderDTO) (string, error) {
|
||||
split := strings.Split(header.Authorization, " ")
|
||||
if len(split) != 2 {
|
||||
return "", ErrParsingAccessToken
|
||||
}
|
||||
|
||||
return split[1], nil
|
||||
}
|
||||
|
||||
func (a *AuthService) getUIDByAccesssToken(aToken string) (string, error) {
|
||||
res := a.cache.Get(context.Background(), "user:"+aToken)
|
||||
if err := res.Err(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
uid, _ := res.Result()
|
||||
|
||||
return uid, nil
|
||||
}
|
||||
|
||||
func (a *AuthService) saveTokensToCache(id, aToken, rToken string) error {
|
||||
res := a.cache.Set(context.Background(), "auth:access_token:"+id, aToken, accessTokenExpireTime)
|
||||
if err := res.Err(); err != nil {
|
||||
fmt.Println("failed to save access token in cache: ", err.Error())
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
res = a.cache.Set(context.Background(), "auth:refresh_token:"+id, rToken, refreshTokenExpireTime)
|
||||
if err := res.Err(); err != nil {
|
||||
fmt.Println("failed to save refresh token in cache: ", err.Error())
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
82
src/internal/service/guard.go
Normal file
82
src/internal/service/guard.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
dto "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
type GuardService struct {
|
||||
authSrv *AuthService
|
||||
cache *redis.Client
|
||||
userRepo *repository.UserRepository
|
||||
roleRepo *repository.RoleRepository
|
||||
urlRepo *repository.URLAccessRepository
|
||||
}
|
||||
|
||||
func NewGuardService(authSrv *AuthService, cache *redis.Client, userRepo *repository.UserRepository, roleRepo *repository.RoleRepository, urlRepo *repository.URLAccessRepository) *GuardService {
|
||||
return &GuardService{
|
||||
authSrv: authSrv,
|
||||
cache: cache,
|
||||
userRepo: userRepo,
|
||||
roleRepo: roleRepo,
|
||||
urlRepo: urlRepo,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GuardService) CheckUserPermissions(authHeader *dto.AuthorizationHeaderDTO, url, srvName string) error {
|
||||
token, _ := g.authSrv.GetTokenFromAuthorizationHeader(authHeader)
|
||||
|
||||
uid, _ := g.authSrv.getUIDByAccesssToken(token)
|
||||
user, err := g.userRepo.FindByID(uid)
|
||||
if err != nil {
|
||||
return errors.New("user not found")
|
||||
}
|
||||
|
||||
role := g.roleRepo.GetUserRole(user)
|
||||
|
||||
if _, err := g.urlRepo.FindByURLAndServiceForRole(url, srvName, role.Name); err != nil {
|
||||
return errors.New("user doesn't have required permission")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GuardService) CacheAllPermissions() error {
|
||||
urls, err := g.urlRepo.FindAll()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var urlsArr = make(map[string][]entity.URLAccess)
|
||||
for _, url := range urls {
|
||||
urlsArr[url.Service] = append(urlsArr[url.Service], url)
|
||||
}
|
||||
|
||||
for service, url := range urlsArr {
|
||||
json, err := json.Marshal(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
jsonUrl := string(json)
|
||||
|
||||
if err := g.cache.HSet(context.Background(), "urls_access", service, jsonUrl).Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := g.cache.Expire(context.Background(), "urls_access", time.Duration(time.Hour)).Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// func (g *GuardService) fetchURLAccessFromCache() {}
|
||||
100
src/internal/service/jwt.go
Normal file
100
src/internal/service/jwt.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
cnf "git.ego.freeddns.org/egommerce/go-api-pkg/config"
|
||||
|
||||
"github.com/golang-jwt/jwt"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrorTokenExpired = errors.New("token has expired")
|
||||
ErrInvalidToken = errors.New("invalid token")
|
||||
|
||||
accessTokenExpireTime time.Duration
|
||||
refreshTokenExpireTime time.Duration
|
||||
)
|
||||
|
||||
var jwtSrv *JWT
|
||||
|
||||
func init() {
|
||||
expAccessTokenTime, _ := strconv.Atoi(cnf.GetEnv("JWT_ACCESS_TOKEN_EXPIRE_TIME", "1"))
|
||||
accessTokenExpireTime = time.Duration(int(time.Hour) * expAccessTokenTime) // hours
|
||||
|
||||
expRefreshTokenTime, _ := strconv.Atoi(cnf.GetEnv("JWT_REFRESH_TOKEN_EXPIRE_TIME", "7"))
|
||||
refreshTokenExpireTime = time.Duration(int(time.Hour*24) * expRefreshTokenTime) // days
|
||||
|
||||
jwtSrv = NewJWTService(
|
||||
accessTokenExpireTime,
|
||||
[]byte(cnf.GetEnv("JWT_ACCESS_TOKEN_SECRET_KEY", "FallbackAccessTokenSecret")),
|
||||
refreshTokenExpireTime,
|
||||
[]byte(cnf.GetEnv("JWT_REFRESH_TOKEN_SECRET_KEY", "FallbackRefreshTokenSecret")),
|
||||
)
|
||||
}
|
||||
|
||||
func NewJWTService(aTokenExp time.Duration, aTokenSecret []byte, rTokenExp time.Duration, rTokenSecret []byte) *JWT {
|
||||
return &JWT{aTokenExp, aTokenSecret, rTokenExp, rTokenSecret}
|
||||
}
|
||||
|
||||
type JWT struct {
|
||||
accessTokenExpireTime time.Duration
|
||||
accessTokenSecret []byte
|
||||
|
||||
refreshTokenExpireTime time.Duration
|
||||
refreshTokenSecret []byte
|
||||
}
|
||||
|
||||
func (s *JWT) CreateAccessToken(id string) (string, error) {
|
||||
claims := &jwt.StandardClaims{
|
||||
Subject: id,
|
||||
IssuedAt: time.Now().Unix(),
|
||||
ExpiresAt: time.Now().Add(s.accessTokenExpireTime).Unix(),
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
|
||||
return token.SignedString(s.accessTokenSecret)
|
||||
}
|
||||
|
||||
func (s *JWT) CreateRefreshToken(id string) (string, error) {
|
||||
claims := &jwt.StandardClaims{
|
||||
Subject: id,
|
||||
IssuedAt: time.Now().Unix(),
|
||||
ExpiresAt: time.Now().Add(s.refreshTokenExpireTime).Unix(),
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
|
||||
return token.SignedString(s.accessTokenSecret)
|
||||
}
|
||||
|
||||
func (s *JWT) ValidateAccessToken(tokenStr string) (*jwt.Token, jwt.MapClaims, error) {
|
||||
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
|
||||
// Don't forget to validate the alg is what you expect:
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
|
||||
return s.accessTokenSecret, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
||||
if exp, ok := claims["exp"].(float64); ok {
|
||||
if int64(exp) < time.Now().Unix() {
|
||||
return nil, nil, ErrorTokenExpired
|
||||
}
|
||||
|
||||
return token, claims, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil, ErrInvalidToken
|
||||
}
|
||||
22
src/internal/service/password.go
Normal file
22
src/internal/service/password.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package service
|
||||
|
||||
import "golang.org/x/crypto/bcrypt"
|
||||
|
||||
type PaswordService struct{}
|
||||
|
||||
func NewPasswordService() *PaswordService {
|
||||
return &PaswordService{}
|
||||
}
|
||||
|
||||
func (p *PaswordService) Hash(pass string) (string, error) {
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(hash), nil
|
||||
}
|
||||
|
||||
func (p *PaswordService) Verify(pass, hashedPass string) error {
|
||||
return bcrypt.CompareHashAndPassword([]byte(hashedPass), []byte(pass))
|
||||
}
|
||||
24
src/internal/ui/check_user_permissions_action.go
Normal file
24
src/internal/ui/check_user_permissions_action.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
)
|
||||
|
||||
type CheckUserPermissionsUI struct {
|
||||
guard *service.GuardService
|
||||
}
|
||||
|
||||
func NewAccessActionUI(guard *service.GuardService) *CheckUserPermissionsUI {
|
||||
return &CheckUserPermissionsUI{guard: guard}
|
||||
}
|
||||
|
||||
func (ui *CheckUserPermissionsUI) Execute(data *identityDTO.AuthorizationHeaderDTO, url, srvName string) error { // TODO: rename to CheckAccess
|
||||
err := ui.guard.CheckUserPermissions(data, url, srvName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
30
src/internal/ui/login_action.go
Normal file
30
src/internal/ui/login_action.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
)
|
||||
|
||||
type LoginActionUI struct {
|
||||
authSrv *service.AuthService
|
||||
}
|
||||
|
||||
func NewLoginActionUI(authSrv *service.AuthService) *LoginActionUI {
|
||||
return &LoginActionUI{
|
||||
authSrv: authSrv,
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *LoginActionUI) Execute(data *identityDTO.AuthLoginRequestDTO) (string, error) {
|
||||
token, err := ui.authSrv.Login(data.Username, data.Password)
|
||||
if err != nil {
|
||||
// TODO: handle other response status codes -- add struct to decorate error with code and message
|
||||
if err == service.ErrUnableToCacheToken {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
30
src/internal/ui/refresh_action.go
Normal file
30
src/internal/ui/refresh_action.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
)
|
||||
|
||||
type RefreshTokenActionUI struct {
|
||||
auth *service.AuthService
|
||||
}
|
||||
|
||||
func NewRefreshTokenActionUI(auth *service.AuthService) *RefreshTokenActionUI {
|
||||
return &RefreshTokenActionUI{
|
||||
auth: auth,
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *RefreshTokenActionUI) Execute(header *identityDTO.AuthorizationHeaderDTO) (string, error) {
|
||||
token, _ := ui.auth.GetTokenFromAuthorizationHeader(header)
|
||||
newToken, err := ui.auth.RefreshToken(token)
|
||||
if err != nil {
|
||||
if err == service.ErrUnableToCacheToken { // FIXME: Move to RefreshHandlerFn
|
||||
return "", err
|
||||
}
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
||||
return newToken, nil
|
||||
}
|
||||
28
src/internal/ui/register_action.go
Normal file
28
src/internal/ui/register_action.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
identityDTO "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
||||
"git.ego.freeddns.org/egommerce/identity-service/internal/service"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
type RegisterActionUI struct {
|
||||
authSrv *service.AuthService
|
||||
}
|
||||
|
||||
func NewRegisterActionUI(repo *repository.UserRepository, cache *redis.Client) *RegisterActionUI {
|
||||
return &RegisterActionUI{
|
||||
authSrv: service.NewAuthService(repo, cache),
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *RegisterActionUI) Execute(data *identityDTO.AuthRegisterRequestDTO) (string, error) {
|
||||
id, err := ui.authSrv.Register(data.Email, data.Username, data.Password)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
Reference in New Issue
Block a user