27 changed files with 1489 additions and 0 deletions
@ -0,0 +1 @@ |
|||
.git |
@ -0,0 +1,9 @@ |
|||
ENVIRONMENT= |
|||
DB_HOST= |
|||
DB_PORT= |
|||
DB_USER= |
|||
DB_PASS= |
|||
DB_NAME= |
|||
DB_SSL= |
|||
TELEGRAM_API_KEY= |
|||
HOST_URL= |
@ -0,0 +1,46 @@ |
|||
pipeline { |
|||
agent any |
|||
|
|||
environment { |
|||
ATHENA_DEPLOYMENT_SSH_KEY = credentials("athena_ssh_key") |
|||
ENVIRONMENT = credentials("ENVIRONMENT") |
|||
DB_HOST = credentials("DB_HOST") |
|||
DB_PORT = credentials("DB_PORT") |
|||
DB_USER = credentials("DB_USER") |
|||
DB_PASS = credentials("DB_PASS") |
|||
DB_NAME = credentials("DB_NAME") |
|||
DB_SSL = credentials("DB_SSL") |
|||
TELEGRAM_API_KEY = credentials("TELEGRAM_API_KEY") |
|||
} |
|||
|
|||
stages { |
|||
stage('Build') { |
|||
steps { |
|||
echo 'Creating environment variables (.env)' |
|||
sh 'echo ENVIRONMENT=$ENVIRONMENT >> .env' |
|||
sh 'echo DB_HOST=$DB_HOST >> .env' |
|||
sh 'echo DB_PORT=$DB_PORT >> .env' |
|||
sh 'echo DB_USER=$DB_USER >> .env' |
|||
sh 'echo DB_PASS=$DB_PASS >> .env' |
|||
sh 'echo DB_NAME=$DB_NAME >> .env' |
|||
sh 'echo DB_SSL=$DB_SSL >> .env' |
|||
sh 'echo TELEGRAM_API_KEY=$TELEGRAM_API_KEY >> .env' |
|||
echo 'Clearing Git directory' |
|||
sh 'rm -rf ./.git' |
|||
} |
|||
} |
|||
stage('Test') { |
|||
steps { |
|||
echo 'Testing..' |
|||
} |
|||
} |
|||
stage('Deploy') { |
|||
steps { |
|||
echo 'Creating SSH Key...' |
|||
sh 'apt update' |
|||
sh 'apt install -y rsync' |
|||
sh 'bash scripts/deploy.sh' |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,31 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/go-chi/render" |
|||
) |
|||
|
|||
type HealthStatus struct { |
|||
Status string `json:"status"` |
|||
} |
|||
|
|||
func (*HealthStatus) Render(w http.ResponseWriter, r *http.Request) error { |
|||
// Pre-processing before a response is marshalled and sent across the wire
|
|||
return nil |
|||
} |
|||
|
|||
// Health Check``
|
|||
// @Summary Responds to health check
|
|||
// @Description Description
|
|||
// @Tags Base
|
|||
// @Accept json
|
|||
// @Produce json
|
|||
// @Success 200 {object} string
|
|||
// @Failure 404 {object} string
|
|||
// @Router / [get]
|
|||
func healthHandler(w http.ResponseWriter, r *http.Request) { |
|||
var okRender HealthStatus |
|||
okRender.Status = "ok" |
|||
render.Render(w, r, &okRender) |
|||
} |
@ -0,0 +1,70 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"log" |
|||
"net/http" |
|||
"os" |
|||
|
|||
_ "git.samuelpua.com/telboon/webhook-everything/backend/docs" |
|||
"git.samuelpua.com/telboon/webhook-everything/backend/internal/common" |
|||
"git.samuelpua.com/telboon/webhook-everything/backend/internal/telegrampackage" |
|||
"git.samuelpua.com/telboon/webhook-everything/backend/internal/webhookeverything" |
|||
"github.com/go-chi/chi" |
|||
"github.com/joho/godotenv" |
|||
httpSwagger "github.com/swaggo/http-swagger" |
|||
) |
|||
|
|||
// Root Handler - Test
|
|||
// @Summary This is test
|
|||
// @Description Description
|
|||
// @Tags Base
|
|||
// @Accept json
|
|||
// @Produce json
|
|||
// @Success 200 {object} string
|
|||
// @Failure 404 {object} string
|
|||
// @Router / [get]
|
|||
func rootHandler(w http.ResponseWriter, r *http.Request) { |
|||
w.Write([]byte("hello world")) |
|||
} |
|||
|
|||
// @title Eyes of Twitterverse API
|
|||
// @version 1.0
|
|||
// @description API for frontend - built on Go-chi
|
|||
// @BasePath /
|
|||
// @contact.name Samuel Pua
|
|||
// @contact.url https://git.samuelpua.com/telboon
|
|||
func main() { |
|||
err := godotenv.Load() |
|||
if err != nil { |
|||
log.Fatal("Error loading .env file") |
|||
} |
|||
environment := os.Getenv("ENVIRONMENT") |
|||
|
|||
db := common.InitDB() |
|||
// CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
|||
db.Exec("CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";") |
|||
db.AutoMigrate(&webhookeverything.WebhookRoute{}) |
|||
db.AutoMigrate(&telegrampackage.ChatIDMap{}) |
|||
|
|||
// Setup telegram
|
|||
telegramAPIKey := os.Getenv("TELEGRAM_API_KEY") |
|||
telegramEnv := telegrampackage.NewEnv(db, telegramAPIKey, nil) |
|||
|
|||
// Get Host URL
|
|||
hostURL := os.Getenv("HOST_URL") |
|||
|
|||
r := chi.NewRouter() |
|||
|
|||
if environment == "dev" { |
|||
r.Mount("/swagger", httpSwagger.WrapHandler) |
|||
} |
|||
|
|||
r.Get("/", rootHandler) |
|||
r.Get("/health", healthHandler) |
|||
|
|||
r.Mount("/webhook", webhookeverything.WebhookEverythingRoutes(db, telegramEnv, hostURL)) |
|||
|
|||
server_str := ":8000" |
|||
log.Printf("Starting server at %s\n", server_str) |
|||
http.ListenAndServe(server_str, r) |
|||
} |
@ -0,0 +1,138 @@ |
|||
// Package docs GENERATED BY SWAG; DO NOT EDIT
|
|||
// This file was generated by swaggo/swag
|
|||
package docs |
|||
|
|||
import "github.com/swaggo/swag" |
|||
|
|||
const docTemplate = `{ |
|||
"schemes": {{ marshal .Schemes }}, |
|||
"swagger": "2.0", |
|||
"info": { |
|||
"description": "{{escape .Description}}", |
|||
"title": "{{.Title}}", |
|||
"contact": { |
|||
"name": "Samuel Pua", |
|||
"url": "https://git.samuelpua.com/telboon" |
|||
}, |
|||
"version": "{{.Version}}" |
|||
}, |
|||
"host": "{{.Host}}", |
|||
"basePath": "{{.BasePath}}", |
|||
"paths": { |
|||
"/": { |
|||
"get": { |
|||
"description": "Description", |
|||
"consumes": [ |
|||
"application/json" |
|||
], |
|||
"produces": [ |
|||
"application/json" |
|||
], |
|||
"tags": [ |
|||
"Base" |
|||
], |
|||
"summary": "This is test", |
|||
"responses": { |
|||
"200": { |
|||
"description": "OK", |
|||
"schema": { |
|||
"type": "string" |
|||
} |
|||
}, |
|||
"404": { |
|||
"description": "Not Found", |
|||
"schema": { |
|||
"type": "string" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"/webhook/routes/{webhookID}": { |
|||
"post": { |
|||
"description": "Description", |
|||
"consumes": [ |
|||
"application/json" |
|||
], |
|||
"produces": [ |
|||
"application/json" |
|||
], |
|||
"tags": [ |
|||
"Webhook" |
|||
], |
|||
"summary": "Pre-generated webhooks", |
|||
"parameters": [ |
|||
{ |
|||
"type": "string", |
|||
"description": "Pre-registered Webhook Path", |
|||
"name": "webhookID", |
|||
"in": "path", |
|||
"required": true |
|||
} |
|||
], |
|||
"responses": { |
|||
"200": { |
|||
"description": "OK", |
|||
"schema": { |
|||
"$ref": "#/definitions/common.TextResponse" |
|||
} |
|||
}, |
|||
"500": { |
|||
"description": "Internal Server Error", |
|||
"schema": { |
|||
"$ref": "#/definitions/common.ErrResponse" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"definitions": { |
|||
"common.ErrResponse": { |
|||
"type": "object", |
|||
"properties": { |
|||
"code": { |
|||
"description": "application-specific error code", |
|||
"type": "integer" |
|||
}, |
|||
"error": { |
|||
"description": "application-level error message, for debugging", |
|||
"type": "string" |
|||
}, |
|||
"status": { |
|||
"description": "user-level status message", |
|||
"type": "string" |
|||
} |
|||
} |
|||
}, |
|||
"common.TextResponse": { |
|||
"type": "object", |
|||
"properties": { |
|||
"status": { |
|||
"description": "user-level status message", |
|||
"type": "string" |
|||
}, |
|||
"text": { |
|||
"description": "application-specific error code", |
|||
"type": "string" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}` |
|||
|
|||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
|||
var SwaggerInfo = &swag.Spec{ |
|||
Version: "1.0", |
|||
Host: "", |
|||
BasePath: "/", |
|||
Schemes: []string{}, |
|||
Title: "Eyes of Twitterverse API", |
|||
Description: "API for frontend - built on Go-chi", |
|||
InfoInstanceName: "swagger", |
|||
SwaggerTemplate: docTemplate, |
|||
} |
|||
|
|||
func init() { |
|||
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) |
|||
} |
@ -0,0 +1,114 @@ |
|||
{ |
|||
"swagger": "2.0", |
|||
"info": { |
|||
"description": "API for frontend - built on Go-chi", |
|||
"title": "Eyes of Twitterverse API", |
|||
"contact": { |
|||
"name": "Samuel Pua", |
|||
"url": "https://git.samuelpua.com/telboon" |
|||
}, |
|||
"version": "1.0" |
|||
}, |
|||
"basePath": "/", |
|||
"paths": { |
|||
"/": { |
|||
"get": { |
|||
"description": "Description", |
|||
"consumes": [ |
|||
"application/json" |
|||
], |
|||
"produces": [ |
|||
"application/json" |
|||
], |
|||
"tags": [ |
|||
"Base" |
|||
], |
|||
"summary": "This is test", |
|||
"responses": { |
|||
"200": { |
|||
"description": "OK", |
|||
"schema": { |
|||
"type": "string" |
|||
} |
|||
}, |
|||
"404": { |
|||
"description": "Not Found", |
|||
"schema": { |
|||
"type": "string" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"/webhook/routes/{webhookID}": { |
|||
"post": { |
|||
"description": "Description", |
|||
"consumes": [ |
|||
"application/json" |
|||
], |
|||
"produces": [ |
|||
"application/json" |
|||
], |
|||
"tags": [ |
|||
"Webhook" |
|||
], |
|||
"summary": "Pre-generated webhooks", |
|||
"parameters": [ |
|||
{ |
|||
"type": "string", |
|||
"description": "Pre-registered Webhook Path", |
|||
"name": "webhookID", |
|||
"in": "path", |
|||
"required": true |
|||
} |
|||
], |
|||
"responses": { |
|||
"200": { |
|||
"description": "OK", |
|||
"schema": { |
|||
"$ref": "#/definitions/common.TextResponse" |
|||
} |
|||
}, |
|||
"500": { |
|||
"description": "Internal Server Error", |
|||
"schema": { |
|||
"$ref": "#/definitions/common.ErrResponse" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"definitions": { |
|||
"common.ErrResponse": { |
|||
"type": "object", |
|||
"properties": { |
|||
"code": { |
|||
"description": "application-specific error code", |
|||
"type": "integer" |
|||
}, |
|||
"error": { |
|||
"description": "application-level error message, for debugging", |
|||
"type": "string" |
|||
}, |
|||
"status": { |
|||
"description": "user-level status message", |
|||
"type": "string" |
|||
} |
|||
} |
|||
}, |
|||
"common.TextResponse": { |
|||
"type": "object", |
|||
"properties": { |
|||
"status": { |
|||
"description": "user-level status message", |
|||
"type": "string" |
|||
}, |
|||
"text": { |
|||
"description": "application-specific error code", |
|||
"type": "string" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,76 @@ |
|||
basePath: / |
|||
definitions: |
|||
common.ErrResponse: |
|||
properties: |
|||
code: |
|||
description: application-specific error code |
|||
type: integer |
|||
error: |
|||
description: application-level error message, for debugging |
|||
type: string |
|||
status: |
|||
description: user-level status message |
|||
type: string |
|||
type: object |
|||
common.TextResponse: |
|||
properties: |
|||
status: |
|||
description: user-level status message |
|||
type: string |
|||
text: |
|||
description: application-specific error code |
|||
type: string |
|||
type: object |
|||
info: |
|||
contact: |
|||
name: Samuel Pua |
|||
url: https://git.samuelpua.com/telboon |
|||
description: API for frontend - built on Go-chi |
|||
title: Eyes of Twitterverse API |
|||
version: "1.0" |
|||
paths: |
|||
/: |
|||
get: |
|||
consumes: |
|||
- application/json |
|||
description: Description |
|||
produces: |
|||
- application/json |
|||
responses: |
|||
"200": |
|||
description: OK |
|||
schema: |
|||
type: string |
|||
"404": |
|||
description: Not Found |
|||
schema: |
|||
type: string |
|||
summary: This is test |
|||
tags: |
|||
- Base |
|||
/webhook/routes/{webhookID}: |
|||
post: |
|||
consumes: |
|||
- application/json |
|||
description: Description |
|||
parameters: |
|||
- description: Pre-registered Webhook Path |
|||
in: path |
|||
name: webhookID |
|||
required: true |
|||
type: string |
|||
produces: |
|||
- application/json |
|||
responses: |
|||
"200": |
|||
description: OK |
|||
schema: |
|||
$ref: '#/definitions/common.TextResponse' |
|||
"500": |
|||
description: Internal Server Error |
|||
schema: |
|||
$ref: '#/definitions/common.ErrResponse' |
|||
summary: Pre-generated webhooks |
|||
tags: |
|||
- Webhook |
|||
swagger: "2.0" |
@ -0,0 +1,52 @@ |
|||
module git.samuelpua.com/telboon/webhook-everything/backend |
|||
|
|||
go 1.17 |
|||
|
|||
require ( |
|||
github.com/DATA-DOG/go-sqlmock v1.5.0 |
|||
github.com/go-chi/chi v1.5.4 |
|||
github.com/go-chi/render v1.0.1 |
|||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 |
|||
github.com/google/uuid v1.3.0 |
|||
github.com/swaggo/http-swagger v1.2.0 |
|||
github.com/swaggo/swag v1.7.9 |
|||
gorm.io/driver/postgres v1.2.3 |
|||
gorm.io/gorm v1.22.5 |
|||
) |
|||
|
|||
require ( |
|||
github.com/KyleBanks/depth v1.2.1 // indirect |
|||
github.com/PuerkitoBio/purell v1.1.1 // indirect |
|||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect |
|||
github.com/go-openapi/jsonpointer v0.19.5 // indirect |
|||
github.com/go-openapi/jsonreference v0.19.6 // indirect |
|||
github.com/go-openapi/spec v0.20.4 // indirect |
|||
github.com/go-openapi/swag v0.19.15 // indirect |
|||
github.com/josharian/intern v1.0.0 // indirect |
|||
github.com/kr/pretty v0.3.0 // indirect |
|||
github.com/mailru/easyjson v0.7.6 // indirect |
|||
github.com/rogpeppe/go-internal v1.8.0 // indirect |
|||
github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 // indirect |
|||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect |
|||
golang.org/x/tools v0.1.7 // indirect |
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect |
|||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect |
|||
) |
|||
|
|||
require ( |
|||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect |
|||
github.com/jackc/pgconn v1.10.1 // indirect |
|||
github.com/jackc/pgio v1.0.0 // indirect |
|||
github.com/jackc/pgpassfile v1.0.0 // indirect |
|||
github.com/jackc/pgproto3/v2 v2.2.0 // indirect |
|||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect |
|||
github.com/jackc/pgtype v1.9.0 // indirect |
|||
github.com/jackc/pgx/v4 v4.14.0 // indirect |
|||
github.com/jinzhu/inflection v1.0.0 // indirect |
|||
github.com/jinzhu/now v1.1.4 // indirect |
|||
github.com/joho/godotenv v1.4.0 |
|||
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed // indirect |
|||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect |
|||
golang.org/x/text v0.3.7 // indirect |
|||
gopkg.in/yaml.v2 v2.4.0 // indirect |
|||
) |
@ -0,0 +1,286 @@ |
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= |
|||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= |
|||
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= |
|||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= |
|||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= |
|||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= |
|||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= |
|||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= |
|||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= |
|||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= |
|||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= |
|||
github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs= |
|||
github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= |
|||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= |
|||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= |
|||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= |
|||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= |
|||
github.com/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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= |
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/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/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8= |
|||
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns= |
|||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= |
|||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= |
|||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= |
|||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= |
|||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= |
|||
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= |
|||
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= |
|||
github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= |
|||
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= |
|||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= |
|||
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= |
|||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= |
|||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= |
|||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc= |
|||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= |
|||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= |
|||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= |
|||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= |
|||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= |
|||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= |
|||
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.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= |
|||
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= |
|||
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= |
|||
github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8= |
|||
github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= |
|||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= |
|||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= |
|||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= |
|||
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= |
|||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= |
|||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= |
|||
github.com/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.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= |
|||
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= |
|||
github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns= |
|||
github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= |
|||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= |
|||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= |
|||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= |
|||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= |
|||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= |
|||
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= |
|||
github.com/jackc/pgtype v1.9.0 h1:/SH1RxEtltvJgsDqp3TbiTFApD3mey3iygpuEGeuBXk= |
|||
github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= |
|||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= |
|||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= |
|||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= |
|||
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= |
|||
github.com/jackc/pgx/v4 v4.14.0 h1:TgdrmgnM7VY72EuSQzBbBd4JA1RLqJolrw9nQVZABVc= |
|||
github.com/jackc/pgx/v4 v4.14.0/go.mod h1:jT3ibf/A0ZVCp89rtCIN0zCJxcE74ypROmHEZYsG/j8= |
|||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= |
|||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= |
|||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= |
|||
github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= |
|||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= |
|||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= |
|||
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= |
|||
github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= |
|||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= |
|||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= |
|||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= |
|||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= |
|||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= |
|||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= |
|||
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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= |
|||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= |
|||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= |
|||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= |
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
|||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= |
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= |
|||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= |
|||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= |
|||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= |
|||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= |
|||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= |
|||
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= |
|||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= |
|||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= |
|||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= |
|||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= |
|||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= |
|||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= |
|||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= |
|||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= |
|||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= |
|||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= |
|||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= |
|||
github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE= |
|||
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= |
|||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= |
|||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= |
|||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= |
|||
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= |
|||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= |
|||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= |
|||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
|||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= |
|||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= |
|||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= |
|||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= |
|||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= |
|||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= |
|||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= |
|||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= |
|||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= |
|||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= |
|||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= |
|||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= |
|||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= |
|||
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/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/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 h1:+iNTcqQJy0OZ5jk6a5NLib47eqXK8uYcPX+O4+cBpEM= |
|||
github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= |
|||
github.com/swaggo/http-swagger v1.2.0 h1:G5EBD5nvw379l2sFhact660YDT++eLviczLPrgNw/lU= |
|||
github.com/swaggo/http-swagger v1.2.0/go.mod h1:P7+V1SLG2zloe+VvAGL7WgFimhJACaBLAv2N7YQ0ikI= |
|||
github.com/swaggo/swag v1.7.8/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU= |
|||
github.com/swaggo/swag v1.7.9 h1:6vCG5mm43ebDzGlZPMGYrYI4zKFfOr5kicQX8qjeDwc= |
|||
github.com/swaggo/swag v1.7.9/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU= |
|||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= |
|||
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.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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= |
|||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= |
|||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= |
|||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= |
|||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= |
|||
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed h1:YoWVYYAfvQ4ddHv3OKmIvX7NCAhFGTj62VP2l2kfBbA= |
|||
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= |
|||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= |
|||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= |
|||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= |
|||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
|||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= |
|||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= |
|||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/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/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/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-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= |
|||
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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
|||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
|||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= |
|||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= |
|||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
|||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= |
|||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-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.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= |
|||
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-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= |
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= |
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= |
|||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= |
|||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= |
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= |
|||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= |
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
|||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
|||
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= |
|||
gorm.io/driver/postgres v1.2.3 h1:f4t0TmNMy9gh3TU2PX+EppoA6YsgFnyq8Ojtddb42To= |
|||
gorm.io/driver/postgres v1.2.3/go.mod h1:pJV6RgYQPG47aM1f0QeOzFH9HxQc8JcmAgjRCgS0wjs= |
|||
gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= |
|||
gorm.io/gorm v1.22.5 h1:lYREBgc02Be/5lSCTuysZZDb6ffL2qrat6fg9CFbvXU= |
|||
gorm.io/gorm v1.22.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= |
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= |
@ -0,0 +1,81 @@ |
|||
package common |
|||
|
|||
import ( |
|||
"fmt" |
|||
"log" |
|||
"os" |
|||
"time" |
|||
|
|||
"github.com/DATA-DOG/go-sqlmock" |
|||
"gorm.io/driver/postgres" |
|||
"gorm.io/gorm" |
|||
"gorm.io/gorm/logger" |
|||
) |
|||
|
|||
type Database struct { |
|||
*gorm.DB |
|||
} |
|||
|
|||
var DB *gorm.DB |
|||
|
|||
// Opening a database and save the reference to `Database` struct.
|
|||
func InitDB() *gorm.DB { |
|||
host := os.Getenv("DB_HOST") |
|||
user := os.Getenv("DB_USER") |
|||
pass := os.Getenv("DB_PASS") |
|||
dbName := os.Getenv("DB_NAME") |
|||
port := os.Getenv("DB_PORT") |
|||
|
|||
var sslMode string |
|||
if os.Getenv("DB_SSL") == "TRUE" { |
|||
sslMode = "enable" |
|||
} else { |
|||
sslMode = "disable" |
|||
} |
|||
|
|||
// DB Logger config
|
|||
newLogger := logger.New( |
|||
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
|
|||
logger.Config{ |
|||
SlowThreshold: time.Second, // Slow SQL threshold
|
|||
LogLevel: logger.Silent, // Log level
|
|||
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
|
|||
Colorful: true, // Disable color
|
|||
}, |
|||
) |
|||
|
|||
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=%s TimeZone=Asia/Singapore", host, user, pass, dbName, port, sslMode) |
|||
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{ |
|||
Logger: newLogger, |
|||
}) |
|||
if err != nil { |
|||
fmt.Println("db err: (Init) ", err) |
|||
} |
|||
DB = db |
|||
return DB |
|||
} |
|||
|
|||
// This function will create a temporarily database for running testing cases
|
|||
func TestDBInit() *gorm.DB { |
|||
testSQLDB, mock, err := sqlmock.New() |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
|
|||
testDB, err := gorm.Open(postgres.New(postgres.Config{ |
|||
Conn: testSQLDB, |
|||
}), &gorm.Config{}) |
|||
|
|||
if err != nil { |
|||
fmt.Println("db err: (TestDBInit) ", err) |
|||
} |
|||
|
|||
DB = testDB |
|||
_ = mock |
|||
return DB |
|||
} |
|||
|
|||
// Using this function to get a connection, you can create your connection pool here.
|
|||
func GetDB() *gorm.DB { |
|||
return DB |
|||
} |
@ -0,0 +1,56 @@ |
|||
package common |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/go-chi/render" |
|||
) |
|||
|
|||
type ErrResponse struct { |
|||
Err error `json:"-"` // low-level runtime error
|
|||
HTTPStatusCode int `json:"-"` // http response status code
|
|||
|
|||
StatusText string `json:"status"` // user-level status message
|
|||
AppCode int64 `json:"code,omitempty"` // application-specific error code
|
|||
ErrorText string `json:"error,omitempty"` // application-level error message, for debugging
|
|||
} |
|||
|
|||
func (e *ErrResponse) Render(w http.ResponseWriter, r *http.Request) error { |
|||
render.Status(r, e.HTTPStatusCode) |
|||
return nil |
|||
} |
|||
|
|||
func ErrInvalidRequest(err error) render.Renderer { |
|||
return &ErrResponse{ |
|||
Err: err, |
|||
HTTPStatusCode: 400, |
|||
StatusText: "Invalid request.", |
|||
ErrorText: err.Error(), |
|||
} |
|||
} |
|||
|
|||
func ErrValidationError(err error) render.Renderer { |
|||
return &ErrResponse{ |
|||
Err: err, |
|||
HTTPStatusCode: 422, |
|||
StatusText: "Validation error.", |
|||
ErrorText: err.Error(), |
|||
} |
|||
} |
|||
|
|||
func ErrInternalError(err error) render.Renderer { |
|||
return &ErrResponse{ |
|||
Err: err, |
|||
HTTPStatusCode: 500, |
|||
StatusText: "Invalid request.", |
|||
ErrorText: err.Error(), |
|||
} |
|||
} |
|||
|
|||
func ErrNotFound(err error) render.Renderer { |
|||
return &ErrResponse{ |
|||
HTTPStatusCode: 404, |
|||
StatusText: "Resource not found.", |
|||
ErrorText: err.Error(), |
|||
} |
|||
} |
@ -0,0 +1,24 @@ |
|||
package common |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/go-chi/render" |
|||
) |
|||
|
|||
type TextResponse struct { |
|||
Status string `json:"status"` // user-level status message
|
|||
Text string `json:"text"` // application-specific error code
|
|||
} |
|||
|
|||
func (e *TextResponse) Render(w http.ResponseWriter, r *http.Request) error { |
|||
render.Status(r, http.StatusOK) |
|||
return nil |
|||
} |
|||
|
|||
func NewGenericTextResponse(status string, text string) render.Renderer { |
|||
return &TextResponse{ |
|||
Status: status, |
|||
Text: text, |
|||
} |
|||
} |
@ -0,0 +1,52 @@ |
|||
package telegrampackage |
|||
|
|||
import ( |
|||
"fmt" |
|||
"math/rand" |
|||
"strings" |
|||
"time" |
|||
|
|||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" |
|||
"gorm.io/gorm" |
|||
) |
|||
|
|||
type TelegramHandlerFunction func(shortCode string, text string) (handled bool, responseText *string) |
|||
|
|||
type Env struct { |
|||
DB *gorm.DB |
|||
TelegramAPIKey string |
|||
HandlerFunctions []TelegramHandlerFunction |
|||
} |
|||
|
|||
func NewEnv(db *gorm.DB, telegramAPIKey string, handlerFunctions []TelegramHandlerFunction) *Env { |
|||
var env Env |
|||
env.DB = db |
|||
env.TelegramAPIKey = telegramAPIKey |
|||
env.HandlerFunctions = handlerFunctions |
|||
// Example handler function
|
|||
_ = env.telegramHandlerExample |
|||
|
|||
// Seed random
|
|||
rand.Seed(time.Now().UnixNano()) |
|||
|
|||
// Start listening job
|
|||
go env.TelegramListenAndGen() |
|||
|
|||
return &env |
|||
} |
|||
|
|||
func (env *Env) AddTelegramHandlerFunc(handlerFunction TelegramHandlerFunction) { |
|||
env.HandlerFunctions = append(env.HandlerFunctions, handlerFunction) |
|||
} |
|||
|
|||
// Not used normally. Shown here as example only
|
|||
func (env *Env) telegramHandlerExample(shortCode string, text string) (bool, *string) { |
|||
commandSplitted := ParseTelegramBotCommand(text) |
|||
if len(commandSplitted) > 0 && commandSplitted[0] == "/command" { |
|||
responseText := fmt.Sprintf("Your short code is %s.\n\nYour message is %s", shortCode, text) |
|||
responseText = responseText + fmt.Sprintf("\n\nYour parameters are: %s", strings.Join(commandSplitted[1:], "\n - ")) |
|||
responseText = "<code>" + tgbotapi.EscapeText("HTML", responseText) + "</code>" |
|||
return true, &responseText |
|||
} |
|||
return false, nil |
|||
} |
@ -0,0 +1,35 @@ |
|||
package telegrampackage |
|||
|
|||
import "strings" |
|||
|
|||
func ParseTelegramBotCommand(fullCmd string) []string { |
|||
var results []string |
|||
currentInsideQuote := false |
|||
splitted := strings.Split(fullCmd, " ") |
|||
for _, currSplit := range splitted { |
|||
if !currentInsideQuote { |
|||
if strings.HasPrefix(currSplit, "\"") { |
|||
if len(currSplit) >= 2 && !strings.HasSuffix(currSplit, "\\\"") && strings.HasSuffix(currSplit, "\"") { |
|||
currSplit = strings.ReplaceAll(currSplit, "\\\"", "\"") |
|||
results = append(results, currSplit[1:len(currSplit)-1]) |
|||
} else { |
|||
currentInsideQuote = true |
|||
currSplit = strings.ReplaceAll(currSplit, "\\\"", "\"") |
|||
results = append(results, currSplit[1:]) |
|||
} |
|||
} else { |
|||
results = append(results, currSplit) |
|||
} |
|||
} else { |
|||
if !strings.HasSuffix(currSplit, "\\\"") && strings.HasSuffix(currSplit, "\"") { |
|||
currentInsideQuote = false |
|||
currSplit = strings.ReplaceAll(currSplit, "\\\"", "\"") |
|||
results[len(results)-1] = results[len(results)-1] + " " + currSplit[:len(currSplit)-1] |
|||
} else { |
|||
currSplit = strings.ReplaceAll(currSplit, "\\\"", "\"") |
|||
results[len(results)-1] = results[len(results)-1] + " " + currSplit |
|||
} |
|||
} |
|||
} |
|||
return results |
|||
} |
@ -0,0 +1,173 @@ |
|||
package telegrampackage |
|||
|
|||
import ( |
|||
"errors" |
|||
"fmt" |
|||
"log" |
|||
"math/rand" |
|||
"strings" |
|||
"time" |
|||
|
|||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" |
|||
"github.com/google/uuid" |
|||
"gorm.io/gorm" |
|||
) |
|||
|
|||
type ChatIDMap struct { |
|||
ID uuid.UUID `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()"` |
|||
CreatedAt time.Time |
|||
UpdatedAt time.Time |
|||
DeletedAt gorm.DeletedAt `gorm:"index"` |
|||
ChatID int64 |
|||
ChatIDShort string |
|||
} |
|||
|
|||
func (env *Env) TelegramSend(chatIDShort string, msg string) error { |
|||
if chatIDShort == "" { |
|||
return errors.New("no chat ID provided") |
|||
} |
|||
bot, err := tgbotapi.NewBotAPI(env.TelegramAPIKey) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return err |
|||
} |
|||
var chatIDMap ChatIDMap |
|||
err = env.DB.Where(&ChatIDMap{ChatIDShort: chatIDShort}).Last(&chatIDMap).Error |
|||
if err != nil { |
|||
log.Println(err) |
|||
log.Println("No such telegram chat ID") |
|||
return err |
|||
} |
|||
chatMsg := tgbotapi.NewMessage(chatIDMap.ChatID, msg) |
|||
_, err = bot.Send(chatMsg) |
|||
if err != nil { |
|||
log.Println(err) |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (env *Env) TelegramListenAndGen() error { |
|||
for { |
|||
bot, err := tgbotapi.NewBotAPI(env.TelegramAPIKey) |
|||
if err != nil { |
|||
log.Println(err) |
|||
log.Println("Error occured on Telegram listen. Waiting 1 minute") |
|||
time.Sleep(60 * time.Second) |
|||
} |
|||
u := tgbotapi.NewUpdate(0) |
|||
u.Timeout = 60 |
|||
|
|||
updates := bot.GetUpdatesChan(u) |
|||
|
|||
for update := range updates { |
|||
if update.Message == nil { // ignore any non-Message Updates
|
|||
continue |
|||
} |
|||
|
|||
log.Printf("New message: [%s] %s", update.Message.From.UserName, update.Message.Text) |
|||
|
|||
// check if contains registration
|
|||
if strings.Compare(update.Message.Text, "/register") == 0 { |
|||
var chatIDMap ChatIDMap |
|||
err := env.DB.Where(&ChatIDMap{ChatID: update.Message.Chat.ID}).Last(&chatIDMap).Error |
|||
// chatID already exists
|
|||
if err == nil { |
|||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, "You already have a chat ID") |
|||
_, err := bot.Send(msg) |
|||
if err != nil { |
|||
log.Println(err) |
|||
} |
|||
msg = tgbotapi.NewMessage(update.Message.Chat.ID, fmt.Sprintf("Your chat ID is: %s", chatIDMap.ChatIDShort)) |
|||
_, err = bot.Send(msg) |
|||
if err != nil { |
|||
log.Println(err) |
|||
} |
|||
} else { |
|||
currChatCode := genShortCode(5) |
|||
chatIDMap.ChatIDShort = currChatCode |
|||
chatIDMap.ChatID = update.Message.Chat.ID |
|||
err := env.DB.Create(&chatIDMap).Error |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
} |
|||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, fmt.Sprintf("Your chat ID is: %s", chatIDMap.ChatIDShort)) |
|||
_, err = bot.Send(msg) |
|||
if err != nil { |
|||
log.Println(err) |
|||
} |
|||
} |
|||
} else { |
|||
// Get his current chat ID
|
|||
var chatIDMap ChatIDMap |
|||
err := env.DB.Where(&ChatIDMap{ChatID: update.Message.Chat.ID}).Last(&chatIDMap).Error |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
} |
|||
|
|||
var handled = false |
|||
for _, currFunc := range env.HandlerFunctions { |
|||
currHandled, responseText := currFunc(chatIDMap.ChatIDShort, update.Message.Text) |
|||
handled = handled || currHandled |
|||
if responseText != nil { |
|||
splitSendMessage(bot, update.Message.Chat.ID, *responseText) |
|||
} |
|||
} |
|||
if !handled { |
|||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, "Please send /register to register for a chat ID") |
|||
_, err := bot.Send(msg) |
|||
if err != nil { |
|||
log.Println(err) |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
func genShortCode(n int) string { |
|||
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") |
|||
runeCode := make([]rune, n) |
|||
for i := range runeCode { |
|||
runeCode[i] = letters[rand.Intn(len(letters))] |
|||
} |
|||
return string(runeCode) |
|||
} |
|||
|
|||
func splitSendMessage(bot *tgbotapi.BotAPI, chatID int64, message string) { |
|||
MAXMESSAGELENGTH := 2000 |
|||
|
|||
leftoverMessage := []rune(tgbotapi.EscapeText("HTML", message)) |
|||
if len(leftoverMessage) > MAXMESSAGELENGTH { |
|||
for len(leftoverMessage) > 0 { |
|||
var currMessage []rune |
|||
if len(leftoverMessage) <= MAXMESSAGELENGTH { |
|||
currMessage = leftoverMessage[:] |
|||
leftoverMessage = []rune("") |
|||
} else { |
|||
currMessage = leftoverMessage[:MAXMESSAGELENGTH] |
|||
leftoverMessage = leftoverMessage[MAXMESSAGELENGTH:] |
|||
} |
|||
|
|||
msg := tgbotapi.NewMessage(chatID, string(currMessage)) |
|||
msg.ParseMode = "HTML" |
|||
msg.DisableWebPagePreview = true |
|||
_, err := bot.Send(msg) |
|||
if err != nil { |
|||
msg := tgbotapi.NewMessage(chatID, err.Error()) |
|||
bot.Send(msg) |
|||
log.Println(err) |
|||
} |
|||
} |
|||
} else { |
|||
msg := tgbotapi.NewMessage(chatID, string(message)) |
|||
msg.ParseMode = "HTML" |
|||
msg.DisableWebPagePreview = true |
|||
_, err := bot.Send(msg) |
|||
if err != nil { |
|||
msg := tgbotapi.NewMessage(chatID, err.Error()) |
|||
bot.Send(msg) |
|||
log.Println(err) |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,34 @@ |
|||
package webhookeverything |
|||
|
|||
import ( |
|||
"math/rand" |
|||
"time" |
|||
|
|||
"git.samuelpua.com/telboon/webhook-everything/backend/internal/telegrampackage" |
|||
"github.com/go-chi/chi" |
|||
"gorm.io/gorm" |
|||
) |
|||
|
|||
type Env struct { |
|||
DB *gorm.DB |
|||
TelegramEnv *telegrampackage.Env |
|||
HostUrl string |
|||
} |
|||
|
|||
func WebhookEverythingRoutes(db *gorm.DB, telegramEnv *telegrampackage.Env, hostURL string) chi.Router { |
|||
var env Env |
|||
env.DB = db |
|||
env.TelegramEnv = telegramEnv |
|||
|
|||
// Seed random
|
|||
rand.Seed(time.Now().UnixNano()) |
|||
|
|||
// Web Routes
|
|||
r := chi.NewRouter() |
|||
r.HandleFunc("/routes/{routeID}", env.handleWebhook) |
|||
|
|||
// Telegram handlers
|
|||
env.TelegramEnv.AddTelegramHandlerFunc(env.registerWebhook) |
|||
|
|||
return r |
|||
} |
@ -0,0 +1,40 @@ |
|||
package webhookeverything |
|||
|
|||
import ( |
|||
"fmt" |
|||
"math/rand" |
|||
"net/url" |
|||
"path" |
|||
|
|||
"git.samuelpua.com/telboon/webhook-everything/backend/internal/telegrampackage" |
|||
) |
|||
|
|||
func (env *Env) registerWebhook(shortCode string, text string) (bool, *string) { |
|||
commandSplitted := telegrampackage.ParseTelegramBotCommand(text) |
|||
if len(commandSplitted) > 0 && commandSplitted[0] == "/register-webhook" { |
|||
newWebhookID := genWebhookCode(6) |
|||
baseURL, _ := url.Parse(env.HostUrl) |
|||
baseURL.Path = path.Join(baseURL.Path, "webhook") |
|||
baseURL.Path = path.Join(baseURL.Path, "routes") |
|||
baseURL.Path = path.Join(baseURL.Path, newWebhookID) |
|||
webhookURL := baseURL.String() |
|||
|
|||
var webhookRoute WebhookRoute |
|||
webhookRoute.TelegramShortCode = shortCode |
|||
webhookRoute.WebhookID = newWebhookID |
|||
env.DB.Create(&webhookRoute) |
|||
|
|||
responseText := fmt.Sprintf("Your generated webhook URL is: %s", webhookURL) |
|||
return true, &responseText |
|||
} |
|||
return false, nil |
|||
} |
|||
|
|||
func genWebhookCode(n int) string { |
|||
var letters = []rune("abcdefghijklmnopqrstuvwxyz1234567890") |
|||
runeCode := make([]rune, n) |
|||
for i := range runeCode { |
|||
runeCode[i] = letters[rand.Intn(len(letters))] |
|||
} |
|||
return string(runeCode) |
|||
} |
@ -0,0 +1,26 @@ |
|||
package webhookeverything |
|||
|
|||
import ( |
|||
"net/http" |
|||
"net/http/httputil" |
|||
) |
|||
|
|||
func (env *Env) forwardHookToTelegram(r *http.Request, routeID string) error { |
|||
// Get Telegram code
|
|||
var routeResult WebhookRoute |
|||
err := env.DB.Where(&WebhookRoute{WebhookID: routeID}).First(&routeResult).Error |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
// Dump request as string
|
|||
responseStr, err := httputil.DumpRequest(r, true) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
// Send telegram
|
|||
env.TelegramEnv.TelegramSend(routeResult.TelegramShortCode, string(responseStr)) |
|||
|
|||
return nil |
|||
} |
@ -0,0 +1,28 @@ |
|||
package webhookeverything |
|||
|
|||
import ( |
|||
"net/http" |
|||
"time" |
|||
|
|||
"github.com/google/uuid" |
|||
"gorm.io/gorm" |
|||
) |
|||
|
|||
type WebhookRoute struct { |
|||
ID uuid.UUID `gorm:"primaryKey;type:uuid;default:uuid_generate_v4()"` |
|||
CreatedAt time.Time |
|||
UpdatedAt time.Time |
|||
DeletedAt gorm.DeletedAt `gorm:"index"` |
|||
WebhookID string `gorm:"index,unique"` |
|||
TelegramShortCode string `gorm:"index"` |
|||
} |
|||
|
|||
type StatusMessage struct { |
|||
Status string `json:"status"` |
|||
Message string `json:"message"` |
|||
} |
|||
|
|||
func (statusMessage *StatusMessage) Render(w http.ResponseWriter, r *http.Request) error { |
|||
// Pre-processing before a response is marshalled and sent across the wire
|
|||
return nil |
|||
} |
@ -0,0 +1,34 @@ |
|||
package webhookeverything |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"git.samuelpua.com/telboon/webhook-everything/backend/internal/common" |
|||
"github.com/go-chi/chi" |
|||
"github.com/go-chi/render" |
|||
) |
|||
|
|||
// Handles pre-generated webhooks
|
|||
// @Summary Pre-generated webhooks
|
|||
// @Description Description
|
|||
// @Tags Webhook
|
|||
// @Accept json
|
|||
// @Produce json
|
|||
// @Param webhookID path string true "Pre-registered Webhook Path"
|
|||
// @Success 200 {object} common.TextResponse
|
|||
// @Failure 500 {object} common.ErrResponse
|
|||
// @Router /webhook/routes/{webhookID} [POST]
|
|||
func (env *Env) handleWebhook(w http.ResponseWriter, r *http.Request) { |
|||
ctx := r.Context() |
|||
routeID := chi.URLParam(r, "routeID") |
|||
_ = ctx |
|||
|
|||
err := env.forwardHookToTelegram(r, routeID) |
|||
|
|||
if err != nil { |
|||
render.Render(w, r, common.ErrInternalError(err)) |
|||
return |
|||
} |
|||
|
|||
render.Render(w, r, common.NewGenericTextResponse("success", "")) |
|||
} |
@ -0,0 +1,25 @@ |
|||
version: '3' |
|||
services: |
|||
####################################### |
|||
# Webhook Everything |
|||
####################################### |
|||
webhook-everythin: |
|||
restart: always |
|||
build: |
|||
context: . |
|||
dockerfile: docker/Dockerfile |
|||
ports: |
|||
- "127.0.0.1:8006:8000" |
|||
|
|||
####################################### |
|||
# Postgres server |
|||
####################################### |
|||
postgres-webhook-everything: |
|||
image: postgres |
|||
restart: always |
|||
volumes: |
|||
- "./_postgres_data:/var/lib/postgresql/data" |
|||
environment: |
|||
- "POSTGRES_USER=${DB_USER}" |
|||
- "POSTGRES_PASSWORD=${DB_PASS}" |
|||
- "POSTGRES_DB=${DB_NAME}" |
@ -0,0 +1,21 @@ |
|||
FROM golang:1.17-buster as go-builder |
|||
|
|||
COPY . /build |
|||
|
|||
WORKDIR /build/ |
|||
RUN /build/scripts/build.sh |
|||
|
|||
FROM ubuntu |
|||
ENV debian_frontend=noninteractive |
|||
|
|||
WORKDIR /app/ |
|||
RUN apt update |
|||
RUN apt install -y ca-certificates |
|||
|
|||
COPY --from=go-builder /build/backend/server /app/server |
|||
COPY .env /app/.env |
|||
|
|||
RUN useradd -ms /bin/bash user |
|||
USER user |
|||
|
|||
ENTRYPOINT ["/app/server"] |
@ -0,0 +1,16 @@ |
|||
#! /bin/bash |
|||
|
|||
# Install goswag |
|||
go install github.com/swaggo/swag/cmd/swag@latest |
|||
|
|||
# go to backend directory |
|||
cd backend |
|||
|
|||
# rebuild swagger docs |
|||
swag init --dir cmd/server/ --parseDependency |
|||
|
|||
# build binary |
|||
go build git.samuelpua.com/telboon/webhook-everything/backend/cmd/server |
|||
|
|||
# go to base directory |
|||
cd .. |
@ -0,0 +1,6 @@ |
|||
#!/bin/bash |
|||
|
|||
echo $ATHENA_DEPLOYMENT_SSH_KEY | base64 -d > /tmp/ssh-key |
|||
chmod 600 /tmp/ssh-key |
|||
rsync -v -e "ssh -o StrictHostKeyChecking=no -i /tmp/ssh-key -p 777" -a --exclude="_postgres_data" --delete . samuel@athena.gaia:~/webhook-everything || true |
|||
ssh -p 777 -o StrictHostKeyChecking=no -i /tmp/ssh-key samuel@athena.gaia "cd /home/samuel/webhook-everything && docker-compose up --build -d" |
@ -0,0 +1,9 @@ |
|||
docker rm -f dev_postgres |
|||
docker run -d \ |
|||
-v `pwd`/_postgres_data:/var/lib/postgresql/data \ |
|||
-e POSTGRES_USER=testuser \ |
|||
-e POSTGRES_PASSWORD=testpassword \ |
|||
-e POSTGRES_DB=testdb \ |
|||
--name dev_postgres \ |
|||
-p 127.0.0.1:5432:5432 \ |
|||
postgres:14 |
Loading…
Reference in new issue