megre main into leadTarget

This commit is contained in:
Pavel 2024-06-24 13:45:58 +03:00
commit c23fda5f3f
20 changed files with 1076 additions and 609 deletions

@ -5,6 +5,8 @@ import (
"database/sql" "database/sql"
_ "embed" _ "embed"
"errors" "errors"
"fmt"
_ "github.com/ClickHouse/clickhouse-go"
_ "github.com/lib/pq" _ "github.com/lib/pq"
"github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal/sqlcgen" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal/sqlcgen"
@ -31,6 +33,7 @@ type DAL struct {
ResultRepo *result.ResultRepository ResultRepo *result.ResultRepository
WorkerRepo *workers.WorkerRepository WorkerRepo *workers.WorkerRepository
StatisticsRepo *statistics.StatisticsRepository StatisticsRepo *statistics.StatisticsRepository
WorkerAnsRepo *answer.WorkerAnswerRepository
} }
func New(ctx context.Context, cred string, minioClient *minio.Client) (*DAL, error) { func New(ctx context.Context, cred string, minioClient *minio.Client) (*DAL, error) {
@ -62,12 +65,17 @@ func New(ctx context.Context, cred string, minioClient *minio.Client) (*DAL, err
} }
} }
answerRepo := answer.NewAnswerRepository(answer.Deps{ workerAnsRepo := answer.NewWorkerAnswerRepo(answer.Deps{
Queries: queries, Queries: queries,
Pool: pool, Pool: pool,
AnswerMinio: storerAnswer, AnswerMinio: storerAnswer,
}) })
answerRepo := answer.NewAnswerRepository(answer.Deps{
Queries: queries,
Pool: pool,
})
questionRepo := question.NewQuestionRepository(question.Deps{ questionRepo := question.NewQuestionRepository(question.Deps{
Queries: queries, Queries: queries,
Pool: pool, Pool: pool,
@ -102,6 +110,7 @@ func New(ctx context.Context, cred string, minioClient *minio.Client) (*DAL, err
ResultRepo: resultRepo, ResultRepo: resultRepo,
WorkerRepo: workerRepo, WorkerRepo: workerRepo,
StatisticsRepo: statisticsRepo, StatisticsRepo: statisticsRepo,
WorkerAnsRepo: workerAnsRepo,
}, nil }, nil
} }
@ -177,3 +186,38 @@ func (d *AmoDal) Close(ctx context.Context) error {
} }
return nil return nil
} }
type ClickHouseDAL struct {
conn *sql.DB
StatisticClickRepo *statistics.StatisticClick
}
func NewClickHouseDAL(ctx context.Context, cred string) (*ClickHouseDAL, error) {
conn, err := sql.Open("clickhouse", cred)
if err != nil {
return nil, fmt.Errorf("error open database connection: %w", err)
}
timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
if err := conn.PingContext(timeoutCtx); err != nil {
return nil, fmt.Errorf("error ping database: %w", err)
}
statsClickRepo, err := statistics.NewClickStatistic(ctx, statistics.DepsClick{
Conn: conn,
})
if err != nil {
return nil, err
}
return &ClickHouseDAL{
conn: conn,
StatisticClickRepo: statsClickRepo,
}, nil
}
func (d *ClickHouseDAL) Close(ctx context.Context) error {
return d.conn.Close()
}

@ -20,7 +20,7 @@ INSERT INTO quiz (accountid,
qid qid
) )
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19)
RETURNING id, created_at, updated_at, qid; RETURNING id, created_at, updated_at, qid;
-- name: InsertQuestion :one -- name: InsertQuestion :one
INSERT INTO question ( INSERT INTO question (
@ -35,7 +35,7 @@ INSERT INTO question (
updated_at updated_at
) )
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)
RETURNING id, created_at, updated_at; RETURNING id, created_at, updated_at;
-- name: DeleteQuestion :one -- name: DeleteQuestion :one
UPDATE question SET deleted=true WHERE id=$1 RETURNING question.*; UPDATE question SET deleted=true WHERE id=$1 RETURNING question.*;
@ -51,7 +51,7 @@ INSERT INTO question(
SELECT $1, title, description, questiontype, required, SELECT $1, title, description, questiontype, required,
page, content, version, parent_ids page, content, version, parent_ids
FROM question WHERE question.id=$2 FROM question WHERE question.id=$2
RETURNING question.id, quiz_id, created_at, updated_at; RETURNING question.id, quiz_id, created_at, updated_at;
-- name: DuplicateQuestion :one -- name: DuplicateQuestion :one
INSERT INTO question( INSERT INTO question(
@ -61,7 +61,7 @@ INSERT INTO question(
SELECT quiz_id, title, description, questiontype, required, SELECT quiz_id, title, description, questiontype, required,
page, content, version, parent_ids page, content, version, parent_ids
FROM question WHERE question.id=$1 FROM question WHERE question.id=$1
RETURNING question.id, quiz_id, created_at, updated_at; RETURNING question.id, quiz_id, created_at, updated_at;
-- name: MoveToHistory :one -- name: MoveToHistory :one
INSERT INTO question( INSERT INTO question(
@ -71,7 +71,7 @@ INSERT INTO question(
SELECT quiz_id, title, description, questiontype, required, SELECT quiz_id, title, description, questiontype, required,
page, content, version, parent_ids, true as deleted page, content, version, parent_ids, true as deleted
FROM question WHERE question.id=$1 FROM question WHERE question.id=$1
RETURNING question.id, quiz_id, parent_ids; RETURNING question.id, quiz_id, parent_ids;
-- name: MoveToHistoryQuiz :one -- name: MoveToHistoryQuiz :one
INSERT INTO quiz(deleted, INSERT INTO quiz(deleted,
@ -81,7 +81,7 @@ INSERT INTO quiz(deleted,
SELECT true as deleted, accountid, archived,fingerprinting,repeatable,note_prevented,mail_notifications,unique_answers,name,description,config, SELECT true as deleted, accountid, archived,fingerprinting,repeatable,note_prevented,mail_notifications,unique_answers,name,description,config,
status,limit_answers,due_to,time_of_passing,pausable,version,version_comment,parent_ids,questions_count,answers_count,average_time_passing, super, group_id status,limit_answers,due_to,time_of_passing,pausable,version,version_comment,parent_ids,questions_count,answers_count,average_time_passing, super, group_id
FROM quiz WHERE quiz.id=$1 AND quiz.accountid=$2 FROM quiz WHERE quiz.id=$1 AND quiz.accountid=$2
RETURNING quiz.id, qid, parent_ids; RETURNING quiz.id, qid, parent_ids;
-- name: CopyQuiz :one -- name: CopyQuiz :one
INSERT INTO quiz( INSERT INTO quiz(
@ -91,7 +91,7 @@ INSERT INTO quiz(
SELECT accountid, archived,fingerprinting,repeatable,note_prevented,mail_notifications,unique_answers,name,description,config, SELECT accountid, archived,fingerprinting,repeatable,note_prevented,mail_notifications,unique_answers,name,description,config,
status,limit_answers,due_to,time_of_passing,pausable,version,version_comment,parent_ids,questions_count, super, group_id status,limit_answers,due_to,time_of_passing,pausable,version,version_comment,parent_ids,questions_count, super, group_id
FROM quiz WHERE quiz.id=$1 AND quiz.accountId=$2 FROM quiz WHERE quiz.id=$1 AND quiz.accountId=$2
RETURNING id, qid,created_at, updated_at; RETURNING id, qid,created_at, updated_at;
-- name: CopyQuizQuestions :exec -- name: CopyQuizQuestions :exec
INSERT INTO question( INSERT INTO question(
@ -134,6 +134,7 @@ SELECT
p.amount, p.amount,
p.created_at, p.created_at,
a.id, a.id,
a.email,
qz.config qz.config
FROM FROM
privileges AS p privileges AS p
@ -143,7 +144,7 @@ WHERE
qz.id = $1; qz.id = $1;
-- name: CreateAccount :one -- name: CreateAccount :one
INSERT INTO account (id, user_id, created_at, deleted) VALUES ($1, $2, $3, $4) RETURNING *; INSERT INTO account (id, user_id, email, created_at, deleted) VALUES ($1, $2, $3, $4, $5) RETURNING *;;
-- name: DeletePrivilegeByAccID :exec -- name: DeletePrivilegeByAccID :exec
DELETE FROM privileges WHERE account_id = $1; DELETE FROM privileges WHERE account_id = $1;
@ -232,11 +233,11 @@ SET
answers_count = COALESCE(aa.unique_true_answers_count, 0), answers_count = COALESCE(aa.unique_true_answers_count, 0),
average_time_passing = COALESCE(sta.average_session_time, 0), average_time_passing = COALESCE(sta.average_session_time, 0),
sessions_count = COALESCE(sta.sess,0) sessions_count = COALESCE(sta.sess,0)
FROM FROM
(SELECT * FROM quiz WHERE deleted = FALSE AND archived = FALSE) q_sub (SELECT * FROM quiz WHERE deleted = FALSE AND archived = FALSE) q_sub
LEFT JOIN answer_aggregates aa ON q_sub.id = aa.quiz_id LEFT JOIN answer_aggregates aa ON q_sub.id = aa.quiz_id
LEFT JOIN question_aggregates qa ON q_sub.id = qa.quiz_id LEFT JOIN question_aggregates qa ON q_sub.id = qa.quiz_id
LEFT JOIN session_times_aggregates sta ON q_sub.id = sta.quiz_id LEFT JOIN session_times_aggregates sta ON q_sub.id = sta.quiz_id
WHERE WHERE
q.id = q_sub.id; q.id = q_sub.id;
@ -247,6 +248,7 @@ UPDATE privileges SET amount = $1 WHERE id = $2;
SELECT SELECT
a.id, a.id,
a.user_id, a.user_id,
a.email,
a.created_at, a.created_at,
COALESCE(p.ID,0), COALESCE(p.ID,0),
coalesce(p.privilegeid,''), coalesce(p.privilegeid,''),
@ -407,13 +409,13 @@ WITH TimeBucket AS (
SELECT SELECT
date_trunc('hour', timestamp_bucket)::TIMESTAMP AS time_interval_start, date_trunc('hour', timestamp_bucket)::TIMESTAMP AS time_interval_start,
COALESCE(LEAD( COALESCE(LEAD(
date_trunc('hour', timestamp_bucket)::TIMESTAMP date_trunc('hour', timestamp_bucket)::TIMESTAMP
) OVER (ORDER BY timestamp_bucket), NOW()) AS time_interval_end ) OVER (ORDER BY timestamp_bucket), NOW()) AS time_interval_end
FROM FROM
generate_series(TO_TIMESTAMP($1), TO_TIMESTAMP($2), CASE generate_series(TO_TIMESTAMP($1), TO_TIMESTAMP($2), CASE
WHEN EXTRACT(epoch FROM TO_TIMESTAMP($2)) - EXTRACT(epoch FROM TO_TIMESTAMP($1)) > 172800 THEN '1 day'::interval WHEN EXTRACT(epoch FROM TO_TIMESTAMP($2)) - EXTRACT(epoch FROM TO_TIMESTAMP($1)) > 172800 THEN '1 day'::interval
ELSE '1 hour'::interval ELSE '1 hour'::interval
END) AS timestamp_bucket END) AS timestamp_bucket
), ),
OpenStats AS ( OpenStats AS (
SELECT SELECT
@ -494,7 +496,7 @@ SELECT
CASE CASE
WHEN COALESCE(os.open_count, 0) > 0 THEN COALESCE(rs.true_result_count, 0)::float / COALESCE(os.open_count, 0)::float WHEN COALESCE(os.open_count, 0) > 0 THEN COALESCE(rs.true_result_count, 0)::float / COALESCE(os.open_count, 0)::float
ELSE 0 ELSE 0
END::float AS conversion, END::float AS conversion,
COALESCE(at.avg_time, 0) AS avg_time COALESCE(at.avg_time, 0) AS avg_time
FROM FROM
TimeBucket tb TimeBucket tb
@ -511,10 +513,10 @@ FROM
-- name: QuestionsStatistics :many -- name: QuestionsStatistics :many
WITH Funnel AS ( WITH Funnel AS (
SELECT SELECT
COUNT(DISTINCT a.session) FILTER (WHERE a.start = FALSE) AS count_start_false, COUNT(DISTINCT a.session) FILTER (WHERE a.start = FALSE) AS count_start_false,
COUNT(DISTINCT a.session) FILTER (WHERE a.start = TRUE) AS count_start_true, COUNT(DISTINCT a.session) FILTER (WHERE a.start = TRUE) AS count_start_true,
COUNT(DISTINCT CASE WHEN a.result = FALSE AND qid_true_result IS NOT NULL THEN a.session END) AS count_f_result_with_t_question, COUNT(DISTINCT CASE WHEN a.result = FALSE AND qid_true_result IS NOT NULL THEN a.session END) AS count_f_result_with_t_question,
COUNT(DISTINCT a.session) FILTER (WHERE a.result = TRUE) AS count_t_result COUNT(DISTINCT a.session) FILTER (WHERE a.result = TRUE) AS count_t_result
FROM FROM
answer a answer a
LEFT JOIN ( LEFT JOIN (
@ -529,23 +531,23 @@ WITH Funnel AS (
AND a.created_at <= TO_TIMESTAMP($3) AND a.created_at <= TO_TIMESTAMP($3)
), ),
Results AS ( Results AS (
SELECT SELECT
COALESCE(q.title, '') AS question_title, COALESCE(q.title, '') AS question_title,
COUNT(*) AS total_answers, COUNT(*) AS total_answers,
CAST(COUNT(*) * 100.0 / NULLIF(SUM(COUNT(*)) FILTER (WHERE a.result = TRUE) OVER (PARTITION BY a.quiz_id), 0) AS FLOAT8) AS percentage CAST(COUNT(*) * 100.0 / NULLIF(SUM(COUNT(*)) FILTER (WHERE a.result = TRUE) OVER (PARTITION BY a.quiz_id), 0) AS FLOAT8) AS percentage
FROM FROM
question q question q
JOIN answer a ON q.id = a.question_id JOIN answer a ON q.id = a.question_id
WHERE WHERE
a.quiz_id = $1 a.quiz_id = $1
AND a.created_at >= TO_TIMESTAMP($2) AND a.created_at >= TO_TIMESTAMP($2)
AND a.created_at <= TO_TIMESTAMP($3) AND a.created_at <= TO_TIMESTAMP($3)
AND a.result = TRUE AND a.result = TRUE
GROUP BY GROUP BY
q.title, a.quiz_id, a.result q.title, a.quiz_id, a.result
HAVING HAVING
COUNT(*) >= 1 COUNT(*) >= 1
), ),
LastContent AS ( LastContent AS (
SELECT SELECT
a.question_id, a.question_id,
@ -561,35 +563,35 @@ WITH Funnel AS (
answer answer
WHERE WHERE
quiz_id = $1 quiz_id = $1
AND start != true AND start != true
AND created_at >= TO_TIMESTAMP($2) AND created_at >= TO_TIMESTAMP($2)
AND created_at <= TO_TIMESTAMP($3) AND created_at <= TO_TIMESTAMP($3)
GROUP BY GROUP BY
question_id, session question_id, session
) AS last_created_at_one_session ON a.session = last_created_at_one_session.session AND a.question_id = last_created_at_one_session.question_id AND a.created_at = last_created_at_one_session.last_created_at ) AS last_created_at_one_session ON a.session = last_created_at_one_session.session AND a.question_id = last_created_at_one_session.question_id AND a.created_at = last_created_at_one_session.last_created_at
), ),
Questions AS ( Questions AS (
SELECT SELECT
q.title AS question_title, q.title AS question_title,
q.page AS question_page, q.page AS question_page,
lc.last_answer_content AS answer_content, lc.last_answer_content AS answer_content,
CAST( CAST(
COUNT(CASE WHEN a.result = FALSE THEN 1 END) * 100.0 / NULLIF(SUM(COUNT(CASE WHEN a.result = FALSE THEN 1 END)) OVER (PARTITION BY q.id), 0) AS FLOAT8 COUNT(CASE WHEN a.result = FALSE THEN 1 END) * 100.0 / NULLIF(SUM(COUNT(CASE WHEN a.result = FALSE THEN 1 END)) OVER (PARTITION BY q.id), 0) AS FLOAT8
) AS percentage ) AS percentage
FROM FROM
question q question q
JOIN LastContent lc ON q.id = lc.question_id JOIN LastContent lc ON q.id = lc.question_id
JOIN answer a ON q.id = a.question_id JOIN answer a ON q.id = a.question_id
WHERE WHERE
a.quiz_id = $1 a.quiz_id = $1
AND a.start != true AND a.start != true
AND a.created_at >= TO_TIMESTAMP($2) AND a.created_at >= TO_TIMESTAMP($2)
AND a.created_at <= TO_TIMESTAMP($3) AND a.created_at <= TO_TIMESTAMP($3)
GROUP BY GROUP BY
q.id, q.title, lc.last_answer_content q.id, q.title, lc.last_answer_content
HAVING HAVING
COUNT(*) >= 1 COUNT(*) >= 1
) )
SELECT SELECT
Funnel.count_start_false, Funnel.count_start_false,
Funnel.count_start_true, Funnel.count_start_true,
@ -603,34 +605,34 @@ SELECT
COALESCE(Questions.percentage, 0) AS questions_percentage COALESCE(Questions.percentage, 0) AS questions_percentage
FROM FROM
Funnel Funnel
LEFT JOIN Results ON true LEFT JOIN Results ON true
LEFT JOIN Questions ON Questions.percentage >= 1; LEFT JOIN Questions ON Questions.percentage >= 1;
-- name: QuizCopyQid :one -- name: QuizCopyQid :one
INSERT INTO quiz ( INSERT INTO quiz (
accountid, archived, fingerprinting, repeatable, note_prevented, mail_notifications, unique_answers, name, description, config, accountid, archived, fingerprinting, repeatable, note_prevented, mail_notifications, unique_answers, name, description, config,
status, limit_answers, due_to, time_of_passing, pausable, version, version_comment, parent_ids, questions_count, answers_count, average_time_passing, super, group_id status, limit_answers, due_to, time_of_passing, pausable, version, version_comment, parent_ids, questions_count, answers_count, average_time_passing, super, group_id
) )
SELECT SELECT
$2, archived, fingerprinting, repeatable, note_prevented, mail_notifications, unique_answers, name, description, config, $2, archived, fingerprinting, repeatable, note_prevented, mail_notifications, unique_answers, name, description, config,
status, limit_answers, due_to, time_of_passing, pausable, version, version_comment, parent_ids, questions_count, answers_count, average_time_passing, super, group_id status, limit_answers, due_to, time_of_passing, pausable, version, version_comment, parent_ids, questions_count, answers_count, average_time_passing, super, group_id
FROM FROM
quiz as q quiz as q
WHERE WHERE
q.qid = $1 q.qid = $1
RETURNING (select id from quiz where qid = $1),id, qid; RETURNING (select id from quiz where qid = $1),id, qid;
-- name: CopyQuestionQuizID :exec -- name: CopyQuestionQuizID :exec
INSERT INTO question ( INSERT INTO question (
quiz_id, title, description, questiontype, required, quiz_id, title, description, questiontype, required,
page, content, version, parent_ids, created_at, updated_at page, content, version, parent_ids, created_at, updated_at
) )
SELECT SELECT
$2, title, description, questiontype, required, $2, title, description, questiontype, required,
page, content, version, parent_ids, created_at, updated_at page, content, version, parent_ids, created_at, updated_at
FROM FROM
question question
WHERE WHERE
question.quiz_id = $1 AND deleted = false; question.quiz_id = $1 AND deleted = false;
-- name: GetQidOwner :one -- name: GetQidOwner :one
@ -656,7 +658,7 @@ SELECT
(SELECT registration_count FROM Registrations) AS registrations, (SELECT registration_count FROM Registrations) AS registrations,
(SELECT quiz_count FROM Quizes) AS quizes, (SELECT quiz_count FROM Quizes) AS quizes,
(SELECT result_count FROM Results) AS results; (SELECT result_count FROM Results) AS results;
-- name: GetListStartQuiz :many -- name: GetListStartQuiz :many
SELECT id FROM quiz WHERE accountid = $1 AND status = 'start'; SELECT id FROM quiz WHERE accountid = $1 AND status = 'start';
@ -684,8 +686,8 @@ RETURNING quiz_id;
-- amo methods: -- amo methods:
-- name: CreateAmoAccount :exec -- name: CreateAmoAccount :exec
INSERT INTO users (AccountID, AmoID, Name, Email, Role, "Group", Deleted, CreatedAt, Subdomain, AmoUserID, Country,DriveURL) INSERT INTO accountsAmo (AccountID, AmoID,Name, Subdomain, Country,DriveURL)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12); VALUES ($1, $2, $3, $4, $5, $6);
-- name: CreateWebHook :exec -- name: CreateWebHook :exec
INSERT INTO tokens (AccountID, RefreshToken, AccessToken, AuthCode, Expiration, CreatedAt) INSERT INTO tokens (AccountID, RefreshToken, AccessToken, AuthCode, Expiration, CreatedAt)
@ -698,61 +700,80 @@ WHERE accountID = $5;
-- name: GetAllTokens :many -- name: GetAllTokens :many
SELECT * FROM tokens; SELECT * FROM tokens;
-- name: CheckExpired :many -- name: CheckExpiredToken :one
SELECT * FROM tokens WHERE Expiration <= TO_TIMESTAMP(EXTRACT(EPOCH FROM NOW()) + (10 * 60)); SELECT * FROM tokens WHERE AccountID = $1 AND Expiration <= NOW();
-- name: UpdateAmoAccount :exec
UPDATE accountsAmo SET Name = $2, Subdomain = $3, Country = $4, DriveURL = $5 WHERE AccountID = $1 AND Deleted = false;
-- name: WebhookDelete :exec -- name: WebhookDelete :exec
WITH userd AS ( WITH companyDel AS (
UPDATE users SET Deleted = true WHERE AmoUserID = $1 RETURNING AccountID UPDATE accountsAmo SET Deleted = true WHERE accountsAmo.AmoID = $1 RETURNING AccountID
) ),
DELETE FROM tokens WHERE AccountID IN (SELECT AccountID FROM userd); userDel AS (
UPDATE usersAmo SET Deleted = true WHERE AmoID = $1
)
DELETE FROM tokens WHERE AccountID IN (SELECT AccountID FROM companyDel);
-- name: SoftDeleteAccount :exec -- name: SoftDeleteAccount :exec
WITH userd AS ( WITH amoCompany AS (
SELECT AmoUserID FROM users WHERE users.AccountID = $1 SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1
),usersDel AS (
UPDATE usersAmo SET Deleted = true WHERE AmoID = (SELECT AmoID FROM amoCompany)
), ),
tokend AS ( companyDel AS ( UPDATE accountsAmo SET Deleted = true WHERE AmoID = (SELECT AmoID FROM amoCompany)
UPDATE users SET Deleted = true WHERE AmoUserID IN (SELECT AmoUserID FROM userd)
) )
DELETE FROM tokens WHERE tokens.AccountID = $1; DELETE FROM tokens WHERE tokens.AccountID = $1;
-- name: GetCurrentAccount :one -- name: GetCurrentCompany :one
SELECT * FROM users WHERE AccountID = $1 AND Deleted = false; SELECT * FROM accountsAmo WHERE AccountID = $1 AND Deleted = false;
-- name: CheckMainUser :exec -- name: GetAllCompanyUsers :many
UPDATE users SET Name = $1, "Group" = $2, Email = $3, Role = $4 WHERE AmoID = $5; SELECT * FROM usersamo WHERE amoid = $1 AND deleted = false;
-- name: GetUsersWithPagination :many -- name: GetUsersWithPagination :many
WITH user_data AS ( WITH user_data AS (
SELECT AmoID FROM users WHERE users.AccountID = $1 AND Deleted = false SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
) )
SELECT u.*, COUNT(*) OVER() as total_count SELECT u.*, COUNT(*) OVER() as total_count
FROM users u FROM usersAmo u
JOIN user_data a ON u.AmoUserID = a.AmoID JOIN user_data a ON u.AmoID = a.AmoID
WHERE u.Deleted = false WHERE u.Deleted = false
ORDER BY u.ID OFFSET ($2 - 1) * $3 LIMIT $3; ORDER BY u.ID OFFSET ($2 - 1) * $3 LIMIT $3;
-- name: GetTagsWithPagination :many -- name: GetTagsWithPagination :many
WITH user_data AS (
SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
)
SELECT t.*, COUNT(*) OVER() as total_count SELECT t.*, COUNT(*) OVER() as total_count
FROM tags t JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1 AND Deleted = false) u ON t.AccountID = u.AmoID FROM tags t JOIN user_data u ON t.AccountID = u.AmoID
WHERE t.Deleted = false WHERE t.Deleted = false
ORDER BY t.ID OFFSET ($2 - 1) * $3 LIMIT $3; ORDER BY t.ID OFFSET ($2 - 1) * $3 LIMIT $3;
-- name: GetStepsWithPagination :many -- name: GetStepsWithPagination :many
WITH user_data AS (
SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
)
SELECT s.*, COUNT(*) OVER() as total_count SELECT s.*, COUNT(*) OVER() as total_count
FROM steps s JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1 AND Deleted = false) u ON s.AccountID = u.AmoID FROM steps s JOIN user_data u ON s.AccountID = u.AmoID
WHERE s.Deleted = false AND PipelineID = $4 WHERE s.Deleted = false AND PipelineID = $4
ORDER BY s.ID OFFSET ($2 - 1) * $3 LIMIT $3; ORDER BY s.ID OFFSET ($2 - 1) * $3 LIMIT $3;
-- name: GetPipelinesWithPagination :many -- name: GetPipelinesWithPagination :many
WITH user_data AS (
SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
)
SELECT p.*, COUNT(*) OVER() as total_count SELECT p.*, COUNT(*) OVER() as total_count
FROM pipelines p JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1 AND Deleted = false) u ON p.AccountID = u.AmoID FROM pipelines p JOIN user_data u ON p.AccountID = u.AmoID
WHERE p.Deleted = false WHERE p.Deleted = false
ORDER BY p.ID OFFSET ($2 - 1) * $3 LIMIT $3; ORDER BY p.ID OFFSET ($2 - 1) * $3 LIMIT $3;
-- name: GetFieldsWithPagination :many -- name: GetFieldsWithPagination :many
WITH user_data AS (
SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
)
SELECT f.*, COUNT(*) OVER() as total_count SELECT f.*, COUNT(*) OVER() as total_count
FROM fields f JOIN (SELECT AmoID FROM users WHERE users.AccountID = $1 AND Deleted = false) u ON f.AccountID = u.AmoID FROM fields f JOIN user_data u ON f.AccountID = u.AmoID
WHERE f.Deleted = false WHERE f.Deleted = false
ORDER BY f.ID OFFSET ($2 - 1) * $3 LIMIT $3; ORDER BY f.ID OFFSET ($2 - 1) * $3 LIMIT $3;
@ -791,12 +812,10 @@ FROM json_array_elements($1::json) AS update_data
WHERE f.amoID = (update_data ->> 'AmoID')::INT WHERE f.amoID = (update_data ->> 'AmoID')::INT
AND f.accountID = (update_data ->> 'AccountID')::INT AND f.accountID = (update_data ->> 'AccountID')::INT
AND f.Entity = (update_data ->> 'Entity')::entitytype; AND f.Entity = (update_data ->> 'Entity')::entitytype;
-- name: CheckTags :many -- name: CheckTags :many
WITH user_data AS ( WITH user_data AS (
SELECT AmoID SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
FROM users
WHERE users.AccountID = $1
), new_tags AS ( ), new_tags AS (
SELECT (tag->>'AmoID')::INT AS amoID, SELECT (tag->>'AmoID')::INT AS amoID,
(tag->>'Entity')::entitytype AS Entity, (tag->>'Entity')::entitytype AS Entity,
@ -818,7 +837,7 @@ WITH user_data AS (
) )
SELECT nt.*,ud.AmoID SELECT nt.*,ud.AmoID
FROM new_tags nt FROM new_tags nt
JOIN user_data ud ON true JOIN user_data ud ON true
WHERE NOT EXISTS ( WHERE NOT EXISTS (
SELECT * SELECT *
FROM inserted_tags ins FROM inserted_tags ins
@ -836,14 +855,14 @@ WITH new_pipelines AS (
FROM json_array_elements($1::json) AS pipeline FROM json_array_elements($1::json) AS pipeline
), inserted_pipelines AS( ), inserted_pipelines AS(
INSERT INTO pipelines (amoID, accountID, name, isArchive, createdAt) INSERT INTO pipelines (amoID, accountID, name, isArchive, createdAt)
SELECT np.amoID, SELECT np.amoID,
np.accountID, np.accountID,
np.name, np.name,
np.isArchive, np.isArchive,
np.createdAt np.createdAt
FROM new_pipelines np FROM new_pipelines np
ON CONFLICT (amoID, accountID) DO NOTHING ON CONFLICT (amoID, accountID) DO NOTHING
RETURNING * RETURNING *
) )
SELECT np.* SELECT np.*
FROM new_pipelines np FROM new_pipelines np
@ -855,34 +874,32 @@ WHERE NOT EXISTS (
-- name: CheckFields :many -- name: CheckFields :many
WITH user_data AS ( WITH user_data AS (
SELECT AmoID SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
FROM users
WHERE users.AccountID = $1
), new_fields AS ( ), new_fields AS (
SELECT (field->>'AmoID')::INT AS amoID, SELECT (field->>'AmoID')::INT AS amoID,
COALESCE(field->>'Code', '')::varchar(255) AS code, COALESCE(field->>'Code', '')::varchar(255) AS code,
COALESCE(field->>'Name', '')::varchar(512) AS name, COALESCE(field->>'Name', '')::varchar(512) AS name,
CAST(field->>'Entity' AS entitytype) AS Entity, CAST(field->>'Entity' AS entitytype) AS Entity,
COALESCE(field->>'Type', '')::fieldtype AS type, COALESCE(field->>'Type', '')::fieldtype AS type,
CURRENT_TIMESTAMP AS createdAt CURRENT_TIMESTAMP AS createdAt
FROM json_array_elements($2::json) AS field FROM json_array_elements($2::json) AS field
), inserted_fields AS( ), inserted_fields AS(
INSERT INTO fields (amoID, code, accountID, name, Entity, type, createdAt) INSERT INTO fields (amoID, code, accountID, name, Entity, type, createdAt)
SELECT nf.amoID, SELECT nf.amoID,
nf.code, nf.code,
ud.AmoID, ud.AmoID,
nf.name, nf.name,
nf.Entity, nf.Entity,
nf.type, nf.type,
nf.createdAt nf.createdAt
FROM new_fields nf FROM new_fields nf
JOIN user_data ud ON true JOIN user_data ud ON true
ON CONFLICT (amoID, accountID, entity) DO NOTHING ON CONFLICT (amoID, accountID, entity) DO NOTHING
RETURNING * RETURNING *
) )
SELECT nf.*,ud.AmoID SELECT nf.*,ud.AmoID
FROM new_fields nf FROM new_fields nf
JOIN user_data ud ON true JOIN user_data ud ON true
WHERE NOT EXISTS ( WHERE NOT EXISTS (
SELECT * SELECT *
FROM inserted_fields ins FROM inserted_fields ins
@ -901,15 +918,15 @@ WITH new_steps AS (
FROM json_array_elements($1::json) AS step FROM json_array_elements($1::json) AS step
), inserted_steps AS ( ), inserted_steps AS (
INSERT INTO steps (amoID, pipelineID, accountID, name, color, createdAt) INSERT INTO steps (amoID, pipelineID, accountID, name, color, createdAt)
SELECT ns.amoID, SELECT ns.amoID,
ns.pipelineID, ns.pipelineID,
ns.accountID, ns.accountID,
ns.name, ns.name,
ns.color, ns.color,
ns.createdAt ns.createdAt
FROM new_steps ns FROM new_steps ns
ON CONFLICT (amoID, accountID, PipelineID) DO NOTHING ON CONFLICT (amoID, accountID, PipelineID) DO NOTHING
RETURNING * RETURNING *
) )
SELECT ns.* SELECT ns.*
FROM new_steps ns FROM new_steps ns
@ -928,13 +945,13 @@ SELECT * FROM rules WHERE QuizID = $1 AND Deleted = false;
-- name: SetQuizSettings :one -- name: SetQuizSettings :one
INSERT INTO rules (AccountID, QuizID, PerformerID, PipelineID, StepID, FieldsRule,TagsToAdd) INSERT INTO rules (AccountID, QuizID, PerformerID, PipelineID, StepID, FieldsRule,TagsToAdd)
SELECT u.AmoID AS AccountID,$1 AS QuizID,$2 AS PerformerID,$3 AS PipelineID, SELECT u.AmoID AS AccountID,$1 AS QuizID,$2 AS PerformerID,$3 AS PipelineID,
$4 AS StepID,$5 AS FieldsRule,$6 AS TagsToAdd FROM users u WHERE u.AccountID = $7 AND u.Deleted = false $4 AS StepID,$5 AS FieldsRule,$6 AS TagsToAdd FROM accountsamo u WHERE u.AccountID = $7 AND u.Deleted = false
RETURNING id; RETURNING id;
-- name: ChangeQuizSettings :one -- name: ChangeQuizSettings :one
UPDATE rules UPDATE rules
SET PerformerID = $1,PipelineID = $2,StepID = $3,FieldsRule = $4, TagsToAdd=$5 SET PerformerID = $1,PipelineID = $2,StepID = $3,FieldsRule = $4, TagsToAdd=$5
WHERE AccountID = (SELECT AmoID FROM users WHERE users.AccountID = $6 AND users.Deleted = false) AND QuizID = $7 AND Deleted = false WHERE AccountID = (SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $6 AND accountsAmo.Deleted = false) AND QuizID = $7 AND Deleted = false
RETURNING id; RETURNING id;
-- name: GetQuestionListByIDs :many -- name: GetQuestionListByIDs :many
@ -942,62 +959,29 @@ SELECT * FROM question WHERE id = ANY($1::int[]) AND deleted = FALSE;
-- name: UpdateFieldRules :exec -- name: UpdateFieldRules :exec
UPDATE rules SET FieldsRule = $1 UPDATE rules SET FieldsRule = $1
WHERE AccountID = (SELECT AmoID FROM users WHERE users.AccountID = $2 AND users.Deleted = false) AND QuizID = $3 AND Deleted = false; WHERE AccountID = (SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $2 AND accountsAmo.Deleted = false) AND QuizID = $3 AND Deleted = false;
-- name: UpdateUsers :exec -- name: UpdateAmoAccountUser :exec
UPDATE users AS u UPDATE usersAmo SET Name = $3, Email = $4, Role = $5, "Group" = $6
SET Name = (update_data ->> 'Name')::varchar(512), WHERE AmoID = $1 AND AmoUserID = $2 AND deleted = false;
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 -- name: AddAmoAccountUser :exec
WITH new_users AS ( INSERT INTO usersAmo (AmoID, AmoUserID, Name, Email, Role, "Group")
SELECT (u->>'AmocrmID')::INT AS AmoID, VALUES ($1, $2, $3, $4, $5, $6);
(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 -- name: GettingAmoUsersTrueResults :many
SELECT a.quiz_id,a.id,a.result,a.question_id,a.content,a.session, SELECT a.quiz_id,a.id,a.result,a.question_id,a.content,a.session,
(SELECT a2.utm COALESCE((SELECT a2.utm
FROM answer a2 FROM answer a2
WHERE a2.start = true AND a2.session = a.session WHERE a2.start = true AND a2.session = a.session
LIMIT 1) AS utm LIMIT 1), '{}'::jsonb) AS utm
,t.accesstoken,r.accountid,r.fieldsrule,r.tagstoadd,r.performerid,r.stepid,r.pipelineid,(SELECT u.name FROM users u WHERE u.amoid = r.performerid) AS performer_name,u.subdomain,u.accountid,u.driveurl ,t.accesstoken,r.accountid,r.fieldsrule,r.tagstoadd,r.performerid,r.stepid,r.pipelineid,(SELECT u.name FROM usersAmo u WHERE u.AmoUserID = r.performerid AND u.deleted = false) AS performer_name,u.subdomain,u.accountid,u.driveurl
FROM answer a FROM answer a
INNER JOIN quiz q ON a.quiz_id = q.id INNER JOIN quiz q ON a.quiz_id = q.id
LEFT JOIN amoCRMStatuses s ON a.id = s.AnswerID LEFT JOIN amoCRMStatuses s ON a.id = s.AnswerID
INNER JOIN rules r ON q.id = r.QuizID INNER JOIN rules r ON q.id = r.QuizID
INNER JOIN tokens t ON q.accountid = t.AccountID INNER JOIN tokens t ON q.accountid = t.AccountID
INNER JOIN users u ON q.accountid = u.accountid AND u.amoid = r.accountid INNER JOIN accountsAmo u ON q.accountid = u.accountid AND u.amoid = r.accountid
WHERE a.result = true WHERE a.result = true
AND s.id IS NULL AND s.id IS NULL
AND a.deleted = false AND a.deleted = false
@ -1009,12 +993,12 @@ WHERE a.result = true
INSERT INTO amoCRMStatuses (AccountID, DealID, AnswerID, Status) INSERT INTO amoCRMStatuses (AccountID, DealID, AnswerID, Status)
SELECT u.AmoID, $1, $2, $3 SELECT u.AmoID, $1, $2, $3
FROM tokens AS t FROM tokens AS t
JOIN users AS u ON t.AccountID = u.AccountID JOIN accountsAmo AS u ON t.AccountID = u.AccountID
WHERE t.AccessToken = $4 AND u.Deleted = false; WHERE t.AccessToken = $4 AND u.Deleted = false;
-- name: UpdatingDealAmoStatus :exec -- name: UpdatingDealAmoStatus :exec
UPDATE amoCRMStatuses SET Status = $1 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 AND u.Deleted = false); WHERE DealID = $2 AND AccountID = (SELECT u.AmoID FROM tokens AS t JOIN accountsAmo AS u ON t.AccountID = u.AccountID WHERE t.AccessToken = $3 AND u.Deleted = false);
-- name: DeleteFields :exec -- name: DeleteFields :exec
UPDATE fields SET Deleted = true WHERE ID = ANY($1::bigint[]); UPDATE fields SET Deleted = true WHERE ID = ANY($1::bigint[]);
@ -1029,7 +1013,7 @@ UPDATE steps SET Deleted = true WHERE ID = ANY($1::bigint[]);
UPDATE pipelines SET Deleted = true WHERE ID = ANY($1::bigint[]); UPDATE pipelines SET Deleted = true WHERE ID = ANY($1::bigint[]);
-- name: DeleteUsers :exec -- name: DeleteUsers :exec
UPDATE users SET Deleted = true WHERE ID = ANY($1::bigint[]); UPDATE usersAmo SET Deleted = true WHERE ID = ANY($1::bigint[]);
-- name: GetUserTagsByID :many -- name: GetUserTagsByID :many
SELECT ID,AmoID,AccountID,Name,Entity,Color SELECT ID,AmoID,AccountID,Name,Entity,Color
@ -1047,9 +1031,7 @@ FROM pipelines
WHERE AccountID = $1 AND Deleted = false; WHERE AccountID = $1 AND Deleted = false;
-- name: GetUserUsersByID :many -- name: GetUserUsersByID :many
SELECT ID,AccountID,AmoID,Name,Email,Role,"Group",Subdomain,AmoUserID,Country SELECT * FROM usersAmo WHERE amoid = $1 AND Deleted = false;
FROM users
WHERE AmoUserID = $1 AND Deleted = false;
-- name: GetFieldByAmoID :one -- name: GetFieldByAmoID :one
SELECT * FROM fields WHERE AmoID = $1 AND Deleted = false; SELECT * FROM fields WHERE AmoID = $1 AND Deleted = false;
@ -1062,7 +1044,19 @@ WHERE AccountID = $1 AND Deleted = false;
-- name: DecrementManual :one -- name: DecrementManual :one
UPDATE privileges p SET amount = amount - 1 FROM account a UPDATE privileges p SET amount = amount - 1 FROM account a
WHERE p.account_id = a.id AND a.user_id = $1 AND p.privilegeID = $2 AND p.amount > 0 WHERE p.account_id = a.id AND a.user_id = $1 AND p.privilegeID = $2 AND p.amount > 0
RETURNING p.id, p.privilegeID, p.account_id, p.privilege_name, p.amount, p.created_at;; RETURNING p.id, p.privilegeID, p.account_id, p.privilege_name, p.amount, p.created_at;
-- name: GetExistingContactAmo :many
WITH getAmoID AS (
SELECT AmoID FROM amoContact WHERE amoContact.AccountID = $1 AND amoContact.Field = ANY($2::text[])
) SELECT * FROM amoContact
WHERE amoContact.AccountID = $1 AND amoContact.AmoID IN (SELECT AmoID FROM getAmoID);
-- name: InsertContactAmo :one
INSERT INTO amoContact (AccountID, AmoID, Field) VALUES ($1, $2, $3) RETURNING AmoID;
-- name: UpdateAmoContact :exec
UPDATE amoContact SET Field = $1,AmoID=$3 WHERE ID = $2;
-- name: CreateLeadTarget :one -- name: CreateLeadTarget :one
INSERT INTO leadtarget (accountID,type,quizID,target) VALUES ($1,$2,$3,$4) RETURNING *; INSERT INTO leadtarget (accountID,type,quizID,target) VALUES ($1,$2,$3,$4) RETURNING *;

@ -0,0 +1,20 @@
DROP TABLE IF EXISTS usersAmo;
DROP INDEX IF EXISTS idx_unique_accountsAmo;
DROP TABLE IF EXISTS accountsAmo;
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 UNIQUE INDEX idx_unique_users ON users (amoID) WHERE Deleted = false;

@ -0,0 +1,28 @@
DROP TABLE IF EXISTS users;
DROP INDEX IF EXISTS idx_unique_users;
CREATE TABLE IF NOT EXISTS accountsAmo (
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 '',
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
Subdomain VARCHAR(50) NOT NULL DEFAULT '', -- поддомен - пример https://penadigitaltech.amocrm.ru
Country VARCHAR(50) NOT NULL DEFAULT '',
DriveURL VARCHAR(255) NOT NULL DEFAULT '' -- URL объктного хранилища
);
CREATE UNIQUE INDEX idx_unique_accountsAmo ON accountsAmo (amoID) WHERE Deleted = false;
CREATE TABLE IF NOT EXISTS usersAmo (
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
AmoID INT NOT NULL, -- ID компании в амо (внешний ключ)
AmoUserID 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 NOT NULL DEFAULT CURRENT_TIMESTAMP
);

@ -0,0 +1,19 @@
UPDATE answer
SET content =
CASE
WHEN content ~ '<tr>|<td>' THEN
regexp_replace(content, '<\/?tr[^>]*>|<\/?td[^>]*>', '', 'g')
WHEN content ~ '<a download>[^<]+</a>' THEN
regexp_replace(content, '<a download>([^<]+)</a>', '\1', 'g')
WHEN content ~ '<img[^>]*src="([^"]*)"[^>]*' THEN
regexp_replace(content, '<img[^>]*src="\s*"[^>]*', '', 'g')
ELSE content
END;
UPDATE answer
SET content =
CASE
WHEN content ~ '<img' THEN
regexp_replace(content, '(.*?)(<img[^>]*src=["'']?([^"''>]+)["'']?[^>]*>)', '\1\3', 'g')
ELSE content
END;

@ -0,0 +1 @@
DROP TABLE IF EXISTS amoContact;

@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS amoContact (
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
AccountID INT NOT NULL, -- ID "компании" в амо
AmoID INT NOT NULL, -- ID контакта в амо
Field text NOT NULL DEFAULT '' -- значение чего то email? phone? etc
)

@ -19,6 +19,25 @@ type Account struct {
Deleted sql.NullBool `db:"deleted" json:"deleted"` Deleted sql.NullBool `db:"deleted" json:"deleted"`
} }
type Accountsamo 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"`
Deleted bool `db:"deleted" json:"deleted"`
Createdat time.Time `db:"createdat" json:"createdat"`
Subdomain string `db:"subdomain" json:"subdomain"`
Country string `db:"country" json:"country"`
Driveurl string `db:"driveurl" json:"driveurl"`
}
type Amocontact struct {
ID int64 `db:"id" json:"id"`
Accountid int32 `db:"accountid" json:"accountid"`
Amoid int32 `db:"amoid" json:"amoid"`
Field string `db:"field" json:"field"`
}
type Amocrmstatus struct { type Amocrmstatus struct {
ID int64 `db:"id" json:"id"` ID int64 `db:"id" json:"id"`
Accountid int32 `db:"accountid" json:"accountid"` Accountid int32 `db:"accountid" json:"accountid"`
@ -182,18 +201,14 @@ type Token struct {
Createdat sql.NullTime `db:"createdat" json:"createdat"` Createdat sql.NullTime `db:"createdat" json:"createdat"`
} }
type User struct { type Usersamo struct {
ID int64 `db:"id" json:"id"` ID int64 `db:"id" json:"id"`
Accountid string `db:"accountid" json:"accountid"` Amoid int32 `db:"amoid" json:"amoid"`
Amoid int32 `db:"amoid" json:"amoid"` Amouserid int32 `db:"amouserid" json:"amouserid"`
Name string `db:"name" json:"name"` Name string `db:"name" json:"name"`
Email string `db:"email" json:"email"` Email string `db:"email" json:"email"`
Role int32 `db:"role" json:"role"` Role int32 `db:"role" json:"role"`
Group int32 `db:"Group" json:"Group"` Group int32 `db:"Group" json:"Group"`
Deleted bool `db:"deleted" json:"deleted"` Deleted bool `db:"deleted" json:"deleted"`
Createdat sql.NullTime `db:"createdat" json:"createdat"` Createdat time.Time `db:"createdat" json:"createdat"`
Subdomain string `db:"subdomain" json:"subdomain"`
Amouserid int32 `db:"amouserid" json:"amouserid"`
Country string `db:"country" json:"country"`
Driveurl string `db:"driveurl" json:"driveurl"`
} }

@ -53,6 +53,32 @@ func (q *Queries) AccountPagination(ctx context.Context, arg AccountPaginationPa
return items, nil return items, nil
} }
const addAmoAccountUser = `-- name: AddAmoAccountUser :exec
INSERT INTO usersAmo (AmoID, AmoUserID, Name, Email, Role, "Group")
VALUES ($1, $2, $3, $4, $5, $6)
`
type AddAmoAccountUserParams struct {
Amoid int32 `db:"amoid" json:"amoid"`
Amouserid int32 `db:"amouserid" json:"amouserid"`
Name string `db:"name" json:"name"`
Email string `db:"email" json:"email"`
Role int32 `db:"role" json:"role"`
Group int32 `db:"Group" json:"Group"`
}
func (q *Queries) AddAmoAccountUser(ctx context.Context, arg AddAmoAccountUserParams) error {
_, err := q.db.ExecContext(ctx, addAmoAccountUser,
arg.Amoid,
arg.Amouserid,
arg.Name,
arg.Email,
arg.Role,
arg.Group,
)
return err
}
const allServiceStatistics = `-- name: AllServiceStatistics :one const allServiceStatistics = `-- name: AllServiceStatistics :one
WITH Registrations AS ( WITH Registrations AS (
SELECT COUNT(*) AS registration_count SELECT COUNT(*) AS registration_count
@ -110,7 +136,7 @@ func (q *Queries) ArchiveQuiz(ctx context.Context, arg ArchiveQuizParams) error
const changeQuizSettings = `-- name: ChangeQuizSettings :one const changeQuizSettings = `-- name: ChangeQuizSettings :one
UPDATE rules UPDATE rules
SET PerformerID = $1,PipelineID = $2,StepID = $3,FieldsRule = $4, TagsToAdd=$5 SET PerformerID = $1,PipelineID = $2,StepID = $3,FieldsRule = $4, TagsToAdd=$5
WHERE AccountID = (SELECT AmoID FROM users WHERE users.AccountID = $6 AND users.Deleted = false) AND QuizID = $7 AND Deleted = false WHERE AccountID = (SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $6 AND accountsAmo.Deleted = false) AND QuizID = $7 AND Deleted = false
RETURNING id RETURNING id
` `
@ -157,45 +183,27 @@ func (q *Queries) CheckAndAddDefault(ctx context.Context, arg CheckAndAddDefault
return err return err
} }
const checkExpired = `-- name: CheckExpired :many const checkExpiredToken = `-- name: CheckExpiredToken :one
SELECT accountid, refreshtoken, accesstoken, authcode, expiration, createdat FROM tokens WHERE Expiration <= TO_TIMESTAMP(EXTRACT(EPOCH FROM NOW()) + (10 * 60)) SELECT accountid, refreshtoken, accesstoken, authcode, expiration, createdat FROM tokens WHERE AccountID = $1 AND Expiration <= NOW()
` `
func (q *Queries) CheckExpired(ctx context.Context) ([]Token, error) { func (q *Queries) CheckExpiredToken(ctx context.Context, accountid string) (Token, error) {
rows, err := q.db.QueryContext(ctx, checkExpired) row := q.db.QueryRowContext(ctx, checkExpiredToken, accountid)
if err != nil { var i Token
return nil, err err := row.Scan(
} &i.Accountid,
defer rows.Close() &i.Refreshtoken,
var items []Token &i.Accesstoken,
for rows.Next() { &i.Authcode,
var i Token &i.Expiration,
if err := rows.Scan( &i.Createdat,
&i.Accountid, )
&i.Refreshtoken, return i, err
&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 const checkFields = `-- name: CheckFields :many
WITH user_data AS ( WITH user_data AS (
SELECT AmoID SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
FROM users
WHERE users.AccountID = $1
), new_fields AS ( ), new_fields AS (
SELECT (field->>'AmoID')::INT AS amoID, SELECT (field->>'AmoID')::INT AS amoID,
COALESCE(field->>'Code', '')::varchar(255) AS code, COALESCE(field->>'Code', '')::varchar(255) AS code,
@ -275,29 +283,6 @@ func (q *Queries) CheckFields(ctx context.Context, arg CheckFieldsParams) ([]Che
return items, nil 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 const checkPipelines = `-- name: CheckPipelines :many
WITH new_pipelines AS ( WITH new_pipelines AS (
SELECT (pipeline->>'AmoID')::INT AS amoID, SELECT (pipeline->>'AmoID')::INT AS amoID,
@ -480,9 +465,7 @@ func (q *Queries) CheckSteps(ctx context.Context, dollar_1 json.RawMessage) ([]C
const checkTags = `-- name: CheckTags :many const checkTags = `-- name: CheckTags :many
WITH user_data AS ( WITH user_data AS (
SELECT AmoID SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
FROM users
WHERE users.AccountID = $1
), new_tags AS ( ), new_tags AS (
SELECT (tag->>'AmoID')::INT AS amoID, SELECT (tag->>'AmoID')::INT AS amoID,
(tag->>'Entity')::entitytype AS Entity, (tag->>'Entity')::entitytype AS Entity,
@ -555,79 +538,6 @@ func (q *Queries) CheckTags(ctx context.Context, arg CheckTagsParams) ([]CheckTa
return items, nil 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, driveurl
)
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, driveurl
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 const copyQuestion = `-- name: CopyQuestion :one
INSERT INTO question( INSERT INTO question(
quiz_id, title, description, questiontype, required, quiz_id, title, description, questiontype, required,
@ -770,23 +680,17 @@ func (q *Queries) CreateAccount(ctx context.Context, arg CreateAccountParams) (A
const createAmoAccount = `-- name: CreateAmoAccount :exec const createAmoAccount = `-- name: CreateAmoAccount :exec
INSERT INTO users (AccountID, AmoID, Name, Email, Role, "Group", Deleted, CreatedAt, Subdomain, AmoUserID, Country,DriveURL) INSERT INTO accountsAmo (AccountID, AmoID,Name, Subdomain, Country,DriveURL)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) VALUES ($1, $2, $3, $4, $5, $6)
` `
type CreateAmoAccountParams struct { type CreateAmoAccountParams struct {
Accountid string `db:"accountid" json:"accountid"` Accountid string `db:"accountid" json:"accountid"`
Amoid int32 `db:"amoid" json:"amoid"` Amoid int32 `db:"amoid" json:"amoid"`
Name string `db:"name" json:"name"` Name string `db:"name" json:"name"`
Email string `db:"email" json:"email"` Subdomain string `db:"subdomain" json:"subdomain"`
Role int32 `db:"role" json:"role"` Country string `db:"country" json:"country"`
Group int32 `db:"Group" json:"Group"` Driveurl string `db:"driveurl" json:"driveurl"`
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"`
Driveurl string `db:"driveurl" json:"driveurl"`
} }
// amo methods: // amo methods:
@ -795,13 +699,7 @@ func (q *Queries) CreateAmoAccount(ctx context.Context, arg CreateAmoAccountPara
arg.Accountid, arg.Accountid,
arg.Amoid, arg.Amoid,
arg.Name, arg.Name,
arg.Email,
arg.Role,
arg.Group,
arg.Deleted,
arg.Createdat,
arg.Subdomain, arg.Subdomain,
arg.Amouserid,
arg.Country, arg.Country,
arg.Driveurl, arg.Driveurl,
) )
@ -1034,7 +932,7 @@ func (q *Queries) DeleteTags(ctx context.Context, dollar_1 []int64) error {
} }
const deleteUsers = `-- name: DeleteUsers :exec const deleteUsers = `-- name: DeleteUsers :exec
UPDATE users SET Deleted = true WHERE ID = ANY($1::bigint[]) UPDATE usersAmo SET Deleted = true WHERE ID = ANY($1::bigint[])
` `
func (q *Queries) DeleteUsers(ctx context.Context, dollar_1 []int64) error { func (q *Queries) DeleteUsers(ctx context.Context, dollar_1 []int64) error {
@ -1486,6 +1384,43 @@ func (q *Queries) GetAllAnswersByQuizID(ctx context.Context, session sql.NullStr
return items, nil return items, nil
} }
const getAllCompanyUsers = `-- name: GetAllCompanyUsers :many
SELECT id, amoid, amouserid, name, email, role, "Group", deleted, createdat FROM usersamo WHERE amoid = $1 AND deleted = false
`
func (q *Queries) GetAllCompanyUsers(ctx context.Context, amoid int32) ([]Usersamo, error) {
rows, err := q.db.QueryContext(ctx, getAllCompanyUsers, amoid)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Usersamo
for rows.Next() {
var i Usersamo
if err := rows.Scan(
&i.ID,
&i.Amoid,
&i.Amouserid,
&i.Name,
&i.Email,
&i.Role,
&i.Group,
&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 getAllTokens = `-- name: GetAllTokens :many const getAllTokens = `-- name: GetAllTokens :many
SELECT accountid, refreshtoken, accesstoken, authcode, expiration, createdat FROM tokens SELECT accountid, refreshtoken, accesstoken, authcode, expiration, createdat FROM tokens
` `
@ -1520,31 +1455,67 @@ func (q *Queries) GetAllTokens(ctx context.Context) ([]Token, error) {
return items, nil return items, nil
} }
const getCurrentAccount = `-- name: GetCurrentAccount :one const getCurrentCompany = `-- name: GetCurrentCompany :one
SELECT id, accountid, amoid, name, email, role, "Group", deleted, createdat, subdomain, amouserid, country, driveurl FROM users WHERE AccountID = $1 AND Deleted = false SELECT id, accountid, amoid, name, deleted, createdat, subdomain, country, driveurl FROM accountsAmo WHERE AccountID = $1 AND Deleted = false
` `
func (q *Queries) GetCurrentAccount(ctx context.Context, accountid string) (User, error) { func (q *Queries) GetCurrentCompany(ctx context.Context, accountid string) (Accountsamo, error) {
row := q.db.QueryRowContext(ctx, getCurrentAccount, accountid) row := q.db.QueryRowContext(ctx, getCurrentCompany, accountid)
var i User var i Accountsamo
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.Accountid, &i.Accountid,
&i.Amoid, &i.Amoid,
&i.Name, &i.Name,
&i.Email,
&i.Role,
&i.Group,
&i.Deleted, &i.Deleted,
&i.Createdat, &i.Createdat,
&i.Subdomain, &i.Subdomain,
&i.Amouserid,
&i.Country, &i.Country,
&i.Driveurl, &i.Driveurl,
) )
return i, err return i, err
} }
const getExistingContactAmo = `-- name: GetExistingContactAmo :many
WITH getAmoID AS (
SELECT AmoID FROM amoContact WHERE amoContact.AccountID = $1 AND amoContact.Field = ANY($2::text[])
) SELECT id, accountid, amoid, field FROM amoContact
WHERE amoContact.AccountID = $1 AND amoContact.AmoID IN (SELECT AmoID FROM getAmoID)
`
type GetExistingContactAmoParams struct {
Accountid int32 `db:"accountid" json:"accountid"`
Column2 []string `db:"column_2" json:"column_2"`
}
func (q *Queries) GetExistingContactAmo(ctx context.Context, arg GetExistingContactAmoParams) ([]Amocontact, error) {
rows, err := q.db.QueryContext(ctx, getExistingContactAmo, arg.Accountid, pq.Array(arg.Column2))
if err != nil {
return nil, err
}
defer rows.Close()
var items []Amocontact
for rows.Next() {
var i Amocontact
if err := rows.Scan(
&i.ID,
&i.Accountid,
&i.Amoid,
&i.Field,
); 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 getExpiredCountPrivilege = `-- name: GetExpiredCountPrivilege :many const getExpiredCountPrivilege = `-- name: GetExpiredCountPrivilege :many
SELECT p.id, p.privilegeID, p.privilege_name, p.amount, p.created_at, a.user_id SELECT p.id, p.privilegeID, p.privilege_name, p.amount, p.created_at, a.user_id
FROM privileges p FROM privileges p
@ -1661,8 +1632,11 @@ func (q *Queries) GetFieldByAmoID(ctx context.Context, amoid int32) (Field, erro
} }
const getFieldsWithPagination = `-- name: GetFieldsWithPagination :many const getFieldsWithPagination = `-- name: GetFieldsWithPagination :many
WITH user_data AS (
SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
)
SELECT f.id, f.amoid, f.code, f.accountid, f.name, f.entity, f.type, f.deleted, f.createdat, COUNT(*) OVER() as total_count 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 AND Deleted = false) u ON f.AccountID = u.AmoID FROM fields f JOIN user_data u ON f.AccountID = u.AmoID
WHERE f.Deleted = false WHERE f.Deleted = false
ORDER BY f.ID OFFSET ($2 - 1) * $3 LIMIT $3 ORDER BY f.ID OFFSET ($2 - 1) * $3 LIMIT $3
` `
@ -1817,8 +1791,11 @@ func (q *Queries) GetListStartQuiz(ctx context.Context, accountid string) ([]int
} }
const getPipelinesWithPagination = `-- name: GetPipelinesWithPagination :many const getPipelinesWithPagination = `-- name: GetPipelinesWithPagination :many
WITH user_data AS (
SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
)
SELECT p.id, p.amoid, p.accountid, p.name, p.isarchive, p.deleted, p.createdat, COUNT(*) OVER() as total_count 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 AND Deleted = false) u ON p.AccountID = u.AmoID FROM pipelines p JOIN user_data u ON p.AccountID = u.AmoID
WHERE p.Deleted = false WHERE p.Deleted = false
ORDER BY p.ID OFFSET ($2 - 1) * $3 LIMIT $3 ORDER BY p.ID OFFSET ($2 - 1) * $3 LIMIT $3
` `
@ -2432,8 +2409,11 @@ func (q *Queries) GetResultAnswers(ctx context.Context, id int64) ([]GetResultAn
} }
const getStepsWithPagination = `-- name: GetStepsWithPagination :many const getStepsWithPagination = `-- name: GetStepsWithPagination :many
WITH user_data AS (
SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
)
SELECT s.id, s.amoid, s.pipelineid, s.accountid, s.name, s.color, s.deleted, s.createdat, COUNT(*) OVER() as total_count 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 AND Deleted = false) u ON s.AccountID = u.AmoID FROM steps s JOIN user_data u ON s.AccountID = u.AmoID
WHERE s.Deleted = false AND PipelineID = $4 WHERE s.Deleted = false AND PipelineID = $4
ORDER BY s.ID OFFSET ($2 - 1) * $3 LIMIT $3 ORDER BY s.ID OFFSET ($2 - 1) * $3 LIMIT $3
` `
@ -2496,8 +2476,11 @@ func (q *Queries) GetStepsWithPagination(ctx context.Context, arg GetStepsWithPa
} }
const getTagsWithPagination = `-- name: GetTagsWithPagination :many const getTagsWithPagination = `-- name: GetTagsWithPagination :many
WITH user_data AS (
SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
)
SELECT t.id, t.amoid, t.accountid, t.entity, t.name, t.color, t.deleted, t.createdat, COUNT(*) OVER() as total_count 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 AND Deleted = false) u ON t.AccountID = u.AmoID FROM tags t JOIN user_data u ON t.AccountID = u.AmoID
WHERE t.Deleted = false WHERE t.Deleted = false
ORDER BY t.ID OFFSET ($2 - 1) * $3 LIMIT $3 ORDER BY t.ID OFFSET ($2 - 1) * $3 LIMIT $3
` `
@ -2752,44 +2735,28 @@ func (q *Queries) GetUserTagsByID(ctx context.Context, accountid int32) ([]GetUs
} }
const getUserUsersByID = `-- name: GetUserUsersByID :many const getUserUsersByID = `-- name: GetUserUsersByID :many
SELECT ID,AccountID,AmoID,Name,Email,Role,"Group",Subdomain,AmoUserID,Country SELECT id, amoid, amouserid, name, email, role, "Group", deleted, createdat FROM usersAmo WHERE amoid = $1 AND Deleted = false
FROM users
WHERE AmoUserID = $1 AND Deleted = false
` `
type GetUserUsersByIDRow struct { func (q *Queries) GetUserUsersByID(ctx context.Context, amoid int32) ([]Usersamo, error) {
ID int64 `db:"id" json:"id"` rows, err := q.db.QueryContext(ctx, getUserUsersByID, amoid)
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 { if err != nil {
return nil, err return nil, err
} }
defer rows.Close() defer rows.Close()
var items []GetUserUsersByIDRow var items []Usersamo
for rows.Next() { for rows.Next() {
var i GetUserUsersByIDRow var i Usersamo
if err := rows.Scan( if err := rows.Scan(
&i.ID, &i.ID,
&i.Accountid,
&i.Amoid, &i.Amoid,
&i.Amouserid,
&i.Name, &i.Name,
&i.Email, &i.Email,
&i.Role, &i.Role,
&i.Group, &i.Group,
&i.Subdomain, &i.Deleted,
&i.Amouserid, &i.Createdat,
&i.Country,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
@ -2806,11 +2773,11 @@ func (q *Queries) GetUserUsersByID(ctx context.Context, amouserid int32) ([]GetU
const getUsersWithPagination = `-- name: GetUsersWithPagination :many const getUsersWithPagination = `-- name: GetUsersWithPagination :many
WITH user_data AS ( WITH user_data AS (
SELECT AmoID FROM users WHERE users.AccountID = $1 AND Deleted = false SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.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, u.driveurl, COUNT(*) OVER() as total_count SELECT u.id, u.amoid, u.amouserid, u.name, u.email, u.role, u."Group", u.deleted, u.createdat, COUNT(*) OVER() as total_count
FROM users u FROM usersAmo u
JOIN user_data a ON u.AmoUserID = a.AmoID JOIN user_data a ON u.AmoID = a.AmoID
WHERE u.Deleted = false WHERE u.Deleted = false
ORDER BY u.ID OFFSET ($2 - 1) * $3 LIMIT $3 ORDER BY u.ID OFFSET ($2 - 1) * $3 LIMIT $3
` `
@ -2822,20 +2789,16 @@ type GetUsersWithPaginationParams struct {
} }
type GetUsersWithPaginationRow struct { type GetUsersWithPaginationRow struct {
ID int64 `db:"id" json:"id"` ID int64 `db:"id" json:"id"`
Accountid string `db:"accountid" json:"accountid"` Amoid int32 `db:"amoid" json:"amoid"`
Amoid int32 `db:"amoid" json:"amoid"` Amouserid int32 `db:"amouserid" json:"amouserid"`
Name string `db:"name" json:"name"` Name string `db:"name" json:"name"`
Email string `db:"email" json:"email"` Email string `db:"email" json:"email"`
Role int32 `db:"role" json:"role"` Role int32 `db:"role" json:"role"`
Group int32 `db:"Group" json:"Group"` Group int32 `db:"Group" json:"Group"`
Deleted bool `db:"deleted" json:"deleted"` Deleted bool `db:"deleted" json:"deleted"`
Createdat sql.NullTime `db:"createdat" json:"createdat"` Createdat time.Time `db:"createdat" json:"createdat"`
Subdomain string `db:"subdomain" json:"subdomain"` TotalCount int64 `db:"total_count" json:"total_count"`
Amouserid int32 `db:"amouserid" json:"amouserid"`
Country string `db:"country" json:"country"`
Driveurl string `db:"driveurl" json:"driveurl"`
TotalCount int64 `db:"total_count" json:"total_count"`
} }
func (q *Queries) GetUsersWithPagination(ctx context.Context, arg GetUsersWithPaginationParams) ([]GetUsersWithPaginationRow, error) { func (q *Queries) GetUsersWithPagination(ctx context.Context, arg GetUsersWithPaginationParams) ([]GetUsersWithPaginationRow, error) {
@ -2849,18 +2812,14 @@ func (q *Queries) GetUsersWithPagination(ctx context.Context, arg GetUsersWithPa
var i GetUsersWithPaginationRow var i GetUsersWithPaginationRow
if err := rows.Scan( if err := rows.Scan(
&i.ID, &i.ID,
&i.Accountid,
&i.Amoid, &i.Amoid,
&i.Amouserid,
&i.Name, &i.Name,
&i.Email, &i.Email,
&i.Role, &i.Role,
&i.Group, &i.Group,
&i.Deleted, &i.Deleted,
&i.Createdat, &i.Createdat,
&i.Subdomain,
&i.Amouserid,
&i.Country,
&i.Driveurl,
&i.TotalCount, &i.TotalCount,
); err != nil { ); err != nil {
return nil, err return nil, err
@ -2878,17 +2837,17 @@ func (q *Queries) GetUsersWithPagination(ctx context.Context, arg GetUsersWithPa
const gettingAmoUsersTrueResults = `-- name: GettingAmoUsersTrueResults :many const gettingAmoUsersTrueResults = `-- name: GettingAmoUsersTrueResults :many
SELECT a.quiz_id,a.id,a.result,a.question_id,a.content,a.session, SELECT a.quiz_id,a.id,a.result,a.question_id,a.content,a.session,
(SELECT a2.utm COALESCE((SELECT a2.utm
FROM answer a2 FROM answer a2
WHERE a2.start = true AND a2.session = a.session WHERE a2.start = true AND a2.session = a.session
LIMIT 1) AS utm LIMIT 1), '{}'::jsonb) AS utm
,t.accesstoken,r.accountid,r.fieldsrule,r.tagstoadd,r.performerid,r.stepid,r.pipelineid,(SELECT u.name FROM users u WHERE u.amoid = r.performerid) AS performer_name,u.subdomain,u.accountid,u.driveurl ,t.accesstoken,r.accountid,r.fieldsrule,r.tagstoadd,r.performerid,r.stepid,r.pipelineid,(SELECT u.name FROM usersAmo u WHERE u.AmoUserID = r.performerid AND u.deleted = false) AS performer_name,u.subdomain,u.accountid,u.driveurl
FROM answer a FROM answer a
INNER JOIN quiz q ON a.quiz_id = q.id INNER JOIN quiz q ON a.quiz_id = q.id
LEFT JOIN amoCRMStatuses s ON a.id = s.AnswerID LEFT JOIN amoCRMStatuses s ON a.id = s.AnswerID
INNER JOIN rules r ON q.id = r.QuizID INNER JOIN rules r ON q.id = r.QuizID
INNER JOIN tokens t ON q.accountid = t.AccountID INNER JOIN tokens t ON q.accountid = t.AccountID
INNER JOIN users u ON q.accountid = u.accountid AND u.amoid = r.accountid INNER JOIN accountsAmo u ON q.accountid = u.accountid AND u.amoid = r.accountid
WHERE a.result = true WHERE a.result = true
AND s.id IS NULL AND s.id IS NULL
AND a.deleted = false AND a.deleted = false
@ -2904,7 +2863,7 @@ type GettingAmoUsersTrueResultsRow struct {
QuestionID int64 `db:"question_id" json:"question_id"` QuestionID int64 `db:"question_id" json:"question_id"`
Content sql.NullString `db:"content" json:"content"` Content sql.NullString `db:"content" json:"content"`
Session sql.NullString `db:"session" json:"session"` Session sql.NullString `db:"session" json:"session"`
Utm json.RawMessage `db:"utm" json:"utm"` Utm interface{} `db:"utm" json:"utm"`
Accesstoken string `db:"accesstoken" json:"accesstoken"` Accesstoken string `db:"accesstoken" json:"accesstoken"`
Accountid int32 `db:"accountid" json:"accountid"` Accountid int32 `db:"accountid" json:"accountid"`
Fieldsrule json.RawMessage `db:"fieldsrule" json:"fieldsrule"` Fieldsrule json.RawMessage `db:"fieldsrule" json:"fieldsrule"`
@ -3038,6 +2997,23 @@ func (q *Queries) InsertAnswers(ctx context.Context, arg InsertAnswersParams) (A
return i, err return i, err
} }
const insertContactAmo = `-- name: InsertContactAmo :one
INSERT INTO amoContact (AccountID, AmoID, Field) VALUES ($1, $2, $3) RETURNING AmoID
`
type InsertContactAmoParams struct {
Accountid int32 `db:"accountid" json:"accountid"`
Amoid int32 `db:"amoid" json:"amoid"`
Field string `db:"field" json:"field"`
}
func (q *Queries) InsertContactAmo(ctx context.Context, arg InsertContactAmoParams) (int32, error) {
row := q.db.QueryRowContext(ctx, insertContactAmo, arg.Accountid, arg.Amoid, arg.Field)
var amoid int32
err := row.Scan(&amoid)
return amoid, err
}
const insertPrivilege = `-- name: InsertPrivilege :exec const insertPrivilege = `-- name: InsertPrivilege :exec
INSERT INTO privileges (privilegeID, account_id, privilege_name, amount, created_at) VALUES ($1, $2, $3, $4, $5) INSERT INTO privileges (privilegeID, account_id, privilege_name, amount, created_at) VALUES ($1, $2, $3, $4, $5)
` `
@ -3439,7 +3415,7 @@ func (q *Queries) QuizCopyQid(ctx context.Context, arg QuizCopyQidParams) (QuizC
const setQuizSettings = `-- name: SetQuizSettings :one const setQuizSettings = `-- name: SetQuizSettings :one
INSERT INTO rules (AccountID, QuizID, PerformerID, PipelineID, StepID, FieldsRule,TagsToAdd) INSERT INTO rules (AccountID, QuizID, PerformerID, PipelineID, StepID, FieldsRule,TagsToAdd)
SELECT u.AmoID AS AccountID,$1 AS QuizID,$2 AS PerformerID,$3 AS PipelineID, SELECT u.AmoID AS AccountID,$1 AS QuizID,$2 AS PerformerID,$3 AS PipelineID,
$4 AS StepID,$5 AS FieldsRule,$6 AS TagsToAdd FROM users u WHERE u.AccountID = $7 AND u.Deleted = false $4 AS StepID,$5 AS FieldsRule,$6 AS TagsToAdd FROM accountsamo u WHERE u.AccountID = $7 AND u.Deleted = false
RETURNING id RETURNING id
` `
@ -3472,7 +3448,7 @@ const settingDealAmoStatus = `-- name: SettingDealAmoStatus :exec
INSERT INTO amoCRMStatuses (AccountID, DealID, AnswerID, Status) INSERT INTO amoCRMStatuses (AccountID, DealID, AnswerID, Status)
SELECT u.AmoID, $1, $2, $3 SELECT u.AmoID, $1, $2, $3
FROM tokens AS t FROM tokens AS t
JOIN users AS u ON t.AccountID = u.AccountID JOIN accountsAmo AS u ON t.AccountID = u.AccountID
WHERE t.AccessToken = $4 AND u.Deleted = false WHERE t.AccessToken = $4 AND u.Deleted = false
` `
@ -3494,12 +3470,13 @@ func (q *Queries) SettingDealAmoStatus(ctx context.Context, arg SettingDealAmoSt
} }
const softDeleteAccount = `-- name: SoftDeleteAccount :exec const softDeleteAccount = `-- name: SoftDeleteAccount :exec
WITH userd AS ( WITH amoCompany AS (
SELECT AmoUserID FROM users WHERE users.AccountID = $1 SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1
), ),usersDel AS (
tokend AS ( UPDATE usersAmo SET Deleted = true WHERE AmoID = (SELECT AmoID FROM amoCompany)
UPDATE users SET Deleted = true WHERE AmoUserID IN (SELECT AmoUserID FROM userd) ),
) companyDel AS ( UPDATE accountsAmo SET Deleted = true WHERE AmoID = (SELECT AmoID FROM amoCompany)
)
DELETE FROM tokens WHERE tokens.AccountID = $1 DELETE FROM tokens WHERE tokens.AccountID = $1
` `
@ -3545,9 +3522,73 @@ func (q *Queries) TemplateCopy(ctx context.Context, arg TemplateCopyParams) (int
return quiz_id, err return quiz_id, err
} }
const updateAmoAccount = `-- name: UpdateAmoAccount :exec
UPDATE accountsAmo SET Name = $2, Subdomain = $3, Country = $4, DriveURL = $5 WHERE AccountID = $1 AND Deleted = false
`
type UpdateAmoAccountParams struct {
Accountid string `db:"accountid" json:"accountid"`
Name string `db:"name" json:"name"`
Subdomain string `db:"subdomain" json:"subdomain"`
Country string `db:"country" json:"country"`
Driveurl string `db:"driveurl" json:"driveurl"`
}
func (q *Queries) UpdateAmoAccount(ctx context.Context, arg UpdateAmoAccountParams) error {
_, err := q.db.ExecContext(ctx, updateAmoAccount,
arg.Accountid,
arg.Name,
arg.Subdomain,
arg.Country,
arg.Driveurl,
)
return err
}
const updateAmoAccountUser = `-- name: UpdateAmoAccountUser :exec
UPDATE usersAmo SET Name = $3, Email = $4, Role = $5, "Group" = $6
WHERE AmoID = $1 AND AmoUserID = $2 AND deleted = false
`
type UpdateAmoAccountUserParams struct {
Amoid int32 `db:"amoid" json:"amoid"`
Amouserid int32 `db:"amouserid" json:"amouserid"`
Name string `db:"name" json:"name"`
Email string `db:"email" json:"email"`
Role int32 `db:"role" json:"role"`
Group int32 `db:"Group" json:"Group"`
}
func (q *Queries) UpdateAmoAccountUser(ctx context.Context, arg UpdateAmoAccountUserParams) error {
_, err := q.db.ExecContext(ctx, updateAmoAccountUser,
arg.Amoid,
arg.Amouserid,
arg.Name,
arg.Email,
arg.Role,
arg.Group,
)
return err
}
const updateAmoContact = `-- name: UpdateAmoContact :exec
UPDATE amoContact SET Field = $1,AmoID=$3 WHERE ID = $2
`
type UpdateAmoContactParams struct {
Field string `db:"field" json:"field"`
ID int64 `db:"id" json:"id"`
Amoid int32 `db:"amoid" json:"amoid"`
}
func (q *Queries) UpdateAmoContact(ctx context.Context, arg UpdateAmoContactParams) error {
_, err := q.db.ExecContext(ctx, updateAmoContact, arg.Field, arg.ID, arg.Amoid)
return err
}
const updateFieldRules = `-- name: UpdateFieldRules :exec const updateFieldRules = `-- name: UpdateFieldRules :exec
UPDATE rules SET FieldsRule = $1 UPDATE rules SET FieldsRule = $1
WHERE AccountID = (SELECT AmoID FROM users WHERE users.AccountID = $2 AND users.Deleted = false) AND QuizID = $3 AND Deleted = false WHERE AccountID = (SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $2 AND accountsAmo.Deleted = false) AND QuizID = $3 AND Deleted = false
` `
type UpdateFieldRulesParams struct { type UpdateFieldRulesParams struct {
@ -3680,25 +3721,9 @@ func (q *Queries) UpdateTags(ctx context.Context, dollar_1 json.RawMessage) erro
return err 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 updatingDealAmoStatus = `-- name: UpdatingDealAmoStatus :exec const updatingDealAmoStatus = `-- name: UpdatingDealAmoStatus :exec
UPDATE amoCRMStatuses SET Status = $1 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 AND u.Deleted = false) WHERE DealID = $2 AND AccountID = (SELECT u.AmoID FROM tokens AS t JOIN accountsAmo AS u ON t.AccountID = u.AccountID WHERE t.AccessToken = $3 AND u.Deleted = false)
` `
type UpdatingDealAmoStatusParams struct { type UpdatingDealAmoStatusParams struct {
@ -3713,14 +3738,17 @@ func (q *Queries) UpdatingDealAmoStatus(ctx context.Context, arg UpdatingDealAmo
} }
const webhookDelete = `-- name: WebhookDelete :exec const webhookDelete = `-- name: WebhookDelete :exec
WITH userd AS ( WITH companyDel AS (
UPDATE users SET Deleted = true WHERE AmoUserID = $1 RETURNING AccountID UPDATE accountsAmo SET Deleted = true WHERE accountsAmo.AmoID = $1 RETURNING AccountID
),
userDel AS (
UPDATE usersAmo SET Deleted = true WHERE AmoID = $1
) )
DELETE FROM tokens WHERE AccountID IN (SELECT AccountID FROM userd) DELETE FROM tokens WHERE AccountID IN (SELECT AccountID FROM companyDel)
` `
func (q *Queries) WebhookDelete(ctx context.Context, amouserid int32) error { func (q *Queries) WebhookDelete(ctx context.Context, amoid int32) error {
_, err := q.db.ExecContext(ctx, webhookDelete, amouserid) _, err := q.db.ExecContext(ctx, webhookDelete, amoid)
return err return err
} }

2
go.mod

@ -3,6 +3,7 @@ module penahub.gitlab.yandexcloud.net/backend/quiz/common.git
go 1.21.4 go 1.21.4
require ( require (
github.com/ClickHouse/clickhouse-go v1.5.4
github.com/gofiber/fiber/v2 v2.52.0 github.com/gofiber/fiber/v2 v2.52.0
github.com/golang-jwt/jwt/v5 v5.2.0 github.com/golang-jwt/jwt/v5 v5.2.0
github.com/golang/protobuf v1.5.3 github.com/golang/protobuf v1.5.3
@ -19,6 +20,7 @@ require (
require ( require (
github.com/andybalholm/brotli v1.0.5 // indirect github.com/andybalholm/brotli v1.0.5 // indirect
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.6.0 // indirect

12
go.sum

@ -1,12 +1,19 @@
github.com/ClickHouse/clickhouse-go v1.5.4 h1:cKjXeYLNWVJIx2J1K6H2CqyRmfwVJVY1OV1coaaFcI0=
github.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/gofiber/fiber/v2 v2.52.0 h1:S+qXi7y+/Pgvqq4DrSmREGiFwtB7Bu6+QFLuIHYw/UE= github.com/gofiber/fiber/v2 v2.52.0 h1:S+qXi7y+/Pgvqq4DrSmREGiFwtB7Bu6+QFLuIHYw/UE=
github.com/gofiber/fiber/v2 v2.52.0/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/gofiber/fiber/v2 v2.52.0/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
@ -20,6 +27,7 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 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 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
@ -32,6 +40,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@ -41,6 +50,7 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.69 h1:l8AnsQFyY1xiwa/DaQskY4NXSLA2yrGsW5iD9nRPVS0= github.com/minio/minio-go/v7 v7.0.69 h1:l8AnsQFyY1xiwa/DaQskY4NXSLA2yrGsW5iD9nRPVS0=
@ -52,6 +62,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

@ -1,32 +1,30 @@
package model package model
type User struct { import "time"
/* - айдишник в нашей системе Primary Key*/
ID int64 `json:"ID"` type AmoAccountUser struct {
/* - id пользователя из токена в нашей системе*/ ID int64 `json:"id"` // ID пользователя
Accountid string `json:"AccountID"` AmoID int32 `json:"amoID"` // ID компании в амо, к которой пользователь принадлежит
/* - айдишник пользователя в амо*/ AmoUserID int32 `json:"amoUserID"` // ID пользователя в амо
AmoID int32 `json:"AmocrmID"` Name string `json:"name"` // Имя
/* - имя аккаунта в амо*/ Email string `json:"email"` // Email
Name string `json:"Name"` Role int32 `json:"role"` // Роль
/* - почта пользователя из амо*/ Group int32 `json:"group"` // Группа
Email string `json:"Email"` Deleted bool `json:"deleted"`
/* - роль пользователя в амо*/ CreatedAt time.Time `json:"createdAt"`
Role int32 `json:"Role"` }
/* - группы пользователя в амо*/
Group int32 `json:"Group"` type AmoAccount struct {
/* - флаг мягкого удаления*/ ID int64 `json:"id"` // ID компании
Deleted bool `json:"Deleted"` AccountID string `json:"accountID"` // ID аккаунта нас
/* - таймштамп создания аккаунта*/ AmoID int32 `json:"amoID"` // ID компании в амо
Createdat int64 `json:"CreatedAt"` Name string `json:"name"` // Название
/* - поддомен организации в амо*/ Deleted bool `json:"deleted"`
Subdomain string `json:"Subdomain"` CreatedAt time.Time `json:"createdAt"`
/* - айдишник пользвателя, который подключал интеграцию*/ Subdomain string `json:"subdomain"` // поддомен
Amouserid int32 `json:"AmoUserID"` Country string `json:"country"` // Страна
/* - страна указанная в настройках амо*/ DriveURL string `json:"driveURL"` // URL объктного хранилища
Country string `json:"Country"` Stale bool `json:"stale"` // флаг "не свежести" если с токенами все в порядке - false, если просрочились то true
// урл объектного хранилища пользователя в амо
DriveURL string `json:"DriveURL"`
} }
type UserGroups struct { type UserGroups struct {
@ -290,3 +288,11 @@ type AmoUsersTrueResults struct {
QuizAccountID string QuizAccountID string
DriveURL string DriveURL string
} }
// возможно стоит добавить enum? тип ContactQuizConfig уже есть
type ContactAmo struct {
ID int64
AccountID int32 // id аккаунта в амо к которому привязан контакт
AmoID int32 // id контакта в амо
Field string // значение поля
}

@ -55,7 +55,7 @@ type UserListResp struct {
/* - общее количество юзеров, которые у нас закешированы для этого пользователя*/ /* - общее количество юзеров, которые у нас закешированы для этого пользователя*/
Count int64 `json:"count"` Count int64 `json:"count"`
/* - список юзеров, которые были закешированы нашим сервисом*/ /* - список юзеров, которые были закешированы нашим сервисом*/
Items []User `json:"items"` Items []AmoAccountUser `json:"items"`
} }
type UserListStepsResp struct { type UserListStepsResp struct {

@ -6,6 +6,7 @@ import (
"encoding/json" "encoding/json"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal/sqlcgen" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal/sqlcgen"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model" "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/pj_errors"
"time" "time"
) )
@ -39,20 +40,18 @@ func (r *AmoRepository) GettingUserWithPagination(ctx context.Context, req *mode
return nil, err return nil, err
} }
var count int64 var count int64
var users []model.User var users []model.AmoAccountUser
for _, row := range rows { for _, row := range rows {
user := model.User{ user := model.AmoAccountUser{
ID: row.ID, ID: row.ID,
Accountid: row.Accountid,
AmoID: row.Amoid, AmoID: row.Amoid,
AmoUserID: row.Amouserid,
Name: row.Name, Name: row.Name,
Email: row.Email, Email: row.Email,
Group: row.Group, Group: row.Group,
Role: row.Role, Role: row.Role,
Createdat: row.Createdat.Time.Unix(), Deleted: row.Deleted,
Subdomain: row.Subdomain, CreatedAt: row.Createdat,
Amouserid: row.Amouserid,
Country: row.Country,
} }
count = row.TotalCount count = row.TotalCount
@ -75,41 +74,58 @@ func (r *AmoRepository) SoftDeleteAccount(ctx context.Context, accountID string)
return nil return nil
} }
func (r *AmoRepository) GetCurrentAccount(ctx context.Context, accountID string) (*model.User, error) { func (r *AmoRepository) GetCurrentAccount(ctx context.Context, accountID string) (*model.AmoAccount, error) {
row, err := r.queries.GetCurrentAccount(ctx, accountID) row, err := r.queries.GetCurrentCompany(ctx, accountID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
user := model.User{ user := model.AmoAccount{
ID: row.ID, ID: row.ID,
Accountid: row.Accountid, AccountID: row.Accountid,
AmoID: row.Amoid, AmoID: row.Amoid,
Name: row.Name, Name: row.Name,
Email: row.Email, Deleted: row.Deleted,
Role: row.Role, CreatedAt: row.Createdat,
Group: row.Group,
Createdat: row.Createdat.Time.Unix(),
Subdomain: row.Subdomain, Subdomain: row.Subdomain,
Amouserid: row.Amouserid,
Country: row.Country, Country: row.Country,
DriveURL: row.Driveurl, DriveURL: row.Driveurl,
} }
_, err = r.queries.CheckExpiredToken(ctx, accountID)
if err != nil {
if err == sql.ErrNoRows {
user.Stale = false
return &user, nil
}
return nil, err
}
user.Stale = true
return &user, nil return &user, nil
} }
func (r *AmoRepository) CreateAccount(ctx context.Context, accountID string, userInfo model.User) error { func (r *AmoRepository) UpdateCurrentAccount(ctx context.Context, user model.AmoAccount) error {
err := r.queries.UpdateAmoAccount(ctx, sqlcgen.UpdateAmoAccountParams{
Accountid: user.AccountID,
Name: user.Name,
Subdomain: user.Subdomain,
Country: user.Country,
Driveurl: user.DriveURL,
})
if err != nil {
return err
}
return nil
}
func (r *AmoRepository) CreateAccount(ctx context.Context, userInfo model.AmoAccount) error {
err := r.queries.CreateAmoAccount(ctx, sqlcgen.CreateAmoAccountParams{ err := r.queries.CreateAmoAccount(ctx, sqlcgen.CreateAmoAccountParams{
Accountid: accountID, Accountid: userInfo.AccountID,
Amoid: userInfo.AmoID, Amoid: userInfo.AmoID,
Name: userInfo.Name, Name: userInfo.Name,
Email: userInfo.Email,
Role: userInfo.Role,
Group: userInfo.Group,
Createdat: sql.NullTime{Time: time.Now(), Valid: true},
Subdomain: userInfo.Subdomain, Subdomain: userInfo.Subdomain,
Amouserid: userInfo.Amouserid,
Country: userInfo.Country, Country: userInfo.Country,
Driveurl: userInfo.DriveURL, Driveurl: userInfo.DriveURL,
}) })
@ -121,15 +137,17 @@ func (r *AmoRepository) CreateAccount(ctx context.Context, accountID string, use
return nil return nil
} }
func (r *AmoRepository) CheckMainUser(ctx context.Context, user model.User) error { // todo возможно стоит обновлять еще и компанию пока не знаю
err := r.queries.CheckMainUser(ctx, sqlcgen.CheckMainUserParams{
Name: user.Name,
Group: user.Group,
Email: user.Email,
Role: user.Role,
Amoid: user.AmoID,
})
func (r *AmoRepository) AddAmoAccountUser(ctx context.Context, user model.AmoAccountUser) error {
err := r.queries.AddAmoAccountUser(ctx, sqlcgen.AddAmoAccountUserParams{
Amoid: user.AmoID,
Amouserid: user.AmoUserID,
Name: user.Name,
Email: user.Email,
Role: user.Role,
Group: user.Group,
})
if err != nil { if err != nil {
return err return err
} }
@ -137,39 +155,18 @@ func (r *AmoRepository) CheckMainUser(ctx context.Context, user model.User) erro
return nil return nil
} }
func (r *AmoRepository) CheckAndUpdateUsers(ctx context.Context, users []model.User) error { func (r *AmoRepository) UpdateAmoAccountUser(ctx context.Context, user model.AmoAccountUser) error {
dollar1, err := json.Marshal(users) err := r.queries.UpdateAmoAccountUser(ctx, sqlcgen.UpdateAmoAccountUserParams{
Amoid: user.AmoID,
Amouserid: user.AmoUserID,
Name: user.Name,
Email: user.Email,
Role: user.Role,
Group: user.Group,
})
if err != nil { if err != nil {
return err 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 return nil
} }
@ -195,27 +192,25 @@ func (r *AmoRepository) DeleteUsers(ctx context.Context, ids []int64) error {
return nil return nil
} }
func (r *AmoRepository) GetUserUsersByID(ctx context.Context, amoUserID int32) ([]model.User, error) { func (r *AmoRepository) GetUserUsersByID(ctx context.Context, amoUserID int32) ([]model.AmoAccountUser, error) {
rows, err := r.queries.GetUserUsersByID(ctx, amoUserID) rows, err := r.queries.GetUserUsersByID(ctx, amoUserID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var users []model.User var users []model.AmoAccountUser
for _, row := range rows { for _, row := range rows {
user := model.User{ user := model.AmoAccountUser{
ID: row.ID, ID: row.ID,
Accountid: row.Accountid,
AmoID: row.Amoid, AmoID: row.Amoid,
AmoUserID: row.Amouserid,
Name: row.Name, Name: row.Name,
Email: row.Email, Email: row.Email,
Group: row.Group, Group: row.Group,
Role: row.Role, Role: row.Role,
Subdomain: row.Subdomain, Deleted: row.Deleted,
Amouserid: row.Amouserid, CreatedAt: row.Createdat,
Country: row.Country,
} }
users = append(users, user) users = append(users, user)
} }
@ -256,31 +251,6 @@ func (r *AmoRepository) WebhookUpdate(ctx context.Context, token model.Token) er
return nil 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) { func (r *AmoRepository) GetAllTokens(ctx context.Context) ([]model.Token, error) {
rows, err := r.queries.GetAllTokens(ctx) rows, err := r.queries.GetAllTokens(ctx)
if err != nil { if err != nil {
@ -1038,7 +1008,7 @@ func (r *AmoRepository) GettingAmoUsersTrueResults(ctx context.Context) ([]model
} }
var utm model.UTMSavingMap var utm model.UTMSavingMap
err = json.Unmarshal(row.Utm, &utm) err = json.Unmarshal(row.Utm.([]byte), &utm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1111,3 +1081,60 @@ func (r *AmoRepository) UpdatingDealAmoStatus(ctx context.Context, deps SaveDeal
return nil return nil
} }
// методы для contact в амо
func (r *AmoRepository) GetExistingContactAmo(ctx context.Context, accountID int32, fields []string) (map[int32][]model.ContactAmo, error) {
rows, err := r.queries.GetExistingContactAmo(ctx, sqlcgen.GetExistingContactAmoParams{
Accountid: accountID,
Column2: fields,
})
if err != nil {
if err == sql.ErrNoRows {
return nil, pj_errors.ErrNotFound
}
return nil, err
}
result := make(map[int32][]model.ContactAmo)
for _, row := range rows {
result[row.Amoid] = append(result[row.Amoid], model.ContactAmo{
ID: row.ID,
AmoID: row.Amoid,
AccountID: row.Accountid,
Field: row.Field,
})
}
return result, nil
}
func (r *AmoRepository) InsertContactAmo(ctx context.Context, val model.ContactAmo) (int32, error) {
amoID, err := r.queries.InsertContactAmo(ctx, sqlcgen.InsertContactAmoParams{
Accountid: val.AccountID,
Amoid: val.AmoID,
Field: val.Field,
})
if err != nil {
return 0, err
}
return amoID, err
}
func (r *AmoRepository) UpdateAmoContact(ctx context.Context, id int64, field string, newAmoID int32) error {
err := r.queries.UpdateAmoContact(ctx, sqlcgen.UpdateAmoContactParams{
Field: field,
ID: id,
Amoid: newAmoID,
})
if err != nil {
return err
}
return nil
}

@ -15,16 +15,14 @@ type Deps struct {
} }
type AnswerRepository struct { type AnswerRepository struct {
queries *sqlcgen.Queries queries *sqlcgen.Queries
pool *sql.DB pool *sql.DB
answerMinio *StorerAnswer
} }
func NewAnswerRepository(deps Deps) *AnswerRepository { func NewAnswerRepository(deps Deps) *AnswerRepository {
return &AnswerRepository{ return &AnswerRepository{
queries: deps.Queries, queries: deps.Queries,
pool: deps.Pool, pool: deps.Pool,
answerMinio: deps.AnswerMinio,
} }
} }
@ -111,17 +109,6 @@ func (r *AnswerRepository) GetAllAnswersByQuizID(ctx context.Context, session st
} }
for _, row := range rows { 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)
if err != nil {
fmt.Println("GetAnswerURL dal answer minio answer", err)
return nil, err
}
row.Content = sql.NullString{String: fmt.Sprintf("%s|%s", fileURL, row.Content.String), Valid: true}
}*/
resultAnswer := model.ResultAnswer{ resultAnswer := model.ResultAnswer{
Content: row.Content.String, Content: row.Content.String,
CreatedAt: row.CreatedAt.Time, CreatedAt: row.CreatedAt.Time,

@ -0,0 +1,55 @@
package answer
import (
"context"
"database/sql"
"fmt"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal/sqlcgen"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
)
type WorkerAnswerRepository struct {
queries *sqlcgen.Queries
pool *sql.DB
answerMinio *StorerAnswer
}
func NewWorkerAnswerRepo(deps Deps) *WorkerAnswerRepository {
return &WorkerAnswerRepository{
queries: deps.Queries,
pool: deps.Pool,
answerMinio: deps.AnswerMinio,
}
}
func (r *WorkerAnswerRepository) GetAllAnswersByQuizID(ctx context.Context, session string) ([]model.ResultAnswer, error) {
var results []model.ResultAnswer
rows, err := r.queries.GetAllAnswersByQuizID(ctx, sql.NullString{String: session, Valid: true})
if err != nil {
return nil, err
}
for _, row := range rows {
if row.Questiontype == model.TypeFile && r.answerMinio != nil {
fmt.Println("GALL", row.Qid, row.QuestionID, row.Content)
fileURL, err := r.answerMinio.GetAnswerURL(ctx, row.Qid.UUID.String(), row.QuestionID, row.Content.String)
if err != nil {
fmt.Println("GetAnswerURL dal answer minio answer", err)
return nil, err
}
row.Content = sql.NullString{String: fmt.Sprintf("%s|%s", fileURL, row.Content.String), Valid: true}
}
resultAnswer := model.ResultAnswer{
Content: row.Content.String,
CreatedAt: row.CreatedAt.Time,
QuestionID: uint64(row.QuestionID),
AnswerID: uint64(row.ID),
}
results = append(results, resultAnswer)
}
return results, nil
}

@ -0,0 +1,199 @@
package statistics
import (
"context"
"database/sql"
"fmt"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/utils"
"sort"
"strings"
)
type DepsClick struct {
Conn *sql.DB
}
type StatisticClick struct {
conn *sql.DB
}
func NewClickStatistic(ctx context.Context, deps DepsClick) (*StatisticClick, error) {
s := &StatisticClick{
conn: deps.Conn,
}
err := s.checkMW(ctx)
if err != nil {
fmt.Println("error check material view existing", err)
return nil, err
}
return s, nil
}
func (s *StatisticClick) checkMW(ctx context.Context) error {
query := `
CREATE MATERIALIZED VIEW IF NOT EXISTS mv_last_answers_events
ENGINE = MergeTree()
ORDER BY (ctxsession, event_time) POPULATE AS
SELECT
event_time, ctxsession, ctxquizid, ctxquestionid, ctxidint, message,ctxquiz
FROM statistics
WHERE message IN ('InfoQuizOpen', 'InfoAnswer', 'InfoResult') AND event_level = 'info';
`
_, err := s.conn.ExecContext(ctx, query)
if err != nil {
return err
}
return nil
}
type Statistic struct {
Count int64
QuestionID int64
}
type PipeLineStatsResp map[int64][]Statistic
// пример:
//"[0, 116783, 116810]"
//"[0, 116783, 116798]"
//"[0, 116783, 116798, 116831]"
//"[0, 116783, 116810, 116849]"
//[0]
//"[0, 116783]"
//"[0, 116783, 116810, 116843]"
//SELECT DISTINCT last_que, reversed
//FROM ( SELECT groupArray(ctxquestionid) AS reversed, arraySlice(arrayReverse(groupArray(ctxquestionid)), 1, 1)[1] AS last_que
//FROM statistics WHERE ctxquizid = 26276 GROUP BY ctxsession ) AS sub;
func (s *StatisticClick) getFunnel(ctx context.Context, quizID int64, from uint64, to uint64) (map[int64][]int64, error) {
query := `
SELECT DISTINCT last_que, reversed
FROM ( SELECT groupUniqArray(ctxquestionid) AS reversed, arraySlice(arrayReverse(groupArray(ctxquestionid)), 1, 1)[1] AS last_que
FROM mv_last_answers_events WHERE ctxquizid = ? AND event_time BETWEEN ? AND ? GROUP BY ctxsession ) AS sub;
`
rows, err := s.conn.QueryContext(ctx, query, quizID, from, to)
if err != nil {
return nil, err
}
defer rows.Close()
funnel := make(map[int64][]int64)
for rows.Next() {
var lastQue int64
var reversed []int64
if err := rows.Scan(&lastQue, &reversed); err != nil {
return nil, err
}
funnel[lastQue] = reversed
}
if err := rows.Err(); err != nil {
return nil, err
}
result := make(map[int64][]int64)
keys := make([]int64, 0, len(funnel))
for key := range funnel {
keys = append(keys, key)
}
sort.Slice(keys, func(i, j int) bool {
return keys[i] < keys[j]
})
for _, lastQue := range keys {
reversed := funnel[lastQue]
found := false
for _, otherLastQue := range keys {
if otherLastQue != lastQue {
otherReversed := funnel[otherLastQue]
sort.Slice(otherReversed, func(i, j int) bool {
return otherReversed[i] < otherReversed[j]
})
index := utils.BinarySearch(lastQue, otherReversed)
if index {
found = true
break
}
}
}
if !found {
result[lastQue] = reversed
}
}
return result, nil
}
func (s *StatisticClick) GetPipelinesStatistics(ctx context.Context, quizID int64, from uint64, to uint64) (PipeLineStatsResp, error) {
pipelines := make(PipeLineStatsResp)
funnel, err := s.getFunnel(ctx, quizID, from, to)
if err != nil {
return nil, err
}
for lastQue, idS := range funnel {
sesCount, err := s.countSession(ctx, quizID, from, to, idS)
if err != nil {
return nil, err
}
for _, queID := range idS {
if sessionCount, ok := sesCount[queID]; ok {
pipeline := Statistic{
QuestionID: queID,
Count: sessionCount,
}
pipelines[lastQue] = append(pipelines[lastQue], pipeline)
}
}
}
return pipelines, nil
}
func (s *StatisticClick) countSession(ctx context.Context, quizID int64, from uint64, to uint64, questionIDs []int64) (map[int64]int64, error) {
placeholders := make([]string, len(questionIDs))
args := make([]interface{}, len(questionIDs)+3)
args[0] = quizID
for i, id := range questionIDs {
placeholders[i] = "?"
args[i+1] = id
}
args[len(args)-2] = from
args[len(args)-1] = to
query := fmt.Sprintf(`
SELECT ctxquestionid, COUNT(DISTINCT ctxsession) AS session_count
FROM statistics
WHERE ctxquizid = ? AND ctxquestionid IN (%s) AND event_time BETWEEN ? AND ?
GROUP BY ctxquestionid;
`, strings.Join(placeholders, ","))
rows, err := s.conn.QueryContext(ctx, query, args...)
if err != nil {
return nil, err
}
defer rows.Close()
counts := make(map[int64]int64)
for rows.Next() {
var questionID int64
var count int64
err := rows.Scan(&questionID, &count)
if err != nil {
return nil, err
}
counts[questionID] = count
}
if err := rows.Err(); err != nil {
return nil, err
}
return counts, nil
}

@ -30,6 +30,10 @@ packages:
- "./dal/schema/000012_init.down.sql" - "./dal/schema/000012_init.down.sql"
- "./dal/schema/000013_init.up.sql" - "./dal/schema/000013_init.up.sql"
- "./dal/schema/000013_init.down.sql" - "./dal/schema/000013_init.down.sql"
- "./dal/schema/000014_init.up.sql"
- "./dal/schema/000014_init.down.sql"
- "./dal/schema/000016_init.up.sql"
- "./dal/schema/000016_init.down.sql"
- "./dal/schema/000017_init.up.sql" - "./dal/schema/000017_init.up.sql"
- "./dal/schema/000017_init.down.sql" - "./dal/schema/000017_init.down.sql"
engine: "postgresql" engine: "postgresql"

20
utils/binary_search.go Normal file

@ -0,0 +1,20 @@
package utils
func BinarySearch(target int64, array []int64) bool {
left := 0
right := len(array) - 1
for left <= right {
mid := (left + right) / 2
if array[mid] == target {
return true
} else if array[mid] < target {
left = mid + 1
} else if array[mid] > target {
right = mid - 1
}
}
return false
}