diff --git a/dal/dal.go b/dal/dal.go index c64e4bc..6a500c2 100644 --- a/dal/dal.go +++ b/dal/dal.go @@ -12,6 +12,7 @@ import ( "github.com/minio/minio-go/v7" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal/sqlcgen" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/account" + "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/amo" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/answer" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/question" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/quiz" @@ -51,8 +52,8 @@ func New(ctx context.Context, cred string, minioClient *minio.Client) (*DAL, err queries := sqlcgen.New(pool) accountRepo := account.NewAccountRepository(account.Deps{ - Queries: queries, - Pool: pool, + Queries: queries, + Pool: pool, }) storerAnswer := &answer.StorerAnswer{} @@ -130,3 +131,65 @@ func (d *DAL) Init() error { } return nil } + +type AmoDal struct { + conn *sql.DB + queries *sqlcgen.Queries + AmoRepo *amo.AmoRepository + QuestionRepo *question.QuestionRepository + AnswerRepo *answer.AnswerRepository + QuizRepo *quiz.QuizRepository +} + +func NewAmoDal(ctx context.Context, cred string) (*AmoDal, error) { + pool, err := sql.Open("postgres", cred) + if err != nil { + return nil, err + } + + timeoutCtx, cancel := context.WithTimeout(ctx, time.Second) + defer cancel() + + if err := pool.PingContext(timeoutCtx); err != nil { + return nil, err + } + + queries := sqlcgen.New(pool) + + amoRepo := amo.NewAmoRepository(amo.Deps{ + Queries: queries, + Pool: pool, + }) + + questionRepo := question.NewQuestionRepository(question.Deps{ + Queries: queries, + Pool: pool, + }) + + answerRepo := answer.NewAnswerRepository(answer.Deps{ + Queries: queries, + Pool: pool, + }) + + quizRepo := quiz.NewQuizRepository(quiz.Deps{ + Queries: queries, + Pool: pool, + }) + + return &AmoDal{ + conn: pool, + queries: queries, + AmoRepo: amoRepo, + QuestionRepo: questionRepo, + AnswerRepo: answerRepo, + QuizRepo: quizRepo, + }, nil +} + +func (d *AmoDal) Close(ctx context.Context) error { + err := d.conn.Close() + if err != nil { + return err + } + return nil +} diff --git a/dal/db_query/queries.sql b/dal/db_query/queries.sql index ae4ccb5..ff66bfe 100644 --- a/dal/db_query/queries.sql +++ b/dal/db_query/queries.sql @@ -670,3 +670,424 @@ SELECT cq.id AS quiz_id, q.title, q.description, q.questiontype, q.required, q.d FROM question q JOIN quiz old ON q.quiz_id = old.id JOIN copied_quiz cq ON old.qid = $2; + + +-- amo methods: + +-- name: CreateAmoAccount :exec +INSERT INTO users (AccountID, AmoID, Name, Email, Role, "Group", Deleted, CreatedAt, Subdomain, AmoUserID, Country) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11); + +-- name: CreateWebHook :exec +INSERT INTO tokens (AccountID, RefreshToken, AccessToken, AuthCode, Expiration, CreatedAt) +VALUES ($1, $2, $3, $4, $5, $6); + +-- name: WebhookUpdate :exec +UPDATE tokens SET AccessToken = $1,RefreshToken = $2,Expiration = to_timestamp(($3)::bigint) AT TIME ZONE 'UTC' + INTERVAL '3 hours',CreatedAt = to_timestamp(($4)::bigint) AT TIME ZONE 'UTC' + INTERVAL '3 hours' +WHERE accountID = $5; + +-- name: GetAllTokens :many +SELECT * FROM tokens; + +-- name: CheckExpired :many +SELECT * FROM tokens WHERE Expiration <= TO_TIMESTAMP(EXTRACT(EPOCH FROM NOW()) + (10 * 60)); + +-- name: WebhookDelete :exec +WITH userd AS ( + UPDATE users SET Deleted = true WHERE AmoUserID = $1 RETURNING AccountID +) +DELETE FROM tokens WHERE AccountID IN (SELECT AccountID FROM userd); + +-- name: SoftDeleteAccount :exec +WITH userd AS ( + SELECT AmoUserID FROM users WHERE users.AccountID = $1 +), + tokend AS ( + UPDATE users SET Deleted = true WHERE AmoUserID IN (SELECT AmoUserID FROM userd) RETURNING users.AccountID + ) +DELETE FROM tokens WHERE tokens.AccountID IN (SELECT AccountID FROM tokend); + +-- name: GetCurrentAccount :one +SELECT * FROM users WHERE AccountID = $1; + +-- name: CheckMainUser :exec +UPDATE users SET Name = $1, "Group" = $2, Email = $3, Role = $4 WHERE AmoID = $5; + +-- name: GetUsersWithPagination :many +WITH user_data AS ( + SELECT AmoID FROM users WHERE users.AccountID = $1 AND Deleted = false +) +SELECT u.*, COUNT(*) OVER() as total_count +FROM users u +JOIN user_data a ON u.AmoUserID = a.AmoID +WHERE u.Deleted = false +ORDER BY u.ID OFFSET ($2 - 1) * $3 LIMIT $3; + +-- name: GetTagsWithPagination :many +SELECT t.*, COUNT(*) OVER() as total_count +FROM tags t JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1) u ON t.AccountID = u.AmoID +WHERE t.Deleted = false +ORDER BY t.ID OFFSET ($2 - 1) * $3 LIMIT $3; + +-- name: GetStepsWithPagination :many +SELECT s.*, COUNT(*) OVER() as total_count +FROM steps s JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1) u ON s.AccountID = u.AmoID +WHERE s.Deleted = false +ORDER BY s.ID OFFSET ($2 - 1) * $3 LIMIT $3; + +-- name: GetPipelinesWithPagination :many +SELECT p.*, COUNT(*) OVER() as total_count +FROM pipelines p JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1) u ON p.AccountID = u.AmoID +WHERE p.Deleted = false +ORDER BY p.ID OFFSET ($2 - 1) * $3 LIMIT $3; + +-- name: GetFieldsWithPagination :many +SELECT f.*, COUNT(*) OVER() as total_count +FROM fields f JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1) u ON f.AccountID = u.AmoID +WHERE f.Deleted = false +ORDER BY f.ID OFFSET ($2 - 1) * $3 LIMIT $3; + +-- name: UpdateTags :exec +UPDATE tags AS t +SET name = (update_data ->> 'Name')::varchar(512), + color = (update_data ->> 'Color')::varchar(50) +FROM json_array_elements($1::json) AS update_data +WHERE t.amoID = (update_data ->> 'AmoID')::INT + AND t.accountID = (update_data ->> 'AccountID')::INT + AND t.Entity = (update_data ->> 'Entity')::entitytype; + +-- name: UpdatePipelines :exec +UPDATE pipelines AS p +SET name = (update_data ->> 'Name')::varchar(512), + isArchive = CASE WHEN (update_data ->> 'IsArchive') = 'true' THEN TRUE ELSE FALSE END +FROM json_array_elements($1::json) AS update_data +WHERE p.amoID = (update_data ->> 'AmoID')::INT + AND p.accountID = (update_data ->> 'AccountID')::INT; + +-- name: UpdateSteps :exec +UPDATE steps AS s +SET name = (update_data ->> 'Name')::varchar(512), + color = (update_data ->> 'Color')::varchar(50) +FROM json_array_elements($1::json) AS update_data +WHERE s.amoID = (update_data ->> 'AmoID')::INT + AND s.accountID = (update_data ->> 'AccountID')::INT + AND s.pipelineID = (update_data ->> 'PipelineID')::INT; + +-- name: UpdateFields :exec +UPDATE fields AS f +SET name = (update_data ->> 'Name')::varchar(512), + code = (update_data ->> 'Code')::varchar(255), + type = (update_data ->> 'Type')::fieldtype +FROM json_array_elements($1::json) AS update_data +WHERE f.amoID = (update_data ->> 'AmoID')::INT + AND f.accountID = (update_data ->> 'AccountID')::INT + AND f.Entity = (update_data ->> 'Entity')::entitytype; + +-- name: CheckTags :many +WITH user_data AS ( + SELECT AmoID + FROM users + WHERE users.AccountID = $1 +), new_tags AS ( + SELECT (tag->>'AmoID')::INT AS amoID, + (tag->>'Entity')::entitytype AS Entity, + COALESCE(tag->>'Name', '')::VARCHAR(512) AS name, + COALESCE(tag->>'Color', '')::VARCHAR(50) AS color + FROM json_array_elements($2::json) AS tag +), inserted_tags AS ( + INSERT INTO tags (amoID, accountID, Entity, name, color, createdAt) + SELECT nt.amoID, + ud.AmoID, + nt.Entity, + nt.name, + nt.color, + CURRENT_TIMESTAMP + FROM new_tags nt + JOIN user_data ud ON true + ON CONFLICT (amoID, accountID, Entity) DO NOTHING + RETURNING * +) +SELECT nt.*,ud.AmoID +FROM new_tags nt + JOIN user_data ud ON true +WHERE NOT EXISTS ( + SELECT * + FROM inserted_tags ins + JOIN user_data ud ON true + WHERE ins.amoID = nt.amoID AND ins.accountID = ud.amoid AND ins.Entity = nt.Entity +); + +-- name: CheckPipelines :many +WITH new_pipelines AS ( + SELECT (pipeline->>'AmoID')::INT AS amoID, + (pipeline->>'AccountID')::INT AS accountID, + COALESCE(pipeline->>'Name', '')::varchar(512) AS name, + CASE WHEN (pipeline->>'IsArchive') = 'true' THEN TRUE ELSE FALSE END AS isArchive, + CURRENT_TIMESTAMP AS createdAt + FROM json_array_elements($1::json) AS pipeline +), inserted_pipelines AS( + INSERT INTO pipelines (amoID, accountID, name, isArchive, createdAt) + SELECT np.amoID, + np.accountID, + np.name, + np.isArchive, + np.createdAt + FROM new_pipelines np + ON CONFLICT (amoID, accountID) DO NOTHING + RETURNING * +) +SELECT np.* +FROM new_pipelines np +WHERE NOT EXISTS ( + SELECT * + FROM inserted_pipelines ins + WHERE ins.amoID = np.amoID AND ins.accountID = np.accountID +); + +-- name: CheckFields :many +WITH user_data AS ( + SELECT AmoID + FROM users + WHERE users.AccountID = $1 +), new_fields AS ( + SELECT (field->>'AmoID')::INT AS amoID, + COALESCE(field->>'Code', '')::varchar(255) AS code, + COALESCE(field->>'Name', '')::varchar(512) AS name, + CAST(field->>'Entity' AS entitytype) AS Entity, + COALESCE(field->>'Type', '')::fieldtype AS type, + CURRENT_TIMESTAMP AS createdAt + FROM json_array_elements($2::json) AS field +), inserted_fields AS( + INSERT INTO fields (amoID, code, accountID, name, Entity, type, createdAt) + SELECT nf.amoID, + nf.code, + ud.AmoID, + nf.name, + nf.Entity, + nf.type, + nf.createdAt + FROM new_fields nf + JOIN user_data ud ON true + ON CONFLICT (amoID, accountID, entity) DO NOTHING + RETURNING * +) +SELECT nf.*,ud.AmoID +FROM new_fields nf + JOIN user_data ud ON true +WHERE NOT EXISTS ( + SELECT * + FROM inserted_fields ins + JOIN user_data ud ON true + WHERE ins.amoID = nf.amoID AND ins.accountID = ud.amoid AND ins.Entity = nf.Entity +); + +-- name: CheckSteps :many +WITH new_steps AS ( + SELECT (step->>'AmoID')::INT AS amoID, + (step->>'PipelineID')::INT AS pipelineID, + (step->>'AccountID')::INT AS accountID, + COALESCE(step->>'Name', '')::varchar(512) AS name, + COALESCE(step->>'Color', '')::varchar(50) AS color, + CURRENT_TIMESTAMP AS createdAt + FROM json_array_elements($1::json) AS step +), inserted_steps AS ( + INSERT INTO steps (amoID, pipelineID, accountID, name, color, createdAt) + SELECT ns.amoID, + ns.pipelineID, + ns.accountID, + ns.name, + ns.color, + ns.createdAt + FROM new_steps ns + ON CONFLICT (amoID, accountID, PipelineID) DO NOTHING + RETURNING * +) +SELECT ns.* +FROM new_steps ns +WHERE NOT EXISTS ( + SELECT * + FROM inserted_steps ins + WHERE ins.amoID = ns.amoID AND ins.accountID = ns.accountID AND ins.pipelineID = ns.pipelineID +); + +-- name: GetTokenById :one +SELECT * FROM tokens WHERE accountID = $1; + +-- name: DeletingUTM :exec +UPDATE utms SET Deleted = true WHERE ID = ANY($1::int[]); + +-- name: GetUTMsWithPagination :many +SELECT ut.*, COUNT(*) OVER() as total_count +FROM utms ut JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1) u ON ut.AccountID = u.AmoID +WHERE ut.Deleted = false and ut.QuizID = $4 +ORDER BY ut.ID OFFSET ($2 - 1) * $3 LIMIT $3; + +-- name: SaveUTMs :many +WITH user_data AS ( + SELECT AmoID + FROM users + WHERE users.AccountID = $1 +), new_UTMs AS ( + SELECT (utm->>'AmoFieldID')::INT AS amoFieldID, + COALESCE(utm->>'QuizID', '')::INT AS quizID, + COALESCE(utm->>'Name', '')::varchar(512) AS name, + CURRENT_TIMESTAMP AS createdAt + FROM json_array_elements($2::json) AS utm +), inserted_utms AS( + INSERT INTO utms (AmoFieldID, QuizID, AccountID, Name, createdAt) + SELECT nu.amoFieldID, + nu.quizID, + ud.AmoID, + nu.name, + nu.createdAt + FROM new_UTMs nu + JOIN user_data ud ON true + RETURNING * +) +SELECT * from inserted_utms; + +-- name: GetQuizRule :one +SELECT * FROM rules WHERE QuizID = $1 AND Deleted = false; + +-- name: SetQuizSettings :exec +INSERT INTO rules (AccountID, QuizID, PerformerID, PipelineID, StepID, UTMS, FieldsRule) +SELECT u.AmoID AS AccountID,$1 AS QuizID,$2 AS PerformerID,$3 AS PipelineID, + $4 AS StepID,$5 AS UTMS,$6 AS FieldsRule FROM users u WHERE u.AccountID = $7; + +-- name: ChangeQuizSettings :exec +UPDATE rules +SET PerformerID = $1,PipelineID = $2,StepID = $3,UTMS = $4,FieldsRule = $5 +WHERE AccountID = (SELECT AmoID FROM users WHERE users.AccountID = $6) AND QuizID = $7 AND Deleted = false; + +-- name: GetUtmsByID :many +SELECT ID,AmoFieldID,QuizID,AccountID,Name +FROM utms +WHERE + ID = ANY($1::int[]) AND Deleted = FALSE; + +-- name: GetUserFieldsByID :many +SELECT ID,AmoID,Code,AccountID,Name,Entity,Type +FROM fields +WHERE AccountID = $1 AND Deleted = false; + +-- name: UpdateUtms :exec +UPDATE utms AS u +SET name = (update_data ->> 'Name')::varchar(512), + AmoFieldID = (update_data ->> 'AmoFieldID')::INT +FROM json_array_elements($1::json) AS update_data +WHERE u.ID = (update_data ->> 'ID')::INT; + +-- name: UpdateUtmsFields :exec +UPDATE utms AS u SET AmoFieldID = f.AmoID FROM fields AS f +WHERE u.Name = f.Name AND u.ID = ANY($1::int[]) AND u.Deleted = FALSE; + +-- name: GetQuestionListByIDs :many +SELECT * FROM question WHERE id = ANY($1::int[]) AND deleted = FALSE; + +-- name: UpdateFieldRules :exec +UPDATE rules SET FieldsRule = $1 +WHERE AccountID = (SELECT AmoID FROM users WHERE users.AccountID = $2) AND QuizID = $3 AND Deleted = false; + +-- name: UpdateUsers :exec +UPDATE users AS u +SET Name = (update_data ->> 'Name')::varchar(512), + Email = (update_data ->> 'Email')::varchar(50), + Role = (update_data ->> 'Role')::INT, + "Group" = (update_data ->> 'Group')::INT, + AmoUserID= (update_data ->> 'AmoUserID')::INT +FROM json_array_elements($1::json) AS update_data +WHERE u.AmoID = (update_data ->> 'AmocrmID')::INT; + +-- name: CheckUsers :many +WITH new_users AS ( + SELECT (u->>'AmocrmID')::INT AS AmoID, + (u->>'Name')::VARCHAR(512) AS Name, + (u->>'Group')::INT AS "Group", + (u->>'Role')::INT AS Role, + (u->>'Email')::VARCHAR(50) AS Email, + (u->>'AmoUserID')::INT AS AmoUserID, + CURRENT_TIMESTAMP AS createdAt + FROM json_array_elements($1::json) AS u +), inserted_users AS ( + INSERT INTO users (AmoID, Name, "Group", Role, Email, AmoUserID,createdAt) + SELECT nu.AmoID, + nu.Name, + nu."Group", + nu.Role, + nu.Email, + nu.AmoUserID, + nu.createdAt + FROM new_users nu + ON CONFLICT (amoID) DO NOTHING + RETURNING * +) +SELECT nu.* +FROM new_users nu +WHERE NOT EXISTS ( + SELECT * + FROM inserted_users ins + WHERE ins.amoID = nu.amoID +); + +-- name: GettingAmoUsersTrueResults :many +SELECT a.quiz_id,a.id,a.result,a.question_id,a.content,a.session,t.accesstoken,r.accountid,r.utms,r.fieldsrule,r.performerid,r.stepid,r.pipelineid,(SELECT u.name FROM users u WHERE u.amoid = r.performerid) AS performer_name +FROM answer a + INNER JOIN quiz q ON a.quiz_id = q.id + LEFT JOIN amoCRMStatuses s ON a.id = s.AnswerID + INNER JOIN rules r ON q.id = r.QuizID + INNER JOIN tokens t ON q.accountid = t.AccountID + INNER JOIN users u ON q.accountid = u.accountid AND u.amoid = r.accountid +WHERE a.result = true + AND s.id IS NULL + AND a.deleted = false + AND r.deleted = false + AND q.deleted = false; + +-- name: SettingDealAmoStatus :exec +INSERT INTO amoCRMStatuses (AccountID, DealID, AnswerID, Status) +SELECT u.AmoID, $1, $2, $3 +FROM tokens AS t + JOIN users AS u ON t.AccountID = u.AccountID +WHERE t.AccessToken = $4; + +-- name: UpdatingDealAmoStatus :exec +UPDATE amoCRMStatuses SET Status = $1 +WHERE DealID = $2 AND AccountID = (SELECT u.AmoID FROM tokens AS t JOIN users AS u ON t.AccountID = u.AccountID WHERE t.AccessToken = $3); + +-- name: DeleteFields :exec +UPDATE fields SET Deleted = true WHERE ID = ANY($1::bigint[]); + +-- name: DeleteTags :exec +UPDATE tags SET Deleted = true WHERE ID = ANY($1::bigint[]); + +-- name: DeleteSteps :exec +UPDATE steps SET Deleted = true WHERE ID = ANY($1::bigint[]); + +-- name: DeletePipelines :exec +UPDATE pipelines SET Deleted = true WHERE ID = ANY($1::bigint[]); + +-- name: DeleteUsers :exec +UPDATE users SET Deleted = true WHERE ID = ANY($1::bigint[]); + +-- name: GetUserTagsByID :many +SELECT ID,AmoID,AccountID,Name,Entity,Color +FROM tags +WHERE AccountID = $1 AND Deleted = false; + +-- name: GetUserStepsByID :many +SELECT ID,AmoID,PipelineID,AccountID,Name,Color +FROM steps +WHERE AccountID = $1 AND Deleted = false; + +-- name: GetUserPipelinesByID :many +SELECT ID,AmoID,AccountID,Name,IsArchive +FROM pipelines +WHERE AccountID = $1 AND Deleted = false; + +-- name: GetUserUsersByID :many +SELECT ID,AccountID,AmoID,Name,Email,Role,"Group",Subdomain,AmoUserID,Country +FROM users +WHERE AmoUserID = $1 AND Deleted = false; + +-- name: GetFieldByAmoID :one +SELECT * FROM fields WHERE AmoID = $1 AND Deleted = false; diff --git a/dal/schema/000010_init.down.sql b/dal/schema/000010_init.down.sql new file mode 100644 index 0000000..02f12e4 --- /dev/null +++ b/dal/schema/000010_init.down.sql @@ -0,0 +1,31 @@ +DROP INDEX IF EXISTS idx_unique_users; +DROP INDEX IF EXISTS idx_unique_pipeline; +DROP INDEX IF EXISTS idx_unique_step; +DROP INDEX IF EXISTS idx_unique_field; +DROP INDEX IF EXISTS idx_unique_tag; +DROP INDEX IF EXISTS idx_unique_rules; + +DROP TABLE IF EXISTS amoCRMStatuses; +DROP TABLE IF EXISTS rules; +DROP TABLE IF EXISTS utms; +DROP TABLE IF EXISTS tags; +DROP TABLE IF EXISTS fields; + +DO $$ + BEGIN + IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entitytype') THEN + DROP TYPE EntityType; + END IF; +END $$; + +DO $$ + BEGIN + IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'fieldtype') THEN + DROP TYPE FieldType; + END IF; +END $$; + +DROP TABLE IF EXISTS steps; +DROP TABLE IF EXISTS pipelines; +DROP TABLE IF EXISTS tokens; +DROP TABLE IF EXISTS users; \ No newline at end of file diff --git a/dal/schema/000010_init.up.sql b/dal/schema/000010_init.up.sql new file mode 100644 index 0000000..37ee29e --- /dev/null +++ b/dal/schema/000010_init.up.sql @@ -0,0 +1,119 @@ +CREATE TABLE IF NOT EXISTS tokens ( + AccountID VARCHAR(30) PRIMARY KEY, -- связь с users AccountID неявная посредством join + RefreshToken TEXT NOT NULL , + AccessToken TEXT NOT NULL , + AuthCode TEXT NOT NULL , -- код авторизации который получаем при вебхук + Expiration TIMESTAMP NOT NULL, -- время истечения токенов + CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS users ( + ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY, + AccountID VARCHAR(30) NOT NULL DEFAULT '', -- id квизе из токена + AmoID INT NOT NULL , -- id в амо + Name VARCHAR(512) NOT NULL DEFAULT '', -- имя в амо + Email VARCHAR(50) NOT NULL DEFAULT '', -- почта в амо + Role INT NOT NULL DEFAULT 0, -- роль в амо + "Group" INT NOT NULL DEFAULT 0, -- вложенная структура так как в амо группы хранятся массивом структур + Deleted BOOLEAN NOT NULL DEFAULT FALSE, + CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + Subdomain VARCHAR(50) NOT NULL DEFAULT '', + AmoUserID INT NOT NULL , -- id пользователя который подключал интеграцию + Country VARCHAR(50) NOT NULL DEFAULT '' -- страна в амо +); + +CREATE TABLE IF NOT EXISTS pipelines ( + ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY, + AmoID INT NOT NULL , --id воронки в амо + AccountID INT NOT NULL , --id аккаунта в амо связь с таблицей users AmoID неявная посредством join + Name VARCHAR(512) NOT NULL DEFAULT '', --название воронки в амо + IsArchive BOOLEAN NOT NULL DEFAULT FALSE, --флаг архивной воронки в амо + Deleted BOOLEAN NOT NULL DEFAULT FALSE, + CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS steps ( + ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY, + AmoID INT NOT NULL, --id шага воронки в амо + PipelineID INT NOT NULL, --id воронки AmoID pipelines неявная посредством join + AccountID INT NOT NULL, --id аккаунта в амо связь с таблицей users AmoID неявная посредством join + Name VARCHAR(512) NOT NULL DEFAULT '', --название воронки в амо + Color VARCHAR(50) NOT NULL DEFAULT '', --цвет шага в амо* + Deleted BOOLEAN NOT NULL DEFAULT FALSE, + CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +DO $$ + BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entitytype') THEN + CREATE TYPE EntityType AS ENUM ('leads', 'contacts', 'companies', 'customers'); + END IF; +END $$; + +DO $$ + BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'fieldtype') THEN + CREATE TYPE FieldType AS ENUM ('text', 'numeric', 'checkbox', 'select', 'multiselect', 'date', 'url', 'textarea', 'radiobutton', 'streetaddress', 'smart_address', 'birthday', 'legal_entity', 'date_time', 'price', 'category', 'items', 'tracking_data', 'linked_entity', 'chained_list', 'monetary', 'file', 'payer', 'supplier', 'multitext'); + END IF; +END $$; + +CREATE TABLE IF NOT EXISTS fields ( + ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY, + AmoID INT NOT NULL, -- айдишник кастомного поля в амо + Code VARCHAR(255) NOT NULL DEFAULT '', -- кодовое слово в амо + AccountID INT NOT NULL, -- id аккаунта в амо связь с таблицей users AmoID неявная посредством join + Name VARCHAR(512) NOT NULL DEFAULT '', -- название воронки в амо + Entity EntityType NOT NULL, -- тип сущности в амо, для которой это кастомное поле + Type FieldType NOT NULL, -- тип поля + Deleted BOOLEAN NOT NULL DEFAULT FALSE, + CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS tags ( + ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY, + AmoID INT NOT NULL, -- айдишник тега в амо + AccountID INT NOT NULL, -- id аккаунта в амо связь с таблицей users AmoID неявная посредством join + Entity EntityType NOT NULL, -- сущность, к которой принадлежит этот тег + Name VARCHAR(512) NOT NULL DEFAULT '', -- название тега в амо + Color VARCHAR(50) NOT NULL DEFAULT '', -- цвет тега в амо + Deleted BOOLEAN NOT NULL DEFAULT FALSE, + CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS utms ( + ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY, + AmoFieldID INT NOT NULL DEFAULT 0, -- id field в амо + QuizID INT NOT NULL, -- id опроса + AccountID INT NOT NULL, -- id аккаунта в амо AMOID + Name VARCHAR(512) NOT NULL DEFAULT '', -- название utm + Deleted BOOLEAN NOT NULL DEFAULT FALSE, + CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS rules ( + ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY, + AccountID INT NOT NULL, -- id аккаунта в амо AMOID + QuizID INT NOT NULL, -- id опроса + PerformerID INT NOT NULL, -- айдишник ответственного за сделку + PipelineID INT NOT NULL, --id воронки AmoID pipelines неявная посредством join + StepID INT NOT NULL , -- id этапа steps AmoID join + UTMS INTEGER[], -- список UTM для этого опроса id utm + FieldsRule JSONB NOT NULL DEFAULT '{}', -- вложенная структура + Deleted BOOLEAN NOT NULL DEFAULT FALSE, + CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX idx_unique_users ON users (amoID); +CREATE UNIQUE INDEX idx_unique_pipeline ON pipelines (amoID, accountID); +CREATE UNIQUE INDEX idx_unique_step ON steps (amoID, accountID, PipelineID); +CREATE UNIQUE INDEX idx_unique_field ON fields (amoID, accountID, entity); +CREATE UNIQUE INDEX idx_unique_tag ON tags (amoID, accountID, entity); +CREATE UNIQUE INDEX idx_unique_rules ON rules (accountID, QuizID); + +CREATE TABLE IF NOT EXISTS amoCRMStatuses ( + ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY, + AccountID INT NOT NULL, -- id аккаунта в амо + DealID INT NOT NULL, -- id сделки в которую добавлялось + AnswerID BIGINT NOT NULL REFERENCES answer(id), -- id true result который вызвал действие + Status TEXT NOT NULL DEFAULT '', -- запись о ошибке, либо успехе + CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); \ No newline at end of file diff --git a/dal/sqlcgen/db.go b/dal/sqlcgen/db.go index 7090fb4..6e5541c 100644 --- a/dal/sqlcgen/db.go +++ b/dal/sqlcgen/db.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.26.0 +// sqlc v1.25.0 package sqlcgen diff --git a/dal/sqlcgen/models.go b/dal/sqlcgen/models.go index 75ae972..3df41c2 100644 --- a/dal/sqlcgen/models.go +++ b/dal/sqlcgen/models.go @@ -1,11 +1,13 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.26.0 +// sqlc v1.25.0 package sqlcgen import ( "database/sql" + "encoding/json" + "time" "github.com/google/uuid" ) @@ -18,6 +20,15 @@ type Account struct { Deleted sql.NullBool `db:"deleted" json:"deleted"` } +type Amocrmstatus struct { + ID int64 `db:"id" json:"id"` + Accountid int32 `db:"accountid" json:"accountid"` + Dealid int32 `db:"dealid" json:"dealid"` + Answerid int64 `db:"answerid" json:"answerid"` + Status string `db:"status" json:"status"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` +} + type Answer struct { ID int64 `db:"id" json:"id"` Content sql.NullString `db:"content" json:"content"` @@ -38,6 +49,28 @@ type Answer struct { Start bool `db:"start" json:"start"` } +type Field struct { + ID int64 `db:"id" json:"id"` + Amoid int32 `db:"amoid" json:"amoid"` + Code string `db:"code" json:"code"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Entity interface{} `db:"entity" json:"entity"` + Type interface{} `db:"type" json:"type"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` +} + +type Pipeline struct { + ID int64 `db:"id" json:"id"` + Amoid int32 `db:"amoid" json:"amoid"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Isarchive bool `db:"isarchive" json:"isarchive"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` +} + type Privilege struct { ID int32 `db:"id" json:"id"` Privilegeid sql.NullString `db:"privilegeid" json:"privilegeid"` @@ -94,3 +127,72 @@ type Quiz struct { AverageTimePassing sql.NullInt32 `db:"average_time_passing" json:"average_time_passing"` SessionsCount sql.NullInt32 `db:"sessions_count" json:"sessions_count"` } + +type Rule struct { + ID int64 `db:"id" json:"id"` + Accountid int32 `db:"accountid" json:"accountid"` + Quizid int32 `db:"quizid" json:"quizid"` + Performerid int32 `db:"performerid" json:"performerid"` + Pipelineid int32 `db:"pipelineid" json:"pipelineid"` + Stepid int32 `db:"stepid" json:"stepid"` + Utms []int32 `db:"utms" json:"utms"` + Fieldsrule json.RawMessage `db:"fieldsrule" json:"fieldsrule"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` +} + +type Step struct { + ID int64 `db:"id" json:"id"` + Amoid int32 `db:"amoid" json:"amoid"` + Pipelineid int32 `db:"pipelineid" json:"pipelineid"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Color string `db:"color" json:"color"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` +} + +type Tag struct { + ID int64 `db:"id" json:"id"` + Amoid int32 `db:"amoid" json:"amoid"` + Accountid int32 `db:"accountid" json:"accountid"` + Entity interface{} `db:"entity" json:"entity"` + Name string `db:"name" json:"name"` + Color string `db:"color" json:"color"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` +} + +type Token struct { + Accountid string `db:"accountid" json:"accountid"` + Refreshtoken string `db:"refreshtoken" json:"refreshtoken"` + Accesstoken string `db:"accesstoken" json:"accesstoken"` + Authcode string `db:"authcode" json:"authcode"` + Expiration time.Time `db:"expiration" json:"expiration"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` +} + +type User struct { + ID int64 `db:"id" json:"id"` + Accountid string `db:"accountid" json:"accountid"` + Amoid int32 `db:"amoid" json:"amoid"` + Name string `db:"name" json:"name"` + Email string `db:"email" json:"email"` + Role int32 `db:"role" json:"role"` + Group int32 `db:"Group" json:"Group"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` + Subdomain string `db:"subdomain" json:"subdomain"` + Amouserid int32 `db:"amouserid" json:"amouserid"` + Country string `db:"country" json:"country"` +} + +type Utm struct { + ID int64 `db:"id" json:"id"` + Amofieldid int32 `db:"amofieldid" json:"amofieldid"` + Quizid int32 `db:"quizid" json:"quizid"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` +} diff --git a/dal/sqlcgen/queries.sql.go b/dal/sqlcgen/queries.sql.go index 9d88c2a..97c2b82 100644 --- a/dal/sqlcgen/queries.sql.go +++ b/dal/sqlcgen/queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.26.0 +// sqlc v1.25.0 // source: queries.sql package sqlcgen @@ -8,6 +8,7 @@ package sqlcgen import ( "context" "database/sql" + "encoding/json" "time" "github.com/google/uuid" @@ -113,6 +114,35 @@ func (q *Queries) ArchiveQuiz(ctx context.Context, arg ArchiveQuizParams) error return err } +const changeQuizSettings = `-- name: ChangeQuizSettings :exec +UPDATE rules +SET PerformerID = $1,PipelineID = $2,StepID = $3,UTMS = $4,FieldsRule = $5 +WHERE AccountID = (SELECT AmoID FROM users WHERE users.AccountID = $6) AND QuizID = $7 AND Deleted = false +` + +type ChangeQuizSettingsParams struct { + Performerid int32 `db:"performerid" json:"performerid"` + Pipelineid int32 `db:"pipelineid" json:"pipelineid"` + Stepid int32 `db:"stepid" json:"stepid"` + Utms []int32 `db:"utms" json:"utms"` + Fieldsrule json.RawMessage `db:"fieldsrule" json:"fieldsrule"` + Accountid string `db:"accountid" json:"accountid"` + Quizid int32 `db:"quizid" json:"quizid"` +} + +func (q *Queries) ChangeQuizSettings(ctx context.Context, arg ChangeQuizSettingsParams) error { + _, err := q.db.ExecContext(ctx, changeQuizSettings, + arg.Performerid, + arg.Pipelineid, + arg.Stepid, + pq.Array(arg.Utms), + arg.Fieldsrule, + arg.Accountid, + arg.Quizid, + ) + return err +} + const checkAndAddDefault = `-- name: CheckAndAddDefault :exec UPDATE privileges SET amount = $1, created_at = NOW() @@ -131,6 +161,212 @@ func (q *Queries) CheckAndAddDefault(ctx context.Context, arg CheckAndAddDefault return err } +const checkExpired = `-- name: CheckExpired :many +SELECT accountid, refreshtoken, accesstoken, authcode, expiration, createdat FROM tokens WHERE Expiration <= TO_TIMESTAMP(EXTRACT(EPOCH FROM NOW()) + (10 * 60)) +` + +func (q *Queries) CheckExpired(ctx context.Context) ([]Token, error) { + rows, err := q.db.QueryContext(ctx, checkExpired) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Token + for rows.Next() { + var i Token + if err := rows.Scan( + &i.Accountid, + &i.Refreshtoken, + &i.Accesstoken, + &i.Authcode, + &i.Expiration, + &i.Createdat, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const checkFields = `-- name: CheckFields :many +WITH user_data AS ( + SELECT AmoID + FROM users + WHERE users.AccountID = $1 +), new_fields AS ( + SELECT (field->>'AmoID')::INT AS amoID, + COALESCE(field->>'Code', '')::varchar(255) AS code, + COALESCE(field->>'Name', '')::varchar(512) AS name, + CAST(field->>'Entity' AS entitytype) AS Entity, + COALESCE(field->>'Type', '')::fieldtype AS type, + CURRENT_TIMESTAMP AS createdAt + FROM json_array_elements($2::json) AS field +), inserted_fields AS( + INSERT INTO fields (amoID, code, accountID, name, Entity, type, createdAt) + SELECT nf.amoID, + nf.code, + ud.AmoID, + nf.name, + nf.Entity, + nf.type, + nf.createdAt + FROM new_fields nf + JOIN user_data ud ON true + ON CONFLICT (amoID, accountID, entity) DO NOTHING + RETURNING id, amoid, code, accountid, name, entity, type, deleted, createdat +) +SELECT nf.amoid, nf.code, nf.name, nf.entity, nf.type, nf.createdat,ud.AmoID +FROM new_fields nf + JOIN user_data ud ON true +WHERE NOT EXISTS ( + SELECT id, ins.amoid, code, accountid, name, entity, type, deleted, createdat, ud.amoid + FROM inserted_fields ins + JOIN user_data ud ON true + WHERE ins.amoID = nf.amoID AND ins.accountID = ud.amoid AND ins.Entity = nf.Entity +) +` + +type CheckFieldsParams struct { + Accountid string `db:"accountid" json:"accountid"` + Column2 json.RawMessage `db:"column_2" json:"column_2"` +} + +type CheckFieldsRow struct { + Amoid int32 `db:"amoid" json:"amoid"` + Code string `db:"code" json:"code"` + Name string `db:"name" json:"name"` + Entity interface{} `db:"entity" json:"entity"` + Type interface{} `db:"type" json:"type"` + Createdat interface{} `db:"createdat" json:"createdat"` + Amoid_2 int32 `db:"amoid_2" json:"amoid_2"` +} + +func (q *Queries) CheckFields(ctx context.Context, arg CheckFieldsParams) ([]CheckFieldsRow, error) { + rows, err := q.db.QueryContext(ctx, checkFields, arg.Accountid, arg.Column2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CheckFieldsRow + for rows.Next() { + var i CheckFieldsRow + if err := rows.Scan( + &i.Amoid, + &i.Code, + &i.Name, + &i.Entity, + &i.Type, + &i.Createdat, + &i.Amoid_2, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const checkMainUser = `-- name: CheckMainUser :exec +UPDATE users SET Name = $1, "Group" = $2, Email = $3, Role = $4 WHERE AmoID = $5 +` + +type CheckMainUserParams struct { + Name string `db:"name" json:"name"` + Group int32 `db:"Group" json:"Group"` + Email string `db:"email" json:"email"` + Role int32 `db:"role" json:"role"` + Amoid int32 `db:"amoid" json:"amoid"` +} + +func (q *Queries) CheckMainUser(ctx context.Context, arg CheckMainUserParams) error { + _, err := q.db.ExecContext(ctx, checkMainUser, + arg.Name, + arg.Group, + arg.Email, + arg.Role, + arg.Amoid, + ) + return err +} + +const checkPipelines = `-- name: CheckPipelines :many +WITH new_pipelines AS ( + SELECT (pipeline->>'AmoID')::INT AS amoID, + (pipeline->>'AccountID')::INT AS accountID, + COALESCE(pipeline->>'Name', '')::varchar(512) AS name, + CASE WHEN (pipeline->>'IsArchive') = 'true' THEN TRUE ELSE FALSE END AS isArchive, + CURRENT_TIMESTAMP AS createdAt + FROM json_array_elements($1::json) AS pipeline +), inserted_pipelines AS( + INSERT INTO pipelines (amoID, accountID, name, isArchive, createdAt) + SELECT np.amoID, + np.accountID, + np.name, + np.isArchive, + np.createdAt + FROM new_pipelines np + ON CONFLICT (amoID, accountID) DO NOTHING + RETURNING id, amoid, accountid, name, isarchive, deleted, createdat +) +SELECT np.amoid, np.accountid, np.name, np.isarchive, np.createdat +FROM new_pipelines np +WHERE NOT EXISTS ( + SELECT id, amoid, accountid, name, isarchive, deleted, createdat + FROM inserted_pipelines ins + WHERE ins.amoID = np.amoID AND ins.accountID = np.accountID +) +` + +type CheckPipelinesRow struct { + Amoid int32 `db:"amoid" json:"amoid"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Isarchive bool `db:"isarchive" json:"isarchive"` + Createdat interface{} `db:"createdat" json:"createdat"` +} + +func (q *Queries) CheckPipelines(ctx context.Context, dollar_1 json.RawMessage) ([]CheckPipelinesRow, error) { + rows, err := q.db.QueryContext(ctx, checkPipelines, dollar_1) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CheckPipelinesRow + for rows.Next() { + var i CheckPipelinesRow + if err := rows.Scan( + &i.Amoid, + &i.Accountid, + &i.Name, + &i.Isarchive, + &i.Createdat, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const checkResultOwner = `-- name: CheckResultOwner :one SELECT q.accountid FROM answer a JOIN quiz q ON a.quiz_id = q.id WHERE a.id = $1 AND a.deleted = FALSE AND a.start = false ` @@ -177,6 +413,225 @@ func (q *Queries) CheckResultsOwner(ctx context.Context, arg CheckResultsOwnerPa return items, nil } +const checkSteps = `-- name: CheckSteps :many +WITH new_steps AS ( + SELECT (step->>'AmoID')::INT AS amoID, + (step->>'PipelineID')::INT AS pipelineID, + (step->>'AccountID')::INT AS accountID, + COALESCE(step->>'Name', '')::varchar(512) AS name, + COALESCE(step->>'Color', '')::varchar(50) AS color, + CURRENT_TIMESTAMP AS createdAt + FROM json_array_elements($1::json) AS step +), inserted_steps AS ( + INSERT INTO steps (amoID, pipelineID, accountID, name, color, createdAt) + SELECT ns.amoID, + ns.pipelineID, + ns.accountID, + ns.name, + ns.color, + ns.createdAt + FROM new_steps ns + ON CONFLICT (amoID, accountID, PipelineID) DO NOTHING + RETURNING id, amoid, pipelineid, accountid, name, color, deleted, createdat +) +SELECT ns.amoid, ns.pipelineid, ns.accountid, ns.name, ns.color, ns.createdat +FROM new_steps ns +WHERE NOT EXISTS ( + SELECT id, amoid, pipelineid, accountid, name, color, deleted, createdat + FROM inserted_steps ins + WHERE ins.amoID = ns.amoID AND ins.accountID = ns.accountID AND ins.pipelineID = ns.pipelineID +) +` + +type CheckStepsRow struct { + Amoid int32 `db:"amoid" json:"amoid"` + Pipelineid int32 `db:"pipelineid" json:"pipelineid"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Color string `db:"color" json:"color"` + Createdat interface{} `db:"createdat" json:"createdat"` +} + +func (q *Queries) CheckSteps(ctx context.Context, dollar_1 json.RawMessage) ([]CheckStepsRow, error) { + rows, err := q.db.QueryContext(ctx, checkSteps, dollar_1) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CheckStepsRow + for rows.Next() { + var i CheckStepsRow + if err := rows.Scan( + &i.Amoid, + &i.Pipelineid, + &i.Accountid, + &i.Name, + &i.Color, + &i.Createdat, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const checkTags = `-- name: CheckTags :many +WITH user_data AS ( + SELECT AmoID + FROM users + WHERE users.AccountID = $1 +), new_tags AS ( + SELECT (tag->>'AmoID')::INT AS amoID, + (tag->>'Entity')::entitytype AS Entity, + COALESCE(tag->>'Name', '')::VARCHAR(512) AS name, + COALESCE(tag->>'Color', '')::VARCHAR(50) AS color + FROM json_array_elements($2::json) AS tag +), inserted_tags AS ( + INSERT INTO tags (amoID, accountID, Entity, name, color, createdAt) + SELECT nt.amoID, + ud.AmoID, + nt.Entity, + nt.name, + nt.color, + CURRENT_TIMESTAMP + FROM new_tags nt + JOIN user_data ud ON true + ON CONFLICT (amoID, accountID, Entity) DO NOTHING + RETURNING id, amoid, accountid, entity, name, color, deleted, createdat +) +SELECT nt.amoid, nt.entity, nt.name, nt.color,ud.AmoID +FROM new_tags nt + JOIN user_data ud ON true +WHERE NOT EXISTS ( + SELECT id, ins.amoid, accountid, entity, name, color, deleted, createdat, ud.amoid + FROM inserted_tags ins + JOIN user_data ud ON true + WHERE ins.amoID = nt.amoID AND ins.accountID = ud.amoid AND ins.Entity = nt.Entity +) +` + +type CheckTagsParams struct { + Accountid string `db:"accountid" json:"accountid"` + Column2 json.RawMessage `db:"column_2" json:"column_2"` +} + +type CheckTagsRow struct { + Amoid int32 `db:"amoid" json:"amoid"` + Entity interface{} `db:"entity" json:"entity"` + Name string `db:"name" json:"name"` + Color string `db:"color" json:"color"` + Amoid_2 int32 `db:"amoid_2" json:"amoid_2"` +} + +func (q *Queries) CheckTags(ctx context.Context, arg CheckTagsParams) ([]CheckTagsRow, error) { + rows, err := q.db.QueryContext(ctx, checkTags, arg.Accountid, arg.Column2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CheckTagsRow + for rows.Next() { + var i CheckTagsRow + if err := rows.Scan( + &i.Amoid, + &i.Entity, + &i.Name, + &i.Color, + &i.Amoid_2, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const checkUsers = `-- name: CheckUsers :many +WITH new_users AS ( + SELECT (u->>'AmocrmID')::INT AS AmoID, + (u->>'Name')::VARCHAR(512) AS Name, + (u->>'Group')::INT AS "Group", + (u->>'Role')::INT AS Role, + (u->>'Email')::VARCHAR(50) AS Email, + (u->>'AmoUserID')::INT AS AmoUserID, + CURRENT_TIMESTAMP AS createdAt + FROM json_array_elements($1::json) AS u +), inserted_users AS ( + INSERT INTO users (AmoID, Name, "Group", Role, Email, AmoUserID,createdAt) + SELECT nu.AmoID, + nu.Name, + nu."Group", + nu.Role, + nu.Email, + nu.AmoUserID, + nu.createdAt + FROM new_users nu + ON CONFLICT (amoID) DO NOTHING + RETURNING id, accountid, amoid, name, email, role, "Group", deleted, createdat, subdomain, amouserid, country +) +SELECT nu.amoid, nu.name, nu."Group", nu.role, nu.email, nu.amouserid, nu.createdat +FROM new_users nu +WHERE NOT EXISTS ( + SELECT id, accountid, amoid, name, email, role, "Group", deleted, createdat, subdomain, amouserid, country + FROM inserted_users ins + WHERE ins.amoID = nu.amoID +) +` + +type CheckUsersRow struct { + Amoid int32 `db:"amoid" json:"amoid"` + Name string `db:"name" json:"name"` + Group int32 `db:"Group" json:"Group"` + Role int32 `db:"role" json:"role"` + Email string `db:"email" json:"email"` + Amouserid int32 `db:"amouserid" json:"amouserid"` + Createdat interface{} `db:"createdat" json:"createdat"` +} + +func (q *Queries) CheckUsers(ctx context.Context, dollar_1 json.RawMessage) ([]CheckUsersRow, error) { + rows, err := q.db.QueryContext(ctx, checkUsers, dollar_1) + if err != nil { + return nil, err + } + defer rows.Close() + var items []CheckUsersRow + for rows.Next() { + var i CheckUsersRow + if err := rows.Scan( + &i.Amoid, + &i.Name, + &i.Group, + &i.Role, + &i.Email, + &i.Amouserid, + &i.Createdat, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const copyQuestion = `-- name: CopyQuestion :one INSERT INTO question( quiz_id, title, description, questiontype, required, @@ -312,6 +767,70 @@ func (q *Queries) CreateAccount(ctx context.Context, arg CreateAccountParams) er return err } +const createAmoAccount = `-- name: CreateAmoAccount :exec + +INSERT INTO users (AccountID, AmoID, Name, Email, Role, "Group", Deleted, CreatedAt, Subdomain, AmoUserID, Country) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) +` + +type CreateAmoAccountParams struct { + Accountid string `db:"accountid" json:"accountid"` + Amoid int32 `db:"amoid" json:"amoid"` + Name string `db:"name" json:"name"` + Email string `db:"email" json:"email"` + Role int32 `db:"role" json:"role"` + Group int32 `db:"Group" json:"Group"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` + Subdomain string `db:"subdomain" json:"subdomain"` + Amouserid int32 `db:"amouserid" json:"amouserid"` + Country string `db:"country" json:"country"` +} + +// amo methods: +func (q *Queries) CreateAmoAccount(ctx context.Context, arg CreateAmoAccountParams) error { + _, err := q.db.ExecContext(ctx, createAmoAccount, + arg.Accountid, + arg.Amoid, + arg.Name, + arg.Email, + arg.Role, + arg.Group, + arg.Deleted, + arg.Createdat, + arg.Subdomain, + arg.Amouserid, + arg.Country, + ) + return err +} + +const createWebHook = `-- name: CreateWebHook :exec +INSERT INTO tokens (AccountID, RefreshToken, AccessToken, AuthCode, Expiration, CreatedAt) +VALUES ($1, $2, $3, $4, $5, $6) +` + +type CreateWebHookParams struct { + Accountid string `db:"accountid" json:"accountid"` + Refreshtoken string `db:"refreshtoken" json:"refreshtoken"` + Accesstoken string `db:"accesstoken" json:"accesstoken"` + Authcode string `db:"authcode" json:"authcode"` + Expiration time.Time `db:"expiration" json:"expiration"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` +} + +func (q *Queries) CreateWebHook(ctx context.Context, arg CreateWebHookParams) error { + _, err := q.db.ExecContext(ctx, createWebHook, + arg.Accountid, + arg.Refreshtoken, + arg.Accesstoken, + arg.Authcode, + arg.Expiration, + arg.Createdat, + ) + return err +} + const deleteAccountById = `-- name: DeleteAccountById :exec DELETE FROM account WHERE id = $1 ` @@ -321,6 +840,24 @@ func (q *Queries) DeleteAccountById(ctx context.Context, id uuid.UUID) error { return err } +const deleteFields = `-- name: DeleteFields :exec +UPDATE fields SET Deleted = true WHERE ID = ANY($1::bigint[]) +` + +func (q *Queries) DeleteFields(ctx context.Context, dollar_1 []int64) error { + _, err := q.db.ExecContext(ctx, deleteFields, pq.Array(dollar_1)) + return err +} + +const deletePipelines = `-- name: DeletePipelines :exec +UPDATE pipelines SET Deleted = true WHERE ID = ANY($1::bigint[]) +` + +func (q *Queries) DeletePipelines(ctx context.Context, dollar_1 []int64) error { + _, err := q.db.ExecContext(ctx, deletePipelines, pq.Array(dollar_1)) + return err +} + const deletePrivilegeByAccID = `-- name: DeletePrivilegeByAccID :exec DELETE FROM privileges WHERE account_id = $1 ` @@ -410,6 +947,42 @@ func (q *Queries) DeleteQuizByID(ctx context.Context, arg DeleteQuizByIDParams) return i, err } +const deleteSteps = `-- name: DeleteSteps :exec +UPDATE steps SET Deleted = true WHERE ID = ANY($1::bigint[]) +` + +func (q *Queries) DeleteSteps(ctx context.Context, dollar_1 []int64) error { + _, err := q.db.ExecContext(ctx, deleteSteps, pq.Array(dollar_1)) + return err +} + +const deleteTags = `-- name: DeleteTags :exec +UPDATE tags SET Deleted = true WHERE ID = ANY($1::bigint[]) +` + +func (q *Queries) DeleteTags(ctx context.Context, dollar_1 []int64) error { + _, err := q.db.ExecContext(ctx, deleteTags, pq.Array(dollar_1)) + return err +} + +const deleteUsers = `-- name: DeleteUsers :exec +UPDATE users SET Deleted = true WHERE ID = ANY($1::bigint[]) +` + +func (q *Queries) DeleteUsers(ctx context.Context, dollar_1 []int64) error { + _, err := q.db.ExecContext(ctx, deleteUsers, pq.Array(dollar_1)) + return err +} + +const deletingUTM = `-- name: DeletingUTM :exec +UPDATE utms SET Deleted = true WHERE ID = ANY($1::int[]) +` + +func (q *Queries) DeletingUTM(ctx context.Context, dollar_1 []int32) error { + _, err := q.db.ExecContext(ctx, deletingUTM, pq.Array(dollar_1)) + return err +} + const deviceStatistics = `-- name: DeviceStatistics :many WITH DeviceStats AS ( SELECT @@ -857,6 +1430,64 @@ func (q *Queries) GetAllAnswersByQuizID(ctx context.Context, session sql.NullStr return items, nil } +const getAllTokens = `-- name: GetAllTokens :many +SELECT accountid, refreshtoken, accesstoken, authcode, expiration, createdat FROM tokens +` + +func (q *Queries) GetAllTokens(ctx context.Context) ([]Token, error) { + rows, err := q.db.QueryContext(ctx, getAllTokens) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Token + for rows.Next() { + var i Token + if err := rows.Scan( + &i.Accountid, + &i.Refreshtoken, + &i.Accesstoken, + &i.Authcode, + &i.Expiration, + &i.Createdat, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getCurrentAccount = `-- name: GetCurrentAccount :one +SELECT id, accountid, amoid, name, email, role, "Group", deleted, createdat, subdomain, amouserid, country FROM users WHERE AccountID = $1 +` + +func (q *Queries) GetCurrentAccount(ctx context.Context, accountid string) (User, error) { + row := q.db.QueryRowContext(ctx, getCurrentAccount, accountid) + var i User + err := row.Scan( + &i.ID, + &i.Accountid, + &i.Amoid, + &i.Name, + &i.Email, + &i.Role, + &i.Group, + &i.Deleted, + &i.Createdat, + &i.Subdomain, + &i.Amouserid, + &i.Country, + ) + return i, err +} + const getExpiredPrivilege = `-- name: GetExpiredPrivilege :many SELECT id, privilegeID, privilege_name, amount, created_at FROM privileges @@ -901,6 +1532,87 @@ func (q *Queries) GetExpiredPrivilege(ctx context.Context, privilegeid sql.NullS return items, nil } +const getFieldByAmoID = `-- name: GetFieldByAmoID :one +SELECT id, amoid, code, accountid, name, entity, type, deleted, createdat FROM fields WHERE AmoID = $1 AND Deleted = false +` + +func (q *Queries) GetFieldByAmoID(ctx context.Context, amoid int32) (Field, error) { + row := q.db.QueryRowContext(ctx, getFieldByAmoID, amoid) + var i Field + err := row.Scan( + &i.ID, + &i.Amoid, + &i.Code, + &i.Accountid, + &i.Name, + &i.Entity, + &i.Type, + &i.Deleted, + &i.Createdat, + ) + return i, err +} + +const getFieldsWithPagination = `-- name: GetFieldsWithPagination :many +SELECT f.id, f.amoid, f.code, f.accountid, f.name, f.entity, f.type, f.deleted, f.createdat, COUNT(*) OVER() as total_count +FROM fields f JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1) u ON f.AccountID = u.AmoID +WHERE f.Deleted = false +ORDER BY f.ID OFFSET ($2 - 1) * $3 LIMIT $3 +` + +type GetFieldsWithPaginationParams struct { + Accountid string `db:"accountid" json:"accountid"` + Column2 interface{} `db:"column_2" json:"column_2"` + Limit int32 `db:"limit" json:"limit"` +} + +type GetFieldsWithPaginationRow struct { + ID int64 `db:"id" json:"id"` + Amoid int32 `db:"amoid" json:"amoid"` + Code string `db:"code" json:"code"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Entity interface{} `db:"entity" json:"entity"` + Type interface{} `db:"type" json:"type"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` + TotalCount int64 `db:"total_count" json:"total_count"` +} + +func (q *Queries) GetFieldsWithPagination(ctx context.Context, arg GetFieldsWithPaginationParams) ([]GetFieldsWithPaginationRow, error) { + rows, err := q.db.QueryContext(ctx, getFieldsWithPagination, arg.Accountid, arg.Column2, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetFieldsWithPaginationRow + for rows.Next() { + var i GetFieldsWithPaginationRow + if err := rows.Scan( + &i.ID, + &i.Amoid, + &i.Code, + &i.Accountid, + &i.Name, + &i.Entity, + &i.Type, + &i.Deleted, + &i.Createdat, + &i.TotalCount, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const getListCreatedQuizzes = `-- name: GetListCreatedQuizzes :many SELECT id FROM quiz @@ -957,6 +1669,62 @@ func (q *Queries) GetListStartQuiz(ctx context.Context, accountid string) ([]int return items, nil } +const getPipelinesWithPagination = `-- name: GetPipelinesWithPagination :many +SELECT p.id, p.amoid, p.accountid, p.name, p.isarchive, p.deleted, p.createdat, COUNT(*) OVER() as total_count +FROM pipelines p JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1) u ON p.AccountID = u.AmoID +WHERE p.Deleted = false +ORDER BY p.ID OFFSET ($2 - 1) * $3 LIMIT $3 +` + +type GetPipelinesWithPaginationParams struct { + Accountid string `db:"accountid" json:"accountid"` + Column2 interface{} `db:"column_2" json:"column_2"` + Limit int32 `db:"limit" json:"limit"` +} + +type GetPipelinesWithPaginationRow struct { + ID int64 `db:"id" json:"id"` + Amoid int32 `db:"amoid" json:"amoid"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Isarchive bool `db:"isarchive" json:"isarchive"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` + TotalCount int64 `db:"total_count" json:"total_count"` +} + +func (q *Queries) GetPipelinesWithPagination(ctx context.Context, arg GetPipelinesWithPaginationParams) ([]GetPipelinesWithPaginationRow, error) { + rows, err := q.db.QueryContext(ctx, getPipelinesWithPagination, arg.Accountid, arg.Column2, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetPipelinesWithPaginationRow + for rows.Next() { + var i GetPipelinesWithPaginationRow + if err := rows.Scan( + &i.ID, + &i.Amoid, + &i.Accountid, + &i.Name, + &i.Isarchive, + &i.Deleted, + &i.Createdat, + &i.TotalCount, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const getPrivilegesByAccountID = `-- name: GetPrivilegesByAccountID :many SELECT id,privilegeID,privilege_name,amount, created_at FROM privileges WHERE account_id = $1 ` @@ -1157,6 +1925,47 @@ func (q *Queries) GetQuestionHistory(ctx context.Context, arg GetQuestionHistory return items, nil } +const getQuestionListByIDs = `-- name: GetQuestionListByIDs :many +SELECT id, quiz_id, title, description, questiontype, required, deleted, page, content, version, parent_ids, created_at, updated_at FROM question WHERE id = ANY($1::int[]) AND deleted = FALSE +` + +func (q *Queries) GetQuestionListByIDs(ctx context.Context, dollar_1 []int32) ([]Question, error) { + rows, err := q.db.QueryContext(ctx, getQuestionListByIDs, pq.Array(dollar_1)) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Question + for rows.Next() { + var i Question + if err := rows.Scan( + &i.ID, + &i.QuizID, + &i.Title, + &i.Description, + &i.Questiontype, + &i.Required, + &i.Deleted, + &i.Page, + &i.Content, + &i.Version, + pq.Array(&i.ParentIds), + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const getQuestionTitle = `-- name: GetQuestionTitle :one SELECT title, questiontype,page FROM question WHERE id = $1 ` @@ -1394,6 +2203,28 @@ func (q *Queries) GetQuizHistory(ctx context.Context, arg GetQuizHistoryParams) return items, nil } +const getQuizRule = `-- name: GetQuizRule :one +SELECT id, accountid, quizid, performerid, pipelineid, stepid, utms, fieldsrule, deleted, createdat FROM rules WHERE QuizID = $1 AND Deleted = false +` + +func (q *Queries) GetQuizRule(ctx context.Context, quizid int32) (Rule, error) { + row := q.db.QueryRowContext(ctx, getQuizRule, quizid) + var i Rule + err := row.Scan( + &i.ID, + &i.Accountid, + &i.Quizid, + &i.Performerid, + &i.Pipelineid, + &i.Stepid, + pq.Array(&i.Utms), + &i.Fieldsrule, + &i.Deleted, + &i.Createdat, + ) + return i, err +} + const getResultAnswers = `-- name: GetResultAnswers :many SELECT DISTINCT on (question_id) id, content, quiz_id, question_id, fingerprint, session,created_at, result, new,deleted, device_type,device,os,browser,ip FROM answer WHERE session = ( SELECT session FROM answer WHERE answer.id = $1) ORDER BY question_id, created_at DESC @@ -1456,6 +2287,619 @@ func (q *Queries) GetResultAnswers(ctx context.Context, id int64) ([]GetResultAn return items, nil } +const getStepsWithPagination = `-- name: GetStepsWithPagination :many +SELECT s.id, s.amoid, s.pipelineid, s.accountid, s.name, s.color, s.deleted, s.createdat, COUNT(*) OVER() as total_count +FROM steps s JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1) u ON s.AccountID = u.AmoID +WHERE s.Deleted = false +ORDER BY s.ID OFFSET ($2 - 1) * $3 LIMIT $3 +` + +type GetStepsWithPaginationParams struct { + Accountid string `db:"accountid" json:"accountid"` + Column2 interface{} `db:"column_2" json:"column_2"` + Limit int32 `db:"limit" json:"limit"` +} + +type GetStepsWithPaginationRow struct { + ID int64 `db:"id" json:"id"` + Amoid int32 `db:"amoid" json:"amoid"` + Pipelineid int32 `db:"pipelineid" json:"pipelineid"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Color string `db:"color" json:"color"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` + TotalCount int64 `db:"total_count" json:"total_count"` +} + +func (q *Queries) GetStepsWithPagination(ctx context.Context, arg GetStepsWithPaginationParams) ([]GetStepsWithPaginationRow, error) { + rows, err := q.db.QueryContext(ctx, getStepsWithPagination, arg.Accountid, arg.Column2, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetStepsWithPaginationRow + for rows.Next() { + var i GetStepsWithPaginationRow + if err := rows.Scan( + &i.ID, + &i.Amoid, + &i.Pipelineid, + &i.Accountid, + &i.Name, + &i.Color, + &i.Deleted, + &i.Createdat, + &i.TotalCount, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTagsWithPagination = `-- name: GetTagsWithPagination :many +SELECT t.id, t.amoid, t.accountid, t.entity, t.name, t.color, t.deleted, t.createdat, COUNT(*) OVER() as total_count +FROM tags t JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1) u ON t.AccountID = u.AmoID +WHERE t.Deleted = false +ORDER BY t.ID OFFSET ($2 - 1) * $3 LIMIT $3 +` + +type GetTagsWithPaginationParams struct { + Accountid string `db:"accountid" json:"accountid"` + Column2 interface{} `db:"column_2" json:"column_2"` + Limit int32 `db:"limit" json:"limit"` +} + +type GetTagsWithPaginationRow struct { + ID int64 `db:"id" json:"id"` + Amoid int32 `db:"amoid" json:"amoid"` + Accountid int32 `db:"accountid" json:"accountid"` + Entity interface{} `db:"entity" json:"entity"` + Name string `db:"name" json:"name"` + Color string `db:"color" json:"color"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` + TotalCount int64 `db:"total_count" json:"total_count"` +} + +func (q *Queries) GetTagsWithPagination(ctx context.Context, arg GetTagsWithPaginationParams) ([]GetTagsWithPaginationRow, error) { + rows, err := q.db.QueryContext(ctx, getTagsWithPagination, arg.Accountid, arg.Column2, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetTagsWithPaginationRow + for rows.Next() { + var i GetTagsWithPaginationRow + if err := rows.Scan( + &i.ID, + &i.Amoid, + &i.Accountid, + &i.Entity, + &i.Name, + &i.Color, + &i.Deleted, + &i.Createdat, + &i.TotalCount, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTokenById = `-- name: GetTokenById :one +SELECT accountid, refreshtoken, accesstoken, authcode, expiration, createdat FROM tokens WHERE accountID = $1 +` + +func (q *Queries) GetTokenById(ctx context.Context, accountid string) (Token, error) { + row := q.db.QueryRowContext(ctx, getTokenById, accountid) + var i Token + err := row.Scan( + &i.Accountid, + &i.Refreshtoken, + &i.Accesstoken, + &i.Authcode, + &i.Expiration, + &i.Createdat, + ) + return i, err +} + +const getUTMsWithPagination = `-- name: GetUTMsWithPagination :many +SELECT ut.id, ut.amofieldid, ut.quizid, ut.accountid, ut.name, ut.deleted, ut.createdat, COUNT(*) OVER() as total_count +FROM utms ut JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1) u ON ut.AccountID = u.AmoID +WHERE ut.Deleted = false and ut.QuizID = $4 +ORDER BY ut.ID OFFSET ($2 - 1) * $3 LIMIT $3 +` + +type GetUTMsWithPaginationParams struct { + Accountid string `db:"accountid" json:"accountid"` + Column2 interface{} `db:"column_2" json:"column_2"` + Limit int32 `db:"limit" json:"limit"` + Quizid int32 `db:"quizid" json:"quizid"` +} + +type GetUTMsWithPaginationRow struct { + ID int64 `db:"id" json:"id"` + Amofieldid int32 `db:"amofieldid" json:"amofieldid"` + Quizid int32 `db:"quizid" json:"quizid"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` + TotalCount int64 `db:"total_count" json:"total_count"` +} + +func (q *Queries) GetUTMsWithPagination(ctx context.Context, arg GetUTMsWithPaginationParams) ([]GetUTMsWithPaginationRow, error) { + rows, err := q.db.QueryContext(ctx, getUTMsWithPagination, + arg.Accountid, + arg.Column2, + arg.Limit, + arg.Quizid, + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetUTMsWithPaginationRow + for rows.Next() { + var i GetUTMsWithPaginationRow + if err := rows.Scan( + &i.ID, + &i.Amofieldid, + &i.Quizid, + &i.Accountid, + &i.Name, + &i.Deleted, + &i.Createdat, + &i.TotalCount, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserFieldsByID = `-- name: GetUserFieldsByID :many +SELECT ID,AmoID,Code,AccountID,Name,Entity,Type +FROM fields +WHERE AccountID = $1 AND Deleted = false +` + +type GetUserFieldsByIDRow struct { + ID int64 `db:"id" json:"id"` + Amoid int32 `db:"amoid" json:"amoid"` + Code string `db:"code" json:"code"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Entity interface{} `db:"entity" json:"entity"` + Type interface{} `db:"type" json:"type"` +} + +func (q *Queries) GetUserFieldsByID(ctx context.Context, accountid int32) ([]GetUserFieldsByIDRow, error) { + rows, err := q.db.QueryContext(ctx, getUserFieldsByID, accountid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetUserFieldsByIDRow + for rows.Next() { + var i GetUserFieldsByIDRow + if err := rows.Scan( + &i.ID, + &i.Amoid, + &i.Code, + &i.Accountid, + &i.Name, + &i.Entity, + &i.Type, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserPipelinesByID = `-- name: GetUserPipelinesByID :many +SELECT ID,AmoID,AccountID,Name,IsArchive +FROM pipelines +WHERE AccountID = $1 AND Deleted = false +` + +type GetUserPipelinesByIDRow struct { + ID int64 `db:"id" json:"id"` + Amoid int32 `db:"amoid" json:"amoid"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Isarchive bool `db:"isarchive" json:"isarchive"` +} + +func (q *Queries) GetUserPipelinesByID(ctx context.Context, accountid int32) ([]GetUserPipelinesByIDRow, error) { + rows, err := q.db.QueryContext(ctx, getUserPipelinesByID, accountid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetUserPipelinesByIDRow + for rows.Next() { + var i GetUserPipelinesByIDRow + if err := rows.Scan( + &i.ID, + &i.Amoid, + &i.Accountid, + &i.Name, + &i.Isarchive, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserStepsByID = `-- name: GetUserStepsByID :many +SELECT ID,AmoID,PipelineID,AccountID,Name,Color +FROM steps +WHERE AccountID = $1 AND Deleted = false +` + +type GetUserStepsByIDRow struct { + ID int64 `db:"id" json:"id"` + Amoid int32 `db:"amoid" json:"amoid"` + Pipelineid int32 `db:"pipelineid" json:"pipelineid"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Color string `db:"color" json:"color"` +} + +func (q *Queries) GetUserStepsByID(ctx context.Context, accountid int32) ([]GetUserStepsByIDRow, error) { + rows, err := q.db.QueryContext(ctx, getUserStepsByID, accountid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetUserStepsByIDRow + for rows.Next() { + var i GetUserStepsByIDRow + if err := rows.Scan( + &i.ID, + &i.Amoid, + &i.Pipelineid, + &i.Accountid, + &i.Name, + &i.Color, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserTagsByID = `-- name: GetUserTagsByID :many +SELECT ID,AmoID,AccountID,Name,Entity,Color +FROM tags +WHERE AccountID = $1 AND Deleted = false +` + +type GetUserTagsByIDRow struct { + ID int64 `db:"id" json:"id"` + Amoid int32 `db:"amoid" json:"amoid"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Entity interface{} `db:"entity" json:"entity"` + Color string `db:"color" json:"color"` +} + +func (q *Queries) GetUserTagsByID(ctx context.Context, accountid int32) ([]GetUserTagsByIDRow, error) { + rows, err := q.db.QueryContext(ctx, getUserTagsByID, accountid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetUserTagsByIDRow + for rows.Next() { + var i GetUserTagsByIDRow + if err := rows.Scan( + &i.ID, + &i.Amoid, + &i.Accountid, + &i.Name, + &i.Entity, + &i.Color, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserUsersByID = `-- name: GetUserUsersByID :many +SELECT ID,AccountID,AmoID,Name,Email,Role,"Group",Subdomain,AmoUserID,Country +FROM users +WHERE AmoUserID = $1 AND Deleted = false +` + +type GetUserUsersByIDRow struct { + ID int64 `db:"id" json:"id"` + Accountid string `db:"accountid" json:"accountid"` + Amoid int32 `db:"amoid" json:"amoid"` + Name string `db:"name" json:"name"` + Email string `db:"email" json:"email"` + Role int32 `db:"role" json:"role"` + Group int32 `db:"Group" json:"Group"` + Subdomain string `db:"subdomain" json:"subdomain"` + Amouserid int32 `db:"amouserid" json:"amouserid"` + Country string `db:"country" json:"country"` +} + +func (q *Queries) GetUserUsersByID(ctx context.Context, amouserid int32) ([]GetUserUsersByIDRow, error) { + rows, err := q.db.QueryContext(ctx, getUserUsersByID, amouserid) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetUserUsersByIDRow + for rows.Next() { + var i GetUserUsersByIDRow + if err := rows.Scan( + &i.ID, + &i.Accountid, + &i.Amoid, + &i.Name, + &i.Email, + &i.Role, + &i.Group, + &i.Subdomain, + &i.Amouserid, + &i.Country, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUsersWithPagination = `-- name: GetUsersWithPagination :many +WITH user_data AS ( + SELECT AmoID FROM users WHERE users.AccountID = $1 AND Deleted = false +) +SELECT u.id, u.accountid, u.amoid, u.name, u.email, u.role, u."Group", u.deleted, u.createdat, u.subdomain, u.amouserid, u.country, COUNT(*) OVER() as total_count +FROM users u +JOIN user_data a ON u.AmoUserID = a.AmoID +WHERE u.Deleted = false +ORDER BY u.ID OFFSET ($2 - 1) * $3 LIMIT $3 +` + +type GetUsersWithPaginationParams struct { + Accountid string `db:"accountid" json:"accountid"` + Column2 interface{} `db:"column_2" json:"column_2"` + Limit int32 `db:"limit" json:"limit"` +} + +type GetUsersWithPaginationRow struct { + ID int64 `db:"id" json:"id"` + Accountid string `db:"accountid" json:"accountid"` + Amoid int32 `db:"amoid" json:"amoid"` + Name string `db:"name" json:"name"` + Email string `db:"email" json:"email"` + Role int32 `db:"role" json:"role"` + Group int32 `db:"Group" json:"Group"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` + Subdomain string `db:"subdomain" json:"subdomain"` + Amouserid int32 `db:"amouserid" json:"amouserid"` + Country string `db:"country" json:"country"` + TotalCount int64 `db:"total_count" json:"total_count"` +} + +func (q *Queries) GetUsersWithPagination(ctx context.Context, arg GetUsersWithPaginationParams) ([]GetUsersWithPaginationRow, error) { + rows, err := q.db.QueryContext(ctx, getUsersWithPagination, arg.Accountid, arg.Column2, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetUsersWithPaginationRow + for rows.Next() { + var i GetUsersWithPaginationRow + if err := rows.Scan( + &i.ID, + &i.Accountid, + &i.Amoid, + &i.Name, + &i.Email, + &i.Role, + &i.Group, + &i.Deleted, + &i.Createdat, + &i.Subdomain, + &i.Amouserid, + &i.Country, + &i.TotalCount, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUtmsByID = `-- name: GetUtmsByID :many +SELECT ID,AmoFieldID,QuizID,AccountID,Name +FROM utms +WHERE + ID = ANY($1::int[]) AND Deleted = FALSE +` + +type GetUtmsByIDRow struct { + ID int64 `db:"id" json:"id"` + Amofieldid int32 `db:"amofieldid" json:"amofieldid"` + Quizid int32 `db:"quizid" json:"quizid"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` +} + +func (q *Queries) GetUtmsByID(ctx context.Context, dollar_1 []int32) ([]GetUtmsByIDRow, error) { + rows, err := q.db.QueryContext(ctx, getUtmsByID, pq.Array(dollar_1)) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetUtmsByIDRow + for rows.Next() { + var i GetUtmsByIDRow + if err := rows.Scan( + &i.ID, + &i.Amofieldid, + &i.Quizid, + &i.Accountid, + &i.Name, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const gettingAmoUsersTrueResults = `-- name: GettingAmoUsersTrueResults :many +SELECT a.quiz_id,a.id,a.result,a.question_id,a.content,a.session,t.accesstoken,r.accountid,r.utms,r.fieldsrule,r.performerid,r.stepid,r.pipelineid,(SELECT u.name FROM users u WHERE u.amoid = r.performerid) AS performer_name +FROM answer a + INNER JOIN quiz q ON a.quiz_id = q.id + LEFT JOIN amoCRMStatuses s ON a.id = s.AnswerID + INNER JOIN rules r ON q.id = r.QuizID + INNER JOIN tokens t ON q.accountid = t.AccountID + INNER JOIN users u ON q.accountid = u.accountid AND u.amoid = r.accountid +WHERE a.result = true + AND s.id IS NULL + AND a.deleted = false + AND r.deleted = false + AND q.deleted = false +` + +type GettingAmoUsersTrueResultsRow struct { + QuizID int64 `db:"quiz_id" json:"quiz_id"` + ID int64 `db:"id" json:"id"` + Result sql.NullBool `db:"result" json:"result"` + QuestionID int64 `db:"question_id" json:"question_id"` + Content sql.NullString `db:"content" json:"content"` + Session sql.NullString `db:"session" json:"session"` + Accesstoken string `db:"accesstoken" json:"accesstoken"` + Accountid int32 `db:"accountid" json:"accountid"` + Utms []int32 `db:"utms" json:"utms"` + Fieldsrule json.RawMessage `db:"fieldsrule" json:"fieldsrule"` + Performerid int32 `db:"performerid" json:"performerid"` + Stepid int32 `db:"stepid" json:"stepid"` + Pipelineid int32 `db:"pipelineid" json:"pipelineid"` + PerformerName string `db:"performer_name" json:"performer_name"` +} + +func (q *Queries) GettingAmoUsersTrueResults(ctx context.Context) ([]GettingAmoUsersTrueResultsRow, error) { + rows, err := q.db.QueryContext(ctx, gettingAmoUsersTrueResults) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GettingAmoUsersTrueResultsRow + for rows.Next() { + var i GettingAmoUsersTrueResultsRow + if err := rows.Scan( + &i.QuizID, + &i.ID, + &i.Result, + &i.QuestionID, + &i.Content, + &i.Session, + &i.Accesstoken, + &i.Accountid, + pq.Array(&i.Utms), + &i.Fieldsrule, + &i.Performerid, + &i.Stepid, + &i.Pipelineid, + &i.PerformerName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const insertAnswers = `-- name: InsertAnswers :exec INSERT INTO answer( content, @@ -1907,6 +3351,146 @@ func (q *Queries) QuizCopyQid(ctx context.Context, arg QuizCopyQidParams) (QuizC return i, err } +const saveUTMs = `-- name: SaveUTMs :many +WITH user_data AS ( + SELECT AmoID + FROM users + WHERE users.AccountID = $1 +), new_UTMs AS ( + SELECT (utm->>'AmoFieldID')::INT AS amoFieldID, + COALESCE(utm->>'QuizID', '')::INT AS quizID, + COALESCE(utm->>'Name', '')::varchar(512) AS name, + CURRENT_TIMESTAMP AS createdAt + FROM json_array_elements($2::json) AS utm +), inserted_utms AS( + INSERT INTO utms (AmoFieldID, QuizID, AccountID, Name, createdAt) + SELECT nu.amoFieldID, + nu.quizID, + ud.AmoID, + nu.name, + nu.createdAt + FROM new_UTMs nu + JOIN user_data ud ON true + RETURNING id, amofieldid, quizid, accountid, name, deleted, createdat +) +SELECT id, amofieldid, quizid, accountid, name, deleted, createdat from inserted_utms +` + +type SaveUTMsParams struct { + Accountid string `db:"accountid" json:"accountid"` + Column2 json.RawMessage `db:"column_2" json:"column_2"` +} + +type SaveUTMsRow struct { + ID int64 `db:"id" json:"id"` + Amofieldid int32 `db:"amofieldid" json:"amofieldid"` + Quizid int32 `db:"quizid" json:"quizid"` + Accountid int32 `db:"accountid" json:"accountid"` + Name string `db:"name" json:"name"` + Deleted bool `db:"deleted" json:"deleted"` + Createdat sql.NullTime `db:"createdat" json:"createdat"` +} + +func (q *Queries) SaveUTMs(ctx context.Context, arg SaveUTMsParams) ([]SaveUTMsRow, error) { + rows, err := q.db.QueryContext(ctx, saveUTMs, arg.Accountid, arg.Column2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []SaveUTMsRow + for rows.Next() { + var i SaveUTMsRow + if err := rows.Scan( + &i.ID, + &i.Amofieldid, + &i.Quizid, + &i.Accountid, + &i.Name, + &i.Deleted, + &i.Createdat, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const setQuizSettings = `-- name: SetQuizSettings :exec +INSERT INTO rules (AccountID, QuizID, PerformerID, PipelineID, StepID, UTMS, FieldsRule) +SELECT u.AmoID AS AccountID,$1 AS QuizID,$2 AS PerformerID,$3 AS PipelineID, + $4 AS StepID,$5 AS UTMS,$6 AS FieldsRule FROM users u WHERE u.AccountID = $7 +` + +type SetQuizSettingsParams struct { + Quizid int32 `db:"quizid" json:"quizid"` + Performerid int32 `db:"performerid" json:"performerid"` + Pipelineid int32 `db:"pipelineid" json:"pipelineid"` + Stepid int32 `db:"stepid" json:"stepid"` + Utms []int32 `db:"utms" json:"utms"` + Fieldsrule json.RawMessage `db:"fieldsrule" json:"fieldsrule"` + Accountid string `db:"accountid" json:"accountid"` +} + +func (q *Queries) SetQuizSettings(ctx context.Context, arg SetQuizSettingsParams) error { + _, err := q.db.ExecContext(ctx, setQuizSettings, + arg.Quizid, + arg.Performerid, + arg.Pipelineid, + arg.Stepid, + pq.Array(arg.Utms), + arg.Fieldsrule, + arg.Accountid, + ) + return err +} + +const settingDealAmoStatus = `-- name: SettingDealAmoStatus :exec +INSERT INTO amoCRMStatuses (AccountID, DealID, AnswerID, Status) +SELECT u.AmoID, $1, $2, $3 +FROM tokens AS t + JOIN users AS u ON t.AccountID = u.AccountID +WHERE t.AccessToken = $4 +` + +type SettingDealAmoStatusParams struct { + Dealid int32 `db:"dealid" json:"dealid"` + Answerid int64 `db:"answerid" json:"answerid"` + Status string `db:"status" json:"status"` + Accesstoken string `db:"accesstoken" json:"accesstoken"` +} + +func (q *Queries) SettingDealAmoStatus(ctx context.Context, arg SettingDealAmoStatusParams) error { + _, err := q.db.ExecContext(ctx, settingDealAmoStatus, + arg.Dealid, + arg.Answerid, + arg.Status, + arg.Accesstoken, + ) + return err +} + +const softDeleteAccount = `-- name: SoftDeleteAccount :exec +WITH userd AS ( + SELECT AmoUserID FROM users WHERE users.AccountID = $1 +), + tokend AS ( + UPDATE users SET Deleted = true WHERE AmoUserID IN (SELECT AmoUserID FROM userd) RETURNING users.AccountID + ) +DELETE FROM tokens WHERE tokens.AccountID IN (SELECT AccountID FROM tokend) +` + +func (q *Queries) SoftDeleteAccount(ctx context.Context, accountid string) error { + _, err := q.db.ExecContext(ctx, softDeleteAccount, accountid) + return err +} + const softDeleteResultByID = `-- name: SoftDeleteResultByID :exec UPDATE answer SET deleted = TRUE WHERE id = $1 AND deleted = FALSE ` @@ -1941,6 +3525,52 @@ func (q *Queries) TemplateCopy(ctx context.Context, arg TemplateCopyParams) erro return err } +const updateFieldRules = `-- name: UpdateFieldRules :exec +UPDATE rules SET FieldsRule = $1 +WHERE AccountID = (SELECT AmoID FROM users WHERE users.AccountID = $2) AND QuizID = $3 AND Deleted = false +` + +type UpdateFieldRulesParams struct { + Fieldsrule json.RawMessage `db:"fieldsrule" json:"fieldsrule"` + Accountid string `db:"accountid" json:"accountid"` + Quizid int32 `db:"quizid" json:"quizid"` +} + +func (q *Queries) UpdateFieldRules(ctx context.Context, arg UpdateFieldRulesParams) error { + _, err := q.db.ExecContext(ctx, updateFieldRules, arg.Fieldsrule, arg.Accountid, arg.Quizid) + return err +} + +const updateFields = `-- name: UpdateFields :exec +UPDATE fields AS f +SET name = (update_data ->> 'Name')::varchar(512), + code = (update_data ->> 'Code')::varchar(255), + type = (update_data ->> 'Type')::fieldtype +FROM json_array_elements($1::json) AS update_data +WHERE f.amoID = (update_data ->> 'AmoID')::INT + AND f.accountID = (update_data ->> 'AccountID')::INT + AND f.Entity = (update_data ->> 'Entity')::entitytype +` + +func (q *Queries) UpdateFields(ctx context.Context, dollar_1 json.RawMessage) error { + _, err := q.db.ExecContext(ctx, updateFields, dollar_1) + return err +} + +const updatePipelines = `-- name: UpdatePipelines :exec +UPDATE pipelines AS p +SET name = (update_data ->> 'Name')::varchar(512), + isArchive = CASE WHEN (update_data ->> 'IsArchive') = 'true' THEN TRUE ELSE FALSE END +FROM json_array_elements($1::json) AS update_data +WHERE p.amoID = (update_data ->> 'AmoID')::INT + AND p.accountID = (update_data ->> 'AccountID')::INT +` + +func (q *Queries) UpdatePipelines(ctx context.Context, dollar_1 json.RawMessage) error { + _, err := q.db.ExecContext(ctx, updatePipelines, dollar_1) + return err +} + const updatePrivilege = `-- name: UpdatePrivilege :exec UPDATE privileges SET amount = $1, created_at = $2 WHERE account_id = $3 AND privilegeID = $4 ` @@ -1976,6 +3606,127 @@ func (q *Queries) UpdatePrivilegeAmount(ctx context.Context, arg UpdatePrivilege return err } +const updateSteps = `-- name: UpdateSteps :exec +UPDATE steps AS s +SET name = (update_data ->> 'Name')::varchar(512), + color = (update_data ->> 'Color')::varchar(50) +FROM json_array_elements($1::json) AS update_data +WHERE s.amoID = (update_data ->> 'AmoID')::INT + AND s.accountID = (update_data ->> 'AccountID')::INT + AND s.pipelineID = (update_data ->> 'PipelineID')::INT +` + +func (q *Queries) UpdateSteps(ctx context.Context, dollar_1 json.RawMessage) error { + _, err := q.db.ExecContext(ctx, updateSteps, dollar_1) + return err +} + +const updateTags = `-- name: UpdateTags :exec +UPDATE tags AS t +SET name = (update_data ->> 'Name')::varchar(512), + color = (update_data ->> 'Color')::varchar(50) +FROM json_array_elements($1::json) AS update_data +WHERE t.amoID = (update_data ->> 'AmoID')::INT + AND t.accountID = (update_data ->> 'AccountID')::INT + AND t.Entity = (update_data ->> 'Entity')::entitytype +` + +func (q *Queries) UpdateTags(ctx context.Context, dollar_1 json.RawMessage) error { + _, err := q.db.ExecContext(ctx, updateTags, dollar_1) + return err +} + +const updateUsers = `-- name: UpdateUsers :exec +UPDATE users AS u +SET Name = (update_data ->> 'Name')::varchar(512), + Email = (update_data ->> 'Email')::varchar(50), + Role = (update_data ->> 'Role')::INT, + "Group" = (update_data ->> 'Group')::INT, + AmoUserID= (update_data ->> 'AmoUserID')::INT +FROM json_array_elements($1::json) AS update_data +WHERE u.AmoID = (update_data ->> 'AmocrmID')::INT +` + +func (q *Queries) UpdateUsers(ctx context.Context, dollar_1 json.RawMessage) error { + _, err := q.db.ExecContext(ctx, updateUsers, dollar_1) + return err +} + +const updateUtms = `-- name: UpdateUtms :exec +UPDATE utms AS u +SET name = (update_data ->> 'Name')::varchar(512), + AmoFieldID = (update_data ->> 'AmoFieldID')::INT +FROM json_array_elements($1::json) AS update_data +WHERE u.ID = (update_data ->> 'ID')::INT +` + +func (q *Queries) UpdateUtms(ctx context.Context, dollar_1 json.RawMessage) error { + _, err := q.db.ExecContext(ctx, updateUtms, dollar_1) + return err +} + +const updateUtmsFields = `-- name: UpdateUtmsFields :exec +UPDATE utms AS u SET AmoFieldID = f.AmoID FROM fields AS f +WHERE u.Name = f.Name AND u.ID = ANY($1::int[]) AND u.Deleted = FALSE +` + +func (q *Queries) UpdateUtmsFields(ctx context.Context, dollar_1 []int32) error { + _, err := q.db.ExecContext(ctx, updateUtmsFields, pq.Array(dollar_1)) + return err +} + +const updatingDealAmoStatus = `-- name: UpdatingDealAmoStatus :exec +UPDATE amoCRMStatuses SET Status = $1 +WHERE DealID = $2 AND AccountID = (SELECT u.AmoID FROM tokens AS t JOIN users AS u ON t.AccountID = u.AccountID WHERE t.AccessToken = $3) +` + +type UpdatingDealAmoStatusParams struct { + Status string `db:"status" json:"status"` + Dealid int32 `db:"dealid" json:"dealid"` + Accesstoken string `db:"accesstoken" json:"accesstoken"` +} + +func (q *Queries) UpdatingDealAmoStatus(ctx context.Context, arg UpdatingDealAmoStatusParams) error { + _, err := q.db.ExecContext(ctx, updatingDealAmoStatus, arg.Status, arg.Dealid, arg.Accesstoken) + return err +} + +const webhookDelete = `-- name: WebhookDelete :exec +WITH userd AS ( + UPDATE users SET Deleted = true WHERE AmoUserID = $1 RETURNING AccountID +) +DELETE FROM tokens WHERE AccountID IN (SELECT AccountID FROM userd) +` + +func (q *Queries) WebhookDelete(ctx context.Context, amouserid int32) error { + _, err := q.db.ExecContext(ctx, webhookDelete, amouserid) + return err +} + +const webhookUpdate = `-- name: WebhookUpdate :exec +UPDATE tokens SET AccessToken = $1,RefreshToken = $2,Expiration = to_timestamp(($3)::bigint) AT TIME ZONE 'UTC' + INTERVAL '3 hours',CreatedAt = to_timestamp(($4)::bigint) AT TIME ZONE 'UTC' + INTERVAL '3 hours' +WHERE accountID = $5 +` + +type WebhookUpdateParams struct { + Accesstoken string `db:"accesstoken" json:"accesstoken"` + Refreshtoken string `db:"refreshtoken" json:"refreshtoken"` + Column3 int64 `db:"column_3" json:"column_3"` + Column4 int64 `db:"column_4" json:"column_4"` + Accountid string `db:"accountid" json:"accountid"` +} + +func (q *Queries) WebhookUpdate(ctx context.Context, arg WebhookUpdateParams) error { + _, err := q.db.ExecContext(ctx, webhookUpdate, + arg.Accesstoken, + arg.Refreshtoken, + arg.Column3, + arg.Column4, + arg.Accountid, + ) + return err +} + const workerStatProcess = `-- name: WorkerStatProcess :exec WITH answer_aggregates AS ( SELECT diff --git a/go.mod b/go.mod index 2f74b5c..9e74c54 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/uuid v1.6.0 github.com/lib/pq v1.10.9 github.com/rs/xid v1.5.0 - google.golang.org/protobuf v1.32.0 + google.golang.org/protobuf v1.33.0 penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240202120244-c4ef330cfe5d penahub.gitlab.yandexcloud.net/backend/quiz/core.git v0.0.0-20240219174804-d78fd38511af ) @@ -18,7 +18,7 @@ require ( require ( github.com/andybalholm/brotli v1.0.5 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -33,11 +33,13 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/rivo/uniseg v0.2.0 // indirect + github.com/sqlc-dev/pqtype v0.3.0 // indirect + github.com/sqlc-dev/sqlc v1.26.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - go.uber.org/atomic v1.7.0 // indirect - golang.org/x/crypto v0.19.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + golang.org/x/crypto v0.20.0 // indirect golang.org/x/net v0.21.0 // indirect golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/go.sum b/go.sum index 12c0db5..51dfdee 100644 --- a/go.sum +++ b/go.sum @@ -33,6 +33,7 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu 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/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -86,6 +87,10 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/sqlc-dev/pqtype v0.3.0 h1:b09TewZ3cSnO5+M1Kqq05y0+OjqIptxELaSayg7bmqk= +github.com/sqlc-dev/pqtype v0.3.0/go.mod h1:oyUjp5981ctiL9UYvj1bVvCKi8OXkCa0u645hce7CAs= +github.com/sqlc-dev/sqlc v1.26.0 h1:bW6TA1vVdi2lfqsEddN5tSznRMYcWez7hf+AOqSiEp8= +github.com/sqlc-dev/sqlc v1.26.0/go.mod h1:k2F3RWilLCup3D0XufrzZENCyXjtplALmHDmOt4v5bs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= @@ -98,8 +103,11 @@ github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVS github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= @@ -122,6 +130,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/middleware/middleware.go b/middleware/middleware.go index bd4290d..0c596d7 100644 --- a/middleware/middleware.go +++ b/middleware/middleware.go @@ -36,6 +36,7 @@ func AnswererChain() fiber.Handler { func JWTAuth() fiber.Handler { return func(c *fiber.Ctx) error { + //todo также сделать для хуков на добавление удаление в амо if c.Path() == "/quiz/logo" { return c.Next() } diff --git a/model/amo.go b/model/amo.go new file mode 100644 index 0000000..ec87d68 --- /dev/null +++ b/model/amo.go @@ -0,0 +1,277 @@ +package model + +type User struct { + /* - айдишник в нашей системе Primary Key*/ + ID int64 `json:"ID"` + /* - id пользователя из токена в нашей системе*/ + Accountid string `json:"AccountID"` + /* - айдишник пользователя в амо*/ + AmoID int32 `json:"AmocrmID"` + /* - имя аккаунта в амо*/ + Name string `json:"Name"` + /* - почта пользователя из амо*/ + Email string `json:"Email"` + /* - роль пользователя в амо*/ + Role int32 `json:"Role"` + /* - группы пользователя в амо*/ + Group int32 `json:"Group"` + /* - флаг мягкого удаления*/ + Deleted bool `json:"Deleted"` + /* - таймштамп создания аккаунта*/ + Createdat int64 `json:"CreatedAt"` + /* - поддомен организации в амо*/ + Subdomain string `json:"Subdomain"` + /* - айдишник пользвателя, который подключал интеграцию*/ + Amouserid int32 `json:"AmoUserID"` + /* - страна указанная в настройках амо*/ + Country string `json:"Country"` +} + +type UserGroups struct { + ID int `json:"id" bson:"id"` + Name string `json:"name" bson:"name"` + UUID interface{} `json:"uuid" bson:"uuid"` +} + +type Token struct { + AccountID string `json:"account_id"` // id в квизе + RefreshToken string `json:"refresh_token"` // 80 дней + AccessToken string `json:"access_token"` // 20 минут + AuthCode string `json:"auth_code"` + Expiration int64 `json:"expiration"` // таймшамп времени когда кончится AccessToken + CreatedAt int64 `json:"created_at"` // таймшамп времени создания, нужен для отслеживания 80 дней +} + +type Pipeline struct { + // айдишник в нашей системе Primary Key + ID int64 `json:"ID"` + /* - айдишник воронки в амо*/ + Amoid int32 `json:"AmoID"` + /* - связь с аккаунтом в интеграции амо id аккаунта в амо*/ + AccountID int32 `json:"AccountID"` + /* - название воронки в амо*/ + Name string `json:"Name"` + /* - флаг архивной воронки в амо*/ + Isarchive bool `json:"IsArchive"` + /* - флаг мягкого удаления*/ + Deleted bool `json:"Deleted"` + /* - таймштамп создания воронки в нашей системе*/ + Createdat int64 `json:"CreatedAt"` +} + +type Step struct { + /* - айдишник в нашей системе Primary Key*/ + ID int64 `json:"ID"` + /* - айдишник шага воронки в амо*/ + Amoid int32 `json:"AmoID"` + /* - айдишник воронки в амо*/ + Pipelineid int32 `json:"PipelineID"` + /* - связь с аккаунтом в интеграции амо id в амо*/ + Accountid int32 `json:"AccountID"` + /* - название воронки в амо*/ + Name string `json:"Name"` + /* - цвет шага в амо*/ + Color string `json:"Color"` + /* - флаг мягкого удаления*/ + Deleted bool `json:"Deleted"` + /* - таймштамп создания воронки в нашей системе*/ + Createdat int64 `json:"CreatedAt"` +} + +type Tag struct { + /* - айдишник в нашей системе Primary Key*/ + ID int64 `json:"ID"` + /* - айдишник тега в амо*/ + Amoid int32 `json:"AmoID"` + /* - связь с аккаунтом в интеграции амо id аккаунта в амо*/ + Accountid int32 `json:"AccountID"` + /* - сущность, к которой принадлежит этот тег. Наверное, стоит сделать через enum в базе*/ + Entity EntityType `json:"Entity"` + /* - название тега в амо*/ + Name string `json:"Name"` + /* - цвет тега в амо*/ + Color *string `json:"Color"` + /* - флаг мягкого удаления*/ + Deleted bool `json:"Deleted"` + /* - таймштамп создания тега в нашей системе*/ + Createdat int64 `json:"CreatedAt"` +} + +type Field struct { + /* - айдишник в нашей системе Primary Key*/ + ID int64 `json:"ID"` + /* - айдишник кастомного поля в амо*/ + Amoid int32 `json:"AmoID"` + /* - кодовое слово в амо*/ + Code string `json:"Code"` + /* - связь с аккаунтом в интеграции амо id аккаунта в амо*/ + Accountid int32 `json:"AccountID"` + /* - название воронки в амо*/ + Name string `json:"Name"` + /* - тип сущности в амо, для которой это кастомное поле*/ + Entity EntityType `json:"Entity"` + /* - тип поля https://www.amocrm.ru/developers/content/crm_platform/custom-fields#%D0%94%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9*/ + Type FieldType `json:"Type"` + /* - флаг мягкого удаления*/ + Deleted bool `json:"Deleted"` + /* - таймштамп создания воронки в нашей системе*/ + Createdat int64 `json:"CreatedAt"` +} + +type EntityType string + +const ( + LeadsType EntityType = "leads" + ContactsType EntityType = "contacts" + CompaniesType EntityType = "companies" + CustomersType EntityType = "customers" +) + +type Rule struct { + /* - айдишник в нашей системе*/ + ID int64 `json:"ID"` + /* - связь с аккаунтом в интеграции амо id в амо*/ + Accountid int32 `json:"AccountID"` + /* - айдишник опроса*/ + Quizid int32 `json:"QuizID"` + /* - айдишник ответственного за сделку*/ + Performerid int32 `json:"PerformerID"` + /* - айдишник воронки*/ + Pipelineid int32 `json:"PipelineID"` + /* - айдишник этапа*/ + Stepid int32 `json:"StepID"` + /* - список UTM для этого опроса*/ + Utms []int32 `json:"UTMs"` + /* - правила заполнения полей сущностей в амо*/ + Fieldsrule Fieldsrule `json:"FieldsRule"` + /* - флаг мягкого удаления*/ + Deleted bool `json:"Deleted"` + /* - таймштамп создания воронки в нашей системе*/ + Createdat int64 `json:"CreatedAt"` +} + +type Fieldsrule struct { + Lead []FieldRule `json:"Lead"` + Contact ContactRules `json:"Contact"` + Company []FieldRule `json:"Company"` + Customer []FieldRule `json:"Customer"` +} + +type FieldRule struct { + /* - сопоставление айдишника вопроса полю, которое будет заполняться ответом. соответственно QuestionID это айдишник вопроса. это я так мэпу пытался записать*/ + Questionid map[int]int `json:"QuestionID"` // ключ id вопроса значение id астомного поля +} + +type ContactRules struct { + // ключ имя, значение id кастомного поля + ContactRuleMap map[string]int +} + +type QuizContact struct { + FormContact struct { + Fields struct { + Name ContactField `json:"name"` + Email ContactField `json:"email"` + Phone ContactField `json:"phone"` + Text ContactField `json:"text"` + Address ContactField `json:"address"` + } `json:"fields"` + } `json:"formContact"` +} + +type ContactField struct { + Text string `json:"text"` + InnerText string `json:"innerText"` + Key string `json:"key"` + Required bool `json:"required"` + Used bool `json:"used"` +} + +type ContactQuizConfig string + +const ( + TypeContactName ContactQuizConfig = "name" + TypeContactEmail ContactQuizConfig = "email" + TypeContactPhone ContactQuizConfig = "phone" + TypeContactText ContactQuizConfig = "text" + TypeContactAddress ContactQuizConfig = "address" +) + +type UTM struct { + /* - айдишник в нашей системе Primary Key*/ + ID int64 `json:"ID"` + /* - айдишник кастомного поля в амо*/ + Amofieldid int32 `json:"AmoFieldID"` + /* - айдишник квиза*/ + Quizid int32 `json:"QuizID"` + /* - связь с аккаунтом в интеграции амо id амо*/ + Accountid int32 `json:"AccountID"` + /* - название тега в амо*/ + Name string `json:"Name"` + /* - флаг мягкого удаления*/ + Deleted bool `json:"Deleted"` + /* - таймштамп создания тега в нашей системе*/ + Createdat int64 `json:"CreatedAt"` +} + +type FieldType string + +const ( + TypeAmoText FieldType = "text" //Текст + TypeAmoNumeric FieldType = "numeric" //Число + TypeAmoCheckbox FieldType = "checkbox" //Флаг + TypeAmoSelect FieldType = "select" //Список + TypeAmoMultiselect FieldType = "multiselect" //Мультисписок + TypeAmoDate FieldType = "date" //Дата + TypeAmoUrl FieldType = "url" // Ссылка + TypeAmoTextarea FieldType = "textarea" // Текстовая область + TypeAmoRadiobutton FieldType = "radiobutton" // Переключатель + TypeAmoStreetAddress FieldType = "streetaddress" // Короткий адрес + TypeAmoSmartAddress FieldType = "smart_address" // Адрес + TypeAmoBirthday FieldType = "birthday" // День рождения + TypeAmoLegalEntity FieldType = "legal_entity" // Юр. лицо + TypeAmoDateTime FieldType = "date_time" // Дата и время + TypeAmoPrice FieldType = "price" //Цена + TypeAmoCategory FieldType = "category" // Категория + TypeAmoItems FieldType = "items" // Предметы + TypeAmoTrackingData FieldType = "tracking_data" // Отслеживаемые данные + TypeAmoLinkedEntity FieldType = "linked_entity" // Связь с другим элементом + TypeAmoChainedList FieldType = "chained_list" // Каталоги и списки (платная опция Супер-поля) + TypeAmoMonetary FieldType = "monetary" // Денежное (платная опция Супер-поля) + TypeAmoFile FieldType = "file" // Файл + TypeAmoPayer FieldType = "payer" // Плательщик (только в списке Счета-покупки) + TypeAmoSupplier FieldType = "supplier" // Поставщик (только в списке Счета-покупки) + TypeAmoMultiText FieldType = "multitext" // что то чего нет в списке полей но она есть в амо)) +) + +var TypeMapping = map[string]FieldType{ + "variant": TypeAmoText, //TypeAmoChainedList, + "images": TypeAmoText, //TypeAmoFile, + "varimg": TypeAmoText, //TypeAmoFile, + "file": TypeAmoFile, + "text": TypeAmoText, + "emoji": TypeAmoText, + "select": TypeAmoText, //TypeAmoSelect, + "date": TypeAmoText, //TypeAmoDate, + "number": TypeAmoText, //TypeAmoNumeric, + "page": TypeAmoText, + "rating": TypeAmoText, + "result": TypeAmoText, +} + +type AmoUsersTrueResults struct { + QuizID int64 + AnswerID int64 + Result bool + QuestionID int64 + Content string + Session string + AccessToken string + AmoAccountID int32 + UTMs []int32 + FieldsRule Fieldsrule + PerformerID int32 + StepID int32 + PipelineID int32 + PerformerName string +} diff --git a/model/amoReq.go b/model/amoReq.go new file mode 100644 index 0000000..81f7209 --- /dev/null +++ b/model/amoReq.go @@ -0,0 +1,26 @@ +package model + +type ListDeleteUTMIDsReq struct { + /* - список айдишников utm которые удалить*/ + Utms []int32 `json:"utms"` +} + +type PaginationReq struct { + /* - указание страницы пагинации. Если страница не указана, применять 0*/ + Page int `json:"page"` + /* - указание размера страницы пагинации. По умолчанию применять 25*/ + Size int32 `json:"size"` +} + +type RulesReq struct { + PerformerID int32 // айдишник ответственного за сделку + PipelineID int32 // айдишник воронки + StepID int32 // айдишник этапа + Utms []int32 // список UTM для этого опроса + Fieldsrule Fieldsrule // правила заполнения полей сущностей в амо +} + +type SaveUserListUTMReq struct { + /* - список utm для сохранения. сохранять только те, которых в этом аккаунте ещё нет*/ + Utms []UTM `json:"utms"` +} diff --git a/model/amoResp.go b/model/amoResp.go new file mode 100644 index 0000000..b23663e --- /dev/null +++ b/model/amoResp.go @@ -0,0 +1,72 @@ +package model + +type ConnectAccountResp struct { + /* - ссылка для авторизации в амо*/ + Link string `json:"link"` +} + +type GetCurrentAccountResp struct { + /* - айдишник в нашей системе Primary Key*/ + ID int64 `json:"ID"` + /* - имя аккаунта в амо*/ + Name string `json:"Name"` + /* - поддомен организации в амо*/ + Subdomain string `json:"Subdomain"` + /* - id пользователя из токена в нашей системе*/ + Accountid string `json:"AccountID"` + /* - айдишник пользвателя, который подключал интеграцию*/ + Amouserid int32 `json:"AmoUserID"` + /* - связь с аккаунтом в амо*/ + Amocrmid int32 `json:"AmocrmID"` + /* - страна указанная в настройках амо*/ + Country string `json:"Country"` + /* - таймштамп создания аккаунта*/ + Createdat int64 `json:"CreatedAt"` +} + +type GetListUserUTMResp struct { + /* - общее количество юзеров, которые у нас закешированы для этого пользователя*/ + Count int64 `json:"count"` + /* - список юзеров, которые были закешированы нашим сервисом*/ + Items []UTM `json:"items"` +} + +type ListSavedIDUTMResp struct { + /* - список айдишников сохранённых меток*/ + Ids []int64 `json:"IDs"` +} + +type UserListFieldsResp struct { + /* - общее количество кастомных полей, которые у нас закешированы для этого пользователя*/ + Count int64 `json:"count"` + /* - список кастомных полей, которые были закешированы нашим сервисом*/ + Items []Field `json:"items"` +} + +type UserListPipelinesResp struct { + /* - общее количество воронок, которые у нас закешированы для этого пользователя*/ + Count int64 `json:"count"` + /* - список воронок, которые были закешированы нашим сервисом*/ + Items []Pipeline `json:"items"` +} + +type UserListResp struct { + /* - общее количество юзеров, которые у нас закешированы для этого пользователя*/ + Count int64 `json:"count"` + /* - список юзеров, которые были закешированы нашим сервисом*/ + Items []User `json:"items"` +} + +type UserListStepsResp struct { + /* - список шагов воронок, которые были закешированы нашим сервисом*/ + Items []Step `json:"items"` + /* - общее количество шагов воронок, которые у нас закешированы для этого пользователя*/ + Count int64 `json:"count"` +} + +type UserListTagsResp struct { + /* - общее количество тегов, которые у нас закешированы для этого пользователя*/ + Count int64 `json:"count"` + /* - список тегов, которые были закешированы нашим сервисом*/ + Items []Tag `json:"items"` +} diff --git a/repository/amo/amo.go b/repository/amo/amo.go new file mode 100644 index 0000000..f8a262a --- /dev/null +++ b/repository/amo/amo.go @@ -0,0 +1,1074 @@ +package amo + +import ( + "context" + "database/sql" + "encoding/json" + "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal/sqlcgen" + "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model" + "time" +) + +type AmoRepository struct { + queries *sqlcgen.Queries + pool *sql.DB +} + +type Deps struct { + Queries *sqlcgen.Queries + Pool *sql.DB +} + +func NewAmoRepository(deps Deps) *AmoRepository { + return &AmoRepository{ + queries: deps.Queries, + pool: deps.Pool, + } +} + +// методы пользователя + +func (r *AmoRepository) GettingUserWithPagination(ctx context.Context, req *model.PaginationReq, accountID string) (*model.UserListResp, error) { + rows, err := r.queries.GetUsersWithPagination(ctx, sqlcgen.GetUsersWithPaginationParams{ + Column2: req.Page, + Limit: req.Size, + Accountid: accountID, + }) + + if err != nil { + return nil, err + } + var count int64 + var users []model.User + for _, row := range rows { + user := model.User{ + ID: row.ID, + Accountid: row.Accountid, + AmoID: row.Amoid, + Name: row.Name, + Email: row.Email, + Group: row.Group, + Role: row.Role, + Createdat: row.Createdat.Time.Unix(), + Subdomain: row.Subdomain, + Amouserid: row.Amouserid, + Country: row.Country, + } + count = row.TotalCount + + users = append(users, user) + } + + resp := model.UserListResp{ + Count: count, + Items: users, + } + + return &resp, nil +} + +func (r *AmoRepository) SoftDeleteAccount(ctx context.Context, accountID string) error { + err := r.queries.SoftDeleteAccount(ctx, accountID) + if err != nil { + return err + } + return nil +} + +func (r *AmoRepository) GetCurrentAccount(ctx context.Context, accountID string) (*model.User, error) { + row, err := r.queries.GetCurrentAccount(ctx, accountID) + if err != nil { + return nil, err + } + + user := model.User{ + ID: row.ID, + Accountid: row.Accountid, + AmoID: row.Amoid, + Name: row.Name, + Email: row.Email, + Role: row.Role, + Group: row.Group, + Createdat: row.Createdat.Time.Unix(), + Subdomain: row.Subdomain, + Amouserid: row.Amouserid, + Country: row.Country, + } + + return &user, nil +} + +func (r *AmoRepository) CreateAccount(ctx context.Context, accountID string, userInfo model.User) error { + err := r.queries.CreateAmoAccount(ctx, sqlcgen.CreateAmoAccountParams{ + Accountid: accountID, + Amoid: userInfo.AmoID, + Name: userInfo.Name, + Email: userInfo.Email, + Role: userInfo.Role, + Group: userInfo.Group, + Createdat: sql.NullTime{Time: time.Now(), Valid: true}, + Subdomain: userInfo.Subdomain, + Amouserid: userInfo.Amouserid, + Country: userInfo.Country, + }) + + if err != nil { + return err + } + + return nil +} + +func (r *AmoRepository) CheckMainUser(ctx context.Context, user model.User) error { + err := r.queries.CheckMainUser(ctx, sqlcgen.CheckMainUserParams{ + Name: user.Name, + Group: user.Group, + Email: user.Email, + Role: user.Role, + Amoid: user.AmoID, + }) + + if err != nil { + return err + } + + return nil +} + +func (r *AmoRepository) CheckAndUpdateUsers(ctx context.Context, users []model.User) error { + dollar1, err := json.Marshal(users) + if err != nil { + return err + } + rows, err := r.queries.CheckUsers(ctx, dollar1) + if err != nil { + return err + } + + if rows != nil { + var toUpdate []model.User + for _, row := range rows { + to := model.User{ + AmoID: row.Amoid, + Name: row.Name, + Group: row.Group, + Role: row.Role, + Email: row.Email, + Amouserid: row.Amouserid, + } + toUpdate = append(toUpdate, to) + } + dollar1, err := json.Marshal(toUpdate) + if err != nil { + return err + } + + err = r.queries.UpdateUsers(ctx, dollar1) + if err != nil { + return err + } + } + + return nil +} + +func (r *AmoRepository) GetTokenByID(ctx context.Context, accountID string) (*model.Token, error) { + row, err := r.queries.GetTokenById(ctx, accountID) + if err != nil { + return nil, err + } + + return &model.Token{ + AccountID: row.Accountid, + RefreshToken: row.Refreshtoken, + AccessToken: row.Accesstoken, + }, nil +} + +func (r *AmoRepository) DeleteUsers(ctx context.Context, ids []int64) error { + err := r.queries.DeleteUsers(ctx, ids) + if err != nil { + return err + } + return nil +} + +func (r *AmoRepository) GetUserUsersByID(ctx context.Context, amoUserID int32) ([]model.User, error) { + rows, err := r.queries.GetUserUsersByID(ctx, amoUserID) + if err != nil { + return nil, err + } + + var users []model.User + for _, row := range rows { + user := model.User{ + ID: row.ID, + Accountid: row.Accountid, + AmoID: row.Amoid, + Name: row.Name, + Email: row.Email, + Group: row.Group, + Role: row.Role, + Subdomain: row.Subdomain, + Amouserid: row.Amouserid, + Country: row.Country, + } + + users = append(users, user) + } + + return users, nil +} + +// методы webhook + +func (r *AmoRepository) WebhookCreate(ctx context.Context, tokens model.Token) error { + err := r.queries.CreateWebHook(ctx, sqlcgen.CreateWebHookParams{ + Accountid: tokens.AccountID, + Refreshtoken: tokens.RefreshToken, + Accesstoken: tokens.AccessToken, + Authcode: tokens.AuthCode, + Expiration: time.Unix(tokens.Expiration, 0).In(time.Unix(tokens.CreatedAt, 0).Location()), + Createdat: sql.NullTime{Time: time.Unix(tokens.CreatedAt, 0), Valid: true}, + }) + + if err != nil { + return err + } + + return nil +} + +func (r *AmoRepository) WebhookUpdate(ctx context.Context, token model.Token) error { + err := r.queries.WebhookUpdate(ctx, sqlcgen.WebhookUpdateParams{ + Accesstoken: token.AccessToken, + Refreshtoken: token.RefreshToken, + Accountid: token.AccountID, + Column3: token.Expiration, + Column4: token.CreatedAt, + }) + if err != nil { + return err + } + + return nil +} + +// воркер запускается каждые 5 минут, поэтомму ищем токены котторые исекают менее чем через 10 минут отдаем их на обноление +func (r *AmoRepository) CheckExpired(ctx context.Context) ([]model.Token, error) { + rows, err := r.queries.CheckExpired(ctx) + if err != nil { + return nil, err + } + + var tokens []model.Token + + for _, row := range rows { + token := model.Token{ + AccountID: row.Accountid, + AccessToken: row.Accesstoken, + RefreshToken: row.Refreshtoken, + AuthCode: row.Authcode, + Expiration: row.Expiration.Unix(), + CreatedAt: row.Createdat.Time.Unix(), + } + + tokens = append(tokens, token) + } + + return tokens, nil +} + +func (r *AmoRepository) GetAllTokens(ctx context.Context) ([]model.Token, error) { + rows, err := r.queries.GetAllTokens(ctx) + if err != nil { + return nil, err + } + + var tokens []model.Token + + for _, row := range rows { + token := model.Token{ + AccountID: row.Accountid, + AccessToken: row.Accesstoken, + RefreshToken: row.Refreshtoken, + AuthCode: row.Authcode, + Expiration: row.Expiration.Unix(), + CreatedAt: row.Createdat.Time.Unix(), + } + + tokens = append(tokens, token) + } + + return tokens, nil +} + +func (r *AmoRepository) WebhookDelete(ctx context.Context, amoID int) error { + err := r.queries.WebhookDelete(ctx, int32(amoID)) + if err != nil { + return err + } + return nil +} + +// методы pipelines + +func (r *AmoRepository) GetPipelinesWithPagination(ctx context.Context, req *model.PaginationReq, accountID string) (*model.UserListPipelinesResp, error) { + rows, err := r.queries.GetPipelinesWithPagination(ctx, sqlcgen.GetPipelinesWithPaginationParams{ + Accountid: accountID, + Column2: req.Page, + Limit: req.Size, + }) + if err != nil { + return nil, err + } + + var count int64 + var pipelines []model.Pipeline + + for _, row := range rows { + count = row.TotalCount + pipeline := model.Pipeline{ + ID: row.ID, + Amoid: row.Amoid, + AccountID: row.Accountid, + Name: row.Name, + Isarchive: row.Isarchive, + Createdat: row.Createdat.Time.Unix(), + } + pipelines = append(pipelines, pipeline) + } + + resp := model.UserListPipelinesResp{ + Count: count, + Items: pipelines, + } + return &resp, nil +} + +func (r *AmoRepository) CheckPipelines(ctx context.Context, pipelines []model.Pipeline) error { + dollar1, err := json.Marshal(pipelines) + if err != nil { + return err + } + rows, err := r.queries.CheckPipelines(ctx, dollar1) + if err != nil { + return err + } + + if rows != nil { + var toUpdate []model.Pipeline + for _, row := range rows { + to := model.Pipeline{ + Amoid: row.Amoid, + AccountID: row.Accountid, + Name: row.Name, + Isarchive: row.Isarchive, + } + toUpdate = append(toUpdate, to) + } + dollar1, err := json.Marshal(toUpdate) + if err != nil { + return err + } + + err = r.queries.UpdatePipelines(ctx, dollar1) + if err != nil { + return err + } + } + + return nil +} + +func (r *AmoRepository) DeletePipelines(ctx context.Context, ids []int64) error { + err := r.queries.DeletePipelines(ctx, ids) + if err != nil { + return err + } + return nil +} + +func (r *AmoRepository) GetUserPipelinesByID(ctx context.Context, accountID int32) ([]model.Pipeline, error) { + rows, err := r.queries.GetUserPipelinesByID(ctx, accountID) + if err != nil { + return nil, err + } + + var pipelines []model.Pipeline + + for _, row := range rows { + pipeline := model.Pipeline{ + ID: row.ID, + Amoid: row.Amoid, + AccountID: row.Accountid, + Name: row.Name, + Isarchive: row.Isarchive, + } + pipelines = append(pipelines, pipeline) + } + + return pipelines, nil +} + +// методы steps + +func (r *AmoRepository) GetStepsWithPagination(ctx context.Context, req *model.PaginationReq, accountID string) (*model.UserListStepsResp, error) { + rows, err := r.queries.GetStepsWithPagination(ctx, sqlcgen.GetStepsWithPaginationParams{ + Accountid: accountID, + Column2: req.Page, + Limit: req.Size, + }) + if err != nil { + return nil, err + } + + var count int64 + var steps []model.Step + + for _, row := range rows { + count = row.TotalCount + step := model.Step{ + ID: row.ID, + Amoid: row.Amoid, + Pipelineid: row.Pipelineid, + Accountid: row.Accountid, + Name: row.Name, + Color: row.Color, + Createdat: row.Createdat.Time.Unix(), + } + steps = append(steps, step) + } + + resp := model.UserListStepsResp{ + Count: count, + Items: steps, + } + + return &resp, nil +} + +func (r *AmoRepository) CheckSteps(ctx context.Context, steps []model.Step) error { + dollar1, err := json.Marshal(steps) + if err != nil { + return err + } + + rows, err := r.queries.CheckSteps(ctx, dollar1) + if err != nil { + return err + } + + if rows != nil { + var toUpdate []model.Step + for _, row := range rows { + to := model.Step{ + Amoid: row.Amoid, + Pipelineid: row.Pipelineid, + Accountid: row.Accountid, + Name: row.Name, + Color: row.Color, + } + toUpdate = append(toUpdate, to) + } + + dollar1, err := json.Marshal(toUpdate) + if err != nil { + return err + } + + err = r.queries.UpdateSteps(ctx, dollar1) + if err != nil { + return err + } + } + + return nil +} + +func (r *AmoRepository) DeleteSteps(ctx context.Context, ids []int64) error { + err := r.queries.DeleteSteps(ctx, ids) + if err != nil { + return err + } + return nil +} + +func (r *AmoRepository) GetUserStepsByID(ctx context.Context, accountID int32) ([]model.Step, error) { + rows, err := r.queries.GetUserStepsByID(ctx, accountID) + if err != nil { + return nil, err + } + + var steps []model.Step + + for _, row := range rows { + step := model.Step{ + ID: row.ID, + Amoid: row.Amoid, + Pipelineid: row.Pipelineid, + Accountid: row.Accountid, + Name: row.Name, + Color: row.Color, + } + steps = append(steps, step) + } + + return steps, nil +} + +// методы tags + +func (r *AmoRepository) GetTagsWithPagination(ctx context.Context, req *model.PaginationReq, accountID string) (*model.UserListTagsResp, error) { + rows, err := r.queries.GetTagsWithPagination(ctx, sqlcgen.GetTagsWithPaginationParams{ + Accountid: accountID, + Column2: req.Page, + Limit: req.Size, + }) + if err != nil { + return nil, err + } + + var count int64 + var tags []model.Tag + for _, row := range rows { + count = row.TotalCount + + var entity model.EntityType + v := string(row.Entity.([]byte)) + entity = model.EntityType(v) + + tag := model.Tag{ + ID: row.ID, + Amoid: row.Amoid, + Accountid: row.Accountid, + Entity: entity, + Name: row.Name, + Color: &row.Color, + Createdat: row.Createdat.Time.Unix(), + } + tags = append(tags, tag) + } + + resp := model.UserListTagsResp{ + Count: count, + Items: tags, + } + + return &resp, nil +} + +func (r *AmoRepository) CheckTags(ctx context.Context, tags []model.Tag, tokenID string) error { + column2, err := json.Marshal(tags) + if err != nil { + return err + } + + rows, err := r.queries.CheckTags(ctx, sqlcgen.CheckTagsParams{ + Accountid: tokenID, + Column2: column2, + }) + + if rows != nil { + var toUpdate []model.Tag + for _, row := range rows { + var entity model.EntityType + v := string(row.Entity.([]byte)) + entity = model.EntityType(v) + to := model.Tag{ + Amoid: row.Amoid, + Accountid: row.Amoid_2, + Entity: entity, + Name: row.Name, + Color: &row.Color, + } + toUpdate = append(toUpdate, to) + } + + dollar1, err := json.Marshal(toUpdate) + if err != nil { + return err + } + + err = r.queries.UpdateTags(ctx, dollar1) + if err != nil { + return err + } + } + + if err != nil { + return err + } + return nil +} + +func (r *AmoRepository) DeleteTags(ctx context.Context, ids []int64) error { + err := r.queries.DeleteTags(ctx, ids) + if err != nil { + return err + } + return nil +} + +func (r *AmoRepository) GetUserTagsByID(ctx context.Context, accountID int32) ([]model.Tag, error) { + rows, err := r.queries.GetUserTagsByID(ctx, accountID) + if err != nil { + return nil, err + } + + var tags []model.Tag + for _, row := range rows { + var entity model.EntityType + v := string(row.Entity.([]byte)) + entity = model.EntityType(v) + + tag := model.Tag{ + ID: row.ID, + Amoid: row.Amoid, + Accountid: row.Accountid, + Entity: entity, + Name: row.Name, + Color: &row.Color, + } + tags = append(tags, tag) + } + + return tags, nil +} + +// методы fields + +func (r *AmoRepository) GetFieldsWithPagination(ctx context.Context, req *model.PaginationReq, accountID string) (*model.UserListFieldsResp, error) { + rows, err := r.queries.GetFieldsWithPagination(ctx, sqlcgen.GetFieldsWithPaginationParams{ + Accountid: accountID, + Column2: req.Page, + Limit: req.Size, + }) + if err != nil { + return nil, err + } + + var count int64 + var fields []model.Field + + for _, row := range rows { + count = row.TotalCount + + var entity model.EntityType + v := string(row.Entity.([]byte)) + entity = model.EntityType(v) + + var fieldType model.FieldType + f := string(row.Type.([]byte)) + fieldType = model.FieldType(f) + + field := model.Field{ + ID: row.ID, + Amoid: row.Amoid, + Code: row.Code, + Accountid: row.Accountid, + Name: row.Name, + Entity: entity, + Type: fieldType, + Createdat: row.Createdat.Time.Unix(), + } + + fields = append(fields, field) + } + + resp := model.UserListFieldsResp{ + Count: count, + Items: fields, + } + + return &resp, nil +} + +func (r *AmoRepository) CheckFields(ctx context.Context, fields []model.Field, tokenID string) error { + column2, err := json.Marshal(fields) + if err != nil { + return err + } + + rows, err := r.queries.CheckFields(ctx, sqlcgen.CheckFieldsParams{ + Accountid: tokenID, + Column2: column2, + }) + + if err != nil { + return err + } + + if rows != nil { + var toUpdate []model.Field + for _, row := range rows { + var entity model.EntityType + v := string(row.Entity.([]byte)) + entity = model.EntityType(v) + + var fieldType model.FieldType + f := string(row.Type.([]byte)) + fieldType = model.FieldType(f) + + to := model.Field{ + Amoid: row.Amoid, + Code: row.Code, + Accountid: row.Amoid_2, + Entity: entity, + Type: fieldType, + Name: row.Name, + } + toUpdate = append(toUpdate, to) + } + + dollar1, err := json.Marshal(toUpdate) + if err != nil { + return err + } + + err = r.queries.UpdateFields(ctx, dollar1) + if err != nil { + return err + } + } + return nil +} + +func (r *AmoRepository) GetUserFieldsByID(ctx context.Context, accountID int32) ([]model.Field, error) { + rows, err := r.queries.GetUserFieldsByID(ctx, accountID) + if err != nil { + return nil, err + } + var fields []model.Field + for _, row := range rows { + + var entity model.EntityType + v := string(row.Entity.([]byte)) + entity = model.EntityType(v) + + var fieldType model.FieldType + f := string(row.Type.([]byte)) + fieldType = model.FieldType(f) + + field := model.Field{ + ID: row.ID, + Amoid: row.Amoid, + Code: row.Code, + Accountid: row.Accountid, + Name: row.Name, + Entity: entity, + Type: fieldType, + } + + fields = append(fields, field) + } + + return fields, err +} + +func (r *AmoRepository) DeleteFields(ctx context.Context, ids []int64) error { + err := r.queries.DeleteFields(ctx, ids) + if err != nil { + return err + } + return nil +} + +func (r *AmoRepository) GetFieldByID(ctx context.Context, amoID int32) (*model.Field, error) { + row, err := r.queries.GetFieldByAmoID(ctx, amoID) + if err != nil { + return nil, err + } + + var entity model.EntityType + v := string(row.Entity.([]byte)) + entity = model.EntityType(v) + + var fieldType model.FieldType + f := string(row.Type.([]byte)) + fieldType = model.FieldType(f) + + return &model.Field{ + ID: row.ID, + Amoid: row.Amoid, + Code: row.Code, + Accountid: row.Accountid, + Name: row.Name, + Entity: entity, + Type: fieldType, + }, nil +} + +// методы rules + +func (r *AmoRepository) ChangeQuizSettings(ctx context.Context, request *model.RulesReq, accountID string, quizID int) error { + jsonFieldRule, err := json.Marshal(request.Fieldsrule) + if err != nil { + return err + } + err = r.queries.ChangeQuizSettings(ctx, sqlcgen.ChangeQuizSettingsParams{ + Performerid: request.PerformerID, + Pipelineid: request.PipelineID, + Stepid: request.StepID, + Utms: request.Utms, + Fieldsrule: jsonFieldRule, + Accountid: accountID, + Quizid: int32(quizID), + }) + + if err != nil { + return err + } + + return nil +} + +func (r *AmoRepository) SetQuizSettings(ctx context.Context, request *model.RulesReq, accountID string, quizID int) error { + jsonFieldRule, err := json.Marshal(request.Fieldsrule) + if err != nil { + return err + } + err = r.queries.SetQuizSettings(ctx, sqlcgen.SetQuizSettingsParams{ + Performerid: request.PerformerID, + Pipelineid: request.PipelineID, + Stepid: request.StepID, + Utms: request.Utms, + Fieldsrule: jsonFieldRule, + Accountid: accountID, + Quizid: int32(quizID), + }) + + if err != nil { + return err + } + + return nil +} + +func (r *AmoRepository) GettingQuizRules(ctx context.Context, quizID int) (*model.Rule, error) { + row, err := r.queries.GetQuizRule(ctx, int32(quizID)) + if err != nil { + return nil, err + } + + var fieldsRule model.Fieldsrule + err = json.Unmarshal(row.Fieldsrule, &fieldsRule) + if err != nil { + return nil, err + } + + return &model.Rule{ + ID: row.ID, + Accountid: row.Accountid, + Quizid: row.Quizid, + Performerid: row.Performerid, + Pipelineid: row.Pipelineid, + Stepid: row.Stepid, + Utms: row.Utms, + Fieldsrule: fieldsRule, + }, nil +} + +func (r *AmoRepository) UpdateFieldRules(ctx context.Context, fieldRules model.Fieldsrule, accountID string, quizID int32) error { + jsonFieldsRule, err := json.Marshal(fieldRules) + if err != nil { + return err + } + err = r.queries.UpdateFieldRules(ctx, sqlcgen.UpdateFieldRulesParams{ + Fieldsrule: jsonFieldsRule, + Accountid: accountID, + Quizid: quizID, + }) + + if err != nil { + return err + } + + return nil +} + +// методы UTMs + +func (r *AmoRepository) DeletingUserUtm(ctx context.Context, request *model.ListDeleteUTMIDsReq) error { + err := r.queries.DeletingUTM(ctx, request.Utms) + if err != nil { + return err + } + return nil +} + +// todo нужно ли тут ограничивать индексом что то +func (r *AmoRepository) SavingUserUtm(ctx context.Context, utms []model.UTM, accountID string) (*model.ListSavedIDUTMResp, error) { + column2, err := json.Marshal(utms) + if err != nil { + return nil, err + } + rows, err := r.queries.SaveUTMs(ctx, sqlcgen.SaveUTMsParams{ + Accountid: accountID, + Column2: column2, + }) + + var ids []int64 + + for _, row := range rows { + ids = append(ids, row.ID) + } + + return &model.ListSavedIDUTMResp{ + Ids: ids, + }, nil +} + +func (r *AmoRepository) GettingUserUtm(ctx context.Context, request *model.PaginationReq, accountID string, quizID int) (*model.GetListUserUTMResp, error) { + rows, err := r.queries.GetUTMsWithPagination(ctx, sqlcgen.GetUTMsWithPaginationParams{ + Accountid: accountID, + Column2: request.Page, + Limit: request.Size, + Quizid: int32(quizID), + }) + + if err != nil { + return nil, err + } + + var count int64 + var utmS []model.UTM + + for _, row := range rows { + count = row.TotalCount + utm := model.UTM{ + ID: row.ID, + Amofieldid: row.Amofieldid, + Quizid: row.Quizid, + Accountid: row.Accountid, + Name: row.Name, + Deleted: row.Deleted, + Createdat: row.Createdat.Time.Unix(), + } + + utmS = append(utmS, utm) + } + + return &model.GetListUserUTMResp{ + Count: count, + Items: utmS, + }, nil +} + +func (r *AmoRepository) GetUtmsByID(ctx context.Context, ids []int32) ([]model.UTM, error) { + rows, err := r.queries.GetUtmsByID(ctx, ids) + if err != nil { + return nil, err + } + + var utmS []model.UTM + for _, row := range rows { + utm := model.UTM{ + ID: row.ID, + Amofieldid: row.Amofieldid, + Quizid: row.Quizid, + Accountid: row.Accountid, + Name: row.Name, + } + + utmS = append(utmS, utm) + } + + return utmS, nil +} + +func (r *AmoRepository) UpdateUTMs(ctx context.Context, utms []model.UTM) error { + dollar1, err := json.Marshal(utms) + if err != nil { + return err + } + err = r.queries.UpdateUtms(ctx, dollar1) + + if err != nil { + return err + } + + return nil +} + +func (r *AmoRepository) UpdateUtmsFields(ctx context.Context, ids []int32) error { + err := r.queries.UpdateUtmsFields(ctx, ids) + if err != nil { + return err + } + + return nil +} + +func (r *AmoRepository) GettingAmoUsersTrueResults(ctx context.Context) ([]model.AmoUsersTrueResults, error) { + rows, err := r.queries.GettingAmoUsersTrueResults(ctx) + if err != nil { + return nil, err + } + + var results []model.AmoUsersTrueResults + + for _, row := range rows { + var fieldsRule model.Fieldsrule + err = json.Unmarshal(row.Fieldsrule, &fieldsRule) + if err != nil { + return nil, err + } + result := model.AmoUsersTrueResults{ + QuizID: row.QuizID, + AnswerID: row.ID, + Result: row.Result.Bool, + QuestionID: row.QuestionID, + Content: row.Content.String, + Session: row.Session.String, + AccessToken: row.Accesstoken, + AmoAccountID: row.Accountid, + UTMs: row.Utms, + FieldsRule: fieldsRule, + PerformerID: row.Performerid, + StepID: row.Stepid, + PipelineID: row.Pipelineid, + PerformerName: row.PerformerName, + } + + results = append(results, result) + } + + return results, nil +} + +type SaveDealAmoDeps struct { + DealID int32 + AnswerID int64 + Status string + AccessToken string +} + +func (r *AmoRepository) SaveDealAmoStatus(ctx context.Context, deps SaveDealAmoDeps) error { + err := r.queries.SettingDealAmoStatus(ctx, sqlcgen.SettingDealAmoStatusParams{ + Dealid: deps.DealID, + Answerid: deps.AnswerID, + Status: deps.Status, + Accesstoken: deps.AccessToken, + }) + + if err != nil { + return err + } + + return nil +} + +func (r *AmoRepository) UpdatingDealAmoStatus(ctx context.Context, deps SaveDealAmoDeps) error { + err := r.queries.UpdatingDealAmoStatus(ctx, sqlcgen.UpdatingDealAmoStatusParams{ + Status: deps.Status, + Accesstoken: deps.AccessToken, + Dealid: deps.DealID, + }) + + if err != nil { + return err + } + + return nil +} diff --git a/repository/answer/answer.go b/repository/answer/answer.go index e579112..7e9c90c 100644 --- a/repository/answer/answer.go +++ b/repository/answer/answer.go @@ -83,6 +83,7 @@ func (r *AnswerRepository) GetAllAnswersByQuizID(ctx context.Context, session st } for _, row := range rows { + //todo тут забыл добавить проверку на то что minio !=nil /*if row.Questiontype == model.TypeFile { fmt.Println("GALL", row.Qid, row.QuestionID, row.Content) fileURL, err := r.answerMinio.GetAnswerURL(ctx, row.Qid.UUID.String(), row.QuestionID, row.Content.String) diff --git a/repository/question/question.go b/repository/question/question.go index 866a35b..88e33e0 100644 --- a/repository/question/question.go +++ b/repository/question/question.go @@ -245,12 +245,12 @@ func (r *QuestionRepository) UpdateQuestion(ctx context.Context, record model.Qu params = append(params, record.Required, record.Version, record.Id) var placeholders []any - for i:=1;i<=len(params);i++ { + for i := 1; i <= len(params); i++ { placeholders = append(placeholders, i) } query = fmt.Sprintf(query, placeholders...) - + _, err := r.pool.ExecContext(ctx, query, params...) return err } @@ -455,3 +455,33 @@ func (r *QuestionRepository) ForSortingResults(ctx context.Context, allAnswers [ return sortedAllAnswers, nil } + +func (r *QuestionRepository) GetQuestionListByIDs(ctx context.Context, ids []int32) ([]model.Question, error) { + rows, err := r.queries.GetQuestionListByIDs(ctx, ids) + if err != nil { + return nil, err + } + + var questions []model.Question + for _, row := range rows { + question := model.Question{ + Id: uint64(row.ID), + QuizId: uint64(row.QuizID), + Title: row.Title, + Description: row.Description.String, + Type: string(row.Questiontype.([]byte)), + Required: row.Required.Bool, + Deleted: row.Deleted.Bool, + Page: int(row.Page.Int16), + Content: row.Content.String, + Version: int(row.Version.Int16), + ParentIds: row.ParentIds, + CreatedAt: row.CreatedAt.Time, + UpdatedAt: row.UpdatedAt.Time, + } + + questions = append(questions, question) + } + + return questions, nil +} diff --git a/sqlc.yaml b/sqlc.yaml index 625e6c4..f25b4b1 100644 --- a/sqlc.yaml +++ b/sqlc.yaml @@ -18,6 +18,12 @@ packages: - "./dal/schema/000006_init.down.sql" - "./dal/schema/000007_init.up.sql" - "./dal/schema/000007_init.down.sql" + - "./dal/schema/000008_init.up.sql" + - "./dal/schema/000008_init.down.sql" + - "./dal/schema/000009_init.up.sql" + - "./dal/schema/000009_init.down.sql" + - "./dal/schema/000010_init.up.sql" + - "./dal/schema/000010_init.down.sql" engine: "postgresql" emit_json_tags: true emit_db_tags: true