mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-12-29 18:06:15 -06:00
fix up some stuffffff
This commit is contained in:
parent
6d3efd3511
commit
e12b81e3f1
34 changed files with 236 additions and 2484 deletions
3
go.mod
3
go.mod
|
|
@ -30,7 +30,6 @@ require (
|
|||
github.com/uptrace/bun v1.0.5
|
||||
github.com/uptrace/bun/dialect/pgdialect v1.0.5
|
||||
github.com/uptrace/bun/dialect/sqlitedialect v1.0.5
|
||||
github.com/uptrace/bun/extra/bundebug v1.0.5
|
||||
github.com/urfave/cli/v2 v2.3.0
|
||||
github.com/wagslane/go-password-validator v0.3.0
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
|
||||
|
|
@ -53,7 +52,6 @@ require (
|
|||
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d // indirect
|
||||
github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d // indirect
|
||||
github.com/dsoprea/go-utility v0.0.0-20200717064901-2fccff4aa15e // indirect
|
||||
github.com/fatih/color v1.10.0 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-errors/errors v1.4.0 // indirect
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
|
|
@ -77,7 +75,6 @@ require (
|
|||
github.com/json-iterator/go v1.1.11 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
|
|
|
|||
6
go.sum
6
go.sum
|
|
@ -108,8 +108,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
|
|||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
|
||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
|
|
@ -337,8 +335,6 @@ github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O
|
|||
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-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/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.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
|
|
@ -460,8 +456,6 @@ github.com/uptrace/bun/dialect/pgdialect v1.0.5 h1:mq694/aMvs7GwuTar9NIlCLQt/2u4
|
|||
github.com/uptrace/bun/dialect/pgdialect v1.0.5/go.mod h1:MKWjO0PC20ris2oJ3dd6mI/762x24Cjwh8XmbqUhM8A=
|
||||
github.com/uptrace/bun/dialect/sqlitedialect v1.0.5 h1:6cIj31YVJr4vvA15C2v76soXL+7WtjFdV6WraApc3r0=
|
||||
github.com/uptrace/bun/dialect/sqlitedialect v1.0.5/go.mod h1:NW2Gctc9ooQXGSD4kYSac2aiF49lo8YJ3ZAr93lH2p8=
|
||||
github.com/uptrace/bun/extra/bundebug v1.0.5 h1:g7ILRgoPXSKOQ6Wq+n9leF/ehGLzHmktBL33JIHmgq0=
|
||||
github.com/uptrace/bun/extra/bundebug v1.0.5/go.mod h1:548Yazx7hlZDkLQyHBIz840rOspP2ceBVEwl/FJHubU=
|
||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@
|
|||
package account
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
|
|
@ -107,17 +109,24 @@ func (m *Module) AccountUpdateCredentialsPATCHHandler(c *gin.Context) {
|
|||
}
|
||||
l.Tracef("retrieved account %+v", authed.Account.ID)
|
||||
|
||||
form := &model.UpdateCredentialsRequest{}
|
||||
if err := c.ShouldBind(&form); err != nil || form == nil {
|
||||
l.Debugf("could not parse form from request: %s", err)
|
||||
form, err := parseUpdateAccountForm(c)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
l.Debugf("parsed request form %+v", form)
|
||||
|
||||
// if everything on the form is nil, then nothing has been set and we shouldn't continue
|
||||
if form.Discoverable == nil && form.Bot == nil && form.DisplayName == nil && form.Note == nil && form.Avatar == nil && form.Header == nil && form.Locked == nil && form.Source == nil && form.FieldsAttributes == nil {
|
||||
if form.Discoverable == nil &&
|
||||
form.Bot == nil &&
|
||||
form.DisplayName == nil &&
|
||||
form.Note == nil &&
|
||||
form.Avatar == nil &&
|
||||
form.Header == nil &&
|
||||
form.Locked == nil &&
|
||||
form.Source.Privacy == nil &&
|
||||
form.Source.Sensitive == nil &&
|
||||
form.Source.Language == nil &&
|
||||
form.FieldsAttributes == nil {
|
||||
l.Debugf("could not parse form from request")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "empty form submitted"})
|
||||
return
|
||||
|
|
@ -133,3 +142,34 @@ func (m *Module) AccountUpdateCredentialsPATCHHandler(c *gin.Context) {
|
|||
l.Tracef("conversion successful, returning OK and mastosensitive account %+v", acctSensitive)
|
||||
c.JSON(http.StatusOK, acctSensitive)
|
||||
}
|
||||
|
||||
func parseUpdateAccountForm(c *gin.Context) (*model.UpdateCredentialsRequest, error) {
|
||||
// parse main fields from request
|
||||
form := &model.UpdateCredentialsRequest{
|
||||
Source: &model.UpdateSource{},
|
||||
}
|
||||
if err := c.ShouldBind(&form); err != nil || form == nil {
|
||||
return nil, fmt.Errorf("could not parse form from request: %s", err)
|
||||
}
|
||||
|
||||
// parse source field-by-field
|
||||
sourceMap := c.PostFormMap("source")
|
||||
|
||||
if privacy, ok := sourceMap["privacy"]; ok {
|
||||
form.Source.Privacy = &privacy
|
||||
}
|
||||
|
||||
if sensitive, ok := sourceMap["sensitive"]; ok {
|
||||
sensitiveBool, err := strconv.ParseBool(sensitive)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing form source[sensitive]: %s", err)
|
||||
}
|
||||
form.Source.Sensitive = &sensitiveBool
|
||||
}
|
||||
|
||||
if language, ok := sourceMap["language"]; ok {
|
||||
form.Source.Language = &language
|
||||
}
|
||||
|
||||
return form, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ package account_test
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
|
@ -51,7 +50,6 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandler()
|
|||
panic(err)
|
||||
}
|
||||
bodyBytes := requestBody.Bytes()
|
||||
fmt.Println(string(bodyBytes))
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, account.UpdateCredentialsPath, w.FormDataContentType())
|
||||
|
||||
|
|
@ -68,7 +66,6 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandler()
|
|||
// check the response
|
||||
b, err := ioutil.ReadAll(result.Body)
|
||||
assert.NoError(suite.T(), err)
|
||||
fmt.Println(string(b))
|
||||
|
||||
// unmarshal the returned account
|
||||
apimodelAccount := &apimodel.Account{}
|
||||
|
|
@ -77,7 +74,7 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandler()
|
|||
|
||||
// check the returned api model account
|
||||
// fields should be updated
|
||||
suite.Equal(newBio, apimodelAccount.Note)
|
||||
suite.Equal("<p>this is my new bio read it and weep</p>", apimodelAccount.Note)
|
||||
}
|
||||
|
||||
func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerGetAccountFirst() {
|
||||
|
|
@ -114,7 +111,6 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerGet
|
|||
// check the response
|
||||
b, err := ioutil.ReadAll(result.Body)
|
||||
assert.NoError(suite.T(), err)
|
||||
fmt.Println(string(b))
|
||||
|
||||
// unmarshal the returned account
|
||||
apimodelAccount := &apimodel.Account{}
|
||||
|
|
@ -123,7 +119,7 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerGet
|
|||
|
||||
// check the returned api model account
|
||||
// fields should be updated
|
||||
suite.Equal(newBio, apimodelAccount.Note)
|
||||
suite.Equal("<p>this is my new bio read it and weep</p>", apimodelAccount.Note)
|
||||
}
|
||||
|
||||
func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerTwoFields() {
|
||||
|
|
@ -140,7 +136,6 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerTwo
|
|||
panic(err)
|
||||
}
|
||||
bodyBytes := requestBody.Bytes()
|
||||
fmt.Println(string(bodyBytes))
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, account.UpdateCredentialsPath, w.FormDataContentType())
|
||||
|
||||
|
|
@ -157,7 +152,6 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerTwo
|
|||
// check the response
|
||||
b, err := ioutil.ReadAll(result.Body)
|
||||
assert.NoError(suite.T(), err)
|
||||
fmt.Println(string(b))
|
||||
|
||||
// unmarshal the returned account
|
||||
apimodelAccount := &apimodel.Account{}
|
||||
|
|
@ -166,7 +160,7 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerTwo
|
|||
|
||||
// check the returned api model account
|
||||
// fields should be updated
|
||||
suite.Equal(newBio, apimodelAccount.Note)
|
||||
suite.Equal("<p>this is my new bio read it and weep</p>", apimodelAccount.Note)
|
||||
suite.True(apimodelAccount.Locked)
|
||||
}
|
||||
|
||||
|
|
@ -201,7 +195,6 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerWit
|
|||
// check the response
|
||||
b, err := ioutil.ReadAll(result.Body)
|
||||
assert.NoError(suite.T(), err)
|
||||
fmt.Println(string(b))
|
||||
|
||||
// unmarshal the returned account
|
||||
apimodelAccount := &apimodel.Account{}
|
||||
|
|
@ -246,6 +239,52 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerEmp
|
|||
suite.Equal(`{"error":"empty form submitted"}`, string(b))
|
||||
}
|
||||
|
||||
func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUpdateSource() {
|
||||
// set up the request
|
||||
// we're updating the language of zork
|
||||
newLanguage := "de"
|
||||
requestBody, w, err := testrig.CreateMultipartFormData(
|
||||
"", "",
|
||||
map[string]string{
|
||||
"source[privacy]": string(apimodel.VisibilityPrivate),
|
||||
"source[language]": "de",
|
||||
"source[sensitive]": "true",
|
||||
"locked": "true",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bodyBytes := requestBody.Bytes()
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, account.UpdateCredentialsPath, w.FormDataContentType())
|
||||
|
||||
// call the handler
|
||||
suite.accountModule.AccountUpdateCredentialsPATCHHandler(ctx)
|
||||
|
||||
// 1. we should have OK because our request was valid
|
||||
suite.Equal(http.StatusOK, recorder.Code)
|
||||
|
||||
// 2. we should have no error message in the result body
|
||||
result := recorder.Result()
|
||||
defer result.Body.Close()
|
||||
|
||||
// check the response
|
||||
b, err := ioutil.ReadAll(result.Body)
|
||||
assert.NoError(suite.T(), err)
|
||||
|
||||
// unmarshal the returned account
|
||||
apimodelAccount := &apimodel.Account{}
|
||||
err = json.Unmarshal(b, apimodelAccount)
|
||||
suite.NoError(err)
|
||||
|
||||
// check the returned api model account
|
||||
// fields should be updated
|
||||
suite.Equal(newLanguage, apimodelAccount.Source.Language)
|
||||
suite.EqualValues(apimodel.VisibilityPrivate, apimodelAccount.Source.Privacy)
|
||||
suite.True(apimodelAccount.Source.Sensitive)
|
||||
suite.True(apimodelAccount.Locked)
|
||||
}
|
||||
|
||||
func TestAccountUpdateTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(AccountUpdateTestSuite))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@ type StatusCreateRequest struct {
|
|||
// - public
|
||||
// - unlisted
|
||||
// - private
|
||||
// - mutuals_only
|
||||
// - direct
|
||||
type Visibility string
|
||||
|
||||
|
|
|
|||
|
|
@ -66,10 +66,6 @@ type Basic interface {
|
|||
// The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice.
|
||||
UpdateByPrimaryKey(ctx context.Context, i interface{}) Error
|
||||
|
||||
// UpdateOneByPrimaryKey sets one column of interface, with the given key, to the given value.
|
||||
// It uses the primary key of interface i to decide which row to update. This is usually the `id`.
|
||||
UpdateOneByPrimaryKey(ctx context.Context, key string, value interface{}, i interface{}) Error
|
||||
|
||||
// UpdateWhere updates column key of interface i with the given value, where the given parameters apply.
|
||||
UpdateWhere(ctx context.Context, where []Where, key string, value interface{}, i interface{}) Error
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/cache"
|
||||
|
|
@ -103,16 +102,15 @@ func (a *accountDB) getAccount(ctx context.Context, cacheGet func() (*gtsmodel.A
|
|||
}
|
||||
|
||||
func (a *accountDB) UpdateAccount(ctx context.Context, account *gtsmodel.Account) (*gtsmodel.Account, db.Error) {
|
||||
if strings.TrimSpace(account.ID) == "" {
|
||||
// TODO: we should not need this check here
|
||||
return nil, errors.New("account had no ID")
|
||||
}
|
||||
|
||||
// Update the account's last-used
|
||||
// Update the account's last-updated
|
||||
account.UpdatedAt = time.Now()
|
||||
|
||||
// Update the account model in the DB
|
||||
_, err := a.conn.NewUpdate().Model(account).WherePK().Exec(ctx)
|
||||
_, err := a.conn.
|
||||
NewUpdate().
|
||||
Model(account).
|
||||
WherePK().
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return nil, a.conn.ProcessError(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,16 +105,6 @@ func (b *basicDB) UpdateByPrimaryKey(ctx context.Context, i interface{}) db.Erro
|
|||
return b.conn.ProcessError(err)
|
||||
}
|
||||
|
||||
func (b *basicDB) UpdateOneByPrimaryKey(ctx context.Context, key string, value interface{}, i interface{}) db.Error {
|
||||
q := b.conn.NewUpdate().
|
||||
Model(i).
|
||||
Set("? = ?", bun.Safe(key), value).
|
||||
WherePK()
|
||||
|
||||
_, err := q.Exec(ctx)
|
||||
return b.conn.ProcessError(err)
|
||||
}
|
||||
|
||||
func (b *basicDB) UpdateWhere(ctx context.Context, where []db.Where, key string, value interface{}, i interface{}) db.Error {
|
||||
q := b.conn.NewUpdate().Model(i)
|
||||
|
||||
|
|
|
|||
|
|
@ -64,40 +64,6 @@ func (suite *BasicTestSuite) TestGetAllNotNull() {
|
|||
}
|
||||
}
|
||||
|
||||
func (suite *BasicTestSuite) TestUpdateOneByPrimaryKeySetEmpty() {
|
||||
testAccount := suite.testAccounts["local_account_1"]
|
||||
|
||||
// try removing the note from zork
|
||||
err := suite.db.UpdateOneByPrimaryKey(context.Background(), "note", "", testAccount)
|
||||
suite.NoError(err)
|
||||
|
||||
// get zork out of the database
|
||||
dbAccount, err := suite.db.GetAccountByID(context.Background(), testAccount.ID)
|
||||
suite.NoError(err)
|
||||
suite.NotNil(dbAccount)
|
||||
|
||||
// note should be empty now
|
||||
suite.Empty(dbAccount.Note)
|
||||
}
|
||||
|
||||
func (suite *BasicTestSuite) TestUpdateOneByPrimaryKeySetValue() {
|
||||
testAccount := suite.testAccounts["local_account_1"]
|
||||
|
||||
note := "this is my new note :)"
|
||||
|
||||
// try updating the note on zork
|
||||
err := suite.db.UpdateOneByPrimaryKey(context.Background(), "note", note, testAccount)
|
||||
suite.NoError(err)
|
||||
|
||||
// get zork out of the database
|
||||
dbAccount, err := suite.db.GetAccountByID(context.Background(), testAccount.ID)
|
||||
suite.NoError(err)
|
||||
suite.NotNil(dbAccount)
|
||||
|
||||
// note should be set now
|
||||
suite.Equal(note, dbAccount.Note)
|
||||
}
|
||||
|
||||
func TestBasicTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(BasicTestSuite))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ func NewBunDBService(ctx context.Context, c *config.Config, log *logrus.Logger)
|
|||
|
||||
if log.Level >= logrus.TraceLevel {
|
||||
// add a hook to just log queries and the time they take
|
||||
conn.DB.AddQueryHook(&debugQueryHook{log: log})
|
||||
conn.DB.AddQueryHook(newDebugQueryHook(log))
|
||||
}
|
||||
|
||||
// actually *begin* the connection so that we can tell if the db is there and listening
|
||||
|
|
@ -407,7 +407,7 @@ func (ps *bunDBService) MentionStringsToMentions(ctx context.Context, targetAcco
|
|||
return menchies, nil
|
||||
}
|
||||
|
||||
func (ps *bunDBService) TagStringsToTags(ctx context.Context, tags []string, originAccountID string, statusID string) ([]*gtsmodel.Tag, error) {
|
||||
func (ps *bunDBService) TagStringsToTags(ctx context.Context, tags []string, originAccountID string) ([]*gtsmodel.Tag, error) {
|
||||
newTags := []*gtsmodel.Tag{}
|
||||
for _, t := range tags {
|
||||
tag := >smodel.Tag{}
|
||||
|
|
@ -443,7 +443,7 @@ func (ps *bunDBService) TagStringsToTags(ctx context.Context, tags []string, ori
|
|||
return newTags, nil
|
||||
}
|
||||
|
||||
func (ps *bunDBService) EmojiStringsToEmojis(ctx context.Context, emojis []string, originAccountID string, statusID string) ([]*gtsmodel.Emoji, error) {
|
||||
func (ps *bunDBService) EmojiStringsToEmojis(ctx context.Context, emojis []string) ([]*gtsmodel.Emoji, error) {
|
||||
newEmojis := []*gtsmodel.Emoji{}
|
||||
for _, e := range emojis {
|
||||
emoji := >smodel.Emoji{}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,13 @@ import (
|
|||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
// queryHook is just a wrapper for bun.QueryHook
|
||||
type queryHook bun.QueryHook
|
||||
func newDebugQueryHook(log *logrus.Logger) bun.QueryHook {
|
||||
return &debugQueryHook{
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
// debugQueryHook implements queryHook
|
||||
// debugQueryHook implements bun.QueryHook
|
||||
type debugQueryHook struct {
|
||||
log *logrus.Logger
|
||||
}
|
||||
|
|
@ -41,7 +44,7 @@ func (q *debugQueryHook) BeforeQuery(ctx context.Context, event *bun.QueryEvent)
|
|||
|
||||
// AfterQuery logs the time taken to query, the operation (select, update, etc), and the query itself as translated by bun.
|
||||
func (q *debugQueryHook) AfterQuery(ctx context.Context, event *bun.QueryEvent) {
|
||||
dur := time.Now().Sub(event.StartTime).Round(time.Microsecond)
|
||||
dur := time.Since(event.StartTime).Round(time.Microsecond)
|
||||
l := q.log.WithFields(logrus.Fields{
|
||||
"queryTime": dur,
|
||||
"operation": event.Operation(),
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ type DB interface {
|
|||
//
|
||||
// Note: this func doesn't/shouldn't do any manipulation of the tags in the DB, it's just for checking
|
||||
// if they exist in the db already, and conveniently returning them, or creating new tag structs.
|
||||
TagStringsToTags(ctx context.Context, tags []string, originAccountID string, statusID string) ([]*gtsmodel.Tag, error)
|
||||
TagStringsToTags(ctx context.Context, tags []string, originAccountID string) ([]*gtsmodel.Tag, error)
|
||||
|
||||
// EmojiStringsToEmojis takes a slice of deduplicated, lowercase emojis in the form ":emojiname:", which have been
|
||||
// used in a status. It takes the id of the account that wrote the status, and the id of the status itself, and then
|
||||
|
|
@ -72,5 +72,5 @@ type DB interface {
|
|||
//
|
||||
// Note: this func doesn't/shouldn't do any manipulation of the emoji in the DB, it's just for checking
|
||||
// if they exist in the db and conveniently returning them if they do.
|
||||
EmojiStringsToEmojis(ctx context.Context, emojis []string, originAccountID string, statusID string) ([]*gtsmodel.Emoji, error)
|
||||
EmojiStringsToEmojis(ctx context.Context, emojis []string) ([]*gtsmodel.Emoji, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/media"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/messages"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/text"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/typeutils"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/visibility"
|
||||
"github.com/superseriousbusiness/oauth2/v4"
|
||||
|
|
@ -83,6 +84,7 @@ type processor struct {
|
|||
fromClientAPI chan messages.FromClientAPI
|
||||
oauthServer oauth.Server
|
||||
filter visibility.Filter
|
||||
formatter text.Formatter
|
||||
db db.DB
|
||||
federator federation.Federator
|
||||
log *logrus.Logger
|
||||
|
|
@ -97,6 +99,7 @@ func New(db db.DB, tc typeutils.TypeConverter, mediaHandler media.Handler, oauth
|
|||
fromClientAPI: fromClientAPI,
|
||||
oauthServer: oauthServer,
|
||||
filter: visibility.NewFilter(db, log),
|
||||
formatter: text.NewFormatter(config, db, log),
|
||||
db: db,
|
||||
federator: federator,
|
||||
log: log,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/media"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/messages"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/text"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/validate"
|
||||
)
|
||||
|
||||
|
|
@ -39,35 +40,29 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
|||
l := p.log.WithField("func", "AccountUpdate")
|
||||
|
||||
if form.Discoverable != nil {
|
||||
if err := p.db.UpdateOneByPrimaryKey(ctx, "discoverable", *form.Discoverable, account); err != nil {
|
||||
return nil, fmt.Errorf("error updating discoverable: %s", err)
|
||||
}
|
||||
account.Discoverable = *form.Discoverable
|
||||
}
|
||||
|
||||
if form.Bot != nil {
|
||||
if err := p.db.UpdateOneByPrimaryKey(ctx, "bot", *form.Bot, account); err != nil {
|
||||
return nil, fmt.Errorf("error updating bot: %s", err)
|
||||
}
|
||||
account.Bot = *form.Bot
|
||||
}
|
||||
|
||||
if form.DisplayName != nil {
|
||||
if err := validate.DisplayName(*form.DisplayName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
displayName := text.RemoveHTML(*form.DisplayName) // no html allowed in display name
|
||||
if err := p.db.UpdateOneByPrimaryKey(ctx, "display_name", displayName, account); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
account.DisplayName = text.RemoveHTML(*form.DisplayName)
|
||||
}
|
||||
|
||||
if form.Note != nil {
|
||||
if err := validate.Note(*form.Note); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
note := text.SanitizeHTML(*form.Note) // html OK in note but sanitize it
|
||||
if err := p.db.UpdateOneByPrimaryKey(ctx, "note", note, account); err != nil {
|
||||
note, err := p.processNote(ctx, *form.Note, account.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
account.Note = note
|
||||
}
|
||||
|
||||
if form.Avatar != nil && form.Avatar.Size != 0 {
|
||||
|
|
@ -75,6 +70,8 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
account.AvatarMediaAttachmentID = avatarInfo.ID
|
||||
account.AvatarMediaAttachment = avatarInfo
|
||||
l.Tracef("new avatar info for account %s is %+v", account.ID, avatarInfo)
|
||||
}
|
||||
|
||||
|
|
@ -83,13 +80,13 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
account.HeaderMediaAttachmentID = headerInfo.ID
|
||||
account.HeaderMediaAttachment = headerInfo
|
||||
l.Tracef("new header info for account %s is %+v", account.ID, headerInfo)
|
||||
}
|
||||
|
||||
if form.Locked != nil {
|
||||
if err := p.db.UpdateOneByPrimaryKey(ctx, "locked", *form.Locked, account); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
account.Locked = *form.Locked
|
||||
}
|
||||
|
||||
if form.Source != nil {
|
||||
|
|
@ -97,31 +94,25 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
|||
if err := validate.Language(*form.Source.Language); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := p.db.UpdateOneByPrimaryKey(ctx, "language", *form.Source.Language, account); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
account.Language = *form.Source.Language
|
||||
}
|
||||
|
||||
if form.Source.Sensitive != nil {
|
||||
if err := p.db.UpdateOneByPrimaryKey(ctx, "locked", *form.Locked, account); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
account.Sensitive = *form.Source.Sensitive
|
||||
}
|
||||
|
||||
if form.Source.Privacy != nil {
|
||||
if err := validate.Privacy(*form.Source.Privacy); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := p.db.UpdateOneByPrimaryKey(ctx, "privacy", *form.Source.Privacy, account); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
privacy := p.tc.MastoVisToVis(apimodel.Visibility(*form.Source.Privacy))
|
||||
account.Privacy = privacy
|
||||
}
|
||||
}
|
||||
|
||||
// fetch the account with all updated values set
|
||||
updatedAccount, err := p.db.GetAccountByID(ctx, account.ID)
|
||||
updatedAccount, err := p.db.UpdateAccount(ctx, account)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not fetch updated account %s: %s", account.ID, err)
|
||||
return nil, fmt.Errorf("could not update account %s: %s", account.ID, err)
|
||||
}
|
||||
|
||||
p.fromClientAPI <- messages.FromClientAPI{
|
||||
|
|
@ -203,3 +194,27 @@ func (p *processor) UpdateHeader(ctx context.Context, header *multipart.FileHead
|
|||
|
||||
return headerInfo, f.Close()
|
||||
}
|
||||
|
||||
func (p *processor) processNote(ctx context.Context, note string, accountID string) (string, error) {
|
||||
if note == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
tagStrings := util.DeriveHashtagsFromText(note)
|
||||
tags, err := p.db.TagStringsToTags(ctx, tagStrings, accountID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
mentionStrings := util.DeriveMentionsFromText(note)
|
||||
mentions, err := p.db.MentionStringsToMentions(ctx, mentionStrings, accountID, "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// TODO: support emojis in account notes
|
||||
// emojiStrings := util.DeriveEmojisFromText(note)
|
||||
// emojis, err := p.db.EmojiStringsToEmojis(ctx, emojiStrings)
|
||||
|
||||
return p.formatter.FromPlain(ctx, note, mentions, tags), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateSimple() {
|
|||
|
||||
locked := true
|
||||
displayName := "new display name"
|
||||
note := ""
|
||||
note := "#hello here i am!"
|
||||
|
||||
form := &apimodel.UpdateCredentialsRequest{
|
||||
DisplayName: &displayName,
|
||||
|
|
@ -52,7 +52,7 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateSimple() {
|
|||
// fields on the profile should be updated
|
||||
suite.True(apiAccount.Locked)
|
||||
suite.Equal(displayName, apiAccount.DisplayName)
|
||||
suite.Empty(apiAccount.Note)
|
||||
suite.Equal(`<p><a href="http://localhost:8080/tags/hello" class="mention hashtag" rel="tag nofollow noreferrer noopener" target="_blank">#<span>hello</span></a> here i am!</p>`, apiAccount.Note)
|
||||
|
||||
// we should have an update in the client api channel
|
||||
msg := <-suite.fromClientAPIChan
|
||||
|
|
@ -67,7 +67,50 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateSimple() {
|
|||
suite.NoError(err)
|
||||
suite.True(dbAccount.Locked)
|
||||
suite.Equal(displayName, dbAccount.DisplayName)
|
||||
suite.Empty(dbAccount.Note)
|
||||
suite.Equal(`<p><a href="http://localhost:8080/tags/hello" class="mention hashtag" rel="tag nofollow noreferrer noopener" target="_blank">#<span>hello</span></a> here i am!</p>`, dbAccount.Note)
|
||||
}
|
||||
|
||||
func (suite *AccountUpdateTestSuite) TestAccountUpdateWithMention() {
|
||||
testAccount := suite.testAccounts["local_account_1"]
|
||||
|
||||
locked := true
|
||||
displayName := "new display name"
|
||||
note := `#hello here i am!
|
||||
|
||||
go check out @1happyturtle, they have a cool account!
|
||||
`
|
||||
noteExpected := `<p><a href="http://localhost:8080/tags/hello" class="mention hashtag" rel="tag nofollow noreferrer noopener" target="_blank">#<span>hello</span></a> here i am!<br><br>go check out <span class="h-card"><a href="http://localhost:8080/@1happyturtle" class="u-url mention" rel="nofollow noreferrer noopener" target="_blank">@<span>1happyturtle</span></a></span>, they have a cool account!</p>`
|
||||
|
||||
form := &apimodel.UpdateCredentialsRequest{
|
||||
DisplayName: &displayName,
|
||||
Locked: &locked,
|
||||
Note: ¬e,
|
||||
}
|
||||
|
||||
// should get no error from the update function, and an api model account returned
|
||||
apiAccount, err := suite.accountProcessor.Update(context.Background(), testAccount, form)
|
||||
suite.NoError(err)
|
||||
suite.NotNil(apiAccount)
|
||||
|
||||
// fields on the profile should be updated
|
||||
suite.True(apiAccount.Locked)
|
||||
suite.Equal(displayName, apiAccount.DisplayName)
|
||||
suite.Equal(noteExpected, apiAccount.Note)
|
||||
|
||||
// we should have an update in the client api channel
|
||||
msg := <-suite.fromClientAPIChan
|
||||
suite.Equal(ap.ActivityUpdate, msg.APActivityType)
|
||||
suite.Equal(ap.ObjectProfile, msg.APObjectType)
|
||||
suite.NotNil(msg.OriginAccount)
|
||||
suite.Equal(testAccount.ID, msg.OriginAccount.ID)
|
||||
suite.Nil(msg.TargetAccount)
|
||||
|
||||
// fields should be updated in the database as well
|
||||
dbAccount, err := suite.db.GetAccountByID(context.Background(), testAccount.ID)
|
||||
suite.NoError(err)
|
||||
suite.True(dbAccount.Locked)
|
||||
suite.Equal(displayName, dbAccount.DisplayName)
|
||||
suite.Equal(noteExpected, dbAccount.Note)
|
||||
}
|
||||
|
||||
func TestAccountUpdateTestSuite(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ func (p *processor) ProcessLanguage(ctx context.Context, form *apimodel.Advanced
|
|||
|
||||
func (p *processor) ProcessMentions(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error {
|
||||
menchies := []string{}
|
||||
gtsMenchies, err := p.db.MentionStringsToMentions(ctx, util.DeriveMentionsFromStatus(form.Status), accountID, status.ID)
|
||||
gtsMenchies, err := p.db.MentionStringsToMentions(ctx, util.DeriveMentionsFromText(form.Status), accountID, status.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating mentions from status: %s", err)
|
||||
}
|
||||
|
|
@ -217,7 +217,7 @@ func (p *processor) ProcessMentions(ctx context.Context, form *apimodel.Advanced
|
|||
|
||||
func (p *processor) ProcessTags(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error {
|
||||
tags := []string{}
|
||||
gtsTags, err := p.db.TagStringsToTags(ctx, util.DeriveHashtagsFromStatus(form.Status), accountID, status.ID)
|
||||
gtsTags, err := p.db.TagStringsToTags(ctx, util.DeriveHashtagsFromText(form.Status), accountID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating hashtags from status: %s", err)
|
||||
}
|
||||
|
|
@ -236,7 +236,7 @@ func (p *processor) ProcessTags(ctx context.Context, form *apimodel.AdvancedStat
|
|||
|
||||
func (p *processor) ProcessEmojis(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error {
|
||||
emojis := []string{}
|
||||
gtsEmojis, err := p.db.EmojiStringsToEmojis(ctx, util.DeriveEmojisFromStatus(form.Status), accountID, status.ID)
|
||||
gtsEmojis, err := p.db.EmojiStringsToEmojis(ctx, util.DeriveEmojisFromText(form.Status))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error generating emojis from status: %s", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,38 +25,38 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/regexes"
|
||||
)
|
||||
|
||||
// DeriveMentionsFromStatus takes a plaintext (ie., not html-formatted) status,
|
||||
// DeriveMentionsFromText takes a plaintext (ie., not html-formatted) text,
|
||||
// and applies a regex to it to return a deduplicated list of accounts
|
||||
// mentioned in that status.
|
||||
// mentioned in that text.
|
||||
//
|
||||
// It will look for fully-qualified account names in the form "@user@example.org".
|
||||
// or the form "@username" for local users.
|
||||
func DeriveMentionsFromStatus(status string) []string {
|
||||
func DeriveMentionsFromText(text string) []string {
|
||||
mentionedAccounts := []string{}
|
||||
for _, m := range regexes.MentionFinder.FindAllStringSubmatch(status, -1) {
|
||||
for _, m := range regexes.MentionFinder.FindAllStringSubmatch(text, -1) {
|
||||
mentionedAccounts = append(mentionedAccounts, m[1])
|
||||
}
|
||||
return UniqueStrings(mentionedAccounts)
|
||||
}
|
||||
|
||||
// DeriveHashtagsFromStatus takes a plaintext (ie., not html-formatted) status,
|
||||
// DeriveHashtagsFromText takes a plaintext (ie., not html-formatted) text,
|
||||
// and applies a regex to it to return a deduplicated list of hashtags
|
||||
// used in that status, without the leading #. The case of the returned
|
||||
// used in that text, without the leading #. The case of the returned
|
||||
// tags will be lowered, for consistency.
|
||||
func DeriveHashtagsFromStatus(status string) []string {
|
||||
func DeriveHashtagsFromText(text string) []string {
|
||||
tags := []string{}
|
||||
for _, m := range regexes.HashtagFinder.FindAllStringSubmatch(status, -1) {
|
||||
for _, m := range regexes.HashtagFinder.FindAllStringSubmatch(text, -1) {
|
||||
tags = append(tags, strings.TrimPrefix(m[1], "#"))
|
||||
}
|
||||
return UniqueStrings(tags)
|
||||
}
|
||||
|
||||
// DeriveEmojisFromStatus takes a plaintext (ie., not html-formatted) status,
|
||||
// DeriveEmojisFromText takes a plaintext (ie., not html-formatted) text,
|
||||
// and applies a regex to it to return a deduplicated list of emojis
|
||||
// used in that status, without the surround ::.
|
||||
func DeriveEmojisFromStatus(status string) []string {
|
||||
// used in that text, without the surrounding `::`
|
||||
func DeriveEmojisFromText(text string) []string {
|
||||
emojis := []string{}
|
||||
for _, m := range regexes.EmojiFinder.FindAllStringSubmatch(status, -1) {
|
||||
for _, m := range regexes.EmojiFinder.FindAllStringSubmatch(text, -1) {
|
||||
emojis = append(emojis, m[1])
|
||||
}
|
||||
return UniqueStrings(emojis)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ func (suite *StatusTestSuite) TestDeriveMentionsOK() {
|
|||
|
||||
`
|
||||
|
||||
menchies := util.DeriveMentionsFromStatus(statusText)
|
||||
menchies := util.DeriveMentionsFromText(statusText)
|
||||
assert.Len(suite.T(), menchies, 6)
|
||||
assert.Equal(suite.T(), "@dumpsterqueer@example.org", menchies[0])
|
||||
assert.Equal(suite.T(), "@someone_else@testing.best-horse.com", menchies[1])
|
||||
|
|
@ -57,7 +57,7 @@ func (suite *StatusTestSuite) TestDeriveMentionsOK() {
|
|||
|
||||
func (suite *StatusTestSuite) TestDeriveMentionsEmpty() {
|
||||
statusText := ``
|
||||
menchies := util.DeriveMentionsFromStatus(statusText)
|
||||
menchies := util.DeriveMentionsFromText(statusText)
|
||||
assert.Len(suite.T(), menchies, 0)
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ func (suite *StatusTestSuite) TestDeriveHashtagsOK() {
|
|||
|
||||
#111111 thisalsoshouldn'twork#### ##`
|
||||
|
||||
tags := util.DeriveHashtagsFromStatus(statusText)
|
||||
tags := util.DeriveHashtagsFromText(statusText)
|
||||
assert.Len(suite.T(), tags, 5)
|
||||
assert.Equal(suite.T(), "testing123", tags[0])
|
||||
assert.Equal(suite.T(), "also", tags[1])
|
||||
|
|
@ -97,7 +97,7 @@ Here's some normal text with an :emoji: at the end
|
|||
:underscores_ok_too:
|
||||
`
|
||||
|
||||
tags := util.DeriveEmojisFromStatus(statusText)
|
||||
tags := util.DeriveEmojisFromText(statusText)
|
||||
assert.Len(suite.T(), tags, 7)
|
||||
assert.Equal(suite.T(), "test", tags[0])
|
||||
assert.Equal(suite.T(), "another", tags[1])
|
||||
|
|
@ -115,9 +115,9 @@ func (suite *StatusTestSuite) TestDeriveMultiple() {
|
|||
|
||||
Text`
|
||||
|
||||
ms := util.DeriveMentionsFromStatus(statusText)
|
||||
hs := util.DeriveHashtagsFromStatus(statusText)
|
||||
es := util.DeriveEmojisFromStatus(statusText)
|
||||
ms := util.DeriveMentionsFromText(statusText)
|
||||
hs := util.DeriveHashtagsFromText(statusText)
|
||||
es := util.DeriveEmojisFromText(statusText)
|
||||
|
||||
assert.Len(suite.T(), ms, 1)
|
||||
assert.Equal(suite.T(), "@foss_satan@fossbros-anonymous.io", ms[0])
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"fmt"
|
||||
"net/mail"
|
||||
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/regexes"
|
||||
pwv "github.com/wagslane/go-password-validator"
|
||||
"golang.org/x/text/language"
|
||||
|
|
@ -126,8 +127,14 @@ func Note(note string) error {
|
|||
|
||||
// Privacy checks that the desired privacy setting is valid
|
||||
func Privacy(privacy string) error {
|
||||
// TODO: add some validation logic here -- length, characters, etc
|
||||
return nil
|
||||
if privacy == "" {
|
||||
return fmt.Errorf("empty string for privacy not allowed")
|
||||
}
|
||||
switch apimodel.Visibility(privacy) {
|
||||
case apimodel.VisibilityDirect, apimodel.VisibilityMutualsOnly, apimodel.VisibilityPrivate, apimodel.VisibilityPublic, apimodel.VisibilityUnlisted:
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("privacy %s was not recognized", privacy)
|
||||
}
|
||||
|
||||
// EmojiShortcode just runs the given shortcode through the regular expression
|
||||
|
|
|
|||
20
vendor/github.com/fatih/color/LICENSE.md
generated
vendored
20
vendor/github.com/fatih/color/LICENSE.md
generated
vendored
|
|
@ -1,20 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Fatih Arslan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
173
vendor/github.com/fatih/color/README.md
generated
vendored
173
vendor/github.com/fatih/color/README.md
generated
vendored
|
|
@ -1,173 +0,0 @@
|
|||
# color [](https://github.com/fatih/color/actions) [](https://pkg.go.dev/github.com/fatih/color)
|
||||
|
||||
Color lets you use colorized outputs in terms of [ANSI Escape
|
||||
Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It
|
||||
has support for Windows too! The API can be used in several ways, pick one that
|
||||
suits you.
|
||||
|
||||

|
||||
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get github.com/fatih/color
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Standard colors
|
||||
|
||||
```go
|
||||
// Print with default helper functions
|
||||
color.Cyan("Prints text in cyan.")
|
||||
|
||||
// A newline will be appended automatically
|
||||
color.Blue("Prints %s in blue.", "text")
|
||||
|
||||
// These are using the default foreground colors
|
||||
color.Red("We have red")
|
||||
color.Magenta("And many others ..")
|
||||
|
||||
```
|
||||
|
||||
### Mix and reuse colors
|
||||
|
||||
```go
|
||||
// Create a new color object
|
||||
c := color.New(color.FgCyan).Add(color.Underline)
|
||||
c.Println("Prints cyan text with an underline.")
|
||||
|
||||
// Or just add them to New()
|
||||
d := color.New(color.FgCyan, color.Bold)
|
||||
d.Printf("This prints bold cyan %s\n", "too!.")
|
||||
|
||||
// Mix up foreground and background colors, create new mixes!
|
||||
red := color.New(color.FgRed)
|
||||
|
||||
boldRed := red.Add(color.Bold)
|
||||
boldRed.Println("This will print text in bold red.")
|
||||
|
||||
whiteBackground := red.Add(color.BgWhite)
|
||||
whiteBackground.Println("Red text with white background.")
|
||||
```
|
||||
|
||||
### Use your own output (io.Writer)
|
||||
|
||||
```go
|
||||
// Use your own io.Writer output
|
||||
color.New(color.FgBlue).Fprintln(myWriter, "blue color!")
|
||||
|
||||
blue := color.New(color.FgBlue)
|
||||
blue.Fprint(writer, "This will print text in blue.")
|
||||
```
|
||||
|
||||
### Custom print functions (PrintFunc)
|
||||
|
||||
```go
|
||||
// Create a custom print function for convenience
|
||||
red := color.New(color.FgRed).PrintfFunc()
|
||||
red("Warning")
|
||||
red("Error: %s", err)
|
||||
|
||||
// Mix up multiple attributes
|
||||
notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
|
||||
notice("Don't forget this...")
|
||||
```
|
||||
|
||||
### Custom fprint functions (FprintFunc)
|
||||
|
||||
```go
|
||||
blue := color.New(FgBlue).FprintfFunc()
|
||||
blue(myWriter, "important notice: %s", stars)
|
||||
|
||||
// Mix up with multiple attributes
|
||||
success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
|
||||
success(myWriter, "Don't forget this...")
|
||||
```
|
||||
|
||||
### Insert into noncolor strings (SprintFunc)
|
||||
|
||||
```go
|
||||
// Create SprintXxx functions to mix strings with other non-colorized strings:
|
||||
yellow := color.New(color.FgYellow).SprintFunc()
|
||||
red := color.New(color.FgRed).SprintFunc()
|
||||
fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error"))
|
||||
|
||||
info := color.New(color.FgWhite, color.BgGreen).SprintFunc()
|
||||
fmt.Printf("This %s rocks!\n", info("package"))
|
||||
|
||||
// Use helper functions
|
||||
fmt.Println("This", color.RedString("warning"), "should be not neglected.")
|
||||
fmt.Printf("%v %v\n", color.GreenString("Info:"), "an important message.")
|
||||
|
||||
// Windows supported too! Just don't forget to change the output to color.Output
|
||||
fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
|
||||
```
|
||||
|
||||
### Plug into existing code
|
||||
|
||||
```go
|
||||
// Use handy standard colors
|
||||
color.Set(color.FgYellow)
|
||||
|
||||
fmt.Println("Existing text will now be in yellow")
|
||||
fmt.Printf("This one %s\n", "too")
|
||||
|
||||
color.Unset() // Don't forget to unset
|
||||
|
||||
// You can mix up parameters
|
||||
color.Set(color.FgMagenta, color.Bold)
|
||||
defer color.Unset() // Use it in your function
|
||||
|
||||
fmt.Println("All text will now be bold magenta.")
|
||||
```
|
||||
|
||||
### Disable/Enable color
|
||||
|
||||
There might be a case where you want to explicitly disable/enable color output. the
|
||||
`go-isatty` package will automatically disable color output for non-tty output streams
|
||||
(for example if the output were piped directly to `less`)
|
||||
|
||||
`Color` has support to disable/enable colors both globally and for single color
|
||||
definitions. For example suppose you have a CLI app and a `--no-color` bool flag. You
|
||||
can easily disable the color output with:
|
||||
|
||||
```go
|
||||
|
||||
var flagNoColor = flag.Bool("no-color", false, "Disable color output")
|
||||
|
||||
if *flagNoColor {
|
||||
color.NoColor = true // disables colorized output
|
||||
}
|
||||
```
|
||||
|
||||
It also has support for single color definitions (local). You can
|
||||
disable/enable color output on the fly:
|
||||
|
||||
```go
|
||||
c := color.New(color.FgCyan)
|
||||
c.Println("Prints cyan text")
|
||||
|
||||
c.DisableColor()
|
||||
c.Println("This is printed without any color")
|
||||
|
||||
c.EnableColor()
|
||||
c.Println("This prints again cyan...")
|
||||
```
|
||||
|
||||
## Todo
|
||||
|
||||
* Save/Return previous values
|
||||
* Evaluate fmt.Formatter interface
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
* [Fatih Arslan](https://github.com/fatih)
|
||||
* Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable)
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details
|
||||
|
||||
603
vendor/github.com/fatih/color/color.go
generated
vendored
603
vendor/github.com/fatih/color/color.go
generated
vendored
|
|
@ -1,603 +0,0 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
var (
|
||||
// NoColor defines if the output is colorized or not. It's dynamically set to
|
||||
// false or true based on the stdout's file descriptor referring to a terminal
|
||||
// or not. This is a global option and affects all colors. For more control
|
||||
// over each color block use the methods DisableColor() individually.
|
||||
NoColor = os.Getenv("TERM") == "dumb" ||
|
||||
(!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()))
|
||||
|
||||
// Output defines the standard output of the print functions. By default
|
||||
// os.Stdout is used.
|
||||
Output = colorable.NewColorableStdout()
|
||||
|
||||
// Error defines a color supporting writer for os.Stderr.
|
||||
Error = colorable.NewColorableStderr()
|
||||
|
||||
// colorsCache is used to reduce the count of created Color objects and
|
||||
// allows to reuse already created objects with required Attribute.
|
||||
colorsCache = make(map[Attribute]*Color)
|
||||
colorsCacheMu sync.Mutex // protects colorsCache
|
||||
)
|
||||
|
||||
// Color defines a custom color object which is defined by SGR parameters.
|
||||
type Color struct {
|
||||
params []Attribute
|
||||
noColor *bool
|
||||
}
|
||||
|
||||
// Attribute defines a single SGR Code
|
||||
type Attribute int
|
||||
|
||||
const escape = "\x1b"
|
||||
|
||||
// Base attributes
|
||||
const (
|
||||
Reset Attribute = iota
|
||||
Bold
|
||||
Faint
|
||||
Italic
|
||||
Underline
|
||||
BlinkSlow
|
||||
BlinkRapid
|
||||
ReverseVideo
|
||||
Concealed
|
||||
CrossedOut
|
||||
)
|
||||
|
||||
// Foreground text colors
|
||||
const (
|
||||
FgBlack Attribute = iota + 30
|
||||
FgRed
|
||||
FgGreen
|
||||
FgYellow
|
||||
FgBlue
|
||||
FgMagenta
|
||||
FgCyan
|
||||
FgWhite
|
||||
)
|
||||
|
||||
// Foreground Hi-Intensity text colors
|
||||
const (
|
||||
FgHiBlack Attribute = iota + 90
|
||||
FgHiRed
|
||||
FgHiGreen
|
||||
FgHiYellow
|
||||
FgHiBlue
|
||||
FgHiMagenta
|
||||
FgHiCyan
|
||||
FgHiWhite
|
||||
)
|
||||
|
||||
// Background text colors
|
||||
const (
|
||||
BgBlack Attribute = iota + 40
|
||||
BgRed
|
||||
BgGreen
|
||||
BgYellow
|
||||
BgBlue
|
||||
BgMagenta
|
||||
BgCyan
|
||||
BgWhite
|
||||
)
|
||||
|
||||
// Background Hi-Intensity text colors
|
||||
const (
|
||||
BgHiBlack Attribute = iota + 100
|
||||
BgHiRed
|
||||
BgHiGreen
|
||||
BgHiYellow
|
||||
BgHiBlue
|
||||
BgHiMagenta
|
||||
BgHiCyan
|
||||
BgHiWhite
|
||||
)
|
||||
|
||||
// New returns a newly created color object.
|
||||
func New(value ...Attribute) *Color {
|
||||
c := &Color{params: make([]Attribute, 0)}
|
||||
c.Add(value...)
|
||||
return c
|
||||
}
|
||||
|
||||
// Set sets the given parameters immediately. It will change the color of
|
||||
// output with the given SGR parameters until color.Unset() is called.
|
||||
func Set(p ...Attribute) *Color {
|
||||
c := New(p...)
|
||||
c.Set()
|
||||
return c
|
||||
}
|
||||
|
||||
// Unset resets all escape attributes and clears the output. Usually should
|
||||
// be called after Set().
|
||||
func Unset() {
|
||||
if NoColor {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(Output, "%s[%dm", escape, Reset)
|
||||
}
|
||||
|
||||
// Set sets the SGR sequence.
|
||||
func (c *Color) Set() *Color {
|
||||
if c.isNoColorSet() {
|
||||
return c
|
||||
}
|
||||
|
||||
fmt.Fprintf(Output, c.format())
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Color) unset() {
|
||||
if c.isNoColorSet() {
|
||||
return
|
||||
}
|
||||
|
||||
Unset()
|
||||
}
|
||||
|
||||
func (c *Color) setWriter(w io.Writer) *Color {
|
||||
if c.isNoColorSet() {
|
||||
return c
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, c.format())
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Color) unsetWriter(w io.Writer) {
|
||||
if c.isNoColorSet() {
|
||||
return
|
||||
}
|
||||
|
||||
if NoColor {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "%s[%dm", escape, Reset)
|
||||
}
|
||||
|
||||
// Add is used to chain SGR parameters. Use as many as parameters to combine
|
||||
// and create custom color objects. Example: Add(color.FgRed, color.Underline).
|
||||
func (c *Color) Add(value ...Attribute) *Color {
|
||||
c.params = append(c.params, value...)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Color) prepend(value Attribute) {
|
||||
c.params = append(c.params, 0)
|
||||
copy(c.params[1:], c.params[0:])
|
||||
c.params[0] = value
|
||||
}
|
||||
|
||||
// Fprint formats using the default formats for its operands and writes to w.
|
||||
// Spaces are added between operands when neither is a string.
|
||||
// It returns the number of bytes written and any write error encountered.
|
||||
// On Windows, users should wrap w with colorable.NewColorable() if w is of
|
||||
// type *os.File.
|
||||
func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
|
||||
c.setWriter(w)
|
||||
defer c.unsetWriter(w)
|
||||
|
||||
return fmt.Fprint(w, a...)
|
||||
}
|
||||
|
||||
// Print formats using the default formats for its operands and writes to
|
||||
// standard output. Spaces are added between operands when neither is a
|
||||
// string. It returns the number of bytes written and any write error
|
||||
// encountered. This is the standard fmt.Print() method wrapped with the given
|
||||
// color.
|
||||
func (c *Color) Print(a ...interface{}) (n int, err error) {
|
||||
c.Set()
|
||||
defer c.unset()
|
||||
|
||||
return fmt.Fprint(Output, a...)
|
||||
}
|
||||
|
||||
// Fprintf formats according to a format specifier and writes to w.
|
||||
// It returns the number of bytes written and any write error encountered.
|
||||
// On Windows, users should wrap w with colorable.NewColorable() if w is of
|
||||
// type *os.File.
|
||||
func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
|
||||
c.setWriter(w)
|
||||
defer c.unsetWriter(w)
|
||||
|
||||
return fmt.Fprintf(w, format, a...)
|
||||
}
|
||||
|
||||
// Printf formats according to a format specifier and writes to standard output.
|
||||
// It returns the number of bytes written and any write error encountered.
|
||||
// This is the standard fmt.Printf() method wrapped with the given color.
|
||||
func (c *Color) Printf(format string, a ...interface{}) (n int, err error) {
|
||||
c.Set()
|
||||
defer c.unset()
|
||||
|
||||
return fmt.Fprintf(Output, format, a...)
|
||||
}
|
||||
|
||||
// Fprintln formats using the default formats for its operands and writes to w.
|
||||
// Spaces are always added between operands and a newline is appended.
|
||||
// On Windows, users should wrap w with colorable.NewColorable() if w is of
|
||||
// type *os.File.
|
||||
func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
|
||||
c.setWriter(w)
|
||||
defer c.unsetWriter(w)
|
||||
|
||||
return fmt.Fprintln(w, a...)
|
||||
}
|
||||
|
||||
// Println formats using the default formats for its operands and writes to
|
||||
// standard output. Spaces are always added between operands and a newline is
|
||||
// appended. It returns the number of bytes written and any write error
|
||||
// encountered. This is the standard fmt.Print() method wrapped with the given
|
||||
// color.
|
||||
func (c *Color) Println(a ...interface{}) (n int, err error) {
|
||||
c.Set()
|
||||
defer c.unset()
|
||||
|
||||
return fmt.Fprintln(Output, a...)
|
||||
}
|
||||
|
||||
// Sprint is just like Print, but returns a string instead of printing it.
|
||||
func (c *Color) Sprint(a ...interface{}) string {
|
||||
return c.wrap(fmt.Sprint(a...))
|
||||
}
|
||||
|
||||
// Sprintln is just like Println, but returns a string instead of printing it.
|
||||
func (c *Color) Sprintln(a ...interface{}) string {
|
||||
return c.wrap(fmt.Sprintln(a...))
|
||||
}
|
||||
|
||||
// Sprintf is just like Printf, but returns a string instead of printing it.
|
||||
func (c *Color) Sprintf(format string, a ...interface{}) string {
|
||||
return c.wrap(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// FprintFunc returns a new function that prints the passed arguments as
|
||||
// colorized with color.Fprint().
|
||||
func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) {
|
||||
return func(w io.Writer, a ...interface{}) {
|
||||
c.Fprint(w, a...)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintFunc returns a new function that prints the passed arguments as
|
||||
// colorized with color.Print().
|
||||
func (c *Color) PrintFunc() func(a ...interface{}) {
|
||||
return func(a ...interface{}) {
|
||||
c.Print(a...)
|
||||
}
|
||||
}
|
||||
|
||||
// FprintfFunc returns a new function that prints the passed arguments as
|
||||
// colorized with color.Fprintf().
|
||||
func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) {
|
||||
return func(w io.Writer, format string, a ...interface{}) {
|
||||
c.Fprintf(w, format, a...)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintfFunc returns a new function that prints the passed arguments as
|
||||
// colorized with color.Printf().
|
||||
func (c *Color) PrintfFunc() func(format string, a ...interface{}) {
|
||||
return func(format string, a ...interface{}) {
|
||||
c.Printf(format, a...)
|
||||
}
|
||||
}
|
||||
|
||||
// FprintlnFunc returns a new function that prints the passed arguments as
|
||||
// colorized with color.Fprintln().
|
||||
func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) {
|
||||
return func(w io.Writer, a ...interface{}) {
|
||||
c.Fprintln(w, a...)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintlnFunc returns a new function that prints the passed arguments as
|
||||
// colorized with color.Println().
|
||||
func (c *Color) PrintlnFunc() func(a ...interface{}) {
|
||||
return func(a ...interface{}) {
|
||||
c.Println(a...)
|
||||
}
|
||||
}
|
||||
|
||||
// SprintFunc returns a new function that returns colorized strings for the
|
||||
// given arguments with fmt.Sprint(). Useful to put into or mix into other
|
||||
// string. Windows users should use this in conjunction with color.Output, example:
|
||||
//
|
||||
// put := New(FgYellow).SprintFunc()
|
||||
// fmt.Fprintf(color.Output, "This is a %s", put("warning"))
|
||||
func (c *Color) SprintFunc() func(a ...interface{}) string {
|
||||
return func(a ...interface{}) string {
|
||||
return c.wrap(fmt.Sprint(a...))
|
||||
}
|
||||
}
|
||||
|
||||
// SprintfFunc returns a new function that returns colorized strings for the
|
||||
// given arguments with fmt.Sprintf(). Useful to put into or mix into other
|
||||
// string. Windows users should use this in conjunction with color.Output.
|
||||
func (c *Color) SprintfFunc() func(format string, a ...interface{}) string {
|
||||
return func(format string, a ...interface{}) string {
|
||||
return c.wrap(fmt.Sprintf(format, a...))
|
||||
}
|
||||
}
|
||||
|
||||
// SprintlnFunc returns a new function that returns colorized strings for the
|
||||
// given arguments with fmt.Sprintln(). Useful to put into or mix into other
|
||||
// string. Windows users should use this in conjunction with color.Output.
|
||||
func (c *Color) SprintlnFunc() func(a ...interface{}) string {
|
||||
return func(a ...interface{}) string {
|
||||
return c.wrap(fmt.Sprintln(a...))
|
||||
}
|
||||
}
|
||||
|
||||
// sequence returns a formatted SGR sequence to be plugged into a "\x1b[...m"
|
||||
// an example output might be: "1;36" -> bold cyan
|
||||
func (c *Color) sequence() string {
|
||||
format := make([]string, len(c.params))
|
||||
for i, v := range c.params {
|
||||
format[i] = strconv.Itoa(int(v))
|
||||
}
|
||||
|
||||
return strings.Join(format, ";")
|
||||
}
|
||||
|
||||
// wrap wraps the s string with the colors attributes. The string is ready to
|
||||
// be printed.
|
||||
func (c *Color) wrap(s string) string {
|
||||
if c.isNoColorSet() {
|
||||
return s
|
||||
}
|
||||
|
||||
return c.format() + s + c.unformat()
|
||||
}
|
||||
|
||||
func (c *Color) format() string {
|
||||
return fmt.Sprintf("%s[%sm", escape, c.sequence())
|
||||
}
|
||||
|
||||
func (c *Color) unformat() string {
|
||||
return fmt.Sprintf("%s[%dm", escape, Reset)
|
||||
}
|
||||
|
||||
// DisableColor disables the color output. Useful to not change any existing
|
||||
// code and still being able to output. Can be used for flags like
|
||||
// "--no-color". To enable back use EnableColor() method.
|
||||
func (c *Color) DisableColor() {
|
||||
c.noColor = boolPtr(true)
|
||||
}
|
||||
|
||||
// EnableColor enables the color output. Use it in conjunction with
|
||||
// DisableColor(). Otherwise this method has no side effects.
|
||||
func (c *Color) EnableColor() {
|
||||
c.noColor = boolPtr(false)
|
||||
}
|
||||
|
||||
func (c *Color) isNoColorSet() bool {
|
||||
// check first if we have user setted action
|
||||
if c.noColor != nil {
|
||||
return *c.noColor
|
||||
}
|
||||
|
||||
// if not return the global option, which is disabled by default
|
||||
return NoColor
|
||||
}
|
||||
|
||||
// Equals returns a boolean value indicating whether two colors are equal.
|
||||
func (c *Color) Equals(c2 *Color) bool {
|
||||
if len(c.params) != len(c2.params) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, attr := range c.params {
|
||||
if !c2.attrExists(attr) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Color) attrExists(a Attribute) bool {
|
||||
for _, attr := range c.params {
|
||||
if attr == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func boolPtr(v bool) *bool {
|
||||
return &v
|
||||
}
|
||||
|
||||
func getCachedColor(p Attribute) *Color {
|
||||
colorsCacheMu.Lock()
|
||||
defer colorsCacheMu.Unlock()
|
||||
|
||||
c, ok := colorsCache[p]
|
||||
if !ok {
|
||||
c = New(p)
|
||||
colorsCache[p] = c
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func colorPrint(format string, p Attribute, a ...interface{}) {
|
||||
c := getCachedColor(p)
|
||||
|
||||
if !strings.HasSuffix(format, "\n") {
|
||||
format += "\n"
|
||||
}
|
||||
|
||||
if len(a) == 0 {
|
||||
c.Print(format)
|
||||
} else {
|
||||
c.Printf(format, a...)
|
||||
}
|
||||
}
|
||||
|
||||
func colorString(format string, p Attribute, a ...interface{}) string {
|
||||
c := getCachedColor(p)
|
||||
|
||||
if len(a) == 0 {
|
||||
return c.SprintFunc()(format)
|
||||
}
|
||||
|
||||
return c.SprintfFunc()(format, a...)
|
||||
}
|
||||
|
||||
// Black is a convenient helper function to print with black foreground. A
|
||||
// newline is appended to format by default.
|
||||
func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) }
|
||||
|
||||
// Red is a convenient helper function to print with red foreground. A
|
||||
// newline is appended to format by default.
|
||||
func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) }
|
||||
|
||||
// Green is a convenient helper function to print with green foreground. A
|
||||
// newline is appended to format by default.
|
||||
func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) }
|
||||
|
||||
// Yellow is a convenient helper function to print with yellow foreground.
|
||||
// A newline is appended to format by default.
|
||||
func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) }
|
||||
|
||||
// Blue is a convenient helper function to print with blue foreground. A
|
||||
// newline is appended to format by default.
|
||||
func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) }
|
||||
|
||||
// Magenta is a convenient helper function to print with magenta foreground.
|
||||
// A newline is appended to format by default.
|
||||
func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) }
|
||||
|
||||
// Cyan is a convenient helper function to print with cyan foreground. A
|
||||
// newline is appended to format by default.
|
||||
func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) }
|
||||
|
||||
// White is a convenient helper function to print with white foreground. A
|
||||
// newline is appended to format by default.
|
||||
func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) }
|
||||
|
||||
// BlackString is a convenient helper function to return a string with black
|
||||
// foreground.
|
||||
func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) }
|
||||
|
||||
// RedString is a convenient helper function to return a string with red
|
||||
// foreground.
|
||||
func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) }
|
||||
|
||||
// GreenString is a convenient helper function to return a string with green
|
||||
// foreground.
|
||||
func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) }
|
||||
|
||||
// YellowString is a convenient helper function to return a string with yellow
|
||||
// foreground.
|
||||
func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) }
|
||||
|
||||
// BlueString is a convenient helper function to return a string with blue
|
||||
// foreground.
|
||||
func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) }
|
||||
|
||||
// MagentaString is a convenient helper function to return a string with magenta
|
||||
// foreground.
|
||||
func MagentaString(format string, a ...interface{}) string {
|
||||
return colorString(format, FgMagenta, a...)
|
||||
}
|
||||
|
||||
// CyanString is a convenient helper function to return a string with cyan
|
||||
// foreground.
|
||||
func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) }
|
||||
|
||||
// WhiteString is a convenient helper function to return a string with white
|
||||
// foreground.
|
||||
func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) }
|
||||
|
||||
// HiBlack is a convenient helper function to print with hi-intensity black foreground. A
|
||||
// newline is appended to format by default.
|
||||
func HiBlack(format string, a ...interface{}) { colorPrint(format, FgHiBlack, a...) }
|
||||
|
||||
// HiRed is a convenient helper function to print with hi-intensity red foreground. A
|
||||
// newline is appended to format by default.
|
||||
func HiRed(format string, a ...interface{}) { colorPrint(format, FgHiRed, a...) }
|
||||
|
||||
// HiGreen is a convenient helper function to print with hi-intensity green foreground. A
|
||||
// newline is appended to format by default.
|
||||
func HiGreen(format string, a ...interface{}) { colorPrint(format, FgHiGreen, a...) }
|
||||
|
||||
// HiYellow is a convenient helper function to print with hi-intensity yellow foreground.
|
||||
// A newline is appended to format by default.
|
||||
func HiYellow(format string, a ...interface{}) { colorPrint(format, FgHiYellow, a...) }
|
||||
|
||||
// HiBlue is a convenient helper function to print with hi-intensity blue foreground. A
|
||||
// newline is appended to format by default.
|
||||
func HiBlue(format string, a ...interface{}) { colorPrint(format, FgHiBlue, a...) }
|
||||
|
||||
// HiMagenta is a convenient helper function to print with hi-intensity magenta foreground.
|
||||
// A newline is appended to format by default.
|
||||
func HiMagenta(format string, a ...interface{}) { colorPrint(format, FgHiMagenta, a...) }
|
||||
|
||||
// HiCyan is a convenient helper function to print with hi-intensity cyan foreground. A
|
||||
// newline is appended to format by default.
|
||||
func HiCyan(format string, a ...interface{}) { colorPrint(format, FgHiCyan, a...) }
|
||||
|
||||
// HiWhite is a convenient helper function to print with hi-intensity white foreground. A
|
||||
// newline is appended to format by default.
|
||||
func HiWhite(format string, a ...interface{}) { colorPrint(format, FgHiWhite, a...) }
|
||||
|
||||
// HiBlackString is a convenient helper function to return a string with hi-intensity black
|
||||
// foreground.
|
||||
func HiBlackString(format string, a ...interface{}) string {
|
||||
return colorString(format, FgHiBlack, a...)
|
||||
}
|
||||
|
||||
// HiRedString is a convenient helper function to return a string with hi-intensity red
|
||||
// foreground.
|
||||
func HiRedString(format string, a ...interface{}) string { return colorString(format, FgHiRed, a...) }
|
||||
|
||||
// HiGreenString is a convenient helper function to return a string with hi-intensity green
|
||||
// foreground.
|
||||
func HiGreenString(format string, a ...interface{}) string {
|
||||
return colorString(format, FgHiGreen, a...)
|
||||
}
|
||||
|
||||
// HiYellowString is a convenient helper function to return a string with hi-intensity yellow
|
||||
// foreground.
|
||||
func HiYellowString(format string, a ...interface{}) string {
|
||||
return colorString(format, FgHiYellow, a...)
|
||||
}
|
||||
|
||||
// HiBlueString is a convenient helper function to return a string with hi-intensity blue
|
||||
// foreground.
|
||||
func HiBlueString(format string, a ...interface{}) string { return colorString(format, FgHiBlue, a...) }
|
||||
|
||||
// HiMagentaString is a convenient helper function to return a string with hi-intensity magenta
|
||||
// foreground.
|
||||
func HiMagentaString(format string, a ...interface{}) string {
|
||||
return colorString(format, FgHiMagenta, a...)
|
||||
}
|
||||
|
||||
// HiCyanString is a convenient helper function to return a string with hi-intensity cyan
|
||||
// foreground.
|
||||
func HiCyanString(format string, a ...interface{}) string { return colorString(format, FgHiCyan, a...) }
|
||||
|
||||
// HiWhiteString is a convenient helper function to return a string with hi-intensity white
|
||||
// foreground.
|
||||
func HiWhiteString(format string, a ...interface{}) string {
|
||||
return colorString(format, FgHiWhite, a...)
|
||||
}
|
||||
133
vendor/github.com/fatih/color/doc.go
generated
vendored
133
vendor/github.com/fatih/color/doc.go
generated
vendored
|
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
Package color is an ANSI color package to output colorized or SGR defined
|
||||
output to the standard output. The API can be used in several way, pick one
|
||||
that suits you.
|
||||
|
||||
Use simple and default helper functions with predefined foreground colors:
|
||||
|
||||
color.Cyan("Prints text in cyan.")
|
||||
|
||||
// a newline will be appended automatically
|
||||
color.Blue("Prints %s in blue.", "text")
|
||||
|
||||
// More default foreground colors..
|
||||
color.Red("We have red")
|
||||
color.Yellow("Yellow color too!")
|
||||
color.Magenta("And many others ..")
|
||||
|
||||
// Hi-intensity colors
|
||||
color.HiGreen("Bright green color.")
|
||||
color.HiBlack("Bright black means gray..")
|
||||
color.HiWhite("Shiny white color!")
|
||||
|
||||
However there are times where custom color mixes are required. Below are some
|
||||
examples to create custom color objects and use the print functions of each
|
||||
separate color object.
|
||||
|
||||
// Create a new color object
|
||||
c := color.New(color.FgCyan).Add(color.Underline)
|
||||
c.Println("Prints cyan text with an underline.")
|
||||
|
||||
// Or just add them to New()
|
||||
d := color.New(color.FgCyan, color.Bold)
|
||||
d.Printf("This prints bold cyan %s\n", "too!.")
|
||||
|
||||
|
||||
// Mix up foreground and background colors, create new mixes!
|
||||
red := color.New(color.FgRed)
|
||||
|
||||
boldRed := red.Add(color.Bold)
|
||||
boldRed.Println("This will print text in bold red.")
|
||||
|
||||
whiteBackground := red.Add(color.BgWhite)
|
||||
whiteBackground.Println("Red text with White background.")
|
||||
|
||||
// Use your own io.Writer output
|
||||
color.New(color.FgBlue).Fprintln(myWriter, "blue color!")
|
||||
|
||||
blue := color.New(color.FgBlue)
|
||||
blue.Fprint(myWriter, "This will print text in blue.")
|
||||
|
||||
You can create PrintXxx functions to simplify even more:
|
||||
|
||||
// Create a custom print function for convenient
|
||||
red := color.New(color.FgRed).PrintfFunc()
|
||||
red("warning")
|
||||
red("error: %s", err)
|
||||
|
||||
// Mix up multiple attributes
|
||||
notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
|
||||
notice("don't forget this...")
|
||||
|
||||
You can also FprintXxx functions to pass your own io.Writer:
|
||||
|
||||
blue := color.New(FgBlue).FprintfFunc()
|
||||
blue(myWriter, "important notice: %s", stars)
|
||||
|
||||
// Mix up with multiple attributes
|
||||
success := color.New(color.Bold, color.FgGreen).FprintlnFunc()
|
||||
success(myWriter, don't forget this...")
|
||||
|
||||
|
||||
Or create SprintXxx functions to mix strings with other non-colorized strings:
|
||||
|
||||
yellow := New(FgYellow).SprintFunc()
|
||||
red := New(FgRed).SprintFunc()
|
||||
|
||||
fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error"))
|
||||
|
||||
info := New(FgWhite, BgGreen).SprintFunc()
|
||||
fmt.Printf("this %s rocks!\n", info("package"))
|
||||
|
||||
Windows support is enabled by default. All Print functions work as intended.
|
||||
However only for color.SprintXXX functions, user should use fmt.FprintXXX and
|
||||
set the output to color.Output:
|
||||
|
||||
fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
|
||||
|
||||
info := New(FgWhite, BgGreen).SprintFunc()
|
||||
fmt.Fprintf(color.Output, "this %s rocks!\n", info("package"))
|
||||
|
||||
Using with existing code is possible. Just use the Set() method to set the
|
||||
standard output to the given parameters. That way a rewrite of an existing
|
||||
code is not required.
|
||||
|
||||
// Use handy standard colors.
|
||||
color.Set(color.FgYellow)
|
||||
|
||||
fmt.Println("Existing text will be now in Yellow")
|
||||
fmt.Printf("This one %s\n", "too")
|
||||
|
||||
color.Unset() // don't forget to unset
|
||||
|
||||
// You can mix up parameters
|
||||
color.Set(color.FgMagenta, color.Bold)
|
||||
defer color.Unset() // use it in your function
|
||||
|
||||
fmt.Println("All text will be now bold magenta.")
|
||||
|
||||
There might be a case where you want to disable color output (for example to
|
||||
pipe the standard output of your app to somewhere else). `Color` has support to
|
||||
disable colors both globally and for single color definition. For example
|
||||
suppose you have a CLI app and a `--no-color` bool flag. You can easily disable
|
||||
the color output with:
|
||||
|
||||
var flagNoColor = flag.Bool("no-color", false, "Disable color output")
|
||||
|
||||
if *flagNoColor {
|
||||
color.NoColor = true // disables colorized output
|
||||
}
|
||||
|
||||
It also has support for single color definitions (local). You can
|
||||
disable/enable color output on the fly:
|
||||
|
||||
c := color.New(color.FgCyan)
|
||||
c.Println("Prints cyan text")
|
||||
|
||||
c.DisableColor()
|
||||
c.Println("This is printed without any color")
|
||||
|
||||
c.EnableColor()
|
||||
c.Println("This prints again cyan...")
|
||||
*/
|
||||
package color
|
||||
15
vendor/github.com/mattn/go-colorable/.travis.yml
generated
vendored
15
vendor/github.com/mattn/go-colorable/.travis.yml
generated
vendored
|
|
@ -1,15 +0,0 @@
|
|||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.13.x
|
||||
- tip
|
||||
|
||||
before_install:
|
||||
- go get -t -v ./...
|
||||
|
||||
script:
|
||||
- ./go.test.sh
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
21
vendor/github.com/mattn/go-colorable/LICENSE
generated
vendored
21
vendor/github.com/mattn/go-colorable/LICENSE
generated
vendored
|
|
@ -1,21 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Yasuhiro Matsumoto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
48
vendor/github.com/mattn/go-colorable/README.md
generated
vendored
48
vendor/github.com/mattn/go-colorable/README.md
generated
vendored
|
|
@ -1,48 +0,0 @@
|
|||
# go-colorable
|
||||
|
||||
[](https://travis-ci.org/mattn/go-colorable)
|
||||
[](https://codecov.io/gh/mattn/go-colorable)
|
||||
[](http://godoc.org/github.com/mattn/go-colorable)
|
||||
[](https://goreportcard.com/report/mattn/go-colorable)
|
||||
|
||||
Colorable writer for windows.
|
||||
|
||||
For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
|
||||
This package is possible to handle escape sequence for ansi color on windows.
|
||||
|
||||
## Too Bad!
|
||||
|
||||

|
||||
|
||||
|
||||
## So Good!
|
||||
|
||||

|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
|
||||
logrus.SetOutput(colorable.NewColorableStdout())
|
||||
|
||||
logrus.Info("succeeded")
|
||||
logrus.Warn("not correct")
|
||||
logrus.Error("something error")
|
||||
logrus.Fatal("panic")
|
||||
```
|
||||
|
||||
You can compile above code on non-windows OSs.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
$ go get github.com/mattn/go-colorable
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
MIT
|
||||
|
||||
# Author
|
||||
|
||||
Yasuhiro Matsumoto (a.k.a mattn)
|
||||
37
vendor/github.com/mattn/go-colorable/colorable_appengine.go
generated
vendored
37
vendor/github.com/mattn/go-colorable/colorable_appengine.go
generated
vendored
|
|
@ -1,37 +0,0 @@
|
|||
// +build appengine
|
||||
|
||||
package colorable
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
_ "github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
// NewColorable returns new instance of Writer which handles escape sequence.
|
||||
func NewColorable(file *os.File) io.Writer {
|
||||
if file == nil {
|
||||
panic("nil passed instead of *os.File to NewColorable()")
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
|
||||
func NewColorableStdout() io.Writer {
|
||||
return os.Stdout
|
||||
}
|
||||
|
||||
// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
|
||||
func NewColorableStderr() io.Writer {
|
||||
return os.Stderr
|
||||
}
|
||||
|
||||
// EnableColorsStdout enable colors if possible.
|
||||
func EnableColorsStdout(enabled *bool) func() {
|
||||
if enabled != nil {
|
||||
*enabled = true
|
||||
}
|
||||
return func() {}
|
||||
}
|
||||
38
vendor/github.com/mattn/go-colorable/colorable_others.go
generated
vendored
38
vendor/github.com/mattn/go-colorable/colorable_others.go
generated
vendored
|
|
@ -1,38 +0,0 @@
|
|||
// +build !windows
|
||||
// +build !appengine
|
||||
|
||||
package colorable
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
_ "github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
// NewColorable returns new instance of Writer which handles escape sequence.
|
||||
func NewColorable(file *os.File) io.Writer {
|
||||
if file == nil {
|
||||
panic("nil passed instead of *os.File to NewColorable()")
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
|
||||
func NewColorableStdout() io.Writer {
|
||||
return os.Stdout
|
||||
}
|
||||
|
||||
// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
|
||||
func NewColorableStderr() io.Writer {
|
||||
return os.Stderr
|
||||
}
|
||||
|
||||
// EnableColorsStdout enable colors if possible.
|
||||
func EnableColorsStdout(enabled *bool) func() {
|
||||
if enabled != nil {
|
||||
*enabled = true
|
||||
}
|
||||
return func() {}
|
||||
}
|
||||
1043
vendor/github.com/mattn/go-colorable/colorable_windows.go
generated
vendored
1043
vendor/github.com/mattn/go-colorable/colorable_windows.go
generated
vendored
File diff suppressed because it is too large
Load diff
12
vendor/github.com/mattn/go-colorable/go.test.sh
generated
vendored
12
vendor/github.com/mattn/go-colorable/go.test.sh
generated
vendored
|
|
@ -1,12 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
echo "" > coverage.txt
|
||||
|
||||
for d in $(go list ./... | grep -v vendor); do
|
||||
go test -race -coverprofile=profile.out -covermode=atomic "$d"
|
||||
if [ -f profile.out ]; then
|
||||
cat profile.out >> coverage.txt
|
||||
rm profile.out
|
||||
fi
|
||||
done
|
||||
55
vendor/github.com/mattn/go-colorable/noncolorable.go
generated
vendored
55
vendor/github.com/mattn/go-colorable/noncolorable.go
generated
vendored
|
|
@ -1,55 +0,0 @@
|
|||
package colorable
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
// NonColorable holds writer but removes escape sequence.
|
||||
type NonColorable struct {
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
// NewNonColorable returns new instance of Writer which removes escape sequence from Writer.
|
||||
func NewNonColorable(w io.Writer) io.Writer {
|
||||
return &NonColorable{out: w}
|
||||
}
|
||||
|
||||
// Write writes data on console
|
||||
func (w *NonColorable) Write(data []byte) (n int, err error) {
|
||||
er := bytes.NewReader(data)
|
||||
var bw [1]byte
|
||||
loop:
|
||||
for {
|
||||
c1, err := er.ReadByte()
|
||||
if err != nil {
|
||||
break loop
|
||||
}
|
||||
if c1 != 0x1b {
|
||||
bw[0] = c1
|
||||
w.out.Write(bw[:])
|
||||
continue
|
||||
}
|
||||
c2, err := er.ReadByte()
|
||||
if err != nil {
|
||||
break loop
|
||||
}
|
||||
if c2 != 0x5b {
|
||||
continue
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
for {
|
||||
c, err := er.ReadByte()
|
||||
if err != nil {
|
||||
break loop
|
||||
}
|
||||
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
|
||||
break
|
||||
}
|
||||
buf.Write([]byte(string(c)))
|
||||
}
|
||||
}
|
||||
|
||||
return len(data), nil
|
||||
}
|
||||
24
vendor/github.com/uptrace/bun/extra/bundebug/LICENSE
generated
vendored
24
vendor/github.com/uptrace/bun/extra/bundebug/LICENSE
generated
vendored
|
|
@ -1,24 +0,0 @@
|
|||
Copyright (c) 2021 Vladimir Mihailenco. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
109
vendor/github.com/uptrace/bun/extra/bundebug/debug.go
generated
vendored
109
vendor/github.com/uptrace/bun/extra/bundebug/debug.go
generated
vendored
|
|
@ -1,109 +0,0 @@
|
|||
package bundebug
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
type ConfigOption func(*QueryHook)
|
||||
|
||||
func WithVerbose() ConfigOption {
|
||||
return func(h *QueryHook) {
|
||||
h.verbose = true
|
||||
}
|
||||
}
|
||||
|
||||
type QueryHook struct {
|
||||
verbose bool
|
||||
}
|
||||
|
||||
var _ bun.QueryHook = (*QueryHook)(nil)
|
||||
|
||||
func NewQueryHook(opts ...ConfigOption) *QueryHook {
|
||||
h := new(QueryHook)
|
||||
for _, opt := range opts {
|
||||
opt(h)
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *QueryHook) BeforeQuery(
|
||||
ctx context.Context, event *bun.QueryEvent,
|
||||
) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (h *QueryHook) AfterQuery(ctx context.Context, event *bun.QueryEvent) {
|
||||
if !h.verbose {
|
||||
switch event.Err {
|
||||
case nil, sql.ErrNoRows:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
dur := now.Sub(event.StartTime)
|
||||
|
||||
args := []interface{}{
|
||||
"[bun]",
|
||||
now.Format(" 15:04:05.000 "),
|
||||
formatOperation(event),
|
||||
fmt.Sprintf(" %10s ", dur.Round(time.Microsecond)),
|
||||
event.Query,
|
||||
}
|
||||
|
||||
if event.Err != nil {
|
||||
typ := reflect.TypeOf(event.Err).String()
|
||||
args = append(args,
|
||||
"\t",
|
||||
color.New(color.BgRed).Sprintf(" %s ", typ+": "+event.Err.Error()),
|
||||
)
|
||||
}
|
||||
|
||||
fmt.Println(args...)
|
||||
}
|
||||
|
||||
func formatOperation(event *bun.QueryEvent) string {
|
||||
operation := event.Operation()
|
||||
return operationColor(operation).Sprintf(" %-16s ", operation)
|
||||
}
|
||||
|
||||
func eventOperation(event *bun.QueryEvent) string {
|
||||
if event.QueryAppender != nil {
|
||||
return event.QueryAppender.Operation()
|
||||
}
|
||||
return queryOperation(event.Query)
|
||||
}
|
||||
|
||||
func queryOperation(name string) string {
|
||||
if idx := strings.IndexByte(name, ' '); idx > 0 {
|
||||
name = name[:idx]
|
||||
}
|
||||
if len(name) > 16 {
|
||||
name = name[:16]
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func operationColor(operation string) *color.Color {
|
||||
switch operation {
|
||||
case "SELECT":
|
||||
return color.New(color.BgGreen, color.FgHiWhite)
|
||||
case "INSERT":
|
||||
return color.New(color.BgBlue, color.FgHiWhite)
|
||||
case "UPDATE":
|
||||
return color.New(color.BgYellow, color.FgHiBlack)
|
||||
case "DELETE":
|
||||
return color.New(color.BgMagenta, color.FgHiWhite)
|
||||
default:
|
||||
return color.New(color.BgWhite, color.FgHiBlack)
|
||||
}
|
||||
}
|
||||
9
vendor/modules.txt
vendored
9
vendor/modules.txt
vendored
|
|
@ -44,9 +44,6 @@ github.com/dsoprea/go-png-image-structure
|
|||
# github.com/dsoprea/go-utility v0.0.0-20200717064901-2fccff4aa15e
|
||||
## explicit; go 1.12
|
||||
github.com/dsoprea/go-utility/image
|
||||
# github.com/fatih/color v1.10.0
|
||||
## explicit; go 1.13
|
||||
github.com/fatih/color
|
||||
# github.com/gin-contrib/cors v1.3.1
|
||||
## explicit; go 1.13
|
||||
github.com/gin-contrib/cors
|
||||
|
|
@ -352,9 +349,6 @@ github.com/kballard/go-shellquote
|
|||
# github.com/leodido/go-urn v1.2.1
|
||||
## explicit; go 1.13
|
||||
github.com/leodido/go-urn
|
||||
# github.com/mattn/go-colorable v0.1.8
|
||||
## explicit; go 1.13
|
||||
github.com/mattn/go-colorable
|
||||
# github.com/mattn/go-isatty v0.0.14
|
||||
## explicit; go 1.12
|
||||
github.com/mattn/go-isatty
|
||||
|
|
@ -442,9 +436,6 @@ github.com/uptrace/bun/dialect/pgdialect
|
|||
# github.com/uptrace/bun/dialect/sqlitedialect v1.0.5
|
||||
## explicit; go 1.16
|
||||
github.com/uptrace/bun/dialect/sqlitedialect
|
||||
# github.com/uptrace/bun/extra/bundebug v1.0.5
|
||||
## explicit; go 1.16
|
||||
github.com/uptrace/bun/extra/bundebug
|
||||
# github.com/urfave/cli/v2 v2.3.0
|
||||
## explicit; go 1.11
|
||||
github.com/urfave/cli/v2
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue