mirror of https://github.com/harness/drone.git
Initial commit
commit
5891818ce1
|
@ -0,0 +1,9 @@
|
|||
NOTES*
|
||||
_research
|
||||
.env
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
web/node_modules
|
||||
web/dist/files
|
||||
release
|
||||
my-app
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"go.testTags": "sqlite_fts5"
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this pipeline adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
@ -0,0 +1,93 @@
|
|||
# PolyForm Free Trial License 1.0.0
|
||||
|
||||
<https://polyformproject.org/licenses/free-trial/1.0.0>
|
||||
|
||||
## Acceptance
|
||||
|
||||
In order to get any license under these terms, you must agree
|
||||
to them as both strict obligations and conditions to all
|
||||
your licenses.
|
||||
|
||||
## Copyright License
|
||||
|
||||
The licensor grants you a copyright license for the software
|
||||
to do everything you might do with the software that would
|
||||
otherwise infringe the licensor's copyright in it for any
|
||||
permitted purpose. However, you may only make changes or
|
||||
new works based on the software according to [Changes and New
|
||||
Works License](#changes-and-new-works-license), and you may
|
||||
not distribute copies of the software.
|
||||
|
||||
## Changes and New Works License
|
||||
|
||||
The licensor grants you an additional copyright license to
|
||||
make changes and new works based on the software for any
|
||||
permitted purpose.
|
||||
|
||||
## Patent License
|
||||
|
||||
The licensor grants you a patent license for the software that
|
||||
covers patent claims the licensor can license, or becomes able
|
||||
to license, that you would infringe by using the software.
|
||||
|
||||
## Fair Use
|
||||
|
||||
You may have "fair use" rights for the software under the
|
||||
law. These terms do not limit them.
|
||||
|
||||
## Free Trial
|
||||
|
||||
Use to evaluate whether the software suits a particular
|
||||
application for less than 32 consecutive calendar days, on
|
||||
behalf of you or your company, is use for a permitted purpose.
|
||||
|
||||
## No Other Rights
|
||||
|
||||
These terms do not allow you to sublicense or transfer any of
|
||||
your licenses to anyone else, or prevent the licensor from
|
||||
granting licenses to anyone else. These terms do not imply
|
||||
any other licenses.
|
||||
|
||||
## Patent Defense
|
||||
|
||||
If you make any written claim that the software infringes or
|
||||
contributes to infringement of any patent, your patent license
|
||||
for the software granted under these terms ends immediately. If
|
||||
your company makes such a claim, your patent license ends
|
||||
immediately for work on behalf of your company.
|
||||
|
||||
## Violations
|
||||
|
||||
If you violate any of these terms, or do anything with the
|
||||
software not covered by your licenses, all your licenses
|
||||
end immediately.
|
||||
|
||||
## No Liability
|
||||
|
||||
***As far as the law allows, the software comes as is, without
|
||||
any warranty or condition, and the licensor will not be liable
|
||||
to you for any damages arising out of these terms or the use
|
||||
or nature of the software, under any kind of legal claim.***
|
||||
|
||||
## Definitions
|
||||
|
||||
The **licensor** is the individual or entity offering these
|
||||
terms, and the **software** is the software the licensor makes
|
||||
available under these terms.
|
||||
|
||||
**You** refers to the individual or entity agreeing to these
|
||||
terms.
|
||||
|
||||
**Your company** is any legal entity, sole proprietorship,
|
||||
or other kind of organization that you work for, plus all
|
||||
organizations that have control over, are under the control of,
|
||||
or are under common control with that organization. **Control**
|
||||
means ownership of substantially all the assets of an entity,
|
||||
or the power to direct its management and policies by vote,
|
||||
contract, or otherwise. Control can be direct or indirect.
|
||||
|
||||
**Your licenses** are all the licenses granted to you for the
|
||||
software under these terms.
|
||||
|
||||
**Use** means anything you do with the software requiring one
|
||||
of your licenses.
|
|
@ -0,0 +1,111 @@
|
|||
# Pre-Requisites
|
||||
|
||||
Install the latest stable version of Node and Go version 1.17 or higher, and then install the below Go programs. Ensure the GOPATH [bin directory](https://go.dev/doc/gopath_code#GOPATH) is added to your PATH.
|
||||
|
||||
```text
|
||||
$ go install github.com/golang/mock/mockgen@latest
|
||||
$ go install github.com/google/wire/cmd/wire@latest
|
||||
```
|
||||
|
||||
# Build
|
||||
|
||||
Build the user interface:
|
||||
|
||||
```text
|
||||
$ pushd web
|
||||
$ npm install
|
||||
$ npm run build
|
||||
$ popd
|
||||
```
|
||||
|
||||
Build the server and command line tools:
|
||||
|
||||
```text
|
||||
$ go generate ./...
|
||||
$ go build -o release/my-app
|
||||
```
|
||||
|
||||
# Test
|
||||
|
||||
Execute the unit tests:
|
||||
|
||||
```text
|
||||
$ go generate ./...
|
||||
$ go test -v -cover ./...
|
||||
```
|
||||
|
||||
# Run
|
||||
|
||||
This project supports all operating systems and architectures supported by Go. This means you can build and run the system on your machine; docker containers are not required for local development and testing.
|
||||
|
||||
Start the server at `localhost:3000`
|
||||
|
||||
```text
|
||||
$ release/my-app server
|
||||
```
|
||||
|
||||
# User Interface
|
||||
|
||||
This project includes a simple user interface for interacting with the system. When you run the application, you can access the user interface by navigating to `http://localhost:3000` in your browser.
|
||||
|
||||
# Swagger
|
||||
|
||||
This project includes a swagger specification. When you run the application, you can access the swagger specification by navigating to `http://localhost:3000/swagger` in your browser.
|
||||
|
||||
# Command Line
|
||||
|
||||
This project includes simple command line tools for interacting with the system. Please remember that you must start the server before you can execute commands.
|
||||
|
||||
Register a new user:
|
||||
|
||||
```text
|
||||
$ release/my-app register
|
||||
```
|
||||
|
||||
Login to the application:
|
||||
|
||||
```text
|
||||
$ release/my-app login
|
||||
```
|
||||
|
||||
Logout from the application:
|
||||
|
||||
```text
|
||||
$ release/my-app logout
|
||||
```
|
||||
|
||||
View your account details:
|
||||
|
||||
```text
|
||||
$ release/my-app account
|
||||
```
|
||||
|
||||
Generate a peronsal access token:
|
||||
|
||||
```text
|
||||
$ release/my-app token
|
||||
```
|
||||
|
||||
Create a pipeline:
|
||||
|
||||
```text
|
||||
$ release/my-app pipeline create <name>
|
||||
```
|
||||
|
||||
List pipelines:
|
||||
|
||||
```text
|
||||
$ release/my-app pipeline ls
|
||||
```
|
||||
|
||||
Debug and output http responses from the server:
|
||||
|
||||
```text
|
||||
$ DEBUG=true release/my-app pipeline ls
|
||||
```
|
||||
|
||||
View all commands:
|
||||
|
||||
```text
|
||||
$ release/my-app --help
|
||||
```
|
|
@ -0,0 +1,60 @@
|
|||
version: '3'
|
||||
|
||||
tasks:
|
||||
test:
|
||||
cmds:
|
||||
- go test -v -cover ./...
|
||||
|
||||
# postgres tests are currently failing due to issues
|
||||
# with the seed.sql file.
|
||||
test-postgres:
|
||||
env:
|
||||
DATABASE_DRIVER: postgres
|
||||
DATABASE_CONFIG: host=localhost user=postgres password=postgres dbname=postgres sslmode=disable
|
||||
GO111MODULE: 'on'
|
||||
cmds:
|
||||
- cmd: docker kill postgres
|
||||
ignore_error: true
|
||||
silent: false
|
||||
- silent: false
|
||||
cmd: >
|
||||
docker run
|
||||
-p 5432:5432
|
||||
--env POSTGRES_PASSWORD=postgres
|
||||
--env POSTGRES_USER=postgres
|
||||
--name postgres
|
||||
--detach
|
||||
--rm
|
||||
postgres:9-alpine
|
||||
- cmd: go test -v -cover github.com/bradrydzewski/my-app/internal/store/database
|
||||
- cmd: docker kill postgres
|
||||
silent: true
|
||||
|
||||
setup:
|
||||
cmds:
|
||||
- cd web; npm install
|
||||
- cd web; npm run build
|
||||
- go generate ./...
|
||||
- go build
|
||||
|
||||
teardown:
|
||||
cmds:
|
||||
- rm -rf release
|
||||
- rm -rf web/.cache
|
||||
- rm -rf web/dist/files
|
||||
- rm -rf web/node_modules
|
||||
- rm -rf web/.env.development.local
|
||||
- rm -rf web/swagger.yaml
|
||||
- rm -rf my-app
|
||||
- rm -rf database.sqlite3
|
||||
- rm -rf .env
|
||||
|
||||
docker-build:
|
||||
cmds:
|
||||
- docker build -t bradrydzewski/my-app:linux-amd64 -f docker/Dockerfile .
|
||||
|
||||
docker-build-all:
|
||||
cmds:
|
||||
- docker build -t bradrydzewski/my-app:linux-amd64 -f docker/Dockerfile .
|
||||
- docker build -t bradrydzewski/my-app:linux-arm64 -f docker/Dockerfile.linux.arm64 .
|
||||
- docker build -t bradrydzewski/my-app:linux-arm -f docker/Dockerfile.linux.arm .
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/execution"
|
||||
"github.com/bradrydzewski/my-app/cli/pipeline"
|
||||
"github.com/bradrydzewski/my-app/cli/server"
|
||||
"github.com/bradrydzewski/my-app/cli/token"
|
||||
"github.com/bradrydzewski/my-app/cli/user"
|
||||
"github.com/bradrydzewski/my-app/cli/users"
|
||||
"github.com/bradrydzewski/my-app/version"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
// empty context
|
||||
var nocontext = context.Background()
|
||||
|
||||
// application name
|
||||
var application = "my-app"
|
||||
|
||||
// application description
|
||||
var description = "description goes here" // TODO edit this application description
|
||||
|
||||
// Command parses the command line arguments and then executes a
|
||||
// subcommand program.
|
||||
func Command() {
|
||||
app := kingpin.New(application, description)
|
||||
server.Register(app)
|
||||
user.Register(app)
|
||||
pipeline.Register(app)
|
||||
execution.Register(app)
|
||||
users.Register(app)
|
||||
token.Register(app)
|
||||
registerLogin(app)
|
||||
registerLogout(app)
|
||||
registerRegister(app)
|
||||
registerSwagger(app)
|
||||
|
||||
kingpin.Version(version.Version.String())
|
||||
kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
|
||||
"github.com/drone/funcmap"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type createCommand struct {
|
||||
pipeline string
|
||||
slug string
|
||||
name string
|
||||
desc string
|
||||
tmpl string
|
||||
json bool
|
||||
}
|
||||
|
||||
func (c *createCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
in := &types.Execution{
|
||||
Slug: c.slug,
|
||||
Name: c.name,
|
||||
Desc: c.desc,
|
||||
}
|
||||
item, err := client.ExecutionCreate(c.pipeline, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(item)
|
||||
}
|
||||
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, item)
|
||||
}
|
||||
|
||||
// helper function registers the user create command
|
||||
func registerCreate(app *kingpin.CmdClause) {
|
||||
c := new(createCommand)
|
||||
|
||||
cmd := app.Command("create", "create a execution").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("pipeline ", "pipeline slug").
|
||||
Required().
|
||||
StringVar(&c.pipeline)
|
||||
|
||||
cmd.Arg("slug ", "execution slug").
|
||||
Required().
|
||||
StringVar(&c.slug)
|
||||
|
||||
cmd.Flag("name", "execution name").
|
||||
StringVar(&c.name)
|
||||
|
||||
cmd.Flag("desc", "execution description").
|
||||
StringVar(&c.desc)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
cmd.Flag("format", "format the output using a Go template").
|
||||
Default(executionTmpl).
|
||||
Hidden().
|
||||
StringVar(&c.tmpl)
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type deleteCommand struct {
|
||||
pipeline string
|
||||
slug string
|
||||
}
|
||||
|
||||
func (c *deleteCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return client.ExecutionDelete(c.pipeline, c.slug)
|
||||
}
|
||||
|
||||
// helper function registers the user delete command
|
||||
func registerDelete(app *kingpin.CmdClause) {
|
||||
c := new(deleteCommand)
|
||||
|
||||
cmd := app.Command("delete", "delete a execution").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("pipeline ", "pipeline slug").
|
||||
Required().
|
||||
StringVar(&c.pipeline)
|
||||
|
||||
cmd.Arg("slug ", "execution slug").
|
||||
Required().
|
||||
StringVar(&c.slug)
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import "gopkg.in/alecthomas/kingpin.v2"
|
||||
|
||||
// Register the command.
|
||||
func Register(app *kingpin.Application) {
|
||||
cmd := app.Command("execution", "manage executions")
|
||||
registerFind(cmd)
|
||||
registerList(cmd)
|
||||
registerCreate(cmd)
|
||||
registerUpdate(cmd)
|
||||
registerDelete(cmd)
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
|
||||
"github.com/drone/funcmap"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type findCommand struct {
|
||||
pipeline string
|
||||
slug string
|
||||
tmpl string
|
||||
json bool
|
||||
}
|
||||
|
||||
func (c *findCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
item, err := client.Execution(c.pipeline, c.slug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(item)
|
||||
}
|
||||
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl + "\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, item)
|
||||
}
|
||||
|
||||
// helper function registers the user find command
|
||||
func registerFind(app *kingpin.CmdClause) {
|
||||
c := new(findCommand)
|
||||
|
||||
cmd := app.Command("find", "display pipeline details").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("pipeline ", "pipeline slug").
|
||||
Required().
|
||||
StringVar(&c.pipeline)
|
||||
|
||||
cmd.Arg("slug ", "execution slug").
|
||||
Required().
|
||||
StringVar(&c.slug)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
cmd.Flag("format", "format the output using a Go template").
|
||||
Default(executionTmpl).
|
||||
Hidden().
|
||||
StringVar(&c.tmpl)
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/drone/funcmap"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
const executionTmpl = `
|
||||
id: {{ .ID }}
|
||||
slug: {{ .Slug }}
|
||||
name: {{ .Name }}
|
||||
desc: {{ .Desc }}
|
||||
`
|
||||
|
||||
type listCommand struct {
|
||||
slug string
|
||||
tmpl string
|
||||
json bool
|
||||
page int
|
||||
size int
|
||||
}
|
||||
|
||||
func (c *listCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
list, err := client.ExecutionList(c.slug, types.Params{
|
||||
Size: c.size,
|
||||
Page: c.page,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(list)
|
||||
}
|
||||
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl + "\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range list {
|
||||
tmpl.Execute(os.Stdout, item)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// helper function registers the list command
|
||||
func registerList(app *kingpin.CmdClause) {
|
||||
c := new(listCommand)
|
||||
|
||||
cmd := app.Command("ls", "display a list of executions").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("pipeline ", "pipeline slug").
|
||||
Required().
|
||||
StringVar(&c.slug)
|
||||
|
||||
cmd.Flag("page", "page number").
|
||||
IntVar(&c.page)
|
||||
|
||||
cmd.Flag("per-page", "page size").
|
||||
IntVar(&c.size)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
cmd.Flag("format", "format the output using a Go template").
|
||||
Default(executionTmpl).
|
||||
Hidden().
|
||||
StringVar(&c.tmpl)
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/gotidy/ptr"
|
||||
|
||||
"github.com/drone/funcmap"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type updateCommand struct {
|
||||
pipeline string
|
||||
slug string
|
||||
name string
|
||||
desc string
|
||||
tmpl string
|
||||
json bool
|
||||
}
|
||||
|
||||
func (c *updateCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
in := new(types.ExecutionInput)
|
||||
if v := c.name; v != "" {
|
||||
in.Name = ptr.String(v)
|
||||
}
|
||||
if v := c.desc; v != "" {
|
||||
in.Desc = ptr.String(v)
|
||||
}
|
||||
|
||||
item, err := client.ExecutionUpdate(c.pipeline, c.slug, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(item)
|
||||
}
|
||||
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, item)
|
||||
}
|
||||
|
||||
// helper function registers the update command
|
||||
func registerUpdate(app *kingpin.CmdClause) {
|
||||
c := new(updateCommand)
|
||||
|
||||
cmd := app.Command("update", "update a execution").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("pipeline ", "pipeline slug").
|
||||
Required().
|
||||
StringVar(&c.pipeline)
|
||||
|
||||
cmd.Arg("slug ", "execution slug").
|
||||
Required().
|
||||
StringVar(&c.slug)
|
||||
|
||||
cmd.Flag("name", "update pipeline name").
|
||||
StringVar(&c.name)
|
||||
|
||||
cmd.Flag("desc", "update pipeline description").
|
||||
StringVar(&c.desc)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
cmd.Flag("format", "format the output using a Go template").
|
||||
Default(executionTmpl).
|
||||
Hidden().
|
||||
StringVar(&c.tmpl)
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
"github.com/bradrydzewski/my-app/client"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type loginCommand struct {
|
||||
server string
|
||||
}
|
||||
|
||||
func (c *loginCommand) run(*kingpin.ParseContext) error {
|
||||
username, password := util.Credentials()
|
||||
client := client.New(c.server)
|
||||
token, err := client.Login(username, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path, err := util.Config()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
token.Address = c.server
|
||||
data, err := json.Marshal(token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(path, data, 0600)
|
||||
}
|
||||
|
||||
// helper function to register the logout command.
|
||||
func registerLogin(app *kingpin.Application) {
|
||||
c := new(loginCommand)
|
||||
|
||||
cmd := app.Command("login", "login to the remote server").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("server", "server address").
|
||||
Default("http://localhost:3000").
|
||||
StringVar(&c.server)
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type logoutCommand struct{}
|
||||
|
||||
func (c *logoutCommand) run(*kingpin.ParseContext) error {
|
||||
path, err := util.Config()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
// helper function to register the logout command.
|
||||
func registerLogout(app *kingpin.Application) {
|
||||
c := new(logoutCommand)
|
||||
|
||||
app.Command("logout", "logout from the remote server").
|
||||
Action(c.run)
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
|
||||
"github.com/drone/funcmap"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type createCommand struct {
|
||||
slug string
|
||||
name string
|
||||
desc string
|
||||
tmpl string
|
||||
json bool
|
||||
}
|
||||
|
||||
func (c *createCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
in := &types.Pipeline{
|
||||
Slug: c.slug,
|
||||
Name: c.name,
|
||||
Desc: c.desc,
|
||||
}
|
||||
item, err := client.PipelineCreate(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(item)
|
||||
}
|
||||
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, item)
|
||||
}
|
||||
|
||||
// helper function registers the user create command
|
||||
func registerCreate(app *kingpin.CmdClause) {
|
||||
c := new(createCommand)
|
||||
|
||||
cmd := app.Command("create", "create a pipeline").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("slug", "pipeline slug").
|
||||
Required().
|
||||
StringVar(&c.slug)
|
||||
|
||||
cmd.Flag("name", "pipeline name").
|
||||
StringVar(&c.name)
|
||||
|
||||
cmd.Flag("desc", "pipeline description").
|
||||
StringVar(&c.desc)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
cmd.Flag("format", "format the output using a Go template").
|
||||
Default(pipelineTmpl).
|
||||
Hidden().
|
||||
StringVar(&c.tmpl)
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type deleteCommand struct {
|
||||
slug string
|
||||
}
|
||||
|
||||
func (c *deleteCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return client.PipelineDelete(c.slug)
|
||||
}
|
||||
|
||||
// helper function registers the user delete command
|
||||
func registerDelete(app *kingpin.CmdClause) {
|
||||
c := new(deleteCommand)
|
||||
|
||||
cmd := app.Command("delete", "delete a pipeline").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("slug ", "pipeline slug").
|
||||
Required().
|
||||
StringVar(&c.slug)
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
|
||||
"github.com/drone/funcmap"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type findCommand struct {
|
||||
slug string
|
||||
tmpl string
|
||||
json bool
|
||||
}
|
||||
|
||||
func (c *findCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
item, err := client.Pipeline(c.slug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(item)
|
||||
}
|
||||
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl + "\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, item)
|
||||
}
|
||||
|
||||
// helper function registers the user find command
|
||||
func registerFind(app *kingpin.CmdClause) {
|
||||
c := new(findCommand)
|
||||
|
||||
cmd := app.Command("find", "display pipeline details").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("slug", "pipeline slug").
|
||||
Required().
|
||||
StringVar(&c.slug)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
cmd.Flag("format", "format the output using a Go template").
|
||||
Default(pipelineTmpl).
|
||||
Hidden().
|
||||
StringVar(&c.tmpl)
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/drone/funcmap"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
const pipelineTmpl = `
|
||||
id: {{ .ID }}
|
||||
slug: {{ .Slug }}
|
||||
name: {{ .Name }}
|
||||
desc: {{ .Desc }}
|
||||
`
|
||||
|
||||
type listCommand struct {
|
||||
page int
|
||||
size int
|
||||
json bool
|
||||
tmpl string
|
||||
}
|
||||
|
||||
func (c *listCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
list, err := client.PipelineList(types.Params{
|
||||
Size: c.size,
|
||||
Page: c.page,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(list)
|
||||
}
|
||||
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl + "\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range list {
|
||||
tmpl.Execute(os.Stdout, item)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// helper function registers the user list command
|
||||
func registerList(app *kingpin.CmdClause) {
|
||||
c := new(listCommand)
|
||||
|
||||
cmd := app.Command("ls", "display a list of pipelines").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Flag("page", "page number").
|
||||
IntVar(&c.page)
|
||||
|
||||
cmd.Flag("per-page", "page size").
|
||||
IntVar(&c.size)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
cmd.Flag("format", "format the output using a Go template").
|
||||
Default(pipelineTmpl).
|
||||
Hidden().
|
||||
StringVar(&c.tmpl)
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import "gopkg.in/alecthomas/kingpin.v2"
|
||||
|
||||
// Register the command.
|
||||
func Register(app *kingpin.Application) {
|
||||
cmd := app.Command("pipeline", "manage pipelines")
|
||||
registerFind(cmd)
|
||||
registerList(cmd)
|
||||
registerCreate(cmd)
|
||||
registerUpdate(cmd)
|
||||
registerDelete(cmd)
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/gotidy/ptr"
|
||||
|
||||
"github.com/drone/funcmap"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type updateCommand struct {
|
||||
slug string
|
||||
name string
|
||||
desc string
|
||||
tmpl string
|
||||
json bool
|
||||
}
|
||||
|
||||
func (c *updateCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
in := new(types.PipelineInput)
|
||||
if v := c.name; v != "" {
|
||||
in.Name = ptr.String(v)
|
||||
}
|
||||
if v := c.desc; v != "" {
|
||||
in.Desc = ptr.String(v)
|
||||
}
|
||||
|
||||
item, err := client.PipelineUpdate(c.slug, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(item)
|
||||
}
|
||||
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, item)
|
||||
}
|
||||
|
||||
// helper function registers the user update command
|
||||
func registerUpdate(app *kingpin.CmdClause) {
|
||||
c := new(updateCommand)
|
||||
|
||||
cmd := app.Command("update", "update a pipeline").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("slug", "pipeline slug").
|
||||
Required().
|
||||
StringVar(&c.slug)
|
||||
|
||||
cmd.Flag("name", "update pipeline name").
|
||||
StringVar(&c.name)
|
||||
|
||||
cmd.Flag("desc", "update pipeline description").
|
||||
StringVar(&c.desc)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
cmd.Flag("format", "format the output using a Go template").
|
||||
Default(pipelineTmpl).
|
||||
Hidden().
|
||||
StringVar(&c.tmpl)
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
"github.com/bradrydzewski/my-app/client"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type registerCommand struct {
|
||||
server string
|
||||
}
|
||||
|
||||
func (c *registerCommand) run(*kingpin.ParseContext) error {
|
||||
username, password := util.Credentials()
|
||||
client := client.New(c.server)
|
||||
token, err := client.Register(username, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path, err := util.Config()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
token.Address = c.server
|
||||
data, err := json.Marshal(token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(path, data, 0600)
|
||||
}
|
||||
|
||||
// helper function to register the register command.
|
||||
func registerRegister(app *kingpin.Application) {
|
||||
c := new(registerCommand)
|
||||
|
||||
cmd := app.Command("register", "register a user").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("server", "server address").
|
||||
Default("http://localhost:3000").
|
||||
StringVar(&c.server)
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
|
||||
"github.com/kelseyhightower/envconfig"
|
||||
)
|
||||
|
||||
// legacy environment variables. the key is the legacy
|
||||
// variable name, and the value is the new variable name.
|
||||
var legacy = map[string]string{
|
||||
// none defined
|
||||
}
|
||||
|
||||
// load returns the system configuration from the
|
||||
// host environment.
|
||||
func load() (*types.Config, error) {
|
||||
|
||||
// loop through legacy environment variable and, if set
|
||||
// rewrite to the new variable name.
|
||||
for k, v := range legacy {
|
||||
if s, ok := os.LookupEnv(k); ok {
|
||||
os.Setenv(v, s)
|
||||
}
|
||||
}
|
||||
|
||||
config := new(types.Config)
|
||||
// read the configuration from the environment and
|
||||
// populate the configuration structure.
|
||||
err := envconfig.Process("", config)
|
||||
return config, err
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/bradrydzewski/my-app/version"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
envfile string
|
||||
}
|
||||
|
||||
func (c *command) run(*kingpin.ParseContext) error {
|
||||
// load environment variables from file.
|
||||
godotenv.Load(c.envfile)
|
||||
|
||||
// create the system configuration store by loading
|
||||
// data from the environment.
|
||||
config, err := load()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).
|
||||
Msg("cannot load configuration")
|
||||
}
|
||||
|
||||
// configure the log level
|
||||
setupLogger(config)
|
||||
|
||||
system, err := initSystem(config)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).
|
||||
Msg("cannot boot server")
|
||||
}
|
||||
|
||||
var g errgroup.Group
|
||||
|
||||
// starts the http server.
|
||||
g.Go(func() error {
|
||||
log.Info().
|
||||
Str("port", config.Server.Bind).
|
||||
Str("revision", version.GitCommit).
|
||||
Str("repository", version.GitRepository).
|
||||
Stringer("version", version.Version).
|
||||
Msg("server started")
|
||||
return system.server.ListenAndServe(context.Background())
|
||||
})
|
||||
|
||||
// start the purge routine.
|
||||
g.Go(func() error {
|
||||
log.Debug().Msg("starting the nightly subroutine")
|
||||
system.nightly.Run(context.Background())
|
||||
return nil
|
||||
})
|
||||
|
||||
return g.Wait()
|
||||
}
|
||||
|
||||
// helper function configures the global logger from
|
||||
// the loaded configuration.
|
||||
func setupLogger(config *types.Config) {
|
||||
// configure the log level
|
||||
switch {
|
||||
case config.Trace:
|
||||
zerolog.SetGlobalLevel(zerolog.TraceLevel)
|
||||
case config.Debug:
|
||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||
default:
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
}
|
||||
|
||||
// if the terminal is a tty we should output the
|
||||
// logs in pretty format
|
||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||
log.Logger = log.Output(
|
||||
zerolog.ConsoleWriter{
|
||||
Out: os.Stderr,
|
||||
NoColor: false,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Register the server command.
|
||||
func Register(app *kingpin.Application) {
|
||||
c := new(command)
|
||||
|
||||
cmd := app.Command("server", "starts the server").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("envfile", "load the environment variable file").
|
||||
Default("").
|
||||
StringVar(&c.envfile)
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/bradrydzewski/my-app/internal/cron"
|
||||
"github.com/bradrydzewski/my-app/internal/server"
|
||||
)
|
||||
|
||||
// system stores high level system sub-routines.
|
||||
type system struct {
|
||||
server *server.Server
|
||||
nightly *cron.Nightly
|
||||
}
|
||||
|
||||
// newSystem returns a new system structure.
|
||||
func newSystem(server *server.Server, nightly *cron.Nightly) *system {
|
||||
return &system{
|
||||
server: server,
|
||||
nightly: nightly,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
//+build wireinject
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/bradrydzewski/my-app/internal/cron"
|
||||
"github.com/bradrydzewski/my-app/internal/router"
|
||||
"github.com/bradrydzewski/my-app/internal/server"
|
||||
"github.com/bradrydzewski/my-app/internal/store/database"
|
||||
"github.com/bradrydzewski/my-app/internal/store/memory"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
func initSystem(config *types.Config) (*system, error) {
|
||||
wire.Build(
|
||||
database.WireSet,
|
||||
memory.WireSet,
|
||||
router.WireSet,
|
||||
server.WireSet,
|
||||
cron.WireSet,
|
||||
newSystem,
|
||||
)
|
||||
return &system{}, nil
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
// Code generated by Wire. DO NOT EDIT.
|
||||
|
||||
//go:generate go run github.com/google/wire/cmd/wire
|
||||
//go:build !wireinject
|
||||
// +build !wireinject
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/bradrydzewski/my-app/internal/cron"
|
||||
"github.com/bradrydzewski/my-app/internal/router"
|
||||
"github.com/bradrydzewski/my-app/internal/server"
|
||||
"github.com/bradrydzewski/my-app/internal/store/database"
|
||||
"github.com/bradrydzewski/my-app/internal/store/memory"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
)
|
||||
|
||||
// Injectors from wire.go:
|
||||
|
||||
func initSystem(config *types.Config) (*system, error) {
|
||||
db, err := database.ProvideDatabase(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
executionStore := database.ProvideExecutionStore(db)
|
||||
pipelineStore := database.ProvidePipelineStore(db)
|
||||
userStore := database.ProvideUserStore(db)
|
||||
systemStore := memory.New(config)
|
||||
handler := router.New(executionStore, pipelineStore, userStore, systemStore)
|
||||
serverServer := server.ProvideServer(config, handler)
|
||||
nightly := cron.NewNightly()
|
||||
serverSystem := newSystem(serverServer, nightly)
|
||||
return serverSystem, nil
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/openapi"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type swaggerCommand struct {
|
||||
path string
|
||||
}
|
||||
|
||||
func (c *swaggerCommand) run(*kingpin.ParseContext) error {
|
||||
spec := openapi.Generate()
|
||||
data, _ := spec.MarshalYAML()
|
||||
if c.path == "" {
|
||||
os.Stdout.Write(data)
|
||||
return nil
|
||||
}
|
||||
return ioutil.WriteFile(c.path, data, 0600)
|
||||
}
|
||||
|
||||
// helper function to register the swagger command.
|
||||
func registerSwagger(app *kingpin.Application) {
|
||||
c := new(swaggerCommand)
|
||||
|
||||
cmd := app.Command("swagger", "generate swagger file").
|
||||
Hidden().
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("path", "path to save swagger file").
|
||||
StringVar(&c.path)
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package token
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
json bool
|
||||
}
|
||||
|
||||
func (c *command) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
token, err := client.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(token)
|
||||
}
|
||||
println(token.Value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Register the command.
|
||||
func Register(app *kingpin.Application) {
|
||||
c := new(command)
|
||||
|
||||
cmd := app.Command("token", "generate a personal token").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
|
||||
"github.com/drone/funcmap"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
const userTmpl = `
|
||||
email: {{ .Email }}
|
||||
admin: {{ .Admin }}
|
||||
`
|
||||
|
||||
type command struct {
|
||||
tmpl string
|
||||
json bool
|
||||
}
|
||||
|
||||
func (c *command) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := client.Self()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(user)
|
||||
}
|
||||
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, user)
|
||||
}
|
||||
|
||||
// Register the command.
|
||||
func Register(app *kingpin.Application) {
|
||||
c := new(command)
|
||||
|
||||
cmd := app.Command("account", "display authenticated user").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
cmd.Flag("format", "format the output using a Go template").
|
||||
Default(userTmpl).
|
||||
Hidden().
|
||||
StringVar(&c.tmpl)
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
|
||||
"github.com/drone/funcmap"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type createCommand struct {
|
||||
email string
|
||||
admin bool
|
||||
tmpl string
|
||||
json bool
|
||||
}
|
||||
|
||||
func (c *createCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
in := &types.User{
|
||||
Admin: c.admin,
|
||||
Email: c.email,
|
||||
Password: util.Password(),
|
||||
}
|
||||
user, err := client.UserCreate(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(user)
|
||||
}
|
||||
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, user)
|
||||
}
|
||||
|
||||
// helper function registers the user create command
|
||||
func registerCreate(app *kingpin.CmdClause) {
|
||||
c := new(createCommand)
|
||||
|
||||
cmd := app.Command("create", "create a user").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("email", "user email").
|
||||
Required().
|
||||
StringVar(&c.email)
|
||||
|
||||
cmd.Arg("admin", "user is admin").
|
||||
BoolVar(&c.admin)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
cmd.Flag("format", "format the output using a Go template").
|
||||
Default(userTmpl).
|
||||
Hidden().
|
||||
StringVar(&c.tmpl)
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type deleteCommand struct {
|
||||
email string
|
||||
}
|
||||
|
||||
func (c *deleteCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return client.UserDelete(c.email)
|
||||
}
|
||||
|
||||
// helper function registers the user delete command
|
||||
func registerDelete(app *kingpin.CmdClause) {
|
||||
c := new(deleteCommand)
|
||||
|
||||
cmd := app.Command("delete", "delete a user").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("id or email", "user id or email").
|
||||
Required().
|
||||
StringVar(&c.email)
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
|
||||
"github.com/drone/funcmap"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type findCommand struct {
|
||||
email string
|
||||
tmpl string
|
||||
json bool
|
||||
}
|
||||
|
||||
func (c *findCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := client.User(c.email)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(user)
|
||||
}
|
||||
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl + "\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, user)
|
||||
}
|
||||
|
||||
// helper function registers the user find command
|
||||
func registerFind(app *kingpin.CmdClause) {
|
||||
c := new(findCommand)
|
||||
|
||||
cmd := app.Command("find", "display user details").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("id or email", "user id or email").
|
||||
Required().
|
||||
StringVar(&c.email)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
cmd.Flag("format", "format the output using a Go template").
|
||||
Default(userTmpl).
|
||||
Hidden().
|
||||
StringVar(&c.tmpl)
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/drone/funcmap"
|
||||
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
const userTmpl = `
|
||||
id: {{ .ID }}
|
||||
email: {{ .Email }}
|
||||
admin: {{ .Admin }}
|
||||
`
|
||||
|
||||
type listCommand struct {
|
||||
tmpl string
|
||||
page int
|
||||
size int
|
||||
json bool
|
||||
}
|
||||
|
||||
func (c *listCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
list, err := client.UserList(types.Params{
|
||||
Size: c.size,
|
||||
Page: c.page,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl + "\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(list)
|
||||
}
|
||||
for _, item := range list {
|
||||
tmpl.Execute(os.Stdout, item)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// helper function registers the user list command
|
||||
func registerList(app *kingpin.CmdClause) {
|
||||
c := new(listCommand)
|
||||
|
||||
cmd := app.Command("ls", "display a list of users").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Flag("page", "page number").
|
||||
IntVar(&c.page)
|
||||
|
||||
cmd.Flag("per-page", "page size").
|
||||
IntVar(&c.size)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
cmd.Flag("format", "format the output using a Go template").
|
||||
Default(userTmpl).
|
||||
Hidden().
|
||||
StringVar(&c.tmpl)
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/bradrydzewski/my-app/cli/util"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
|
||||
"github.com/dchest/uniuri"
|
||||
"github.com/drone/funcmap"
|
||||
"github.com/gotidy/ptr"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
type updateCommand struct {
|
||||
id string
|
||||
email string
|
||||
admin bool
|
||||
demote bool
|
||||
passgen bool
|
||||
pass string
|
||||
tmpl string
|
||||
json bool
|
||||
}
|
||||
|
||||
func (c *updateCommand) run(*kingpin.ParseContext) error {
|
||||
client, err := util.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
in := new(types.UserInput)
|
||||
if v := c.email; v != "" {
|
||||
in.Username = ptr.String(v)
|
||||
}
|
||||
if v := c.pass; v != "" {
|
||||
in.Password = ptr.String(v)
|
||||
}
|
||||
if v := c.admin; v {
|
||||
in.Admin = ptr.Bool(v)
|
||||
}
|
||||
if v := c.demote; v {
|
||||
in.Admin = ptr.Bool(false)
|
||||
}
|
||||
if c.passgen {
|
||||
v := uniuri.NewLen(8)
|
||||
in.Password = ptr.String(v)
|
||||
fmt.Printf("generated temporary password: %s\n", v)
|
||||
}
|
||||
|
||||
user, err := client.UserUpdate(c.id, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.json {
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetIndent("", " ")
|
||||
return enc.Encode(user)
|
||||
}
|
||||
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, user)
|
||||
}
|
||||
|
||||
// helper function registers the user update command
|
||||
func registerUpdate(app *kingpin.CmdClause) {
|
||||
c := new(updateCommand)
|
||||
|
||||
cmd := app.Command("update", "update a user").
|
||||
Action(c.run)
|
||||
|
||||
cmd.Arg("id or email", "user id or email").
|
||||
Required().
|
||||
StringVar(&c.id)
|
||||
|
||||
cmd.Flag("email", "update user email").
|
||||
StringVar(&c.email)
|
||||
|
||||
cmd.Flag("password", "update user password").
|
||||
StringVar(&c.pass)
|
||||
|
||||
cmd.Flag("password-gen", "generate and update user password").
|
||||
BoolVar(&c.passgen)
|
||||
|
||||
cmd.Flag("promote", "promote user to admin").
|
||||
BoolVar(&c.admin)
|
||||
|
||||
cmd.Flag("demote", "demote user from admin").
|
||||
BoolVar(&c.demote)
|
||||
|
||||
cmd.Flag("json", "json encode the output").
|
||||
BoolVar(&c.json)
|
||||
|
||||
cmd.Flag("format", "format the output using a Go template").
|
||||
Default(userTmpl).
|
||||
Hidden().
|
||||
StringVar(&c.tmpl)
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
||||
|
||||
import "gopkg.in/alecthomas/kingpin.v2"
|
||||
|
||||
// Register the command.
|
||||
func Register(app *kingpin.Application) {
|
||||
cmd := app.Command("user", "manage users")
|
||||
registerFind(cmd)
|
||||
registerList(cmd)
|
||||
registerCreate(cmd)
|
||||
registerUpdate(cmd)
|
||||
registerDelete(cmd)
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/bradrydzewski/my-app/client"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
// Client returns a client that is configured from file.
|
||||
func Client() (*client.HTTPClient, error) {
|
||||
path, err := Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
token := new(types.Token)
|
||||
if err := json.Unmarshal(data, token); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if time.Now().Unix() > token.Expires.Unix() {
|
||||
return nil, errors.New("token is expired, please login")
|
||||
}
|
||||
client := client.NewToken(token.Address, token.Value)
|
||||
if os.Getenv("DEBUG") == "true" {
|
||||
client.SetDebug(true)
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// Config returns the configuration file path.
|
||||
func Config() (string, error) {
|
||||
return xdg.ConfigFile(
|
||||
filepath.Join("app", "config.json"),
|
||||
)
|
||||
}
|
||||
|
||||
// Credentials returns the username and password from stdin.
|
||||
func Credentials() (string, string) {
|
||||
return Username(), Password()
|
||||
}
|
||||
|
||||
// Username returns the username from stdin.
|
||||
func Username() string {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
fmt.Print("Enter Username: ")
|
||||
username, _ := reader.ReadString('\n')
|
||||
|
||||
return strings.TrimSpace(username)
|
||||
}
|
||||
|
||||
// Password returns the password from stdin.
|
||||
func Password() string {
|
||||
fmt.Print("Enter Password: ")
|
||||
passwordb, _ := terminal.ReadPassword(int(syscall.Stdin))
|
||||
password := string(passwordb)
|
||||
|
||||
return strings.TrimSpace(password)
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package util
|
|
@ -0,0 +1,336 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/bradrydzewski/my-app/version"
|
||||
)
|
||||
|
||||
// ensure HTTPClient implements Client interface.
|
||||
var _ Client = (*HTTPClient)(nil)
|
||||
|
||||
// HTTPClient provides an HTTP client for interacting
|
||||
// with the remote API.
|
||||
type HTTPClient struct {
|
||||
client *http.Client
|
||||
base string
|
||||
token string
|
||||
debug bool
|
||||
}
|
||||
|
||||
// New returns a client at the specified url.
|
||||
func New(uri string) *HTTPClient {
|
||||
return NewToken(uri, "")
|
||||
}
|
||||
|
||||
// NewToken returns a client at the specified url that
|
||||
// authenticates all outbound requests with the given token.
|
||||
func NewToken(uri, token string) *HTTPClient {
|
||||
return &HTTPClient{http.DefaultClient, uri, token, false}
|
||||
}
|
||||
|
||||
// SetClient sets the default http client. This can be
|
||||
// used in conjunction with golang.org/x/oauth2 to
|
||||
// authenticate requests to the server.
|
||||
func (c *HTTPClient) SetClient(client *http.Client) {
|
||||
c.client = client
|
||||
}
|
||||
|
||||
// SetDebug sets the debug flag. When the debug flag is
|
||||
// true, the http.Resposne body to stdout which can be
|
||||
// helpful when debugging.
|
||||
func (c *HTTPClient) SetDebug(debug bool) {
|
||||
c.debug = debug
|
||||
}
|
||||
|
||||
// Login authenticates the user and returns a JWT token.
|
||||
func (c *HTTPClient) Login(username, password string) (*types.Token, error) {
|
||||
form := &url.Values{}
|
||||
form.Add("username", username)
|
||||
form.Add("password", password)
|
||||
out := new(types.UserToken)
|
||||
uri := fmt.Sprintf("%s/api/v1/login?return_user=true", c.base)
|
||||
err := c.post(uri, form, out)
|
||||
return out.Token, err
|
||||
}
|
||||
|
||||
// Register registers a new user and returns a JWT token.
|
||||
func (c *HTTPClient) Register(username, password string) (*types.Token, error) {
|
||||
form := &url.Values{}
|
||||
form.Add("username", username)
|
||||
form.Add("password", password)
|
||||
out := new(types.UserToken)
|
||||
uri := fmt.Sprintf("%s/api/v1/register?return_user=true", c.base)
|
||||
err := c.post(uri, form, out)
|
||||
return out.Token, err
|
||||
}
|
||||
|
||||
//
|
||||
// User Endpoints
|
||||
//
|
||||
|
||||
// Self returns the currently authenticated user.
|
||||
func (c *HTTPClient) Self() (*types.User, error) {
|
||||
out := new(types.User)
|
||||
uri := fmt.Sprintf("%s/api/v1/user", c.base)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// Token returns an oauth2 bearer token for the currently
|
||||
// authenticated user.
|
||||
func (c *HTTPClient) Token() (*types.Token, error) {
|
||||
out := new(types.Token)
|
||||
uri := fmt.Sprintf("%s/api/v1/user/token", c.base)
|
||||
err := c.post(uri, nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// User returns a user by ID or email.
|
||||
func (c *HTTPClient) User(key string) (*types.User, error) {
|
||||
out := new(types.User)
|
||||
uri := fmt.Sprintf("%s/api/v1/users/%s", c.base, key)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// UserList returns a list of all registered users.
|
||||
func (c *HTTPClient) UserList(params types.Params) ([]*types.User, error) {
|
||||
out := []*types.User{}
|
||||
uri := fmt.Sprintf("%s/api/v1/users?page=%d&per_page=%d", c.base, params.Page, params.Size)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// UserCreate creates a new user account.
|
||||
func (c *HTTPClient) UserCreate(user *types.User) (*types.User, error) {
|
||||
out := new(types.User)
|
||||
uri := fmt.Sprintf("%s/api/v1/users", c.base)
|
||||
err := c.post(uri, user, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// UserUpdate updates a user account by ID or email.
|
||||
func (c *HTTPClient) UserUpdate(key string, user *types.UserInput) (*types.User, error) {
|
||||
out := new(types.User)
|
||||
uri := fmt.Sprintf("%s/api/v1/users/%s", c.base, key)
|
||||
err := c.patch(uri, user, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// UserDelete deletes a user account by ID or email.
|
||||
func (c *HTTPClient) UserDelete(key string) error {
|
||||
uri := fmt.Sprintf("%s/api/v1/users/%s", c.base, key)
|
||||
err := c.delete(uri)
|
||||
return err
|
||||
}
|
||||
|
||||
//
|
||||
// Pipeline endpoints
|
||||
//
|
||||
|
||||
//
|
||||
// Pipeline endpoints
|
||||
//
|
||||
|
||||
// Pipeline returns a pipeline by slug.
|
||||
func (c *HTTPClient) Pipeline(slug string) (*types.Pipeline, error) {
|
||||
out := new(types.Pipeline)
|
||||
uri := fmt.Sprintf("%s/api/v1/pipelines/%s", c.base, slug)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineList returns a list of all pipelines.
|
||||
func (c *HTTPClient) PipelineList(params types.Params) ([]*types.Pipeline, error) {
|
||||
out := []*types.Pipeline{}
|
||||
uri := fmt.Sprintf("%s/api/v1/pipelines?page=%dper_page=%d", c.base, params.Page, params.Size)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineCreate creates a new pipeline.
|
||||
func (c *HTTPClient) PipelineCreate(pipeline *types.Pipeline) (*types.Pipeline, error) {
|
||||
out := new(types.Pipeline)
|
||||
uri := fmt.Sprintf("%s/api/v1/pipelines", c.base)
|
||||
err := c.post(uri, pipeline, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineUpdate updates a pipeline.
|
||||
func (c *HTTPClient) PipelineUpdate(key string, user *types.PipelineInput) (*types.Pipeline, error) {
|
||||
out := new(types.Pipeline)
|
||||
uri := fmt.Sprintf("%s/api/v1/pipelines/%s", c.base, key)
|
||||
err := c.patch(uri, user, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineDelete deletes a pipeline.
|
||||
func (c *HTTPClient) PipelineDelete(key string) error {
|
||||
uri := fmt.Sprintf("%s/api/v1/pipelines/%s", c.base, key)
|
||||
err := c.delete(uri)
|
||||
return err
|
||||
}
|
||||
|
||||
//
|
||||
// Execution endpoints
|
||||
//
|
||||
|
||||
// Execution returns a execution by ID.
|
||||
func (c *HTTPClient) Execution(pipeline, slug string) (*types.Execution, error) {
|
||||
out := new(types.Execution)
|
||||
uri := fmt.Sprintf("%s/api/v1/pipelines/%s/executions/%s", c.base, pipeline, slug)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// ExecutionList returns a list of all executions by pipeline id.
|
||||
func (c *HTTPClient) ExecutionList(pipeline string, params types.Params) ([]*types.Execution, error) {
|
||||
out := []*types.Execution{}
|
||||
uri := fmt.Sprintf("%s/api/v1/pipelines/%s/executions?page=%dper_page=%d", c.base, pipeline, params.Page, params.Size)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// ExecutionCreate creates a new execution.
|
||||
func (c *HTTPClient) ExecutionCreate(pipeline string, execution *types.Execution) (*types.Execution, error) {
|
||||
out := new(types.Execution)
|
||||
uri := fmt.Sprintf("%s/api/v1/pipelines/%s/executions", c.base, pipeline)
|
||||
err := c.post(uri, execution, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// ExecutionUpdate updates a execution.
|
||||
func (c *HTTPClient) ExecutionUpdate(pipeline, slug string, execution *types.ExecutionInput) (*types.Execution, error) {
|
||||
out := new(types.Execution)
|
||||
uri := fmt.Sprintf("%s/api/v1/pipelines/%s/executions/%s", c.base, pipeline, slug)
|
||||
err := c.patch(uri, execution, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// ExecutionDelete deletes a execution.
|
||||
func (c *HTTPClient) ExecutionDelete(pipeline, slug string) error {
|
||||
uri := fmt.Sprintf("%s/api/v1/pipelines/%s/executions/%s", c.base, pipeline, slug)
|
||||
err := c.delete(uri)
|
||||
return err
|
||||
}
|
||||
|
||||
//
|
||||
// http request helper functions
|
||||
//
|
||||
|
||||
// helper function for making an http GET request.
|
||||
func (c *HTTPClient) get(rawurl string, out interface{}) error {
|
||||
return c.do(rawurl, "GET", nil, out)
|
||||
}
|
||||
|
||||
// helper function for making an http POST request.
|
||||
func (c *HTTPClient) post(rawurl string, in, out interface{}) error {
|
||||
return c.do(rawurl, "POST", in, out)
|
||||
}
|
||||
|
||||
// helper function for making an http PUT request.
|
||||
func (c *HTTPClient) put(rawurl string, in, out interface{}) error {
|
||||
return c.do(rawurl, "PUT", in, out)
|
||||
}
|
||||
|
||||
// helper function for making an http PATCH request.
|
||||
func (c *HTTPClient) patch(rawurl string, in, out interface{}) error {
|
||||
return c.do(rawurl, "PATCH", in, out)
|
||||
}
|
||||
|
||||
// helper function for making an http DELETE request.
|
||||
func (c *HTTPClient) delete(rawurl string) error {
|
||||
return c.do(rawurl, "DELETE", nil, nil)
|
||||
}
|
||||
|
||||
// helper function to make an http request
|
||||
func (c *HTTPClient) do(rawurl, method string, in, out interface{}) error {
|
||||
// executes the http request and returns the body as
|
||||
// and io.ReadCloser
|
||||
body, err := c.stream(rawurl, method, in, out)
|
||||
if body != nil {
|
||||
defer body.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if a json response is expected, parse and return
|
||||
// the json response.
|
||||
if out != nil {
|
||||
return json.NewDecoder(body).Decode(out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// helper function to stream an http request
|
||||
func (c *HTTPClient) stream(rawurl, method string, in, out interface{}) (io.ReadCloser, error) {
|
||||
uri, err := url.Parse(rawurl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if we are posting or putting data, we need to
|
||||
// write it to the body of the request.
|
||||
var buf io.ReadWriter
|
||||
if in != nil {
|
||||
buf = new(bytes.Buffer)
|
||||
// if posting form data, encode the form values.
|
||||
if form, ok := in.(*url.Values); ok {
|
||||
io.WriteString(buf, form.Encode())
|
||||
} else {
|
||||
if err := json.NewEncoder(buf).Encode(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// creates a new http request.
|
||||
req, err := http.NewRequest(method, uri.String(), buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if in != nil {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
if c.token != "" {
|
||||
req.Header.Set("Authorization", "Bearer "+c.token)
|
||||
}
|
||||
if _, ok := in.(*url.Values); ok {
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
}
|
||||
|
||||
// include the client version information in the
|
||||
// http accept header for debugging purposes.
|
||||
req.Header.Set("Accept", "application/json;version="+version.Version.String())
|
||||
|
||||
// send the http request.
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.debug {
|
||||
dump, _ := httputil.DumpResponse(resp, true)
|
||||
fmt.Println(method, rawurl)
|
||||
fmt.Println(string(dump))
|
||||
}
|
||||
if resp.StatusCode > 299 {
|
||||
defer resp.Body.Close()
|
||||
err := new(remoteError)
|
||||
json.NewDecoder(resp.Body).Decode(err)
|
||||
return nil, err
|
||||
}
|
||||
return resp.Body, nil
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package client
|
||||
|
||||
import "github.com/bradrydzewski/my-app/types"
|
||||
|
||||
// Client to access the remote APIs.
|
||||
type Client interface {
|
||||
// Login authenticates the user and returns a JWT token.
|
||||
Login(username, password string) (*types.Token, error)
|
||||
|
||||
// Register registers a new user and returns a JWT token.
|
||||
Register(username, password string) (*types.Token, error)
|
||||
|
||||
// Self returns the currently authenticated user.
|
||||
Self() (*types.User, error)
|
||||
|
||||
// Token returns an oauth2 bearer token for the currently
|
||||
// authenticated user.
|
||||
Token() (*types.Token, error)
|
||||
|
||||
// User returns a user by ID or email.
|
||||
User(key string) (*types.User, error)
|
||||
|
||||
// UserList returns a list of all registered users.
|
||||
UserList(params types.Params) ([]*types.User, error)
|
||||
|
||||
// UserCreate creates a new user account.
|
||||
UserCreate(user *types.User) (*types.User, error)
|
||||
|
||||
// UserUpdate updates a user account by ID or email.
|
||||
UserUpdate(key string, input *types.UserInput) (*types.User, error)
|
||||
|
||||
// UserDelete deletes a user account by ID or email.
|
||||
UserDelete(key string) error
|
||||
|
||||
// Pipeline returns a pipeline by slug.
|
||||
Pipeline(slug string) (*types.Pipeline, error)
|
||||
|
||||
// PipelineList returns a list of all pipelines.
|
||||
PipelineList(params types.Params) ([]*types.Pipeline, error)
|
||||
|
||||
// PipelineCreate creates a new pipeline.
|
||||
PipelineCreate(user *types.Pipeline) (*types.Pipeline, error)
|
||||
|
||||
// PipelineUpdate updates a pipeline.
|
||||
PipelineUpdate(slug string, input *types.PipelineInput) (*types.Pipeline, error)
|
||||
|
||||
// PipelineDelete deletes a pipeline.
|
||||
PipelineDelete(slug string) error
|
||||
|
||||
// Execution returns a execution by pipeline and slug.
|
||||
Execution(pipeline, slug string) (*types.Execution, error)
|
||||
|
||||
// ExecutionList returns a list of all executions by pipeline slug.
|
||||
ExecutionList(pipeline string, params types.Params) ([]*types.Execution, error)
|
||||
|
||||
// ExecutionCreate creates a new execution.
|
||||
ExecutionCreate(pipeline string, execution *types.Execution) (*types.Execution, error)
|
||||
|
||||
// ExecutionUpdate updates a execution.
|
||||
ExecutionUpdate(pipeline, slug string, input *types.ExecutionInput) (*types.Execution, error)
|
||||
|
||||
// ExecutionDelete deletes a execution.
|
||||
ExecutionDelete(pipeline, slug string) error
|
||||
}
|
||||
|
||||
// remoteError store the error payload returned
|
||||
// fro the remote API.
|
||||
type remoteError struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Error returns the error message.
|
||||
func (e *remoteError) Error() string {
|
||||
return e.Message
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
The contrib directory contains scripts, images, and other helpful things which are not part of the core docker distribution. Please note that they could be out of date, since they do not receive the same attention as the rest of the repository.
|
|
@ -0,0 +1,58 @@
|
|||
apiVersion: v1
|
||||
items:
|
||||
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: my-app
|
||||
name: my-app
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: my-app
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
containers:
|
||||
- image: gcr.io/XXXXX-XXXXXXX/my-app
|
||||
imagePullPolicy: Never
|
||||
name: my-app
|
||||
|
||||
- apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: my-app
|
||||
name: my-app
|
||||
spec:
|
||||
ports:
|
||||
- port: 3000
|
||||
protocol: TCP
|
||||
targetPort: 3000
|
||||
selector:
|
||||
app: my-app
|
||||
|
||||
- apiVersion: networking.k8s.io/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: my-app
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /$1
|
||||
kubernetes.io/ingress.class: "nginx"
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /pm/(.*)
|
||||
backend:
|
||||
serviceName: my-app
|
||||
servicePort: 3000
|
||||
|
||||
kind: List
|
||||
metadata:
|
||||
resourceVersion: ""
|
||||
selfLink: ""
|
|
@ -0,0 +1,12 @@
|
|||
FROM alpine:3 as alpine
|
||||
RUN apk add -U --no-cache ca-certificates
|
||||
|
||||
FROM us.gcr.io/platform-205701/busybox:safe
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
|
||||
COPY --from=alpine /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
|
||||
ENV GODEBUG netdns=go
|
||||
ADD release/linux/amd64/my-app /bin/
|
||||
ENTRYPOINT ["/bin/my-app", "server"]
|
|
@ -0,0 +1,12 @@
|
|||
FROM alpine:3 as alpine
|
||||
RUN apk add -U --no-cache ca-certificates
|
||||
|
||||
FROM alpine:3
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
|
||||
COPY --from=alpine /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
|
||||
ENV GODEBUG netdns=go
|
||||
ADD release/linux/amd64/my-app /bin/
|
||||
ENTRYPOINT ["/bin/my-app", "server"]
|
|
@ -0,0 +1,51 @@
|
|||
module github.com/bradrydzewski/my-app
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/Masterminds/squirrel v1.5.1
|
||||
github.com/adrg/xdg v0.3.2
|
||||
github.com/coreos/go-semver v0.3.0
|
||||
github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/drone/funcmap v0.0.0-20190918184546-d4ef6e88376d
|
||||
github.com/go-chi/chi v1.5.4
|
||||
github.com/go-chi/cors v1.2.0
|
||||
github.com/golang/mock v1.5.0
|
||||
github.com/google/go-cmp v0.5.5
|
||||
github.com/google/wire v0.5.0
|
||||
github.com/gosimple/slug v1.11.2
|
||||
github.com/gotidy/ptr v1.3.0
|
||||
github.com/jmoiron/sqlx v1.3.1
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/kelseyhightower/envconfig v1.4.0
|
||||
github.com/lib/pq v1.10.0
|
||||
github.com/maragudk/migrate v0.4.1
|
||||
github.com/mattn/go-isatty v0.0.12
|
||||
github.com/mattn/go-sqlite3 v1.14.10-0.20211026011849-85436841b33e
|
||||
github.com/rs/zerolog v1.26.0
|
||||
github.com/swaggest/openapi-go v0.2.13
|
||||
github.com/swaggest/swgui v1.4.2
|
||||
github.com/unrolled/secure v1.0.8
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 // indirect
|
||||
github.com/gosimple/unidecode v1.0.1 // indirect
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/rs/xid v1.3.0 // indirect
|
||||
github.com/swaggest/jsonschema-go v0.3.24 // indirect
|
||||
github.com/swaggest/refl v1.0.1 // indirect
|
||||
github.com/vearutop/statigz v1.1.5 // indirect
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
|
@ -0,0 +1,632 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/Masterminds/squirrel v1.5.1 h1:kWAKlLLJFxZG7N2E0mBMNWVp5AuUX+JUrnhFN74Eg+w=
|
||||
github.com/Masterminds/squirrel v1.5.1/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/adrg/xdg v0.3.2 h1:GUSGQ5pHdev83AYhDSS1A/CX+0JIsxbiWtow2DSA+RU=
|
||||
github.com/adrg/xdg v0.3.2/go.mod h1:7I2hH/IT30IsupOpKZ5ue7/qNi3CoKzD6tL3HwpaRMQ=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 h1:AUNCr9CiJuwrRYS3XieqF+Z9B9gNxo/eANAJCF2eiN4=
|
||||
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||
github.com/andybalholm/brotli v1.0.3 h1:fpcw+r1N1h0Poc1F/pHbW40cUm/lMEQslZtCkBQ0UnM=
|
||||
github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
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/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bool64/dev v0.1.17/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zRWU=
|
||||
github.com/bool64/dev v0.1.25/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zRWU=
|
||||
github.com/bool64/dev v0.1.41/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zRWU=
|
||||
github.com/bool64/dev v0.1.42 h1:Ps0IvNNf/v1MlIXt8Q5YKcKjYsIVLY/fb/5BmA7gepg=
|
||||
github.com/bool64/dev v0.1.42/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zRWU=
|
||||
github.com/bool64/shared v0.1.3 h1:gj7XZPYa1flQsCg3q9AIju+W2A1jaexK0fdFu2XtaG0=
|
||||
github.com/bool64/shared v0.1.3/go.mod h1:RF1p1Oi29ofgOvinBpetbF5mceOUP3kpMkvLbWOmtm0=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
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/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
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/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5 h1:RAV05c0xOkJ3dZGS0JFybxFKZ2WMLabgx3uXnd7rpGs=
|
||||
github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/drone/funcmap v0.0.0-20190918184546-d4ef6e88376d h1:/IO7UVVu191Jc0DajV4cDVoO+91cuppvgxg2MZl+AXI=
|
||||
github.com/drone/funcmap v0.0.0-20190918184546-d4ef6e88376d/go.mod h1:Hph0/pT6ZxbujnE1Z6/08p5I0XXuOsppqF6NQlGOK0E=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||
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/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||
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/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs=
|
||||
github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg=
|
||||
github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE=
|
||||
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
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.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.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/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=
|
||||
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.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
|
||||
github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gosimple/slug v1.11.2 h1:MxFR0TmQ/qz0KvIrBbf4phu+G0RBgpwxOn6jPKFKFOw=
|
||||
github.com/gosimple/slug v1.11.2/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
|
||||
github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
|
||||
github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
|
||||
github.com/gotidy/ptr v1.3.0 h1:5wdrH1G8X4txy6fbWWRznr7k974wMWtePWP3p6s1API=
|
||||
github.com/gotidy/ptr v1.3.0/go.mod h1:vpltyHhOZE+NGXUiwpVl3wV9AGEBlxhdnaimPDxRLxg=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA=
|
||||
github.com/iancoleman/orderedmap v0.2.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
|
||||
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.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk=
|
||||
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
|
||||
github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
|
||||
github.com/jackc/pgconn v1.8.1 h1:ySBX7Q87vOMqKU2bbmKbUvtYhauDFclYbNDYIE1/h6s=
|
||||
github.com/jackc/pgconn v1.8.1/go.mod h1:JV6m6b6jhjdmzchES0drzCcYcAHS1OPD5xu3OZ/lE2g=
|
||||
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/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 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
|
||||
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.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.1.0 h1:h2yg3kjIyAGSZKDijYn1/gXHlYLCwl9ZjEh2PU0yVxE=
|
||||
github.com/jackc/pgproto3/v2 v2.1.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
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.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0=
|
||||
github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po=
|
||||
github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
|
||||
github.com/jackc/pgtype v1.7.0 h1:6f4kVsW01QftE38ufBYxKciO6gyioXSC0ABIRLcZrGs=
|
||||
github.com/jackc/pgtype v1.7.0/go.mod h1:ZnHF+rMePVqDKaOfJVI4Q8IVvAQMryDlDkZnKOI75BE=
|
||||
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.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA=
|
||||
github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o=
|
||||
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
|
||||
github.com/jackc/pgx/v4 v4.11.0 h1:J86tSWd3Y7nKjwT/43xZBvpi04keQWx8gNC2YkdJhZI=
|
||||
github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc=
|
||||
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.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmoiron/sqlx v1.3.1 h1:aLN7YINNZ7cYOPK3QC83dbM6KT0NMqVMw961TqrejlE=
|
||||
github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
|
||||
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
||||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||
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/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
||||
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.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
|
||||
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/maragudk/migrate v0.4.1 h1:oAY8bCyaHIreLj3ar9b6cf7PSqOZsCkKXHU8Yn1bkb4=
|
||||
github.com/maragudk/migrate v0.4.1/go.mod h1:vhmL4s+Xz75KU6DPZWRfqb45YyqjYQfcXliA1DsYzvY=
|
||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
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.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.10-0.20211026011849-85436841b33e h1:aF8T4W7RUsJjsbSVHyxjqt7aWrGpkCN8m6m8D38SU8Q=
|
||||
github.com/mattn/go-sqlite3 v1.14.10-0.20211026011849-85436841b33e/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
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/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
||||
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
|
||||
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
|
||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.15.2/go.mod h1:Dd6YFfwBW84ETqqtL0CPyPXillHgY6XhQH3uuCCTr/o=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
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.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
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/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4=
|
||||
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
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/rs/zerolog v1.26.0 h1:ORM4ibhEZeTeQlCojCK2kPz1ogAY4bGs4tD+SaAdGaE=
|
||||
github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo=
|
||||
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/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/httpgzip v0.0.0-20190720172056-320755c1c1b0/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
||||
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/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
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/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||
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/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
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 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/swaggest/assertjson v1.6.8 h1:1O/9UI5M+2OJI7BeEWKGj0wTvpRXZt5FkOJ4nRkY4rA=
|
||||
github.com/swaggest/assertjson v1.6.8/go.mod h1:Euf0upn9Vlaf1/llYHTs+Kx5K3vVbpMbsZhth7zlN7M=
|
||||
github.com/swaggest/jsonschema-go v0.3.24 h1:vVtFhWQWT9sgsvgMdh0n3O1F0+TnhOWz4+lbz5p5ChY=
|
||||
github.com/swaggest/jsonschema-go v0.3.24/go.mod h1:B2ZSqrrlkj21zhywlkh8VnKBmuqUwDv3dLQoPjgHk7M=
|
||||
github.com/swaggest/openapi-go v0.2.13 h1:2u3Im5S6BX6GFqux2I035FSXWn6jgWsXY8SNhc0jHE4=
|
||||
github.com/swaggest/openapi-go v0.2.13/go.mod h1:Y3+sBULNSPwoUbExcY+0AwjWX0oxFspaBGha7tx/DWk=
|
||||
github.com/swaggest/refl v1.0.0/go.mod h1:acYd5x8NNxivp+ZHdRZKJYz66n/qjo3Q9Sa/jAivljQ=
|
||||
github.com/swaggest/refl v1.0.1 h1:YQHb7Ic6EMpdUpxQmTWmf/O4IWN6iIErxJNWA7LwyyM=
|
||||
github.com/swaggest/refl v1.0.1/go.mod h1:dnx+n9YaI0o+FH+OR2tJZWLABBVIPs9qc4VY9UdrhLE=
|
||||
github.com/swaggest/swgui v1.4.2 h1:6AT8ICO0+t6WpbIFsACf5vBmviVX0sqspNbZLoe6vgw=
|
||||
github.com/swaggest/swgui v1.4.2/go.mod h1:xWDsT2h8obEoGHzX/a6FRClUOS8NvkICyInhi7s3fN8=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/unrolled/secure v1.0.8 h1:JaMvKbe4CRt8oyxVXn+xY+6jlqd7pyJNSVkmsBxxQsM=
|
||||
github.com/unrolled/secure v1.0.8/go.mod h1:fO+mEan+FLB0CdEnHf6Q4ZZVNqG+5fuLFnP8p0BXDPI=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=
|
||||
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
||||
github.com/vearutop/statigz v1.1.5 h1:qWvRgXFsseWVTFCkIvwHQPpaLNf9WI0+dDJE7I9432o=
|
||||
github.com/vearutop/statigz v1.1.5/go.mod h1:czAv7iXgPv/s+xsgXpVEhhD0NSOQ4wZPgmM/n7LANDI=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yosuke-furukawa/json5 v0.1.2-0.20201207051438-cf7bb3f354ff/go.mod h1:sw49aWDqNdRJ6DYUtIQiaA3xyj2IL9tjeNYmX2ixwcU=
|
||||
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
|
||||
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
|
||||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
|
||||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
|
||||
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
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=
|
||||
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-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-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI=
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/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/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
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-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211105192438-b53810dc28af/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
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=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-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-20181122145206-62eef0e2fa9b/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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/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-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-20191220142924-d4481acd189f/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-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/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/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
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.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.26.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.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
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/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.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package api
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package account
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/internal/token"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
|
||||
"github.com/rs/zerolog/hlog"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// HandleLogin returns an http.HandlerFunc that authenticates
|
||||
// the user and returns an authentication token on success.
|
||||
func HandleLogin(users store.UserStore, system store.SystemStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := hlog.FromRequest(r)
|
||||
|
||||
username := r.FormValue("username")
|
||||
password := r.FormValue("password")
|
||||
user, err := users.FindEmail(ctx, username)
|
||||
if err != nil {
|
||||
render.NotFoundf(w, "Invalid email or password")
|
||||
log.Debug().Err(err).
|
||||
Str("user", username).
|
||||
Msg("cannot find user")
|
||||
return
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword(
|
||||
[]byte(user.Password),
|
||||
[]byte(password),
|
||||
)
|
||||
if err != nil {
|
||||
render.NotFoundf(w, "Invalid email or password")
|
||||
log.Debug().Err(err).
|
||||
Str("user", username).
|
||||
Msg("invalid password")
|
||||
return
|
||||
}
|
||||
|
||||
expires := time.Now().Add(system.Config(ctx).Token.Expire)
|
||||
token_, err := token.GenerateExp(user, expires.Unix(), user.Salt)
|
||||
if err != nil {
|
||||
render.InternalErrorf(w, "Failed to create session")
|
||||
log.Debug().Err(err).
|
||||
Str("user", username).
|
||||
Msg("failed to generate token")
|
||||
return
|
||||
}
|
||||
|
||||
// return the token if the with_user boolean
|
||||
// query parameter is set to true.
|
||||
if r.FormValue("return_user") == "true" {
|
||||
render.JSON(w, &types.UserToken{
|
||||
User: user,
|
||||
Token: &types.Token{
|
||||
Value: token_,
|
||||
Expires: expires.UTC(),
|
||||
},
|
||||
}, 200)
|
||||
} else {
|
||||
// else return the token only.
|
||||
render.JSON(w, &types.Token{Value: token_}, 200)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package account
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestLogin(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
func TestLogin_NotFound(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
func TestLogin_BcryptError(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
func TestLogin_TokenError(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package account
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/internal/token"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/bradrydzewski/my-app/types/check"
|
||||
|
||||
"github.com/dchest/uniuri"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// HandleRegister returns an http.HandlerFunc that processes an http.Request
|
||||
// to register the named user account with the system.
|
||||
func HandleRegister(users store.UserStore, system store.SystemStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := hlog.FromRequest(r)
|
||||
|
||||
username := r.FormValue("username")
|
||||
password := r.FormValue("password")
|
||||
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Debug().Err(err).
|
||||
Str("email", username).
|
||||
Msg("cannot hash password")
|
||||
return
|
||||
}
|
||||
|
||||
user := &types.User{
|
||||
Name: username,
|
||||
Email: username,
|
||||
Password: string(hash),
|
||||
Salt: uniuri.NewLen(uniuri.UUIDLen),
|
||||
Created: time.Now().UnixMilli(),
|
||||
Updated: time.Now().UnixMilli(),
|
||||
}
|
||||
|
||||
if ok, err := check.User(user); !ok {
|
||||
render.BadRequest(w, err)
|
||||
log.Debug().Err(err).
|
||||
Str("email", username).
|
||||
Msg("invalid user input")
|
||||
return
|
||||
}
|
||||
|
||||
if err := users.Create(ctx, user); err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Error().Err(err).
|
||||
Str("email", username).
|
||||
Msg("cannot create user")
|
||||
return
|
||||
}
|
||||
|
||||
// if the registered user is the first user of the system,
|
||||
// assume they are the system administrator and grant the
|
||||
// user system admin access.
|
||||
if user.ID == 1 {
|
||||
user.Admin = true
|
||||
if err := users.Update(ctx, user); err != nil {
|
||||
log.Error().Err(err).
|
||||
Str("email", username).
|
||||
Msg("cannot enable admin user")
|
||||
}
|
||||
}
|
||||
|
||||
expires := time.Now().Add(system.Config(ctx).Token.Expire)
|
||||
token_, err := token.GenerateExp(user, expires.Unix(), user.Salt)
|
||||
if err != nil {
|
||||
render.InternalErrorf(w, "Failed to create session")
|
||||
log.Error().Err(err).
|
||||
Str("email", username).
|
||||
Msg("failed to generate token")
|
||||
return
|
||||
}
|
||||
|
||||
// return the token if the with_user boolean
|
||||
// query parameter is set to true.
|
||||
if r.FormValue("return_user") == "true" {
|
||||
render.JSON(w, &types.UserToken{
|
||||
User: user,
|
||||
Token: &types.Token{
|
||||
Value: token_,
|
||||
Expires: expires.UTC(),
|
||||
},
|
||||
}, 200)
|
||||
} else {
|
||||
// else return the token only.
|
||||
render.JSON(w, &types.Token{Value: token_}, 200)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package account
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestRegiser(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
func TestRegiserAdmin(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
func TestRegiser_CreateError(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
func TestRegiser_BcryptError(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
func TestRegiser_TokenError(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package executions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/bradrydzewski/my-app/types/check"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/gosimple/slug"
|
||||
"github.com/gotidy/ptr"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
)
|
||||
|
||||
// HandleCreate returns an http.HandlerFunc that creates
|
||||
// the object and persists to the datastore.
|
||||
func HandleCreate(pipelines store.PipelineStore, executions store.ExecutionStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
log = hlog.FromRequest(r)
|
||||
param = chi.URLParam(r, "pipeline")
|
||||
)
|
||||
|
||||
pipeline, err := pipelines.FindSlug(ctx, param)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
log.Debug().Err(err).
|
||||
Str("pipeline_slug", param).
|
||||
Msg("pipeline not found")
|
||||
return
|
||||
}
|
||||
|
||||
sublog := log.With().
|
||||
Int64("pipeline_id", pipeline.ID).
|
||||
Str("pipeline_slug", pipeline.Slug).
|
||||
Logger()
|
||||
|
||||
in := new(types.ExecutionInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
sublog.Debug().Err(err).
|
||||
Msg("cannot unmarshal json request")
|
||||
return
|
||||
}
|
||||
|
||||
execution := &types.Execution{
|
||||
Pipeline: pipeline.ID,
|
||||
Slug: ptr.ToString(in.Slug),
|
||||
Name: ptr.ToString(in.Name),
|
||||
Desc: ptr.ToString(in.Desc),
|
||||
Created: time.Now().UnixMilli(),
|
||||
Updated: time.Now().UnixMilli(),
|
||||
}
|
||||
|
||||
// if the slug is empty we can derrive
|
||||
// the slug from the name.
|
||||
if execution.Slug == "" {
|
||||
execution.Slug = slug.Make(execution.Name)
|
||||
}
|
||||
|
||||
// if the name is empty we can derrive
|
||||
// the name from the slug.
|
||||
if execution.Name == "" {
|
||||
execution.Name = execution.Slug
|
||||
}
|
||||
|
||||
if ok, err := check.Execution(execution); !ok {
|
||||
render.BadRequest(w, err)
|
||||
sublog.Debug().Err(err).
|
||||
Int64("execution_id", execution.ID).
|
||||
Str("execution_slug", execution.Slug).
|
||||
Msg("cannot validate execution")
|
||||
return
|
||||
}
|
||||
|
||||
err = executions.Create(ctx, execution)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
sublog.Error().Err(err).
|
||||
Int64("execution_id", execution.ID).
|
||||
Str("execution_slug", execution.Slug).
|
||||
Msg("cannot create execution")
|
||||
} else {
|
||||
render.JSON(w, execution, 200)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package executions
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package executions
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
)
|
||||
|
||||
// HandleDelete returns an http.HandlerFunc that deletes
|
||||
// the object from the datastore.
|
||||
func HandleDelete(pipelines store.PipelineStore, executions store.ExecutionStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
log = hlog.FromRequest(r)
|
||||
pipelineParam = chi.URLParam(r, "pipeline")
|
||||
executionParam = chi.URLParam(r, "execution")
|
||||
)
|
||||
|
||||
pipeline, err := pipelines.FindSlug(ctx, pipelineParam)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
log.Debug().Err(err).
|
||||
Str("pipeline_slug", pipelineParam).
|
||||
Msg("pipeline not found")
|
||||
return
|
||||
}
|
||||
|
||||
execution, err := executions.FindSlug(ctx, pipeline.ID, executionParam)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
log.Debug().Err(err).
|
||||
Int64("pipeline_id", pipeline.ID).
|
||||
Str("pipeline_slug", pipeline.Slug).
|
||||
Str("execution_slug", executionParam).
|
||||
Msg("execution not found")
|
||||
return
|
||||
}
|
||||
|
||||
err = executions.Delete(ctx, execution)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Error().Err(err).
|
||||
Int64("pipeline_id", pipeline.ID).
|
||||
Str("pipeline_slug", pipeline.Slug).
|
||||
Int64("execution_id", execution.ID).
|
||||
Str("execution_slug", execution.Slug).
|
||||
Msg("cannot delete execution")
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package executions
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package executions
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
)
|
||||
|
||||
// HandleFind returns an http.HandlerFunc that writes the
|
||||
// json-encoded execution details to the response body.
|
||||
func HandleFind(pipelines store.PipelineStore, executions store.ExecutionStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
log = hlog.FromRequest(r)
|
||||
pipelineParam = chi.URLParam(r, "pipeline")
|
||||
executionParam = chi.URLParam(r, "execution")
|
||||
)
|
||||
|
||||
pipeline, err := pipelines.FindSlug(ctx, pipelineParam)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
log.Debug().Err(err).
|
||||
Str("pipeline_slug", pipelineParam).
|
||||
Msg("pipeline not found")
|
||||
return
|
||||
}
|
||||
|
||||
execution, err := executions.FindSlug(ctx, pipeline.ID, executionParam)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
log.Debug().Err(err).
|
||||
Int64("pipeline_id", pipeline.ID).
|
||||
Str("pipeline_slug", pipeline.Slug).
|
||||
Str("execution_slug", executionParam).
|
||||
Msg("execution not found")
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, execution, 200)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package executions
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package executions
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/api/request"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
)
|
||||
|
||||
// HandleList returns an http.HandlerFunc that writes a json-encoded
|
||||
// list of objects to the response body.
|
||||
func HandleList(pipelines store.PipelineStore, executions store.ExecutionStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
log = hlog.FromRequest(r)
|
||||
slug = chi.URLParam(r, "pipeline")
|
||||
page = request.ParsePage(r)
|
||||
size = request.ParseSize(r)
|
||||
)
|
||||
|
||||
pipeline, err := pipelines.FindSlug(ctx, slug)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
log.Debug().Err(err).
|
||||
Str("pipeline_slug", slug).
|
||||
Msg("pipeline not found")
|
||||
return
|
||||
}
|
||||
|
||||
executions, err := executions.List(ctx, pipeline.ID, types.Params{
|
||||
Size: size,
|
||||
Page: page,
|
||||
})
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Error().Err(err).
|
||||
Int64("pipeline_id", pipeline.ID).
|
||||
Str("pipeline_slug", pipeline.Slug).
|
||||
Msg("cannot retrieve list")
|
||||
} else {
|
||||
render.Pagination(r, w, page, size, 0)
|
||||
render.JSON(w, executions, 200)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package executions
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package executions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/bradrydzewski/my-app/types/check"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/gotidy/ptr"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
)
|
||||
|
||||
// HandleUpdate returns an http.HandlerFunc that processes http
|
||||
// requests to update the object details.
|
||||
func HandleUpdate(pipelines store.PipelineStore, executions store.ExecutionStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
log = hlog.FromRequest(r)
|
||||
pipelineParam = chi.URLParam(r, "pipeline")
|
||||
executionParam = chi.URLParam(r, "execution")
|
||||
)
|
||||
|
||||
pipeline, err := pipelines.FindSlug(ctx, pipelineParam)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
log.Debug().Err(err).
|
||||
Str("pipeline_slug", pipelineParam).
|
||||
Msg("pipeline not found")
|
||||
return
|
||||
}
|
||||
|
||||
sublog := log.With().
|
||||
Int64("pipeline_id", pipeline.ID).
|
||||
Str("pipeline_slug", pipeline.Slug).
|
||||
Logger()
|
||||
|
||||
execution, err := executions.FindSlug(ctx, pipeline.ID, executionParam)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
sublog.Debug().Err(err).
|
||||
Str("execution_slug", executionParam).
|
||||
Msg("execution not found")
|
||||
return
|
||||
}
|
||||
|
||||
sublog = sublog.With().
|
||||
Str("execution_slug", execution.Slug).
|
||||
Int64("execution_id", execution.ID).
|
||||
Logger()
|
||||
|
||||
in := new(types.ExecutionInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
sublog.Debug().Err(err).
|
||||
Msg("cannot unmarshal json request")
|
||||
return
|
||||
}
|
||||
|
||||
if in.Name != nil {
|
||||
execution.Name = ptr.ToString(in.Name)
|
||||
}
|
||||
if in.Desc != nil {
|
||||
execution.Desc = ptr.ToString(in.Desc)
|
||||
}
|
||||
|
||||
if ok, err := check.Execution(execution); !ok {
|
||||
render.BadRequest(w, err)
|
||||
sublog.Debug().Err(err).
|
||||
Msg("cannot validate execution")
|
||||
return
|
||||
}
|
||||
|
||||
execution.Updated = time.Now().UnixMilli()
|
||||
|
||||
err = executions.Update(ctx, execution)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
sublog.Error().Err(err).
|
||||
Msg("cannot update execution")
|
||||
} else {
|
||||
render.JSON(w, execution, 200)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package executions
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipelines
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/bradrydzewski/my-app/types/check"
|
||||
|
||||
"github.com/dchest/uniuri"
|
||||
"github.com/gosimple/slug"
|
||||
"github.com/gotidy/ptr"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
)
|
||||
|
||||
// HandleCreate returns an http.HandlerFunc that creates
|
||||
// a new pipeline.
|
||||
func HandleCreate(pipelines store.PipelineStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := hlog.FromRequest(r)
|
||||
|
||||
in := new(types.PipelineInput)
|
||||
err := json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
log.Debug().Err(err).
|
||||
Msg("cannot unmarshal json request")
|
||||
return
|
||||
}
|
||||
|
||||
pipeline := &types.Pipeline{
|
||||
Slug: ptr.ToString(in.Slug),
|
||||
Name: ptr.ToString(in.Name),
|
||||
Desc: ptr.ToString(in.Desc),
|
||||
Token: uniuri.NewLen(uniuri.UUIDLen),
|
||||
Created: time.Now().UnixMilli(),
|
||||
Updated: time.Now().UnixMilli(),
|
||||
}
|
||||
|
||||
// if the slug is empty we can derrive
|
||||
// the slug from the pipeline name.
|
||||
if pipeline.Slug == "" {
|
||||
pipeline.Slug = slug.Make(pipeline.Name)
|
||||
}
|
||||
|
||||
// if the name is empty we can derrive
|
||||
// the name from the pipeline slug.
|
||||
if pipeline.Name == "" {
|
||||
pipeline.Name = pipeline.Slug
|
||||
}
|
||||
|
||||
if ok, err := check.Pipeline(pipeline); !ok {
|
||||
render.BadRequest(w, err)
|
||||
log.Debug().Err(err).
|
||||
Str("pipeline_slug", pipeline.Slug).
|
||||
Msg("cannot create pipeline")
|
||||
return
|
||||
}
|
||||
|
||||
err = pipelines.Create(ctx, pipeline)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Error().Err(err).
|
||||
Str("pipeline_name", pipeline.Name).
|
||||
Str("pipeline_slug", pipeline.Slug).
|
||||
Msg("cannot create pipeline")
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, pipeline, 200)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipelines
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipelines
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
)
|
||||
|
||||
// HandleDelete returns an http.HandlerFunc that deletes
|
||||
// the object from the datastore.
|
||||
func HandleDelete(pipelines store.PipelineStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
id := chi.URLParam(r, "pipeline")
|
||||
|
||||
pipeline, err := pipelines.FindSlug(ctx, id)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
hlog.FromRequest(r).
|
||||
Debug().Err(err).
|
||||
Str("pipeline_slug", id).
|
||||
Msg("pipeline not found")
|
||||
return
|
||||
}
|
||||
|
||||
err = pipelines.Delete(ctx, pipeline)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
hlog.FromRequest(r).
|
||||
Error().Err(err).
|
||||
Int64("pipeline_id", pipeline.ID).
|
||||
Str("pipeline_slug", pipeline.Slug).
|
||||
Msg("cannot delete pipeline")
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipelines
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipelines
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
type pipelineToken struct {
|
||||
*types.Pipeline
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
// HandleFind returns an http.HandlerFunc that writes the
|
||||
// json-encoded pipeline details to the response body.
|
||||
func HandleFind(pipelines store.PipelineStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
id := chi.URLParam(r, "pipeline")
|
||||
|
||||
pipeline, err := pipelines.FindSlug(ctx, id)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
hlog.FromRequest(r).
|
||||
Debug().Err(err).
|
||||
Str("pipeline_slug", id).
|
||||
Msg("pipeline not found")
|
||||
return
|
||||
}
|
||||
|
||||
// if the caller requests the pipeline details without
|
||||
// the token, return the token object as-is.
|
||||
if r.FormValue("token") != "true" {
|
||||
render.JSON(w, pipeline, 200)
|
||||
return
|
||||
}
|
||||
|
||||
// if the caller requests the pipeline details with
|
||||
// the token then it can be safely included.
|
||||
render.JSON(w, &pipelineToken{pipeline, pipeline.Token}, 200)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipelines
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipelines
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/api/request"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// HandleList returns an http.HandlerFunc that writes a json-encoded
|
||||
// list of pipelines to the response body.
|
||||
func HandleList(pipelines store.PipelineStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
page = request.ParsePage(r)
|
||||
size = request.ParseSize(r)
|
||||
ctx = r.Context()
|
||||
)
|
||||
|
||||
viewer, _ := request.UserFrom(ctx)
|
||||
list, err := pipelines.List(ctx, viewer.ID, types.Params{
|
||||
Page: page,
|
||||
Size: size,
|
||||
})
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Ctx(ctx).Error().
|
||||
Err(err).Msg("cannot list pipelines")
|
||||
} else {
|
||||
render.Pagination(r, w, page, size, 0)
|
||||
render.JSON(w, list, 200)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipelines
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/api/request"
|
||||
"github.com/bradrydzewski/my-app/mocks"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestHandleList(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
mockUser := &types.User{
|
||||
ID: 1,
|
||||
Email: "octocat@github.com",
|
||||
}
|
||||
|
||||
mockList := []*types.Pipeline{
|
||||
{
|
||||
Name: "test",
|
||||
Desc: "desc",
|
||||
},
|
||||
}
|
||||
|
||||
projs := mocks.NewMockPipelineStore(controller)
|
||||
projs.EXPECT().List(gomock.Any(), mockUser.ID, gomock.Any()).Return(mockList, nil)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(
|
||||
request.WithUser(r.Context(), mockUser),
|
||||
)
|
||||
|
||||
HandleList(projs)(w, r)
|
||||
if got, want := w.Code, http.StatusOK; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := []*types.Pipeline{}, mockList
|
||||
json.NewDecoder(w.Body).Decode(&got)
|
||||
if diff := cmp.Diff(got, want); len(diff) > 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListErr(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
mockUser := &types.User{
|
||||
ID: 1,
|
||||
Email: "octocat@github.com",
|
||||
}
|
||||
|
||||
projs := mocks.NewMockPipelineStore(controller)
|
||||
projs.EXPECT().List(gomock.Any(), mockUser.ID, gomock.Any()).Return(nil, render.ErrNotFound)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(
|
||||
request.WithUser(r.Context(), mockUser),
|
||||
)
|
||||
|
||||
HandleList(projs)(w, r)
|
||||
if got, want := w.Code, http.StatusInternalServerError; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := &render.Error{}, render.ErrNotFound
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) > 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipelines
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/bradrydzewski/my-app/types/check"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/gotidy/ptr"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
)
|
||||
|
||||
// HandleUpdate returns an http.HandlerFunc that processes http
|
||||
// requests to update the pipeline details.
|
||||
func HandleUpdate(pipelines store.PipelineStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := hlog.FromRequest(r)
|
||||
id := chi.URLParam(r, "pipeline")
|
||||
|
||||
pipeline, err := pipelines.FindSlug(ctx, id)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
log.Debug().Err(err).
|
||||
Str("pipeline_slug", id).
|
||||
Msg("pipeline not found")
|
||||
return
|
||||
}
|
||||
|
||||
in := new(types.PipelineInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
log.Debug().Err(err).
|
||||
Int64("pipeline_id", pipeline.ID).
|
||||
Str("pipeline_slug", pipeline.Slug).
|
||||
Msg("cannot unmarshal json request")
|
||||
return
|
||||
}
|
||||
|
||||
if in.Name != nil {
|
||||
pipeline.Name = ptr.ToString(in.Name)
|
||||
}
|
||||
if in.Desc != nil {
|
||||
pipeline.Desc = ptr.ToString(in.Desc)
|
||||
}
|
||||
|
||||
if ok, err := check.Pipeline(pipeline); !ok {
|
||||
render.BadRequest(w, err)
|
||||
log.Debug().Err(err).
|
||||
Int64("pipeline_id", pipeline.ID).
|
||||
Str("pipeline_slug", pipeline.Slug).
|
||||
Msg("cannot update pipeline")
|
||||
return
|
||||
}
|
||||
|
||||
pipeline.Updated = time.Now().UnixMilli()
|
||||
|
||||
err = pipelines.Update(ctx, pipeline)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Error().Err(err).
|
||||
Int64("pipeline_id", pipeline.ID).
|
||||
Str("pipeline_slug", pipeline.Slug).
|
||||
Msg("cannot update the pipeline")
|
||||
} else {
|
||||
render.JSON(w, pipeline, 200)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipelines
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package projects
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render/platform"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
)
|
||||
|
||||
// standalone version of the product uses a single,
|
||||
// hard-coded project as its default.
|
||||
var defaultProject = &types.Project{
|
||||
Identifier: "default",
|
||||
Color: "#0063f7",
|
||||
Desc: "Default Project",
|
||||
Name: "Default Project",
|
||||
Modules: []string{},
|
||||
Org: "default",
|
||||
Tags: map[string]string{},
|
||||
}
|
||||
|
||||
// HandleFind returns an http.HandlerFunc that writes json-encoded
|
||||
// project to the http response body.
|
||||
func HandleFind() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
platform.RenderResource(w, defaultProject, 200)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package projects
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package projects
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render/platform"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
)
|
||||
|
||||
// standalone version of the product uses a single,
|
||||
// hard-coded project as its default.
|
||||
var defaultProjectList = &types.ProjectList{
|
||||
Data: []*types.Project{defaultProject},
|
||||
Empty: false,
|
||||
PageIndex: 1,
|
||||
PageItemCount: 1,
|
||||
PageSize: 1,
|
||||
TotalItems: 1,
|
||||
TotalPages: 1,
|
||||
}
|
||||
|
||||
// HandleList returns an http.HandlerFunc that writes json-encoded
|
||||
// project list to the http response body.
|
||||
func HandleList() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
platform.RenderResource(w, defaultProjectList, 200)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package projects
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package system
|
||||
|
||||
import "net/http"
|
||||
|
||||
// HandleHealth writes a 200 OK status to the http.Response
|
||||
// if the server is healthy.
|
||||
func HandleHealth(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package system
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestHealth(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/version"
|
||||
)
|
||||
|
||||
// HandleVersion writes the server version number
|
||||
// to the http.Response body in plain text.
|
||||
func HandleVersion(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "%s", version.Version)
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package system
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/api/render/platform"
|
||||
"github.com/bradrydzewski/my-app/internal/api/request"
|
||||
)
|
||||
|
||||
// HandleFind returns an http.HandlerFunc that writes json-encoded
|
||||
// account information to the http response body.
|
||||
func HandleFind() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
viewer, _ := request.UserFrom(ctx)
|
||||
render.JSON(w, viewer, 200)
|
||||
}
|
||||
}
|
||||
|
||||
// func returns an http.HandlerFunc that writes json-encoded
|
||||
// account information to the http response body in platform
|
||||
// format.
|
||||
func HandleCurrent() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
viewer, _ := request.UserFrom(ctx)
|
||||
platform.RenderResource(w, viewer, 200)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/request"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
mockUser := &types.User{
|
||||
ID: 1,
|
||||
Email: "octocat@github.com",
|
||||
}
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/api/v1/user", nil)
|
||||
r = r.WithContext(
|
||||
request.WithUser(r.Context(), mockUser),
|
||||
)
|
||||
|
||||
HandleFind()(w, r)
|
||||
if got, want := w.Code, 200; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := &types.User{}, mockUser
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/api/request"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/internal/token"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
)
|
||||
|
||||
// HandleToken returns an http.HandlerFunc that generates and
|
||||
// writes a json-encoded token to the http.Response body.
|
||||
func HandleToken(users store.UserStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
viewer, _ := request.UserFrom(r.Context())
|
||||
|
||||
token, err := token.Generate(viewer, viewer.Salt)
|
||||
if err != nil {
|
||||
render.InternalErrorf(w, "Failed to generate token")
|
||||
hlog.FromRequest(r).
|
||||
Error().Err(err).
|
||||
Str("user", viewer.Email).
|
||||
Msg("failed to generate token")
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, &types.Token{Value: token}, 200)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/request"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
func TestToken(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
mockUser := &types.User{
|
||||
ID: 1,
|
||||
Email: "octocat@github.com",
|
||||
Salt: "12345",
|
||||
}
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("POST", "/", nil)
|
||||
r = r.WithContext(
|
||||
request.WithUser(r.Context(), mockUser),
|
||||
)
|
||||
|
||||
HandleToken(nil)(w, r)
|
||||
if got, want := w.Code, 200; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
result := &types.Token{}
|
||||
json.NewDecoder(w.Body).Decode(&result)
|
||||
|
||||
_, err := jwt.Parse(result.Value, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(mockUser.Salt), nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/api/request"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
|
||||
"github.com/gotidy/ptr"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// GenerateFromPassword returns the bcrypt hash of the
|
||||
// password at the given cost.
|
||||
var hashPassword = bcrypt.GenerateFromPassword
|
||||
|
||||
// HandleUpdate returns an http.HandlerFunc that processes an http.Request
|
||||
// to update the current user account.
|
||||
func HandleUpdate(users store.UserStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := hlog.FromRequest(r)
|
||||
viewer, _ := request.UserFrom(ctx)
|
||||
|
||||
in := new(types.UserInput)
|
||||
err := json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
log.Error().Err(err).
|
||||
Str("email", viewer.Email).
|
||||
Msg("cannot unmarshal request")
|
||||
return
|
||||
}
|
||||
|
||||
if in.Password != nil {
|
||||
hash, err := hashPassword([]byte(ptr.ToString(in.Password)), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Debug().Err(err).
|
||||
Msg("cannot hash password")
|
||||
return
|
||||
}
|
||||
viewer.Password = string(hash)
|
||||
}
|
||||
|
||||
if in.Name != nil {
|
||||
viewer.Name = ptr.ToString(in.Name)
|
||||
}
|
||||
|
||||
if in.Company != nil {
|
||||
viewer.Company = ptr.ToString(in.Company)
|
||||
}
|
||||
|
||||
err = users.Update(ctx, viewer)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Error().Err(err).
|
||||
Str("email", viewer.Email).
|
||||
Msg("cannot update user")
|
||||
} else {
|
||||
render.JSON(w, viewer, 200)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/api/request"
|
||||
"github.com/bradrydzewski/my-app/mocks"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/gotidy/ptr"
|
||||
)
|
||||
|
||||
// mock bcrypt has function returns an error
|
||||
// when attepting to has the password.
|
||||
func bcryptHashErrror(password []byte, cost int) ([]byte, error) {
|
||||
return nil, bcrypt.ErrHashTooShort
|
||||
}
|
||||
|
||||
// mock bcrypt has function returns a deterministic
|
||||
// hash value for testing purposes.
|
||||
func bcryptHashStatic(password []byte, cost int) ([]byte, error) {
|
||||
return []byte("$2a$10$onMfkmQZtlkOfnZJe7GaiesbPBbXcyB53KyFKllWq829mxlhNoJSi"), nil
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
hashPassword = bcryptHashStatic
|
||||
defer func() {
|
||||
hashPassword = bcrypt.GenerateFromPassword
|
||||
}()
|
||||
|
||||
userInput := &types.UserInput{
|
||||
Username: ptr.String("octocat@google.com"),
|
||||
Password: ptr.String("password"),
|
||||
Company: ptr.String("google"),
|
||||
}
|
||||
before := &types.User{
|
||||
Email: "octocat@google.com",
|
||||
Password: "acme",
|
||||
}
|
||||
|
||||
users := mocks.NewMockUserStore(controller)
|
||||
users.EXPECT().Update(gomock.Any(), before)
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(userInput)
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("PATCH", "/api/v1/user", in)
|
||||
r = r.WithContext(
|
||||
request.WithUser(r.Context(), before),
|
||||
)
|
||||
|
||||
HandleUpdate(users)(w, r)
|
||||
if got, want := w.Code, 200; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
if got, want := before.Email, "octocat@google.com"; got != want {
|
||||
t.Errorf("Want user email %v, got %v", want, got)
|
||||
}
|
||||
if got, want := before.Password, "$2a$10$onMfkmQZtlkOfnZJe7GaiesbPBbXcyB53KyFKllWq829mxlhNoJSi"; got != want {
|
||||
t.Errorf("Want user password %v, got %v", want, got)
|
||||
}
|
||||
|
||||
after := &types.User{
|
||||
Email: "octocat@google.com",
|
||||
Company: "google",
|
||||
// Password hash is not exposecd to JSON
|
||||
}
|
||||
got, want := new(types.User), after
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
||||
|
||||
// the purpose of this unit test is to verify that a
|
||||
// failure to hash the password will return an internal
|
||||
// server error.
|
||||
func TestUpdate_HashError(t *testing.T) {
|
||||
hashPassword = bcryptHashErrror
|
||||
defer func() {
|
||||
hashPassword = bcrypt.GenerateFromPassword
|
||||
}()
|
||||
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
userInput := &types.UserInput{
|
||||
Username: ptr.String("octocat@github.com"),
|
||||
Password: ptr.String("password"),
|
||||
}
|
||||
user := &types.User{
|
||||
Email: "octocat@github.com",
|
||||
}
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(userInput)
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("PATCH", "/api/v1/user", in)
|
||||
r = r.WithContext(
|
||||
request.WithUser(r.Context(), user),
|
||||
)
|
||||
|
||||
HandleUpdate(nil)(w, r)
|
||||
if got, want := w.Code, 500; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := new(render.Error), &render.Error{Message: bcrypt.ErrHashTooShort.Error()}
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
||||
|
||||
// the purpose of this unit test is to verify that an invalid
|
||||
// (in this case missing) request body will result in a bad
|
||||
// request error returned to the client.
|
||||
func TestUpdate_BadRequest(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
mockUser := &types.User{
|
||||
ID: 1,
|
||||
Email: "octocat@github.com",
|
||||
}
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("PATCH", "/api/v1/user", in)
|
||||
r = r.WithContext(
|
||||
request.WithUser(r.Context(), mockUser),
|
||||
)
|
||||
|
||||
HandleUpdate(nil)(w, r)
|
||||
if got, want := w.Code, 400; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := new(render.Error), &render.Error{Message: "EOF"}
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
||||
|
||||
// the purpose of this unit test is to verify that an error
|
||||
// updating the database will result in an internal server
|
||||
// error returned to the client.
|
||||
func TestUpdate_ServerError(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
userInput := &types.UserInput{
|
||||
Username: ptr.String("octocat@github.com"),
|
||||
}
|
||||
user := &types.User{
|
||||
Email: "octocat@github.com",
|
||||
}
|
||||
|
||||
users := mocks.NewMockUserStore(controller)
|
||||
users.EXPECT().Update(gomock.Any(), user).Return(render.ErrNotFound)
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(userInput)
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("PATCH", "/api/v1/user", in)
|
||||
r = r.WithContext(
|
||||
request.WithUser(r.Context(), user),
|
||||
)
|
||||
|
||||
HandleUpdate(users)(w, r)
|
||||
if got, want := w.Code, 500; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := new(render.Error), render.ErrNotFound
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/bradrydzewski/my-app/types/check"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/dchest/uniuri"
|
||||
)
|
||||
|
||||
type userCreateInput struct {
|
||||
Username string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
Admin bool `json:"admin"`
|
||||
}
|
||||
|
||||
// HandleCreate returns an http.HandlerFunc that processes an http.Request
|
||||
// to create the named user account in the system.
|
||||
func HandleCreate(users store.UserStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := hlog.FromRequest(r)
|
||||
|
||||
in := new(userCreateInput)
|
||||
err := json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
log.Debug().Err(err).
|
||||
Msg("cannot unmarshal json request")
|
||||
return
|
||||
}
|
||||
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(in.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Debug().Err(err).
|
||||
Msg("cannot hash password")
|
||||
return
|
||||
}
|
||||
|
||||
user := &types.User{
|
||||
Email: in.Username,
|
||||
Admin: in.Admin,
|
||||
Password: string(hash),
|
||||
Salt: uniuri.NewLen(uniuri.UUIDLen),
|
||||
Created: time.Now().UnixMilli(),
|
||||
Updated: time.Now().UnixMilli(),
|
||||
}
|
||||
|
||||
if ok, err := check.User(user); !ok {
|
||||
render.BadRequest(w, err)
|
||||
log.Debug().Err(err).
|
||||
Str("user_email", user.Email).
|
||||
Msg("cannot validate user")
|
||||
return
|
||||
}
|
||||
|
||||
err = users.Create(ctx, user)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Error().Err(err).
|
||||
Int64("user_id", user.ID).
|
||||
Str("user_email", user.Email).
|
||||
Msg("cannot create user")
|
||||
} else {
|
||||
render.JSON(w, user, 200)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
// HandleDelete returns an http.HandlerFunc that processes an http.Request
|
||||
// to delete the named user account from the system.
|
||||
func HandleDelete(users store.UserStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := hlog.FromRequest(r)
|
||||
|
||||
key := chi.URLParam(r, "user")
|
||||
user, err := users.FindKey(ctx, key)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
log.Debug().Err(err).
|
||||
Str("user_key", key).
|
||||
Msg("cannot find user")
|
||||
return
|
||||
}
|
||||
err = users.Delete(ctx, user)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Error().Err(err).
|
||||
Int64("user_id", user.ID).
|
||||
Str("user_email", user.Email).
|
||||
Msg("cannot delete user")
|
||||
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
// HandleFind returns an http.HandlerFunc that writes json-encoded
|
||||
// user account information to the the response body.
|
||||
func HandleFind(users store.UserStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := hlog.FromRequest(r)
|
||||
|
||||
key := chi.URLParam(r, "user")
|
||||
user, err := users.FindKey(ctx, key)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
log.Debug().Err(err).
|
||||
Str("user_key", key).
|
||||
Msg("cannot find user")
|
||||
} else {
|
||||
render.JSON(w, user, 200)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/api/request"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/types/enum"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
)
|
||||
|
||||
// HandleList returns an http.HandlerFunc that writes a json-encoded
|
||||
// list of all registered system users to the response body.
|
||||
func HandleList(users store.UserStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
log = hlog.FromRequest(r)
|
||||
)
|
||||
|
||||
params := request.ParseUserFilter(r)
|
||||
if params.Order == enum.OrderDefault {
|
||||
params.Order = enum.OrderAsc
|
||||
}
|
||||
|
||||
count, err := users.Count(ctx)
|
||||
if err != nil {
|
||||
log.Error().Err(err).
|
||||
Msg("cannot retrieve user count")
|
||||
}
|
||||
|
||||
list, err := users.List(ctx, params)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Error().Err(err).
|
||||
Msg("cannot retrieve user list")
|
||||
return
|
||||
}
|
||||
|
||||
render.Pagination(r, w, params.Page, params.Size, int(count))
|
||||
render.JSON(w, list, 200)
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
|
@ -0,0 +1,112 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
"github.com/bradrydzewski/my-app/types/check"
|
||||
"github.com/gotidy/ptr"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// GenerateFromPassword returns the bcrypt hash of the
|
||||
// password at the given cost.
|
||||
var hashPassword = bcrypt.GenerateFromPassword
|
||||
|
||||
// HandleUpdate returns an http.HandlerFunc that processes an http.Request
|
||||
// to update a user account.
|
||||
func HandleUpdate(users store.UserStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := hlog.FromRequest(r)
|
||||
|
||||
key := chi.URLParam(r, "user")
|
||||
user, err := users.FindKey(ctx, key)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
log.Debug().Err(err).
|
||||
Str("user_key", key).
|
||||
Msg("cannot find user")
|
||||
return
|
||||
}
|
||||
|
||||
in := new(types.UserInput)
|
||||
if err := json.NewDecoder(r.Body).Decode(in); err != nil {
|
||||
render.BadRequest(w, err)
|
||||
log.Debug().Err(err).
|
||||
Int64("user_id", user.ID).
|
||||
Str("user_email", user.Email).
|
||||
Msg("cannot unmarshal request")
|
||||
return
|
||||
}
|
||||
|
||||
if in.Password != nil {
|
||||
hash, err := hashPassword([]byte(ptr.ToString(in.Password)), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Debug().Err(err).
|
||||
Int64("user_id", user.ID).
|
||||
Str("user_email", user.Email).
|
||||
Msg("cannot hash password")
|
||||
return
|
||||
}
|
||||
user.Password = string(hash)
|
||||
}
|
||||
|
||||
if in.Name != nil {
|
||||
user.Name = ptr.ToString(in.Name)
|
||||
}
|
||||
|
||||
if in.Company != nil {
|
||||
user.Company = ptr.ToString(in.Company)
|
||||
}
|
||||
|
||||
if in.Admin != nil {
|
||||
user.Admin = ptr.ToBool(in.Admin)
|
||||
}
|
||||
|
||||
if in.Password != nil {
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(ptr.ToString(in.Password)), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Debug().Err(err).
|
||||
Msg("cannot hash password")
|
||||
return
|
||||
}
|
||||
user.Password = string(hash)
|
||||
}
|
||||
|
||||
if ok, err := check.User(user); !ok {
|
||||
render.BadRequest(w, err)
|
||||
log.Debug().Err(err).
|
||||
Int64("user_id", user.ID).
|
||||
Str("user_email", user.Email).
|
||||
Msg("cannot update user")
|
||||
return
|
||||
}
|
||||
|
||||
user.Updated = time.Now().UnixMilli()
|
||||
|
||||
err = users.Update(ctx, user)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
log.Error().Err(err).
|
||||
Int64("user_id", user.ID).
|
||||
Str("user_email", user.Email).
|
||||
Msg("cannot update user")
|
||||
} else {
|
||||
render.JSON(w, user, 200)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package users
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package access
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/api/request"
|
||||
)
|
||||
|
||||
// SystemAdmin returns an http.HandlerFunc middleware that authorizes
|
||||
// the user access to system administration capabilities.
|
||||
func SystemAdmin() func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
user, ok := request.UserFrom(ctx)
|
||||
if !ok {
|
||||
render.ErrorCode(w, errors.New("Requires authentication"), 401)
|
||||
return
|
||||
}
|
||||
if !user.Admin {
|
||||
render.ErrorCode(w, errors.New("Forbidden"), 403)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package access
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package address
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Handler returns an http.HandlerFunc middleware that sets
|
||||
// the http.Request scheme and hostname.
|
||||
func Handler(scheme, host string) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// update the scheme and host for the inbound
|
||||
// http.Request so they are available to subsequent
|
||||
// handlers in the chain.
|
||||
r.URL.Scheme = scheme
|
||||
r.URL.Host = host
|
||||
|
||||
// if the scheme is not configured, attempt to ascertain
|
||||
// the scheme from the inbound http.Request.
|
||||
if r.URL.Scheme == "" {
|
||||
r.URL.Scheme = resolveScheme(r)
|
||||
}
|
||||
|
||||
// if the host is not configured, attempt to ascertain
|
||||
// the host from the inbound http.Request.
|
||||
if r.URL.Host == "" {
|
||||
r.URL.Host = resolveHost(r)
|
||||
}
|
||||
|
||||
// invoke the next handler in the chain.
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// resolveScheme is a helper function that evaluates the http.Request
|
||||
// and returns the scheme, HTTP or HTTPS. It is able to detect,
|
||||
// using the X-Forwarded-Proto, if the original request was HTTPS
|
||||
// and routed through a reverse proxy with SSL termination.
|
||||
func resolveScheme(r *http.Request) string {
|
||||
switch {
|
||||
case r.URL.Scheme == "https":
|
||||
return "https"
|
||||
case r.TLS != nil:
|
||||
return "https"
|
||||
case strings.HasPrefix(r.Proto, "HTTPS"):
|
||||
return "https"
|
||||
case r.Header.Get("X-Forwarded-Proto") == "https":
|
||||
return "https"
|
||||
default:
|
||||
return "http"
|
||||
}
|
||||
}
|
||||
|
||||
// resolveHost is a helper function that evaluates the http.Request
|
||||
// and returns the hostname. It is able to detect, using the
|
||||
// X-Forarded-For header, the original hostname when routed
|
||||
// through a reverse proxy.
|
||||
func resolveHost(r *http.Request) string {
|
||||
switch {
|
||||
case len(r.Host) != 0:
|
||||
return r.Host
|
||||
case len(r.URL.Host) != 0:
|
||||
return r.URL.Host
|
||||
case len(r.Header.Get("X-Forwarded-For")) != 0:
|
||||
return r.Header.Get("X-Forwarded-For")
|
||||
case len(r.Header.Get("X-Host")) != 0:
|
||||
return r.Header.Get("X-Host")
|
||||
case len(r.Header.Get("XFF")) != 0:
|
||||
return r.Header.Get("XFF")
|
||||
case len(r.Header.Get("X-Real-IP")) != 0:
|
||||
return r.Header.Get("X-Real-IP")
|
||||
default:
|
||||
return "localhost:3000"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package address
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright 2021 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package token
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bradrydzewski/my-app/internal/api/render"
|
||||
"github.com/bradrydzewski/my-app/internal/api/request"
|
||||
"github.com/bradrydzewski/my-app/internal/store"
|
||||
"github.com/bradrydzewski/my-app/internal/token"
|
||||
"github.com/bradrydzewski/my-app/types"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// Must returns an http.HandlerFunc middleware that authenticates
|
||||
// the http.Request and errors if the account cannot be authenticated.
|
||||
func Must(users store.UserStore) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
str := extractToken(r)
|
||||
|
||||
if len(str) == 0 {
|
||||
render.ErrorCode(w, errors.New("Requires authentication"), 401)
|
||||
return
|
||||
}
|
||||
|
||||
var user *types.User
|
||||
parsed, err := jwt.ParseWithClaims(str, &token.Claims{}, func(token_ *jwt.Token) (interface{}, error) {
|
||||
sub := token_.Claims.(*token.Claims).Subject
|
||||
id, err := strconv.ParseInt(sub, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user, err = users.Find(ctx, id)
|
||||
if err != nil {
|
||||
hlog.FromRequest(r).
|
||||
Error().Err(err).
|
||||
Int64("user", id).
|
||||
Msg("cannot find user")
|
||||
return nil, err
|
||||
}
|
||||
return []byte(user.Salt), nil
|
||||
})
|
||||
if err != nil {
|
||||
render.ErrorCode(w, err, 401)
|
||||
return
|
||||
}
|
||||
if parsed.Valid == false {
|
||||
render.ErrorCode(w, errors.New("Invalid token"), 401)
|
||||
return
|
||||
}
|
||||
if _, ok := parsed.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
render.ErrorCode(w, errors.New("Invalid token"), 401)
|
||||
return
|
||||
}
|
||||
|
||||
// this code should be deprecated, since the jwt.ParseWithClaims
|
||||
// should fail if the token is expired. TODO remove once we have
|
||||
// proper unit tests in place.
|
||||
if claims, ok := parsed.Claims.(*token.Claims); ok {
|
||||
if claims.ExpiresAt > 0 {
|
||||
if time.Now().Unix() > claims.ExpiresAt {
|
||||
render.ErrorCode(w, errors.New("Expired token"), 401)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Ctx(ctx).UpdateContext(func(c zerolog.Context) zerolog.Context {
|
||||
return c.Str("session_email", user.Email).Bool("session_admin", user.Admin)
|
||||
})
|
||||
|
||||
next.ServeHTTP(w, r.WithContext(
|
||||
request.WithUser(ctx, user),
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func extractToken(r *http.Request) string {
|
||||
bearer := r.Header.Get("Authorization")
|
||||
if bearer == "" {
|
||||
return r.FormValue("access_token")
|
||||
}
|
||||
bearer = strings.TrimPrefix(bearer, "Bearer ")
|
||||
bearer = strings.TrimPrefix(bearer, "IdentityService ")
|
||||
return bearer
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue