From e7d5c33638abcd6903f40f84c310fd167c8eb585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernd-Ren=C3=A9=20Predota?= Date: Mon, 10 May 2021 16:15:27 +0200 Subject: [PATCH] structure rewrite ongoing, user/token model added --- .gitignore | 1 + README.md | 2 +- go.mod | 4 +- go.sum | 52 +++++++---- lib/cmd/cmd.go | 132 +++++++++++++++++++--------- lib/cmd/cmd_test.go | 33 +++++-- lib/common/common.go | 126 +++++++++++++++++++++++++++ lib/config/config.go | 2 +- lib/database/database.go | 17 +++- lib/utils/utils.go | 60 +++++++++++++ main.go | 180 +++++++++++++++++++++++++++++++++++++-- models/token.go | 63 ++++++++++++++ models/user.go | 70 +++++++++++++++ pkg/user/database.go | 31 ------- pkg/user/model.go | 16 ---- pkg/user/repository.go | 20 ----- pkg/user/service.go | 18 ---- repositories/token.go | 53 ++++++++++++ repositories/user.go | 42 +++++++++ services/token.go | 35 ++++++++ services/user.go | 35 ++++++++ 21 files changed, 830 insertions(+), 162 deletions(-) create mode 100644 lib/common/common.go create mode 100644 lib/utils/utils.go create mode 100644 models/token.go create mode 100644 models/user.go delete mode 100644 pkg/user/database.go delete mode 100644 pkg/user/model.go delete mode 100644 pkg/user/repository.go delete mode 100644 pkg/user/service.go create mode 100644 repositories/token.go create mode 100644 repositories/user.go create mode 100644 services/token.go create mode 100644 services/user.go diff --git a/.gitignore b/.gitignore index 72f5ed7..5c092e4 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,6 @@ _vendor-*/ gin-bin goAPISkel goAPISkel.yml +config.yml gorm.db coverage.out diff --git a/README.md b/README.md index 45bac13..9e55ca6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # golang API Skeleton -[![Build Status](https://drone.devices.local/api/badges/mawas/golang-api-skeleton/status.svg)](https://drone.devices.local/mawas/golang-api-skeleton)![gopherbadger-tag-do-not-edit](https://img.shields.io/badge/Go%20Coverage-83%25-brightgreen.svg?longCache=true&style=flat) +[![Build Status](https://drone.devices.local/api/badges/mawas/golang-api-skeleton/status.svg)](https://drone.devices.local/mawas/golang-api-skeleton)![gopherbadger-tag-do-not-edit](https://img.shields.io/badge/Go%20Coverage-77%25-brightgreen.svg?longCache=true&style=flat) refined skeleton future apis should be based on diff --git a/go.mod b/go.mod index 9e1409e..d8c2548 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,13 @@ module git.devices.local/mawas/golang-api-skeleton go 1.15 require ( + github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7 // indirect github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect + github.com/dgraph-io/badger/v2 v2.2007.2 // indirect github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/go-ozzo/ozzo-validation v3.6.0+incompatible github.com/go-ozzo/ozzo-validation/v4 v4.3.0 - github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect + github.com/google/uuid v1.2.0 github.com/magiconair/properties v1.8.4 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/pelletier/go-toml v1.8.1 // indirect diff --git a/go.sum b/go.sum index ecddf9b..eb9888f 100644 --- a/go.sum +++ b/go.sum @@ -11,16 +11,18 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0= github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= @@ -28,16 +30,21 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 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/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 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/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -45,10 +52,17 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg= github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= +github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -77,7 +91,10 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 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 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -86,6 +103,8 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -182,9 +201,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -198,7 +215,7 @@ 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.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -223,7 +240,6 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -232,7 +248,6 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= @@ -257,6 +272,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR 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/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -267,7 +283,6 @@ github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhr github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= @@ -277,24 +292,23 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg= github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= @@ -309,7 +323,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -324,6 +340,7 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= @@ -366,6 +383,7 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 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 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -381,6 +399,7 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -391,19 +410,18 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/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 h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -460,9 +478,9 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -470,9 +488,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/lib/cmd/cmd.go b/lib/cmd/cmd.go index b8730ac..ec2d416 100644 --- a/lib/cmd/cmd.go +++ b/lib/cmd/cmd.go @@ -1,61 +1,77 @@ package cmd import ( - "fmt" "os" "git.devices.local/mawas/golang-api-skeleton/lib/config" "github.com/spf13/cobra" ) -var ( - Version string - APPName string - APPDescription string -) +// TODO add shell completion -var rootCmd = &cobra.Command{ - Use: APPName, - Short: APPDescription, - Long: APPDescription, - // SilenceUsage: true, - // SilenceErrors: true, - Run: func(cmd *cobra.Command, args []string) { - }, +func newRootCmd(appName string, appDescription string) *cobra.Command { + return &cobra.Command{ + Use: appName, + Short: appDescription, + Long: appDescription, + // SilenceUsage: true, + // SilenceErrors: true, + DisableAutoGenTag: true, + Run: func(cmd *cobra.Command, args []string) { + }, + } } -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print the version number", - Long: "Print the version number", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println(APPName, "version:", Version) - os.Exit(0) - }, +func newVersionCmd(version string, appName string) *cobra.Command { + return &cobra.Command{ + Use: "version", + Aliases: []string{"Version"}, + Short: "Print the version number", + Long: "Print the version number", + DisableAutoGenTag: true, + Run: func(cmd *cobra.Command, args []string) { + cmd.Println(appName, "version", version) + os.Exit(0) + }, + } } -var sampleCfgCmd = &cobra.Command{ - Use: "sample-config", - Short: "Print sample config", - Long: "Print an example configuration file content", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println(config.Sample) - os.Exit(0) - }, + +func newSampleCfgCmd() *cobra.Command { + return &cobra.Command{ + Use: "sample-config", + Short: "Print sample config", + Long: "Print an example configuration file content", + Run: func(cmd *cobra.Command, args []string) { + cmd.Println(config.Sample) + os.Exit(0) + }, + } +} + +func newSampleCLICmd() *cobra.Command { + return &cobra.Command{ + Use: "cli", + Short: "Interactive CLI", + Long: "Interactive CLI maybe", + Run: func(cmd *cobra.Command, args []string) { + cmd.Println("here might be an cli") + os.Exit(0) + }, + } } -func Initialize(version string, appName string, appDescription string) error { +func Initialize(version string, appName string, appDescription string) (string, map[string]interface{}, error) { var cfgFile string - Version = version - APPName = appName - APPDescription = appDescription + rootCmd := newRootCmd(appName, appDescription) rootCmd.SetHelpFunc(func(cmd *cobra.Command, args []string) { if err := cmd.Usage(); err != nil { os.Exit(1) } os.Exit(0) }) - rootCmd.AddCommand(versionCmd) - rootCmd.AddCommand(sampleCfgCmd) + rootCmd.AddCommand(newVersionCmd(version, appName)) + rootCmd.AddCommand(newSampleCfgCmd()) + // rootCmd.AddCommand(newSampleCLICmd()) rootCmd.Flags().StringVarP(&cfgFile, "config", "c", "", "config file") flagCfg := map[string]interface{}{ @@ -73,10 +89,44 @@ func Initialize(version string, appName string, appDescription string) error { "database.maxlifetime": rootCmd.Flags().IntP("database-maxlifetime", "t", 0, "database max connection lifetime"), } if err := rootCmd.Execute(); err != nil { - return err - } - if err := config.Initialize(appName, cfgFile, flagCfg); err != nil { - return err + return cfgFile, flagCfg, err } - return nil + return cfgFile, flagCfg, nil } + +// func Initialize(version string, appName string, appDescription string) error { +// var cfgFile string +// rootCmd := newRootCmd(appName, appDescription) +// rootCmd.SetHelpFunc(func(cmd *cobra.Command, args []string) { +// if err := cmd.Usage(); err != nil { +// os.Exit(1) +// } +// os.Exit(0) +// }) +// rootCmd.AddCommand(newVersionCmd(version, appName)) +// rootCmd.AddCommand(newSampleCfgCmd()) +// // rootCmd.AddCommand(newSampleCLICmd()) +// +// rootCmd.Flags().StringVarP(&cfgFile, "config", "c", "", "config file") +// flagCfg := map[string]interface{}{ +// "application.environment": rootCmd.Flags().StringP("environment", "e", "", "application environment"), +// "application.listenaddress": rootCmd.Flags().StringP("listenaddress", "l", "", "application listenaddress or host"), +// "application.port": rootCmd.Flags().IntP("port", "p", 0, "application listenport"), +// "database.host": rootCmd.Flags().StringP("database-host", "H", "", "database host"), +// "database.port": rootCmd.Flags().IntP("database-port", "P", 0, "database port"), +// "database.dialect": rootCmd.Flags().StringP("database-dialect", "D", "", "database dialect"), +// "database.database": rootCmd.Flags().StringP("database-name", "d", "", "database name"), +// "database.user": rootCmd.Flags().StringP("database-user", "u", "", "database user"), +// "database.password": rootCmd.Flags().StringP("database-password", "s", "", "database password"), +// "database.maxopenconn": rootCmd.Flags().IntP("database-maxopen", "o", 0, "database max open connections"), +// "database.maxidleconn": rootCmd.Flags().IntP("database-maxidle", "i", 0, "database max idle connections"), +// "database.maxlifetime": rootCmd.Flags().IntP("database-maxlifetime", "t", 0, "database max connection lifetime"), +// } +// if err := rootCmd.Execute(); err != nil { +// return err +// } +// if err := config.Initialize(appName, cfgFile, flagCfg); err != nil { +// return err +// } +// return nil +// } diff --git a/lib/cmd/cmd_test.go b/lib/cmd/cmd_test.go index d00cd3f..49bddb0 100644 --- a/lib/cmd/cmd_test.go +++ b/lib/cmd/cmd_test.go @@ -4,11 +4,34 @@ import ( "testing" ) +// func TestVersion(t *testing.T) { +// // FIXME maybe PanicOnExit0 can help regarding unexpected call to os.Exit(0) during test +// appname := "unittest" +// version := "0.0.1" +// cmd := newVersionCmd(version, appname) +// b := bytes.NewBufferString("") +// cmd.SetOut(b) +// if err := cmd.Execute(); err != nil { +// t.Fatal(err) +// } +// out, err := ioutil.ReadAll(b) +// if err != nil { +// t.Fatal(err) +// } +// expected := appname + " version " + version +// got := strings.TrimSpace(string(out)) +// if got != expected { +// t.Fatalf("expected \"%s\" got \"%s\"", expected, got) +// } +// } + func TestInitalize(t *testing.T) { - args := []string{"--database-user", "unittest"} - rootCmd.SetArgs(args) - if err := Initialize("0.0.1", "unittest", ""); err != nil { - t.Errorf("%v\n", err) + _, flagCfg, err := Initialize("0.0.1", "unittest", "") + if err != nil { + t.Fatal(err) + } + if len(flagCfg) == 0 { + t.Fatal("flag configuration missing") } } @@ -19,6 +42,6 @@ func TestInitalize(t *testing.T) { // t.Errorf("%v\n", err) // } // if err := Initialize("0.0.1", "unittest", ""); err != nil { -// t.Errorf("%v\n", err) +// t.Errorf("%v\n", err) // } // } diff --git a/lib/common/common.go b/lib/common/common.go new file mode 100644 index 0000000..faf40dc --- /dev/null +++ b/lib/common/common.go @@ -0,0 +1,126 @@ +package common + +import ( + "database/sql/driver" + "time" + + "github.com/google/uuid" + "gorm.io/gorm" +) + +type UsernameContextKey string + +// GUID -> new datatype +type GUID uuid.UUID + +// StringToGUID -> parse string to GUID +func StringToGUID(s string) (GUID, error) { + id, err := uuid.Parse(s) + return GUID(id), err +} + +// String -> String Representation of Binary16 +func (guid GUID) String() string { + return uuid.UUID(guid).String() +} + +// GormDataType -> sets type to binary(16) +func (guid GUID) GormDataType() string { + return "binary(16)" +} + +func (guid GUID) MarshalJSON() ([]byte, error) { + s := uuid.UUID(guid) + str := "\"" + s.String() + "\"" + return []byte(str), nil +} + +func (guid *GUID) UnmarshalJSON(by []byte) error { + s, err := uuid.ParseBytes(by) + *guid = GUID(s) + return err +} + +// Scan --> tells GORM how to receive from the database +func (guid *GUID) Scan(value interface{}) error { + bytes, _ := value.([]byte) + parseByte, err := uuid.FromBytes(bytes) + *guid = GUID(parseByte) + return err +} + +// Value -> tells GORM how to save into the database +func (guid GUID) Value() (driver.Value, error) { + return uuid.UUID(guid).MarshalBinary() +} + +type BasicFields struct { + CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` + CreatedByDB GUID `gorm:"column:created_by" json:"-"` + CreatedByJSON string `gorm:"-" json:"created_by"` + UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"` + UpdatedByDB GUID `gorm:"column:updated_by" json:"-"` + UpdatedByJSON string `gorm:"-" json:"updated_by"` + DeletedAtDB gorm.DeletedAt `gorm:"column:deleted_at" json:"-"` + DeletedAtJSON *time.Time `gorm:"-" json:"deleted_at,omitempty"` + DeletedBy string `gorm:"column:deleted_by" json:"deleted_by,omitempty"` +} + +func (basicFields *BasicFields) BeforeCreate(tx *gorm.DB) error { + if userID, ok := tx.Get("userID"); ok { + if guid, ok := userID.(GUID); ok { + basicFields.CreatedByDB = guid + basicFields.UpdatedByDB = guid + } + } + return nil +} + +func (basicFields *BasicFields) AfterCreate(tx *gorm.DB) error { + if username, ok := tx.Get("username"); ok { + if name, ok := username.(string); ok { + basicFields.CreatedByJSON = name + basicFields.UpdatedByJSON = name + } + } + return nil +} + +type GUIDPKicPK struct { + ID uint64 `gorm:"primaryKey;column:id" json:"id"` + BasicFields +} + +type ModelGUIDPK struct { + ID GUID `gorm:"primaryKey;column:id" json:"id"` + BasicFields +} + +func (guidPK *ModelGUIDPK) BeforeCreate(tx *gorm.DB) error { + id, err := uuid.NewRandom() + guidPK.ID = GUID(id) + if userID, ok := tx.Get("userID"); ok { + if guid, ok := userID.(GUID); ok { + guidPK.CreatedByDB = guid + guidPK.UpdatedByDB = guid + } + } + return err +} + +type ModelHiddenGUIDPK struct { + ID GUID `gorm:"primaryKey;column:id" json:"-"` + BasicFields +} + +func (guidPK *ModelHiddenGUIDPK) BeforeCreate(tx *gorm.DB) error { + id, err := uuid.NewRandom() + guidPK.ID = GUID(id) + if userID, ok := tx.Get("userID"); ok { + if guid, ok := userID.(GUID); ok { + guidPK.CreatedByDB = guid + guidPK.UpdatedByDB = guid + } + } + return err +} diff --git a/lib/config/config.go b/lib/config/config.go index fbcfd29..f10d7de 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -121,7 +121,7 @@ func validateEnvironment(environment string) error { func validateDatabaseDialect(dialect string) error { if err := validation.Validate( dialect, - validation.In(MYSQL, POSTGRES, MSSQL), + validation.In(MYSQL, POSTGRES, MSSQL, "sqlite"), ); err != nil { return fmt.Errorf( "database.dialect (must be one of %s, %s or %s)", diff --git a/lib/database/database.go b/lib/database/database.go index 1b09db1..540d1f6 100644 --- a/lib/database/database.go +++ b/lib/database/database.go @@ -1,14 +1,18 @@ package database import ( + "log" + "os" "strconv" "strings" + "time" "gorm.io/driver/mysql" "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/driver/sqlserver" "gorm.io/gorm" + "gorm.io/gorm/logger" ) type Credentials struct { @@ -59,13 +63,22 @@ func (c *Credentials) getDSN() gorm.Dialector { " sslmode=disable connect_timeout=5" return postgres.Open(dsn) case "sqlite": - return sqlite.Open("gorm.db") + // return sqlite.Open("gorm.db") + return sqlite.Open("file::memory:?cache=shared") } return nil } func Connect(c Credentials) (*gorm.DB, error) { - db, err := gorm.Open(c.getDSN(), &gorm.Config{}) + newLogger := logger.New( + log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer + logger.Config{ + SlowThreshold: time.Second, // Slow SQL threshold + LogLevel: logger.Info, // Log level + Colorful: true, // Disable color + }, + ) + db, err := gorm.Open(c.getDSN(), &gorm.Config{Logger: newLogger}) if err != nil { return nil, err } diff --git a/lib/utils/utils.go b/lib/utils/utils.go new file mode 100644 index 0000000..7cb8e6e --- /dev/null +++ b/lib/utils/utils.go @@ -0,0 +1,60 @@ +package utils + +import ( + "encoding/json" + "fmt" + "math/rand" + "strings" + "time" +) + +const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +const ( + letterIdxBits = 6 // 6 bits to represent a letter index + letterIdxMask = 1<= 0; { + if remain == 0 { + cache, remain = src.Int63(), letterIdxMax + } + if idx := int(cache & letterIdxMask); idx < len(letterBytes) { + sb.WriteByte(letterBytes[idx]) + i-- + } + cache >>= letterIdxBits + remain-- + } + return sb.String() +} + +func RandInt(s int, e int) int { + var integer int + for { + integer = rand.Intn(e) + if integer > s { + break + } + } + return integer +} + +func PrettyPrintJSON(s interface{}) { + switch s.(type) { + case string: + var j map[string]interface{} + json.Unmarshal([]byte(s.(string)), &j) + // jsonString, _ := json.MarshalIndent(j, "", " ") + jsonString, _ := json.Marshal(j) + fmt.Println(string(jsonString)) + default: + jsonString, _ := json.MarshalIndent(s, "", " ") + fmt.Println(string(jsonString)) + } +} diff --git a/main.go b/main.go index 36b7f02..a8bb6b7 100644 --- a/main.go +++ b/main.go @@ -1,14 +1,37 @@ package main import ( - "fmt" "os" + "strings" + "time" + "git.devices.local/mawas/golang-api-skeleton/lib/cache" "git.devices.local/mawas/golang-api-skeleton/lib/cmd" + "git.devices.local/mawas/golang-api-skeleton/lib/common" + "git.devices.local/mawas/golang-api-skeleton/lib/config" + "git.devices.local/mawas/golang-api-skeleton/lib/database" + "git.devices.local/mawas/golang-api-skeleton/lib/utils" + "git.devices.local/mawas/golang-api-skeleton/models" + "git.devices.local/mawas/golang-api-skeleton/repositories" + "git.devices.local/mawas/golang-api-skeleton/services" log "github.com/sirupsen/logrus" "github.com/spf13/viper" ) +// https://towardsdatascience.com/building-restful-apis-in-golang-e3fe6e3f8f95 +// https://www.voile.com/voile-straps.html + +// FIXME how to set unique index for username to make soft deletes possible but disallow duplicates... also how to cache a username which got delete and recerated... user ID would get overwritten, maybe pre/suffix deleted username? +// TODO replace uuids with ulids +// TODO use badgerdb for permissions? path:[token1, token2...] +// TODO add database loadbalancing feature... so allow more hosts use first as default and other ones as fallback +// TODO add userid and username to repo +// TODO usrid and username for cli user is hardcoded.. no need to live in database +// TODO get-stats cli command... which means unix socket support to communicate with server +// TODO data versioning which will be used as reference from the log, also with predictive analytics for restore which means versioning of reference objects needs to be considered +// TODO request body store as reference for log +// TODO because their is a badgerdb cache which tokens are existing or which userids are existing make an existence check at uuid generation just do be sure + var ( Version string // allows to set version on build APPName string // allows to overwrite app name on build @@ -27,16 +50,153 @@ func main() { "version": Version, "app": APPName, }) - // config priority: flags > env > config file // cobra sets env if flag is given so that viper can pick it up - if err := cmd.Initialize(Version, APPName, APPDescription); err != nil { + cfgFile, flagCfg, err := cmd.Initialize(Version, APPName, APPDescription) + if err != nil { + os.Exit(1) + } + // config priority: flags > env > config file + if err := config.Initialize(APPName, cfgFile, flagCfg); err != nil { contextLogger.WithFields(log.Fields{ "module": "config", }).Fatal(err) } + // bootstrap cache + c, err := cache.Bootstrap() + if err != nil { + contextLogger.WithFields(log.Fields{ + "module": "cache", + }).Fatal(err) + } + defer c.Close() + db, err := database.Connect(database.Credentials{ + Host: viper.GetString("database.host"), + Port: viper.GetInt("database.port"), + Dialect: viper.GetString("database.dialect"), + Database: viper.GetString("database.database"), + User: viper.GetString("database.user"), + Password: viper.GetString("database.password"), + MaxOpenConn: viper.GetInt("database.port"), + MaxIdleConn: viper.GetInt("database.port"), + MaxLifeTime: viper.GetInt("database.port"), + Debug: true, + }) + if err != nil { + contextLogger.WithFields(log.Fields{ + "module": "database", + }).Fatal(err) + } + + db.AutoMigrate(&models.User{}) + db.AutoMigrate(&models.Token{}) + userRepo := repositories.NewUserRepository(db, common.GUID{}, "", nil) + userService := services.NewUserService(userRepo) + + // Prefill cache + // TODO also add deleted users to cache for old references + if userData, err := userService.ReadAll(); err != nil { + contextLogger.WithFields(log.Fields{ + "module": "userService", + }).Fatal(err) + } else { + for i := range userData { + if err := c.Set("user:"+userData[i].ID.String(), userData[i].Username); err != nil { // userID -> username mapping + contextLogger.WithFields(log.Fields{ + "module": "cache", + }).Fatal(err) + } + if err := c.Set("user:"+userData[i].Username, userData[i].ID.String()); err != nil { // username -> userID mapping + contextLogger.WithFields(log.Fields{ + "module": "cache", + }).Fatal(err) + } + } + } + + var userID common.GUID + firstname := strings.ToLower(utils.RandString(utils.RandInt(5, 10))) + lastname := strings.ToLower(utils.RandString(utils.RandInt(6, 14))) + username := string([]byte(firstname)[0]) + lastname + user1 := &models.User{ + Username: username, + Firstname: strings.ToUpper(string([]byte(firstname)[0])) + string([]byte(firstname)[1:]), + Lastname: strings.ToUpper(string([]byte(lastname)[0])) + string([]byte(lastname)[1:]), + Email: username + "@acme.inc", + } + if result, err := userService.Create(user1); err != nil { + panic(err) + } else { + utils.PrettyPrintJSON(result) + if err := c.Set("user:"+result.ID.String(), result.Username); err != nil { // userID -> username mapping + contextLogger.WithFields(log.Fields{ + "module": "cache", + }).Fatal(err) + } + if err := c.Set("user:"+result.Username, result.ID.String()); err != nil { // username -> userID mapping + contextLogger.WithFields(log.Fields{ + "module": "cache", + }).Fatal(err) + } + userID = result.ID + } + + userRepo = repositories.NewUserRepository(db, userID, username, c) + userService = services.NewUserService(userRepo) + // userID db context? + // k := common.UsernameContextKey("username") + // ctx := context.WithValue(context.Background(), "username", username) + // db = db.WithContext(ctx) + // db = db.Set("username", username) + // fmt.Println(db.Get("username")) + + // create example token + tokenRepo := repositories.NewTokenRepository(db, userID, username, c) + tokenService := services.NewTokenService(tokenRepo) + token1 := &models.Token{ + ExpiresAt: time.Now().Add(24 * time.Hour), + UserID: userID, + Active: true, + } + if result1, err := tokenService.Create(token1); err != nil { + panic(err) + } else { + utils.PrettyPrintJSON(result1) + } + + result1, err := tokenService.ReadAll() + if err != nil { + panic(err) + } + utils.PrettyPrintJSON(result1) + + result, err := userService.ReadAll() + if err != nil { + panic(err) + } + utils.PrettyPrintJSON(result) + + firstname2 := strings.ToLower(utils.RandString(utils.RandInt(5, 10))) + lastname2 := strings.ToLower(utils.RandString(utils.RandInt(6, 14))) + username2 := string([]byte(firstname2)[0]) + lastname2 + user2 := &models.User{ + Username: username2, + Firstname: strings.ToUpper(string([]byte(firstname2)[0])) + string([]byte(firstname2)[1:]), + Lastname: strings.ToUpper(string([]byte(lastname2)[0])) + string([]byte(lastname2)[1:]), + Email: username2 + "@acme.inc", + } + if result, err := userService.Create(user2); err != nil { + panic(err) + } else { + utils.PrettyPrintJSON(result) + result3, err := userService.ReadByID(result.Username) + if err != nil { + panic(err) + } + utils.PrettyPrintJSON(result3) + } + // db, _ := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{}) - // db.AutoMigrate(&user.User{}) // userRepo := user.NewRepository(db) // userService := user.NewService(userRepo) // user1 := &user.User{ @@ -51,8 +211,12 @@ func main() { // } // fmt.Println(result) - fmt.Println("main.go --> Environment:", viper.GetString("application.environment")) - fmt.Println("main.go --> Listen:", viper.GetString("application.listenaddress")) - fmt.Println("main.go --> Database Port: ", viper.GetInt("database.port")) - fmt.Println("main.go --> Application Port:", viper.GetInt("application.port")) + // fmt.Println("main.go --> Environment:", viper.GetString("application.environment")) + // fmt.Println("main.go --> Listen:", viper.GetString("application.listenaddress")) + // fmt.Println("main.go --> Database Port: ", viper.GetInt("database.port")) + // fmt.Println("main.go --> Application Port:", viper.GetInt("application.port")) + // contextLogger.WithFields(log.Fields{ + // "module": "config", + // }).Fatal("ADSADSASd") + } diff --git a/models/token.go b/models/token.go new file mode 100644 index 0000000..449aa83 --- /dev/null +++ b/models/token.go @@ -0,0 +1,63 @@ +package models + +import ( + "database/sql" + "time" + + "git.devices.local/mawas/golang-api-skeleton/lib/cache" + "git.devices.local/mawas/golang-api-skeleton/lib/common" + "github.com/google/uuid" + "gorm.io/gorm" +) + +// Token data model +type Token struct { + common.BasicFields + Token common.GUID `gorm:"primaryKey" json:"token"` + LastUsedDB sql.NullTime `gorm:"column:last_used" json:"-"` + LastUsedJSON *time.Time `gorm:"-" json:"last_used,omitempty"` + ExpiresAt time.Time `json:"expires_at"` + UserID common.GUID `json:"asd"` + Username string `json:"username"` + Active bool `json:"active"` +} + +func (token *Token) BeforeCreate(tx *gorm.DB) error { + id, err := uuid.NewRandom() + token.Token = common.GUID(id) + if userID, ok := tx.Get("userID"); ok { + if guid, ok := userID.(common.GUID); ok { + token.CreatedByDB = guid + token.UpdatedByDB = guid + } + } + return err +} + +func (token *Token) AfterFind(tx *gorm.DB) error { + if token.LastUsedDB.Valid { + token.LastUsedJSON = &token.LastUsedDB.Time + } + if token.DeletedAtDB.Valid { + token.DeletedAtJSON = &token.DeletedAtDB.Time + } + if cc, ok := tx.Get("cache"); ok { + if c, ok := cc.(cache.Cache); ok { + if username, err := c.Get("user:" + token.CreatedByDB.String()); err != nil { + return err + } else if username != nil { + token.CreatedByJSON = *username + } + if username, err := c.Get("user:" + token.UpdatedByDB.String()); err != nil { + return err + } else if username != nil { + token.UpdatedByJSON = *username + } + if username, err := c.Get("user:" + token.UserID.String()); err != nil { + } else if username != nil { + token.Username = *username + } + } + } + return nil +} diff --git a/models/user.go b/models/user.go new file mode 100644 index 0000000..71c5287 --- /dev/null +++ b/models/user.go @@ -0,0 +1,70 @@ +package models + +import ( + "git.devices.local/mawas/golang-api-skeleton/lib/cache" + "git.devices.local/mawas/golang-api-skeleton/lib/common" + "gorm.io/gorm" +) + +// User data model +type User struct { + common.ModelHiddenGUIDPK + Username string `gorm:"unique_index:username" json:"username,omitempty"` + Firstname string `json:"firstname,omitempty"` + Lastname string `json:"lastname,omitempty"` + Email string `json:"email,omitempty"` + TokensRef []Token `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-"` + Tokens []string `gorm:"-" json:"tokens"` + PasswordHash string `json:"-"` + Active bool ` json:"active"` +} + +func (user *User) AfterCreate(tx *gorm.DB) error { + if username, ok := tx.Get("username"); ok { + if name, ok := username.(string); ok { + user.CreatedByJSON = name + user.UpdatedByJSON = name + } + } + user.Tokens = []string{} + return nil +} + +func (user *User) AfterFind(tx *gorm.DB) error { + if user.DeletedAtDB.Valid { + user.DeletedAtJSON = &user.DeletedAtDB.Time + } + for i := range user.TokensRef { + user.Tokens = append(user.Tokens, user.TokensRef[i].Token.String()) + } + if len(user.Tokens) == 0 { + user.Tokens = []string{""} + } + if cc, ok := tx.Get("cache"); ok { + if c, ok := cc.(cache.Cache); ok { + if username, err := c.Get("user:" + user.CreatedByDB.String()); err != nil { + return err + } else if username != nil { + user.CreatedByJSON = *username + } + if username, err := c.Get("user:" + user.UpdatedByDB.String()); err != nil { + return err + } else if username != nil { + user.UpdatedByJSON = *username + } + } + } + return nil +} + +// func (user *User) BeforeCreate(tx *gorm.DB) error { +// // ctx := tx.Statement.Context +// // username := ctx.Value("username") +// // switch v := username.(type) { +// // case nil: +// // case string: +// // user.CreatedBy = v +// // } +// // +// return nil +// } diff --git a/pkg/user/database.go b/pkg/user/database.go deleted file mode 100644 index 5958614..0000000 --- a/pkg/user/database.go +++ /dev/null @@ -1,31 +0,0 @@ -package user - -import "gorm.io/gorm" - -type repo struct { - db *gorm.DB -} - -// NewRepository create new repository -func NewRepository(db *gorm.DB) Repository { - return &repo{ - db: db, - } -} - -func (r *repo) ReadByID(id uint) (*User, error) { - result := User{} - err := r.db.First(&result, id).Error - return &result, err -} - -func (r *repo) ReadAll() ([]*User, error) { - var result []*User - err := r.db.Find(&result).Error - return result, err -} - -func (r *repo) Create(user *User) (*User, error) { - err := r.db.Create(user).Error - return user, err -} diff --git a/pkg/user/model.go b/pkg/user/model.go deleted file mode 100644 index 81d7f0a..0000000 --- a/pkg/user/model.go +++ /dev/null @@ -1,16 +0,0 @@ -package user - -import ( - "gorm.io/gorm" -) - -// User data model -type User struct { - gorm.Model - Username string `gorm:"unique_index:username" json:"username,omitempty"` - Firstname string `json:"firstname,omitempty"` - Lastname string `json:"lastname,omitempty"` - Email string `json:"email,omitempty"` - PasswordHash string `json:"-"` - Active bool ` json:"active"` -} diff --git a/pkg/user/repository.go b/pkg/user/repository.go deleted file mode 100644 index d435a46..0000000 --- a/pkg/user/repository.go +++ /dev/null @@ -1,20 +0,0 @@ -package user - -// Reader -type Reader interface { - ReadByID(id uint) (*User, error) - ReadAll() ([]*User, error) -} - -// Writer -type Writer interface { - // Update(user *User) error - Create(user *User) (*User, error) - // Delete(user *User) (uint64, error) -} - -// Repository repository interface -type Repository interface { - Reader - Writer -} diff --git a/pkg/user/service.go b/pkg/user/service.go deleted file mode 100644 index 17f2a78..0000000 --- a/pkg/user/service.go +++ /dev/null @@ -1,18 +0,0 @@ -package user - -// Service service interface -type Service interface { - Reader - Writer - // Register(user *User) (entity.ID, error) - // ForgotPassword(user *User) error - // ChangePassword(user *User, password string) error - // Validate(user *User) error - // Auth(user *User, password string) error - // IsValid(user *User) bool - // GetRepo() Repository -} - -func NewService(repo Repository) Service { - return repo -} diff --git a/repositories/token.go b/repositories/token.go new file mode 100644 index 0000000..9c71880 --- /dev/null +++ b/repositories/token.go @@ -0,0 +1,53 @@ +// Data access objects layer of model token +package repositories + +import ( + "git.devices.local/mawas/golang-api-skeleton/lib/cache" + "git.devices.local/mawas/golang-api-skeleton/lib/common" + model "git.devices.local/mawas/golang-api-skeleton/models" + "gorm.io/gorm" +) + +type tokenDAO struct { + repo +} + +// NewTokenRepository create new repository for model token +func NewTokenRepository(db *gorm.DB, userID common.GUID, username string, cache cache.Cache) *tokenDAO { + db = db.Set("username", username).Set("userID", userID).Set("cache", cache) + return &tokenDAO{ + repo: repo{ + db: db, + userID: userID, + username: username, + }, + } +} + +func (dao *tokenDAO) ReadByKey(key interface{}) (*model.Token, error) { + token := model.Token{} + err := dao.db.Joins("User").First(&token, key).Error + return &token, err +} + +func (dao *tokenDAO) ReadAll() ([]*model.Token, error) { + var tokens []*model.Token + err := dao.db.Find(&tokens).Error + return tokens, err +} + +func (dao *tokenDAO) Create(token *model.Token) (*model.Token, error) { + err := dao.db.Create(token).Error + if cc, ok := dao.db.Get("cache"); ok { + if c, ok := cc.(cache.Cache); ok { + if username, err := c.Get("user:" + token.UserID.String()); err != nil { + return nil, err + } else { + if username != nil { + token.Username = *username + } + } + } + } + return token, err +} diff --git a/repositories/user.go b/repositories/user.go new file mode 100644 index 0000000..4045872 --- /dev/null +++ b/repositories/user.go @@ -0,0 +1,42 @@ +// Data access objects layer of model user +package repositories + +import ( + "git.devices.local/mawas/golang-api-skeleton/lib/cache" + "git.devices.local/mawas/golang-api-skeleton/lib/common" + model "git.devices.local/mawas/golang-api-skeleton/models" + "gorm.io/gorm" +) + +type UserDAO struct { + repo +} + +// NewUserDAO create new repository for model user +func NewUserRepository(db *gorm.DB, userID common.GUID, username string, cache cache.Cache) *UserDAO { + db = db.Set("username", username).Set("userID", userID).Set("cache", cache) + return &UserDAO{ + repo: repo{ + db: db, + userID: userID, + username: username, + }, + } +} + +func (dao *UserDAO) ReadByUsername(username string) (*model.User, error) { + result := model.User{} + err := dao.db.Where(&model.User{Username: username}).First(&result).Error + return &result, err +} + +func (dao *UserDAO) ReadAll() ([]*model.User, error) { + var result []*model.User + err := dao.db.Preload("TokensRef").Find(&result).Error + return result, err +} + +func (dao *UserDAO) Create(user *model.User) (*model.User, error) { + err := dao.db.Create(user).Error + return user, err +} diff --git a/services/token.go b/services/token.go new file mode 100644 index 0000000..8a7a551 --- /dev/null +++ b/services/token.go @@ -0,0 +1,35 @@ +package services + +import ( + model "git.devices.local/mawas/golang-api-skeleton/models" +) + +type tokenRepository interface { + ReadByKey(key interface{}) (*model.Token, error) + ReadAll() ([]*model.Token, error) + Create(token *model.Token) (*model.Token, error) +} + +type TokenService struct { + repo tokenRepository +} + +// NewTokenService creates a new TokenService with the given user DAO. +func NewTokenService(repo tokenRepository) *TokenService { + return &TokenService{repo} +} + +// ReadByKey just retrieves user using User DAO, here can be additional logic for processing data retrieved by DAOs +func (s *TokenService) ReadByKey(key interface{}) (*model.Token, error) { + return s.repo.ReadByKey(key) +} + +// ReadAll just retrieves user using User DAO, here can be additional logic for processing data retrieved by DAOs +func (s *TokenService) ReadAll() ([]*model.Token, error) { + return s.repo.ReadAll() +} + +// Create just retrieves user using User DAO, here can be additional logic for processing data retrieved by DAOs +func (s *TokenService) Create(token *model.Token) (*model.Token, error) { + return s.repo.Create(token) +} diff --git a/services/user.go b/services/user.go new file mode 100644 index 0000000..0f7007d --- /dev/null +++ b/services/user.go @@ -0,0 +1,35 @@ +package services + +import ( + model "git.devices.local/mawas/golang-api-skeleton/models" +) + +type userRepository interface { + ReadByUsername(username string) (*model.User, error) + ReadAll() ([]*model.User, error) + Create(user *model.User) (*model.User, error) +} + +type UserService struct { + repo userRepository +} + +// NewUserService creates a new UserService with the given user DAO. +func NewUserService(repo userRepository) *UserService { + return &UserService{repo} +} + +// ReadByUsername just retrieves user using User DAO, here can be additional logic for processing data retrieved by DAOs +func (s *UserService) ReadByID(id interface{}) (*model.User, error) { + return s.repo.ReadByUsername(id.(string)) +} + +// ReadAll just retrieves user using User DAO, here can be additional logic for processing data retrieved by DAOs +func (s *UserService) ReadAll() ([]*model.User, error) { + return s.repo.ReadAll() +} + +// Create just retrieves user using User DAO, here can be additional logic for processing data retrieved by DAOs +func (s *UserService) Create(user *model.User) (*model.User, error) { + return s.repo.Create(user) +}