diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 733951a..3ff6661 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,11 +5,27 @@ include: file: "/templates/docker/clean-template.gitlab-ci.yml" - project: "devops/pena-continuous-integration" file: "/templates/docker/deploy-template.gitlab-ci.yml" + stages: + - lint - clean - build - deploy +lint: + image: golangci/golangci-lint:v1.53.3-alpine + stage: lint + before_script: + - echo GITLAB_TOKEN = $GITLAB_TOKEN + - git config --global url."https://forgomod:${GITLAB_TOKEN}@penahub.gitlab.yandexcloud.net/".insteadOf "https://penahub.gitlab.yandexcloud.net/" + - export GOPRIVATE=penahub.gitlab.yandexcloud.net/backend/penahub_common/ + - go install github.com/vektra/mockery/v2@v2.26.0 + - go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.12.4 + script: + - go generate ./... + - golangci-lint version + - golangci-lint run ./... + clear-old-images: extends: .clean_template variables: diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..0a07cec --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,167 @@ +run: + timeout: 30m + skip-files: + - \.pb\.go$ + - \.pb\.validate\.go$ + - \.pb\.gw\.go$ + - \.gen\.go$ + skip-dirs: + - mocks + - proto + +linters: + disable-all: true + enable: + - asasalint + - asciicheck + - bidichk + - bodyclose + - containedctx + # - depguard + - dogsled + - dupword + - durationcheck + - errcheck + - errchkjson + - exportloopref + # - goconst Временно отключен, ругается на dal\postgres\user.go [159, 18] + - gocritic + - godot + - gofmt + - gci + - goprintffuncname + - gosec + - gosimple + - govet + - importas + - ineffassign + - misspell + - nakedret + - nilerr + - noctx + - nolintlint + - nosprintfhostport + - prealloc + - predeclared + - revive + - rowserrcheck + - staticcheck + - stylecheck + - thelper + - typecheck + - unconvert + - unparam + - unused + - usestdlibvars + - whitespace + +linters-settings: + errcheck: + exclude-functions: + - (io.Closer).Close + govet: + check-shadowing: true + gci: + custom-order: false + section-separators: + - newLine + sections: + - standard # Standard section: captures all standard packages. + - default # Default section: contains all imports that could not be matched to another section type. + - blank # Blank section: contains all blank imports. This section is not present unless explicitly enabled. + - dot # Dot section: contains all dot imports. This section is not present unless explicitly enabled. + importas: + no-unaliased: true + alias: + # Foundation libraries + - pkg: git.sbercloud.tech/products/paas/shared/foundation/management-server + alias: mgmtserver + maligned: + suggest-new: true + goconst: + min-len: 2 + min-occurrences: 2 + lll: + line-length: 140 + revive: + rules: + # The following rules are recommended https://github.com/mgechev/revive#recommended-configuration + - name: blank-imports + - name: context-as-argument + - name: context-keys-type + - name: dot-imports + - name: error-return + - name: error-strings + - name: error-naming + # - name: exported + - name: if-return + - name: increment-decrement + - name: var-naming + - name: var-declaration + # - name: package-comments + - name: range + - name: receiver-naming + - name: time-naming + - name: unexported-return + - name: indent-error-flow + - name: errorf + - name: empty-block + - name: superfluous-else + - name: unused-parameter + - name: unreachable-code + - name: redefines-builtin-id + # + # Rules in addition to the recommended configuration above. + # + - name: bool-literal-in-expr + - name: constant-logical-expr + gosec: + excludes: + - G304 # Potential file inclusion via variable + - G307 # Deferring unsafe method "Close" on type "\*os.File" + - G107 # Potential HTTP request made with variable url + - G108 # Profiling endpoint is automatically exposed on /debug/pprof + gocritic: + enabled-tags: + - diagnostic + - experimental + - performance + disabled-checks: + - appendAssign + - dupImport # https://github.com/go-critic/go-critic/issues/845 + - evalOrder + - ifElseChain + - octalLiteral + - regexpSimplify + - sloppyReassign + - truncateCmp + - typeDefFirst + - unnamedResult + - unnecessaryDefer + - whyNoLint + - wrapperFunc + - rangeValCopy + - hugeParam + +issues: + fix: true + exclude-rules: + - text: "at least one file in a package should have a package comment" + linters: + - stylecheck + - text: "should have a package comment, unless it's in another file for this package" + linters: + - golint + - text: "should have comment or be unexported" + linters: + - golint + - path: _test\.go + linters: + - gosec + - dupl + exclude-use-default: false + +output: + # colored-line-number|line-number|json|tab|checkstyle, default is "colored-line-number" + format: colored-line-number + print-linter-name: true diff --git a/amo/api.go b/amo/api.go index 508af60..07b8b59 100644 --- a/amo/api.go +++ b/amo/api.go @@ -3,19 +3,21 @@ package amo import ( "context" "encoding/json" - "errors" "fmt" - "io/ioutil" + "io" + "log" "net/http" + "net/url" "time" "github.com/dgrijalva/jwt-go" + "github.com/pkg/errors" "golang.org/x/oauth2" "penahub.gitlab.yandexcloud.net/backend/templategen/tools" ) const ( - OAUTH_URL = "https://www.amocrm.ru/oauth" + OauthURL = "https://www.amocrm.ru/oauth" ) type Client struct { @@ -26,30 +28,50 @@ type Client struct { Token *oauth2.Token } +type transport struct { + underlyingTransport http.RoundTripper +} + +func (t *transport) RoundTrip(request *http.Request) (*http.Response, error) { + request.Header.Set("User-Agent", "amoCRM-oAuth-client/1.0") + request.Header.Set("Content-Type", "application/json") + + return t.underlyingTransport.RoundTrip(request) +} + type ClientApp struct { Config *oauth2.Config } -func NewClientApp(clientID, clientSecret string, redirectUri string) *ClientApp { +/* +TODO: Вероятно стоит вынести аргументы в отдельную структуру типа Deps. + +Аргументация Кирилла: +Я думаю лучше все аргументы для инициализации модуля выносить в структуру, +потому что количество аргументов может в дальнейшем увеличиваться. +И чтобы избежать большого количества аргументов в количестве +3 штук, лучше выносить в структуру. +*/ + +func NewClientApp(clientID, clientSecret string, redirectURI string) *ClientApp { return &ClientApp{ Config: &oauth2.Config{ ClientID: clientID, ClientSecret: clientSecret, Endpoint: oauth2.Endpoint{ - AuthURL: OAUTH_URL, - TokenURL: OAUTH_URL + "2/access_token", + AuthURL: OauthURL, + TokenURL: OauthURL + "2/access_token", }, - RedirectURL: redirectUri, + RedirectURL: redirectURI, Scopes: nil, }, } } -func (ca *ClientApp) GenerateOAuthUrl(userId, redirectUrl string) (string, error) { - state, err := tools.EncryptTokenRC4(tools.StateToken{ - UserID: userId, +func (ca *ClientApp) GenerateOAuthURL(penaID, redirectURL string) (string, error) { + state, err := tools.EncryptTokenAES(tools.StateToken{ + PenaID: penaID, Service: "amo", - RedirectUrl: redirectUrl, + RedirectURL: redirectURL, }) if err != nil { @@ -92,8 +114,6 @@ func (ca *ClientApp) NewClient(ctx context.Context, referer string, token *oauth error) { var err error - referer = "https://" + referer - client := &Client{ App: ca, Config: &oauth2.Config{ @@ -101,7 +121,7 @@ func (ca *ClientApp) NewClient(ctx context.Context, referer string, token *oauth ClientSecret: ca.Config.ClientSecret, Endpoint: oauth2.Endpoint{ AuthURL: ca.Config.Endpoint.AuthURL, - TokenURL: referer + "/oauth2/access_token", + TokenURL: "https://" + referer + "/oauth2/access_token", }, RedirectURL: ca.Config.RedirectURL, Scopes: ca.Config.Scopes, @@ -121,6 +141,7 @@ func (ca *ClientApp) NewClient(ctx context.Context, referer string, token *oauth client.Token = token client.HTTPClient = client.Config.Client(ctx, token) + client.HTTPClient.Transport = &transport{underlyingTransport: http.DefaultTransport} return client, nil } @@ -148,164 +169,208 @@ func (ca *ClientApp) RefreshToken(ctx context.Context, oldToken *oauth2.Token, r return token, nil } -func (c *Client) GetAccount() (*Account, error) { - req, err := http.NewRequest("GET", c.Subdomain+"/api/v4/account", nil) +func (c *Client) GetAccount(ctx context.Context) (*Account, error) { + requestURL := url.URL{ + Scheme: "https", + Host: c.Subdomain, + Path: "api/v4/account", + } + + request, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL.String(), http.NoBody) + if err != nil { + return nil, errors.Wrap(err, "GetAccount.NewRequest") + } + + response, err := c.HTTPClient.Do(request) + if err != nil { + return nil, errors.Wrap(err, "GetAccount.DoRequest") + } + + defer func() { + if err = response.Body.Close(); err != nil { + log.Println("ERROR", errors.Wrap(err, "GetAccount.BodyClose")) + } + }() + + var result Account + // TODO: Проверить в ssa сокращенную запись if err = operation(); err != nil {...} + err = json.NewDecoder(response.Body).Decode(&result) if err != nil { - fmt.Println("1") return nil, err } - c.setHeaders(req) - - resp, err := c.HTTPClient.Do(req) - - if err != nil { - fmt.Println("2") - return nil, err - } - - var response Account - err = json.NewDecoder(resp.Body).Decode(&response) - if err != nil { - fmt.Println("3") - return nil, err - } - - return &response, nil + return &result, nil } -func (c *Client) GetLeadById(id string) (*Lead, error) { - req, err := http.NewRequest("GET", - fmt.Sprintf("%v/api/v4/leads/%v?with=contacts,catalog_elements,is_price_modified_by_robot,loss_reason", - c.Subdomain, id), - nil, - ) +func (c *Client) GetLeadByID(ctx context.Context, id string) (*Lead, error) { + requestURLQueries := make(url.Values) + requestURLQueries.Add("with", "contacts,catalog_elements,is_price_modified_by_robot,loss_reason") - fmt.Println("URL:", fmt.Sprintf("%v/api/v4/leads/%v?with=contacts,catalog_elements,is_price_modified_by_robot,"+ - "loss_reason", - c.Subdomain, id)) - - if err != nil { - fmt.Println("1", err) - return nil, err + requestURL := url.URL{ + Scheme: "https", + Host: c.Subdomain, + Path: fmt.Sprintf("api/v4/leads/%v", id), + RawQuery: requestURLQueries.Encode(), } - c.setHeaders(req) + request, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL.String(), http.NoBody) - resp, err := c.HTTPClient.Do(req) + fmt.Println("URL:", requestURL.String()) if err != nil { - fmt.Println("2", err) - return nil, err + return nil, errors.Wrap(err, "GetLeadByID.NewRequest") } - for resp.StatusCode == 429 { + response, err := c.HTTPClient.Do(request) + if err != nil { + return nil, errors.Wrap(err, "GetLeadByID.DoRequest") + } + + defer func() { + if err = response.Body.Close(); err != nil { + log.Println("ERROR", errors.Wrap(err, "GetLeadByID.BodyClose")) + } + }() + + for response.StatusCode == http.StatusTooManyRequests { time.Sleep(time.Second) - resp, err = c.HTTPClient.Do(req) + response, err = c.HTTPClient.Do(request) if err != nil { - fmt.Println("5", err) - return nil, err + return nil, errors.Wrap(err, "GetLeadByID.DoRequest") } + + func() { + defer func() { + if err = response.Body.Close(); err != nil { + log.Println("ERROR", errors.Wrap(err, "GetLeadByID.BodyClose")) + } + }() + }() } - var response Lead - str, err := ioutil.ReadAll(resp.Body) + var result Lead + responseData, err := io.ReadAll(response.Body) + if err != nil { - fmt.Println("4", err) - } - err = json.Unmarshal(str, &response) - if err != nil { - fmt.Println("3", err, string(str)) - return nil, err + return nil, errors.Wrap(err, "GetLeadByID.ReadAll") } - return &response, nil + err = json.Unmarshal(responseData, &result) + if err != nil { + return nil, errors.Wrap(err, "GetLeadByID.Unmarshal") + } + + return &result, nil } -func (c *Client) GetContactById(id string) (*Contact, error) { - req, err := http.NewRequest("GET", - fmt.Sprintf("%v/api/v4/contacts/%v?with=catalog_elements,leads,customers", - c.Subdomain, id), - nil, - ) - if err != nil { - fmt.Println("1") - return nil, err +func (c *Client) GetContactByID(ctx context.Context, id string) (*Contact, error) { + requestURLQueries := make(url.Values) + requestURLQueries.Add("with", "catalog_elements,leads,customers") + + requestURL := url.URL{ + Scheme: "https", + Host: c.Subdomain, + Path: fmt.Sprintf("api/v4/contacts/%v", id), + RawQuery: requestURLQueries.Encode(), } - c.setHeaders(req) + request, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL.String(), http.NoBody) + if err != nil { + return nil, errors.Wrap(err, "GetContactByID.NewRequest") + } - resp, err := c.HTTPClient.Do(req) + response, err := c.HTTPClient.Do(request) if err != nil { - fmt.Println("2") - return nil, err + return nil, errors.Wrap(err, "GetContactByID.DoRequest") } - for resp.StatusCode == 429 { + defer func() { + if err = response.Body.Close(); err != nil { + log.Println("ERROR", errors.Wrap(err, "GetContactByID.BodyClose")) + } + }() + + // TODO: переписать на отдельную сущность-клиент, которая сама внутри себя будет мониторить вопрос rate-limit + for response.StatusCode == http.StatusTooManyRequests { time.Sleep(time.Second) - resp, err = c.HTTPClient.Do(req) + response, err = c.HTTPClient.Do(request) if err != nil { - fmt.Println("5", err) - return nil, err + return nil, errors.Wrap(err, "GetContactByID.ForDoRequest") } + + func() { + defer func() { + if err = response.Body.Close(); err != nil { + log.Println("ERROR", errors.Wrap(err, "GetContactByID.BodyClose")) + } + }() + }() } - var response Contact - err = json.NewDecoder(resp.Body).Decode(&response) + var result Contact + err = json.NewDecoder(response.Body).Decode(&result) if err != nil { - return nil, err + return nil, errors.Wrap(err, "GetContactByID.Decode") } - return &response, nil + return &result, nil } -func (c *Client) GetCompanyById(id string) (*Company, error) { - req, err := http.NewRequest("GET", - fmt.Sprintf("%v/api/v4/companies/%v?with=contacts,leads,catalog_elements,customers", - c.Subdomain, id), - nil, - ) - if err != nil { - fmt.Println("1") - return nil, err +func (c *Client) GetCompanyByID(ctx context.Context, id string) (*Company, error) { + requestURLQueries := make(url.Values) + requestURLQueries.Add("with", "contacts,leads,catalog_elements,customers") + + requestURL := url.URL{ + Scheme: "https", + Host: c.Subdomain, + Path: fmt.Sprintf("api/v4/companies/%v", id), + RawQuery: requestURLQueries.Encode(), } - c.setHeaders(req) - - resp, err := c.HTTPClient.Do(req) + request, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL.String(), http.NoBody) if err != nil { - fmt.Println("2") - return nil, err + return nil, errors.Wrap(err, "GetCompanyByID.NewRequest") } - for resp.StatusCode == 429 { + + response, err := c.HTTPClient.Do(request) + + if err != nil { + return nil, errors.Wrap(err, "GetCompanyByID.DoRequest") + } + + defer func() { + if err = response.Body.Close(); err != nil { + log.Println("ERROR", errors.Wrap(err, "GetCompanyByID.BodyClose")) + } + }() + + for response.StatusCode == http.StatusTooManyRequests { time.Sleep(time.Second) - resp, err = c.HTTPClient.Do(req) + response, err = c.HTTPClient.Do(request) if err != nil { - fmt.Println("5", err) - return nil, err + return nil, errors.Wrap(err, "GetCompanyByID.ForDoRequest") } + + func() { + defer func() { + if err = response.Body.Close(); err != nil { + log.Println("ERROR", errors.Wrap(err, "GetCompanyByID.BodyClose")) + } + }() + }() } - var response Company - err = json.NewDecoder(resp.Body).Decode(&response) + var result Company + err = json.NewDecoder(response.Body).Decode(&result) if err != nil { - return nil, err + return nil, errors.Wrap(err, "GetCompanyByID.Decode") } - return &response, nil -} - -func (c *Client) setHeaders(req *http.Request) { - req.Header.Set("User-Agent", "amoCRM-oAuth-client/1.0") - req.Header.Set("Content-Type", "application/json") - - //if c.Token != nil { - // c.Token.SetAuthHeader(req) - //} + return &result, nil } diff --git a/amo/model.go b/amo/model.go index 96df5c6..156f8fd 100644 --- a/amo/model.go +++ b/amo/model.go @@ -2,8 +2,9 @@ package amo import ( "errors" - "github.com/dgrijalva/jwt-go" "time" + + "github.com/dgrijalva/jwt-go" ) type RespAuthCode struct { @@ -14,15 +15,15 @@ type RespAuthCode struct { } type Lead struct { - Id int `json:"id"` + ID int `json:"id"` Name string `json:"name"` Price int `json:"price"` - ResponsibleUserId int `json:"responsible_user_id"` - GroupId int `json:"group_id"` - StatusId int `json:"status_id"` - PipelineId int `json:"pipeline_id"` - LossReasonId int `json:"loss_reason_id"` - SourceId interface{} `json:"source_id"` + ResponsibleUserID int `json:"responseonsible_user_id"` + GroupID int `json:"group_id"` + StatusID int `json:"status_id"` + PipelineID int `json:"pipeline_id"` + LossReasonID int `json:"loss_reason_id"` + SourceID interface{} `json:"source_id"` CreatedBy int `json:"created_by"` UpdatedBy int `json:"updated_by"` CreatedAt int `json:"created_at"` @@ -32,7 +33,7 @@ type Lead struct { IsDeleted bool `json:"is_deleted"` CustomFieldsValues []CustomField `json:"custom_fields_values"` Score interface{} `json:"score"` - AccountId int `json:"account_id"` + AccountID int `json:"account_id"` IsPriceModifiedByRobot bool `json:"is_price_modified_by_robot"` Links Links `json:"_links"` Embedded struct { @@ -45,7 +46,7 @@ type Lead struct { } type CustomField struct { - FieldId int `json:"field_id"` + FieldID int `json:"field_id"` FieldName string `json:"field_name"` FieldCode interface{} `json:"field_code"` FieldType string `json:"field_type"` @@ -58,25 +59,25 @@ type CustomField struct { } type Tags struct { - Id int `json:"id"` + ID int `json:"id"` Name string `json:"name"` Color interface{} `json:"color"` } type Contact struct { - Id int `json:"id"` + ID int `json:"id"` Name string `json:"name"` FirstName string `json:"first_name"` LastName string `json:"last_name"` - ResponsibleUserId int `json:"responsible_user_id"` - GroupId int `json:"group_id"` + ResponsibleUserID int `json:"responseonsible_user_id"` + GroupID int `json:"group_id"` CreatedBy int `json:"created_by"` UpdatedBy int `json:"updated_by"` CreatedAt int `json:"created_at"` UpdatedAt int `json:"updated_at"` ClosestTaskAt interface{} `json:"closest_task_at"` CustomFieldsValues []CustomField `json:"custom_fields_values"` - AccountId int `json:"account_id"` + AccountID int `json:"account_id"` Links Links `json:"_links"` Embedded struct { Tags []Tags `json:"tags"` @@ -88,17 +89,17 @@ type Contact struct { } type Company struct { - Id int `json:"id"` + ID int `json:"id"` Name string `json:"name"` - ResponsibleUserId int `json:"responsible_user_id"` - GroupId int `json:"group_id"` + ResponsibleUserID int `json:"responseonsible_user_id"` + GroupID int `json:"group_id"` CreatedBy int `json:"created_by"` UpdatedBy int `json:"updated_by"` CreatedAt int `json:"created_at"` UpdatedAt int `json:"updated_at"` ClosestTaskAt interface{} `json:"closest_task_at"` CustomFieldsValues []CustomField `json:"custom_fields_values"` - AccountId int `json:"account_id"` + AccountID int `json:"account_id"` Links Links `json:"_links"` Embedded struct { Tags []Tags `json:"tags"` @@ -106,12 +107,12 @@ type Company struct { } type Customer struct { - Id int `json:"id"` + ID int `json:"id"` Links Links `json:"_links"` } type LossReason struct { - Id int `json:"id"` + ID int `json:"id"` Name string `json:"name"` Sort int `json:"sort"` CreatedAt int `json:"created_at"` @@ -120,10 +121,10 @@ type LossReason struct { } type CatalogElement struct { - Id int `json:"id"` + ID int `json:"id"` Metadata struct { Quantity int `json:"quantity"` - CatalogId int `json:"catalog_id"` + CatalogID int `json:"catalog_id"` } `json:"metadata"` } @@ -134,14 +135,14 @@ type Links struct { } type Account struct { - Id int64 `json:"id"` + ID int64 `json:"id"` Name string `json:"name"` Subdomain string `json:"subdomain"` CreatedAt int `json:"created_at"` CreatedBy int `json:"created_by"` UpdatedAt int `json:"updated_at"` UpdatedBy int `json:"updated_by"` - CurrentUserId int `json:"current_user_id"` + CurrentUserID int `json:"current_user_id"` Country string `json:"country"` CustomersMode string `json:"customers_mode"` IsUnsortedOn bool `json:"is_unsorted_on"` @@ -149,8 +150,8 @@ type Account struct { IsHelpbotEnabled bool `json:"is_helpbot_enabled"` IsTechnicalAccount bool `json:"is_technical_account"` ContactNameDisplayOrder int `json:"contact_name_display_order"` - AmojoId string `json:"amojo_id"` - Uuid string `json:"uuid"` + AmojoID string `json:"amojo_id"` + UUID string `json:"uuid"` Version int `json:"version"` Links Links `json:"_links"` Embedded struct { @@ -159,15 +160,15 @@ type Account struct { CanCreateGroups bool `json:"can_create_groups"` } `json:"amojo_rights"` UsersGroups []struct { - Id int `json:"id"` + ID int `json:"id"` Name string `json:"name"` - Uuid interface{} `json:"uuid"` + UUID interface{} `json:"uuid"` } `json:"users_groups"` TaskTypes []struct { - Id int `json:"id"` + ID int `json:"id"` Name string `json:"name"` Color interface{} `json:"color"` - IconId interface{} `json:"icon_id"` + IconID interface{} `json:"icon_id"` Code string `json:"code"` } `json:"task_types"` EntityNames struct { @@ -227,30 +228,47 @@ type Account struct { // // Заголовок запроса: x-auth-token // -// Алгоритм подписи токена: HS256, в качестве ключа используется secret_key интеграции +// Алгоритм подписи токена: HS256, в качестве ключа используется secret_key интеграции. type XAuthToken struct { - Iss string `json:"iss"` // Адрес аккаунта - Aud string `json:"aud"` // Базовый адрес, сформированный исходя из значения redirect_uri в интеграции - Jti string `json:"jti"` // UUID токена - Iat int64 `json:"iat"` // Timestamp, когда был выдан токен - Nbf int64 `json:"nbf"` // Timestamp, когда токен начинает действовать - Exp int64 `json:"exp"` // Timestamp, когда токен будет просрочен - AccountId int64 `json:"account_id"` // ID аккаунта, из которого был сделан запрос - Subdomain string `json:"subdomain"` // Субдомен, из которого был сделан запрос - ClientUuid string `json:"client_uuid"` // UUID интеграции, - // которая сделала запрос - UserId int64 `json:"user_id"` // ID пользователя, из под которого был сделан запрос - IsAdmin bool `json:"is_admin"` // Является ли пользователь админом + /* Адрес аккаунта */ + Iss string `json:"iss"` + + /* Базовый адрес, сформированный исходя из значения redirect_uri в интеграции */ + Aud string `json:"aud"` + + /* UUID токена */ + Jti string `json:"jti"` + + /* Timestamp, когда был выдан токен */ + Iat int64 `json:"iat"` + + /* Timestamp, когда токен начинает действовать */ + Nbf int64 `json:"nbf"` + + /* Timestamp, когда токен будет просрочен */ + Exp int64 `json:"exp"` + + /* ID аккаунта, из которого был сделан запрос */ + AccountID int64 `json:"account_id"` + + /* Субдомен, из которого был сделан запрос */ + Subdomain string `json:"subdomain"` + + /* UUID интеграции, которая сделала запрос */ + ClientUUID string `json:"client_uuid"` + + /* ID пользователя, из под которого был сделан запрос */ + UserID int64 `json:"user_id"` + + /* Является ли пользователь админом */ + IsAdmin bool `json:"is_admin"` + jwt.Claims } func (t *XAuthToken) Valid() error { now := time.Now().Unix() - //if now >= t.Nbf && now <= t.Exp { - // return nil - //} - if now <= t.Exp { return nil } diff --git a/broker/tariff/consumer.go b/broker/tariff/consumer.go new file mode 100644 index 0000000..b5b7a62 --- /dev/null +++ b/broker/tariff/consumer.go @@ -0,0 +1,51 @@ +package tariff + +import ( + "context" + "fmt" + + "github.com/twmb/franz-go/pkg/kgo" + "go.uber.org/zap" + "google.golang.org/protobuf/proto" + "penahub.gitlab.yandexcloud.net/backend/templategen/broker/tariff/models" + "penahub.gitlab.yandexcloud.net/backend/templategen/broker/tariff/utils/transfer" + "penahub.gitlab.yandexcloud.net/backend/templategen/proto/tariff" +) + +type ConsumerDeps struct { + Logger *zap.Logger + Client *kgo.Client +} + +type Consumer struct { + logger *zap.Logger + client *kgo.Client +} + +func NewConsumer(deps ConsumerDeps) *Consumer { + return &Consumer{ + logger: deps.Logger, + client: deps.Client, + } +} + +func (receiver *Consumer) FetchTariffs(ctx context.Context) []models.Tariff { + fetches := receiver.client.PollFetches(ctx) + iter := fetches.RecordIter() + + tariffs := make([]models.Tariff, 0) + + for !iter.Done() { + record := iter.Next() + tariff := tariff.TariffMessage{} + + if err := proto.Unmarshal(record.Value, &tariff); err != nil { + receiver.logger.Error(fmt.Sprintf("error decoding message: %v\n", err)) + continue + } + + tariffs = append(tariffs, *transfer.TariffProtoToModel(&tariff)) + } + + return tariffs +} diff --git a/broker/tariff/models/tariff.go b/broker/tariff/models/tariff.go new file mode 100644 index 0000000..f6100a7 --- /dev/null +++ b/broker/tariff/models/tariff.go @@ -0,0 +1,41 @@ +package models + +import "time" + +const ( + ServiceKey = "templategen" + PrivilegeTemplateCount = "templateCnt" + PrivilegeTemplateUnlimTime = "templateUnlimTime" + PrivilegeTemplateStorage = "templateStorage" + BasicAmountPrivilegeTemplateCount = 15 + BasicAmountPrivilegeTemplateStorage = 100 +) + +type Tariff struct { + ID string `json:"_id"` + Name string `json:"name"` + UserID string `json:"user_id"` + Price int64 `json:"price"` + IsCustom bool `json:"isCustom"` + Privileges []Privilege `json:"privileges"` + Deleted bool `json:"isDeleted"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + DeletedAt *time.Time `json:"deletedAt,omitempty"` +} + +type Privilege struct { + ID string `json:"_id"` + Amount int64 `json:"amount"` + PrivilegeID string `json:"privilegeId"` + Name string `json:"name"` + ServiceKey string `json:"serviceKey"` + Description string `json:"description"` + Type string `json:"type"` + Value string `json:"value"` + Price float64 `json:"price"` + IsDeleted bool `json:"isDeleted"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + DeletedAt time.Time `json:"deletedAt"` +} diff --git a/broker/tariff/utils/transfer/privileges.go b/broker/tariff/utils/transfer/privileges.go new file mode 100644 index 0000000..849f15f --- /dev/null +++ b/broker/tariff/utils/transfer/privileges.go @@ -0,0 +1,30 @@ +package transfer + +import ( + "penahub.gitlab.yandexcloud.net/backend/templategen/broker/tariff/models" + "penahub.gitlab.yandexcloud.net/backend/templategen/proto/tariff" +) + +func PrivilegeProtoToModel(privilege *tariff.PrivilegeMessage) *models.Privilege { + if privilege == nil { + return &models.Privilege{} + } + + return &models.Privilege{ + ID: privilege.GetPrivilegeID(), + ServiceKey: privilege.GetServiceKey(), + Type: privilege.GetType().String(), + Value: privilege.GetValue(), + Amount: int64(privilege.GetAmount()), + } +} + +func PrivilegeArrayProtoToModel(privileges []*tariff.PrivilegeMessage) []models.Privilege { + privilegesModel := make([]models.Privilege, len(privileges)) + + for index, privilege := range privileges { + privilegesModel[index] = *PrivilegeProtoToModel(privilege) + } + + return privilegesModel +} diff --git a/broker/tariff/utils/transfer/tariff.go b/broker/tariff/utils/transfer/tariff.go new file mode 100644 index 0000000..75aab10 --- /dev/null +++ b/broker/tariff/utils/transfer/tariff.go @@ -0,0 +1,27 @@ +package transfer + +import ( + "time" + + "penahub.gitlab.yandexcloud.net/backend/templategen/broker/tariff/models" + "penahub.gitlab.yandexcloud.net/backend/templategen/proto/tariff" +) + +func TariffProtoToModel(tariff *tariff.TariffMessage) *models.Tariff { + if tariff == nil { + return &models.Tariff{} + } + + return &models.Tariff{ + ID: "", + UserID: tariff.GetUserID(), + Name: "", + Price: 0, + IsCustom: false, + Privileges: PrivilegeArrayProtoToModel(tariff.Privileges), + Deleted: false, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + DeletedAt: &time.Time{}, + } +} diff --git a/dal/dal.go b/dal/dal.go index 50aff24..8f1ea0c 100644 --- a/dal/dal.go +++ b/dal/dal.go @@ -2,55 +2,18 @@ package dal import ( "context" - "github.com/jackc/pgx/v4/pgxpool" + "time" + "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/readpref" "go.uber.org/zap" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/mongos" - "penahub.gitlab.yandexcloud.net/backend/templategen/dal/postgres" - "time" ) -type PostgresDAL struct { - conn *pgxpool.Pool - User *postgres.User - YaDisk *postgres.YaDisk -} - -func InitPostgresDAL(ctx context.Context, dbURL string) (*PostgresDAL, error) { - conn, err := pgxpool.Connect(ctx, dbURL) - if err != nil { - return nil, err - } - - dal := PostgresDAL{ - conn: conn, - User: postgres.InitUser(ctx, conn), - YaDisk: postgres.InitYaDisk(ctx, conn), - } - - // Init all tables in data access layer - //val := reflect.ValueOf(dal) - //for i := 0; i < val.NumField(); i++ { - // result := val.Field(i).MethodByName("Init").Call([]reflect.Value{reflect.ValueOf(ctx)}) - // - // if !result[0].IsNil() { - // log.Println(result[0]) - // } - //} - - return &dal, nil -} - -func (dal *PostgresDAL) Disconnect() { - -} - type MongoDAL struct { conn *mongo.Client logger *zap.Logger - User *mongos.User YaDisk *mongos.YaDisk GDisk *mongos.GDisk PenaDisk *mongos.PenaDisk @@ -62,16 +25,10 @@ type MongoDAL struct { } func InitMongoDAL(ctx context.Context, dbURL, dbTable string, logger *zap.Logger) (*MongoDAL, error) { - conn, err := mongo.NewClient(options.Client().ApplyURI(dbURL)) - - if err != nil { - return nil, err - } - ctxTO, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() - err = conn.Connect(ctxTO) + conn, err := mongo.Connect(ctxTO, options.Client().ApplyURI(dbURL)) if err != nil { return nil, err @@ -80,7 +37,6 @@ func InitMongoDAL(ctx context.Context, dbURL, dbTable string, logger *zap.Logger dal := &MongoDAL{ conn: conn, logger: logger, - User: mongos.InitUser(conn.Database(dbTable), logger), YaDisk: mongos.InitYaDisk(conn.Database(dbTable), logger), GDisk: mongos.InitGDisk(conn.Database(dbTable), logger), PenaDisk: mongos.InitPenaDisk(conn.Database(dbTable), logger), diff --git a/dal/model/amo.go b/dal/model/amo.go index 18ad535..211b69e 100644 --- a/dal/model/amo.go +++ b/dal/model/amo.go @@ -6,25 +6,62 @@ import ( "golang.org/x/oauth2" ) -type Amo struct { - ID string `bson:"_id,omitempty" json:"id"` - UserID string `bson:"user_id" json:"user_id"` //Id пользователя Амо - AccountID string `bson:"account_id" json:"account_id"` // Account ID in AMO CRM - PenaID string `bson:"pena_id" json:"pena_id"` +const ( + ServiceKey = "templategen" + PrivilegeTemplateCount = "templateCnt" + PrivilegeTemplateUnlimTime = "templateUnlimTime" + PrivilegeTemplateStorage = "templateStorage" + BasicAmountPrivilegeTemplateCount = 15 + BasicAmountPrivilegeTemplateStorage = 100 +) - Subdomain string `bson:"subdomain" json:"subdomain"` // Subdomain in AMO CRM. Example: [subdomain].amocrm.ru/ - Referer string `bson:"referer" json:"referer"` // Referer in AMO CRM. Example: subdomain.amocrm.ru - FromWidget string `bson:"from_widget" json:"from_widget"` - AccessToken string `bson:"access_token" json:"-"` - RefreshToken string `bson:"refresh_token" json:"-"` - ExpiresIn time.Time `bson:"expires_in" json:"-"` - TokenType string `bson:"token_type" json:"-"` - AccessRules AmoAccessRules `bson:"access_rules" json:"access_rules"` - IsDeleted bool `bson:"is_deleted" json:"is_deleted"` - CreatedAt time.Time `bson:"created_at" json:"created_at"` - UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` +type Amo struct { + ID string `bson:"_id,omitempty" json:"id"` + + /* ID интеграции */ + ClientID string `bson:"client_id" json:"client_id"` + + /* Account ID in AMO CRM */ + AccountID string `bson:"account_id" json:"account_id"` + + /* Identifier Pena User */ + PenaID string `bson:"pena_id" json:"pena_id"` + + /* Subdomain in AMO CRM. Example: [subdomain].amocrm.ru/ */ + Subdomain string `bson:"subdomain" json:"subdomain"` + + /* Referer in AMO CRM. Example: subdomain.amocrm.ru */ + Referer string `bson:"referer" json:"referer"` + + FromWidget string `bson:"from_widget" json:"from_widget"` + + AccessToken string `bson:"access_token" json:"-"` + + RefreshToken string `bson:"refresh_token" json:"-"` + + ExpiresIn time.Time `bson:"expires_in" json:"-"` + + TokenType string `bson:"token_type" json:"-"` + + AccessRules AmoAccessRules `bson:"access_rules" json:"access_rules"` + + /* Ключ privileges.Privilege.PrivilegeID */ + Privileges map[string]ShortPrivilige `bson:"privileges" json:"privileges"` + + IsDeleted bool `bson:"is_deleted" json:"is_deleted"` + + CreatedAt time.Time `bson:"created_at" json:"created_at"` + + UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` } +type ShortPrivilige struct { + Amount int64 `bson:"amount" json:"amount"` + + CreatedAt time.Time `bson:"created_at" json:"created_at"` +} + +// AmoAccessRules - права доступа. Значением является UserID из XAuthToken. type AmoAccessRules struct { Visibility []int64 `bson:"visibility"` Creation []int64 `bson:"creation"` diff --git a/dal/model/gdisk.go b/dal/model/gdisk.go index 84c801a..6079b35 100644 --- a/dal/model/gdisk.go +++ b/dal/model/gdisk.go @@ -1,33 +1,55 @@ package model import ( - "golang.org/x/oauth2" "time" + + "golang.org/x/oauth2" ) // GDisk (StorageType) - хранит информацию о пользователе Google и данных необходимых для хранилища. // Пользователь может иметь несколько хранилищ GDisk. -// Email - уникальное поле и закрепляется только за одним пользователем type GDisk struct { - ID string `bson:"_id,omitempty" json:"id"` - UserID string `bson:"user_id" json:"user_id"` - Email string `bson:"email" json:"email"` // Google email. Unique ? - DisplayName string `bson:"display_name" json:"display_name"` // Отображаемое имя пользователя в Google - PhotoLink string `bson:"photo_link" json:"photo_link"` // Фото пользователя в Google - AccessToken string `bson:"access_token" json:"-"` - RefreshToken string `bson:"refresh_token" json:"-"` - ExpiresIn time.Time `bson:"expires_in" json:"-"` - TokenType string `bson:"token_type" json:"-"` - Name string `bson:"name" json:"name"` // Пользовательское название хранилища - DefaultFolder string `bson:"default_folder" json:"default_folder"` - DefaultFolderID string `bson:"default_folder_id" json:"default_folder_id"` - TemplateFolder string `bson:"template_folder" json:"template_folder"` - TemplateFolderID string `bson:"template_folder_id" json:"template_folder_id"` - SaveFolder string `bson:"save_folder" json:"save_folder"` - SaveFolderID string `bson:"save_folder_id" json:"save_folder_id"` - IsDeleted bool `bson:"is_deleted" json:"is_deleted"` - CreatedAt time.Time `bson:"created_at" json:"created_at"` - UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` + ID string `bson:"_id,omitempty" json:"id"` + + PenaID string `bson:"pena_id" json:"pena_id"` + + /* Google email. Уникальное поле и закрепляется только за одним пользователем. */ + Email string `bson:"email" json:"email"` + + /* Отображаемое имя пользователя в Google */ + DisplayName string `bson:"display_name" json:"display_name"` + + /* Фото пользователя в Google */ + PhotoLink string `bson:"photo_link" json:"photo_link"` + + AccessToken string `bson:"access_token" json:"-"` + + RefreshToken string `bson:"refresh_token" json:"-"` + + ExpiresIn time.Time `bson:"expires_in" json:"-"` + + TokenType string `bson:"token_type" json:"-"` + + /* Пользовательское название хранилища */ + Name string `bson:"name" json:"name"` + + DefaultFolder string `bson:"default_folder" json:"default_folder"` + + DefaultFolderID string `bson:"default_folder_id" json:"default_folder_id"` + + TemplateFolder string `bson:"template_folder" json:"template_folder"` + + TemplateFolderID string `bson:"template_folder_id" json:"template_folder_id"` + + SaveFolder string `bson:"save_folder" json:"save_folder"` + + SaveFolderID string `bson:"save_folder_id" json:"save_folder_id"` + + IsDeleted bool `bson:"is_deleted" json:"is_deleted"` + + CreatedAt time.Time `bson:"created_at" json:"created_at"` + + UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` } func (m *GDisk) Token() *oauth2.Token { diff --git a/dal/model/history.go b/dal/model/history.go index d5d2799..22f1a02 100644 --- a/dal/model/history.go +++ b/dal/model/history.go @@ -5,26 +5,41 @@ import ( ) type History struct { - ID string `bson:"_id,omitempty" json:"id"` - UserID string `bson:"user_id" json:"user_id"` - AmoID string `bson:"amo_id" json:"amo_id"` - AmoUserID int64 `bson:"amo_user_id,omitempty" json:"amo_user_id"` - LeadID int64 `bson:"lead_id,omitempty" json:"lead_id"` - Errors []string `bson:"errors" json:"errors"` - Trigger HistoryTrigger `bson:"trigger" json:"trigger"` - TemplateID string `bson:"template_id" json:"template_id"` - Source HistorySource `bson:"source" json:"source"` - Target HistoryTarget `bson:"target" json:"target"` - DownloadUrl string `json:"download_url" bson:"download_url"` // Ссылка для скачивания результата - PublicUrl string `bson:"public_url" json:"public_url"` - WorkerTaskID string `bson:"worker_task_id" json:"worker_task_id"` - UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` - CreatedAt time.Time `bson:"created_at" json:"created_at"` + ID string `bson:"_id,omitempty" json:"id"` + + PenaID string `bson:"pena_id" json:"pena_id"` + + AmoID string `bson:"amo_id" json:"amo_id"` + + AmoUserID int64 `bson:"amo_user_id,omitempty" json:"amo_user_id"` + + LeadID int64 `bson:"lead_id,omitempty" json:"lead_id"` + + Errors []string `bson:"errors" json:"errors"` + + Trigger HistoryTrigger `bson:"trigger" json:"trigger"` + + TemplateID string `bson:"template_id" json:"template_id"` + + Source HistorySource `bson:"source" json:"source"` + + Target HistoryTarget `bson:"target" json:"target"` + + /* Ссылка для скачивания результата */ + DownloadURL string `json:"download_url" bson:"download_url"` // + + PublicURL string `bson:"public_url" json:"public_url"` + + WorkerTaskID string `bson:"worker_task_id" json:"worker_task_id"` + + UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` + + CreatedAt time.Time `bson:"created_at" json:"created_at"` } -func NewHistory(userID, amoID string, amoUserID int64, trigger HistoryTrigger) *History { +func NewHistory(penaID, amoID string, amoUserID int64, trigger HistoryTrigger) *History { return &History{ - UserID: userID, + PenaID: penaID, AmoID: amoID, AmoUserID: amoUserID, Errors: []string{}, diff --git a/dal/model/penadisk.go b/dal/model/penadisk.go index b4c2840..da125ab 100644 --- a/dal/model/penadisk.go +++ b/dal/model/penadisk.go @@ -3,12 +3,20 @@ package model import "time" type PenaDisk struct { - ID string `bson:"_id,omitempty" json:"id"` - UserID string `bson:"user_id" json:"user_id"` - Name string `bson:"name" json:"name"` // Пользовательское название хранилища - TemplateFolder string `bson:"template_folder" json:"template_folder"` - SaveFolder string `bson:"save_folder" json:"save_folder"` - IsDeleted bool `bson:"is_deleted" json:"is_deleted"` - CreatedAt time.Time `bson:"created_at" json:"created_at"` - UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` + ID string `bson:"_id,omitempty" json:"id"` + + PenaID string `bson:"pena_id" json:"pena_id"` + + /* Пользовательское название хранилища */ + Name string `bson:"name" json:"name"` + + TemplateFolder string `bson:"template_folder" json:"template_folder"` + + SaveFolder string `bson:"save_folder" json:"save_folder"` + + IsDeleted bool `bson:"is_deleted" json:"is_deleted"` + + CreatedAt time.Time `bson:"created_at" json:"created_at"` + + UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` } diff --git a/dal/model/template.go b/dal/model/template.go index 1f21140..4d9943c 100644 --- a/dal/model/template.go +++ b/dal/model/template.go @@ -5,15 +5,29 @@ import ( ) type Template struct { - ID string `bson:"_id,omitempty" json:"id"` - UserID string `bson:"user_id" json:"user_id"` - LeadId int64 `bson:"lead_id" json:"lead_id"` // AMO lead - Name string `bson:"name" json:"name"` // Название шаблона - File string `bson:"file" json:"file"` // Имя файла-шаблона for Yandex Disk OR File id for Google Drive - StorageID string `bson:"storage_id" json:"storage_id"` // ID of GDisk or YaDisk - StorageType string `bson:"storage_type" json:"storage_type"` - GroupIDs []string `bson:"group_ids" json:"group_ids"` - IsDeleted bool `bson:"is_deleted" json:"is_deleted"` - CreatedAt time.Time `bson:"created_at" json:"created_at"` - UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` + ID string `bson:"_id,omitempty" json:"id"` + + PenaID string `bson:"pena_id" json:"pena_id"` + + /* AMO lead */ + LeadID int64 `bson:"lead_id" json:"lead_id"` + + /* Название шаблона */ + Name string `bson:"name" json:"name"` + + /* Имя файла-шаблона for Yandex Disk OR File id for Google Drive */ + File string `bson:"file" json:"file"` + + /* ID of GDisk or YaDisk */ + StorageID string `bson:"storage_id" json:"storage_id"` + + StorageType string `bson:"storage_type" json:"storage_type"` + + GroupIDs []string `bson:"group_ids" json:"group_ids"` + + IsDeleted bool `bson:"is_deleted" json:"is_deleted"` + + CreatedAt time.Time `bson:"created_at" json:"created_at"` + + UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` } diff --git a/dal/model/templateGroup.go b/dal/model/templateGroup.go index 215f25b..7c54ce7 100644 --- a/dal/model/templateGroup.go +++ b/dal/model/templateGroup.go @@ -6,7 +6,7 @@ import ( type TemplateGroup struct { ID string `bson:"_id,omitempty" json:"id"` - UserID string `bson:"user_id" json:"user_id"` + PenaID string `bson:"pena_id" json:"pena_id"` Name string `bson:"name" json:"name"` CreatedAt time.Time `bson:"created_at" json:"created_at"` UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` diff --git a/dal/model/user.go b/dal/model/user.go deleted file mode 100644 index f857a27..0000000 --- a/dal/model/user.go +++ /dev/null @@ -1,18 +0,0 @@ -package model - -import ( - "time" -) - -type User struct { - ID string `bson:"_id,omitempty"` - FullName string `bson:"full_name"` - Email string `bson:"email"` - Password string `bson:"password"` - IsActivated bool `bson:"is_activated"` - RoleID int `bson:"role_id"` - JwtToken string `bson:"jwt_token"` // not in use - IsDeleted bool `bson:"is_deleted"` - CreatedAt time.Time `bson:"created_at"` - UpdatedAt time.Time `bson:"updated_at"` -} diff --git a/dal/model/workerTask.go b/dal/model/workerTask.go index 1189bb0..77b532a 100644 --- a/dal/model/workerTask.go +++ b/dal/model/workerTask.go @@ -5,33 +5,44 @@ import ( ) type WorkerTask struct { - ID string `json:"id" bson:"_id,omitempty"` // Идентификатор задачи - UserID string `json:"user_id" bson:"user_id"` // Пользователь пены - AmoID string `json:"amo_id" bson:"amo_id"` // Амо аккаунт вызвавший генерацию - AmoUserID int64 `json:"amo_user_id" bson:"amo_user_id"` // Пользователь амо вызвавший генерацию - Status WorkerTaskStatus `json:"status" bson:"status"` // Статус генерации - LeadId int64 `json:"lead_id" bson:"lead_id"` // Сделка по которой происходит генерация - TemplateID string `json:"template_id" bson:"template_id"` // Шаблон для генерации - Source WorkerSource `json:"source" bson:"source"` // Исходный файл-шаблон - Target WorkerTarget `json:"target" bson:"target"` // Куда отправить результат - DownloadUrl string `json:"download_url" bson:"download_url"` // Ссылка для скачивания результата - PublicUrl string `json:"public_url" bson:"public_url"` // Публичная ссылка для просмотра\редактирования\скачивания - UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` // Время последнего обновления - CreatedAt time.Time `json:"created_at" bson:"created_at"` // Время создания -} + /* Идентификатор задачи */ + ID string `json:"id" bson:"_id,omitempty"` -func NewWorkerTask(userID string, amoID string, amoUserID int64, status WorkerTaskStatus, leadId int64, - templateID string, source WorkerSource, target WorkerTarget) *WorkerTask { - return &WorkerTask{ - UserID: userID, - AmoID: amoID, - AmoUserID: amoUserID, - Status: status, - LeadId: leadId, - TemplateID: templateID, - Source: source, - Target: target, - } + /* Пользователь пены */ + PenaID string `json:"pena_id" bson:"pena_id"` + + /* Амо аккаунт вызвавший генерацию */ + AmoID string `json:"amo_id" bson:"amo_id"` + + /* Пользователь амо вызвавший генерацию */ + AmoUserID int64 `json:"amo_user_id" bson:"amo_user_id"` + + /* Статус генерации */ + Status WorkerTaskStatus `json:"status" bson:"status"` + + /* Сделка по которой происходит генерация */ + LeadID int64 `json:"lead_id" bson:"lead_id"` + + /* Шаблон для генерации */ + TemplateID string `json:"template_id" bson:"template_id"` + + /* Исходный файл-шаблон */ + Source WorkerSource `json:"source" bson:"source"` + + /* Куда отправить результат */ + Target WorkerTarget `json:"target" bson:"target"` + + /* Ссылка для скачивания результата */ + DownloadURL string `json:"download_url" bson:"download_url"` + + /* Публичная ссылка для просмотра\редактирования\скачивания */ + PublicURL string `json:"public_url" bson:"public_url"` + + /* Время последнего обновления */ + UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` + + /* Время создания */ + CreatedAt time.Time `json:"created_at" bson:"created_at"` } type WorkerTaskStatus string diff --git a/dal/model/yadisk.go b/dal/model/yadisk.go index b2410a2..cfe1e1a 100644 --- a/dal/model/yadisk.go +++ b/dal/model/yadisk.go @@ -1,29 +1,50 @@ package model import ( - "golang.org/x/oauth2" "time" + + "golang.org/x/oauth2" ) -// YaDisk (StorageType) - хранит информацию о пользователе Yandex и данных необходимых для хранилища. -// Пользователь может иметь несколько хранилищ YaDisk. -// Login - уникальное поле и закрепляется только за одним пользователем +/* +YaDisk (StorageType) - хранит информацию о пользователе Yandex и данных необходимых для хранилища. + + Пользователь может иметь несколько хранилищ YaDisk. +*/ type YaDisk struct { - ID string `bson:"_id,omitempty" json:"id"` - UserID string `bson:"user_id" json:"user_id"` - UID string `bson:"uid" json:"uid"` // Yandex UID. Unique ? - Login string `bson:"login" json:"login"` // Yandex login. Unique ? - DisplayName string `bson:"display_name" json:"display_name"` // Отображаемое имя пользователя в Yandex - AccessToken string `bson:"access_token" json:"-"` - RefreshToken string `bson:"refresh_token" json:"-"` - ExpiresIn time.Time `bson:"expires_in" json:"-"` - TokenType string `bson:"token_type" json:"-"` - Name string `bson:"name" json:"name"` // Пользовательское название хранилища - TemplateFolder string `bson:"template_folder" json:"template_folder"` - SaveFolder string `bson:"save_folder" json:"save_folder"` - IsDeleted bool `bson:"is_deleted" json:"is_deleted"` - CreatedAt time.Time `bson:"created_at" json:"created_at"` - UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` + ID string `bson:"_id,omitempty" json:"id"` + + PenaID string `bson:"pena_id" json:"pena_id"` + + /* Yandex UID. уникальное поле и закрепляется только за одним пользователем */ + UID string `bson:"uid" json:"uid"` + + /* Yandex login. уникальное поле и закрепляется только за одним пользователем */ + Login string `bson:"login" json:"login"` + + /* Отображаемое имя пользователя в Yandex */ + DisplayName string `bson:"display_name" json:"display_name"` + + AccessToken string `bson:"access_token" json:"-"` + + RefreshToken string `bson:"refresh_token" json:"-"` + + ExpiresIn time.Time `bson:"expires_in" json:"-"` + + TokenType string `bson:"token_type" json:"-"` + + /* Пользовательское название хранилища */ + Name string `bson:"name" json:"name"` + + TemplateFolder string `bson:"template_folder" json:"template_folder"` + + SaveFolder string `bson:"save_folder" json:"save_folder"` + + IsDeleted bool `bson:"is_deleted" json:"is_deleted"` + + CreatedAt time.Time `bson:"created_at" json:"created_at"` + + UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` } func (m *YaDisk) Token() *oauth2.Token { diff --git a/dal/mongos/amo.go b/dal/mongos/amo.go index a5ef7c9..95a8c1d 100644 --- a/dal/mongos/amo.go +++ b/dal/mongos/amo.go @@ -2,13 +2,15 @@ package mongos import ( "context" - "errors" + "fmt" + "time" + + "github.com/pkg/errors" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.uber.org/zap" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" - "time" ) type Amo struct { @@ -23,6 +25,7 @@ func InitAmo(db *mongo.Database, logger *zap.Logger) *Amo { func (d *Amo) InsertOrUpdate(ctx context.Context, record *model.Amo) (string, error) { if record.AccountID == "" { err := errors.New("got empty account_id") + d.logger.Error("ErrorInsertOrUpdateAmo", zap.Error(err)) return "", err } @@ -32,15 +35,18 @@ func (d *Amo) InsertOrUpdate(ctx context.Context, record *model.Amo) (string, er found, err := d.GetByAccountID(ctx, record.AccountID) if err != nil { + d.logger.Error("ErrorInsertOrUpdateAmo", zap.Error(err)) return "", err } if found == nil { - result, err := d.coll.InsertOne(ctx, record) + var result *mongo.InsertOneResult + result, err = d.coll.InsertOne(ctx, record) if err != nil { d.logger.Error("ErrorInsertOrUpdateAmo", zap.Error(err)) return "", err } + id := result.InsertedID.(primitive.ObjectID).Hex() d.logger.Info("ErrorInsertOrUpdateAmo", zap.String("id", id)) @@ -71,33 +77,35 @@ func (d *Amo) GetByID(ctx context.Context, id string) (*model.Amo, error) { err = d.coll.FindOne(ctx, filter).Decode(&result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetAmo", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetAmo", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetAmo", zap.Error(err)) + return nil, nil } d.logger.Info("InfoGetAmo", zap.String("id", result.ID)) return &result, nil } -func (d *Amo) GetListByUserID(ctx context.Context, userID string) ([]model.Amo, error) { - filter := bson.M{"user_id": userID, "is_deleted": false} +func (d *Amo) GetListByPenaID(ctx context.Context, penaID string) ([]model.Amo, error) { + filter := bson.M{"pena_id": penaID, "is_deleted": false} var result []model.Amo cur, err := d.coll.Find(ctx, filter) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetListAmo", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetListAmo", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetListAmo", zap.Error(err)) + return nil, err } err = cur.All(ctx, &result) @@ -110,27 +118,77 @@ func (d *Amo) GetListByUserID(ctx context.Context, userID string) ([]model.Amo, return result, nil } -func (d *Amo) GetByAccountID(ctx context.Context, accId string) (*model.Amo, error) { - filter := bson.M{"account_id": accId, "is_deleted": false} +func (d *Amo) GetByAccountID(ctx context.Context, accountID string) (*model.Amo, error) { + filter := bson.M{"account_id": accountID, "is_deleted": false} var result model.Amo err := d.coll.FindOne(ctx, filter).Decode(&result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetAmo", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetAmo", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetAmo", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetAmo", zap.String("id", result.ID)) return &result, nil } -// Update - обновляет запись по id или accountID +func (d *Amo) GetByPenaID(ctx context.Context, penaID string) (*model.Amo, error) { + filter := bson.M{"pena_id": penaID, "is_deleted": false} + + var result model.Amo + + err := d.coll.FindOne(ctx, filter).Decode(&result) + + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetAmo", zap.String("id", "not found")) + return nil, nil + } + + d.logger.Error("ErrorGetAmo", zap.Error(err)) + return nil, err + } + + d.logger.Info("InfoGetAmo", zap.String("id", result.ID)) + return &result, nil +} + +func (d *Amo) GetAll(ctx context.Context) ([]model.Amo, error) { + filter := bson.M{"is_deleted": false} + + var result []model.Amo + + cur, err := d.coll.Find(ctx, filter) + + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetAllAmo", zap.String("id", "not found")) + return nil, nil + } + + d.logger.Error("ErrorGetAllAmo", zap.Error(err)) + return nil, err + } + + err = cur.All(ctx, &result) + if err != nil { + d.logger.Error("ErrorGetAllAmo", zap.Error(err)) + return nil, err + } + + d.logger.Info("InfoGetAllAmo") + + return result, nil +} + +// Update - обновляет запись по id или accountID. func (d *Amo) Update(ctx context.Context, record *model.Amo) error { filter := bson.M{"is_deleted": false} @@ -152,6 +210,14 @@ func (d *Amo) Update(ctx context.Context, record *model.Amo) error { update := bson.M{"updated_at": time.Now()} + if record.AccountID != "" { + update["account_id"] = record.AccountID + } + + if record.PenaID != "" { + update["pena_id"] = record.PenaID + } + // Token if record.AccessToken != "" { update["access_token"] = record.AccessToken @@ -182,7 +248,7 @@ func (d *Amo) Update(ctx context.Context, record *model.Amo) error { update["access_rules.delete"] = record.AccessRules.Delete } - updated, err := d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) + updated, err := d.coll.UpdateOne(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorUpdateAmo", zap.Error(err)) @@ -199,18 +265,12 @@ func (d *Amo) Update(ctx context.Context, record *model.Amo) error { return nil } -func (d *Amo) DeleteByUserID(ctx context.Context, userID string) error { - if userID == "" { - err := errors.New("got empty user id") - d.logger.Error("ErrorDeleteAmo", zap.Error(err)) - return err - } - - filter := bson.M{"user_id": userID, "is_deleted": false} +func (d *Amo) DeleteByPenaID(ctx context.Context, penaID string) error { + filter := bson.M{"pena_id": penaID, "is_deleted": false} update := bson.M{"updated_at": time.Now(), "is_deleted": true} - _, err := d.coll.UpdateMany(ctx, filter, bson.D{{"$set", update}}) + _, err := d.coll.UpdateMany(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorDeleteAmo", zap.Error(err)) return err @@ -243,7 +303,7 @@ func (d *Amo) UpdateAccessRules(ctx context.Context, id string, record *model.Am update["access_rules.delete"] = record.Delete } - _, err = d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) + _, err = d.coll.UpdateOne(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorUpdateAmoAccessRules", zap.Error(err)) @@ -252,3 +312,178 @@ func (d *Amo) UpdateAccessRules(ctx context.Context, id string, record *model.Am return nil } + +func (d *Amo) AddPrivilege(ctx context.Context, id, privilegeID string, privilegeAmount int64) error { + objID, err := primitive.ObjectIDFromHex(id) + + if err != nil { + d.logger.Error("ErrorAmoAddPrivilege", zap.Error(err)) + return err + } + + filter := bson.M{"_id": objID, "is_deleted": false} + + privilegeKey := fmt.Sprintf("privileges.%v", privilegeID) + + now := time.Now() + + updateData := bson.M{ + privilegeKey: bson.M{ + "created_at": now, + "amount": privilegeAmount, + }, + "updated_at": now, + } + + update := bson.D{ + {Key: "$set", Value: updateData}, + } + + _, err = d.coll.UpdateOne(ctx, filter, update) + + if err != nil { + d.logger.Error("ErrorAmoAddPrivilege", zap.Error(err)) + return err + } + + return nil +} + +func (d *Amo) AddPrivilegeByPenaID(ctx context.Context, penaID, privilegeID string, privilegeAmount int64) error { + filter := bson.M{"pena_id": penaID, "is_deleted": false} + + privilegeKey := fmt.Sprintf("privileges.%v", privilegeID) + + now := time.Now() + + updateData := bson.M{ + privilegeKey: bson.M{ + "created_at": now, + "amount": privilegeAmount, + }, + "updated_at": now, + } + + update := bson.D{ + {Key: "$set", Value: updateData}, + } + + _, err := d.coll.UpdateOne(ctx, filter, update) + + if err != nil { + d.logger.Error("ErrorAmoAddPrivilege", zap.Error(err)) + return err + } + + return nil +} + +func (d *Amo) UpdateAmountPrivilege(ctx context.Context, id, privilegeID string, privilegeAmount int64) error { + objID, err := primitive.ObjectIDFromHex(id) + + if err != nil { + d.logger.Error("ErrorAmoUpdateAmountPrivilege", zap.Error(err)) + return err + } + + privilegeAmountKey := fmt.Sprintf("privileges.%v.amount", privilegeID) + + filter := bson.M{ + "_id": objID, + "is_deleted": false, + privilegeAmountKey: bson.M{"$exists": true}, + } + + updateData := bson.M{ + "updated_at": time.Now(), + privilegeAmountKey: privilegeAmount, + } + + update := bson.D{ + {Key: "$set", Value: updateData}, + } + + _, err = d.coll.UpdateOne(ctx, filter, update) + + if err != nil { + d.logger.Error("ErrorAmoUpdateAmountPrivilege", zap.Error(err)) + return err + } + + return nil +} + +func (d *Amo) UpdateAmountPrivilegeByPenaID(ctx context.Context, penaID, privilegeID string, privilegeAmount int64) error { + privilegeAmountKey := fmt.Sprintf("privileges.%v.amount", privilegeID) + + filter := bson.M{ + "pena_id": penaID, + "is_deleted": false, + privilegeAmountKey: bson.M{"$exists": true}, + } + + updateData := bson.M{ + "updated_at": time.Now(), + privilegeAmountKey: privilegeAmount, + } + + update := bson.D{ + {Key: "$set", Value: updateData}, + } + + _, err := d.coll.UpdateOne(ctx, filter, update) + + if err != nil { + d.logger.Error("ErrorAmoUpdateAmountPrivilege", zap.Error(err)) + return err + } + + return nil +} + +func (d *Amo) DeletePrivilege(ctx context.Context, id, privilegeID string) error { + objID, err := primitive.ObjectIDFromHex(id) + + if err != nil { + d.logger.Error("ErrorAmoDeletetPrivilege", zap.Error(err)) + return err + } + + filter := bson.M{"_id": objID, "is_deleted": false} + + privilegeKey := fmt.Sprintf("privileges.%v", privilegeID) + + update := bson.D{ + {Key: "$unset", Value: bson.M{privilegeKey: ""}}, + {Key: "$set", Value: bson.M{"updated_at": time.Now()}}, + } + + _, err = d.coll.UpdateOne(ctx, filter, update) + + if err != nil { + d.logger.Error("ErrorAmoDeletePrivilege", zap.Error(err)) + return err + } + + return nil +} + +func (d *Amo) DeletePrivilegeByPenaID(ctx context.Context, penaID, privilegeID string) error { + filter := bson.M{"_id": penaID, "is_deleted": false} + + privilegeKey := fmt.Sprintf("privileges.%v", privilegeID) + + update := bson.D{ + {Key: "$unset", Value: bson.M{privilegeKey: ""}}, + {Key: "$set", Value: bson.M{"updated_at": time.Now()}}, + } + + _, err := d.coll.UpdateOne(ctx, filter, update) + + if err != nil { + d.logger.Error("ErrorAmoDeletePrivilege", zap.Error(err)) + return err + } + + return nil +} diff --git a/dal/mongos/gdisk.go b/dal/mongos/gdisk.go index 75819a7..f118784 100644 --- a/dal/mongos/gdisk.go +++ b/dal/mongos/gdisk.go @@ -3,12 +3,13 @@ package mongos import ( "context" "errors" + "time" + "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.uber.org/zap" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" - "time" ) type GDisk struct { @@ -45,11 +46,14 @@ func (d *GDisk) InsertOrUpdate(ctx context.Context, record *model.GDisk) (string if record.TemplateFolder == "" { record.TemplateFolder = "templategen/templates" } + if record.SaveFolder == "" { record.SaveFolder = "templategen/saved" } - result, err := d.coll.InsertOne(ctx, record) + var result *mongo.InsertOneResult + result, err = d.coll.InsertOne(ctx, record) + if err != nil { d.logger.Error("ErrorInsertOrUpdateGDisk", zap.Error(err)) return "", err @@ -82,13 +86,14 @@ func (d *GDisk) GetByID(ctx context.Context, id string) (*model.GDisk, error) { err = d.coll.FindOne(ctx, filter).Decode(&result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetGDisk", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetGDisk", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetGDisk", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetGDisk", zap.String("id", result.ID)) @@ -102,33 +107,35 @@ func (d *GDisk) GetByEmail(ctx context.Context, email string) (*model.GDisk, err err := d.coll.FindOne(ctx, filter).Decode(&result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetGDisk", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetGDisk", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetGDisk", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetGDisk", zap.String("id", result.ID)) return &result, nil } -func (d *GDisk) GetListByUserID(ctx context.Context, userID string) ([]model.GDisk, error) { - filter := bson.M{"user_id": userID, "is_deleted": false} +func (d *GDisk) GetListByPenaID(ctx context.Context, penaID string) ([]model.GDisk, error) { + filter := bson.M{"pena_id": penaID, "is_deleted": false} var result []model.GDisk cur, err := d.coll.Find(ctx, filter) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetListGDisk", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetListGDisk", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetListGDisk", zap.Error(err)) + return nil, err } err = cur.All(ctx, &result) @@ -222,7 +229,7 @@ func (d *GDisk) Update(ctx context.Context, record *model.GDisk) error { update["save_folder_id"] = record.SaveFolderID } - _, err := d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) + _, err := d.coll.UpdateOne(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorUpdateGDisk", zap.Error(err)) @@ -232,18 +239,12 @@ func (d *GDisk) Update(ctx context.Context, record *model.GDisk) error { return nil } -func (d *GDisk) DeleteByUserID(ctx context.Context, userID string) error { - if userID == "" { - err := errors.New("got empty user id") - d.logger.Error("ErrorDeleteGDisk", zap.Error(err)) - return err - } - - filter := bson.M{"user_id": userID, "is_deleted": false} +func (d *GDisk) DeleteByPenaID(ctx context.Context, penaID string) error { + filter := bson.M{"pena_id": penaID, "is_deleted": false} update := bson.M{"updated_at": time.Now(), "is_deleted": true} - _, err := d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) + _, err := d.coll.UpdateOne(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorDeleteGDisk", zap.Error(err)) return err diff --git a/dal/mongos/history.go b/dal/mongos/history.go index a000e6f..6051881 100644 --- a/dal/mongos/history.go +++ b/dal/mongos/history.go @@ -3,12 +3,12 @@ package mongos import ( "context" "errors" - "go.mongodb.org/mongo-driver/mongo/options" "time" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" ) @@ -59,13 +59,14 @@ func (d *History) GetByID(ctx context.Context, id string) (*model.History, error err = d.coll.FindOne(ctx, filter).Decode(&result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetHistory", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetHistory", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetHistory", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetHistory", zap.String("id", result.ID)) @@ -76,11 +77,6 @@ type HistoryFilter struct { AmoID string `bson:"amo_id,omitempty" json:"amo_id"` WorkerTaskID string `bson:"worker_task_id,omitempty" json:"worker_task_id"` AmoUserID int64 `bson:"amo_user_id,omitempty" json:"amo_user_id"` - // LeadID int64 `bson:"lead_id,omitempty" json:"lead_id"` - // Trigger model.HistoryTrigger `bson:"trigger,omitempty" json:"trigger"` - // TemplateID string `bson:"template_id,omitempty" json:"template_id"` - // Source *model.HistorySource `bson:"source,omitempty" json:"source"` - // Target *model.HistoryTarget `bson:"target,omitempty" json:"target"` } func (d *History) GetByFilter(ctx context.Context, filter *HistoryFilter) ([]model.History, error) { @@ -88,14 +84,12 @@ func (d *History) GetByFilter(ctx context.Context, filter *HistoryFilter) ([]mod filter = &HistoryFilter{} } - cur, err := d.coll.Find(ctx, bson.M{}) + cur, err := d.coll.Find(ctx, filter) if err == mongo.ErrNoDocuments { return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetHistory", zap.Error(err)) - return nil, err - } + } else if err != nil { + d.logger.Error("ErrorGetHistory", zap.Error(err)) + return nil, err } var result []model.History @@ -150,13 +144,14 @@ func (d *History) GetByWorkerTaskID(ctx context.Context, workerTaskID string) (* err := d.coll.FindOne(ctx, filter).Decode(&result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetHistory", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetHistory", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetHistory", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetHistory", zap.String("id", result.ID)) @@ -192,15 +187,15 @@ func (d *History) UpdateByID(ctx context.Context, record *model.History) error { update["worker_task_id"] = record.WorkerTaskID } - if record.PublicUrl != "" { - update["public_url"] = record.PublicUrl + if record.PublicURL != "" { + update["public_url"] = record.PublicURL } - if record.DownloadUrl != "" { - update["download_url"] = record.DownloadUrl + if record.DownloadURL != "" { + update["download_url"] = record.DownloadURL } - _, err = d.coll.UpdateByID(ctx, objID, bson.D{{"$set", update}}) + _, err = d.coll.UpdateByID(ctx, objID, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorUpdateHistory", zap.Error(err)) return err diff --git a/dal/mongos/penadisk.go b/dal/mongos/penadisk.go index 01f91e1..53fc693 100644 --- a/dal/mongos/penadisk.go +++ b/dal/mongos/penadisk.go @@ -3,13 +3,14 @@ package mongos import ( "context" "errors" + "time" + "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.uber.org/zap" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" "penahub.gitlab.yandexcloud.net/backend/templategen/penadisk" - "time" ) type PenaDisk struct { @@ -25,13 +26,9 @@ func (d *PenaDisk) InsertOrUpdate(ctx context.Context, record *model.PenaDisk) ( record.CreatedAt = time.Now() record.UpdatedAt = record.CreatedAt - var found *model.PenaDisk - var err error + found, err := d.GetByPenaID(ctx, record.PenaID) - if record.UserID != "" { - found, err = d.GetByUserID(ctx, record.UserID) - } else { - err = errors.New("user_id required") + if err != nil { d.logger.Error("ErrorInsertOrUpdatePenaDisk", zap.Error(err)) return "", err } @@ -39,10 +36,10 @@ func (d *PenaDisk) InsertOrUpdate(ctx context.Context, record *model.PenaDisk) ( if found == nil { // Set default TemplateFolder && SaveFolder if record.TemplateFolder == "" { - record.TemplateFolder = penadisk.DEFAULT_TEMPLATE_FOLDER + record.TemplateFolder = penadisk.DefaultTemplateFolder } if record.SaveFolder == "" { - record.SaveFolder = penadisk.DEFAULT_SAVE_FOLDER + record.SaveFolder = penadisk.DefaultSaveFolder } result, err := d.coll.InsertOne(ctx, record) @@ -70,40 +67,42 @@ func (d *PenaDisk) GetByID(ctx context.Context, id string) (*model.PenaDisk, err err = d.coll.FindOne(ctx, filter).Decode(&result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetPenaDisk", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetPenaDisk", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetPenaDisk", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetPenaDisk", zap.String("id", result.ID)) return &result, nil } -func (d *PenaDisk) GetByUserID(ctx context.Context, userID string) (*model.PenaDisk, error) { - filter := bson.M{"user_id": userID, "is_deleted": false} +func (d *PenaDisk) GetByPenaID(ctx context.Context, penaID string) (*model.PenaDisk, error) { + filter := bson.M{"pena_id": penaID, "is_deleted": false} var result model.PenaDisk err := d.coll.FindOne(ctx, filter).Decode(&result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetPenaDisk", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetPenaDisk", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetPenaDisk", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetPenaDisk", zap.String("id", result.ID)) return &result, nil } -// Update - обновляет запись по её id или UserID +// Update - обновляет запись по её id или PenaID. func (d *PenaDisk) Update(ctx context.Context, record *model.PenaDisk) error { filter := bson.M{"is_deleted": false} @@ -114,10 +113,10 @@ func (d *PenaDisk) Update(ctx context.Context, record *model.PenaDisk) error { return err } filter["_id"] = objID - } else if record.UserID != "" { - filter["user_id"] = record.UserID + } else if record.PenaID != "" { + filter["pena_id"] = record.PenaID } else { - err := errors.New("got empty id and user_id") + err := errors.New("got empty id and pena_id") d.logger.Error("ErrorUpdatePenaDisk", zap.Error(err)) return err } @@ -136,7 +135,7 @@ func (d *PenaDisk) Update(ctx context.Context, record *model.PenaDisk) error { update["save_folder"] = record.SaveFolder } - _, err := d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) + _, err := d.coll.UpdateOne(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorUpdatePenaDisk", zap.Error(err)) @@ -146,18 +145,12 @@ func (d *PenaDisk) Update(ctx context.Context, record *model.PenaDisk) error { return nil } -func (d *PenaDisk) DeleteByUserID(ctx context.Context, userID string) error { - if userID == "" { - err := errors.New("got empty user id") - d.logger.Error("ErrorDeletePenaDisk", zap.Error(err)) - return err - } - - filter := bson.M{"user_id": userID, "is_deleted": false} +func (d *PenaDisk) DeleteByPenaID(ctx context.Context, penaID string) error { + filter := bson.M{"pena_id": penaID, "is_deleted": false} update := bson.M{"updated_at": time.Now(), "is_deleted": true} - _, err := d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) + _, err := d.coll.UpdateOne(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorDeletePenaDisk", zap.Error(err)) return err diff --git a/dal/mongos/template.go b/dal/mongos/template.go index 6511751..f80d3ee 100644 --- a/dal/mongos/template.go +++ b/dal/mongos/template.go @@ -4,12 +4,13 @@ import ( "context" "errors" "fmt" + "time" + "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.uber.org/zap" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" - "time" ) type Template struct { @@ -27,24 +28,12 @@ func (d *Template) Insert(ctx context.Context, record *model.Template) (string, record.UpdatedAt = now record.IsDeleted = false - if record.UserID == "" { + if record.PenaID == "" { err := errors.New("got empty user id") d.logger.Error("ErrorDeleteTemplate", zap.Error(err)) return "", err } - //found, err := d.GetByNameAndUserID(ctx, record.Name, record.UserID) - //if err != nil { - // d.logger.Error("ErrorInsertTemplate", zap.Error(err)) - // return "", err - //} - - //if found != nil { - // err = errors.New("template with this name already exists") - // d.logger.Error("ErrorInsertTemplate", zap.Error(err)) - // return "", err - //} - if record.GroupIDs == nil { record.GroupIDs = []string{} } @@ -75,13 +64,14 @@ func (d *Template) GetByID(ctx context.Context, id string) (*model.Template, err err = d.coll.FindOne(ctx, filter).Decode(&result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetTemplate", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetTemplate", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetTemplate", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetTemplate", zap.String("id", result.ID)) @@ -89,20 +79,21 @@ func (d *Template) GetByID(ctx context.Context, id string) (*model.Template, err return &result, nil } -func (d *Template) GetByLeadId(ctx context.Context, id int64) (*model.Template, error) { +func (d *Template) GetByLeadID(ctx context.Context, id int64) (*model.Template, error) { filter := bson.M{"lead_id": id, "is_deleted": false} var result model.Template err := d.coll.FindOne(ctx, filter).Decode(&result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetTemplate", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetTemplate", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetTemplate", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetTemplate", zap.String("id", result.ID)) @@ -110,8 +101,8 @@ func (d *Template) GetByLeadId(ctx context.Context, id int64) (*model.Template, return &result, nil } -func (d *Template) GetByNameAndUserID(ctx context.Context, name, userID string) (*model.Template, error) { - filter := bson.M{"name": name, "user_id": userID, "is_deleted": false} +func (d *Template) GetByNameAndPenaID(ctx context.Context, name, penaID string) (*model.Template, error) { + filter := bson.M{"name": name, "pena_id": penaID, "is_deleted": false} fmt.Println("-----------------------------------") fmt.Println(filter) @@ -119,13 +110,14 @@ func (d *Template) GetByNameAndUserID(ctx context.Context, name, userID string) var result model.Template err := d.coll.FindOne(ctx, filter).Decode(&result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetTemplate", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetTemplate", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetTemplate", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetTemplate", zap.String("id", result.ID)) @@ -133,20 +125,21 @@ func (d *Template) GetByNameAndUserID(ctx context.Context, name, userID string) return &result, nil } -func (d *Template) GetByFilenameAndUserID(ctx context.Context, name, userID string) (*model.Template, error) { - filter := bson.M{"filename": name, "user_id": userID, "is_deleted": false} +func (d *Template) GetByFilenameAndPenaID(ctx context.Context, name, penaID string) (*model.Template, error) { + filter := bson.M{"filename": name, "pena_id": penaID, "is_deleted": false} var result model.Template err := d.coll.FindOne(ctx, filter).Decode(&result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetTemplate", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetTemplate", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetTemplate", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetTemplate", zap.String("id", result.ID)) @@ -154,8 +147,8 @@ func (d *Template) GetByFilenameAndUserID(ctx context.Context, name, userID stri return &result, nil } -func (d *Template) GetListByUserID(ctx context.Context, userID string) ([]model.Template, error) { - filter := bson.M{"user_id": userID, "is_deleted": false} +func (d *Template) GetListByPenaID(ctx context.Context, penaID string) ([]model.Template, error) { + filter := bson.M{"pena_id": penaID, "is_deleted": false} var result []model.Template @@ -163,29 +156,29 @@ func (d *Template) GetListByUserID(ctx context.Context, userID string) ([]model. if err == mongo.ErrNoDocuments { return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetTemplate", zap.Error(err)) - return nil, err - } + } else if err != nil { + d.logger.Error("ErrorGetTemplate", zap.Error(err)) + return nil, err } err = cursor.All(ctx, &result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetTemplate", zap.Error(err)) - return nil, err + + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetTemplate", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetTemplate", zap.Error(err)) + return nil, err } return result, nil } -func (d *Template) GetListByUserIDAndStorageType(ctx context.Context, userID, storageType string) ([]model.Template, +func (d *Template) GetListByPenaIDAndStorageType(ctx context.Context, penaID, storageType string) ([]model.Template, error) { - filter := bson.M{"user_id": userID, "storage_type": storageType, "is_deleted": false} + filter := bson.M{"pena_id": penaID, "storage_type": storageType, "is_deleted": false} var result []model.Template @@ -193,28 +186,27 @@ func (d *Template) GetListByUserIDAndStorageType(ctx context.Context, userID, st if err == mongo.ErrNoDocuments { return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetTemplate", zap.Error(err)) - return nil, err - } + } else if err != nil { + d.logger.Error("ErrorGetTemplate", zap.Error(err)) + return nil, err } err = cursor.All(ctx, &result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetTemplate", zap.Error(err)) - return nil, err - } - } + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetTemplate", zap.String("id", "not found")) + return nil, nil + } + + d.logger.Error("ErrorGetTemplate", zap.Error(err)) + return nil, err + } return result, nil } -func (d *Template) GetListByGroupID(ctx context.Context, groupID, userID string) ([]model.Template, error) { - filter := bson.M{"user_id": userID} +func (d *Template) GetListByGroupID(ctx context.Context, groupID, penaID string) ([]model.Template, error) { + filter := bson.M{"pena_id": penaID} if groupID == "" { filter["group_ids"] = []string{} @@ -240,7 +232,7 @@ func (d *Template) GetListByGroupID(ctx context.Context, groupID, userID string) return result, nil } -func (d *Template) PushGroup(ctx context.Context, id, groupID, userID string) error { +func (d *Template) PushGroup(ctx context.Context, id, groupID, penaID string) error { objID, err := primitive.ObjectIDFromHex(id) if err != nil { @@ -256,8 +248,8 @@ func (d *Template) PushGroup(ctx context.Context, id, groupID, userID string) er filter := bson.M{"_id": objID} - if userID != "" { - filter["user_id"] = userID + if penaID != "" { + filter["pena_id"] = penaID } update := bson.M{ @@ -277,7 +269,7 @@ func (d *Template) PushGroup(ctx context.Context, id, groupID, userID string) er return nil } -func (d *Template) PullGroup(ctx context.Context, id, groupID, userID string) error { +func (d *Template) PullGroup(ctx context.Context, id, groupID, penaID string) error { objID, err := primitive.ObjectIDFromHex(id) if err != nil { @@ -293,8 +285,8 @@ func (d *Template) PullGroup(ctx context.Context, id, groupID, userID string) er filter := bson.M{"_id": objID} - if userID != "" { - filter["user_id"] = userID + if penaID != "" { + filter["pena_id"] = penaID } update := bson.M{ @@ -362,8 +354,8 @@ func (d *Template) UpdateByID(ctx context.Context, record *model.Template) error update["file"] = record.File } - if record.LeadId > 0 { - update["lead_id"] = record.LeadId + if record.LeadID > 0 { + update["lead_id"] = record.LeadID } if record.StorageID != "" { @@ -374,7 +366,7 @@ func (d *Template) UpdateByID(ctx context.Context, record *model.Template) error update["storage_type"] = record.StorageType } - _, err = d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) + _, err = d.coll.UpdateOne(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorUpdateTemplate", zap.Error(err)) @@ -385,13 +377,13 @@ func (d *Template) UpdateByID(ctx context.Context, record *model.Template) error } func (d *Template) UpdateByLeadID(ctx context.Context, record *model.Template) error { - if record.LeadId <= 0 { + if record.LeadID < 1 { err := errors.New("got empty id") d.logger.Error("ErrorUpdateTemplate", zap.Error(err)) return err } - filter := bson.M{"lead_id": record.LeadId, "is_deleted": false} + filter := bson.M{"lead_id": record.LeadID, "is_deleted": false} update := bson.M{"updated_at": time.Now()} @@ -403,8 +395,8 @@ func (d *Template) UpdateByLeadID(ctx context.Context, record *model.Template) e update["file"] = record.File } - if record.LeadId > 0 { - update["lead_id"] = record.LeadId + if record.LeadID > 0 { + update["lead_id"] = record.LeadID } if record.StorageID != "" { @@ -415,7 +407,7 @@ func (d *Template) UpdateByLeadID(ctx context.Context, record *model.Template) e update["storage_type"] = record.StorageType } - _, err := d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) + _, err := d.coll.UpdateOne(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorUpdateTemplate", zap.Error(err)) @@ -443,7 +435,7 @@ func (d *Template) DeleteByID(ctx context.Context, id string) error { update := bson.M{"updated_at": time.Now(), "is_deleted": true} - _, err = d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) + _, err = d.coll.UpdateOne(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorDeleteTemplate", zap.Error(err)) return err diff --git a/dal/mongos/templateGroup.go b/dal/mongos/templateGroup.go index 9fad680..f067be7 100644 --- a/dal/mongos/templateGroup.go +++ b/dal/mongos/templateGroup.go @@ -3,12 +3,13 @@ package mongos import ( "context" "errors" + "time" + "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.uber.org/zap" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" - "time" ) type TemplateGroup struct { @@ -25,8 +26,8 @@ func (d *TemplateGroup) Insert(ctx context.Context, record *model.TemplateGroup) record.CreatedAt = now record.UpdatedAt = now - if record.UserID == "" { - err := errors.New("user_id required") + if record.PenaID == "" { + err := errors.New("pena_id required") d.logger.Error("ErrorInsertTemplateGroup", zap.Error(err)) return "", err } @@ -64,13 +65,14 @@ func (d *TemplateGroup) GetByID(ctx context.Context, id string) (*model.Template var result model.TemplateGroup err = d.coll.FindOne(ctx, filter).Decode(&result) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetTemplateGroup", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetTemplateGroup", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetTemplateGroup", zap.Error(err)) + return nil, err } d.logger.Info("ErrorGetTemplateGroup", zap.String("id", result.ID)) @@ -78,26 +80,27 @@ func (d *TemplateGroup) GetByID(ctx context.Context, id string) (*model.Template return &result, nil } -func (d *TemplateGroup) GetListByUserID(ctx context.Context, userID string) ([]model.TemplateGroup, error) { - if userID == "" { - err := errors.New("user_id required") +func (d *TemplateGroup) GetListByPenaID(ctx context.Context, penaID string) ([]model.TemplateGroup, error) { + if penaID == "" { + err := errors.New("pena_id required") d.logger.Error("ErrorGetListTemplateGroup") return nil, err } - filter := bson.M{"user_id": userID} + filter := bson.M{"pena_id": penaID} var result []model.TemplateGroup cur, err := d.coll.Find(ctx, filter) - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetTemplateGroup", zap.Error(err)) - return nil, err + if err != nil { + if err == mongo.ErrNoDocuments { + d.logger.Info("InfoGetTemplateGroup", zap.String("id", "not found")) + return nil, nil } + + d.logger.Error("ErrorGetTemplateGroup", zap.Error(err)) + return nil, err } err = cur.All(ctx, &result) @@ -122,8 +125,8 @@ func (d *TemplateGroup) Update(ctx context.Context, record *model.TemplateGroup) filter := bson.M{"_id": objID} - if record.UserID != "" { - filter["user_id"] = record.UserID + if record.PenaID != "" { + filter["pena_id"] = record.PenaID } update := bson.M{"updated_at": time.Now()} @@ -132,7 +135,7 @@ func (d *TemplateGroup) Update(ctx context.Context, record *model.TemplateGroup) update["name"] = record.Name } - _, err = d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) + _, err = d.coll.UpdateOne(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorUpdateTemplateGroup") @@ -163,14 +166,8 @@ func (d *TemplateGroup) Delete(ctx context.Context, id string) error { return nil } -func (d *TemplateGroup) DeleteByUserID(ctx context.Context, userID string) error { - if userID == "" { - err := errors.New("user_id required") - d.logger.Error("ErrorDeleteTemplateGroup", zap.Error(err)) - return err - } - - filter := bson.M{"user_id": userID} +func (d *TemplateGroup) DeleteByPenaID(ctx context.Context, penaID string) error { + filter := bson.M{"pena_id": penaID} _, err := d.coll.DeleteMany(ctx, filter) diff --git a/dal/mongos/user.go b/dal/mongos/user.go deleted file mode 100644 index 25e6fb9..0000000 --- a/dal/mongos/user.go +++ /dev/null @@ -1,203 +0,0 @@ -package mongos - -import ( - "context" - "errors" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.uber.org/zap" - "golang.org/x/crypto/bcrypt" - "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" - "time" -) - -type User struct { - coll *mongo.Collection - logger *zap.Logger -} - -func InitUser(db *mongo.Database, logger *zap.Logger) *User { - return &User{coll: db.Collection("user"), logger: logger} -} - -func (d *User) Insert(ctx context.Context, record *model.User) (string, error) { - now := time.Now() - record.CreatedAt = now - record.UpdatedAt = now - record.IsDeleted = false - - // Find user by email - found, err := d.GetByEmail(ctx, record.Email) - if found != nil { - err = errors.New("user already exists") - } - - if err != nil { - d.logger.Error("ErrorInsertUser", zap.Error(err)) - return "", err - } - - gpass, err := bcrypt.GenerateFromPassword([]byte(record.Password), bcrypt.DefaultCost) - if err != nil { - return "", err - } - - record.Password = string(gpass) - - result, err := d.coll.InsertOne(ctx, record) - - if err != nil { - d.logger.Error("ErrorInsertUser", zap.Error(err)) - return "", err - } - - return result.InsertedID.(primitive.ObjectID).Hex(), nil -} - -func (d *User) GetByID(ctx context.Context, id string) (*model.User, error) { - objID, err := primitive.ObjectIDFromHex(id) - - if err != nil { - d.logger.Error("ErrorGetUser", zap.Error(err)) - return nil, err - } - - filter := bson.M{"_id": objID, "is_deleted": false} - - var result model.User - - err = d.coll.FindOne(ctx, filter).Decode(&result) - - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetUser", zap.Error(err)) - return nil, err - } - } - - d.logger.Info("InfoGetUser", zap.String("id", result.ID)) - - return &result, nil -} - -func (d *User) GetByEmail(ctx context.Context, email string) (*model.User, error) { - filter := bson.M{"email": email, "is_deleted": false} - - var result model.User - - err := d.coll.FindOne(ctx, filter).Decode(&result) - - if err == mongo.ErrNoDocuments { - return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetUser", zap.Error(err)) - return nil, err - } - } - - d.logger.Info("InfoGetUser", zap.String("id", result.ID)) - - return &result, nil -} - -//func (d *User) GetByFilter(ctx context.Context, ) ([]model.User, error) { -// -//} - -func (d *User) Update(ctx context.Context, record *model.User) error { - if record.ID == "" { - err := errors.New("got empty user id") - d.logger.Error("ErrorUpdateUser", zap.Error(err)) - return err - } - - objID, err := primitive.ObjectIDFromHex(record.ID) - - if err != nil { - d.logger.Error("ErrorUpdateUser", zap.Error(err)) - return err - } - - filter := bson.M{"_id": objID, "is_deleted": false} - - update := bson.M{"updated_at": time.Now()} - - if record.FullName != "" { - update["username"] = record.FullName - } - - if record.Email != "" { - update["email"] = record.Email - } - - if record.RoleID > 0 { - update["role_id"] = record.RoleID - } - - _, err = d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) - - if err != nil { - d.logger.Error("ErrorUpdateUser", zap.Error(err)) - return err - } - - return nil -} - -func (d *User) UpdateIsActivated(ctx context.Context, id string, isActivated bool) error { - if id == "" { - err := errors.New("got empty user id") - d.logger.Error("ErrorUpdateUser", zap.Error(err)) - return err - } - - objID, err := primitive.ObjectIDFromHex(id) - - if err != nil { - d.logger.Error("ErrorUpdateUser", zap.Error(err)) - return err - } - - filter := bson.M{"_id": objID, "is_deleted": false} - - update := bson.M{"updated_at": time.Now(), "is_activated": isActivated} - - _, err = d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) - if err != nil { - d.logger.Error("ErrorUpdateUser", zap.Error(err)) - return err - } - - return nil -} - -func (d *User) Delete(ctx context.Context, id string) error { - if id == "" { - err := errors.New("got empty user id") - d.logger.Error("ErrorDeleteUser", zap.Error(err)) - return err - } - - objID, err := primitive.ObjectIDFromHex(id) - - if err != nil { - d.logger.Error("ErrorDeleteUser", zap.Error(err)) - return err - } - - filter := bson.M{"_id": objID, "is_deleted": false} - - update := bson.M{"updated_at": time.Now(), "is_deleted": true} - - _, err = d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) - if err != nil { - d.logger.Error("ErrorDeleteUser", zap.Error(err)) - return err - } - - return nil -} diff --git a/dal/mongos/workerTask.go b/dal/mongos/workerTask.go index 65907dc..70d614f 100644 --- a/dal/mongos/workerTask.go +++ b/dal/mongos/workerTask.go @@ -3,13 +3,14 @@ package mongos import ( "context" "errors" + "time" + "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" - "time" ) type WorkerTask struct { @@ -27,7 +28,7 @@ func (d *WorkerTask) Insert(ctx context.Context, record *model.WorkerTask) (stri } record.CreatedAt = time.Now() - record.UpdatedAt = time.Now() + record.UpdatedAt = record.CreatedAt result, err := d.coll.InsertOne(ctx, record) @@ -59,11 +60,9 @@ func (d *WorkerTask) GetByID(ctx context.Context, id string) (*model.WorkerTask, if err == mongo.ErrNoDocuments { return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetWorkerTask", zap.Error(err)) - return nil, err - } + } else if err != nil { + d.logger.Error("ErrorGetWorkerTask", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetWorkerTask", zap.String("id", result.ID)) @@ -71,12 +70,12 @@ func (d *WorkerTask) GetByID(ctx context.Context, id string) (*model.WorkerTask, } type WorkerStatusFilter struct { - UserID string `json:"user_id" bson:"user_id,omitempty"` // Пользователь пены + PenaID string `json:"pena_id" bson:"pena_id,omitempty"` // Пользователь пены AmoID string `json:"amo_id" bson:"amo_id,omitempty"` // Амо аккаунт вызвавший генерацию AmoUserID int64 `json:"amo_user_id" bson:"amo_user_id,omitempty"` // Пользователь амо вызвавший генерацию Status model.WorkerTaskStatus `json:"status" bson:"status,omitempty"` // Статус генерации Data map[string]any `json:"data" bson:"data,omitempty"` // Данные по которым происходит генерация - LeadId int64 `json:"lead_id" bson:"lead_id,omitempty"` // Сделка по которой происходит генерация + LeadID int64 `json:"lead_id" bson:"lead_id,omitempty"` // Сделка по которой происходит генерация TemplateID string `json:"template_id" bson:"template_id,omitempty"` // Шаблон для генерации Source *model.WorkerSource `json:"source" bson:"source,omitempty"` // Исходный файл-шаблон Target *model.WorkerTarget `json:"target" bson:"target,omitempty"` @@ -91,11 +90,9 @@ func (d *WorkerTask) GetByFilter(ctx context.Context, filter *WorkerStatusFilter cur, err := d.coll.Find(ctx, filter, opts) if err == mongo.ErrNoDocuments { return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetWorkerTask", zap.Error(err)) - return nil, err - } + } else if err != nil { + d.logger.Error("ErrorGetWorkerTask", zap.Error(err)) + return nil, err } var result []model.WorkerTask @@ -123,9 +120,9 @@ func (d *WorkerTask) UpdateStatus(ctx context.Context, id string, status model.W return err } - update := bson.M{"status": status} + update := bson.M{"status": status, "updated_at": time.Now()} - _, err = d.coll.UpdateByID(ctx, objID, bson.D{{"$set", update}}) + _, err = d.coll.UpdateByID(ctx, objID, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorUpdateWorkerTaskStatus", zap.Error(err)) @@ -155,8 +152,8 @@ func (d *WorkerTask) UpdateByID(ctx context.Context, record *model.WorkerTask) e update := bson.M{"updated_at": time.Now()} - if record.UserID != "" { - update["user_id"] = record.UserID + if record.PenaID != "" { + update["pena_id"] = record.PenaID } if record.AmoID != "" { @@ -176,8 +173,9 @@ func (d *WorkerTask) UpdateByID(ctx context.Context, record *model.WorkerTask) e update["status"] = record.Status } - if record.LeadId > 0 { - update["lead_id"] = record.LeadId + // TODO: Изменить логику работы, когда Михаил примет решение по этому моменту. + if record.LeadID > 0 { + update["lead_id"] = record.LeadID } if record.TemplateID != "" { @@ -208,15 +206,15 @@ func (d *WorkerTask) UpdateByID(ctx context.Context, record *model.WorkerTask) e update["target.storage_type"] = record.Target.StorageType } - if record.DownloadUrl != "" { - update["download_url"] = record.DownloadUrl + if record.DownloadURL != "" { + update["download_url"] = record.DownloadURL } - if record.PublicUrl != "" { - update["public_url"] = record.PublicUrl + if record.PublicURL != "" { + update["public_url"] = record.PublicURL } - _, err = d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) + _, err = d.coll.UpdateOne(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorUpdateWorkerTask", zap.Error(err)) @@ -248,14 +246,20 @@ func (d *WorkerTask) Delete(ctx context.Context, id string) error { return nil } -// Listen - смотрит за добавлением и обновлением задач с выбранным статусом и возвращает их в выбранный канал +// Listen - смотрит за добавлением и обновлением задач с выбранным статусом и возвращает их в выбранный канал. func (d *WorkerTask) Listen(ctx context.Context, status model.WorkerTaskStatus, workerTaskChan chan model.WorkerTask) { - operationTypes := []bson.D{{{"operationType", "insert"}}, - {{"operationType", "update"}}} + operationTypes := []bson.D{ + {{Key: "operationType", Value: "insert"}}, + {{Key: "operationType", Value: "update"}}, + } - matchStageOpTypes := bson.D{{"$match", bson.D{{"$or", operationTypes}}}} + matchStageOpTypes := bson.D{ + {Key: "$match", Value: bson.D{{Key: "$or", Value: operationTypes}}}, + } - matchStageStatus := bson.D{{"$match", bson.D{{"fullDocument.status", status}}}} + matchStageStatus := bson.D{ + {Key: "$match", Value: bson.D{{Key: "fullDocument.status", Value: status}}}, + } opts := options.ChangeStream().SetFullDocument(options.UpdateLookup) @@ -299,7 +303,6 @@ func (d *WorkerTask) Listen(ctx context.Context, status model.WorkerTaskStatus, d.logger.Error("ErrorWatchWorkerTask", zap.Error(err)) return } - } workerTaskChan <- task } @@ -308,12 +311,10 @@ func (d *WorkerTask) Listen(ctx context.Context, status model.WorkerTaskStatus, } }() - select { - case <-ctx.Done(): - err = changeStream.Close(context.TODO()) - if err != nil { - d.logger.Error("ErrorWatchWorkerTask", zap.Error(err)) - } - return + <-ctx.Done() + + err = changeStream.Close(context.Background()) // TODO: проверить сокращенную запись в ssa + if err != nil { + d.logger.Error("ErrorWatchWorkerTask", zap.Error(err)) } } diff --git a/dal/mongos/yadisk.go b/dal/mongos/yadisk.go index ee5a61b..224d42f 100644 --- a/dal/mongos/yadisk.go +++ b/dal/mongos/yadisk.go @@ -3,13 +3,14 @@ package mongos import ( "context" "errors" + "time" + "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.uber.org/zap" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" YaDisk2 "penahub.gitlab.yandexcloud.net/backend/templategen/yadisk" - "time" ) type YaDisk struct { @@ -44,13 +45,15 @@ func (d *YaDisk) InsertOrUpdate(ctx context.Context, record *model.YaDisk) (stri if found == nil { // Set default TemplateFolder && SaveFolder if record.TemplateFolder == "" { - record.TemplateFolder = YaDisk2.DEFAULT_TEMPLATE_FOLDER + record.TemplateFolder = YaDisk2.DefaultTemplateFolder } if record.SaveFolder == "" { - record.SaveFolder = YaDisk2.DEFAULT_SAVE_FOLDER + record.SaveFolder = YaDisk2.DefaultSaveFolder } - result, err := d.coll.InsertOne(ctx, record) + var result *mongo.InsertOneResult + result, err = d.coll.InsertOne(ctx, record) + if err != nil { d.logger.Error("ErrorInsertOrUpdateYaDisk", zap.Error(err)) return "", err @@ -92,11 +95,9 @@ func (d *YaDisk) GetByID(ctx context.Context, id string) (*model.YaDisk, error) if err == mongo.ErrNoDocuments { return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetYaDisk", zap.Error(err)) - return nil, err - } + } else if err != nil { + d.logger.Error("ErrorGetYaDisk", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetYaDisk", zap.String("id", result.ID)) @@ -112,19 +113,17 @@ func (d *YaDisk) GetByLogin(ctx context.Context, login string) (*model.YaDisk, e if err == mongo.ErrNoDocuments { return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetYaDisk", zap.Error(err)) - return nil, err - } + } else if err != nil { + d.logger.Error("ErrorGetYaDisk", zap.Error(err)) + return nil, err } d.logger.Info("InfoGetYaDisk", zap.String("id", result.ID)) return &result, nil } -func (d *YaDisk) GetListByUserID(ctx context.Context, userID string) ([]model.YaDisk, error) { - filter := bson.M{"user_id": userID, "is_deleted": false} +func (d *YaDisk) GetListByPenaID(ctx context.Context, penaID string) ([]model.YaDisk, error) { + filter := bson.M{"pena_id": penaID, "is_deleted": false} result := []model.YaDisk{} @@ -132,11 +131,9 @@ func (d *YaDisk) GetListByUserID(ctx context.Context, userID string) ([]model.Ya if err == mongo.ErrNoDocuments { return nil, nil - } else { - if err != nil { - d.logger.Error("ErrorGetListYaDisk", zap.Error(err)) - return nil, err - } + } else if err != nil { + d.logger.Error("ErrorGetListYaDisk", zap.Error(err)) + return nil, err } err = cur.All(ctx, &result) @@ -148,7 +145,7 @@ func (d *YaDisk) GetListByUserID(ctx context.Context, userID string) ([]model.Ya return result, nil } -// Update - обновляет запись по её id или логину Yandex +// Update - обновляет запись по её id или логину Yandex. func (d *YaDisk) Update(ctx context.Context, record *model.YaDisk) error { filter := bson.M{"is_deleted": false} @@ -206,7 +203,7 @@ func (d *YaDisk) Update(ctx context.Context, record *model.YaDisk) error { update["save_folder"] = record.SaveFolder } - _, err := d.coll.UpdateOne(ctx, filter, bson.D{{"$set", update}}) + _, err := d.coll.UpdateOne(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorUpdateYaDisk", zap.Error(err)) @@ -216,18 +213,12 @@ func (d *YaDisk) Update(ctx context.Context, record *model.YaDisk) error { return nil } -func (d *YaDisk) DeleteByUserID(ctx context.Context, userID string) error { - if userID == "" { - err := errors.New("got empty user id") - d.logger.Error("ErrorDeleteYaDisk", zap.Error(err)) - return err - } - - filter := bson.M{"user_id": userID, "is_deleted": false} +func (d *YaDisk) DeleteByPenaID(ctx context.Context, penaID string) error { + filter := bson.M{"pena_id": penaID, "is_deleted": false} update := bson.M{"updated_at": time.Now(), "is_deleted": true} - _, err := d.coll.UpdateMany(ctx, filter, bson.D{{"$set", update}}) + _, err := d.coll.UpdateMany(ctx, filter, bson.D{{Key: "$set", Value: update}}) if err != nil { d.logger.Error("ErrorDeleteYaDisk", zap.Error(err)) return err diff --git a/dal/postgres/errors.go b/dal/postgres/errors.go deleted file mode 100644 index 7534b00..0000000 --- a/dal/postgres/errors.go +++ /dev/null @@ -1,9 +0,0 @@ -package postgres - -import ( - "errors" -) - -var ErrorGotEmptyRow = errors.New("got empty row") -var ErrorNotFound = errors.New("no rows in result set") -var ErrorTimeout = errors.New("timeout") diff --git a/dal/postgres/user.go b/dal/postgres/user.go deleted file mode 100644 index ba01e1d..0000000 --- a/dal/postgres/user.go +++ /dev/null @@ -1,276 +0,0 @@ -package postgres - -import ( - "context" - "errors" - "fmt" - rs "github.com/danilsolovyov/reflectgostructv1" - "github.com/jackc/pgx/v4/pgxpool" - "golang.org/x/crypto/bcrypt" - "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" - "strconv" - "strings" - "time" -) - -type User struct { - conn *pgxpool.Pool -} - -func InitUser(ctx context.Context, conn *pgxpool.Pool) *User { - d := &User{conn: conn} - err := d.init(ctx) - if err != nil { - //glg.Error("ErrInitUser:", err) - return nil - } - - return d -} - -func (d *User) init(ctx context.Context) error { - s := rs.PsqlTagToSql(&model.User{}) - sql := fmt.Sprintf("CREATE TABLE IF NOT EXISTS \"user\" (%v);", s) - _, err := d.conn.Exec(ctx, sql) - return err -} - -func (d *User) Insert(ctx context.Context, record *model.User) (string, error) { - now := time.Now().UTC() - record.CreatedAt = now - record.UpdatedAt = now - record.IsDeleted = false - - conn, err := d.conn.Acquire(ctx) - - if err != nil { - conn.Release() - return "", err - } - - // Find users by email - sql := fmt.Sprintf("SELECT id FROM \"user\" WHERE email = '%v'", record.Email) - - var foundID int - err = conn.QueryRow(ctx, sql).Scan(&foundID) - if err != nil { - if err.Error() != ErrorNotFound.Error() { - return "", err - } - } - - if foundID > 0 { - fmt.Println("user already exists", foundID) - err = errors.New("user already exists") - return "", err - } - - gpass, err := bcrypt.GenerateFromPassword([]byte(record.Password), bcrypt.DefaultCost) - if err != nil { - return "", err - } - - record.Password = string(gpass) - - tags, values := rs.GetPsqlTagsAndValues(record) - sql = fmt.Sprintf("INSERT INTO \"user\" (%v) VALUES (%v) RETURNING id;", tags, values) - - var id int - err = conn.QueryRow(ctx, sql).Scan(&id) - conn.Release() - - if err != nil { - return "", err - } - - return strconv.Itoa(id), nil -} - -func (d *User) GetByID(ctx context.Context, id int) (*model.User, error) { - var result model.User - - conn, err := d.conn.Acquire(ctx) - if err != nil { - conn.Release() - return nil, err - } - - sql := fmt.Sprintf("SELECT * FROM \"user\" WHERE id = %v", id) - rows, err := conn.Query(ctx, sql) - conn.Release() - if err != nil { - return nil, err - } - - for rows.Next() { - err = rows.Scan(&result.ID, &result.FullName, &result.Email, &result.Password, - &result.IsActivated, &result.JwtToken, &result.IsDeleted, &result.CreatedAt, &result.UpdatedAt) - if err != nil { - return nil, err - } - } - - return &result, err -} - -func (d *User) GetByEmail(ctx context.Context, email string) (*model.User, error) { - var result model.User - - conn, err := d.conn.Acquire(ctx) - if err != nil { - conn.Release() - return nil, err - } - - sql := fmt.Sprintf("SELECT * FROM \"user\" WHERE email = '%v'", email) - rows, err := conn.Query(ctx, sql) - conn.Release() - if err != nil { - return nil, err - } - - id := 0 - - for rows.Next() { - err = rows.Scan(&id, &result.FullName, &result.Email, &result.Password, - &result.IsActivated, &result.RoleID, &result.JwtToken, &result.IsDeleted, &result.CreatedAt, - &result.UpdatedAt) - if err != nil { - return nil, err - } - } - - result.ID = strconv.Itoa(id) - - return &result, err -} - -func (d *User) GetByFilter(ctx context.Context, start, count int, needle map[string]string) ([]model.User, error) { - var result []model.User - - conn, err := d.conn.Acquire(ctx) - if err != nil { - conn.Release() - return nil, err - } - - needleToSql := "" - if len(needle) > 0 { - needleToSql += " AND " - i := 0 - for k, v := range needle { - v = strings.ReplaceAll(v, "'", "''") - needleToSql += fmt.Sprintf("%v = %v", k, v) - if i < len(needle) { - needleToSql += " AND " - } - i++ - } - } - - sql := fmt.Sprintf("SELECT * FROM \"user\" WHERE (id >= %v %v) ORDER BY id LIMIT %v;", - start, - needleToSql, - count, - ) - rows, err := conn.Query(ctx, sql) - conn.Release() - - if err != nil { - return nil, err - } - - if rows == nil { - err = ErrorGotEmptyRow - return nil, err - } - - for rows.Next() { - var u model.User - err = rows.Scan(&u.ID, &u.FullName, &u.Email, &u.Password, - &u.IsActivated, &u.RoleID, &u.JwtToken, &u.IsDeleted, &u.CreatedAt, &u.UpdatedAt) - if err != nil { - return nil, err - } - result = append(result, u) - } - - return result, nil -} - -func (d *User) UpdateByID(ctx context.Context, record *model.User) error { - record.UpdatedAt = time.Now() - - conn, err := d.conn.Acquire(ctx) - if err != nil { - conn.Release() - return err - } - - tags, values := rs.GetPsqlTagsAndValues(record) - sql := fmt.Sprintf("UPDATE \"user\" SET (%v) = (%v) WHERE id = %v;", tags, values, record.ID) - err = conn.QueryRow(ctx, sql).Scan() - conn.Release() - - if err != nil { - return err - } - - return nil -} - -func (d *User) DeleteByID(ctx context.Context, id int) error { - conn, err := d.conn.Acquire(ctx) - if err != nil { - conn.Release() - return err - } - - sql := fmt.Sprintf("UPDATE \"user\" SET is_deleted = true WHERE id = %v", id) - err = conn.QueryRow(ctx, sql).Scan() - conn.Release() - if err != nil { - return err - } - - return nil -} - -func (d *User) SetJwtToken(ctx context.Context, id int, jwtToken string) error { - conn, err := d.conn.Acquire(ctx) - if err != nil { - conn.Release() - return err - } - - sql := fmt.Sprintf("UPDATE \"user\" SET jwt_token = '%v' WHERE id = %v", jwtToken, id) - err = conn.QueryRow(ctx, sql).Scan() - conn.Release() - if err != nil { - return err - } - - return nil -} - -func (d *User) ChangePassword(ctx context.Context, id int, password string) error { - gpass, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) - if err != nil { - return err - } - - conn, err := d.conn.Acquire(ctx) - if err != nil { - conn.Release() - return err - } - - sql := fmt.Sprintf("UPDATE \"user\" SET password = '%v' WHERE id = %v", gpass, id) - err = conn.QueryRow(ctx, sql).Scan() - conn.Release() - if err != nil { - return err - } - - return nil -} diff --git a/dal/postgres/yadisk.go b/dal/postgres/yadisk.go deleted file mode 100644 index d132887..0000000 --- a/dal/postgres/yadisk.go +++ /dev/null @@ -1,242 +0,0 @@ -package postgres - -import ( - "context" - "errors" - "fmt" - rs "github.com/danilsolovyov/reflectgostructv1" - "github.com/jackc/pgx/v4/pgxpool" - "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" - "strconv" - "strings" - "time" -) - -type YaDisk struct { - conn *pgxpool.Pool -} - -func InitYaDisk(ctx context.Context, conn *pgxpool.Pool) *YaDisk { - d := &YaDisk{conn: conn} - err := d.init(ctx) - if err != nil { - //glg.Error("ErrInitYaDisk", err) - return nil - } - - return d -} - -func (d *YaDisk) init(ctx context.Context) error { - s := rs.PsqlTagToSql(&model.YaDisk{}) - sql := fmt.Sprintf("CREATE TABLE IF NOT EXISTS \"YaDisk\" (%v);", s) - _, err := d.conn.Exec(ctx, sql) - return err -} - -func (d *YaDisk) Insert(ctx context.Context, record *model.YaDisk) (int, error) { - now := time.Now().UTC() - record.CreatedAt = now - record.UpdatedAt = now - record.IsDeleted = false - - conn, err := d.conn.Acquire(ctx) - - if err != nil { - conn.Release() - return 0, err - } - - //Find YaDisk by user_id - sql := fmt.Sprintf("SELECT id FROM \"YaDisk\" WHERE user_id = '%v'", record.UserID) - - var foundID int - err = conn.QueryRow(ctx, sql).Scan(&foundID) - if err != nil { - if err.Error() != ErrorNotFound.Error() { - return 0, err - } - } - - if foundID > 0 { - fmt.Println("YaDisk already exists", foundID) - err = errors.New("YaDisk already exists") - return 0, err - } - - tags, values := rs.GetPsqlTagsAndValues(record) - sql = fmt.Sprintf("INSERT INTO \"YaDisk\" (%v) VALUES (%v) RETURNING id;", tags, values) - - var id int - err = conn.QueryRow(ctx, sql).Scan(&id) - conn.Release() - - if err != nil { - return 0, err - } - - return id, nil -} - -func (d *YaDisk) InsertOrUpdate(ctx context.Context, record *model.YaDisk) (string, error) { - now := time.Now().UTC() - record.CreatedAt = now - record.UpdatedAt = now - record.IsDeleted = false - - conn, err := d.conn.Acquire(ctx) - - if err != nil { - conn.Release() - return "", err - } - - //Find YaDisk by user_id - sql := fmt.Sprintf("SELECT id FROM \"YaDisk\" WHERE user_id = '%v'", record.UserID) - - var foundID int - err = conn.QueryRow(ctx, sql).Scan(&foundID) - if err != nil { - fmt.Println("errr", err) - if err.Error() != ErrorNotFound.Error() { - return "", err - } - } - - tags, values := rs.GetPsqlTagsAndValues(record) - var id int - - if foundID > 0 { - sql = fmt.Sprintf("UPDATE \"YaDisk\" SET (%v) = (%v) WHERE id = %v;", tags, values, record.ID) - id = foundID - } else { - sql = fmt.Sprintf("INSERT INTO \"YaDisk\" (%v) VALUES (%v) RETURNING id;", tags, values) - } - - err = conn.QueryRow(ctx, sql).Scan(&id) - conn.Release() - - if err != nil { - return "", err - } - - return strconv.Itoa(id), nil -} - -func (d *YaDisk) GetByID(ctx context.Context, id string) (*model.YaDisk, error) { - var result model.YaDisk - - conn, err := d.conn.Acquire(ctx) - if err != nil { - conn.Release() - return nil, err - } - - sql := fmt.Sprintf("SELECT * FROM \"YaDisk\" WHERE id = %v", id) - rows, err := conn.Query(ctx, sql) - conn.Release() - if err != nil { - return nil, err - } - - for rows.Next() { - err = rows.Scan(&result.ID, &result.UserID, &result.AccessToken, &result.TemplateFolder, - &result.SaveFolder, &result.ExpiresIn, &result.IsDeleted, &result.CreatedAt, &result.UpdatedAt) - if err != nil { - return nil, err - } - } - - return &result, err -} - -func (d *YaDisk) GetByFilter(ctx context.Context, start, count int, needle map[string]string) ([]model.YaDisk, error) { - var result []model.YaDisk - - conn, err := d.conn.Acquire(ctx) - if err != nil { - conn.Release() - return nil, err - } - - needleToSql := "" - if len(needle) > 0 { - needleToSql += " AND " - i := 0 - for k, v := range needle { - v = strings.ReplaceAll(v, "'", "''") - needleToSql += fmt.Sprintf("%v = %v", k, v) - if i < len(needle) { - needleToSql += " AND " - } - i++ - } - } - - sql := fmt.Sprintf("SELECT * FROM \"YaDisk\" WHERE (id >= %v %v) ORDER BY id LIMIT %v;", - start, - needleToSql, - count, - ) - rows, err := conn.Query(ctx, sql) - conn.Release() - - if err != nil { - return nil, err - } - - if rows == nil { - err = ErrorGotEmptyRow - return nil, err - } - - for rows.Next() { - var u model.YaDisk - err = rows.Scan(&u.ID, &u.UserID, &u.AccessToken, &u.TemplateFolder, - &u.SaveFolder, &u.ExpiresIn, &u.IsDeleted, &u.CreatedAt, &u.UpdatedAt) - if err != nil { - return nil, err - } - result = append(result, u) - } - - return result, nil -} - -func (d *YaDisk) UpdateByID(ctx context.Context, record *model.YaDisk) error { - record.UpdatedAt = time.Now().UTC() - - conn, err := d.conn.Acquire(ctx) - if err != nil { - conn.Release() - return err - } - - tags, values := rs.GetPsqlTagsAndValues(record) - sql := fmt.Sprintf("UPDATE \"YaDisk\" SET (%v) = (%v) WHERE id = %v;", tags, values, record.ID) - err = conn.QueryRow(ctx, sql).Scan() - conn.Release() - - if err != nil { - return err - } - - return nil -} - -func (d *YaDisk) DeleteByID(ctx context.Context, id string) error { - conn, err := d.conn.Acquire(ctx) - if err != nil { - conn.Release() - return err - } - - sql := fmt.Sprintf("UPDATE \"YaDisk\" SET is_deleted = true WHERE id = %v", id) - err = conn.QueryRow(ctx, sql).Scan() - conn.Release() - if err != nil { - return err - } - - return nil -} diff --git a/gdisk/api.go b/gdisk/api.go index 2bfefd1..f592d92 100644 --- a/gdisk/api.go +++ b/gdisk/api.go @@ -1,19 +1,21 @@ -package GDisk +package gdisk import ( "bytes" "context" - "errors" "fmt" + "io" + "log" + "net/http" + "os" + "strings" + + "github.com/pkg/errors" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/api/drive/v3" "google.golang.org/api/option" - "io" - "net/http" - "os" "penahub.gitlab.yandexcloud.net/backend/templategen/tools" - "strings" ) const ( @@ -37,7 +39,7 @@ type ClientApp struct { func NewClientApp(credentials string) (*ClientApp, error) { b, err := os.ReadFile(credentials) if err != nil { - return nil, err + return nil, errors.Wrap(err, "NewClientApp.ReadFile") } config, err := google.ConfigFromJSON(b, @@ -45,21 +47,21 @@ func NewClientApp(credentials string) (*ClientApp, error) { drive.DriveMetadataScope, ) if err != nil { - return nil, err + return nil, errors.Wrap(err, "NewClientApp.ConfigFromJSON") } return &ClientApp{Config: config}, nil } -func (ca *ClientApp) GenerateOAuthUrl(userId, redirectUrl string) (string, error) { - state, err := tools.EncryptTokenRC4(tools.StateToken{ - UserID: userId, +func (ca *ClientApp) GenerateOAuthURL(penaID, redirectURL string) (string, error) { + state, err := tools.EncryptTokenAES(tools.StateToken{ + PenaID: penaID, Service: "google", - RedirectUrl: redirectUrl, + RedirectURL: redirectURL, }) if err != nil { - return "", err + return "", errors.Wrap(err, "GenerateOAuthURL.Encrypt") } return ca.Config.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.ApprovalForce), nil @@ -68,7 +70,7 @@ func (ca *ClientApp) GenerateOAuthUrl(userId, redirectUrl string) (string, error func (ca *ClientApp) RefreshToken(ctx context.Context, oldToken *oauth2.Token) (*oauth2.Token, error) { token, err := ca.Config.TokenSource(ctx, oldToken).Token() if err != nil { - return nil, err + return nil, errors.Wrap(err, "RefreshToken") } return token, nil @@ -76,15 +78,15 @@ func (ca *ClientApp) RefreshToken(ctx context.Context, oldToken *oauth2.Token) ( func (ca *ClientApp) NewClient(ctx context.Context, token *oauth2.Token) (*Client, error) { client := ca.Config.Client(ctx, token) - srv, err := drive.NewService(ctx, option.WithHTTPClient(client)) + service, err := drive.NewService(ctx, option.WithHTTPClient(client)) if err != nil { - return nil, err + return nil, errors.Wrap(err, "NewClient.NewService") } return &Client{ App: ca, HTTPClient: client, - Service: srv, + Service: service, Token: token, }, nil } @@ -97,24 +99,24 @@ func (c *Client) SetToken(token oauth2.Token) { c.Token = &token } -func (c *Client) GetDisk() { - srv, err := drive.NewService(context.Background(), option.WithHTTPClient(c.HTTPClient)) +func (c *Client) GetDisk(ctx context.Context) { + service, err := drive.NewService(ctx, option.WithHTTPClient(c.HTTPClient)) if err != nil { - fmt.Println("err123", err) + log.Println(errors.Wrap(err, "GetDisk.NewService")) return } - about, err := srv.About.Get().Fields("storageQuota", "user", "exportFormats", "maxImportSizes", "maxUploadSize").Do() + about, err := service.About.Get().Fields("storageQuota", "user", "exportFormats", "maxImportSizes", "maxUploadSize").Do() if err != nil { - fmt.Println("err1234", err) + log.Println(errors.Wrap(err, "GetDisk.ServiceAboutGet")) return } fmt.Printf("srv.About %+v \r\n", about.User) - dl, err := srv.Drives.List().Do() + dl, err := service.Drives.List().Do() if err != nil { - fmt.Println("err12345", err) + log.Println(errors.Wrap(err, "GetDisk.ServiceDriveListDo")) return } @@ -124,32 +126,32 @@ func (c *Client) GetDisk() { } } -// GetUserInfo - получить информацию о пользователе Google -func (c *Client) GetUserInfo() (*drive.User, error) { - srv, err := drive.NewService(context.Background(), option.WithHTTPClient(c.HTTPClient)) +// GetUserInfo - получить информацию о пользователе Google. +func (c *Client) GetUserInfo(ctx context.Context) (*drive.User, error) { + service, err := drive.NewService(ctx, option.WithHTTPClient(c.HTTPClient)) if err != nil { - return nil, err + return nil, errors.Wrap(err, "GetUserInfo.NewService") } - about, err := srv.About.Get().Fields("user").Do() + about, err := service.About.Get().Fields("user").Do() if err != nil { - return nil, err + return nil, errors.Wrap(err, "GetUserInfo.ServiceDo") } if about == nil { - return nil, errors.New("got empty about") + return nil, errors.Wrap(errors.New("got empty about"), "GetUserInfo") } if about.User == nil { - return nil, errors.New("got empty about.User") + return nil, errors.Wrap(errors.New("got empty about.User"), "GetUserInfo") } return about.User, nil } -// GetResourcesByName - получить информацию о ресурсе +// GetResourcesByName - получить информацию о ресурсе. func (c *Client) GetResourcesByName(name, parentID string) (*drive.FileList, error) { query := "name = '" + name + "' and trashed = false" @@ -164,14 +166,14 @@ func (c *Client) GetResourcesByName(name, parentID string) (*drive.FileList, err if strings.Contains(err.Error(), "404") { return nil, nil } - return nil, err + return nil, errors.Wrap(err, "GetResourcesByName.ServiceFileListDo") } return fl, nil } // GetResources - получить список файлов и папок ресурса по его id -// Если id не указан, то принимается значение 'root' +// Если id не указан, то принимается значение 'root'. func (c *Client) GetResources(id string) (*drive.FileList, error) { if id == "" { id = "root" @@ -185,78 +187,81 @@ func (c *Client) GetResources(id string) (*drive.FileList, error) { if strings.Contains(err.Error(), "404") { return nil, nil } - return nil, err + return nil, errors.Wrap(err, "GetResources.ServiceFileListDo") } return fl, nil } -// PutResources - создание папки +// PutResources - создание папки. func (c *Client) PutResources(name, parentID string) (*drive.File, error) { - q := &drive.File{Name: name, MimeType: "application/vnd.google-apps.folder", IsAppAuthorized: true} + queryFile := &drive.File{Name: name, MimeType: "application/vnd.google-apps.folder", IsAppAuthorized: true} if parentID != "" { - q.Parents = []string{parentID} + queryFile.Parents = []string{parentID} } - f, err := c.Service.Files.Create(q).Do() + f, err := c.Service.Files.Create(queryFile).Do() if err != nil { - fmt.Println("3", err.Error()) - fmt.Println("") - return nil, err + return nil, errors.Wrap(err, "PutResources.ServiceFileListDo") } return f, nil } func (c *Client) DeleteResources(id string) error { - return c.Service.Files.Delete(id).Do() + err := c.Service.Files.Delete(id).Do() + return errors.Wrap(err, "DeleteResources") } -// UploadFile - отправить файл в диск +// UploadFile - отправить файл в диск. func (c *Client) UploadFile(filepath, mimetype, parentID string) (string, string, error) { file, err := os.Open(filepath) - defer file.Close() + defer func() { + if err = file.Close(); err != nil { + log.Println("ERROR", errors.Wrap(err, "UploadFile.FileClose")) + } + }() if err != nil { - return "", "", err + return "", "", errors.Wrap(err, "UploadFile.OsOpen") } filename := strings.Split(file.Name(), "/") - q := &drive.File{ + queryFile := &drive.File{ Name: filename[len(filename)-1], MimeType: mimetype, IsAppAuthorized: true, } if parentID != "" { - q.Parents = []string{parentID} + queryFile.Parents = []string{parentID} } - fileData, err := c.Service.Files.Create(q).Media(file).Do() + fileData, err := c.Service.Files.Create(queryFile).Media(file).Do() if err != nil { - return "", "", err + return "", "", errors.Wrap(err, "UploadFile.ServiceFilesCreate") } return fileData.Id, fileData.ExportLinks[mimetype], nil } func (c *Client) UploadFileBytes(file []byte, filename, mimetype, parentID string) (string, string, error) { - q := &drive.File{ + queryFile := &drive.File{ Name: filename, MimeType: mimetype, IsAppAuthorized: true, } if parentID != "" { - q.Parents = []string{parentID} + queryFile.Parents = []string{parentID} } - fileData, err := c.Service.Files.Create(q).Media(bytes.NewReader(file)).Do() + fileData, err := c.Service.Files.Create(queryFile).Media(bytes.NewReader(file)).Do() if err != nil { - return "", "", err + return "", "", errors.Wrap(err, "UploadFileBytes.ServiceFilesCreateDo") } return fileData.Id, fileData.ExportLinks[mimetype], nil @@ -265,7 +270,7 @@ func (c *Client) UploadFileBytes(file []byte, filename, mimetype, parentID strin func (c *Client) DownloadFile(filepath, fileID string) error { file, err := c.Service.Files.Get(fileID).Do() if err != nil { - return err + return errors.Wrap(err, "DownloadFile.ServiceFilesGetDo") } var resp *http.Response @@ -274,26 +279,37 @@ func (c *Client) DownloadFile(filepath, fileID string) error { resp, err = c.Service.Files.Export(fileID, MimeTypeDocx). Fields("exportFormat", "docx"). Download() + err = errors.Wrap(err, "DownloadFile.Export") } else { resp, err = c.Service.Files.Get(fileID).Download() + err = errors.Wrap(err, "DownloadFile.Download") } if err != nil { return err } - defer resp.Body.Close() + defer func() { + if err = resp.Body.Close(); err != nil { + log.Println("ERROR", errors.Wrap(err, "DownloadFile.BodyClose")) + } + }() out, err := os.Create(filepath) - defer out.Close() + + defer func() { + if err = out.Close(); err != nil { + log.Println("ERROR", errors.Wrap(err, "DownloadFile.OutFileClose")) + } + }() if err != nil { - return err + return errors.Wrap(err, "DownloadFile.OsCreate") } _, err = io.Copy(out, resp.Body) if err != nil { - return err + return errors.Wrap(err, "DownloadFile.IoCopy") } return nil @@ -302,31 +318,45 @@ func (c *Client) DownloadFile(filepath, fileID string) error { func (c *Client) DownloadFileBytes(fileID string) ([]byte, error) { file, err := c.Service.Files.Get(fileID).Do() if err != nil { - return nil, err + return nil, errors.Wrap(err, "DownloadFileBytes.ServiceFilesGetDo") } var resp *http.Response if file.MimeType == "application/vnd.google-apps.document" { - resp, err = c.Service.Files.Export(fileID, MimeTypeDocx). - Fields("exportFormat", "docx"). - Download() + resp, err = c.Service.Files.Export(fileID, MimeTypeDocx).Fields("exportFormat", "docx").Download() + err = errors.Wrap(err, "DownloadFileBytes.Export") + defer func() { + if err = resp.Body.Close(); err != nil { + log.Println("ERROR", errors.Wrap(err, "DownloadFileBytes.BodyClose")) + } + }() } else { resp, err = c.Service.Files.Get(fileID).Download() + err = errors.Wrap(err, "DownloadFileBytes.Download") + defer func() { + if err = resp.Body.Close(); err != nil { + log.Println("ERROR", errors.Wrap(err, "DownloadFileBytes.BodyClose")) + } + }() } if err != nil { return nil, err } - defer resp.Body.Close() + defer func() { + if err = resp.Body.Close(); err != nil { + log.Println("ERROR", errors.Wrap(err, "DownloadFile.BodyClose")) + } + }() return io.ReadAll(resp.Body) } // MakeDefaultDirs - проверяет диск на наличие папок DefaultDir, TemplateDir и SaveDir. -// Если папки не существуют, то создает их -func (c *Client) MakeDefaultDirs(defaultId, defaultName, templateId, templateName, saveId, +// Если папки не существуют, то создает их. +func (c *Client) MakeDefaultDirs(defaultID, defaultName, templateID, templateName, saveID, saveName string) (*drive.File, *drive.File, *drive.File, error) { var defaultDir, templateDir, saveDir *drive.File @@ -345,88 +375,91 @@ func (c *Client) MakeDefaultDirs(defaultId, defaultName, templateId, templateNam var err error // Check Default directory - if defaultId == "" { - fl, err := c.GetResourcesByName(defaultName, "") + if defaultID == "" { + var fl *drive.FileList + fl, err = c.GetResourcesByName(defaultName, "") if err != nil { - return nil, nil, nil, err + return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.DefaultDir.GetResourceByName") } if len(fl.Files) == 0 { defaultDir, err = c.PutResources(defaultName, "") if err != nil { - return nil, nil, nil, err + return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.DefaultDir.PutResource") } } else { defaultDir = fl.Files[0] } } else { - defaultDir, err = c.Service.Files.Get(defaultId).Do() + defaultDir, err = c.Service.Files.Get(defaultID).Do() if err != nil { if strings.Contains(err.Error(), "404") { defaultDir, err = c.PutResources(defaultName, "") if err != nil { - return nil, nil, nil, err + return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.DefaultDir.PutResource") } } else { - return nil, nil, nil, err + return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.DefaultDir.ServiceFilesGetDo") } } } // Check Template Directory - if templateId == "" { - fl, err := c.GetResourcesByName(templateName, defaultDir.Id) + if templateID == "" { + var fl *drive.FileList + fl, err = c.GetResourcesByName(templateName, defaultDir.Id) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.TemplateDir.GetResourcesByName") } if len(fl.Files) == 0 { templateDir, err = c.PutResources(templateName, defaultDir.Id) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.TemplateDir.PutResources") } } else { templateDir = fl.Files[0] } } else { - templateDir, err = c.Service.Files.Get(templateId).Do() + templateDir, err = c.Service.Files.Get(templateID).Do() if err != nil { if strings.Contains(err.Error(), "404") { templateDir, err = c.PutResources(templateName, defaultDir.Id) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.TemplateDir.PutResources") } } else { - return nil, nil, nil, err + return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.TemplateDir.ServiceFilesGetDo") } } } // Check Save Directory - if saveId == "" { - fl, err := c.GetResourcesByName(saveName, defaultDir.Id) + if saveID == "" { + var fl *drive.FileList + fl, err = c.GetResourcesByName(saveName, defaultDir.Id) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.SaveDir.GetResourcesByName") } if len(fl.Files) == 0 { saveDir, err = c.PutResources(saveName, defaultDir.Id) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.SaveDir.PutResources") } } else { saveDir = fl.Files[0] } } else { - saveDir, err = c.Service.Files.Get(templateId).Do() + saveDir, err = c.Service.Files.Get(templateID).Do() if err != nil { if strings.Contains(err.Error(), "404") { saveDir, err = c.PutResources(saveName, defaultDir.Id) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.SaveDir.PutResources") } } else { - return nil, nil, nil, err + return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.SaveDir.ServiceFilesGetDo") } } } diff --git a/gdisk/model.go b/gdisk/model.go index 587d9ed..48e073d 100644 --- a/gdisk/model.go +++ b/gdisk/model.go @@ -1 +1 @@ -package GDisk +package gdisk diff --git a/getenv.go b/getenv.go index 2ce92b0..4e43b0d 100644 --- a/getenv.go +++ b/getenv.go @@ -11,8 +11,7 @@ import ( func getEnv(mask interface{}) Env { r := reflect.ValueOf(mask) - var argTypeRV reflect.Value - argTypeRV = reflect.New(r.Type()) + argTypeRV := reflect.New(r.Type()) for i := 0; i < r.NumField(); i++ { v := r.Type().Field(i).Tag.Get("env") @@ -26,11 +25,15 @@ func getEnv(mask interface{}) Env { val = d } - switch t := r.Type().Field(i).Type.Name(); t { + switch t := r.Type().Field(i).Type.String(); t { case "string": argTypeRV.Elem().Field(i).SetString(val) + case "[]string": + divider := "," + arr := strings.Split(val, divider) + argTypeRV.Elem().Field(i).Set(reflect.ValueOf(arr)) case "bool": - if strings.ToLower(val) == "true" { + if strings.EqualFold(val, "true") { argTypeRV.Elem().Field(i).SetBool(true) } else { argTypeRV.Elem().Field(i).SetBool(false) @@ -42,7 +45,7 @@ func getEnv(mask interface{}) Env { } argTypeRV.Elem().Field(i).SetUint(num) default: - panic(errors.New("Something strange happend: " + t)) + panic(errors.New("Something strange happened: " + t)) } } diff --git a/go.mod b/go.mod index fb5a3f1..e65fb07 100644 --- a/go.mod +++ b/go.mod @@ -1,28 +1,28 @@ module penahub.gitlab.yandexcloud.net/backend/templategen -go 1.19 +go 1.20 require ( github.com/danilsolovyov/doc-template v0.0.0-20230327151707-b8182a1ee9f4 - github.com/danilsolovyov/reflectgostructv1 v0.0.11 github.com/dgrijalva/jwt-go v3.2.0+incompatible - github.com/gofiber/fiber/v2 v2.45.0 + github.com/gofiber/fiber/v2 v2.48.0 github.com/gorilla/mux v1.8.0 github.com/gorilla/schema v1.2.0 - github.com/jackc/pgx/v4 v4.18.1 - github.com/minio/minio-go/v7 v7.0.50 - github.com/stretchr/testify v1.8.1 + github.com/minio/minio-go/v7 v7.0.61 + github.com/pkg/errors v0.9.1 + github.com/stretchr/testify v1.8.4 github.com/themakers/bdd v0.0.0-20210316111417-6b1dfe326f33 - go.mongodb.org/mongo-driver v1.11.3 - go.uber.org/zap v1.24.0 - golang.org/x/crypto v0.7.0 - golang.org/x/oauth2 v0.6.0 - google.golang.org/api v0.114.0 - penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20230222172022-007eb6fd0b1f + github.com/twmb/franz-go v1.14.3 + go.mongodb.org/mongo-driver v1.12.1 + go.uber.org/zap v1.25.0 + golang.org/x/oauth2 v0.11.0 + google.golang.org/api v0.137.0 + google.golang.org/protobuf v1.31.0 + penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20230712221540-d9932eb7254e ) require ( - cloud.google.com/go/compute v1.19.0 // indirect + cloud.google.com/go/compute v1.23.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -30,56 +30,45 @@ require ( github.com/fatih/color v1.10.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/golang/snappy v0.0.4 // indirect + github.com/golang/snappy v0.0.1 // indirect + github.com/google/s2a-go v0.1.5 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.8.0 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.14.0 // indirect - github.com/jackc/pgio v1.0.0 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.2 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgtype v1.14.0 // indirect - github.com/jackc/puddle v1.3.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.3 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/minio/md5-simd v1.1.2 // indirect - github.com/minio/sha256-simd v1.0.0 // indirect + github.com/minio/sha256-simd v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/montanaflynn/stats v0.7.0 // indirect - github.com/philhofer/fwd v1.1.2 // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect + github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect - github.com/rs/xid v1.4.0 // indirect - github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect - github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect - github.com/sirupsen/logrus v1.9.0 // indirect - github.com/tinylib/msgp v1.1.8 // indirect + github.com/rs/xid v1.5.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/twmb/franz-go/pkg/kmsg v1.6.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.47.0 // indirect + github.com/valyala/fasthttp v1.48.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect - github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect go.opencensus.io v0.24.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/text v0.8.0 // indirect + go.uber.org/multierr v1.10.0 // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/net v0.14.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd // indirect - google.golang.org/grpc v1.54.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 // indirect + google.golang.org/grpc v1.57.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 40f2101..c821942 100644 --- a/go.sum +++ b/go.sum @@ -1,27 +1,25 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= -cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/danilsolovyov/doc-template v0.0.0-20230327151707-b8182a1ee9f4 h1:GwGyqqRbG1MQi+GgPX9yX8FGNwZJPIpyxivb4OjKgnc= github.com/danilsolovyov/doc-template v0.0.0-20230327151707-b8182a1ee9f4/go.mod h1:nR0IgQFyfxaKnzDMdxyNpNieoL4hW593trhr4q4j6dM= -github.com/danilsolovyov/reflectgostructv1 v0.0.11 h1:aAJo9mWTCt1sgL1bB3LkV2d/hQ07zU5Pj2zpiCaailI= -github.com/danilsolovyov/reflectgostructv1 v0.0.11/go.mod h1:CwTyBEg4Y22p1qZtHzEe07C5nsSVcc7vx3jdzphjmv4= 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= @@ -32,16 +30,14 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gofiber/fiber/v2 v2.45.0 h1:p4RpkJT9GAW6parBSbcNFH2ApnAuW3OzaQzbOCoDu+s= -github.com/gofiber/fiber/v2 v2.45.0/go.mod h1:DNl0/c37WLe0g92U6lx1VMQuxGUQY5V7EIaVoEsUffc= -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/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gofiber/fiber/v2 v2.48.0 h1:cRVMCb9aUJDsyHxGFLwz/sGzDggdailZZyptU9F9cU0= +github.com/gofiber/fiber/v2 v2.48.0/go.mod h1:xqJgfqrc23FJuqGOW6DVgi3HyZEm2Mn9pRqUb2kHSX8= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -50,19 +46,21 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -73,121 +71,52 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.5 h1:8IYp3w9nysqv3JH+NJgXJzGbDHzLOTj43BmSkp+O7qg= +github.com/google/s2a-go v0.1.5/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= -github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= +github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= -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.14.0 h1:vrbA9Ud87g6JdFWkHTJXppVce58qPIdP7N8y0Ml/A7Q= -github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= -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/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= -github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -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.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= -github.com/jackc/pgtype v1.14.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.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= -github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= -github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -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/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.50 h1:4IL4V8m/kI90ZL6GupCARZVrBv8/XrcKcJhaJ3iz68k= -github.com/minio/minio-go/v7 v7.0.50/go.mod h1:IbbodHyjUAguneyucUaahv+VMNs/EOTV9du7A7/Z3HU= -github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/minio/minio-go/v7 v7.0.61 h1:87c+x8J3jxQ5VUGimV9oHdpjsAvy3fhneEBKuoKEVUI= +github.com/minio/minio-go/v7 v7.0.61/go.mod h1:BTu8FcrEw+HidY0zd/0eny43QnVNkXRPXrLXFuQBHXg= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/montanaflynn/stats v0.7.0 h1:r3y12KyNxj/Sb/iOE46ws+3mS1+MZca1wlHQFPsY/JU= -github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= -github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= -github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= +github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -195,223 +124,155 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= -github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4= -github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8= -github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4= -github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= -github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -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/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/themakers/bdd v0.0.0-20210316111417-6b1dfe326f33 h1:N9f/Q+2Ssa+yDcbfaoLTYvXmdeyUUxsJKdPUVsjSmiA= github.com/themakers/bdd v0.0.0-20210316111417-6b1dfe326f33/go.mod h1:rpcH99JknBh8seZmlOlUg51gasZH6QH34oXNsIwYT6E= -github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= -github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= -github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= +github.com/twmb/franz-go v1.14.3 h1:cq8rxAnVYU1uF3SRVn8eEaUf+AaXKWlB0Cl3Ca7JSa4= +github.com/twmb/franz-go v1.14.3/go.mod h1:nMAvTC2kHtK+ceaSHeHm4dlxC78389M/1DjpOswEgu4= +github.com/twmb/franz-go/pkg/kmsg v1.6.1 h1:tm6hXPv5antMHLasTfKv9R+X03AjHSkSkXhQo2c5ALM= +github.com/twmb/franz-go/pkg/kmsg v1.6.1/go.mod h1:se9Mjdt0Nwzc9lnjJ0HyDtLyBnaBDAd7pCje47OhSyw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c= -github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= +github.com/valyala/fasthttp v1.48.0 h1:oJWvHb9BIZToTQS3MuQ2R3bJZiNSa2KiNdeI8A+79Tc= +github.com/valyala/fasthttp v1.48.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= -github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= -go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= +go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE= +go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -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/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -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/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -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= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= +go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= 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-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-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-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 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/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE= -google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +google.golang.org/api v0.137.0 h1:QrKX6uNvzJLr0Fd3vWVqcyrcmFoYi036VUAsZbiF4+s= +google.golang.org/api v0.137.0/go.mod h1:4xyob8CxC+0GChNBvEUAk8VBKNvYOTWM9T3v3UfRxuY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd h1:sLpv7bNL1AsX3fdnWh9WVh7ejIzXdOc1RRHGeAmeStU= -google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= +google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 h1:nIgk/EEq3/YlnmVVXVnm14rC2oxgs1o0ong4sD/rd44= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577 h1:wukfNtZmZUurLN/atp2hiIeTKn7QJWIQdHzqmsOnAOk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= -google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -423,21 +284,18 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 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.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20230222172022-007eb6fd0b1f h1:/ACy953BoX+0T8nizgukSZe/+seDvLne0zJC2lAa4EU= -penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20230222172022-007eb6fd0b1f/go.mod h1:SCqfOb+FHQayOQcxHQKd52Az4sur3hr3Lx1I4UiLf6g= +penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20230712221540-d9932eb7254e h1:nZLUtqm+u3Tf339bioyyaUsxV10RSqKeukVa52H/+DQ= +penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20230712221540-d9932eb7254e/go.mod h1:SCqfOb+FHQayOQcxHQKd52Az4sur3hr3Lx1I4UiLf6g= diff --git a/handlers/amo.go b/handlers/amo.go index efec4aa..8638a6a 100644 --- a/handlers/amo.go +++ b/handlers/amo.go @@ -12,9 +12,9 @@ import ( "go.uber.org/zap" "golang.org/x/oauth2" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" - + "penahub.gitlab.yandexcloud.net/backend/templategen/middleware" "penahub.gitlab.yandexcloud.net/backend/templategen/penadisk" - + "penahub.gitlab.yandexcloud.net/backend/templategen/tools" ) type ReqAmoSaveToken struct { @@ -27,90 +27,103 @@ type ReqAmoSaveToken struct { State string `json:"state" schema:"state"` FromWidget string `json:"from_widget" schema:"from_widget"` Referer string `json:"referer" schema:"referer"` - Platform string `json:"platform" schema:"platform"` // Вообще без понятия, что это + /* Указывает на какой платформе установлен виджет */ + Platform string `json:"platform" schema:"platform"` } +// TODO: обсудить сокращения w, r + func (h *Handlers) AmoSaveToken(w http.ResponseWriter, r *http.Request) { - var req ReqAmoSaveToken + var request ReqAmoSaveToken err := r.ParseForm() if err != nil { - fmt.Println("affi", err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - err = schema.NewDecoder().Decode(&req, r.Form) + err = schema.NewDecoder().Decode(&request, r.Form) if err != nil { - fmt.Println("affi1", err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.AccessToken == "" && req.Code == "" { + if request.AccessToken == "" && request.Code == "" { err = errors.New("token required") - fmt.Println("affi2", err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) + return + } + + if request.State == "" { + err = errors.New("got empty state") + h.reportError(w, http.StatusBadRequest, err) + return + } + + // get user + var state tools.StateToken + err = tools.DecryptTokenAES(request.State, &state) + + if err != nil { + h.reportError(w, http.StatusUnauthorized, err) return } token := &oauth2.Token{ - AccessToken: req.AccessToken, - RefreshToken: req.RefreshToken, - TokenType: req.TokenType, - Expiry: time.Now().Add(time.Duration(req.ExpiresIn) * time.Second), + AccessToken: request.AccessToken, + RefreshToken: request.RefreshToken, + TokenType: request.TokenType, + Expiry: time.Now().Add(time.Duration(request.ExpiresIn) * time.Second), } - amoClient, err := h.Amo.NewClient(r.Context(), req.Referer, token, req.Code) + amoClient, err := h.Amo.NewClient(r.Context(), request.Referer, token, request.Code) if err != nil { - fmt.Println("affi3", err) - h.reportError(w, err, http.StatusForbidden) + h.reportError(w, http.StatusForbidden, err) return } token = amoClient.Token - amoAcc, err := amoClient.GetAccount() + accountAmo, err := amoClient.GetAccount(r.Context()) if err != nil { - fmt.Println("affi4", err) - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } // Insert/Update token in DB _, err = h.dal.Amo.InsertOrUpdate(r.Context(), &model.Amo{ - UserID: req.ClientID, - AccountID: strconv.FormatInt(amoAcc.Id, 10), + ClientID: request.ClientID, + AccountID: strconv.FormatInt(accountAmo.ID, 10), + PenaID: state.PenaID, AccessToken: token.AccessToken, RefreshToken: token.RefreshToken, - FromWidget: req.FromWidget, + FromWidget: request.FromWidget, AccessRules: model.AmoAccessRules{ Visibility: []int64{}, - Creation: []int64{}, - Delete: []int64{}, + Creation: []int64{}, + Delete: []int64{}, }, - Referer: req.Referer, - Subdomain: amoAcc.Subdomain, - ExpiresIn: token.Expiry, - TokenType: token.TokenType, + Referer: request.Referer, + Subdomain: accountAmo.Subdomain, + ExpiresIn: token.Expiry, + TokenType: token.TokenType, }) if err != nil { - fmt.Println("affi5", err) - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - http.Redirect(w, r, "", http.StatusPermanentRedirect) + http.Redirect(w, r, state.RedirectURL, http.StatusPermanentRedirect) } type RespAmoState struct { GenCount int `json:"gen_count"` - AuthYandexUrl string `json:"auth_yandex_url"` - AuthGoogleUrl string `json:"auth_google_url"` - AuthAmoUrl string `json:"auth_amo_url"` + AuthYandexURL string `json:"auth_yandex_url"` + AuthGoogleURL string `json:"auth_google_url"` + AuthAmoURL string `json:"auth_amo_url"` Storages map[string]interface{} `json:"storages"` Examples any `json:"examples"` InvalidTokens map[string]any `json:"invalid_tokens"` // Невалидные токены, которые не получилось обновить @@ -119,55 +132,55 @@ type RespAmoState struct { Delete []int64 `json:"delete"` } -// AmoState - получить актуальное состояние аккаунта пользователя в Amo +// AmoState - получить актуальное состояние аккаунта пользователя в Amo. func (h *Handlers) AmoState(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } account, err := h.dal.Amo.GetByAccountID(ctx, amoData.AccountID) if err != nil { - h.reportError(w, fmt.Errorf("db unexpected error %s", err.Error()), http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, fmt.Errorf("db unexpected error %s", err.Error())) return } + if account == nil { - /*penaid, ok := ctx.Value("PenaUserID").(string) - if !ok || penaid == "" { - h.reportError(w, fmt.Errorf("no pena token"), http.StatusUnauthorized) - return - }*/ account = &model.Amo{ AccountID: amoData.AccountID, - //PenaID: penaid, + PenaID: middleware.GetPenaUserID(r), } - id, err := h.dal.Amo.InsertOrUpdate(ctx, account) + + var id string + + id, err = h.dal.Amo.InsertOrUpdate(ctx, account) if err != nil { - h.reportError(w, fmt.Errorf("db unexpected error %s", err.Error()), http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, fmt.Errorf("db unexpected error %s", err.Error())) return } + account.ID = id } - yaStorages, err := h.dal.YaDisk.GetListByUserID(r.Context(), amoData.UserID) + yaStorages, err := h.dal.YaDisk.GetListByPenaID(r.Context(), account.PenaID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - gStorages, err := h.dal.GDisk.GetListByUserID(r.Context(), amoData.UserID) + gStorages, err := h.dal.GDisk.GetListByPenaID(r.Context(), account.PenaID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - penaStorage, err := h.dal.PenaDisk.GetByUserID(ctx, amoData.AccountID) + penaStorage, err := h.dal.PenaDisk.GetByPenaID(ctx, account.PenaID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } @@ -177,26 +190,26 @@ func (h *Handlers) AmoState(w http.ResponseWriter, r *http.Request) { "penadisk": penaStorage, } - redirectUri := "https://" + amoData.Referer + h.opts.AmoRedirectUrn - authYandexUrl, err := h.YaDisk.GenerateOAuthUrl(amoData.UserID, redirectUri) + redirectURI := "https://" + amoData.Referer + h.opts.AmoRedirectUrn + authYandexURL, err := h.YaDisk.GenerateOAuthURL(account.PenaID, redirectURI) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - authGoogleUrl, err := h.GDisk.GenerateOAuthUrl(amoData.UserID, redirectUri) + authGoogleURL, err := h.GDisk.GenerateOAuthURL(account.PenaID, redirectURI) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - authAmoUrl, err := h.Amo.GenerateOAuthUrl(amoData.UserID, redirectUri) + authAmoURL, err := h.Amo.GenerateOAuthURL(account.PenaID, redirectURI) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - //Add examples + // TODO: Add examples var examples any pathExamples := "./static/examples/docx" @@ -208,21 +221,20 @@ func (h *Handlers) AmoState(w http.ResponseWriter, r *http.Request) { result := map[string]string{} pathExamples = "static/examples/docx" for _, file := range fsExamples { - downloadUrl := fmt.Sprintf("https://%v/%v/%v", h.opts.Domain, pathExamples, file.Name()) - result[file.Name()] = downloadUrl + downloadURL := fmt.Sprintf("https://%v/%v/%v", h.opts.Domain, pathExamples, file.Name()) + result[file.Name()] = downloadURL } examples = result } if penaStorage == nil { - if _, err := penadisk.NewClient(amoData.AccountID).GetDisk(); err != nil { + if _, err = penadisk.NewClient(amoData.AccountID).GetDisk(r.Context()); err != nil { h.logger.Error("ErrorCheckPenaDisk", zap.Error(err)) } - // Check PenaDisk _, err = h.dal.PenaDisk.InsertOrUpdate(r.Context(), &model.PenaDisk{ - UserID: amoData.AccountID, + PenaID: amoData.PenaID, Name: "PenaDisk", }) @@ -240,7 +252,8 @@ func (h *Handlers) AmoState(w http.ResponseWriter, r *http.Request) { continue } - token, err := h.YaDisk.RefreshToken(r.Context(), storage.Token()) + var token *oauth2.Token + token, err = h.YaDisk.RefreshToken(r.Context(), storage.Token()) if err == nil { _, err = h.dal.YaDisk.InsertOrUpdate(r.Context(), &model.YaDisk{ @@ -265,7 +278,8 @@ func (h *Handlers) AmoState(w http.ResponseWriter, r *http.Request) { continue } - token, err := h.GDisk.RefreshToken(r.Context(), storage.Token()) + var token *oauth2.Token + token, err = h.GDisk.RefreshToken(r.Context(), storage.Token()) if err == nil { _, err = h.dal.GDisk.InsertOrUpdate(r.Context(), &model.GDisk{ @@ -283,10 +297,10 @@ func (h *Handlers) AmoState(w http.ResponseWriter, r *http.Request) { } // Amo tokens - amoList, err := h.dal.Amo.GetListByUserID(r.Context(), amoData.UserID) + amoList, err := h.dal.Amo.GetListByPenaID(r.Context(), amoData.PenaID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } @@ -295,7 +309,8 @@ func (h *Handlers) AmoState(w http.ResponseWriter, r *http.Request) { continue } - token, err := h.Amo.RefreshToken(r.Context(), amo.Token(), amo.Referer) + var token *oauth2.Token + token, err = h.Amo.RefreshToken(r.Context(), amo.Token(), amo.Referer) if err == nil { _, err = h.dal.Amo.InsertOrUpdate(r.Context(), &model.Amo{ @@ -316,9 +331,9 @@ func (h *Handlers) AmoState(w http.ResponseWriter, r *http.Request) { resp := RespAmoState{ GenCount: 97, - AuthYandexUrl: authYandexUrl, - AuthGoogleUrl: authGoogleUrl, - AuthAmoUrl: authAmoUrl, + AuthYandexURL: authYandexURL, + AuthGoogleURL: authGoogleURL, + AuthAmoURL: authAmoURL, Storages: storages, Visibility: amoData.AccessRules.Visibility, Creation: amoData.AccessRules.Creation, @@ -327,7 +342,7 @@ func (h *Handlers) AmoState(w http.ResponseWriter, r *http.Request) { InvalidTokens: invalidTokens, } - sendResponse(w, 200, resp) + h.sendResponse(w, http.StatusOK, resp) } type ReqAmoAccessRules struct { @@ -336,47 +351,47 @@ type ReqAmoAccessRules struct { Delete []int64 `json:"delete"` } -// AmoAccessRules - задать правила для пользователя +// AmoAccessRules - задать правила для пользователя. func (h *Handlers) AmoAccessRules(w http.ResponseWriter, r *http.Request) { - var req ReqAmoAccessRules + var request ReqAmoAccessRules - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } isAdmin := r.Context().Value("amoIsAdmin").(bool) if !isAdmin { - h.reportError(w, errors.New("need admin access"), http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, errors.New("need admin access")) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if (req.Visibility == nil || len(req.Visibility) == 0) && - (req.Creation == nil || len(req.Creation) == 0) && - (req.Delete == nil || len(req.Delete) == 0) { - h.reportError(w, errors.New("empty request"), http.StatusBadRequest) + if (request.Visibility == nil || len(request.Visibility) == 0) && + (request.Creation == nil || len(request.Creation) == 0) && + (request.Delete == nil || len(request.Delete) == 0) { + h.reportError(w, http.StatusBadRequest, errors.New("empty request")) return } err = h.dal.Amo.UpdateAccessRules(r.Context(), amoData.ID, &model.AmoAccessRules{ - Visibility: req.Visibility, - Creation: req.Creation, - Delete: req.Delete, + Visibility: request.Visibility, + Creation: request.Creation, + Delete: request.Delete, }) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - w.WriteHeader(200) + w.WriteHeader(http.StatusOK) } diff --git a/handlers/gdisk.go b/handlers/gdisk.go index 6e68e9a..8a08707 100644 --- a/handlers/gdisk.go +++ b/handlers/gdisk.go @@ -3,14 +3,16 @@ package handlers import ( "errors" "fmt" - "github.com/gorilla/schema" - "go.uber.org/zap" - "google.golang.org/api/drive/v3" "io" "net/http" "os" + + "github.com/gorilla/schema" + "go.uber.org/zap" + "google.golang.org/api/drive/v3" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" GDisk "penahub.gitlab.yandexcloud.net/backend/templategen/gdisk" + "penahub.gitlab.yandexcloud.net/backend/templategen/middleware" "penahub.gitlab.yandexcloud.net/backend/templategen/templategen" "penahub.gitlab.yandexcloud.net/backend/templategen/tools" ) @@ -21,91 +23,91 @@ type ReqGDiskSaveToken struct { Scope string `json:"scope" schema:"scope"` } -// GDiskSaveToken - сохраняет токен авторизации +// GDiskSaveToken - сохраняет токен авторизации. func (h *Handlers) GDiskSaveToken(w http.ResponseWriter, r *http.Request) { - var req ReqGDiskSaveToken + var request ReqGDiskSaveToken err := r.ParseForm() if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - err = schema.NewDecoder().Decode(&req, r.Form) + err = schema.NewDecoder().Decode(&request, r.Form) if err != nil { - h.reportError(w, err, 500) + h.reportError(w, 500, err) return } - if req.State == "" { + if request.State == "" { err = errors.New("GDiskErr: got empty state") - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.Code == "" { + if request.Code == "" { err = errors.New("GDiskErr: got empty code") - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } // get user var state tools.StateToken - err = tools.DecryptTokenRC4(req.State, &state) + err = tools.DecryptTokenAES(request.State, &state) if err != nil { - h.reportError(w, err, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, err) return } // generate token - token, err := h.GDisk.GetToken(r.Context(), req.Code) + token, err := h.GDisk.GetToken(r.Context(), request.Code) if err != nil { - h.reportError(w, err, 500) + h.reportError(w, http.StatusInternalServerError, err) return } gDisk, err := h.GDisk.NewClient(r.Context(), token) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } token = gDisk.Token - gUser, err := gDisk.GetUserInfo() + gUser, err := gDisk.GetUserInfo(r.Context()) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } // Make default directories in Google Drive gDiskData, err := h.dal.GDisk.GetByEmail(r.Context(), gUser.EmailAddress) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - var defaultId, defaultName, templateId, templateName, saveId, saveName string + var defaultID, defaultName, templateID, templateName, saveID, saveName string if gDiskData != nil { - defaultId = gDiskData.DefaultFolderID + defaultID = gDiskData.DefaultFolderID defaultName = gDiskData.DefaultFolder - templateId = gDiskData.TemplateFolderID + templateID = gDiskData.TemplateFolderID templateName = gDiskData.TemplateFolder - saveId = gDiskData.SaveFolderID + saveID = gDiskData.SaveFolderID saveName = gDiskData.SaveFolder } - defaultFolder, templateFolder, saveFolder, err := gDisk.MakeDefaultDirs(defaultId, defaultName, templateId, - templateName, saveId, saveName) + defaultFolder, templateFolder, saveFolder, err := gDisk.MakeDefaultDirs(defaultID, defaultName, templateID, + templateName, saveID, saveName) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } // Insert/Update token in DB _, err = h.dal.GDisk.InsertOrUpdate(r.Context(), &model.GDisk{ - UserID: state.UserID, + PenaID: state.PenaID, Name: fmt.Sprintf("Google Disk (%v)", gUser.EmailAddress), DisplayName: gUser.DisplayName, Email: gUser.EmailAddress, @@ -123,18 +125,18 @@ func (h *Handlers) GDiskSaveToken(w http.ResponseWriter, r *http.Request) { }) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - http.Redirect(w, r, state.RedirectUrl, http.StatusPermanentRedirect) + http.Redirect(w, r, state.RedirectURL, http.StatusPermanentRedirect) } type ReqGDiskSetSettings struct { ID string `json:"id"` Name string `json:"name"` // Пользовательское название хранилища DefaultFolder string `json:"default_folder"` - DefaultFolderId string `json:"default_folder_id"` + DefaultFolderID string `json:"default_folder_id"` TemplateFolder string `json:"template_folder"` TemplateFolderID string `json:"template_folder_id"` SaveFolder string `json:"save_folder"` @@ -142,46 +144,42 @@ type ReqGDiskSetSettings struct { } func (h *Handlers) GDiskSetSettings(w http.ResponseWriter, r *http.Request) { - var req ReqGDiskSetSettings + var request ReqGDiskSetSettings - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } err = h.dal.GDisk.Update(r.Context(), &model.GDisk{ - ID: req.ID, - Name: req.Name, - DefaultFolder: req.DefaultFolder, - DefaultFolderID: req.DefaultFolderId, - TemplateFolder: req.TemplateFolder, - TemplateFolderID: req.TemplateFolderID, - SaveFolder: req.SaveFolder, - SaveFolderID: req.SaveFolderID, + ID: request.ID, + Name: request.Name, + DefaultFolder: request.DefaultFolder, + DefaultFolderID: request.DefaultFolderID, + TemplateFolder: request.TemplateFolder, + TemplateFolderID: request.TemplateFolderID, + SaveFolder: request.SaveFolder, + SaveFolderID: request.SaveFolderID, }) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, nil) -} - -func (h *Handlers) GDiskGetFile(w http.ResponseWriter, r *http.Request) { - + w.WriteHeader(http.StatusOK) } type ReqGDiskGetResources struct { @@ -198,131 +196,131 @@ type ReqGDiskGetResources struct { // - Если указан Name и ParentID ищет файл\папку только в родителе // - ParentID игнорируется без Name func (h *Handlers) GDiskGetResources(w http.ResponseWriter, r *http.Request) { - var req ReqGDiskGetResources + var request ReqGDiskGetResources - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } - gdiskInfo, err := h.dal.GDisk.GetByID(r.Context(), req.ID) + gdiskInfo, err := h.dal.GDisk.GetByID(r.Context(), request.ID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } if gdiskInfo == nil { - h.reportError(w, errors.New("gdisk info not found"), http.StatusForbidden) + h.reportError(w, http.StatusForbidden, errors.New("gdisk info not found")) return } client, err := h.GDisk.NewClient(r.Context(), gdiskInfo.Token()) if err != nil { - h.reportError(w, err, http.StatusForbidden) + h.reportError(w, http.StatusForbidden, err) return } var res *drive.FileList - if req.Name != "" { - res, err = client.GetResourcesByName(req.Name, req.ParentID) + if request.Name != "" { + res, err = client.GetResourcesByName(request.Name, request.ParentID) } else { - res, err = client.GetResources(req.FolderID) + res, err = client.GetResources(request.FolderID) } if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, res) + h.sendResponse(w, http.StatusOK, res) } type ReqGDiskGetDirTemplate struct { Email string `json:"email"` // Required. Google Email ? } -// GDiskGetDirTemplate - возвращает данные по папке template, включая список её файлов и папок +// GDiskGetDirTemplate - возвращает данные по папке template, включая список её файлов и папок. func (h *Handlers) GDiskGetDirTemplate(w http.ResponseWriter, r *http.Request) { - var req ReqGDiskGetDirTemplate + var request ReqGDiskGetDirTemplate - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.Email == "" { - h.reportError(w, errors.New("email required"), http.StatusBadRequest) + if request.Email == "" { + h.reportError(w, http.StatusBadRequest, errors.New("email required")) } - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - gdiskInfo, err := h.dal.GDisk.GetByEmail(r.Context(), req.Email) + gdiskInfo, err := h.dal.GDisk.GetByEmail(r.Context(), request.Email) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } if gdiskInfo == nil { - h.reportError(w, errors.New("gdisk info not found"), http.StatusForbidden) + h.reportError(w, http.StatusForbidden, errors.New("gdisk info not found")) return } if gdiskInfo.Token() == nil { - h.reportError(w, errors.New("google token invalid"), http.StatusForbidden) + h.reportError(w, http.StatusForbidden, errors.New("google token invalid")) return } client, err := h.GDisk.NewClient(r.Context(), gdiskInfo.Token()) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } dir, err := client.GetResources(gdiskInfo.TemplateFolderID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, dir) + h.sendResponse(w, http.StatusOK, dir) } -// GDiskGetList - возвращает список хранилищ Google закрепленных за пользователем по его UserID из JWT +// GDiskGetList - возвращает список хранилищ Google закрепленных за пользователем по его UserID из JWT. func (h *Handlers) GDiskGetList(w http.ResponseWriter, r *http.Request) { - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - gdiskInfo, err := h.dal.GDisk.GetListByUserID(r.Context(), amoData.UserID) + gdiskInfo, err := h.dal.GDisk.GetListByPenaID(r.Context(), amoData.PenaID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, http.StatusOK, gdiskInfo) + h.sendResponse(w, http.StatusOK, gdiskInfo) } type ReqGDiskPutResources struct { @@ -331,57 +329,57 @@ type ReqGDiskPutResources struct { ParentID string `json:"parent_id"` } -// GDiskPutResources - создать папку в хранилище +// GDiskPutResources - создать папку в хранилище. func (h *Handlers) GDiskPutResources(w http.ResponseWriter, r *http.Request) { - var req ReqGDiskPutResources + var request ReqGDiskPutResources - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } - if req.Name == "" { - h.reportError(w, errors.New("name required"), http.StatusBadRequest) + if request.Name == "" { + h.reportError(w, http.StatusBadRequest, errors.New("name required")) return } - gdiskInfo, err := h.dal.GDisk.GetByID(r.Context(), req.ID) + gdiskInfo, err := h.dal.GDisk.GetByID(r.Context(), request.ID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } if gdiskInfo == nil { - h.reportError(w, errors.New("gdisk info not found"), http.StatusForbidden) + h.reportError(w, http.StatusForbidden, errors.New("gdisk info not found")) return } client, err := h.GDisk.NewClient(r.Context(), gdiskInfo.Token()) if err != nil { - h.reportError(w, err, http.StatusForbidden) + h.reportError(w, http.StatusForbidden, err) return } - file, err := client.PutResources(req.Name, req.ParentID) + file, err := client.PutResources(request.Name, request.ParentID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, file) + h.sendResponse(w, http.StatusOK, file) } type ReqGDiskUploadResources struct { @@ -389,27 +387,33 @@ type ReqGDiskUploadResources struct { ParentID string `json:"parent_id" schema:"parent_id"` } -// GDiskUploadResources - загрузить файл в хранилище +// GDiskUploadResources - загрузить файл в хранилище. func (h *Handlers) GDiskUploadResources(w http.ResponseWriter, r *http.Request) { // Check form fileData, fileHeader, err := r.FormFile("file") - defer fileData.Close() + + defer fileData.Close() //nolint + + if err != nil { + h.reportError(w, http.StatusInternalServerError, err) + return + } var req ReqGDiskUploadResources err = schema.NewDecoder().Decode(&req, r.Form) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } var maxSize int64 = 10 << 20 // mb if fileHeader.Size > maxSize { - h.reportError(w, errors.New("max size 10 mb"), http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, errors.New("max size 10 mb")) return } @@ -418,30 +422,30 @@ func (h *Handlers) GDiskUploadResources(w http.ResponseWriter, r *http.Request) downloadPath := fmt.Sprintf("%v/%v", templategen.TempDownloaded, fileHeader.Filename) out, err := os.Create(downloadPath) - defer out.Close() + defer out.Close() //nolint if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } _, err = io.Copy(out, fileData) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } // Upload file to the storage storage, err := h.dal.GDisk.GetByID(r.Context(), req.ID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } client, err := h.GDisk.NewClient(r.Context(), storage.Token()) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } @@ -449,7 +453,7 @@ func (h *Handlers) GDiskUploadResources(w http.ResponseWriter, r *http.Request) _, _, err = client.UploadFile(downloadPath, GDisk.MimeTypeDocx, req.ParentID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } @@ -461,53 +465,53 @@ type ReqGDiskDeleteResources struct { FolderID string `json:"folder_id"` } -// GDiskDeleteResources - удалить папку\файл +// GDiskDeleteResources - удалить папку\файл. func (h *Handlers) GDiskDeleteResources(w http.ResponseWriter, r *http.Request) { - var req ReqGDiskDeleteResources + var request ReqGDiskDeleteResources - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } - if req.FolderID == "" { - h.reportError(w, errors.New("folder_id required"), http.StatusBadRequest) + if request.FolderID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("folder_id required")) return } - gdiskInfo, err := h.dal.GDisk.GetByID(r.Context(), req.ID) + gdiskInfo, err := h.dal.GDisk.GetByID(r.Context(), request.ID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } if gdiskInfo == nil { - h.reportError(w, errors.New("gdisk info not found"), http.StatusForbidden) + h.reportError(w, http.StatusForbidden, errors.New("gdisk info not found")) return } client, err := h.GDisk.NewClient(r.Context(), gdiskInfo.Token()) if err != nil { - h.reportError(w, err, http.StatusForbidden) + h.reportError(w, http.StatusForbidden, err) return } - err = client.DeleteResources(req.FolderID) + err = client.DeleteResources(request.FolderID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } diff --git a/handlers/generator.go b/handlers/generator.go index ed84524..6ced46c 100644 --- a/handlers/generator.go +++ b/handlers/generator.go @@ -3,43 +3,48 @@ package handlers import ( "errors" "fmt" - "go.uber.org/zap" "io" "net/http" "net/url" - "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" - "penahub.gitlab.yandexcloud.net/backend/templategen/penadisk" - "penahub.gitlab.yandexcloud.net/backend/templategen/templategen" "strconv" "strings" + "time" + + "go.uber.org/zap" + "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" + "penahub.gitlab.yandexcloud.net/backend/templategen/gdisk" + "penahub.gitlab.yandexcloud.net/backend/templategen/middleware" + "penahub.gitlab.yandexcloud.net/backend/templategen/penadisk" + "penahub.gitlab.yandexcloud.net/backend/templategen/templategen" + "penahub.gitlab.yandexcloud.net/backend/templategen/yadisk" ) type ReqGeneratorByAmoLead struct { File string `json:"file"` // Путь до файла в Yandex Disk, либо ID файла в Google Disk StorageID string `json:"storage_id"` StorageType string `json:"storage_type"` - LeadId int64 `json:"lead_id"` // Required. + LeadID int64 `json:"lead_id"` // Required. } type RespGenerated struct { - DownloadUrl string `json:"download_url"` + DownloadURL string `json:"download_url"` } // GeneratorByAmoLead - сгенерировать файл по lead_id и указанному файлу если он установлен, -// или по шаблону если файл не указан +// или по шаблону если файл не указан. func (h *Handlers) GeneratorByAmoLead(w http.ResponseWriter, r *http.Request) { - var req ReqGeneratorByAmoLead + var request ReqGeneratorByAmoLead - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - amoUserID := getAmoUserID(r) + amoUserID := middleware.GetAmoUserID(r) - history := model.NewHistory(amoData.UserID, amoData.ID, amoUserID, model.HistoryTriggerAmoLead) + history := model.NewHistory(amoData.PenaID, amoData.ID, amoUserID, model.HistoryTriggerAmoLead) defer func() { _, err := h.dal.History.Insert(r.Context(), history) if err != nil { @@ -47,56 +52,57 @@ func (h *Handlers) GeneratorByAmoLead(w http.ResponseWriter, r *http.Request) { } }() - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { history.AddError(err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - history.LeadID = req.LeadId + history.LeadID = request.LeadID - if req.LeadId <= 0 { + if request.LeadID <= 0 { err = errors.New("lead_id required") history.AddError(err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } // Отправляем задачу в воркер var file, storageType, storageID, templateID string - if req.File != "" { - history.Source.File = req.File - history.Source.StorageID = req.StorageID - history.Source.StorageType = req.StorageType + if request.File != "" { + history.Source.File = request.File + history.Source.StorageID = request.StorageID + history.Source.StorageType = request.StorageType - if req.StorageType == "" { + if request.StorageType == "" { err = errors.New("storage required") history.AddError(err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.StorageID == "" { + if request.StorageID == "" { err = errors.New("storage_id required") history.AddError(err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - file = req.File - storageType = req.StorageType - storageID = req.StorageID + file = request.File + storageType = request.StorageType + storageID = request.StorageID } else { - template, err := h.dal.Template.GetByLeadId(r.Context(), req.LeadId) + var template *model.Template + template, err = h.dal.Template.GetByLeadID(r.Context(), request.LeadID) if err != nil { history.AddError(err) - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } if template == nil { history.AddError(err) - h.reportError(w, err, http.StatusNotFound) + h.reportError(w, http.StatusNotFound, err) return } @@ -106,26 +112,34 @@ func (h *Handlers) GeneratorByAmoLead(w http.ResponseWriter, r *http.Request) { templateID = template.ID } - task := model.NewWorkerTask(amoData.UserID, amoData.ID, amoUserID, model.WorkerTaskStatusNew, req.LeadId, - templateID, model.WorkerSource{ + task := &model.WorkerTask{ + PenaID: amoData.PenaID, + AmoID: amoData.ID, + AmoUserID: amoUserID, + Status: model.WorkerTaskStatusNew, + LeadID: request.LeadID, + TemplateID: templateID, + Source: model.WorkerSource{ File: file, StorageID: storageID, StorageType: storageType, - }, model.WorkerTarget{ + }, + Target: model.WorkerTarget{ File: "", StorageID: storageID, StorageType: storageType, - }) + }, + } - taskId, err := h.dal.WorkerTask.Insert(r.Context(), task) + taskID, err := h.dal.WorkerTask.Insert(r.Context(), task) if err != nil { history.AddError(err) - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - history.WorkerTaskID = taskId + history.WorkerTaskID = taskID w.WriteHeader(http.StatusOK) } @@ -139,20 +153,20 @@ type ReqGeneratorByData struct { Data map[string]any `json:"data"` } -// GeneratorByData - сгенерировать файл по данным и указанному файлу или шаблону +// GeneratorByData - сгенерировать файл по данным и указанному файлу или шаблону. func (h *Handlers) GeneratorByData(w http.ResponseWriter, r *http.Request) { - var req ReqGeneratorByData + var request ReqGeneratorByData - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - amoUserID := getAmoUserID(r) + amoUserID := middleware.GetAmoUserID(r) - history := model.NewHistory(amoData.UserID, amoData.ID, amoUserID, model.HistoryTriggerData) + history := model.NewHistory(amoData.PenaID, amoData.ID, amoUserID, model.HistoryTriggerData) defer func() { _, err := h.dal.History.Insert(r.Context(), history) if err != nil { @@ -160,19 +174,20 @@ func (h *Handlers) GeneratorByData(w http.ResponseWriter, r *http.Request) { } }() - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { history.AddError(err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } var file, name, storageID, storageType string - if req.TemplateID != "" { - template, err := h.dal.Template.GetByID(r.Context(), req.TemplateID) + if request.TemplateID != "" { + var template *model.Template + template, err = h.dal.Template.GetByID(r.Context(), request.TemplateID) if err != nil { history.AddError(err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } file = template.File @@ -180,53 +195,53 @@ func (h *Handlers) GeneratorByData(w http.ResponseWriter, r *http.Request) { storageID = template.StorageID name = template.Name } else { - if req.File == "" { + if request.File == "" { err = errors.New("file required") history.AddError(err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.StorageType == "" { + if request.StorageType == "" { err = errors.New("storage required") history.AddError(err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.StorageID == "" { + if request.StorageID == "" { err = errors.New("storage_id required") history.AddError(err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.Name == "" { + if request.Name == "" { err = errors.New("name required") history.AddError(err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - file = req.File - storageType = req.StorageType - storageID = req.StorageID - name = req.Name + file = request.File + storageType = request.StorageType + storageID = request.StorageID + name = request.Name } - exportUrl, err := h.generate(w, r, file, name, storageID, storageType, amoData.UserID, history, req.Data) + exportURL, err := h.generate(r, file, name, storageID, storageType, amoData.PenaID, history, request.Data) if err != nil { history.AddError(err) - sendResponse(w, http.StatusInternalServerError, err) + h.sendResponse(w, http.StatusInternalServerError, err) return } - sendResponse(w, http.StatusOK, RespGenerated{DownloadUrl: exportUrl}) + h.sendResponse(w, http.StatusOK, RespGenerated{DownloadURL: exportURL}) } -// GeneratorByAmoWebhook - эндпоинт для вебхука amo. Генерирует файл по ранее заданному шаблону +// GeneratorByAmoWebhook - эндпоинт для вебхука amo. Генерирует файл по ранее заданному шаблону. func (h *Handlers) GeneratorByAmoWebhook(w http.ResponseWriter, r *http.Request) { reqBody, err := io.ReadAll(r.Body) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } @@ -239,7 +254,7 @@ func (h *Handlers) GeneratorByAmoWebhook(w http.ResponseWriter, r *http.Request) history := model.NewHistory("", "", 0, model.HistoryTriggerWebhook) defer func() { - _, err := h.dal.History.Insert(r.Context(), history) + _, err = h.dal.History.Insert(r.Context(), history) if err != nil { h.logger.Error("GeneratorByData", zap.Error(err)) } @@ -248,49 +263,47 @@ func (h *Handlers) GeneratorByAmoWebhook(w http.ResponseWriter, r *http.Request) p, err := url.ParseQuery(body) if err != nil { history.AddError(err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - leadId := p.Get("event[data][id]") - //subdomain := p.Get("subdomain") - accId := p.Get("account_id") - templateId := p.Get("action[settings][widget][settings][template_id]") - // pipelineId := p.Get("event[data][pipeline_id]") + leadID := p.Get("event[data][id]") + accID := p.Get("account_id") + templateID := p.Get("action[settings][widget][settings][template_id]") - history.TemplateID = templateId + history.TemplateID = templateID - convertedLeadId, err := strconv.ParseInt(leadId, 10, 64) + convertedLeadID, err := strconv.ParseInt(leadID, 10, 64) if err != nil { history.AddError(err) - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - history.LeadID = convertedLeadId + history.LeadID = convertedLeadID // Запрашиваем данные по аккаунту - amoData, err := h.dal.Amo.GetByAccountID(r.Context(), accId) + amoData, err := h.dal.Amo.GetByAccountID(r.Context(), accID) if err != nil { history.AddError(err) - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } if amoData == nil { err = errors.New("amo account not found") history.AddError(err) - h.reportError(w, err, http.StatusForbidden) + h.reportError(w, http.StatusForbidden, err) return } history.AmoID = amoData.ID - history.UserID = amoData.UserID + history.PenaID = amoData.PenaID - template, err := h.dal.Template.GetByID(r.Context(), templateId) + template, err := h.dal.Template.GetByID(r.Context(), templateID) if template == nil { history.AddError(err) - h.reportError(w, err, http.StatusNotFound) + h.reportError(w, http.StatusNotFound, err) return } @@ -306,34 +319,72 @@ func (h *Handlers) GeneratorByAmoWebhook(w http.ResponseWriter, r *http.Request) } // Отправляем задачу в воркер - task := model.NewWorkerTask(amoData.UserID, amoData.ID, 0, model.WorkerTaskStatusNew, convertedLeadId, - templateId, model.WorkerSource{ + task := &model.WorkerTask{ + PenaID: amoData.PenaID, + AmoID: amoData.ID, + AmoUserID: 0, + Status: model.WorkerTaskStatusNew, + LeadID: convertedLeadID, + TemplateID: templateID, + Source: model.WorkerSource{ File: template.File, StorageID: template.StorageID, StorageType: template.StorageType, - }, model.WorkerTarget{ + }, + Target: model.WorkerTarget{ File: "", StorageID: template.StorageID, StorageType: template.StorageType, - }) + }, + } - taskId, err := h.dal.WorkerTask.Insert(r.Context(), task) + taskID, err := h.dal.WorkerTask.Insert(r.Context(), task) if err != nil { history.AddError(err) - h.reportError(w, err, http.StatusForbidden) + h.reportError(w, http.StatusForbidden, err) return } - history.WorkerTaskID = taskId + history.WorkerTaskID = taskID w.WriteHeader(http.StatusOK) } -// generate - локальная функция, для генерации файла, возвращает ссылку для скачивания сгенерированного файла -func (h *Handlers) generate(w http.ResponseWriter, r *http.Request, file, name, storageID, storageType, - userID string, history *model.History, data any) (string, error) { - var exportUrl string +// generate - локальная функция, для генерации файла, возвращает ссылку для скачивания сгенерированного файла. +func (h *Handlers) generate(r *http.Request, file, name, storageID, storageType, + penaID string, history *model.History, data any) (string, error) { + amoData, err := h.dal.Amo.GetByPenaID(r.Context(), penaID) + if err != nil { + return "", err + } + + // Check privileges + if len(amoData.Privileges) == 0 { + return "", errors.New("user has no tariff") + } + + var privilegeAmount int64 + + // По количеству генераций + privilege, privilegeCountExists := amoData.Privileges[model.PrivilegeTemplateCount] + if privilegeCountExists { + privilegeAmount = privilege.Amount + + if privilegeAmount < 1 { + return "", errors.New("tariff ended - not enough count") + } + } + + // По дате + privilege, privilegeUnlimTimeExists := amoData.Privileges[model.PrivilegeTemplateUnlimTime] + if privilegeUnlimTimeExists { + if privilege.CreatedAt.AddDate(0, 0, int(privilege.Amount)).After(time.Now()) { + return "", errors.New("tariff ended - by time") + } + } + + var exportURL string history.Source.File = file history.Source.StorageID = storageID history.Source.StorageType = storageType @@ -344,77 +395,83 @@ func (h *Handlers) generate(w http.ResponseWriter, r *http.Request, file, name, // Генерируем файл и загружаем в хранилище switch storageType { case "gdisk": - gdiskData, err := h.dal.GDisk.GetByID(r.Context(), storageID) + var gdiskData *model.GDisk + gdiskData, err = h.dal.GDisk.GetByID(r.Context(), storageID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) - return "", nil + return "", err } if gdiskData == nil { - h.reportError(w, err, http.StatusInternalServerError) - return "", nil + return "", errors.New("google disk data not found") } - client, err := h.GDisk.NewClient(r.Context(), gdiskData.Token()) - - //history.Target.File, exportUrl, err = templategen.GDiskGenerateDoc(file, name, userID, gdiskData.SaveFolderID, client, - // data) - // - history.Target.File, exportUrl, err = templategen.GDiskGenerateDocBytes(file, name, userID, gdiskData.SaveFolderID, client, data) + var client *gdisk.Client + client, err = h.GDisk.NewClient(r.Context(), gdiskData.Token()) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) - return "", nil + return "", err + } + + history.Target.File, exportURL, err = templategen.GDiskGenerateDocBytes(file, name, gdiskData.SaveFolderID, client, data) + + if err != nil { + return "", err } case "yadisk": - yaDiskData, err := h.dal.YaDisk.GetByID(r.Context(), storageID) + var yaDiskData *model.YaDisk + yaDiskData, err = h.dal.YaDisk.GetByID(r.Context(), storageID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) - return "", nil + return "", err } - client, err := h.YaDisk.NewClient(r.Context(), yaDiskData.Token(), "") + if yaDiskData == nil { + return "", errors.New("yandex disk data not found") + } - //history.Target.File, exportUrl, err = templategen.YaDiskGenerateDoc(file, name, userID, yaDiskData.SaveFolder, - // client, - // data) - - history.Target.File, exportUrl, err = templategen.YaDiskGenerateDocBytes(file, name, userID, yaDiskData.SaveFolder, - client, - data) + var client *yadisk.Client + client, err = h.YaDisk.NewClient(r.Context(), yaDiskData.Token(), "") if err != nil { - h.reportError(w, err, http.StatusInternalServerError) - return "", nil + return "", err + } + + history.Target.File, exportURL, err = templategen.YaDiskGenerateDocBytes(r.Context(), file, name, yaDiskData.SaveFolder, client, data) + + if err != nil { + return "", err } case "example": - generatedFile, err := templategen.ExampleGenerate(file, data) + var generatedFile string + generatedFile, err = templategen.ExampleGenerate(file, data) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + return "", err } history.Target.File = generatedFile generatedFile = strings.TrimPrefix(generatedFile, "./") - exportUrl = fmt.Sprintf("https://%v/%v", h.opts.Domain, generatedFile) + exportURL = fmt.Sprintf("https://%v/%v", h.opts.Domain, generatedFile) case "penadisk": - client := penadisk.NewClient(userID) - var err error + client := penadisk.NewClient(penaID) saveFolder := "templategen/saved" - history.Target.File, exportUrl, err = templategen.PenaDiskGenerateDocBytes(file, name, userID, saveFolder, + history.Target.File, exportURL, err = templategen.PenaDiskGenerateDocBytes(r.Context(), file, name, saveFolder, client, data) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) - return "", nil + return "", err } default: - h.reportError(w, errors.New("got unknown storage"), http.StatusInternalServerError) - return "", nil + err = errors.New("got unknown storage") + return "", err } - // Обновляем счетчик генераций + if privilegeCountExists { + err = h.dal.Amo.UpdateAmountPrivilege(r.Context(), amoData.ID, model.PrivilegeTemplateCount, privilegeAmount-1) + if err != nil { + return "", err + } + } - return exportUrl, nil + return exportURL, nil } diff --git a/handlers/handlers.go b/handlers/handlers.go index c5000ce..9b65eeb 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -3,14 +3,12 @@ package handlers import ( "encoding/json" "errors" - "html/template" - "io/ioutil" + "io" "net/http" "go.uber.org/zap" "penahub.gitlab.yandexcloud.net/backend/templategen/amo" "penahub.gitlab.yandexcloud.net/backend/templategen/dal" - "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" GDisk "penahub.gitlab.yandexcloud.net/backend/templategen/gdisk" YaDisk "penahub.gitlab.yandexcloud.net/backend/templategen/yadisk" ) @@ -36,57 +34,26 @@ func NewHandlers(dal *dal.MongoDAL, yaDisk *YaDisk.ClientApp, gDisk *GDisk.Clien // LOCAL FUNCTIONS -func execTemplate(tplFile string, data interface{}, w http.ResponseWriter) error { - tpl := template.Must(template.ParseFiles("./template/"+tplFile, "./template/header.gohtml", - "./template/footer.gohtml")) - return tpl.Execute(w, data) -} - -func sendResponse(w http.ResponseWriter, status int, response interface{}) error { +func (h *Handlers) sendResponse(w http.ResponseWriter, status int, response interface{}) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(status) e := json.NewEncoder(w) e.SetEscapeHTML(false) - return e.Encode(response) + err := e.Encode(response) + if err != nil { + h.logger.Error("ErrorHandler - JSON ENCODER", zap.Error(err)) + } } -func (h *Handlers) reportError(w http.ResponseWriter, err error, status int) { +func (h *Handlers) reportError(w http.ResponseWriter, status int, err error) { h.logger.Error("ErrorHandler", zap.Error(err)) - sendResponse(w, status, err.Error()) -} - -func getAmoByJwt(r *http.Request) *model.Amo { - amoData, ok := r.Context().Value("amoData").(*model.Amo) - if ok { - return amoData - } - - return nil -} - -func getAmoUserID(r *http.Request) int64 { - result, ok := r.Context().Value("amoUserID").(int64) - - if ok { - return result - } - - return 0 -} - -func getJwtUser(r *http.Request) string { - user, ok := r.Context().Value("UserID").(string) - if ok { - return user - } - - return "" + h.sendResponse(w, status, err.Error()) } func decodePost(s interface{}, r *http.Request) error { - reqBody, err := ioutil.ReadAll(r.Body) + reqBody, err := io.ReadAll(r.Body) if err != nil { return err diff --git a/handlers/history.go b/handlers/history.go index d62f147..3335622 100644 --- a/handlers/history.go +++ b/handlers/history.go @@ -5,6 +5,7 @@ import ( "net/http" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/mongos" + "penahub.gitlab.yandexcloud.net/backend/templategen/middleware" ) type ReqGetHistoryByID struct { @@ -12,76 +13,76 @@ type ReqGetHistoryByID struct { } func (h *Handlers) GetHistoryByID(w http.ResponseWriter, r *http.Request) { - var req ReqGetHistoryByID + var request ReqGetHistoryByID - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) } - result, err := h.dal.History.GetByID(r.Context(), req.ID) + result, err := h.dal.History.GetByID(r.Context(), request.ID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } if result == nil { - sendResponse(w, http.StatusNotFound, "not found") + h.sendResponse(w, http.StatusNotFound, "not found") // TODO: проверить на фронте, используется ли тело. Если нет, то поменять на w.WriteHeader(http.StatusNotFound) return } - sendResponse(w, http.StatusOK, result) + h.sendResponse(w, http.StatusOK, result) } func (h *Handlers) GetHistoryListByFilter(w http.ResponseWriter, r *http.Request) { - var req mongos.HistoryFilter + var request mongos.HistoryFilter - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - amoUserID := getAmoUserID(r) + amoUserID := middleware.GetAmoUserID(r) if amoUserID > 0 { - req.AmoUserID = amoUserID + request.AmoUserID = amoUserID } - req.AmoID = amoData.AccountID + request.AmoID = amoData.AccountID - result, err := h.dal.History.GetByFilter(r.Context(), &req) + result, err := h.dal.History.GetByFilter(r.Context(), &request) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } if len(result) == 0 { - sendResponse(w, http.StatusNotFound, "not found") + h.sendResponse(w, http.StatusNotFound, "not found") // TODO: проверить на фронте, используется ли тело. Если нет, то поменять на w.WriteHeader(http.StatusNotFound) return } - sendResponse(w, http.StatusOK, result) + h.sendResponse(w, http.StatusOK, result) } type ReqGetHistoryList struct { @@ -90,32 +91,32 @@ type ReqGetHistoryList struct { } func (h *Handlers) GetHistoryList(w http.ResponseWriter, r *http.Request) { - var req ReqGetHistoryList + var request ReqGetHistoryList - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - result, err := h.dal.History.GetListPageByAmoID(r.Context(), amoData.ID, req.Limit, req.Page) + result, err := h.dal.History.GetListPageByAmoID(r.Context(), amoData.ID, request.Limit, request.Page) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } if len(result) == 0 { - sendResponse(w, http.StatusNotFound, "not found") + h.sendResponse(w, http.StatusNotFound, "not found") // TODO: проверить на фронте, используется ли тело. Если нет, то поменять на w.WriteHeader(http.StatusNotFound) return } - sendResponse(w, http.StatusOK, result) + h.sendResponse(w, http.StatusOK, result) } diff --git a/handlers/pages.go b/handlers/pages.go index 9188eb7..b6a0328 100644 --- a/handlers/pages.go +++ b/handlers/pages.go @@ -4,6 +4,6 @@ import ( "net/http" ) -func (h *Handlers) PageNotFound(w http.ResponseWriter, r *http.Request) { - sendResponse(w, 404, "404 - Page not found / Страница не найдена") +func (h *Handlers) PageNotFound(w http.ResponseWriter, _ *http.Request) { + h.sendResponse(w, 404, "404 - Page not found / Страница не найдена") } diff --git a/handlers/penadisk.go b/handlers/penadisk.go index cf174e5..ef9ebdf 100644 --- a/handlers/penadisk.go +++ b/handlers/penadisk.go @@ -2,10 +2,11 @@ package handlers import ( "errors" - "github.com/gorilla/schema" "net/http" - "fmt" + + "github.com/gorilla/schema" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" + "penahub.gitlab.yandexcloud.net/backend/templategen/middleware" "penahub.gitlab.yandexcloud.net/backend/templategen/penadisk" ) @@ -16,32 +17,32 @@ type ReqPenaDiskSetSettings struct { } func (h *Handlers) PenaDiskSetSettings(w http.ResponseWriter, r *http.Request) { - var req ReqPenaDiskSetSettings + var request ReqPenaDiskSetSettings - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } err = h.dal.PenaDisk.Update(r.Context(), &model.PenaDisk{ - UserID: amoData.AccountID, - Name: req.Name, - TemplateFolder: req.TemplateFolder, - SaveFolder: req.SaveFolder}) + PenaID: amoData.PenaID, + Name: request.Name, + TemplateFolder: request.TemplateFolder, + SaveFolder: request.SaveFolder}) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, nil) + w.WriteHeader(http.StatusOK) } type ReqPenaDiskGetResources struct { @@ -51,31 +52,30 @@ type ReqPenaDiskGetResources struct { } func (h *Handlers) PenaDiskGetResources(w http.ResponseWriter, r *http.Request) { - var req ReqPenaDiskGetResources + var request ReqPenaDiskGetResources - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - fmt.Println("pdclient1", amoData.AccountID, req.Path) - client := penadisk.NewClient(amoData.AccountID) + client := penadisk.NewClient(amoData.PenaID) - resource, err := client.GetResources(req.Path, req.Recursive, req.WIthVersions) + resource, err := client.GetResources(r.Context(), request.Path, request.Recursive, request.WIthVersions) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, resource) + h.sendResponse(w, http.StatusOK, resource) } type ReqPenaDiskPutResources struct { @@ -83,33 +83,33 @@ type ReqPenaDiskPutResources struct { } func (h *Handlers) PenaDiskPutResources(w http.ResponseWriter, r *http.Request) { - var req ReqPenaDiskPutResources - amoData := getAmoByJwt(r) + var request ReqPenaDiskPutResources + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.Path == "" { - h.reportError(w, errors.New("path required"), http.StatusBadRequest) + if request.Path == "" { + h.reportError(w, http.StatusBadRequest, errors.New("path required")) } - client := penadisk.NewClient(amoData.AccountID) + client := penadisk.NewClient(amoData.PenaID) - err = client.PutResources(req.Path) + err = client.PutResources(r.Context(), request.Path) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, nil) + w.WriteHeader(http.StatusOK) } type ReqPenaDiskDeleteResources struct { @@ -118,92 +118,87 @@ type ReqPenaDiskDeleteResources struct { } func (h *Handlers) PenaDiskDeleteResources(w http.ResponseWriter, r *http.Request) { - var req ReqPenaDiskDeleteResources + var request ReqPenaDiskDeleteResources - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.Path == "" { - h.reportError(w, errors.New("path required"), http.StatusBadRequest) + if request.Path == "" { + h.reportError(w, http.StatusBadRequest, errors.New("path required")) } - client := penadisk.NewClient(amoData.AccountID) + client := penadisk.NewClient(amoData.PenaID) - err = client.DeleteResources(req.Path, req.Permanently) + err = client.DeleteResources(r.Context(), request.Path, request.Permanently) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, nil) + w.WriteHeader(http.StatusOK) } type ReqPenaDiskUploadResources struct { - Id string `json:"id" schema:"id"` + ID string `json:"id" schema:"id"` Path string `json:"path" schema:"path"` Overwrite bool `json:"overwrite" schema:"overwrite"` } func (h *Handlers) PenaDiskUploadResources(w http.ResponseWriter, r *http.Request) { - /*amoData := getAmoByJwt(r) - - if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) - return - } - fmt.Println("PenaDiskUploadResources1", amoData) -*/ // Check form fileData, fileHeader, err := r.FormFile("file") + + if err != nil { + h.reportError(w, http.StatusBadRequest, err) + return + } + defer fileData.Close() - var req ReqPenaDiskUploadResources - err = schema.NewDecoder().Decode(&req, r.Form) + var request ReqPenaDiskUploadResources + err = schema.NewDecoder().Decode(&request, r.Form) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.Id == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } - if req.Path == "" { - req.Path = "/" + if request.Path == "" { + request.Path = "/" } var maxSize int64 = 10 << 20 // mb if fileHeader.Size > maxSize { - h.reportError(w, errors.New("max size 10 mb"), http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, errors.New("max size 10 mb")) return } - pd, err := h.dal.PenaDisk.GetByID(r.Context(), req.Id) + pd, err := h.dal.PenaDisk.GetByID(r.Context(), request.ID) if err != nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - fmt.Println("pdclient2", pd.UserID, req.Path, fileHeader.Filename) // Upload file to the storage - client := penadisk.NewClient(pd.UserID) + client := penadisk.NewClient(pd.PenaID) -//storagePath := fmt.Sprintf("%v/%v", req.Path, fileHeader.Filename) - - _, _, err = client.UploadResources(req.Path, fileHeader.Filename, req.Overwrite, fileData) + _, _, err = client.UploadResources(r.Context(), request.Path, fileHeader.Filename, false, fileData) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } @@ -215,32 +210,32 @@ type ReqPenaDiskDownloadLink struct { } func (h *Handlers) PenaDiskDownloadLink(w http.ResponseWriter, r *http.Request) { - var req ReqPenaDiskDownloadLink + var request ReqPenaDiskDownloadLink - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.Path == "" { - h.reportError(w, errors.New("path required"), http.StatusBadRequest) + if request.Path == "" { + h.reportError(w, http.StatusBadRequest, errors.New("path required")) } - client := penadisk.NewClient(amoData.AccountID) + client := penadisk.NewClient(amoData.PenaID) - href, err := client.GetPublicDownloadURL(req.Path) + href, err := client.GetPublicDownloadURL(r.Context(), request.Path) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, href) + h.sendResponse(w, http.StatusOK, href) } diff --git a/handlers/template.go b/handlers/template.go index 6fbc0a3..10f939a 100644 --- a/handlers/template.go +++ b/handlers/template.go @@ -3,13 +3,15 @@ package handlers import ( "errors" "net/http" - "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" "strconv" + + "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" + "penahub.gitlab.yandexcloud.net/backend/templategen/middleware" ) type ReqTemplateSet struct { - LeadId int64 `json:"lead_id"` // Required for insert/update - TemplateId string `json:"template_id"` // Required for update - может потом удалить ? + LeadID int64 `json:"lead_id"` // Required for insert/update + TemplateID string `json:"template_id"` // Required for update - может потом удалить ? Name string `json:"name"` File string `json:"file"` // Required. StorageID string `json:"storage_id"` // Required. id gdisk or yadisk @@ -20,84 +22,84 @@ type RespTemplateSet struct { ID string `json:"id"` } -// TemplateSet - устанавливает/обновляет шаблон для сделки +// TemplateSet - устанавливает/обновляет шаблон для сделки. func (h *Handlers) TemplateSet(w http.ResponseWriter, r *http.Request) { - var req ReqTemplateSet + var request ReqTemplateSet - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.StorageType == "" || req.StorageID == "" { - h.reportError(w, errors.New("storage_type required "), http.StatusBadRequest) + if request.StorageType == "" || request.StorageID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("storage_type required ")) return } - if req.StorageID == "" { - h.reportError(w, errors.New("storage_id required"), http.StatusBadRequest) + if request.StorageID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("storage_id required")) return } - if req.File == "" { - h.reportError(w, errors.New("file required"), http.StatusBadRequest) + if request.File == "" { + h.reportError(w, http.StatusBadRequest, errors.New("file required")) return } // Search/update template update := &model.Template{ - ID: req.TemplateId, - UserID: amoData.UserID, - LeadId: req.LeadId, - Name: req.Name, - File: req.File, - StorageID: req.StorageID, - StorageType: req.StorageType, + ID: request.TemplateID, + PenaID: amoData.PenaID, + LeadID: request.LeadID, + Name: request.Name, + File: request.File, + StorageID: request.StorageID, + StorageType: request.StorageType, IsDeleted: false, } - templateId := "" - if req.TemplateId == "" { - if req.LeadId > 0 { + templateID := "" + if request.TemplateID == "" { + if request.LeadID > 0 { err = h.dal.Template.UpdateByLeadID(r.Context(), update) } else { - templateId, err = h.dal.Template.Insert(r.Context(), update) + templateID, err = h.dal.Template.Insert(r.Context(), update) } } else { err = h.dal.Template.UpdateByID(r.Context(), update) } if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, RespTemplateSet{templateId}) + h.sendResponse(w, http.StatusOK, RespTemplateSet{templateID}) } func (h *Handlers) TemplateGetListByUser(w http.ResponseWriter, r *http.Request) { - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - result, err := h.dal.Template.GetListByUserID(r.Context(), amoData.UserID) + result, err := h.dal.Template.GetListByPenaID(r.Context(), amoData.PenaID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, result) + h.sendResponse(w, http.StatusOK, result) } type ReqTemplateGetListByGroup struct { @@ -105,96 +107,91 @@ type ReqTemplateGetListByGroup struct { } func (h *Handlers) TemplateGetListByGroup(w http.ResponseWriter, r *http.Request) { - var req ReqTemplateGetListByGroup + var request ReqTemplateGetListByGroup - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - //if req.GroupID == "" { - // h.reportError(w, errors.New("group_id required"), http.StatusBadRequest) - // return - //} - - resp, err := h.dal.Template.GetListByGroupID(r.Context(), req.GroupID, amoData.UserID) + resp, err := h.dal.Template.GetListByGroupID(r.Context(), request.GroupID, amoData.PenaID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, http.StatusOK, resp) + h.sendResponse(w, http.StatusOK, resp) } type ReqTemplateGet struct { - LeadId int64 `json:"lead_id"` - TemplateId string `json:"template_id"` + LeadID int64 `json:"lead_id"` + TemplateID string `json:"template_id"` } func (h *Handlers) TemplateGet(w http.ResponseWriter, r *http.Request) { - var req ReqTemplateGet + var request ReqTemplateGet - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.TemplateId == "" && strconv.FormatInt(req.LeadId, 10) == "" { - h.reportError(w, err, http.StatusBadRequest) + if request.TemplateID == "" && strconv.FormatInt(request.LeadID, 10) == "" { + h.reportError(w, http.StatusBadRequest, err) return } var template *model.Template - if req.TemplateId != "" { - template, err = h.dal.Template.GetByID(r.Context(), req.TemplateId) + if request.TemplateID != "" { + template, err = h.dal.Template.GetByID(r.Context(), request.TemplateID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } } - if req.LeadId > 0 { - template, err = h.dal.Template.GetByLeadId(r.Context(), req.LeadId) + if request.LeadID > 0 { + template, err = h.dal.Template.GetByLeadID(r.Context(), request.LeadID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } } if template == nil { - templateId, err := h.dal.Template.Insert(r.Context(), &model.Template{ - UserID: amoData.UserID, - LeadId: req.LeadId, + var templateID string + templateID, err = h.dal.Template.Insert(r.Context(), &model.Template{ + PenaID: amoData.PenaID, + LeadID: request.LeadID, }) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - template = &model.Template{ID: templateId} - + template = &model.Template{ID: templateID} } - sendResponse(w, 200, template) + h.sendResponse(w, http.StatusOK, template) } type ReqTemplateUpdate struct { @@ -204,41 +201,41 @@ type ReqTemplateUpdate struct { } func (h *Handlers) TemplateUpdate(w http.ResponseWriter, r *http.Request) { - var req ReqTemplateUpdate + var request ReqTemplateUpdate - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } record := &model.Template{ - ID: req.ID, - UserID: amoData.UserID, - Name: req.Name, - File: req.File, + ID: request.ID, + PenaID: amoData.PenaID, + Name: request.Name, + File: request.File, } err = h.dal.Template.UpdateByID(r.Context(), record) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, nil) + w.WriteHeader(http.StatusOK) } type ReqTemplateDelete struct { @@ -246,134 +243,36 @@ type ReqTemplateDelete struct { } func (h *Handlers) TemplateDelete(w http.ResponseWriter, r *http.Request) { - var req ReqTemplateDelete + var request ReqTemplateDelete - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } - err = h.dal.Template.DeleteByID(r.Context(), req.ID) + err = h.dal.Template.DeleteByID(r.Context(), request.ID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - - sendResponse(w, 200, nil) + w.WriteHeader(http.StatusOK) } type ReqTemplateInit struct { EventName string `json:"event_name"` Data map[string]interface{} `json:"data"` } - -func (h *Handlers) TemplateInit(w http.ResponseWriter, r *http.Request) { - //var req ReqTemplateInit - // - //user := getJwtUser(r) - // - //if user == nil { - // h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) - // return - //} - // - //err := decodePost(&resp, r) - // - //if err != nil { - // h.reportError(w, err, http.StatusBadRequest) - // return - //} - // - //// Ищем ивент - //t, err := h.dal.Template.GetByNameAndUserID(r.Context(), resp.EventName, amoData.UserID) - // - //if err != nil { - // h.reportError(w, err, http.StatusInternalServerError) - // return - //} - // - //if t == nil { - // h.reportError(w, errors.New("template not found"), http.StatusNotFound) - // return - //} - // - //YaDiskData, err := h.dal.YaDisk.GetListByUserID(r.Context(), amoData.UserID) - //if err != nil { - // h.reportError(w, err, http.StatusInternalServerError) - // return - //} - // - //if YaDiskData == nil { - // h.reportError(w, errors.New("YaDisk not found"), http.StatusNotFound) - // return - //} - // - //// download file - //token := &oauth2.Token{ - // AccessToken: YaDiskData.AccessToken, - // TokenType: YaDiskData.TokenType, - // RefreshToken: YaDiskData.RefreshToken, - // Expiry: YaDiskData.ExpiresIn, - //} - // - //if !token.Valid() { - // h.reportError(w, errors.New("invalid yandex token"), http.StatusForbidden) - // return - //} - // - //client := h.YaDisk.NewClient(token) - // - //res, err := client.GetResources(YaDiskData.TemplateFolder + "/" + t.Filename) - // - //if res == nil { - // h.reportError(w, errors.New("resource in yandex disk not found"), http.StatusNotFound) - // return - //} - //downloadFileName := fmt.Sprintf("./tmp/downloaded/%v_%v", t.UserID, t.Filename) - // - //err = templategen.DownloadDocument(downloadFileName, res.File) - //if err != nil { - // h.reportError(w, err, http.StatusInternalServerError) - // return - //} - // - //// parsing file - //dc, err := docTemp.GetTemplate(downloadFileName) - //if err != nil { - // h.reportError(w, err, http.StatusInternalServerError) - // return - //} - // - //dc.Parse() - // - //saveFilename := fmt.Sprintf("%v_%v_%v", t.UserID, time.Now().Unix(), t.Filename) - //err = dc.Execute("./tmp/parsed/"+saveFilename, resp.HistoryTriggerData) - //if err != nil { - // h.reportError(w, err, http.StatusInternalServerError) - // return - //} - // - //// Send to Yandex Disk - // - //err = client.UploadResourcesUrl(YaDiskData.SaveFolder+"/"+saveFilename, "https://solweb.site/tmp/parsed/"+saveFilename) - //if err != nil { - // h.reportError(w, err, http.StatusInternalServerError) - // return - //} - // - //fmt.Println("https://solweb.site/tmp/parsed/" + saveFilename) -} diff --git a/handlers/templateGroup.go b/handlers/templateGroup.go index 968de8e..4e9587d 100644 --- a/handlers/templateGroup.go +++ b/handlers/templateGroup.go @@ -2,9 +2,11 @@ package handlers import ( "errors" - "github.com/gorilla/mux" "net/http" + + "github.com/gorilla/mux" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" + "penahub.gitlab.yandexcloud.net/backend/templategen/middleware" ) type ReqTemplateGroupCreate struct { @@ -16,68 +18,73 @@ type RespTemplateGroupCreate struct { } func (h *Handlers) TemplateGroupCreate(w http.ResponseWriter, r *http.Request) { - var req ReqTemplateGroupCreate + var request ReqTemplateGroupCreate - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.Name == "" { - h.reportError(w, errors.New("name required"), http.StatusBadRequest) + if request.Name == "" { + h.reportError(w, http.StatusBadRequest, errors.New("name required")) return } groupID, err := h.dal.TemplateGroup.Insert(r.Context(), &model.TemplateGroup{ - UserID: amoData.AccountID, - Name: req.Name, + PenaID: amoData.PenaID, + Name: request.Name, }) - sendResponse(w, http.StatusOK, &RespTemplateGroupCreate{ID: groupID}) + if err != nil { + h.reportError(w, http.StatusInternalServerError, err) + return + } + + h.sendResponse(w, http.StatusOK, &RespTemplateGroupCreate{ID: groupID}) } func (h *Handlers) TemplateGroupGet(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] if id == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } resp, err := h.dal.TemplateGroup.GetByID(r.Context(), id) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, http.StatusOK, &resp) + h.sendResponse(w, http.StatusOK, &resp) } func (h *Handlers) TemplateGroupGetList(w http.ResponseWriter, r *http.Request) { - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - resp, err := h.dal.TemplateGroup.GetListByUserID(r.Context(), amoData.AccountID) + resp, err := h.dal.TemplateGroup.GetListByPenaID(r.Context(), amoData.PenaID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, http.StatusOK, &resp) + h.sendResponse(w, http.StatusOK, &resp) } type ReqTemplateGroupEdit struct { @@ -86,39 +93,39 @@ type ReqTemplateGroupEdit struct { } func (h *Handlers) TemplateGroupEdit(w http.ResponseWriter, r *http.Request) { - var req ReqTemplateGroupEdit + var request ReqTemplateGroupEdit - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } - if req.Name == "" { - h.reportError(w, errors.New("name required"), http.StatusBadRequest) + if request.Name == "" { + h.reportError(w, http.StatusBadRequest, errors.New("name required")) return } err = h.dal.TemplateGroup.Update(r.Context(), &model.TemplateGroup{ - ID: req.ID, - UserID: amoData.AccountID, - Name: req.Name, + ID: request.ID, + PenaID: amoData.PenaID, + Name: request.Name, }) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } @@ -130,38 +137,38 @@ type ReqTemplateGroupDelete struct { } func (h *Handlers) TemplateGroupDelete(w http.ResponseWriter, r *http.Request) { - var req ReqTemplateGroupDelete + var request ReqTemplateGroupDelete - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } //TODO: Крайне желательно переписать на транзакции! - err = h.dal.Template.DeleteGroupFromAll(r.Context(), req.ID) + err = h.dal.Template.DeleteGroupFromAll(r.Context(), request.ID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - err = h.dal.TemplateGroup.Delete(r.Context(), req.ID) + err = h.dal.TemplateGroup.Delete(r.Context(), request.ID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } @@ -174,35 +181,35 @@ type ReqTemplateGroupPut struct { } func (h *Handlers) TemplateGroupPut(w http.ResponseWriter, r *http.Request) { - var req ReqTemplateGroupPut + var request ReqTemplateGroupPut - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.TemplateID == "" { - h.reportError(w, errors.New("template_id required"), http.StatusBadRequest) + if request.TemplateID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("template_id required")) return } - if req.GroupID == "" { - h.reportError(w, errors.New("group_id required"), http.StatusBadRequest) + if request.GroupID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("group_id required")) return } - err = h.dal.Template.PushGroup(r.Context(), req.TemplateID, req.GroupID, amoData.AccountID) + err = h.dal.Template.PushGroup(r.Context(), request.TemplateID, request.GroupID, amoData.PenaID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } @@ -215,35 +222,35 @@ type ReqTemplateGroupRemove struct { } func (h *Handlers) TemplateGroupRemove(w http.ResponseWriter, r *http.Request) { - var req ReqTemplateGroupRemove + var request ReqTemplateGroupRemove - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.TemplateID == "" { - h.reportError(w, errors.New("template_id required"), http.StatusBadRequest) + if request.TemplateID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("template_id required")) return } - if req.GroupID == "" { - h.reportError(w, errors.New("group_id required"), http.StatusBadRequest) + if request.GroupID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("group_id required")) return } - err = h.dal.Template.PullGroup(r.Context(), req.TemplateID, req.GroupID, amoData.AccountID) + err = h.dal.Template.PullGroup(r.Context(), request.TemplateID, request.GroupID, amoData.PenaID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } diff --git a/handlers/yadisk.go b/handlers/yadisk.go index 0ea695b..e97a943 100644 --- a/handlers/yadisk.go +++ b/handlers/yadisk.go @@ -11,8 +11,9 @@ import ( "go.uber.org/zap" "golang.org/x/oauth2" "penahub.gitlab.yandexcloud.net/backend/templategen/dal/model" + "penahub.gitlab.yandexcloud.net/backend/templategen/middleware" "penahub.gitlab.yandexcloud.net/backend/templategen/tools" - YaDisk "penahub.gitlab.yandexcloud.net/backend/templategen/yadisk" + "penahub.gitlab.yandexcloud.net/backend/templategen/yadisk" ) type ReqYaDiskSaveToken struct { @@ -27,104 +28,105 @@ type ReqYaDiskSaveToken struct { } func (h *Handlers) YaDiskSaveToken(w http.ResponseWriter, r *http.Request) { - var req ReqYaDiskSaveToken + var request ReqYaDiskSaveToken + err := r.ParseForm() if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - err = schema.NewDecoder().Decode(&req, r.Form) + err = schema.NewDecoder().Decode(&request, r.Form) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.Error != "" { - err = errors.New("YaDiskErr:" + req.Error) - h.reportError(w, err, http.StatusBadRequest) + if request.Error != "" { + err = errors.New("YaDiskErr:" + request.Error) + h.reportError(w, http.StatusBadRequest, err) return } - if req.AccessToken == "" && req.Code == "" { + if request.AccessToken == "" && request.Code == "" { err = errors.New("got empty token") - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.State == "" { + if request.State == "" { err = errors.New("got empty state") - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } var state tools.StateToken - err = tools.DecryptTokenRC4(req.State, &state) + err = tools.DecryptTokenAES(request.State, &state) if err != nil { - h.reportError(w, err, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, err) return } token := &oauth2.Token{ - AccessToken: req.AccessToken, - TokenType: req.TokenType, - RefreshToken: req.RefreshToken, - Expiry: time.Now().Add(time.Duration(req.ExpiresIn) * time.Second), + AccessToken: request.AccessToken, + TokenType: request.TokenType, + RefreshToken: request.RefreshToken, + Expiry: time.Now().Add(time.Duration(request.ExpiresIn) * time.Second), } - yaDiskClient, err := h.YaDisk.NewClient(r.Context(), token, req.Code) + yaDiskClient, err := h.YaDisk.NewClient(r.Context(), token, request.Code) if err != nil { - h.reportError(w, err, http.StatusForbidden) + h.reportError(w, http.StatusForbidden, err) return } token = yaDiskClient.Token - yaUser, err := yaDiskClient.GetUser() + yaUser, err := yaDiskClient.GetUser(r.Context()) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } // Insert/Update token in DB _, err = h.dal.YaDisk.InsertOrUpdate(r.Context(), &model.YaDisk{ - UserID: state.UserID, + PenaID: state.PenaID, Name: fmt.Sprintf("Yandex Disk (%v)", yaUser.Login), - UID: yaUser.Uid, + UID: yaUser.UID, Login: yaUser.Login, DisplayName: yaUser.DisplayName, AccessToken: token.AccessToken, RefreshToken: token.RefreshToken, ExpiresIn: token.Expiry, TokenType: token.TokenType, - TemplateFolder: YaDisk.DEFAULT_TEMPLATE_FOLDER, - SaveFolder: YaDisk.DEFAULT_SAVE_FOLDER, + TemplateFolder: yadisk.DefaultTemplateFolder, + SaveFolder: yadisk.DefaultSaveFolder, }) if err != nil { - h.reportError(w, err, 500) + h.reportError(w, 500, err) return } // Make default directories in YandexDisk - _, err = yaDiskClient.PutResources(YaDisk.DEFAULT_FOLDER) + _, err = yaDiskClient.PutResources(yadisk.DefaultFolder) if err != nil { h.logger.Error("ErrorHandler", zap.Error(err)) } - _, err = yaDiskClient.PutResources(YaDisk.DEFAULT_TEMPLATE_FOLDER) + _, err = yaDiskClient.PutResources(yadisk.DefaultTemplateFolder) if err != nil { h.logger.Error("ErrorHandler", zap.Error(err)) } - _, err = yaDiskClient.PutResources(YaDisk.DEFAULT_SAVE_FOLDER) + _, err = yaDiskClient.PutResources(yadisk.DefaultSaveFolder) if err != nil { h.logger.Error("ErrorHandler", zap.Error(err)) } - http.Redirect(w, r, state.RedirectUrl, http.StatusPermanentRedirect) + http.Redirect(w, r, state.RedirectURL, http.StatusPermanentRedirect) } type ReqYaDiskSetSettings struct { @@ -135,55 +137,55 @@ type ReqYaDiskSetSettings struct { } func (h *Handlers) YaDiskSetSettings(w http.ResponseWriter, r *http.Request) { - var req ReqYaDiskSetSettings + var request ReqYaDiskSetSettings - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } err = h.dal.YaDisk.Update(r.Context(), &model.YaDisk{ - ID: req.ID, - Name: req.Name, - TemplateFolder: req.TemplateFolder, - SaveFolder: req.SaveFolder}) + ID: request.ID, + Name: request.Name, + TemplateFolder: request.TemplateFolder, + SaveFolder: request.SaveFolder}) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, nil) + w.WriteHeader(http.StatusOK) } -// YaDiskGetList - возвращает список хранилищ Yandex закрепленных за пользователем по его UserID из JWT +// YaDiskGetList - возвращает список хранилищ Yandex закрепленных за пользователем по его UserID из JWT. func (h *Handlers) YaDiskGetList(w http.ResponseWriter, r *http.Request) { - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - yadiskInfo, err := h.dal.YaDisk.GetListByUserID(r.Context(), amoData.UserID) + yadiskInfo, err := h.dal.YaDisk.GetListByPenaID(r.Context(), amoData.PenaID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, http.StatusOK, yadiskInfo) + h.sendResponse(w, http.StatusOK, yadiskInfo) } type ReqYaDiskGetResources struct { @@ -194,45 +196,45 @@ type ReqYaDiskGetResources struct { } func (h *Handlers) YaDiskGetResources(w http.ResponseWriter, r *http.Request) { - var req ReqYaDiskGetResources + var request ReqYaDiskGetResources - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } - yadisk, err := h.dal.YaDisk.GetByID(r.Context(), req.ID) + yadisk, err := h.dal.YaDisk.GetByID(r.Context(), request.ID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } client, err := h.YaDisk.NewClient(r.Context(), yadisk.Token(), "") if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - resource, err := client.GetResources(req.Path, req.Limit, req.Offset) + resource, err := client.GetResources(r.Context(), request.Path, request.Limit, request.Offset) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, resource) + h.sendResponse(w, http.StatusOK, resource) } type ReqYaDiskPutResources struct { @@ -241,45 +243,45 @@ type ReqYaDiskPutResources struct { } func (h *Handlers) YaDiskPutResources(w http.ResponseWriter, r *http.Request) { - var req ReqYaDiskPutResources + var request ReqYaDiskPutResources - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } - yadisk, err := h.dal.YaDisk.GetByID(r.Context(), req.ID) + yadisk, err := h.dal.YaDisk.GetByID(r.Context(), request.ID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } client, err := h.YaDisk.NewClient(r.Context(), yadisk.Token(), "") if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - res, err := client.PutResources(req.Path) + res, err := client.PutResources(request.Path) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, http.StatusOK, res) + h.sendResponse(w, http.StatusOK, res) } type ReqYaDiskDownload struct { @@ -288,66 +290,73 @@ type ReqYaDiskDownload struct { } func (h *Handlers) YaDiskDownloadLink(w http.ResponseWriter, r *http.Request) { - - var req ReqYaDiskDownload - amoData := getAmoByJwt(r) + var request ReqYaDiskDownload + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } - yadisk, err := h.dal.YaDisk.GetByID(r.Context(), req.ID) + yadisk, err := h.dal.YaDisk.GetByID(r.Context(), request.ID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } if yadisk == nil { - h.reportError(w, errors.New("yandex disk not found"), http.StatusUnprocessableEntity) + h.reportError(w, http.StatusUnprocessableEntity, errors.New("yandex disk not found")) return } client, err := h.YaDisk.NewClient(r.Context(), yadisk.Token(), "") if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - url, err := client.DownloadFile(req.Path) + url, err := client.DownloadFile(request.Path) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - sendResponse(w, 200, url) + + h.sendResponse(w, http.StatusOK, url) } func (h *Handlers) YaDiskDownload(w http.ResponseWriter, r *http.Request) { - - var req ReqYaDiskDownload - err := decodePost(&req, r) + var request ReqYaDiskDownload + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - resp, err := http.Get(req.Path) + reqGet, err := http.NewRequestWithContext(r.Context(), http.MethodGet, request.Path, http.NoBody) if err != nil { - sendResponse(w, http.StatusBadRequest, err.Error()) + h.reportError(w, http.StatusBadRequest, err) + return } + resp, err := http.DefaultClient.Do(reqGet) + if err != nil { + h.reportError(w, http.StatusInternalServerError, err) + return + } + defer resp.Body.Close() + if _, err := io.Copy(w, resp.Body); err != nil { - sendResponse(w, http.StatusBadRequest, err.Error()) + h.reportError(w, http.StatusBadRequest, err) } } @@ -359,48 +368,53 @@ type ReqYaDiskUploadResources struct { func (h *Handlers) YaDiskUploadResources(w http.ResponseWriter, r *http.Request) { // Check form fileData, fileHeader, err := r.FormFile("file") + if err != nil { + h.reportError(w, http.StatusBadRequest, err) + return + } defer fileData.Close() - var req ReqYaDiskUploadResources - err = schema.NewDecoder().Decode(&req, r.Form) + var request ReqYaDiskUploadResources + + err = schema.NewDecoder().Decode(&request, r.Form) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } - if req.Path == "" { - req.Path = "disk:" + if request.Path == "" { + request.Path = "disk:" } var maxSize int64 = 10 << 20 // mb if fileHeader.Size > maxSize { - h.reportError(w, errors.New("max size 10 mb"), http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, errors.New("max size 10 mb")) return } // Upload file to the storage - storage, err := h.dal.YaDisk.GetByID(r.Context(), req.ID) + storage, err := h.dal.YaDisk.GetByID(r.Context(), request.ID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } client, err := h.YaDisk.NewClient(r.Context(), storage.Token(), "") if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - storagePath := fmt.Sprintf("%v/%v", req.Path, fileHeader.Filename) + storagePath := fmt.Sprintf("%v/%v", request.Path, fileHeader.Filename) - _, _, err = client.UploadResources(storagePath, fileData) + _, _, err = client.UploadResources(r.Context(), storagePath, fileData) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } @@ -413,41 +427,41 @@ type ReqYaDiskDeleteResources struct { } func (h *Handlers) YaDiskDeleteResources(w http.ResponseWriter, r *http.Request) { - var req ReqYaDiskPutResources + var request ReqYaDiskPutResources - amoData := getAmoByJwt(r) + amoData := middleware.GetAmoData(r) if amoData == nil { - h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized) + h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized) return } - err := decodePost(&req, r) + err := decodePost(&request, r) if err != nil { - h.reportError(w, err, http.StatusBadRequest) + h.reportError(w, http.StatusBadRequest, err) return } - if req.ID == "" { - h.reportError(w, errors.New("id required"), http.StatusBadRequest) + if request.ID == "" { + h.reportError(w, http.StatusBadRequest, errors.New("id required")) return } - yadisk, err := h.dal.YaDisk.GetByID(r.Context(), req.ID) + yadisk, err := h.dal.YaDisk.GetByID(r.Context(), request.ID) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } client, err := h.YaDisk.NewClient(r.Context(), yadisk.Token(), "") if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } - err = client.DeleteResources(req.Path) + err = client.DeleteResources(r.Context(), request.Path) if err != nil { - h.reportError(w, err, http.StatusInternalServerError) + h.reportError(w, http.StatusInternalServerError, err) return } diff --git a/main.go b/main.go index 448c437..8150231 100644 --- a/main.go +++ b/main.go @@ -3,41 +3,54 @@ package main import ( "context" "fmt" - "log" "net/http" "os" "os/signal" "syscall" + "time" "github.com/gorilla/mux" + "github.com/twmb/franz-go/pkg/kgo" "go.uber.org/zap" "go.uber.org/zap/zapcore" "penahub.gitlab.yandexcloud.net/backend/templategen/amo" + "penahub.gitlab.yandexcloud.net/backend/templategen/broker/tariff" "penahub.gitlab.yandexcloud.net/backend/templategen/dal" - GDisk "penahub.gitlab.yandexcloud.net/backend/templategen/gdisk" + "penahub.gitlab.yandexcloud.net/backend/templategen/gdisk" "penahub.gitlab.yandexcloud.net/backend/templategen/handlers" "penahub.gitlab.yandexcloud.net/backend/templategen/middleware" "penahub.gitlab.yandexcloud.net/backend/templategen/privileges" - YaDisk "penahub.gitlab.yandexcloud.net/backend/templategen/yadisk" + "penahub.gitlab.yandexcloud.net/backend/templategen/tools" + "penahub.gitlab.yandexcloud.net/backend/templategen/worker" + "penahub.gitlab.yandexcloud.net/backend/templategen/yadisk" ) type Env struct { - Domain string `env:"DOMAIN" default:"tempgen.pena.digital"` - LogFile string `env:"LOG_FILE" default:"./tmp/logs.log"` - MongoUrl string `env:"MONGO_URL" default:"mongodb://mongo:30000/?replicaSet=penahub-rs"` - DbName string `env:"DB_NAME" default:"templategen"` - YaDiskClientID string `env:"YADISK_CLIENT_ID" default:"94482c181e5148c096ae6ad3b2a981ea"` - YaDiskClientSecret string `env:"YADISK_CLIENT_SECRET" default:"7dc4f541c3f64f4a9078e59d7494d222"` - GDiskCredentials string `env:"GDISK_CREDENTIALS" default:"./static/gdisk-credentials.json"` - AmoClientID string `env:"AMO_CLIENT_ID" default:"6c7f3fdb-cce7-4fb0-a8a3-640b695c8d00"` - AmoClientSecret string `env:"AMO_CLIENT_SECRET" default:"5oJU1L8pScLKfEasShJ6KuDU32VrIs6BVKQ6BiY4vABIQycUWJziULytiUs5jaZU"` - AmoRedirectUrn string `env:"AMO_REDIRECT_URN" default:"/settings/widgets/penagen/"` + Domain string `env:"DOMAIN" default:"tempgen.pena.digital"` + LogFile string `env:"LOG_FILE" default:"./tmp/logs.log"` + MongoURL string `env:"MONGO_URL" default:"mongodb://mongo:30000/?replicaSet=penahub-rs"` + DBName string `env:"DB_NAME" default:"templategen"` + YaDiskClientID string `env:"YADISK_CLIENT_ID" default:"94482c181e5148c096ae6ad3b2a981ea"` + YaDiskClientSecret string `env:"YADISK_CLIENT_SECRET" default:"7dc4f541c3f64f4a9078e59d7494d222"` + GDiskCredentials string `env:"GDISK_CREDENTIALS" default:"./static/gdisk-credentials.json"` + AmoClientID string `env:"AMO_CLIENT_ID" default:"6c7f3fdb-cce7-4fb0-a8a3-640b695c8d00"` + AmoClientSecret string `env:"AMO_CLIENT_SECRET" default:"5oJU1L8pScLKfEasShJ6KuDU32VrIs6BVKQ6BiY4vABIQycUWJziULytiUs5jaZU"` + AmoRedirectUrn string `env:"AMO_REDIRECT_URN" default:"/settings/widgets/penagen/"` + TokenKey string `env:"TOKEN_KEY" default:"z1eRU{fq*VtfLAszrz"` + KafkaTariff string `env:"KAFKA_TARIFF"` + KafkaBrokers []string `env:"KAFKA_BROKERS"` + KafkaTariffTopic string `env:"KAFKA_TARIFF_TOPIC"` + KafkaConsumerGroupID string `env:"KAFKA_CONSUMER_GROUP_ID"` + PrivilegesDomain string `env:"PRIVILEGES_DOMAIN"` } func main() { opts := GetOpts() ctx, cancel := context.WithCancel(context.Background()) + // Set tools/token + tools.SetToken(opts.TokenKey) + // Logger cfgLogger := zap.NewDevelopmentConfig() cfgLogger.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder @@ -51,20 +64,23 @@ func main() { panic(err) } - if err := privileges.PublishPrivileges(ctx, "https://admin.pena.digital/strator"); err != nil { - logger.Error("ErrorPublishPrivileges", zap.Error(err)) - } + err = privileges.PublishPrivileges(ctx, "https://admin.pena.digital/strator") + + if err != nil { + logger.Error("ErrorPublishPrivileges", zap.Error(err)) + } // Start Data Access Layer - mongoDal, err := dal.InitMongoDAL(ctx, opts.MongoUrl, opts.DbName, logger) + mongoDal, err := dal.InitMongoDAL(ctx, opts.MongoURL, opts.DBName, logger) defer mongoDal.Disconnect() if err != nil { - logger.Fatal("ErrorConnectToDAL", zap.Error(err)) + logger.Error("ErrorConnectToDAL", zap.Error(err)) + return } // Yandex Disk - yaDisk := YaDisk.NewClientApp( + yaDisk := yadisk.NewClientApp( opts.YaDiskClientID, opts.YaDiskClientSecret, fmt.Sprintf("https://%v/yadisk", opts.Domain), @@ -72,16 +88,49 @@ func main() { ) // Google Drive - gDisk, err := GDisk.NewClientApp(opts.GDiskCredentials) + gDisk, err := gdisk.NewClientApp(opts.GDiskCredentials) if err != nil { - log.Fatal("ErrorCreateGoogleDriveClientApp:", err) + logger.Error("ErrorCreateGoogleDriveClientApp", zap.Error(err)) + return } // Amo amoApp := amo.NewClientApp( opts.AmoClientID, opts.AmoClientSecret, - fmt.Sprintf("https://%v/amo", opts.Domain)) + fmt.Sprintf("https://%v/amo", opts.Domain), + ) + + // Tariff + kafkaTariffClient, err := kgo.NewClient( + kgo.SeedBrokers(opts.KafkaBrokers...), + kgo.ConsumerGroup(opts.KafkaConsumerGroupID), + kgo.ConsumeResetOffset(kgo.NewOffset().AtStart()), + kgo.DefaultProduceTopic(opts.KafkaTariffTopic), + kgo.ConsumeTopics(opts.KafkaTariffTopic), + ) + if err != nil { + logger.Error("ErrorCreateKafkaTariffClient", zap.Error(err)) + return + } + + tariffConsumerDeps := tariff.ConsumerDeps{ + Logger: logger, + Client: kafkaTariffClient, + } + tariffConsumer := tariff.NewConsumer(tariffConsumerDeps) + + // Tariff worker + tariffWorkerDeps := worker.TariffWorkerDeps{ + Logger: logger, + Dal: mongoDal, + TariffConsumer: tariffConsumer, + PrivilegesDomain: opts.PrivilegesDomain, + } + + tariffWorker := worker.NewTariffWorker(tariffWorkerDeps) + + go tariffWorker.Run(ctx) // Handlers h := handlers.NewHandlers(mongoDal, yaDisk, gDisk, amoApp, logger, &handlers.HandlerVars{ @@ -90,10 +139,9 @@ func main() { }) r := mux.NewRouter() - // Add Assets - //fs := http.FileServer(http.Dir("assets")) - //r.PathPrefix("/assets/").Handler(http.StripPrefix("/assets/", fs)) + // Add Assets + r.PathPrefix("/tmp/generated/").Handler(http.StripPrefix("/tmp/generated/", http.FileServer(http.Dir("tmp/generated")))) @@ -154,7 +202,6 @@ func main() { r.HandleFunc("/template/getListByGroup", h.TemplateGetListByGroup) r.HandleFunc("/template/update", h.TemplateUpdate) r.HandleFunc("/template/delete", h.TemplateDelete) - r.HandleFunc("/template/init", h.TemplateInit) // устарело r.HandleFunc("/group/create", h.TemplateGroupCreate) r.HandleFunc("/group/getList", h.TemplateGroupGetList) @@ -171,8 +218,6 @@ func main() { r.HandleFunc("/generator/byamowebhook", h.GeneratorByAmoWebhook) r.HandleFunc("/history/get", h.GetHistoryByID) - //r.HandleFunc("/history/getListByFilter", h.GetHistoryListByFilter) - //r.HandleFunc("/history/getlistbyfilter", h.GetHistoryListByFilter) r.HandleFunc("/history/getList", h.GetHistoryList) r.HandleFunc("/history/getlist", h.GetHistoryList) @@ -185,21 +230,23 @@ func main() { mw.MiddlewareHeaders, mw.MiddlewareCors, mw.MiddlewareAmoJwt, - //mw.MiddlewareJwt, - //mw.MiddlewareAmoPlug, + mw.MiddlewareJwt, + // mw.MiddlewareAmoPlug, mw.Logger, ) r.NotFoundHandler = r.NewRoute().HandlerFunc(h.PageNotFound).GetHandler() srv := http.Server{ - Handler: r, + Handler: r, + ReadHeaderTimeout: time.Second * 3, // TODO: Обсудить со Skeris } go func() { err := srv.ListenAndServe() if err != nil { - logger.Fatal("CanNotServe", zap.Error(err)) + logger.Error("CanNotServe", zap.Error(err)) + return } }() @@ -211,7 +258,8 @@ func main() { go func() { err := srv.ListenAndServeTLS(fullCert, privCert) if err != nil { - logger.Fatal("CanNotServe", zap.Error(err)) + logger.Error("CanNotServe", zap.Error(err)) + return } }() @@ -221,9 +269,11 @@ func main() { killSignal := <-interrupt switch killSignal { case os.Interrupt: - logger.Fatal("AppInterrupted") + logger.Error("AppInterrupted") + return case syscall.SIGTERM: - logger.Fatal("AppTerminated") + logger.Error("AppTerminated") + return } defer cancel() diff --git a/middleware/middleware.go b/middleware/middleware.go index 7d4647d..1b26999 100644 --- a/middleware/middleware.go +++ b/middleware/middleware.go @@ -22,6 +22,15 @@ type Middleware struct { AmoAccessMap map[string]string // key - endpoint; value - access (visibility, creation, delete) } +type contextKey uint + +const ( + PenaUserIDContextKey contextKey = 1 // UserID from Pena JWT + AmoDataContextKey contextKey = 2 // AmoData + AmoIsAdminContextKey contextKey = 3 // Is Admin? + AmoUserIDContextKey contextKey = 4 // ID of user making the request from AMO CRM +) + func InitMiddleware(dal *dal.MongoDAL, amo *amo.ClientApp, logger *zap.Logger, amoAccessMap map[string]string) *Middleware { return &Middleware{dal: dal, amo: amo, logger: logger, AmoAccessMap: amoAccessMap} @@ -29,7 +38,7 @@ func InitMiddleware(dal *dal.MongoDAL, amo *amo.ClientApp, logger *zap.Logger, func (mw *Middleware) MiddlewareCors(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Method == "OPTIONS" { + if r.Method == http.MethodOptions { w.WriteHeader(http.StatusOK) } else { next.ServeHTTP(w, r) @@ -43,16 +52,17 @@ func (mw *Middleware) Logger(next http.Handler) http.Handler { next.ServeHTTP(w, r) return } - userId := getJwtUser(r) - amoData := getAmoByJwt(r) + var penaID string + + amoData := GetAmoData(r) if amoData != nil { - userId = amoData.UserID + penaID = amoData.PenaID } mw.logger.Info("HttpRequest", zap.String("URL", r.URL.String()), - zap.String("UserID", userId), + zap.String("PenaID", penaID), ) next.ServeHTTP(w, r) }) @@ -66,18 +76,36 @@ func (mw *Middleware) MiddlewareJwt(next http.Handler) http.Handler { } ctx := r.Context() - if amoData := getAmoByJwt(r); amoData != nil { - ctx = context.WithValue(ctx, "UserID", amoData.UserID) + + // Если уже прошла авторизация через сервис AMO, то пропускаем дальнейшие действия + amoData := GetAmoData(r) + if amoData != nil { + ctx = context.WithValue(ctx, PenaUserIDContextKey, amoData.PenaID) + next.ServeHTTP(w, r.WithContext(ctx)) + return } - // Check token in cookies - c := r.Header.Get(jwt_adapter.DefaultHeaderKey) + // Check token in headers + headerValue := r.Header.Get(jwt_adapter.DefaultHeaderKey) - jwt, err := jwt_adapter.Decode(c) - if err == nil { - ctx = context.WithValue(ctx, "PenaUserID", jwt.GetUserID()) + jwt, err := jwt_adapter.Decode(headerValue) + + if err != nil { + mw.reportError(w, http.StatusUnauthorized, err) } + ctx = context.WithValue(ctx, PenaUserIDContextKey, jwt.GetUserID()) + + // Add AMO data to context + amoData, err = mw.dal.Amo.GetByPenaID(ctx, jwt.GetUserID()) + + if err != nil { + mw.reportError(w, http.StatusInternalServerError, err) + return + } + + ctx = context.WithValue(ctx, AmoDataContextKey, amoData) + next.ServeHTTP(w, r.WithContext(ctx)) }) } @@ -89,7 +117,6 @@ func (mw *Middleware) MiddlewareHeaders(next http.Handler) http.Handler { w.Header().Set("Access-Control-Allow-Credentials", "true") w.Header().Set("Access-Control-Expose-Headers", "*") w.Header().Set("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE") - //w.Header().Add() next.ServeHTTP(w, r) }) } @@ -102,7 +129,7 @@ func (mw *Middleware) MiddlewareAmoJwt(next http.Handler) http.Handler { } authMap := map[string]interface{}{ - //"/amo": nil, + // "/amo": nil, } required := false @@ -114,22 +141,21 @@ func (mw *Middleware) MiddlewareAmoJwt(next http.Handler) http.Handler { token, err := mw.amo.DecodeJwt(r) if err != nil { if required { - mw.reportError(w, err, http.StatusUnauthorized) + mw.reportError(w, http.StatusUnauthorized, err) } else { - // mw.logger.Error("ErrAmoJwtAccess", zap.Error(err)) next.ServeHTTP(w, r) } return } - data, err := mw.dal.Amo.GetByAccountID(r.Context(), strconv.FormatInt(token.AccountId, 10)) + data, err := mw.dal.Amo.GetByAccountID(r.Context(), strconv.FormatInt(token.AccountID, 10)) if err != nil { - mw.reportError(w, err, http.StatusInternalServerError) + mw.reportError(w, http.StatusInternalServerError, err) return } if data == nil && !strings.Contains(r.URL.String(), "/amo/state") { - mw.reportError(w, errors.New("amo account not found"), http.StatusUnauthorized) + mw.reportError(w, http.StatusUnauthorized, errors.New("amo account not found")) return } @@ -141,8 +167,8 @@ func (mw *Middleware) MiddlewareAmoJwt(next http.Handler) http.Handler { if ok { // Если не админ, то проверяем права пользователя if rule == "visibility" && !isAcessGranted { - for _, userId := range data.AccessRules.Visibility { - if userId == token.UserId { + for _, userID := range data.AccessRules.Visibility { + if userID == token.UserID { isAcessGranted = true break } @@ -150,8 +176,8 @@ func (mw *Middleware) MiddlewareAmoJwt(next http.Handler) http.Handler { } if rule == "creation" && !isAcessGranted { - for _, userId := range data.AccessRules.Creation { - if userId == token.UserId { + for _, userID := range data.AccessRules.Creation { + if userID == token.UserID { isAcessGranted = true break } @@ -159,8 +185,8 @@ func (mw *Middleware) MiddlewareAmoJwt(next http.Handler) http.Handler { } if rule == "delete" && !isAcessGranted { - for _, userId := range data.AccessRules.Delete { - if userId == token.UserId { + for _, userID := range data.AccessRules.Delete { + if userID == token.UserID { isAcessGranted = true break } @@ -172,13 +198,13 @@ func (mw *Middleware) MiddlewareAmoJwt(next http.Handler) http.Handler { // Если прав нет, прерываемся if !isAcessGranted { - mw.reportError(w, errors.New("amoUser forbidden"), http.StatusForbidden) // mb: http.StatusForbidden + mw.reportError(w, http.StatusForbidden, errors.New("amoUser forbidden")) // mb: http.StatusForbidden return } - ctx := context.WithValue(r.Context(), "amoData", data) - ctx = context.WithValue(ctx, "amoIsAdmin", token.IsAdmin) - ctx = context.WithValue(ctx, "amoUserID", token.UserId) + ctx := context.WithValue(r.Context(), AmoDataContextKey, data) + ctx = context.WithValue(ctx, AmoIsAdminContextKey, token.IsAdmin) + ctx = context.WithValue(ctx, AmoUserIDContextKey, token.UserID) next.ServeHTTP(w, r.WithContext(ctx)) }) } @@ -196,24 +222,24 @@ func (mw *Middleware) MiddlewareAmoPlug(next http.Handler) http.Handler { data, err := mw.dal.Amo.GetByAccountID(r.Context(), "30228997") if err != nil { - mw.reportError(w, err, http.StatusInternalServerError) + mw.reportError(w, http.StatusInternalServerError, err) return } if data == nil { - mw.reportError(w, errors.New("amo account not found"), http.StatusUnauthorized) + mw.reportError(w, http.StatusUnauthorized, errors.New("amo account not found")) return } - ctx = context.WithValue(ctx, "amoData", data) + ctx = context.WithValue(ctx, AmoDataContextKey, data) } next.ServeHTTP(w, r.WithContext(ctx)) }) } -func getJwtUser(r *http.Request) string { - user, ok := r.Context().Value("UserID").(string) +func GetPenaUserID(r *http.Request) string { + user, ok := r.Context().Value(PenaUserIDContextKey).(string) if ok { return user } @@ -221,8 +247,8 @@ func getJwtUser(r *http.Request) string { return "" } -func getAmoByJwt(r *http.Request) *model.Amo { - amoData, ok := r.Context().Value("amoData").(*model.Amo) +func GetAmoData(r *http.Request) *model.Amo { + amoData, ok := r.Context().Value(AmoDataContextKey).(*model.Amo) if ok { return amoData } @@ -230,9 +256,24 @@ func getAmoByJwt(r *http.Request) *model.Amo { return nil } -func (mw *Middleware) reportError(w http.ResponseWriter, err error, status int) error { +func GetAmoUserID(r *http.Request) int64 { + result, ok := r.Context().Value(AmoUserIDContextKey).(int64) + + if ok { + return result + } + + return 0 +} + +func (mw *Middleware) reportError(w http.ResponseWriter, status int, err error) { mw.logger.Error("ErrorMiddleware", zap.Error(err)) w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(status) - return json.NewEncoder(w).Encode(err) + e := json.NewEncoder(w) + e.SetEscapeHTML(false) + errJSON := e.Encode(err) + if errJSON != nil { + mw.logger.Error("ErrorMiddleware - JSON ENCODE", zap.Error(errJSON)) + } } diff --git a/openapi.yaml b/openapi.yaml index 18cc30a..f1ac1e7 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -210,8 +210,8 @@ components: properties: id: $ref: "#/components/defaultSchemas/id" - user_id: - $ref: "#/components/defaultSchemas/user_id" + pena_id: + $ref: "#/components/defaultSchemas/pena_id" account_id: type: string description: "Идентификатор аккаунта в AMO CRM" @@ -266,8 +266,8 @@ components: properties: id: $ref: "#/components/defaultSchemas/id" - user_id: - $ref: "#/components/defaultSchemas/user_id" + pena_id: + $ref: "#/components/defaultSchemas/pena_id" email: type: string description: "E-mail профиля Google" @@ -321,8 +321,8 @@ components: properties: id: $ref: "#/components/defaultSchemas/id" - user_id: - $ref: "#/components/defaultSchemas/user_id" + pena_id: + $ref: "#/components/defaultSchemas/pena_id" uid: type: string description: "Yandex UID" @@ -359,8 +359,8 @@ components: properties: id: $ref: "#/components/defaultSchemas/id" - user_id: - $ref: "#/components/defaultSchemas/user_id" + pena_id: + $ref: "#/components/defaultSchemas/pena_id" lead_id: type: string description: "Идентификатор сделки в AMO CRM" @@ -399,8 +399,8 @@ components: properties: id: $ref: "#/components/defaultSchemas/id" - user_id: - $ref: "#/components/defaultSchemas/user_id" + pena_id: + $ref: "#/components/defaultSchemas/pena_id" name: type: string description: "Название группы" @@ -561,7 +561,7 @@ components: description: "Уникальный идентификатор" example: "635520d143ebb05286f4fba6" required: true - user_id: + pena_id: type: string description: "Уникальный идентификатор пользователя" example: "62ac67a1471fd0f7892353bf" diff --git a/penadisk/api.go b/penadisk/api.go index 21905c9..bc2daac 100644 --- a/penadisk/api.go +++ b/penadisk/api.go @@ -2,35 +2,38 @@ package penadisk import ( "bytes" + "context" "encoding/json" - "github.com/minio/minio-go/v7" + "fmt" "io" "mime/multipart" "net/http" "net/url" "os" - "fmt" "strconv" "strings" + + "github.com/minio/minio-go/v7" ) const ( - DEFAULT_FOLDER = "templategen" - DEFAULT_TEMPLATE_FOLDER = DEFAULT_FOLDER + "/templates" - DEFAULT_SAVE_FOLDER = DEFAULT_FOLDER + "/saved" + DefaultFolder = "templategen" + DefaultTemplateFolder = DefaultFolder + "/templates" + DefaultSaveFolder = DefaultFolder + "/saved" ) var ( - URL = "" - V1_DISK_API = URL + "/api/v1/" + URL = "" + V1DiskAPI = URL + "/api/v1/" ) func init() { URL = os.Getenv("PENADISK_URL") - V1_DISK_API = URL + "api/v1/" + V1DiskAPI = URL + "api/v1/" } type Client struct { + /* ID пользователя пены */ userID string } @@ -38,8 +41,8 @@ func NewClient(userID string) *Client { return &Client{userID: userID} } -func (c *Client) GetDisk() (*BucketWithStats, error) { - req, err := http.NewRequest("GET", V1_DISK_API+"bucket", nil) +func (c *Client) GetDisk(ctx context.Context) (*BucketWithStats, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, V1DiskAPI+"bucket", http.NoBody) if err != nil { return nil, err } @@ -61,11 +64,11 @@ func (c *Client) GetDisk() (*BucketWithStats, error) { return &r, err } -func (c *Client) SetBucketQuota(size uint64) error { +func (c *Client) SetBucketQuota(ctx context.Context, size uint64) error { data := url.Values{} data.Set("size", strconv.FormatUint(size, 10)) - req, err := http.NewRequest("PUT", V1_DISK_API+"bucket/quota/set?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"bucket/quota/set?"+data.Encode(), http.NoBody) if err != nil { return err } @@ -80,8 +83,8 @@ func (c *Client) SetBucketQuota(size uint64) error { return checkError(resp) } -func (c *Client) UnsetBucketQuota() error { - req, err := http.NewRequest("PUT", V1_DISK_API+"bucket/quota/unset", nil) +func (c *Client) UnsetBucketQuota(ctx context.Context) error { + req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"bucket/quota/unset", http.NoBody) if err != nil { return err } @@ -96,8 +99,8 @@ func (c *Client) UnsetBucketQuota() error { return checkError(resp) } -func (c *Client) EnableBucketVersioning() error { - req, err := http.NewRequest("PUT", V1_DISK_API+"bucket/versioning/enable", nil) +func (c *Client) EnableBucketVersioning(ctx context.Context) error { + req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"bucket/versioning/enable", http.NoBody) if err != nil { return err } @@ -112,8 +115,8 @@ func (c *Client) EnableBucketVersioning() error { return checkError(resp) } -func (c *Client) SuspendBucketVersioning() error { - req, err := http.NewRequest("PUT", V1_DISK_API+"bucket/versioning/suspend", nil) +func (c *Client) SuspendBucketVersioning(ctx context.Context) error { + req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"bucket/versioning/suspend", http.NoBody) if err != nil { return err } @@ -128,8 +131,8 @@ func (c *Client) SuspendBucketVersioning() error { return checkError(resp) } -// GetResources - получить информацию о ресурсах -func (c *Client) GetResources(path string, recursive, withVersion bool) ([]minio.ObjectInfo, error) { +// GetResources - получить информацию о ресурсах. +func (c *Client) GetResources(ctx context.Context, path string, recursive, withVersion bool) ([]minio.ObjectInfo, error) { data := url.Values{} data.Set("path", path) @@ -141,7 +144,7 @@ func (c *Client) GetResources(path string, recursive, withVersion bool) ([]minio data.Set("with_versions", "true") } - req, err := http.NewRequest("GET", V1_DISK_API+"resources?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, V1DiskAPI+"resources?"+data.Encode(), http.NoBody) if err != nil { return nil, err } @@ -163,12 +166,12 @@ func (c *Client) GetResources(path string, recursive, withVersion bool) ([]minio return r, err } -// PutResources - создать папку -func (c *Client) PutResources(path string) error { +// PutResources - создать папку. +func (c *Client) PutResources(ctx context.Context, path string) error { data := url.Values{} data.Set("path", path) - req, err := http.NewRequest("PUT", V1_DISK_API+"resources?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"resources?"+data.Encode(), http.NoBody) if err != nil { return err } @@ -183,22 +186,23 @@ func (c *Client) PutResources(path string) error { return checkError(resp) } -func (c *Client) UploadResources(path, filename string, overwrite bool, - file io.Reader) (fullPath string, exportUrl string, err error) { +func (c *Client) UploadResources(ctx context.Context, path, filename string, overwrite bool, + file io.Reader) (fullPath string, exportURL string, err error) { buf := new(bytes.Buffer) bw := multipart.NewWriter(buf) - if !strings.HasSuffix(path, "/") { path += "/" } - if err := bw.WriteField("path", path); err != nil { + err = bw.WriteField("path", path) + if err != nil { return "", "", err } if overwrite { - if err := bw.WriteField("overwrite", "true"); err != nil { + err = bw.WriteField("overwrite", "true") + if err != nil { return "", "", err } } @@ -213,14 +217,22 @@ func (c *Client) UploadResources(path, filename string, overwrite bool, return "", "", err } - bw.Close() - req, err := http.NewRequest("POST", V1_DISK_API+"resources/upload", buf) + err = bw.Close() + if err != nil { + return "", "", err + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, V1DiskAPI+"resources/upload", buf) + + if err != nil { + return "", "", err + } c.setHeaders(req) req.Header.Set("Content-Type", bw.FormDataContentType()) resp, err := http.DefaultClient.Do(req) - + if err != nil { return "", "", err } @@ -231,18 +243,18 @@ func (c *Client) UploadResources(path, filename string, overwrite bool, fullPath = path + filename - exportUrl, err = c.GetPublicDownloadURL(fullPath) + exportURL, err = c.GetPublicDownloadURL(ctx, fullPath) - return fullPath, exportUrl, err + return fullPath, exportURL, err } -// GetPublicDownloadURL - получить публичную ссылку для скачивания файла. Ссылка живет 30 минут -func (c *Client) GetPublicDownloadURL(path string) (href string, err error) { +// GetPublicDownloadURL - получить публичную ссылку для скачивания файла. Ссылка живет 30 минут. +func (c *Client) GetPublicDownloadURL(ctx context.Context, path string) (href string, err error) { data := url.Values{} data.Set("path", path) // Получаем публичную ссылку на файл живущую 30 минут - req, err := http.NewRequest("GET", V1_DISK_API+"resources/download?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, V1DiskAPI+"resources/download?"+data.Encode(), http.NoBody) if err != nil { return "", err } @@ -265,14 +277,23 @@ func (c *Client) GetPublicDownloadURL(path string) (href string, err error) { return r.Href, err } -func (c *Client) DownloadResource(path, downloadPath string) error { - href, err := c.GetPublicDownloadURL(path) +func (c *Client) DownloadResource(ctx context.Context, path, downloadPath string) error { + href, err := c.GetPublicDownloadURL(ctx, path) if err != nil { return err } - resp, err := http.Get(href) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, href, http.NoBody) + if err != nil { + return err + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() if err != nil { @@ -293,7 +314,7 @@ func (c *Client) DownloadResource(path, downloadPath string) error { if err != nil { return err } - defer out.Close() + defer out.Close() //nolint // Write the body to file _, err = io.Copy(out, resp.Body) @@ -301,19 +322,26 @@ func (c *Client) DownloadResource(path, downloadPath string) error { return err } -func (c *Client) DownloadResourceBytes(path string) ([]byte, error) { - href, err := c.GetPublicDownloadURL(path) +func (c *Client) DownloadResourceBytes(ctx context.Context, path string) ([]byte, error) { + href, err := c.GetPublicDownloadURL(ctx, path) + if err != nil { + return nil, err + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, href, http.NoBody) + + if err != nil { + return nil, err + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { return nil, err } - resp, err := http.Get(href) defer resp.Body.Close() - if err != nil { - return nil, err - } - if err = checkError(resp); err != nil { return nil, err } @@ -321,7 +349,7 @@ func (c *Client) DownloadResourceBytes(path string) ([]byte, error) { return io.ReadAll(resp.Body) } -func (c *Client) CopyResources(from, path string, overwrite bool) error { +func (c *Client) CopyResources(ctx context.Context, from, path string, overwrite bool) error { data := url.Values{} data.Set("from", from) data.Set("path", path) @@ -329,7 +357,7 @@ func (c *Client) CopyResources(from, path string, overwrite bool) error { data.Set("overwrite", "true") } - req, err := http.NewRequest("PUT", V1_DISK_API+"resources/copy?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"resources/copy?"+data.Encode(), http.NoBody) if err != nil { return err } @@ -344,7 +372,7 @@ func (c *Client) CopyResources(from, path string, overwrite bool) error { return checkError(resp) } -func (c *Client) MoveResources(from, path string, overwrite bool) error { +func (c *Client) MoveResources(ctx context.Context, from, path string, overwrite bool) error { data := url.Values{} data.Set("from", from) data.Set("path", path) @@ -352,7 +380,7 @@ func (c *Client) MoveResources(from, path string, overwrite bool) error { data.Set("overwrite", "true") } - req, err := http.NewRequest("PUT", V1_DISK_API+"resources/move?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"resources/move?"+data.Encode(), http.NoBody) if err != nil { return err } @@ -367,14 +395,14 @@ func (c *Client) MoveResources(from, path string, overwrite bool) error { return checkError(resp) } -func (c *Client) DeleteResources(path string, permanently bool) error { +func (c *Client) DeleteResources(ctx context.Context, path string, permanently bool) error { data := url.Values{} data.Set("path", path) if permanently { data.Set("permanently", "true") } - req, err := http.NewRequest("DELETE", V1_DISK_API+"resources?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodDelete, V1DiskAPI+"resources?"+data.Encode(), http.NoBody) if err != nil { return err } @@ -389,11 +417,11 @@ func (c *Client) DeleteResources(path string, permanently bool) error { return checkError(resp) } -func (c *Client) PublishResources(path string) (href string, err error) { +func (c *Client) PublishResources(ctx context.Context, path string) (href string, err error) { data := url.Values{} data.Set("path", path) - req, err := http.NewRequest("PUT", V1_DISK_API+"resources/publish?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"resources/publish?"+data.Encode(), http.NoBody) if err != nil { return "", err @@ -416,11 +444,11 @@ func (c *Client) PublishResources(path string) (href string, err error) { return r.Href, err } -func (c *Client) UnpublishResources(path string) error { +func (c *Client) UnpublishResources(ctx context.Context, path string) error { data := url.Values{} data.Set("path", path) - req, err := http.NewRequest("PUT", V1_DISK_API+"resources/unpublish?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"resources/unpublish?"+data.Encode(), http.NoBody) if err != nil { return err @@ -443,7 +471,9 @@ func (c *Client) setHeaders(req *http.Request) { func checkError(resp *http.Response) error { switch resp.StatusCode { - case 200, 201, 202, 203, 204, 205, 206, 207, 208, 226: + case http.StatusOK, http.StatusCreated, http.StatusAccepted, http.StatusNonAuthoritativeInfo, + http.StatusNoContent, http.StatusResetContent, http.StatusPartialContent, + http.StatusMultiStatus, http.StatusAlreadyReported, http.StatusIMUsed: return nil } @@ -453,5 +483,5 @@ func checkError(resp *http.Response) error { return err } - return fmt.Errorf(fmt.Sprintf("api/penaDisk: %v | %v", resp.StatusCode, string(body))) + return fmt.Errorf("api/penaDisk: %v | %v", resp.StatusCode, string(body)) } diff --git a/penadisk/model.go b/penadisk/model.go index 41275ba..b883b08 100644 --- a/penadisk/model.go +++ b/penadisk/model.go @@ -11,9 +11,9 @@ type RespPublishResources struct { } type Bucket struct { - Id string `json:"id"` + ID string `json:"id"` Name string `json:"name"` - FolderId string `json:"folderId"` + FolderID string `json:"folderId"` AnonymousAccessFlags struct { Read bool `json:"read"` List bool `json:"list"` @@ -23,16 +23,16 @@ type Bucket struct { Versioning string `json:"versioning"` MaxSize string `json:"maxSize"` Policy string `json:"policy"` - Acl struct { + ACL struct { Grants []struct { Permission string `json:"permission"` GrantType string `json:"grantType"` - GranteeId string `json:"granteeId"` + GranteeID string `json:"granteeId"` } `json:"grants"` } `json:"acl"` CreatedAt time.Time `json:"createdAt"` Cors []struct { - Id string `json:"id"` + ID string `json:"id"` AllowedMethods []string `json:"allowedMethods"` AllowedHeaders []string `json:"allowedHeaders"` AllowedOrigins []string `json:"allowedOrigins"` @@ -48,12 +48,12 @@ type Bucket struct { } `json:"redirectAllRequests"` RoutingRules []struct { Condition struct { - HttpErrorCodeReturnedEquals string `json:"httpErrorCodeReturnedEquals"` + HTTPErrorCodeReturnedEquals string `json:"httpErrorCodeReturnedEquals"` KeyPrefixEquals string `json:"keyPrefixEquals"` } `json:"condition"` Redirect struct { Hostname string `json:"hostname"` - HttpRedirectCode string `json:"httpRedirectCode"` + HTTPRedirectCode string `json:"httpRedirectCode"` Protocol string `json:"protocol"` ReplaceKeyPrefixWith string `json:"replaceKeyPrefixWith"` ReplaceKeyWith string `json:"replaceKeyWith"` @@ -61,7 +61,7 @@ type Bucket struct { } `json:"routingRules"` } `json:"websiteSettings"` LifecycleRules []struct { - Id string `json:"id"` + ID string `json:"id"` Enabled bool `json:"enabled"` Filter struct { Prefix string `json:"prefix"` diff --git a/privileges/privileges.go b/privileges/privileges.go index a37e8dc..293eb13 100644 --- a/privileges/privileges.go +++ b/privileges/privileges.go @@ -1,131 +1,132 @@ -package privileges; +package privileges import ( - "fmt" - "context" - "time" - "github.com/gofiber/fiber/v2" + "context" + "fmt" + "time" + + "github.com/gofiber/fiber/v2" ) type Privilege struct { - ID string `json:"_id"` - PrivilegeID string `json:"privilegeId"` - Name string `json:"name"` - ServiceKey string `json:"serviceKey"` - Description string `json:"description"` - Type string `json:"type"` - Value string `json:"value"` - Price float64 `json:"price"` - IsDeleted bool `json:"isDeleted"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - DeletedAt time.Time `json:"deletedAt"` + ID string `json:"_id"` + PrivilegeID string `json:"privilegeId"` + Name string `json:"name"` + ServiceKey string `json:"serviceKey"` + Description string `json:"description"` + Type string `json:"type"` + Value string `json:"value"` + Price float64 `json:"price"` + IsDeleted bool `json:"isDeleted"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + DeletedAt time.Time `json:"deletedAt"` } const skey = "templategen" var ( - Privileges = []Privilege{ - { - PrivilegeID: "templateCnt", - Name: "Количество Шаблонов", - ServiceKey: skey, - Description: "Количество шаблонов, которые может сделать пользователь сервиса", - Type: "count", - Value: "шаблон", - }, - { - PrivilegeID: "templateUnlimTime", - Name: "Безлимит", - ServiceKey: skey, - Description: "Количество дней, в течении которых пользование сервисом безлимитно", - Type: "day", - Value: "день", - }, - { - PrivilegeID: "templateStorage", - Name: "Размер Диска", - ServiceKey: skey, - Description: "Обьём ПенаДиска для хранения шаблонов и результатов шаблонизации", - Type: "count", - Value: "МБ", - }, - } + Privileges = []Privilege{ + { + PrivilegeID: "templateCnt", + Name: "Количество Шаблонов", + ServiceKey: skey, + Description: "Количество шаблонов, которые может сделать пользователь сервиса", + Type: "count", + Value: "шаблон", + }, + { + PrivilegeID: "templateUnlimTime", + Name: "Безлимит", + ServiceKey: skey, + Description: "Количество дней, в течении которых пользование сервисом безлимитно", + Type: "day", + Value: "день", + }, + { + PrivilegeID: "templateStorage", + Name: "Размер Диска", + ServiceKey: skey, + Description: "Обьём ПенаДиска для хранения шаблонов и результатов шаблонизации", + Type: "count", + Value: "МБ", + }, + } ) func PublishPrivileges(ctx context.Context, domain string) error { - old, err := getActualPrivileges(ctx, domain) - if err != nil { - return err - } + old, err := GetActualPrivileges(ctx, domain) + if err != nil { + return err + } - if len(old) == 0 { - return setupActualPrivileges(ctx, Privileges, domain) - } + if len(old) == 0 { + return setupActualPrivileges(ctx, Privileges, domain) + } - found := false - - for _, oldPriv := range old { - for _, newPriv := range Privileges { - if newPriv.PrivilegeID == oldPriv.PrivilegeID { - found = true - } - } - if !found { - if err := removePrivilege(ctx, domain, oldPriv.PrivilegeID); err != nil { - return err - } - } - found = false - } + found := false - return updatePrivileges(ctx, Privileges, domain) + for _, oldPriv := range old { + for _, newPriv := range Privileges { + if newPriv.PrivilegeID == oldPriv.PrivilegeID { + found = true + } + } + if !found { + if err := removePrivilege(ctx, domain, oldPriv.PrivilegeID); err != nil { + return err + } + } + found = false + } + + return updatePrivileges(ctx, Privileges, domain) } -func getActualPrivileges( - ctx context.Context, - domain string) ([]Privilege, error) { - res := []Privilege{} - _, _, err := fiber.Get(domain+"/privilege/service/templategen").Struct(&res) - if err != nil { - return res, err[0] - } - fmt.Println("str", res) - return res, nil +func GetActualPrivileges( + _ context.Context, + domain string) ([]Privilege, error) { + res := []Privilege{} + _, _, err := fiber.Get(domain + "/privilege/service/templategen").Struct(&res) + if err != nil { + return res, err[0] + } + fmt.Println("str", res) + return res, nil } -func updatePrivileges(ctx context.Context, data []Privilege, domain string) error { - _, _, err := fiber.Put(domain+"/privilege/many").JSON(map[string][]Privilege{ - "privilegies": data, - }).Bytes() - if err != nil { - return err[0] - } +func updatePrivileges(_ context.Context, data []Privilege, domain string) error { + _, _, err := fiber.Put(domain + "/privilege/many").JSON(map[string][]Privilege{ + "privilege": data, + }).Bytes() + if err != nil { + return err[0] + } - return nil + return nil } func setupActualPrivileges( - ctx context.Context, - data []Privilege, - domain string) error { - res := []Privilege{} - _, _, err := fiber.Post(domain+"/privilege/many").JSON(map[string][]Privilege{ - "privilegies": data, - }).Struct(&res) + _ context.Context, + data []Privilege, + domain string) error { + res := []Privilege{} + _, _, err := fiber.Post(domain + "/privilege/many").JSON(map[string][]Privilege{ + "privilege": data, + }).Struct(&res) - if err != nil { - return err[0] - } + if err != nil { + return err[0] + } - return nil + return nil } -func removePrivilege(ctx context.Context, domain, id string) error { - _, _, err := fiber.Delete(domain+"/privilege/").JSON(map[string]string{"privilegeId":id}).Bytes() - if err != nil { - return err[0] - } +func removePrivilege(_ context.Context, domain, id string) error { + _, _, err := fiber.Delete(domain + "/privilege/").JSON(map[string]string{"privilegeId": id}).Bytes() + if err != nil { + return err[0] + } - return nil + return nil } diff --git a/privileges/privileges_test.go b/privileges/privileges_test.go index 156b99c..1832d49 100644 --- a/privileges/privileges_test.go +++ b/privileges/privileges_test.go @@ -1,23 +1,25 @@ package privileges import ( - "testing" - "github.com/stretchr/testify/assert" - "github.com/themakers/bdd" - "context" + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/themakers/bdd" ) func TestPrivileges(t *testing.T) { - ctx := context.Background() - bdd.Scenario(t, "setPrivilegesLogic", func(t *testing.T, runID string){ - bdd.Test(t, "getOldPrivileges", func(){ - p, err := getActualPrivileges(ctx,"https://admin.pena.digital/strator") - assert.NoError(t,err) - assert.NotEqual(t, len(p), 0) - }) - bdd.Test(t, "setOldPrivileges", func(){ - err := setupActualPrivileges(ctx,Privileges,"https://admin.pena.digital/strator") - assert.NoError(t,err) - }) - }) + ctx := context.Background() + bdd.Scenario(t, "setPrivilegesLogic", func(t *testing.T, runID string) { + t.Helper() + bdd.Test(t, "getOldPrivileges", func() { + p, err := GetActualPrivileges(ctx, "https://admin.pena.digital/strator") + assert.NoError(t, err) + assert.NotEqual(t, len(p), 0) + }) + bdd.Test(t, "setOldPrivileges", func() { + err := setupActualPrivileges(ctx, Privileges, "https://admin.pena.digital/strator") + assert.NoError(t, err) + }) + }) } diff --git a/proto/tariff/models.pb.go b/proto/tariff/models.pb.go new file mode 100644 index 0000000..8f18d98 --- /dev/null +++ b/proto/tariff/models.pb.go @@ -0,0 +1,313 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v4.23.4 +// source: models.proto + +package tariff + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type PrivilegeType int32 + +const ( + PrivilegeType_Full PrivilegeType = 0 + PrivilegeType_Day PrivilegeType = 1 + PrivilegeType_Count PrivilegeType = 2 +) + +// Enum value maps for PrivilegeType. +var ( + PrivilegeType_name = map[int32]string{ + 0: "Full", + 1: "Day", + 2: "Count", + } + PrivilegeType_value = map[string]int32{ + "Full": 0, + "Day": 1, + "Count": 2, + } +) + +func (x PrivilegeType) Enum() *PrivilegeType { + p := new(PrivilegeType) + *p = x + return p +} + +func (x PrivilegeType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (PrivilegeType) Descriptor() protoreflect.EnumDescriptor { + return file_models_proto_enumTypes[0].Descriptor() +} + +func (PrivilegeType) Type() protoreflect.EnumType { + return &file_models_proto_enumTypes[0] +} + +func (x PrivilegeType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use PrivilegeType.Descriptor instead. +func (PrivilegeType) EnumDescriptor() ([]byte, []int) { + return file_models_proto_rawDescGZIP(), []int{0} +} + +type PrivilegeMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PrivilegeID string `protobuf:"bytes,1,opt,name=PrivilegeID,proto3" json:"PrivilegeID,omitempty"` + ServiceKey string `protobuf:"bytes,2,opt,name=ServiceKey,proto3" json:"ServiceKey,omitempty"` + Type PrivilegeType `protobuf:"varint,3,opt,name=Type,proto3,enum=tariff.PrivilegeType" json:"Type,omitempty"` + Value string `protobuf:"bytes,4,opt,name=Value,proto3" json:"Value,omitempty"` + Amount uint64 `protobuf:"varint,5,opt,name=Amount,proto3" json:"Amount,omitempty"` +} + +func (x *PrivilegeMessage) Reset() { + *x = PrivilegeMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_models_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PrivilegeMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PrivilegeMessage) ProtoMessage() {} + +func (x *PrivilegeMessage) ProtoReflect() protoreflect.Message { + mi := &file_models_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PrivilegeMessage.ProtoReflect.Descriptor instead. +func (*PrivilegeMessage) Descriptor() ([]byte, []int) { + return file_models_proto_rawDescGZIP(), []int{0} +} + +func (x *PrivilegeMessage) GetPrivilegeID() string { + if x != nil { + return x.PrivilegeID + } + return "" +} + +func (x *PrivilegeMessage) GetServiceKey() string { + if x != nil { + return x.ServiceKey + } + return "" +} + +func (x *PrivilegeMessage) GetType() PrivilegeType { + if x != nil { + return x.Type + } + return PrivilegeType_Full +} + +func (x *PrivilegeMessage) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +func (x *PrivilegeMessage) GetAmount() uint64 { + if x != nil { + return x.Amount + } + return 0 +} + +type TariffMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Privileges []*PrivilegeMessage `protobuf:"bytes,1,rep,name=Privileges,proto3" json:"Privileges,omitempty"` + UserID string `protobuf:"bytes,2,opt,name=UserID,proto3" json:"UserID,omitempty"` +} + +func (x *TariffMessage) Reset() { + *x = TariffMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_models_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TariffMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TariffMessage) ProtoMessage() {} + +func (x *TariffMessage) ProtoReflect() protoreflect.Message { + mi := &file_models_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TariffMessage.ProtoReflect.Descriptor instead. +func (*TariffMessage) Descriptor() ([]byte, []int) { + return file_models_proto_rawDescGZIP(), []int{1} +} + +func (x *TariffMessage) GetPrivileges() []*PrivilegeMessage { + if x != nil { + return x.Privileges + } + return nil +} + +func (x *TariffMessage) GetUserID() string { + if x != nil { + return x.UserID + } + return "" +} + +var File_models_proto protoreflect.FileDescriptor + +var file_models_proto_rawDesc = []byte{ + 0x0a, 0x0c, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, + 0x74, 0x61, 0x72, 0x69, 0x66, 0x66, 0x22, 0xad, 0x01, 0x0a, 0x10, 0x50, 0x72, 0x69, 0x76, 0x69, + 0x6c, 0x65, 0x67, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x50, + 0x72, 0x69, 0x76, 0x69, 0x6c, 0x65, 0x67, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x50, 0x72, 0x69, 0x76, 0x69, 0x6c, 0x65, 0x67, 0x65, 0x49, 0x44, 0x12, 0x1e, 0x0a, + 0x0a, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x29, 0x0a, + 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x61, + 0x72, 0x69, 0x66, 0x66, 0x2e, 0x50, 0x72, 0x69, 0x76, 0x69, 0x6c, 0x65, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, + 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x61, 0x0a, 0x0d, 0x54, 0x61, 0x72, 0x69, 0x66, 0x66, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x0a, 0x50, 0x72, 0x69, 0x76, 0x69, + 0x6c, 0x65, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x61, + 0x72, 0x69, 0x66, 0x66, 0x2e, 0x50, 0x72, 0x69, 0x76, 0x69, 0x6c, 0x65, 0x67, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0a, 0x50, 0x72, 0x69, 0x76, 0x69, 0x6c, 0x65, 0x67, 0x65, + 0x73, 0x12, 0x16, 0x0a, 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x2a, 0x2d, 0x0a, 0x0d, 0x50, 0x72, 0x69, + 0x76, 0x69, 0x6c, 0x65, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x75, + 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x61, 0x79, 0x10, 0x01, 0x12, 0x09, 0x0a, + 0x05, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x10, 0x02, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x74, 0x61, + 0x72, 0x69, 0x66, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_models_proto_rawDescOnce sync.Once + file_models_proto_rawDescData = file_models_proto_rawDesc +) + +func file_models_proto_rawDescGZIP() []byte { + file_models_proto_rawDescOnce.Do(func() { + file_models_proto_rawDescData = protoimpl.X.CompressGZIP(file_models_proto_rawDescData) + }) + return file_models_proto_rawDescData +} + +var file_models_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_models_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_models_proto_goTypes = []interface{}{ + (PrivilegeType)(0), // 0: tariff.PrivilegeType + (*PrivilegeMessage)(nil), // 1: tariff.PrivilegeMessage + (*TariffMessage)(nil), // 2: tariff.TariffMessage +} +var file_models_proto_depIdxs = []int32{ + 0, // 0: tariff.PrivilegeMessage.Type:type_name -> tariff.PrivilegeType + 1, // 1: tariff.TariffMessage.Privileges:type_name -> tariff.PrivilegeMessage + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_models_proto_init() } +func file_models_proto_init() { + if File_models_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_models_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PrivilegeMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_models_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TariffMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_models_proto_rawDesc, + NumEnums: 1, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_models_proto_goTypes, + DependencyIndexes: file_models_proto_depIdxs, + EnumInfos: file_models_proto_enumTypes, + MessageInfos: file_models_proto_msgTypes, + }.Build() + File_models_proto = out.File + file_models_proto_rawDesc = nil + file_models_proto_goTypes = nil + file_models_proto_depIdxs = nil +} diff --git a/proto/tariff/models.proto b/proto/tariff/models.proto new file mode 100644 index 0000000..896c4ba --- /dev/null +++ b/proto/tariff/models.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +package tariff; + +option go_package = "./tariff"; + +message PrivilegeMessage { + string PrivilegeID = 1; + string ServiceKey = 2; + PrivilegeType Type = 3; + string Value = 4; + uint64 Amount = 5; +} + +message TariffMessage { + repeated PrivilegeMessage Privileges = 1; + string UserID = 2; +} + +enum PrivilegeType { + Full = 0; + Day = 1; + Count = 2; +} diff --git a/static/cert/solweb.site/cert.pem b/static/cert/solweb.site/cert.pem index 6370aa1..3d9c56c 100644 --- a/static/cert/solweb.site/cert.pem +++ b/static/cert/solweb.site/cert.pem @@ -1,30 +1,30 @@ ------BEGIN CERTIFICATE----- -MIIFHDCCBASgAwIBAgISBLd688uTwblyd0xdFr3L6daQMA0GCSqGSIb3DQEBCwUA -MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD -EwJSMzAeFw0yMjA4MDYwMjI1MDhaFw0yMjExMDQwMjI1MDdaMBYxFDASBgNVBAMT -C3NvbHdlYi5zaXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyX6Y -zAOtmLRKbxckleGYjS5+Z7DUxUyprRqUDr6x1WXNk04y8xil68tiDjYSduQ1KYu0 -lv0hcauKHurhrVpuXOrUI9ysEIyx/xwA5cV6n96gZMv9cO6L4D2V/Nz/8n+aOJZf -i9LHaxHbXK4TRuN0uqUCRhpzVzSIHz5SYamwelr8UowzjCIubCT5tTL5t3g4KF9G -kYvY18pcUFHWk6O1N4CqvEyFWVRjOxEN9NKtEzfScov4dP/X5dU9Hgyuld2OPv6S -RAa/OxhYbO0xwcDV+ARRUGJXffwhA0vn5NTimRb49cUx3PAt+LP4sq3ed/utJPSz -O+BzwglB/oKAzwm5uQIDAQABo4ICRjCCAkIwDgYDVR0PAQH/BAQDAgWgMB0GA1Ud -JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQW -BBTyUZZlKNRuajOyxJrw9tMlJNd4BDAfBgNVHSMEGDAWgBQULrMXt1hWy65QCUDm -H6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0dHA6Ly9yMy5v -LmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iub3JnLzAW -BgNVHREEDzANggtzb2x3ZWIuc2l0ZTBMBgNVHSAERTBDMAgGBmeBDAECATA3Bgsr -BgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0 -Lm9yZzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB3AN+lXqtogk8fbK3uuF9OPlrq -zaISpGpejjsSwCBEXCpzAAABgnEvaaAAAAQDAEgwRgIhAKK+fkTyJFn/HHbYj9BV -LMbGKDIRFjCoLZCAV2cTkvoYAiEA3pc6LREny7ExvkO+0lN38AC6k7jJJa9qdyoS -nucCz6YAdQBGpVXrdfqRIDC1oolp9PN9ESxBdL79SbiFq/L8cP5tRwAAAYJxL2nI -AAAEAwBGMEQCIAuhH4/x7DCwUIu7enewxdn9roNY83x0J9Rja3TZo6W/AiAu/pDM -RweFdZcz21HyqUTVQfjBlabgH8UtNX7A54wgFTANBgkqhkiG9w0BAQsFAAOCAQEA -CqyytF0AWz74DPOFHbsDLb1E8CtsL9DsIJ7EcL9xdJrXYo66J3BIH4PwzkDelFID -v4aUgTYavFqC3ygzOXX1afiayKM15TwqgCQ16qW0lS14N/bv/v/K1sQNAEs2C3/g -Itq7I3sBg7npk+k2bckoa7UccLc3fj/gfaZcI6sTNq6nCc5kmBjar4S3p7Gh4ZyL -cqtECrhnBy6Az8S9se85gVD+NnhEaIgnjifPh5QhLoBn264h0CPH2dUDN1Poxo7u -Z4b4wDaws/QPHe/6jLXscatywEtVezaljj99re1JVnpFN8UzM4Rcuid+Yi6pZJED -LiASDdNrOPfTm8Zu86YRPQ== ------END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFHDCCBASgAwIBAgISBLd688uTwblyd0xdFr3L6daQMA0GCSqGSIb3DQEBCwUA +MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD +EwJSMzAeFw0yMjA4MDYwMjI1MDhaFw0yMjExMDQwMjI1MDdaMBYxFDASBgNVBAMT +C3NvbHdlYi5zaXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyX6Y +zAOtmLRKbxckleGYjS5+Z7DUxUyprRqUDr6x1WXNk04y8xil68tiDjYSduQ1KYu0 +lv0hcauKHurhrVpuXOrUI9ysEIyx/xwA5cV6n96gZMv9cO6L4D2V/Nz/8n+aOJZf +i9LHaxHbXK4TRuN0uqUCRhpzVzSIHz5SYamwelr8UowzjCIubCT5tTL5t3g4KF9G +kYvY18pcUFHWk6O1N4CqvEyFWVRjOxEN9NKtEzfScov4dP/X5dU9Hgyuld2OPv6S +RAa/OxhYbO0xwcDV+ARRUGJXffwhA0vn5NTimRb49cUx3PAt+LP4sq3ed/utJPSz +O+BzwglB/oKAzwm5uQIDAQABo4ICRjCCAkIwDgYDVR0PAQH/BAQDAgWgMB0GA1Ud +JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQW +BBTyUZZlKNRuajOyxJrw9tMlJNd4BDAfBgNVHSMEGDAWgBQULrMXt1hWy65QCUDm +H6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0dHA6Ly9yMy5v +LmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iub3JnLzAW +BgNVHREEDzANggtzb2x3ZWIuc2l0ZTBMBgNVHSAERTBDMAgGBmeBDAECATA3Bgsr +BgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0 +Lm9yZzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB3AN+lXqtogk8fbK3uuF9OPlrq +zaISpGpejjsSwCBEXCpzAAABgnEvaaAAAAQDAEgwRgIhAKK+fkTyJFn/HHbYj9BV +LMbGKDIRFjCoLZCAV2cTkvoYAiEA3pc6LREny7ExvkO+0lN38AC6k7jJJa9qdyoS +nucCz6YAdQBGpVXrdfqRIDC1oolp9PN9ESxBdL79SbiFq/L8cP5tRwAAAYJxL2nI +AAAEAwBGMEQCIAuhH4/x7DCwUIu7enewxdn9roNY83x0J9Rja3TZo6W/AiAu/pDM +RweFdZcz21HyqUTVQfjBlabgH8UtNX7A54wgFTANBgkqhkiG9w0BAQsFAAOCAQEA +CqyytF0AWz74DPOFHbsDLb1E8CtsL9DsIJ7EcL9xdJrXYo66J3BIH4PwzkDelFID +v4aUgTYavFqC3ygzOXX1afiayKM15TwqgCQ16qW0lS14N/bv/v/K1sQNAEs2C3/g +Itq7I3sBg7npk+k2bckoa7UccLc3fj/gfaZcI6sTNq6nCc5kmBjar4S3p7Gh4ZyL +cqtECrhnBy6Az8S9se85gVD+NnhEaIgnjifPh5QhLoBn264h0CPH2dUDN1Poxo7u +Z4b4wDaws/QPHe/6jLXscatywEtVezaljj99re1JVnpFN8UzM4Rcuid+Yi6pZJED +LiASDdNrOPfTm8Zu86YRPQ== +-----END CERTIFICATE----- diff --git a/static/cert/solweb.site/chain.pem b/static/cert/solweb.site/chain.pem index ca1c1a6..b3a7354 100644 --- a/static/cert/solweb.site/chain.pem +++ b/static/cert/solweb.site/chain.pem @@ -1,61 +1,61 @@ ------BEGIN CERTIFICATE----- -MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw -WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg -RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP -R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx -sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm -NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg -Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG -/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC -AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB -Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA -FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw -AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw -Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB -gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W -PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl -ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz -CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm -lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 -avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 -yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O -yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids -hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ -HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv -MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX -nLRbwHOoq7hHwg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC -ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL -wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D -LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK -4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5 -bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y -sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ -Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4 -FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc -SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql -PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND -TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw -SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1 -c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx -+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB -ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu -b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E -U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu -MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC -5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW -9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG -WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O -he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC -Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5 ------END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw +WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP +R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx +sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm +NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg +Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG +/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB +Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA +FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw +AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw +Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB +gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W +PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl +ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz +CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm +lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 +avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 +yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O +yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids +hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ +HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv +MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX +nLRbwHOoq7hHwg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC +ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL +wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D +LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK +4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5 +bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y +sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ +Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4 +FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc +SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql +PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND +TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1 +c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx ++tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB +ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu +b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E +U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu +MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC +5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW +9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG +WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O +he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC +Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5 +-----END CERTIFICATE----- diff --git a/static/cert/solweb.site/fullchain.pem b/static/cert/solweb.site/fullchain.pem index 9e79636..5607b47 100644 --- a/static/cert/solweb.site/fullchain.pem +++ b/static/cert/solweb.site/fullchain.pem @@ -1,91 +1,91 @@ ------BEGIN CERTIFICATE----- -MIIFHDCCBASgAwIBAgISBIL+EiA/jua4C2la/3qwHNB7MA0GCSqGSIb3DQEBCwUA -MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD -EwJSMzAeFw0yMjExMTAxNTQyMjBaFw0yMzAyMDgxNTQyMTlaMBYxFDASBgNVBAMT -C3NvbHdlYi5zaXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy3eA -U7zQ8iJzlHqmxPKottfLIXNBKBxW3B6x6tR5v+pBZFWF6ST3ocIByYfQtGAeNdnY -q95/DRVnSyYnVce47lI3PVB+X25iGUIQWxWcbNP5Ep4fuayA2z9PtTfF6LXbP883 -xFAD9MqQzr+77JjUrm+up3RZmPa8F+o43msZuFBeQgDb9U6ZiRl3yqh67UB5PPVM -5DW18wvFvg1NRWDmAN7FQgi6AkySdLJjo0/4iHfV8e6hDhI1q0Tcnvsp8VFw5QJn -RYcQfKhYVXe62HjRDs08whKlptTcqivzXz2AxnU9yfjVsdaHCBUOyhpGdHQuiIjs -piTadNJmHOHgKZGGBQIDAQABo4ICRjCCAkIwDgYDVR0PAQH/BAQDAgWgMB0GA1Ud -JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQW -BBS5dOhJzo+8FEcBI4VZnCHfMZfBBTAfBgNVHSMEGDAWgBQULrMXt1hWy65QCUDm -H6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0dHA6Ly9yMy5v -LmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iub3JnLzAW -BgNVHREEDzANggtzb2x3ZWIuc2l0ZTBMBgNVHSAERTBDMAgGBmeBDAECATA3Bgsr -BgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0 -Lm9yZzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2ALc++yTfnE26dfI5xbpY9Gxd -/ELPep81xJ4dCYEl7bSZAAABhGJrxCEAAAQDAEcwRQIhALvhrXlgLVUrOdDJ+v+0 -1bITSoGGnx1AtE/qVsMdjZxKAiBmKFihL9ugHjH6Wp3HBOjQg97w1qf+tplKSOE8 -fV0BuwB2AHoyjFTYty22IOo44FIe6YQWcDIThU070ivBOlejUutSAAABhGJrxEAA -AAQDAEcwRQIgIVOVnfb5oqoAcdmGhBMU/d65vfUvt2QP8yU1pmu0uS0CIQD++4kE -/DEYXBye634QVjmf/IcoXsPHQyQ3jIAmInteZDANBgkqhkiG9w0BAQsFAAOCAQEA -a9vkSsknNH5mH8QoFukQPIXDzYAHCaUpL7CzlHt1OWwTIIX/r8J91jrST9k/NHoh -rmvRWwlaLH0i5usYRKotSzdNETaJ5SUSMHdLv8Y/yAMGwURaDQeVwdsMsmraiUxX -84i86N1L/NSgWbgm2g7XS8TSA3mIyBF0BgLDl5pp7Tjywxj538+8a4fnHdFSobrd -3E52YQFP2mzzwgXenJebXrdaYDTAjjMDBpySC6vnRAubLedJE6Tfo2vkrwxfFTJY -ECRPtsEZQj4gyXb+PoPAYVH4DheiIN+xnAS0ZUEVYto4NfszU6dt9D31I3ZBD9a/ -Xpf0e6rBigJ5FrkAlPU8rg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw -WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg -RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP -R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx -sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm -NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg -Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG -/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC -AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB -Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA -FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw -AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw -Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB -gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W -PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl -ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz -CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm -lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 -avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 -yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O -yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids -hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ -HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv -MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX -nLRbwHOoq7hHwg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC -ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL -wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D -LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK -4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5 -bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y -sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ -Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4 -FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc -SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql -PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND -TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw -SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1 -c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx -+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB -ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu -b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E -U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu -MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC -5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW -9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG -WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O -he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC -Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5 ------END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFHDCCBASgAwIBAgISBIL+EiA/jua4C2la/3qwHNB7MA0GCSqGSIb3DQEBCwUA +MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD +EwJSMzAeFw0yMjExMTAxNTQyMjBaFw0yMzAyMDgxNTQyMTlaMBYxFDASBgNVBAMT +C3NvbHdlYi5zaXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy3eA +U7zQ8iJzlHqmxPKottfLIXNBKBxW3B6x6tR5v+pBZFWF6ST3ocIByYfQtGAeNdnY +q95/DRVnSyYnVce47lI3PVB+X25iGUIQWxWcbNP5Ep4fuayA2z9PtTfF6LXbP883 +xFAD9MqQzr+77JjUrm+up3RZmPa8F+o43msZuFBeQgDb9U6ZiRl3yqh67UB5PPVM +5DW18wvFvg1NRWDmAN7FQgi6AkySdLJjo0/4iHfV8e6hDhI1q0Tcnvsp8VFw5QJn +RYcQfKhYVXe62HjRDs08whKlptTcqivzXz2AxnU9yfjVsdaHCBUOyhpGdHQuiIjs +piTadNJmHOHgKZGGBQIDAQABo4ICRjCCAkIwDgYDVR0PAQH/BAQDAgWgMB0GA1Ud +JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQW +BBS5dOhJzo+8FEcBI4VZnCHfMZfBBTAfBgNVHSMEGDAWgBQULrMXt1hWy65QCUDm +H6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0dHA6Ly9yMy5v +LmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iub3JnLzAW +BgNVHREEDzANggtzb2x3ZWIuc2l0ZTBMBgNVHSAERTBDMAgGBmeBDAECATA3Bgsr +BgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0 +Lm9yZzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2ALc++yTfnE26dfI5xbpY9Gxd +/ELPep81xJ4dCYEl7bSZAAABhGJrxCEAAAQDAEcwRQIhALvhrXlgLVUrOdDJ+v+0 +1bITSoGGnx1AtE/qVsMdjZxKAiBmKFihL9ugHjH6Wp3HBOjQg97w1qf+tplKSOE8 +fV0BuwB2AHoyjFTYty22IOo44FIe6YQWcDIThU070ivBOlejUutSAAABhGJrxEAA +AAQDAEcwRQIgIVOVnfb5oqoAcdmGhBMU/d65vfUvt2QP8yU1pmu0uS0CIQD++4kE +/DEYXBye634QVjmf/IcoXsPHQyQ3jIAmInteZDANBgkqhkiG9w0BAQsFAAOCAQEA +a9vkSsknNH5mH8QoFukQPIXDzYAHCaUpL7CzlHt1OWwTIIX/r8J91jrST9k/NHoh +rmvRWwlaLH0i5usYRKotSzdNETaJ5SUSMHdLv8Y/yAMGwURaDQeVwdsMsmraiUxX +84i86N1L/NSgWbgm2g7XS8TSA3mIyBF0BgLDl5pp7Tjywxj538+8a4fnHdFSobrd +3E52YQFP2mzzwgXenJebXrdaYDTAjjMDBpySC6vnRAubLedJE6Tfo2vkrwxfFTJY +ECRPtsEZQj4gyXb+PoPAYVH4DheiIN+xnAS0ZUEVYto4NfszU6dt9D31I3ZBD9a/ +Xpf0e6rBigJ5FrkAlPU8rg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw +WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP +R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx +sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm +NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg +Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG +/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB +Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA +FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw +AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw +Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB +gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W +PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl +ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz +CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm +lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 +avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 +yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O +yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids +hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ +HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv +MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX +nLRbwHOoq7hHwg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC +ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL +wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D +LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK +4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5 +bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y +sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ +Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4 +FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc +SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql +PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND +TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1 +c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx ++tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB +ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu +b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E +U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu +MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC +5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW +9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG +WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O +he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC +Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5 +-----END CERTIFICATE----- diff --git a/static/cert/solweb.site/privkey.pem b/static/cert/solweb.site/privkey.pem index 196ad91..f4686c0 100644 --- a/static/cert/solweb.site/privkey.pem +++ b/static/cert/solweb.site/privkey.pem @@ -1,28 +1,28 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDLd4BTvNDyInOU -eqbE8qi218shc0EoHFbcHrHq1Hm/6kFkVYXpJPehwgHJh9C0YB412dir3n8NFWdL -JidVx7juUjc9UH5fbmIZQhBbFZxs0/kSnh+5rIDbP0+1N8Xotds/zzfEUAP0ypDO -v7vsmNSub66ndFmY9rwX6jjeaxm4UF5CANv1TpmJGXfKqHrtQHk89UzkNbXzC8W+ -DU1FYOYA3sVCCLoCTJJ0smOjT/iId9Xx7qEOEjWrRNye+ynxUXDlAmdFhxB8qFhV -d7rYeNEOzTzCEqWm1NyqK/NfPYDGdT3J+NWx1ocIFQ7KGkZ0dC6IiOymJNp00mYc -4eApkYYFAgMBAAECggEAdst26W08saLbyL0z0Zm8V8T2nLkmOb0SGcLyLiGQVDT5 -qRMl9FHZI2CamofpmubjvJ1MnExz8belb4L/RF4v4zWteuccYauZKxYfZo7fncrF -idE4xLerJFd6ulut+Yj0UfUyojP1m18J3SylFCbHRnF+j9am2WB1waDHQ1VU1v9K -W0Ny0Y3iBPQt34p6+Zt1Fi2zRfW3Wngld8o7Z09uyh5zsu8Esk7iQpSoV5XD0WRv -Ss13WrOZ33VwZxjYAsRh0koz96l4jpmCS5khnzSKmf3uaEOilrUPuGO6VMDv/yVF -guPvHWfusfT57hl6hWhLWb4bT3ZpOLiasyGKIo8lAQKBgQD1CtzQI8Ri+Hpga9XG -5kzO19sggWYxBcVi3Z+IUw9JOV80rMQUJEoFiahyvpItAyFTOcjxYaBHi0zHK5ZK -hRXoc7nvbkha4eVfg3BeSyh+8xjTB754YNfImByso+rW9W+D3n6feFcN4nB3i9qm -vdgCw3ws5XvJjKlFFfUs6sI7/QKBgQDUkLMExgccllxGmzHL7K68oqKKPZsIANBs -FUIFDoGimlfrPdja8/viEDDi15ZhH3tv1LJUeC/aMaLgU2EGarRbYpdD9vKZLvPi -ydEboGFUNJbdnfKxTHeaUrE35xUv8b499bDKsCohW1r4hvadT+8uDr23JtL4SsqH -+ug4+L1cqQKBgQDU9FLAREU46c6Ymz6W87BOlkMmNa6U7foDmK07MUv4i/aUdYyW -II9/zolo5vtsSOseQ/rA4+ICKypXcSbUrmJCuMgfL42MBgNsBXOTTufro+KwC2vZ -e/grqR5KXs4JcBUw2hzbBB9Lvr2U9yLXg+cFR9RTxD/XAfpdQt7m4UJaFQKBgQDI -44vceg6kjNHehLN2J1QowIdeoMRQtvxC+YAwaTpI4xcuIoA8xZMKXgTljZv4ZBlz -Yg+7Vu7ahkiJOyOaPeP/7dhJiixSaxZhAhzWwCbbvuvJvIlt2He8aGRGEeVrL0t9 -ISKZHA5lAgKimGKf37iKzbGsU0vVDlIEWzN3DFViKQKBgHTpq5SeBp3NSnQw5a0y -6vPYtm0t/jysOy3UGIl7qf/P5Ob994E7gVluPN8r4wXcmYqw9/glT2pdqfoBeQmX -UZ0zvcbdTERoNbQP8xkoN6C/8kUxbCVY3TsvteZQbJ7XB1Lcvf5k3aVWYDKabEzX -6kat3P/xhuX2aBJ25n+DEmwt ------END PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDLd4BTvNDyInOU +eqbE8qi218shc0EoHFbcHrHq1Hm/6kFkVYXpJPehwgHJh9C0YB412dir3n8NFWdL +JidVx7juUjc9UH5fbmIZQhBbFZxs0/kSnh+5rIDbP0+1N8Xotds/zzfEUAP0ypDO +v7vsmNSub66ndFmY9rwX6jjeaxm4UF5CANv1TpmJGXfKqHrtQHk89UzkNbXzC8W+ +DU1FYOYA3sVCCLoCTJJ0smOjT/iId9Xx7qEOEjWrRNye+ynxUXDlAmdFhxB8qFhV +d7rYeNEOzTzCEqWm1NyqK/NfPYDGdT3J+NWx1ocIFQ7KGkZ0dC6IiOymJNp00mYc +4eApkYYFAgMBAAECggEAdst26W08saLbyL0z0Zm8V8T2nLkmOb0SGcLyLiGQVDT5 +qRMl9FHZI2CamofpmubjvJ1MnExz8belb4L/RF4v4zWteuccYauZKxYfZo7fncrF +idE4xLerJFd6ulut+Yj0UfUyojP1m18J3SylFCbHRnF+j9am2WB1waDHQ1VU1v9K +W0Ny0Y3iBPQt34p6+Zt1Fi2zRfW3Wngld8o7Z09uyh5zsu8Esk7iQpSoV5XD0WRv +Ss13WrOZ33VwZxjYAsRh0koz96l4jpmCS5khnzSKmf3uaEOilrUPuGO6VMDv/yVF +guPvHWfusfT57hl6hWhLWb4bT3ZpOLiasyGKIo8lAQKBgQD1CtzQI8Ri+Hpga9XG +5kzO19sggWYxBcVi3Z+IUw9JOV80rMQUJEoFiahyvpItAyFTOcjxYaBHi0zHK5ZK +hRXoc7nvbkha4eVfg3BeSyh+8xjTB754YNfImByso+rW9W+D3n6feFcN4nB3i9qm +vdgCw3ws5XvJjKlFFfUs6sI7/QKBgQDUkLMExgccllxGmzHL7K68oqKKPZsIANBs +FUIFDoGimlfrPdja8/viEDDi15ZhH3tv1LJUeC/aMaLgU2EGarRbYpdD9vKZLvPi +ydEboGFUNJbdnfKxTHeaUrE35xUv8b499bDKsCohW1r4hvadT+8uDr23JtL4SsqH ++ug4+L1cqQKBgQDU9FLAREU46c6Ymz6W87BOlkMmNa6U7foDmK07MUv4i/aUdYyW +II9/zolo5vtsSOseQ/rA4+ICKypXcSbUrmJCuMgfL42MBgNsBXOTTufro+KwC2vZ +e/grqR5KXs4JcBUw2hzbBB9Lvr2U9yLXg+cFR9RTxD/XAfpdQt7m4UJaFQKBgQDI +44vceg6kjNHehLN2J1QowIdeoMRQtvxC+YAwaTpI4xcuIoA8xZMKXgTljZv4ZBlz +Yg+7Vu7ahkiJOyOaPeP/7dhJiixSaxZhAhzWwCbbvuvJvIlt2He8aGRGEeVrL0t9 +ISKZHA5lAgKimGKf37iKzbGsU0vVDlIEWzN3DFViKQKBgHTpq5SeBp3NSnQw5a0y +6vPYtm0t/jysOy3UGIl7qf/P5Ob994E7gVluPN8r4wXcmYqw9/glT2pdqfoBeQmX +UZ0zvcbdTERoNbQP8xkoN6C/8kUxbCVY3TsvteZQbJ7XB1Lcvf5k3aVWYDKabEzX +6kat3P/xhuX2aBJ25n+DEmwt +-----END PRIVATE KEY----- diff --git a/static/cert/tempgen.pena.digital/README b/static/cert/tempgen.pena.digital/README index 5050078..61d86a8 100644 --- a/static/cert/tempgen.pena.digital/README +++ b/static/cert/tempgen.pena.digital/README @@ -1,14 +1,14 @@ -This directory contains your keys and certificates. - -`privkey.pem` : the private key for your certificate. -`fullchain.pem`: the certificate file used in most server software. -`chain.pem` : used for OCSP stapling in Nginx >=1.3.7. -`cert.pem` : will break many server configurations, and should not be used - without reading further documentation (see link below). - -WARNING: DO NOT MOVE OR RENAME THESE FILES! - Certbot expects these files to remain in this location in order - to function properly! - -We recommend not moving these files. For more information, see the Certbot -User Guide at https://certbot.eff.org/docs/using.html#where-are-my-certificates. +This directory contains your keys and certificates. + +`privkey.pem` : the private key for your certificate. +`fullchain.pem`: the certificate file used in most server software. +`chain.pem` : used for OCSP stapling in Nginx >=1.3.7. +`cert.pem` : will break many server configurations, and should not be used + without reading further documentation (see link below). + +WARNING: DO NOT MOVE OR RENAME THESE FILES! + Certbot expects these files to remain in this location in order + to function properly! + +We recommend not moving these files. For more information, see the Certbot +User Guide at https://certbot.eff.org/docs/using.html#where-are-my-certificates. diff --git a/static/cert/tempgen.pena.digital/cert.pem b/static/cert/tempgen.pena.digital/cert.pem index e500392..3737e72 100644 --- a/static/cert/tempgen.pena.digital/cert.pem +++ b/static/cert/tempgen.pena.digital/cert.pem @@ -1,26 +1,26 @@ ------BEGIN CERTIFICATE----- -MIIEZjCCA06gAwIBAgISBGHJAxiTkBlLfhA9Rwz3zwttMA0GCSqGSIb3DQEBCwUA -MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD -EwJSMzAeFw0yMzAyMTEwODUxMTNaFw0yMzA1MTIwODUxMTJaMBkxFzAVBgNVBAMM -DioucGVuYS5kaWdpdGFsMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5ZKYmhoJ -q5Tczk43XnFPp3dfnhDtgrkLvtu/0WSn0O1JWOtgN+G9onGWSXhsqUMtVDcxgeep -BXt+BtkochkjOqOCAlgwggJUMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggr -BgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUd/lblpWt -FJN7LdbxW+1dOU2srbMwHwYDVR0jBBgwFoAUFC6zF7dYVsuuUAlA5h+vnYsUwsYw -VQYIKwYBBQUHAQEESTBHMCEGCCsGAQUFBzABhhVodHRwOi8vcjMuby5sZW5jci5v -cmcwIgYIKwYBBQUHMAKGFmh0dHA6Ly9yMy5pLmxlbmNyLm9yZy8wJwYDVR0RBCAw -HoIOKi5wZW5hLmRpZ2l0YWyCDHBlbmEuZGlnaXRhbDBMBgNVHSAERTBDMAgGBmeB -DAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxl -dHNlbmNyeXB0Lm9yZzCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB3ALc++yTfnE26 -dfI5xbpY9Gxd/ELPep81xJ4dCYEl7bSZAAABhj/izVIAAAQDAEgwRgIhAL5qiwhk -g803FM7IvNH43IhGStn0jkJFLNTozliuvIddAiEAykIciMuuyItVE015iL5RujqU -LW7VKXqfNLNxYgwRooQAdgDoPtDaPvUGNTLnVyi8iWvJA9PL0RFr7Otp4Xd9bQa9 -bgAAAYY/4s1JAAAEAwBHMEUCIQCmcAd0nOedpkcswqTmWoY23vDchb02P7xk2svd -EpNRGwIgey5RzutYLEIagpDLah9rNIprriimqeEqhDkPbocshTUwDQYJKoZIhvcN -AQELBQADggEBABPHbpS0lshG8mJ+sWJ2Vaqd/4ld8DPZ9cCzIx/6/xQ3bUnoWACM -6qZhK9pZhmE7/m0ZOgZNay5cDGRwQv8SsrL7llyOpcvOm+pTB6u5OkapB70+BkxJ -v3EZ1CEzjJhWrbwF1eA3Bgd1c6vBoYbhVXHD1ok2i6HYdohwDKaLDwgypRb87MRM -k4fsm1+jFeZ1Y0ghhkXeSvO6HbptxSgqrQpQJ8gthFv0lB54H643IhsQkXjIAOtT -LEqMvQdF2Lums+xkWZOplgiNst+8C2HxVEErh7KDlvdBzOWkeRAdiXEqn/Zsizu3 -x3sOobCSAukTYM+Kj1UoAvwU10cnCy6RZiU= ------END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEZjCCA06gAwIBAgISBGHJAxiTkBlLfhA9Rwz3zwttMA0GCSqGSIb3DQEBCwUA +MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD +EwJSMzAeFw0yMzAyMTEwODUxMTNaFw0yMzA1MTIwODUxMTJaMBkxFzAVBgNVBAMM +DioucGVuYS5kaWdpdGFsMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5ZKYmhoJ +q5Tczk43XnFPp3dfnhDtgrkLvtu/0WSn0O1JWOtgN+G9onGWSXhsqUMtVDcxgeep +BXt+BtkochkjOqOCAlgwggJUMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggr +BgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUd/lblpWt +FJN7LdbxW+1dOU2srbMwHwYDVR0jBBgwFoAUFC6zF7dYVsuuUAlA5h+vnYsUwsYw +VQYIKwYBBQUHAQEESTBHMCEGCCsGAQUFBzABhhVodHRwOi8vcjMuby5sZW5jci5v +cmcwIgYIKwYBBQUHMAKGFmh0dHA6Ly9yMy5pLmxlbmNyLm9yZy8wJwYDVR0RBCAw +HoIOKi5wZW5hLmRpZ2l0YWyCDHBlbmEuZGlnaXRhbDBMBgNVHSAERTBDMAgGBmeB +DAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxl +dHNlbmNyeXB0Lm9yZzCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB3ALc++yTfnE26 +dfI5xbpY9Gxd/ELPep81xJ4dCYEl7bSZAAABhj/izVIAAAQDAEgwRgIhAL5qiwhk +g803FM7IvNH43IhGStn0jkJFLNTozliuvIddAiEAykIciMuuyItVE015iL5RujqU +LW7VKXqfNLNxYgwRooQAdgDoPtDaPvUGNTLnVyi8iWvJA9PL0RFr7Otp4Xd9bQa9 +bgAAAYY/4s1JAAAEAwBHMEUCIQCmcAd0nOedpkcswqTmWoY23vDchb02P7xk2svd +EpNRGwIgey5RzutYLEIagpDLah9rNIprriimqeEqhDkPbocshTUwDQYJKoZIhvcN +AQELBQADggEBABPHbpS0lshG8mJ+sWJ2Vaqd/4ld8DPZ9cCzIx/6/xQ3bUnoWACM +6qZhK9pZhmE7/m0ZOgZNay5cDGRwQv8SsrL7llyOpcvOm+pTB6u5OkapB70+BkxJ +v3EZ1CEzjJhWrbwF1eA3Bgd1c6vBoYbhVXHD1ok2i6HYdohwDKaLDwgypRb87MRM +k4fsm1+jFeZ1Y0ghhkXeSvO6HbptxSgqrQpQJ8gthFv0lB54H643IhsQkXjIAOtT +LEqMvQdF2Lums+xkWZOplgiNst+8C2HxVEErh7KDlvdBzOWkeRAdiXEqn/Zsizu3 +x3sOobCSAukTYM+Kj1UoAvwU10cnCy6RZiU= +-----END CERTIFICATE----- diff --git a/static/cert/tempgen.pena.digital/fullchain.pem b/static/cert/tempgen.pena.digital/fullchain.pem index cfbef0a..ffb3470 100644 --- a/static/cert/tempgen.pena.digital/fullchain.pem +++ b/static/cert/tempgen.pena.digital/fullchain.pem @@ -1,92 +1,92 @@ ------BEGIN CERTIFICATE----- -MIIFLjCCBBagAwIBAgISA2kKBRIxxoABL1n9QL6mzbWZMA0GCSqGSIb3DQEBCwUA -MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD -EwJSMzAeFw0yMzA2MTQxNzE4MDFaFw0yMzA5MTIxNzE4MDBaMB8xHTAbBgNVBAMT -FHRlbXBnZW4ucGVuYS5kaWdpdGFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAqNz9OoBpWMzrKOwtMYADgEkrVVQ8cCBvBREVx/Rnv9cLwjWBr0PD95Wf -oNdVpgpGt0vwaTYVbK6B4jsNQUnX3aMHL9A8ZqjGE65fdN5KsmIOp5RcIgL0v46Z -9puWSO1sw7F2Fx5YexYmXZgcf9Evfw1dUYnwjCtCx6l66PWKoGEmEzhCqobQ+ZbP -92hnZ7KaEGIVM0pHMkTFrpD449ZosbwVhChr5TjDkHC6Vui4ut2gZDavHWxbu2Ai -2GRU4Oem+KY3hrfw/vmaQ8/jyNBk2PJcjTLtaFmiPzM2pCR8vmJ0xjrZx5Y0GDc8 -RtJg1vTTglHkRb/pwle8AP+qNJbFYwIDAQABo4ICTzCCAkswDgYDVR0PAQH/BAQD -AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAA -MB0GA1UdDgQWBBQu9jY2x9RKv0yRqFwju2z7apwwUzAfBgNVHSMEGDAWgBQULrMX -t1hWy65QCUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0 -dHA6Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVu -Y3Iub3JnLzAfBgNVHREEGDAWghR0ZW1wZ2VuLnBlbmEuZGlnaXRhbDBMBgNVHSAE -RTBDMAgGBmeBDAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRw -Oi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2 -ALc++yTfnE26dfI5xbpY9Gxd/ELPep81xJ4dCYEl7bSZAAABiLsg/j0AAAQDAEcw -RQIhAMbDGXZHQI4Evauiri3lI9+HfL/kBoi41mnmM6AZgOZ5AiAWvlR5+ijoxUZF -ja62HaAIJb5/t0lRDwQvcov8WSrk/AB2AK33vvp8/xDIi509nB4+GGq0Zyldz7EM -JMqFhjTr3IKKAAABiLsg/tcAAAQDAEcwRQIhALTfrawjd5xQNOaTuwT/u2Kc25T1 -lpS25L7gNP09de6cAiBejGK1TMIm9hLnWD1B/tTvoD+GWpeVlTdWLYoFLzctqTAN -BgkqhkiG9w0BAQsFAAOCAQEAQwDyqHXnGV/JvEbTHmarIYcVYkLqXbKTHphf0AKC -FmuUxL3mUlvPIel/HTy6WxeLLrkdTTd/j2UkHMLqZk2MulcOh3K3kmRZwg3dha2j -E67ef5+s8obMWJDm4kg4JJT9+lsrfOP3VHhYtBaLN8iiUr02XQfZXEWKAQF35byi -8AszB5vaPfzEM5hNeOUeW8h4RVW1sBSdrUQdxLXBUSZxMUnFMJe4Wq7ru8xPCMSd -gC/DwMa8oHijafy1eCuXsshOqSoKI0sj2u272o8yn4SWJcwpk1PRidf7cIa4hAG3 -Rfw6afhczKB+9myjF2/zRNgklFtdSUEPWIjOQX9l2Z1R0A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw -WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg -RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP -R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx -sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm -NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg -Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG -/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC -AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB -Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA -FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw -AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw -Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB -gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W -PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl -ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz -CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm -lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 -avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 -yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O -yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids -hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ -HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv -MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX -nLRbwHOoq7hHwg== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC -ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL -wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D -LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK -4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5 -bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y -sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ -Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4 -FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc -SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql -PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND -TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw -SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1 -c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx -+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB -ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu -b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E -U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu -MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC -5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW -9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG -WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O -he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC -Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5 ------END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFLjCCBBagAwIBAgISA2kKBRIxxoABL1n9QL6mzbWZMA0GCSqGSIb3DQEBCwUA +MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD +EwJSMzAeFw0yMzA2MTQxNzE4MDFaFw0yMzA5MTIxNzE4MDBaMB8xHTAbBgNVBAMT +FHRlbXBnZW4ucGVuYS5kaWdpdGFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAqNz9OoBpWMzrKOwtMYADgEkrVVQ8cCBvBREVx/Rnv9cLwjWBr0PD95Wf +oNdVpgpGt0vwaTYVbK6B4jsNQUnX3aMHL9A8ZqjGE65fdN5KsmIOp5RcIgL0v46Z +9puWSO1sw7F2Fx5YexYmXZgcf9Evfw1dUYnwjCtCx6l66PWKoGEmEzhCqobQ+ZbP +92hnZ7KaEGIVM0pHMkTFrpD449ZosbwVhChr5TjDkHC6Vui4ut2gZDavHWxbu2Ai +2GRU4Oem+KY3hrfw/vmaQ8/jyNBk2PJcjTLtaFmiPzM2pCR8vmJ0xjrZx5Y0GDc8 +RtJg1vTTglHkRb/pwle8AP+qNJbFYwIDAQABo4ICTzCCAkswDgYDVR0PAQH/BAQD +AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAA +MB0GA1UdDgQWBBQu9jY2x9RKv0yRqFwju2z7apwwUzAfBgNVHSMEGDAWgBQULrMX +t1hWy65QCUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0 +dHA6Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVu +Y3Iub3JnLzAfBgNVHREEGDAWghR0ZW1wZ2VuLnBlbmEuZGlnaXRhbDBMBgNVHSAE +RTBDMAgGBmeBDAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRw +Oi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2 +ALc++yTfnE26dfI5xbpY9Gxd/ELPep81xJ4dCYEl7bSZAAABiLsg/j0AAAQDAEcw +RQIhAMbDGXZHQI4Evauiri3lI9+HfL/kBoi41mnmM6AZgOZ5AiAWvlR5+ijoxUZF +ja62HaAIJb5/t0lRDwQvcov8WSrk/AB2AK33vvp8/xDIi509nB4+GGq0Zyldz7EM +JMqFhjTr3IKKAAABiLsg/tcAAAQDAEcwRQIhALTfrawjd5xQNOaTuwT/u2Kc25T1 +lpS25L7gNP09de6cAiBejGK1TMIm9hLnWD1B/tTvoD+GWpeVlTdWLYoFLzctqTAN +BgkqhkiG9w0BAQsFAAOCAQEAQwDyqHXnGV/JvEbTHmarIYcVYkLqXbKTHphf0AKC +FmuUxL3mUlvPIel/HTy6WxeLLrkdTTd/j2UkHMLqZk2MulcOh3K3kmRZwg3dha2j +E67ef5+s8obMWJDm4kg4JJT9+lsrfOP3VHhYtBaLN8iiUr02XQfZXEWKAQF35byi +8AszB5vaPfzEM5hNeOUeW8h4RVW1sBSdrUQdxLXBUSZxMUnFMJe4Wq7ru8xPCMSd +gC/DwMa8oHijafy1eCuXsshOqSoKI0sj2u272o8yn4SWJcwpk1PRidf7cIa4hAG3 +Rfw6afhczKB+9myjF2/zRNgklFtdSUEPWIjOQX9l2Z1R0A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw +WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP +R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx +sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm +NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg +Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG +/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB +Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA +FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw +AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw +Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB +gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W +PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl +ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz +CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm +lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 +avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 +yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O +yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids +hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ +HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv +MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX +nLRbwHOoq7hHwg== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC +ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL +wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D +LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK +4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5 +bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y +sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ +Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4 +FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc +SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql +PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND +TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1 +c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx ++tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB +ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu +b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E +U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu +MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC +5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW +9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG +WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O +he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC +Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5 +-----END CERTIFICATE----- diff --git a/static/cert/tempgen.pena.digital/privkey.pem b/static/cert/tempgen.pena.digital/privkey.pem index 8f4af27..e09d088 100644 --- a/static/cert/tempgen.pena.digital/privkey.pem +++ b/static/cert/tempgen.pena.digital/privkey.pem @@ -1,28 +1,28 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCo3P06gGlYzOso -7C0xgAOASStVVDxwIG8FERXH9Ge/1wvCNYGvQ8P3lZ+g11WmCka3S/BpNhVsroHi -Ow1BSdfdowcv0DxmqMYTrl903kqyYg6nlFwiAvS/jpn2m5ZI7WzDsXYXHlh7FiZd -mBx/0S9/DV1RifCMK0LHqXro9YqgYSYTOEKqhtD5ls/3aGdnspoQYhUzSkcyRMWu -kPjj1mixvBWEKGvlOMOQcLpW6Li63aBkNq8dbFu7YCLYZFTg56b4pjeGt/D++ZpD -z+PI0GTY8lyNMu1oWaI/MzakJHy+YnTGOtnHljQYNzxG0mDW9NOCUeRFv+nCV7wA -/6o0lsVjAgMBAAECggEBAKbceH5ulariEx4FA0N+s/b4VpGjA3XpFsty7or/v+WZ -okzugo+l7uegOnS9VC0Wynol2BKfFtymNEJRB/AT//NLPbbJlmX7MIASNtFNN5K9 -wq1ltQUG1sLTLuC5LfAybN+TZJXDrrsyUAb8YG0NUFnD4wrHu6NGvF5/4qyAtdNz -kMFEqAJeatGinVH9NKZvVz0pGPv0JWj8aG3NssGmJSNy/sWO1ZfMWAnrG3pTI13N -9bEzyC7MR++oFzGbx02SuWllyoTi5YMP7SbdTYDrmh1aXIQ+OPSAnCAoQ40GjzJ0 -iDwHH8u3VnF1gq5Y+cp7DWxM/Lnu7s3WwkyLjbSCzsECgYEA2jKRay6d+h5DwVwA -AV6AC4W+YfvynPBNBkKVs5bGs+FrFhb0o0Iy5B1JoxhthExTph987bOw1/Rdok8X -yxOZk5JuJyYBoQiOEocNizXK/hseKBJXRAum/ET9PCPdX0RjHq91eTTWStk4dI3d -F0k4EWP/+Bk0TEMqdIfCgh1/Do0CgYEAxh5cfNIPjwmRzdqFLqWo12sLl//KI+WN -zNp8G0ZSYB38THYpVdBVSFLJ1y7dP/B6h/MIpy+m/tgeVg7WWqUB5X7z1aP8006Z -YoUnVlYDXYj3fZHOfDklUO+pnVCEOoD4v22E+YeO2mEiT0gDQ8jK7SlxOgmmLUY7 -GTm+1vEL368CgYANYy7i6aBNuU+k7HUfoGGw00rkDiZLlL7VFH7E3wpf/QOp/kyS -O7yNnHJpLFWD2X8EYUgz+WNvTJH2JG4sSo6QrFpP0pgk/jZhUqH1GZ7TymwmP0HV -bfWX4s+6weSSNMr0FgXaIvDG9N7u38lh5V8oSf9phHpd930CW1YGz7J8/QKBgQDC -INPtdwPJ282j0UB5MdgcpQZqPTj8LZ3hoiDDtQdYqWkkHxBnxskaIg0nLgOb+G6I -MgtDjvzqcChhmQ5PKaqPDvOsXpCJGVZQ5DpkbcnEaEZiI3IZ5QD8qqofvNqkXOXg -5VbMDxlaQJ2W4/BXBjRZaSdKgFP1vwB/ukaWZQGGfwKBgDqOk629Py3DUbqNBNcd -tA5UJ0YKQ+u26gMVLzE6taZsNXxzci2cpLuUwLBaVyDiaydZeRXnss9ayUwXEVP5 -xTcyVdxAoW4cpjTjMPulpjXduMCzYTweQuXVpI8aQ51adlxCvSyE4j1wffY6YVdN -E7FuJt0KKfULcJzcAc+f0qsg ------END PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCo3P06gGlYzOso +7C0xgAOASStVVDxwIG8FERXH9Ge/1wvCNYGvQ8P3lZ+g11WmCka3S/BpNhVsroHi +Ow1BSdfdowcv0DxmqMYTrl903kqyYg6nlFwiAvS/jpn2m5ZI7WzDsXYXHlh7FiZd +mBx/0S9/DV1RifCMK0LHqXro9YqgYSYTOEKqhtD5ls/3aGdnspoQYhUzSkcyRMWu +kPjj1mixvBWEKGvlOMOQcLpW6Li63aBkNq8dbFu7YCLYZFTg56b4pjeGt/D++ZpD +z+PI0GTY8lyNMu1oWaI/MzakJHy+YnTGOtnHljQYNzxG0mDW9NOCUeRFv+nCV7wA +/6o0lsVjAgMBAAECggEBAKbceH5ulariEx4FA0N+s/b4VpGjA3XpFsty7or/v+WZ +okzugo+l7uegOnS9VC0Wynol2BKfFtymNEJRB/AT//NLPbbJlmX7MIASNtFNN5K9 +wq1ltQUG1sLTLuC5LfAybN+TZJXDrrsyUAb8YG0NUFnD4wrHu6NGvF5/4qyAtdNz +kMFEqAJeatGinVH9NKZvVz0pGPv0JWj8aG3NssGmJSNy/sWO1ZfMWAnrG3pTI13N +9bEzyC7MR++oFzGbx02SuWllyoTi5YMP7SbdTYDrmh1aXIQ+OPSAnCAoQ40GjzJ0 +iDwHH8u3VnF1gq5Y+cp7DWxM/Lnu7s3WwkyLjbSCzsECgYEA2jKRay6d+h5DwVwA +AV6AC4W+YfvynPBNBkKVs5bGs+FrFhb0o0Iy5B1JoxhthExTph987bOw1/Rdok8X +yxOZk5JuJyYBoQiOEocNizXK/hseKBJXRAum/ET9PCPdX0RjHq91eTTWStk4dI3d +F0k4EWP/+Bk0TEMqdIfCgh1/Do0CgYEAxh5cfNIPjwmRzdqFLqWo12sLl//KI+WN +zNp8G0ZSYB38THYpVdBVSFLJ1y7dP/B6h/MIpy+m/tgeVg7WWqUB5X7z1aP8006Z +YoUnVlYDXYj3fZHOfDklUO+pnVCEOoD4v22E+YeO2mEiT0gDQ8jK7SlxOgmmLUY7 +GTm+1vEL368CgYANYy7i6aBNuU+k7HUfoGGw00rkDiZLlL7VFH7E3wpf/QOp/kyS +O7yNnHJpLFWD2X8EYUgz+WNvTJH2JG4sSo6QrFpP0pgk/jZhUqH1GZ7TymwmP0HV +bfWX4s+6weSSNMr0FgXaIvDG9N7u38lh5V8oSf9phHpd930CW1YGz7J8/QKBgQDC +INPtdwPJ282j0UB5MdgcpQZqPTj8LZ3hoiDDtQdYqWkkHxBnxskaIg0nLgOb+G6I +MgtDjvzqcChhmQ5PKaqPDvOsXpCJGVZQ5DpkbcnEaEZiI3IZ5QD8qqofvNqkXOXg +5VbMDxlaQJ2W4/BXBjRZaSdKgFP1vwB/ukaWZQGGfwKBgDqOk629Py3DUbqNBNcd +tA5UJ0YKQ+u26gMVLzE6taZsNXxzci2cpLuUwLBaVyDiaydZeRXnss9ayUwXEVP5 +xTcyVdxAoW4cpjTjMPulpjXduMCzYTweQuXVpI8aQ51adlxCvSyE4j1wffY6YVdN +E7FuJt0KKfULcJzcAc+f0qsg +-----END PRIVATE KEY----- diff --git a/templategen/amoDataConverter.go b/templategen/amoDataConverter.go index 0f8bed8..2a9f669 100644 --- a/templategen/amoDataConverter.go +++ b/templategen/amoDataConverter.go @@ -8,7 +8,7 @@ import ( func AmoLeadFieldsToRuMap(data *amo.Lead) map[string]interface{} { result := map[string]interface{}{ - "ID": data.Id, + "ID": data.ID, "Название": data.Name, "Бюджет": data.Price, "Создатель": data.CreatedBy, diff --git a/templategen/examples.go b/templategen/examples.go index 4e59c93..44efc7b 100644 --- a/templategen/examples.go +++ b/templategen/examples.go @@ -1,8 +1,9 @@ package templategen import ( - docTemp "github.com/danilsolovyov/doc-template" "strings" + + docTemp "github.com/danilsolovyov/doc-template" ) func ExampleGenerate(filename string, data any) (string, error) { diff --git a/templategen/funcs.go b/templategen/funcs.go index 2a2b78c..01ee904 100644 --- a/templategen/funcs.go +++ b/templategen/funcs.go @@ -13,7 +13,7 @@ var ( ) // indexArg checks if a reflect.Value can be used as an index, and converts it to int if possible. -func indexArg(index reflect.Value, cap int) (int, error) { +func indexArg(index reflect.Value, caps int) (int, error) { var x int64 switch index.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: @@ -25,7 +25,7 @@ func indexArg(index reflect.Value, cap int) (int, error) { default: return 0, fmt.Errorf("cannot index slice/array with type %s", index.Type()) } - if x < 0 || int(x) < 0 || int(x) >= cap { + if x < 0 || int(x) < 0 || int(x) >= caps { return 0, fmt.Errorf("index out of range: %d", x) } return int(x), nil @@ -80,11 +80,12 @@ func index(item reflect.Value, indexes ...reflect.Value) (reflect.Value, error) case reflect.Array, reflect.Slice, reflect.String: x, err := indexArg(index, item.Len()) if err != nil { - return reflect.Value{}, nil + return reflect.Value{}, err } item = item.Index(x) case reflect.Map: - index, err := prepareArg(index, item.Type().Key()) + var err error + index, err = prepareArg(index, item.Type().Key()) if err != nil { return reflect.Value{}, err } diff --git a/templategen/funcsExec.go b/templategen/funcsExec.go index 06f8b09..abc0eef 100644 --- a/templategen/funcsExec.go +++ b/templategen/funcsExec.go @@ -1,49 +1,13 @@ package templategen import ( - "fmt" "reflect" - "runtime" - "strings" ) var ( - errorType = reflect.TypeOf((*error)(nil)).Elem() - fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() reflectValueType = reflect.TypeOf((*reflect.Value)(nil)).Elem() ) -// maxExecDepth specifies the maximum stack depth of templates within -// templates. This limit is only practically reached by accidentally -// recursive template invocations. This limit allows us to return -// an error instead of triggering a stack overflow. -var maxExecDepth = initMaxExecDepth() - -func initMaxExecDepth() int { - if runtime.GOARCH == "wasm" { - return 1000 - } - return 100000 -} - -// variable holds the dynamic value of a variable such as $, $x etc. -type variable struct { - name string - value reflect.Value -} - -var zero reflect.Value - -type missingValType struct{} - -var missingVal = reflect.ValueOf(missingValType{}) - -// doublePercent returns the string with %'s replaced by %%, if necessary, -// so it can be used safely inside a Printf format string. -func doublePercent(str string) string { - return strings.ReplaceAll(str, "%", "%%") -} - // TODO: It would be nice if ExecError was more broken down, but // the way ErrorContext embeds the template name makes the // processing too clumsy. @@ -64,42 +28,6 @@ func (e ExecError) Unwrap() error { return e.Err } -// writeError is the wrapper type used internally when Execute has an -// error writing to its output. We strip the wrapper in errRecover. -// Note that this is not an implementation of error, so it cannot escape -// from the package as an error value. -type writeError struct { - Err error // Original error. -} - -func isTrue(val reflect.Value) (truth, ok bool) { - if !val.IsValid() { - // Something like var x interface{}, never set. It's a form of nil. - return false, true - } - switch val.Kind() { - case reflect.Array, reflect.Map, reflect.Slice, reflect.String: - truth = val.Len() > 0 - case reflect.Bool: - truth = val.Bool() - case reflect.Complex64, reflect.Complex128: - truth = val.Complex() != 0 - case reflect.Chan, reflect.Func, reflect.Pointer, reflect.Interface: - truth = !val.IsNil() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - truth = val.Int() != 0 - case reflect.Float32, reflect.Float64: - truth = val.Float() != 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - truth = val.Uint() != 0 - case reflect.Struct: - truth = true // Struct values are always true. - default: - return - } - return truth, true -} - // canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero. func canBeNil(typ reflect.Type) bool { switch typ.Kind() { diff --git a/templategen/gdisk.go b/templategen/gdisk.go index 284160e..c14fabe 100644 --- a/templategen/gdisk.go +++ b/templategen/gdisk.go @@ -4,7 +4,7 @@ import ( GDisk "penahub.gitlab.yandexcloud.net/backend/templategen/gdisk" ) -func GDiskGenerateDoc(file, name, userID, saveFolderID string, client *GDisk.Client, data interface{}) (string, string, error) { +func GDiskGenerateDoc(file, name, saveFolderID string, client *GDisk.Client, data interface{}) (string, string, error) { filename := GenerateDocName(name, "gf") // Download file @@ -22,23 +22,27 @@ func GDiskGenerateDoc(file, name, userID, saveFolderID string, client *GDisk.Cli } // Upload file - fileId, exportUrl, err := client.UploadFile( + fileID, exportURL, err := client.UploadFile( TempGenerated+"/"+filename, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", saveFolderID) + if err != nil { + return "", "", err + } + // Delete temps err = DeleteDocument(downloaded) if err != nil { - return fileId, exportUrl, err + return fileID, exportURL, err } err = DeleteDocument(generated) - return fileId, exportUrl, err + return fileID, exportURL, err } -func GDiskGenerateDocBytes(fileID, name, userID, saveFolderID string, client *GDisk.Client, data interface{}) (string, string, error) { +func GDiskGenerateDocBytes(fileID, name, saveFolderID string, client *GDisk.Client, data interface{}) (string, string, error) { filename := GenerateDocName(name, "gf") // Download fileID @@ -55,11 +59,11 @@ func GDiskGenerateDocBytes(fileID, name, userID, saveFolderID string, client *GD } // Upload fileID - fileId, exportUrl, err := client.UploadFileBytes( + resultFileID, exportURL, err := client.UploadFileBytes( resultBytes, filename, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", saveFolderID) - return fileId, exportUrl, err + return resultFileID, exportURL, err } diff --git a/templategen/penadisk.go b/templategen/penadisk.go index 507ae54..c3a4645 100644 --- a/templategen/penadisk.go +++ b/templategen/penadisk.go @@ -2,13 +2,15 @@ package templategen import ( "bytes" + "context" "fmt" "os" - "penahub.gitlab.yandexcloud.net/backend/templategen/penadisk" "time" + + "penahub.gitlab.yandexcloud.net/backend/templategen/penadisk" ) -func PenaDiskGenerateDoc(file, name, userID, saveFolder string, client *penadisk.Client, data interface{}) (string, string, error) { +func PenaDiskGenerateDoc(ctx context.Context, file, name, saveFolder string, client *penadisk.Client, data interface{}) (string, string, error) { d, ok := data.(map[string]interface{}) fmt.Println("data", data) var fio string @@ -30,7 +32,7 @@ func PenaDiskGenerateDoc(file, name, userID, saveFolder string, client *penadisk // Download file downloaded := TempDownloaded + "/" + filename - err := client.DownloadResource(file, downloaded) + err := client.DownloadResource(ctx, file, downloaded) if err != nil { return "", "", err } @@ -43,12 +45,15 @@ func PenaDiskGenerateDoc(file, name, userID, saveFolder string, client *penadisk } out, err := os.Open(generated) - defer out.Close() + if err != nil { + return "", "", err } + defer out.Close() //nolint + // Upload file - filePath, exportUrl, err := client.UploadResources(saveFolder+"/"+filename, filename, true, out) + filePath, exportURL, err := client.UploadResources(ctx, saveFolder+"/"+filename, filename, true, out) if err != nil { return "", "", err } @@ -56,15 +61,15 @@ func PenaDiskGenerateDoc(file, name, userID, saveFolder string, client *penadisk // Delete temps err = DeleteDocument(downloaded) if err != nil { - return filePath, exportUrl, err + return filePath, exportURL, err } err = DeleteDocument(generated) - return filePath, exportUrl, err + return filePath, exportURL, err } -func PenaDiskGenerateDocBytes(file, name, userID, saveFolder string, client *penadisk.Client, data interface{}) (string, string, error) { +func PenaDiskGenerateDocBytes(ctx context.Context, file, name, saveFolder string, client *penadisk.Client, data interface{}) (string, string, error) { d, ok := data.(map[string]interface{}) fmt.Println("data", data) var fio string @@ -85,21 +90,25 @@ func PenaDiskGenerateDocBytes(file, name, userID, saveFolder string, client *pen filename := GenerateDocName(name, fio) // Download file - fileBytes, err := client.DownloadResourceBytes(file) + fileBytes, err := client.DownloadResourceBytes(ctx, file) if err != nil { return "", "", err } // Generate file result, err := GenerateBytesFile(fileBytes, data) - fmt.Println("FILELEN", len(result), string(fileBytes)) - out := bytes.NewReader(result) - - // Upload file - filePath, exportUrl, err := client.UploadResources(saveFolder, filename, true, out) if err != nil { return "", "", err } - return filePath, exportUrl, err + fmt.Println("FILELEN", len(result), string(fileBytes)) + out := bytes.NewReader(result) + + // Upload file + filePath, exportURL, err := client.UploadResources(ctx, saveFolder, filename, true, out) + if err != nil { + return "", "", err + } + + return filePath, exportURL, err } diff --git a/templategen/templategen.go b/templategen/templategen.go index 7355ec6..65537d4 100644 --- a/templategen/templategen.go +++ b/templategen/templategen.go @@ -1,6 +1,7 @@ package templategen import ( + "context" "fmt" "io" "net/http" @@ -49,9 +50,14 @@ func GenerateBytesFile(file []byte, data interface{}) ([]byte, error) { return dc.ExecuteBytes(data) } -// DownloadDocument - загружает документ в filepath из url -func DownloadDocument(filepath, url string) error { - resp, err := http.Get(url) +// DownloadDocument - загружает документ в filepath из url. +func DownloadDocument(ctx context.Context, filepath, url string) error { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody) + if err != nil { + return err + } + + resp, err := http.DefaultClient.Do(req) if err != nil { return err @@ -63,7 +69,7 @@ func DownloadDocument(filepath, url string) error { if err != nil { return err } - defer out.Close() + defer out.Close() //nolint // Write the body to file _, err = io.Copy(out, resp.Body) @@ -73,7 +79,3 @@ func DownloadDocument(filepath, url string) error { func DeleteDocument(filepath string) error { return os.Remove(filepath) } - -func ShareDocument(filepath string) (error, string) { - return nil, "" -} diff --git a/templategen/yadisk.go b/templategen/yadisk.go index 113f295..6da7822 100644 --- a/templategen/yadisk.go +++ b/templategen/yadisk.go @@ -2,6 +2,7 @@ package templategen import ( "bytes" + "context" "fmt" "os" "time" @@ -9,7 +10,7 @@ import ( YaDisk "penahub.gitlab.yandexcloud.net/backend/templategen/yadisk" ) -func YaDiskGenerateDoc(file, name, userID, saveFolder string, client *YaDisk.Client, data interface{}) (string, string, error) { +func YaDiskGenerateDoc(ctx context.Context, file, name, saveFolder string, client *YaDisk.Client, data interface{}) (string, string, error) { d, ok := data.(map[string]interface{}) fmt.Println("data", data) var fio string @@ -31,7 +32,7 @@ func YaDiskGenerateDoc(file, name, userID, saveFolder string, client *YaDisk.Cli // Download file downloaded := TempDownloaded + "/" + filename - err := client.DownloadResource(file, downloaded) + err := client.DownloadResource(ctx, file, downloaded) if err != nil { return "", "", err } @@ -44,12 +45,14 @@ func YaDiskGenerateDoc(file, name, userID, saveFolder string, client *YaDisk.Cli } out, err := os.Open(generated) - defer out.Close() if err != nil { + return "", "", err } + defer out.Close() //nolint + // Upload file - filePath, exportUrl, err := client.UploadResources(saveFolder+"/"+filename, out) + filePath, exportURL, err := client.UploadResources(ctx, saveFolder+"/"+filename, out) if err != nil { return "", "", err } @@ -57,15 +60,15 @@ func YaDiskGenerateDoc(file, name, userID, saveFolder string, client *YaDisk.Cli // Delete temps err = DeleteDocument(downloaded) if err != nil { - return filePath, exportUrl, err + return filePath, exportURL, err } err = DeleteDocument(generated) - return filePath, exportUrl, err + return filePath, exportURL, err } -func YaDiskGenerateDocBytes(file, name, userID, saveFolder string, client *YaDisk.Client, data interface{}) (string, string, error) { +func YaDiskGenerateDocBytes(ctx context.Context, file, name, saveFolder string, client *YaDisk.Client, data interface{}) (string, string, error) { d, ok := data.(map[string]interface{}) fmt.Println("data", data) var fio string @@ -86,17 +89,24 @@ func YaDiskGenerateDocBytes(file, name, userID, saveFolder string, client *YaDis filename := GenerateDocName(name, fio) // Download file - fileBytes, err := client.DownloadResourcesBytes(file) - - // Generate file - result, err := GenerateBytesFile(fileBytes, data) - resultReader := bytes.NewReader(result) - - // Upload file - filePath, exportUrl, err := client.UploadResources(saveFolder+"/"+filename, resultReader) + fileBytes, err := client.DownloadResourcesBytes(ctx, file) if err != nil { return "", "", err } - return filePath, exportUrl, err + // Generate file + result, err := GenerateBytesFile(fileBytes, data) + if err != nil { + return "", "", err + } + + resultReader := bytes.NewReader(result) + + // Upload file + filePath, exportURL, err := client.UploadResources(ctx, saveFolder+"/"+filename, resultReader) + if err != nil { + return "", "", err + } + + return filePath, exportURL, err } diff --git a/tools/token.go b/tools/token.go index 097418e..ac21dc7 100644 --- a/tools/token.go +++ b/tools/token.go @@ -1,23 +1,27 @@ package tools import ( - "crypto/rc4" + "crypto/aes" "encoding/hex" "encoding/json" ) -const ( - TokenKey = "z1eRU{fq*VtfLAszrz" +var ( + TokenKey = "z1eRU{fq*VtfLAszrz" //nolint ) -type StateToken struct { - UserID string `json:"user_id"` - Service string `json:"service"` // yandex, google, etc - RedirectUrl string `json:"redirect_url"` +func SetToken(token string) { + TokenKey = token } -func EncryptTokenRC4(data any) (string, error) { - cipher, err := rc4.NewCipher([]byte(TokenKey)) +type StateToken struct { + PenaID string `json:"pena_id"` + Service string `json:"service"` // yandex, google, etc + RedirectURL string `json:"redirect_url"` +} + +func EncryptTokenAES(data any) (string, error) { + cipher, err := aes.NewCipher([]byte(TokenKey)) if err != nil { return "", err @@ -29,13 +33,13 @@ func EncryptTokenRC4(data any) (string, error) { } encrypted := make([]byte, len(msg)) - cipher.XORKeyStream(encrypted, msg) + cipher.Encrypt(encrypted, msg) return hex.EncodeToString(encrypted), nil } -func DecryptTokenRC4(data string, result any) error { - cipher, err := rc4.NewCipher([]byte(TokenKey)) +func DecryptTokenAES(data string, result any) error { + cipher, err := aes.NewCipher([]byte(TokenKey)) if err != nil { return err @@ -49,7 +53,7 @@ func DecryptTokenRC4(data string, result any) error { decrypted := make([]byte, len(msg)) - cipher.XORKeyStream(decrypted, msg) + cipher.Decrypt(decrypted, msg) err = json.Unmarshal(decrypted, &result) if err != nil { diff --git a/worker/tariff.go b/worker/tariff.go new file mode 100644 index 0000000..9268ddf --- /dev/null +++ b/worker/tariff.go @@ -0,0 +1,193 @@ +package worker + +import ( + "context" + "time" + + "go.uber.org/zap" + "penahub.gitlab.yandexcloud.net/backend/templategen/broker/tariff" + "penahub.gitlab.yandexcloud.net/backend/templategen/broker/tariff/models" + "penahub.gitlab.yandexcloud.net/backend/templategen/dal" + "penahub.gitlab.yandexcloud.net/backend/templategen/penadisk" + "penahub.gitlab.yandexcloud.net/backend/templategen/privileges" +) + +/* TODO: Сделать рефакторинг кода! +Какой то колхоз с привилегиями получился. +Сейчас у меня 3 разных модели привилегий из разных пакетов: boker\tariff\models, proto, privileges. +*/ + +type TariffWorkerDeps struct { + Logger *zap.Logger + Dal *dal.MongoDAL + TariffConsumer *tariff.Consumer + PrivilegesDomain string +} + +type TariffWorker struct { + logger *zap.Logger + dal *dal.MongoDAL + tariffConsumer *tariff.Consumer + privilegesDomain string +} + +func NewTariffWorker(deps TariffWorkerDeps) *TariffWorker { + return &TariffWorker{ + logger: deps.Logger, + dal: deps.Dal, + tariffConsumer: deps.TariffConsumer, + privilegesDomain: deps.PrivilegesDomain, + } +} + +func (w *TariffWorker) Run(ctx context.Context) { + ticker := time.NewTicker(5 * time.Minute) + + for { + select { + case <-ctx.Done(): + w.logger.Info("tariff worker done") + return + case <-ticker.C: + w.Do(ctx) + } + } +} + +func (w *TariffWorker) Do(ctx context.Context) { + // получаем актуальные привилегии + getActualPrivileges, err := privileges.GetActualPrivileges(ctx, w.privilegesDomain) + + if err != nil { + w.logger.Error("cannot get actual privileges") + return + } + + actualPrivileges := make(map[string]models.Privilege) + + for _, privilege := range getActualPrivileges { + actualPrivileges[privilege.ID] = models.Privilege{ + ID: privilege.ID, + Amount: 0, + PrivilegeID: privilege.PrivilegeID, + Name: privilege.Name, + ServiceKey: privilege.ServiceKey, + Description: privilege.Description, + Type: privilege.Type, + Value: privilege.Value, + Price: privilege.Price, + IsDeleted: privilege.IsDeleted, + CreatedAt: privilege.CreatedAt, + UpdatedAt: privilege.UpdatedAt, + DeletedAt: privilege.DeletedAt, + } + } + + // проверяем новые тарифы + tariffs := w.tariffConsumer.FetchTariffs(ctx) + + for _, tariff := range tariffs { + penadisk := penadisk.NewClient(tariff.UserID) + + for _, newPrivilege := range tariff.Privileges { + if newPrivilege.ServiceKey != models.ServiceKey { + continue + } + + privilege := actualPrivileges[newPrivilege.ID] + privilege.Amount = newPrivilege.Amount + + if err = w.dal.Amo.AddPrivilege(ctx, + tariff.UserID, + privilege.PrivilegeID, + privilege.Amount); err != nil { + w.logger.Error("cannot add privilege", + zap.Error(err), + zap.String("user_id", tariff.UserID), + zap.String("privilege_id", privilege.PrivilegeID)) + } + + // передаем в penahub disk запрос на изменение размера диска пользователя + if privilege.PrivilegeID == models.PrivilegeTemplateStorage { + if err = penadisk.SetBucketQuota(ctx, uint64(privilege.Amount)<<20); err != nil { + w.logger.Error("cannot set bucket quota", + zap.Error(err), + zap.String("user_id", tariff.UserID), + zap.String("privilege_id", privilege.PrivilegeID)) + } + } + } + } + + // получаем пользователей + amos, err := w.dal.Amo.GetAll(ctx) + + if err != nil { + w.logger.Error("cannot get all amos", zap.Error(err)) + return + } + + for _, amo := range amos { + penadisk := penadisk.NewClient(amo.PenaID) + + for privilegeID, privilege := range amo.Privileges { + // проверяем истекшие привилегии + if privilegeID == models.PrivilegeTemplateUnlimTime && + privilege.CreatedAt.AddDate(0, 0, int(privilege.Amount)).After(time.Now()) { + if err = w.dal.Amo.DeletePrivilege(ctx, amo.ID, privilegeID); err != nil { + w.logger.Error("cannot delete privilege", + zap.Error(err), + zap.String("amo_id", amo.ID), + zap.String("privilege_id", privilegeID)) + } + } + + // обновляем базовую привилегию на количество, если она закончилась и прошел месяц + if privilegeID == models.PrivilegeTemplateCount && + privilege.Amount == 0 && + privilege.CreatedAt.AddDate(0, 1, 0).Before(time.Now()) { + if err = w.dal.Amo.AddPrivilege(ctx, + amo.ID, + privilegeID, + models.BasicAmountPrivilegeTemplateCount); err != nil { + w.logger.Error("cannot add privilege", + zap.Error(err), + zap.String("amo_ID", amo.ID), + zap.String("privilege_id", privilegeID)) + } + } + } + + // добавляем базовые привилегии если у пользователя нет никаких + if len(amo.Privileges) == 0 { + // привилегия на количество генераций + if err = w.dal.Amo.AddPrivilege(ctx, + amo.ID, + models.PrivilegeTemplateCount, + models.BasicAmountPrivilegeTemplateCount); err != nil { + w.logger.Error("cannot add privilege", + zap.Error(err), + zap.String("amo_ID", amo.ID), + zap.String("privilege_id", models.PrivilegeTemplateCount)) + } + + // привилегия на объем диска + if err = w.dal.Amo.AddPrivilege(ctx, + amo.ID, + models.PrivilegeTemplateStorage, + models.BasicAmountPrivilegeTemplateStorage); err != nil { + w.logger.Error("cannot add privilege", + zap.Error(err), + zap.String("amo_ID", amo.ID), + zap.String("privilege_id", models.PrivilegeTemplateStorage)) + } + + if err := penadisk.SetBucketQuota(ctx, 100<<20); err != nil { + w.logger.Error("cannot set bucket quota", + zap.Error(err), + zap.String("user_id", amo.PenaID), + zap.String("privilege_id", models.PrivilegeTemplateStorage)) + } + } + } +} diff --git a/yadisk/api.go b/yadisk/api.go index 9d215b4..9906f5a 100644 --- a/yadisk/api.go +++ b/yadisk/api.go @@ -1,4 +1,4 @@ -package YaDisk +package yadisk import ( "context" @@ -18,12 +18,12 @@ import ( ) const ( - BASE_URL = "https://cloud-api.yandex.net" - OAUTH_URL = "https://oauth.yandex.ru" - V1_DISK_API = BASE_URL + "/v1/disk" - DEFAULT_FOLDER = "disk:/templategen" - DEFAULT_TEMPLATE_FOLDER = DEFAULT_FOLDER + "/templates" - DEFAULT_SAVE_FOLDER = DEFAULT_FOLDER + "/saved" + BaseURL = "https://cloud-api.yandex.net" + OauthURL = "https://oauth.yandex.ru" + V1DiskAPI = BaseURL + "/v1/disk" + DefaultFolder = "disk:/templategen" + DefaultTemplateFolder = DefaultFolder + "/templates" + DefaultSaveFolder = DefaultFolder + "/saved" ) type Client struct { @@ -34,30 +34,30 @@ type Client struct { type ClientApp struct { Config *oauth2.Config - ServiceUrl string + ServiceURL string } -func NewClientApp(clientID, clientSecret, redirectUri, serviceUrl string) *ClientApp { +func NewClientApp(clientID, clientSecret, redirectURI, serviceURL string) *ClientApp { return &ClientApp{ Config: &oauth2.Config{ ClientID: clientID, ClientSecret: clientSecret, Endpoint: oauth2.Endpoint{ - AuthURL: OAUTH_URL + "/authorize", - TokenURL: OAUTH_URL + "/token", + AuthURL: OauthURL + "/authorize", + TokenURL: OauthURL + "/token", }, - RedirectURL: redirectUri, + RedirectURL: redirectURI, Scopes: nil, }, - ServiceUrl: serviceUrl, + ServiceURL: serviceURL, } } -func (ca *ClientApp) GenerateOAuthUrl(userId, redirectUrl string) (string, error) { - state, err := tools.EncryptTokenRC4(tools.StateToken{ - UserID: userId, +func (ca *ClientApp) GenerateOAuthURL(penaID, redirectURL string) (string, error) { + state, err := tools.EncryptTokenAES(tools.StateToken{ + PenaID: penaID, Service: "yandex", - RedirectUrl: redirectUrl, + RedirectURL: redirectURL, }) if err != nil { @@ -99,8 +99,8 @@ func (ca *ClientApp) RefreshToken(ctx context.Context, oldToken *oauth2.Token) ( return token, nil } -func (c *Client) GetDisk() (*Disk, error) { - req, err := http.NewRequest("GET", V1_DISK_API, nil) +func (c *Client) GetDisk(ctx context.Context) (*Disk, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, V1DiskAPI, http.NoBody) if err != nil { return nil, err } @@ -111,6 +111,8 @@ func (c *Client) GetDisk() (*Disk, error) { return nil, err } + defer resp.Body.Close() + err = checkError(resp) if err != nil { return nil, err @@ -125,8 +127,8 @@ func (c *Client) GetDisk() (*Disk, error) { return &r, nil } -func (c *Client) GetUser() (*User, error) { - disk, err := c.GetDisk() +func (c *Client) GetUser(ctx context.Context) (*User, error) { + disk, err := c.GetDisk(ctx) if err != nil { return nil, err } @@ -144,7 +146,7 @@ func (c *Client) DownloadFile(path string) (*DResp, error) { data := url.Values{} data.Set("path", path) - req, err := http.NewRequest("GET", V1_DISK_API+"/resources/download?"+data.Encode(), nil) + req, err := http.NewRequest(http.MethodGet, V1DiskAPI+"/resources/download?"+data.Encode(), http.NoBody) if err != nil { return nil, err } @@ -154,6 +156,8 @@ func (c *Client) DownloadFile(path string) (*DResp, error) { return nil, err } + defer res.Body.Close() + if err := checkError(res); err != nil { return nil, err } @@ -167,7 +171,7 @@ func (c *Client) DownloadFile(path string) (*DResp, error) { return &resp, nil } -func (c *Client) GetResources(path string, limit, offset int) (*Resource, error) { +func (c *Client) GetResources(ctx context.Context, path string, limit, offset int) (*Resource, error) { if path == "" { path = "disk:/" } @@ -184,7 +188,7 @@ func (c *Client) GetResources(path string, limit, offset int) (*Resource, error) data.Encode() - req, err := http.NewRequest("GET", V1_DISK_API+"/resources?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, V1DiskAPI+"/resources?"+data.Encode(), http.NoBody) if err != nil { return nil, err @@ -195,7 +199,9 @@ func (c *Client) GetResources(path string, limit, offset int) (*Resource, error) return nil, err } - if resp.StatusCode == 404 { + defer resp.Body.Close() + + if resp.StatusCode == http.StatusNotFound { return nil, nil } @@ -210,53 +216,60 @@ func (c *Client) GetResources(path string, limit, offset int) (*Resource, error) return &r, err } -func (c *Client) DownloadResource(path, downloadPath string) error { - res, err := c.GetResources(path, 0, 0) +func (c *Client) DownloadResource(ctx context.Context, path, downloadPath string) error { + res, err := c.GetResources(ctx, path, 0, 0) + if err != nil { + return err + } if res == nil { return errors.New("file not found") } - if err != nil { - return err - } - - resp, err := http.Get(res.File) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, res.File, http.NoBody) if err != nil { return err } - defer resp.Body.Close() + resp, err := http.DefaultClient.Do(req) if checkError(resp) != nil { return err } + defer resp.Body.Close() + // Create the file out, err := os.Create(downloadPath) if err != nil { return err } - defer out.Close() + defer out.Close() //nolint // Write the body to file _, err = io.Copy(out, resp.Body) return err } -func (c *Client) DownloadResourcesBytes(path string) ([]byte, error) { - res, err := c.GetResources(path, 0, 0) - - if res == nil { - return nil, errors.New("file not found") - } +func (c *Client) DownloadResourcesBytes(ctx context.Context, path string) ([]byte, error) { + res, err := c.GetResources(ctx, path, 0, 0) if err != nil { return nil, err } - resp, err := http.Get(res.File) + if res == nil { + return nil, errors.New("file not found") + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, res.File, http.NoBody) + + if err != nil { + return nil, err + } + + resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err @@ -271,11 +284,11 @@ func (c *Client) DownloadResourcesBytes(path string) ([]byte, error) { return io.ReadAll(resp.Body) } -// PutResources - создание папки +// PutResources - создание папки. func (c *Client) PutResources(path string) (*RespPutResources, error) { data := url.Values{} data.Set("path", path) - req, err := http.NewRequest("PUT", V1_DISK_API+"/resources?"+data.Encode(), nil) + req, err := http.NewRequest(http.MethodPut, V1DiskAPI+"/resources?"+data.Encode(), http.NoBody) if err != nil { return nil, err } @@ -285,7 +298,9 @@ func (c *Client) PutResources(path string) (*RespPutResources, error) { return nil, err } - if resp.StatusCode == 409 { + defer resp.Body.Close() + + if resp.StatusCode == http.StatusConflict { return nil, nil } @@ -300,10 +315,10 @@ func (c *Client) PutResources(path string) (*RespPutResources, error) { return &r, err } -func (c *Client) DeleteResources(path string) error { +func (c *Client) DeleteResources(ctx context.Context, path string) error { data := url.Values{} data.Set("path", path) - req, err := http.NewRequest("DELETE", V1_DISK_API+"/resources?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodDelete, V1DiskAPI+"/resources?"+data.Encode(), http.NoBody) if err != nil { return err } @@ -313,24 +328,25 @@ func (c *Client) DeleteResources(path string) error { return err } + defer resp.Body.Close() + err = checkError(resp) return err } -// UploadResourcesUrl - Загрузить файл на Яндекс диск по URL. Нерекомендуемый -func (c *Client) UploadResourcesUrl(path, downloadPath string) (string, error) { - downloadPath = strings.TrimLeft(downloadPath, "..") +// UploadResourcesURL - Загрузить файл на Яндекс диск по URL. Нерекомендуемый. +func (c *Client) UploadResourcesURL(ctx context.Context, path, downloadPath string) (string, error) { downloadPath = strings.TrimLeft(downloadPath, ".") - fmt.Println("dp:", c.App.ServiceUrl+downloadPath) + fmt.Println("dp:", c.App.ServiceURL+downloadPath) fmt.Println("path:", path) data := url.Values{} data.Set("path", path) - data.Set("url", c.App.ServiceUrl+downloadPath) + data.Set("url", c.App.ServiceURL+downloadPath) - req, err := http.NewRequest("POST", V1_DISK_API+"/resources/upload?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, V1DiskAPI+"/resources/upload?"+data.Encode(), http.NoBody) fmt.Println("req:", req.URL) if err != nil { @@ -342,6 +358,8 @@ func (c *Client) UploadResourcesUrl(path, downloadPath string) (string, error) { return "", err } + defer resp.Body.Close() + if checkError(resp) != nil { return "", err } @@ -352,19 +370,21 @@ func (c *Client) UploadResourcesUrl(path, downloadPath string) (string, error) { return "", err } - status, err := c.GetOperationsByUrl(r.Href) + status, err := c.GetOperationsByURL(ctx, r.Href) if err != nil { return "", err } // Ожидаем пока загрузится файл на Я.Диск. Timeout: 5 sec; tick: 100 ms; timer := time.NewTimer(5 * time.Second) + ticker := time.NewTicker(100 * time.Millisecond) + defer ticker.Stop() for status == "in-progress" { select { case <-timer.C: status = "timeout" - case <-time.Tick(100 * time.Millisecond): - status, err = c.GetOperationsByUrl(r.Href) + case <-ticker.C: + status, err = c.GetOperationsByURL(ctx, r.Href) if err != nil { timer.Stop() return "", err @@ -374,29 +394,29 @@ func (c *Client) UploadResourcesUrl(path, downloadPath string) (string, error) { timer.Stop() if status != "success" { - return "", errors.New(fmt.Sprintf("bad upload status: %v", status)) + return "", fmt.Errorf("bad upload status: %v", status) } - resource, err := c.GetResources(path, 0, 0) + resource, err := c.GetResources(ctx, path, 0, 0) if err != nil { return "", err } - var exportUrl string + var exportURL string if resource != nil { - exportUrl = resource.File + exportURL = resource.File } else { return "", errors.New("resource not found") } - return exportUrl, err + return exportURL, err } -// UploadResources - Загрузить файл на Яндекс диск -func (c *Client) UploadResources(path string, file io.Reader) (string, string, error) { +// UploadResources - Загрузить файл на Яндекс диск. +func (c *Client) UploadResources(ctx context.Context, path string, file io.Reader) (string, string, error) { // Get url for request - target, err := c.getUploadResourcesUrl(path) + target, err := c.getUploadResourcesURL(ctx, path) if err != nil { return "", "", err } @@ -405,48 +425,59 @@ func (c *Client) UploadResources(path string, file io.Reader) (string, string, e return "", "", errors.New("got empty url for upload") } - req, err := http.NewRequest(target.Method, target.Href, file) + req, err := http.NewRequestWithContext(ctx, target.Method, target.Href, file) if err != nil { return "", "", err } resp, err := c.HTTPClient.Do(req) + if err != nil { + return "", "", err + } - if err := checkError(resp); err != nil { + defer resp.Body.Close() + + err = checkError(resp) + if err != nil { return "", "", err } // Get uploaded data - resource, err := c.GetResources(path, 0, 0) + resource, err := c.GetResources(ctx, path, 0, 0) if err != nil { return "", "", err } - var exportUrl string + var exportURL string if resource != nil { - exportUrl = resource.File + exportURL = resource.File } else { return "", "", errors.New("resource not found") } - return resource.Path, exportUrl, err + return resource.Path, exportURL, err } -// getUploadResourcesUrl - получить ссылку для отправки файла по TLS -func (c *Client) getUploadResourcesUrl(path string) (*RespUploadResources, error) { +// getUploadResourcesURL - получить ссылку для отправки файла по TLS. +func (c *Client) getUploadResourcesURL(ctx context.Context, path string) (*RespUploadResources, error) { data := url.Values{} data.Set("path", path) data.Set("overwrite", "true") - req, err := http.NewRequest("GET", V1_DISK_API+"/resources/upload?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, V1DiskAPI+"/resources/upload?"+data.Encode(), http.NoBody) if err != nil { return nil, err } resp, err := c.HTTPClient.Do(req) + if err != nil { + return nil, err + } + + defer resp.Body.Close() err = checkError(resp) if err != nil { @@ -459,14 +490,19 @@ func (c *Client) getUploadResourcesUrl(path string) (*RespUploadResources, error return &r, err } -// GetOperations - возвращает статус асинхронной операции -func (c *Client) GetOperations(operationID string) (string, error) { - req, err := http.NewRequest("GET", V1_DISK_API+"/operations/"+operationID, nil) +// GetOperations - возвращает статус асинхронной операции. +func (c *Client) GetOperations(ctx context.Context, operationID string) (string, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, V1DiskAPI+"/operations/"+operationID, http.NoBody) if err != nil { return "", err } resp, err := c.HTTPClient.Do(req) + if err != nil { + return "", err + } + + defer resp.Body.Close() err = checkError(resp) if err != nil { @@ -479,15 +515,20 @@ func (c *Client) GetOperations(operationID string) (string, error) { return r.Status, err } -// GetOperationsByUrl - возвращает статус асинхронной операции -func (c *Client) GetOperationsByUrl(url string) (string, error) { - req, err := http.NewRequest("GET", url, nil) +// GetOperationsByURL - возвращает статус асинхронной операции. +func (c *Client) GetOperationsByURL(ctx context.Context, url string) (string, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody) if err != nil { return "", err } resp, err := c.HTTPClient.Do(req) + if err != nil { + return "", err + } + + defer resp.Body.Close() err = checkError(resp) if err != nil { @@ -500,17 +541,22 @@ func (c *Client) GetOperationsByUrl(url string) (string, error) { return r.Status, err } -// PublishResource - публикует ресурс -func (c *Client) PublishResource(path string) error { +// PublishResource - публикует ресурс. +func (c *Client) PublishResource(ctx context.Context, path string) error { data := url.Values{} data.Set("path", path) - req, err := http.NewRequest("PUT", V1_DISK_API+"/resources/publish?"+data.Encode(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"/resources/publish?"+data.Encode(), http.NoBody) if err != nil { return err } resp, err := c.HTTPClient.Do(req) + if err != nil { + return err + } + + defer resp.Body.Close() err = checkError(resp) if err != nil { @@ -520,10 +566,12 @@ func (c *Client) PublishResource(path string) error { return nil } -// checkError - если статус не в диапазоне 200-х вернет расшифровку ошибки +// checkError - если статус не в диапазоне 200-х вернет расшифровку ошибки. func checkError(resp *http.Response) error { switch resp.StatusCode { - case 200, 201, 202, 203, 204, 205, 206, 207, 208, 226: + case http.StatusOK, http.StatusCreated, http.StatusAccepted, http.StatusNonAuthoritativeInfo, + http.StatusNoContent, http.StatusResetContent, http.StatusPartialContent, + http.StatusMultiStatus, http.StatusAlreadyReported, http.StatusIMUsed: return nil } r := Error{} @@ -532,6 +580,5 @@ func checkError(resp *http.Response) error { return err } - return errors.New(fmt.Sprintf("api/yaDisk (%v) err: %v | %v (%v)", resp.StatusCode, r.Message, r.Description, - r.Error)) + return fmt.Errorf("api/yaDisk (%v) err: %v | %v (%v)", resp.StatusCode, r.Message, r.Description, r.Error) } diff --git a/yadisk/model.go b/yadisk/model.go index 9a17005..9655976 100644 --- a/yadisk/model.go +++ b/yadisk/model.go @@ -1,4 +1,4 @@ -package YaDisk +package yadisk import ( "time" @@ -39,7 +39,7 @@ type User struct { Country string `json:"country"` Login string `json:"login"` DisplayName string `json:"display_name"` - Uid string `json:"uid"` + UID string `json:"uid"` } type Resource struct { @@ -52,11 +52,11 @@ type Resource struct { Total int `json:"total"` } `json:"_embedded"` Name string `json:"name"` - PublicUrl string `json:"public_url"` + PublicURL string `json:"public_url"` PublicKey string `json:"public_key"` Exif struct { } `json:"exif"` - ResourceId string `json:"resource_id"` + ResourceID string `json:"resource_id"` Created time.Time `json:"created"` Modified time.Time `json:"modified"` Path string `json:"path"`