mirror of
https://github.com/abhinavxd/libredesk.git
synced 2026-09-22 18:43:33 +00:00
29881f2f82
Reject disabled agents in FilterAuthorizedListUUIDs, kick role members on permission removal or role delete, and re-sub the list and open conv on ws reconnect using local state. Also plug the app logger into the ws package so kicks no longer log when no connections exist.
423 lines
12 KiB
SQL
423 lines
12 KiB
SQL
-- name: get-users-compact
|
|
SELECT COUNT(*) OVER() as total, users.id, users.avatar_url, users.type, users.created_at, users.updated_at, users.first_name, users.last_name, users.email, users.enabled, users.external_user_id, users.availability_status
|
|
FROM users
|
|
WHERE users.email != 'System' AND users.deleted_at IS NULL AND type = ANY($1)
|
|
|
|
-- name: soft-delete-agent
|
|
WITH soft_delete AS (
|
|
UPDATE users
|
|
SET deleted_at = now(), updated_at = now()
|
|
WHERE id = $1 AND type = 'agent'
|
|
RETURNING id
|
|
),
|
|
-- Delete from user_roles and teams
|
|
delete_team_members AS (
|
|
DELETE FROM team_members
|
|
WHERE user_id IN (SELECT id FROM soft_delete)
|
|
RETURNING 1
|
|
),
|
|
delete_user_roles AS (
|
|
DELETE FROM user_roles
|
|
WHERE user_id IN (SELECT id FROM soft_delete)
|
|
RETURNING 1
|
|
)
|
|
SELECT 1;
|
|
|
|
-- name: get-user
|
|
SELECT
|
|
u.id,
|
|
u.created_at,
|
|
u.updated_at,
|
|
u.email,
|
|
u.password,
|
|
u.type,
|
|
u.enabled,
|
|
u.avatar_url,
|
|
u.first_name,
|
|
u.last_name,
|
|
u.availability_status,
|
|
u.last_active_at,
|
|
u.last_login_at,
|
|
u.phone_number_country_code,
|
|
u.phone_number,
|
|
u.country,
|
|
u.api_key,
|
|
u.api_key_last_used_at,
|
|
u.external_user_id,
|
|
u.api_secret,
|
|
array_agg(DISTINCT r.name) FILTER (WHERE r.name IS NOT NULL) AS roles,
|
|
COALESCE(
|
|
(SELECT json_agg(json_build_object('id', t.id, 'name', t.name, 'emoji', t.emoji))
|
|
FROM team_members tm
|
|
JOIN teams t ON tm.team_id = t.id
|
|
WHERE tm.user_id = u.id),
|
|
'[]'
|
|
) AS teams,
|
|
array_agg(DISTINCT p ORDER BY p) FILTER (WHERE p IS NOT NULL) AS permissions
|
|
FROM users u
|
|
LEFT JOIN user_roles ur ON ur.user_id = u.id
|
|
LEFT JOIN roles r ON r.id = ur.role_id
|
|
LEFT JOIN LATERAL unnest(r.permissions) AS p ON true
|
|
WHERE u.deleted_at IS NULL
|
|
AND ($1 = 0 OR u.id = $1)
|
|
AND ($2 = '' OR u.email = $2)
|
|
AND (cardinality($3::text[]) = 0 OR u.type::text = ANY($3::text[]))
|
|
GROUP BY u.id
|
|
ORDER BY u.id ASC
|
|
LIMIT 1;
|
|
|
|
-- name: set-user-password
|
|
UPDATE users
|
|
SET password = $1, updated_at = now()
|
|
WHERE id = $2;
|
|
|
|
-- name: update-agent
|
|
WITH not_removed_roles AS (
|
|
SELECT r.id FROM unnest($5::text[]) role_name
|
|
JOIN roles r ON r.name = role_name
|
|
),
|
|
old_roles AS (
|
|
DELETE FROM user_roles
|
|
WHERE user_id = $1
|
|
AND role_id NOT IN (SELECT id FROM not_removed_roles)
|
|
),
|
|
new_roles AS (
|
|
INSERT INTO user_roles (user_id, role_id)
|
|
SELECT $1, r.id FROM not_removed_roles r
|
|
ON CONFLICT (user_id, role_id) DO NOTHING
|
|
)
|
|
UPDATE users
|
|
SET first_name = COALESCE($2, first_name),
|
|
last_name = COALESCE($3, last_name),
|
|
email = COALESCE($4, email),
|
|
avatar_url = COALESCE($6, avatar_url),
|
|
password = COALESCE($7, password),
|
|
enabled = COALESCE($8, enabled),
|
|
availability_status = COALESCE($9, availability_status),
|
|
updated_at = now()
|
|
WHERE id = $1;
|
|
|
|
-- name: update-custom-attributes
|
|
UPDATE users
|
|
SET custom_attributes = $2,
|
|
updated_at = now()
|
|
WHERE id = $1;
|
|
|
|
-- name: upsert-custom-attributes
|
|
UPDATE users
|
|
SET custom_attributes = COALESCE(custom_attributes, '{}'::jsonb) || $2,
|
|
updated_at = now()
|
|
WHERE id = $1;
|
|
|
|
-- name: update-avatar
|
|
UPDATE users
|
|
SET avatar_url = $2, updated_at = now()
|
|
WHERE id = $1;
|
|
|
|
-- name: update-availability
|
|
UPDATE users
|
|
SET availability_status = $2
|
|
WHERE id = $1;
|
|
|
|
-- name: update-last-active-at
|
|
WITH prev AS (
|
|
SELECT availability_status AS old_status FROM users WHERE id = $1
|
|
)
|
|
UPDATE users
|
|
SET last_active_at = now(),
|
|
availability_status = CASE WHEN availability_status = 'offline' THEN 'online' ELSE availability_status END
|
|
FROM prev
|
|
WHERE users.id = $1
|
|
RETURNING (prev.old_status = 'offline')::boolean AS was_offline;
|
|
|
|
-- name: update-inactive-offline
|
|
UPDATE users
|
|
SET availability_status = 'offline'
|
|
WHERE
|
|
type IN ('agent', 'contact', 'visitor')
|
|
AND (last_active_at IS NULL OR last_active_at < NOW() - INTERVAL '5 minutes')
|
|
AND availability_status NOT IN ('offline', 'away_and_reassigning', 'away_manual')
|
|
RETURNING id, type;
|
|
|
|
-- name: get-availability-status
|
|
SELECT availability_status FROM users WHERE id = $1;
|
|
|
|
-- name: set-reset-password-token
|
|
UPDATE users
|
|
SET reset_password_token = $2, reset_password_token_expiry = now() + interval '1 day'
|
|
WHERE id = $1 AND type = 'agent';
|
|
|
|
-- name: set-password
|
|
UPDATE users
|
|
SET password = $1, reset_password_token = NULL, reset_password_token_expiry = NULL
|
|
WHERE reset_password_token = $2 AND reset_password_token_expiry > now()
|
|
RETURNING id;
|
|
|
|
-- name: insert-agent
|
|
WITH inserted_user AS (
|
|
INSERT INTO users (email, type, first_name, last_name, "password", avatar_url)
|
|
VALUES ($1, 'agent', $2, $3, $4, $5)
|
|
RETURNING id AS user_id
|
|
)
|
|
INSERT INTO user_roles (user_id, role_id)
|
|
SELECT inserted_user.user_id, r.id
|
|
FROM inserted_user, unnest($6::text[]) role_name
|
|
JOIN roles r ON r.name = role_name
|
|
RETURNING user_id;
|
|
|
|
-- name: insert-contact-with-external-id
|
|
INSERT INTO users (email, type, first_name, last_name, "password", avatar_url, external_user_id, custom_attributes)
|
|
VALUES ($1, 'contact', $2, $3, $4, $5, $6, $7)
|
|
ON CONFLICT (external_user_id) WHERE type = 'contact' AND deleted_at IS NULL AND external_user_id IS NOT NULL
|
|
DO UPDATE SET email = EXCLUDED.email, first_name = EXCLUDED.first_name, last_name = EXCLUDED.last_name, updated_at = now()
|
|
RETURNING id;
|
|
|
|
-- name: insert-contact-without-external-id
|
|
INSERT INTO users (email, type, first_name, last_name, "password", avatar_url, external_user_id)
|
|
VALUES ($1, 'contact', $2, $3, $4, $5, NULL)
|
|
ON CONFLICT (email) WHERE type = 'contact' AND deleted_at IS NULL AND external_user_id IS NULL
|
|
DO UPDATE SET updated_at = now()
|
|
RETURNING id;
|
|
|
|
-- name: get-contact-by-email
|
|
SELECT id, external_user_id FROM users
|
|
WHERE email = $1 AND type = 'contact' AND deleted_at IS NULL
|
|
ORDER BY (external_user_id IS NOT NULL) DESC, id ASC LIMIT 1;
|
|
|
|
-- name: get-contact-by-email-without-ext-id
|
|
SELECT id FROM users
|
|
WHERE email = $1 AND type = 'contact' AND deleted_at IS NULL AND external_user_id IS NULL
|
|
LIMIT 1;
|
|
|
|
-- name: is-email-blocked
|
|
SELECT EXISTS(
|
|
SELECT 1 FROM users
|
|
WHERE email = $1 AND type IN ('contact', 'visitor') AND deleted_at IS NULL AND enabled = false
|
|
) AS is_blocked;
|
|
|
|
-- name: set-external-user-id
|
|
UPDATE users SET external_user_id = $2, updated_at = now()
|
|
WHERE id = $1 AND type = 'contact' AND deleted_at IS NULL;
|
|
|
|
-- name: insert-visitor
|
|
INSERT INTO users (email, type, first_name, last_name, custom_attributes)
|
|
VALUES ($1, 'visitor', $2, $3, $4)
|
|
RETURNING *;
|
|
|
|
-- name: update-last-login-at
|
|
UPDATE users
|
|
SET last_login_at = now(),
|
|
updated_at = now()
|
|
WHERE id = $1;
|
|
|
|
-- name: toggle-enable
|
|
UPDATE users
|
|
SET enabled = $3, updated_at = NOW()
|
|
WHERE id = $1 AND type = $2;
|
|
|
|
-- name: update-contact
|
|
UPDATE users
|
|
SET first_name = COALESCE($2, first_name),
|
|
last_name = COALESCE($3, last_name),
|
|
email = COALESCE($4, email),
|
|
avatar_url = $5,
|
|
phone_number = $6,
|
|
phone_number_country_code = $7,
|
|
country = $8,
|
|
updated_at = now()
|
|
WHERE id = $1 and type in ('contact', 'visitor');
|
|
|
|
-- name: update-contact-basic-info
|
|
UPDATE users
|
|
SET first_name = COALESCE(NULLIF($2, ''), first_name),
|
|
last_name = COALESCE(NULLIF($3, ''), last_name),
|
|
email = COALESCE(NULLIF($4, ''), email),
|
|
updated_at = now()
|
|
WHERE id = $1 AND type IN ('contact', 'visitor');
|
|
|
|
-- name: get-notes
|
|
SELECT
|
|
cn.id,
|
|
cn.created_at,
|
|
cn.updated_at,
|
|
cn.contact_id,
|
|
cn.note,
|
|
cn.user_id,
|
|
u.first_name,
|
|
u.last_name,
|
|
u.avatar_url
|
|
FROM contact_notes cn
|
|
INNER JOIN users u ON u.id = cn.user_id
|
|
WHERE cn.contact_id = $1
|
|
ORDER BY cn.created_at DESC;
|
|
|
|
-- name: insert-note
|
|
INSERT INTO contact_notes (contact_id, user_id, note)
|
|
VALUES ($1, $2, $3)
|
|
RETURNING *;
|
|
|
|
-- name: delete-note
|
|
DELETE FROM contact_notes
|
|
WHERE id = $1 AND contact_id = $2;
|
|
|
|
-- name: get-note
|
|
SELECT
|
|
cn.id,
|
|
cn.created_at,
|
|
cn.updated_at,
|
|
cn.contact_id,
|
|
cn.note,
|
|
cn.user_id,
|
|
u.first_name,
|
|
u.last_name,
|
|
u.avatar_url
|
|
FROM contact_notes cn
|
|
INNER JOIN users u ON u.id = cn.user_id
|
|
WHERE cn.id = $1;
|
|
|
|
-- name: get-user-by-api-key
|
|
SELECT
|
|
u.id,
|
|
u.created_at,
|
|
u.updated_at,
|
|
u.email,
|
|
u.password,
|
|
u.type,
|
|
u.enabled,
|
|
u.avatar_url,
|
|
u.first_name,
|
|
u.last_name,
|
|
u.availability_status,
|
|
u.last_active_at,
|
|
u.last_login_at,
|
|
u.phone_number_country_code,
|
|
u.phone_number,
|
|
u.country,
|
|
u.api_key,
|
|
u.api_key_last_used_at,
|
|
u.api_secret,
|
|
u.external_user_id,
|
|
array_agg(DISTINCT r.name) FILTER (WHERE r.name IS NOT NULL) AS roles,
|
|
COALESCE(
|
|
(SELECT json_agg(json_build_object('id', t.id, 'name', t.name, 'emoji', t.emoji))
|
|
FROM team_members tm
|
|
JOIN teams t ON tm.team_id = t.id
|
|
WHERE tm.user_id = u.id),
|
|
'[]'
|
|
) AS teams,
|
|
array_agg(DISTINCT p ORDER BY p) FILTER (WHERE p IS NOT NULL) AS permissions
|
|
FROM users u
|
|
LEFT JOIN user_roles ur ON ur.user_id = u.id
|
|
LEFT JOIN roles r ON r.id = ur.role_id
|
|
LEFT JOIN LATERAL unnest(r.permissions) AS p ON true
|
|
WHERE u.api_key = $1 AND u.enabled = true AND u.deleted_at IS NULL
|
|
GROUP BY u.id;
|
|
|
|
-- name: set-api-key
|
|
UPDATE users
|
|
SET api_key = $2, api_secret = $3, api_key_last_used_at = NULL, updated_at = now()
|
|
WHERE id = $1;
|
|
|
|
-- name: revoke-api-key
|
|
UPDATE users
|
|
SET api_key = NULL, api_secret = NULL, api_key_last_used_at = NULL, updated_at = now()
|
|
WHERE id = $1;
|
|
|
|
-- name: update-api-key-last-used
|
|
UPDATE users
|
|
SET api_key_last_used_at = now()
|
|
WHERE id = $1;
|
|
|
|
-- name: get-user-by-external-id
|
|
SELECT
|
|
u.id,
|
|
u.created_at,
|
|
u.updated_at,
|
|
u.email,
|
|
u.password,
|
|
u.type,
|
|
u.enabled,
|
|
u.avatar_url,
|
|
u.first_name,
|
|
u.last_name,
|
|
u.availability_status,
|
|
u.last_active_at,
|
|
u.last_login_at,
|
|
u.phone_number_country_code,
|
|
u.phone_number,
|
|
u.country,
|
|
u.external_user_id,
|
|
u.custom_attributes,
|
|
u.api_key,
|
|
u.api_key_last_used_at,
|
|
array_agg(DISTINCT r.name) FILTER (WHERE r.name IS NOT NULL) AS roles,
|
|
COALESCE(
|
|
(SELECT json_agg(json_build_object('id', t.id, 'name', t.name, 'emoji', t.emoji))
|
|
FROM team_members tm
|
|
JOIN teams t ON tm.team_id = t.id
|
|
WHERE tm.user_id = u.id),
|
|
'[]'
|
|
) AS teams,
|
|
array_agg(DISTINCT p ORDER BY p) FILTER (WHERE p IS NOT NULL) AS permissions
|
|
FROM users u
|
|
LEFT JOIN user_roles ur ON ur.user_id = u.id
|
|
LEFT JOIN roles r ON r.id = ur.role_id
|
|
LEFT JOIN LATERAL unnest(r.permissions) AS p ON true
|
|
WHERE u.deleted_at IS NULL
|
|
AND u.external_user_id = $1
|
|
GROUP BY u.id;
|
|
|
|
-- name: get-visitor-by-email
|
|
SELECT id, email, external_user_id FROM users
|
|
WHERE email = $1 AND type = 'visitor' AND deleted_at IS NULL
|
|
LIMIT 1;
|
|
|
|
-- name: upgrade-visitor-to-contact
|
|
UPDATE users SET type = 'contact', updated_at = now()
|
|
WHERE id = $1 AND type = 'visitor';
|
|
|
|
-- name: merge-visitor-to-contact
|
|
WITH transfer_conversations AS (
|
|
UPDATE conversations
|
|
SET contact_id = $2, updated_at = now()
|
|
WHERE contact_id = $1
|
|
RETURNING id
|
|
),
|
|
transfer_messages AS (
|
|
UPDATE conversation_messages
|
|
SET sender_id = $2
|
|
WHERE conversation_id IN (SELECT id FROM transfer_conversations) AND sender_id = $1
|
|
RETURNING id
|
|
),
|
|
transfer_participants AS (
|
|
UPDATE conversation_participants
|
|
SET user_id = $2
|
|
WHERE user_id = $1 AND NOT EXISTS (
|
|
SELECT 1 FROM conversation_participants WHERE user_id = $2 AND conversation_id = conversation_participants.conversation_id
|
|
)
|
|
RETURNING id
|
|
),
|
|
delete_remaining_participants AS (
|
|
DELETE FROM conversation_participants
|
|
WHERE user_id = $1
|
|
RETURNING id
|
|
),
|
|
transfer_notes AS (
|
|
UPDATE contact_notes
|
|
SET contact_id = $2
|
|
WHERE contact_id = $1
|
|
RETURNING id
|
|
),
|
|
delete_visitor AS (
|
|
DELETE FROM users
|
|
WHERE id = $1 AND type = 'visitor'
|
|
RETURNING id
|
|
)
|
|
SELECT
|
|
(SELECT COUNT(*) FROM transfer_conversations) as conversations_transferred,
|
|
(SELECT COUNT(*) FROM transfer_messages) as messages_transferred,
|
|
(SELECT COUNT(*) FROM delete_visitor) as visitor_deleted;
|
|
|
|
-- name: get-user-ids-by-role
|
|
SELECT user_id FROM user_roles WHERE role_id = $1;
|