Fix channel/author subscription confirmation and follow trigger persistence
This commit is contained in:
parent
7bdb3118ae
commit
e17a6765ec
@ -111,18 +111,23 @@ async function resolveChannelTargetFromInput(rawInput) {
|
||||
}
|
||||
|
||||
const ownerFeed = await authService.listSubscriptionsFeed(ownerLogin, 500);
|
||||
const ownChannels = (ownerFeed?.ownedChannels || []).filter((item) => (
|
||||
String(item?.channel?.ownerBlockchainName || '') === String(user.blockchainName)
|
||||
));
|
||||
|
||||
const match = ownChannels.find((item) => (
|
||||
const ownChannels = Array.isArray(ownerFeed?.ownedChannels) ? ownerFeed.ownedChannels : [];
|
||||
const matches = ownChannels.filter((item) => (
|
||||
String(item?.channel?.channelName || '').trim().toLowerCase() === channelName
|
||||
));
|
||||
|
||||
if (!match) {
|
||||
if (!matches.length) {
|
||||
throw new Error('Канал не найден у указанного автора.');
|
||||
}
|
||||
|
||||
const primaryMatches = matches.filter((item) => (
|
||||
String(item?.channel?.ownerBlockchainName || '') === String(user.blockchainName || '')
|
||||
));
|
||||
const pool = primaryMatches.length ? primaryMatches : matches;
|
||||
const match = [...pool].sort((a, b) => (
|
||||
Number(b?.channel?.channelRoot?.blockNumber || -1) - Number(a?.channel?.channelRoot?.blockNumber || -1)
|
||||
))[0];
|
||||
|
||||
return {
|
||||
ownerBlockchainName: String(match?.channel?.ownerBlockchainName || user.blockchainName),
|
||||
rootBlockNumber: Number(match?.channel?.channelRoot?.blockNumber),
|
||||
@ -195,6 +200,36 @@ function renderSuggestions(container, values, onPick) {
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeComparableLogin(value) {
|
||||
return normalizeLoginInput(value).toLowerCase();
|
||||
}
|
||||
|
||||
function isFollowedUserVisible(targetLogin) {
|
||||
const expected = normalizeComparableLogin(targetLogin);
|
||||
if (!expected) return false;
|
||||
const rows = Array.isArray(state.channelsFeed?.followedUsersChannels)
|
||||
? state.channelsFeed.followedUsersChannels
|
||||
: [];
|
||||
return rows.some((row) => normalizeComparableLogin(row?.channel?.ownerLogin) === expected);
|
||||
}
|
||||
|
||||
function isFollowedChannelVisible(target) {
|
||||
const rows = Array.isArray(state.channelsFeed?.followedChannels)
|
||||
? state.channelsFeed.followedChannels
|
||||
: [];
|
||||
const expectedBch = String(target?.ownerBlockchainName || '');
|
||||
const expectedNo = Number(target?.rootBlockNumber);
|
||||
const expectedHash = normalizeHash(target?.rootBlockHash);
|
||||
if (!expectedBch || !Number.isFinite(expectedNo)) return false;
|
||||
|
||||
return rows.some((row) => {
|
||||
const rowBch = String(row?.channel?.ownerBlockchainName || '');
|
||||
const rowNo = Number(row?.channel?.channelRoot?.blockNumber);
|
||||
const rowHash = normalizeHash(row?.channel?.channelRoot?.blockHash);
|
||||
return rowBch === expectedBch && rowNo === expectedNo && rowHash === expectedHash;
|
||||
});
|
||||
}
|
||||
|
||||
function openSimpleSubscribeModal({ kind, kindLabel, submitLabel, unfollow = false, onSuccess }) {
|
||||
const targetHint = kind === 'channel'
|
||||
? '<p class="meta-muted">Канал: user/channel, имя канала или bch:number:hash.</p>'
|
||||
@ -306,35 +341,62 @@ function openSimpleSubscribeModal({ kind, kindLabel, submitLabel, unfollow = fal
|
||||
errorEl.textContent = '';
|
||||
|
||||
try {
|
||||
let channelTarget = null;
|
||||
let userTargetLogin = '';
|
||||
|
||||
if (kind === 'user') {
|
||||
userTargetLogin = normalizeLoginInput(value);
|
||||
await authService.addBlockFollowUser({
|
||||
login,
|
||||
targetLogin: normalizeLoginInput(value),
|
||||
targetLogin: userTargetLogin,
|
||||
storagePwd,
|
||||
unfollow,
|
||||
});
|
||||
} else if (kind === 'channel') {
|
||||
const target = await resolveChannelTargetFromInput(value);
|
||||
if (!target?.ownerBlockchainName || !Number.isFinite(target.rootBlockNumber)) {
|
||||
channelTarget = await resolveChannelTargetFromInput(value);
|
||||
if (!channelTarget?.ownerBlockchainName || !Number.isFinite(channelTarget.rootBlockNumber)) {
|
||||
throw new Error('Канал не найден.');
|
||||
}
|
||||
|
||||
await authService.addBlockFollowChannel({
|
||||
login,
|
||||
storagePwd,
|
||||
targetBlockchainName: target.ownerBlockchainName,
|
||||
targetBlockNumber: target.rootBlockNumber,
|
||||
targetBlockHashHex: target.rootBlockHash,
|
||||
targetBlockchainName: channelTarget.ownerBlockchainName,
|
||||
targetBlockNumber: channelTarget.rootBlockNumber,
|
||||
targetBlockHashHex: channelTarget.rootBlockHash,
|
||||
unfollow,
|
||||
});
|
||||
} else {
|
||||
throw new Error('Неподдерживаемый тип подписки');
|
||||
}
|
||||
|
||||
if (typeof onSuccess === 'function') {
|
||||
await onSuccess();
|
||||
}
|
||||
|
||||
if (kind === 'user') {
|
||||
const visible = isFollowedUserVisible(userTargetLogin);
|
||||
if (!unfollow && !visible) {
|
||||
throw new Error('Подписка не подтвердилась после обновления списка.');
|
||||
}
|
||||
if (unfollow && visible) {
|
||||
throw new Error('Отписка не подтвердилась после обновления списка.');
|
||||
}
|
||||
}
|
||||
|
||||
if (kind === 'channel') {
|
||||
const visible = isFollowedChannelVisible(channelTarget);
|
||||
if (!unfollow && !visible) {
|
||||
throw new Error('Подписка на канал не подтвердилась после обновления списка.');
|
||||
}
|
||||
if (unfollow && visible) {
|
||||
throw new Error('Отписка от канала не подтвердилась после обновления списка.');
|
||||
}
|
||||
}
|
||||
|
||||
softHaptic(15);
|
||||
showToast(unfollow ? 'Отписка выполнена' : 'Подписка выполнена');
|
||||
close();
|
||||
if (typeof onSuccess === 'function') onSuccess();
|
||||
} catch (error) {
|
||||
errorEl.textContent = toUserMessage(error, `${submitText} не удалось.`);
|
||||
setBusy(false);
|
||||
|
||||
@ -212,12 +212,30 @@ public final class DatabaseTriggersInstaller {
|
||||
SELECT
|
||||
NEW.login,
|
||||
NEW.msg_sub_type,
|
||||
COALESCE(
|
||||
NEW.to_login,
|
||||
CASE
|
||||
WHEN NEW.to_bch_name IS NOT NULL
|
||||
AND length(NEW.to_bch_name) > 4
|
||||
AND substr(NEW.to_bch_name, length(NEW.to_bch_name) - 3, 1) = '-'
|
||||
THEN substr(NEW.to_bch_name, 1, length(NEW.to_bch_name) - 4)
|
||||
ELSE NULL
|
||||
END
|
||||
),
|
||||
NEW.to_bch_name,
|
||||
NEW.to_block_number,
|
||||
NEW.to_block_hash
|
||||
WHERE NEW.msg_sub_type IN (%d, %d, %d)
|
||||
AND NEW.to_login IS NOT NULL
|
||||
AND COALESCE(
|
||||
NEW.to_login,
|
||||
CASE
|
||||
WHEN NEW.to_bch_name IS NOT NULL
|
||||
AND length(NEW.to_bch_name) > 4
|
||||
AND substr(NEW.to_bch_name, length(NEW.to_bch_name) - 3, 1) = '-'
|
||||
THEN substr(NEW.to_bch_name, 1, length(NEW.to_bch_name) - 4)
|
||||
ELSE NULL
|
||||
END
|
||||
) IS NOT NULL
|
||||
AND NEW.to_bch_name IS NOT NULL;
|
||||
|
||||
-- 2) если запись есть — обновляем актуальные to_*
|
||||
@ -228,27 +246,64 @@ public final class DatabaseTriggersInstaller {
|
||||
to_block_hash = NEW.to_block_hash
|
||||
WHERE login = NEW.login
|
||||
AND rel_type = NEW.msg_sub_type
|
||||
AND to_login = NEW.to_login
|
||||
AND NEW.msg_sub_type IN (%d, %d, %d)
|
||||
AND NEW.to_login IS NOT NULL
|
||||
AND to_login = COALESCE(
|
||||
NEW.to_login,
|
||||
CASE
|
||||
WHEN NEW.to_bch_name IS NOT NULL
|
||||
AND length(NEW.to_bch_name) > 4
|
||||
AND substr(NEW.to_bch_name, length(NEW.to_bch_name) - 3, 1) = '-'
|
||||
THEN substr(NEW.to_bch_name, 1, length(NEW.to_bch_name) - 4)
|
||||
ELSE NULL
|
||||
END
|
||||
)
|
||||
AND NEW.msg_sub_type IN (%d, %d)
|
||||
AND COALESCE(
|
||||
NEW.to_login,
|
||||
CASE
|
||||
WHEN NEW.to_bch_name IS NOT NULL
|
||||
AND length(NEW.to_bch_name) > 4
|
||||
AND substr(NEW.to_bch_name, length(NEW.to_bch_name) - 3, 1) = '-'
|
||||
THEN substr(NEW.to_bch_name, 1, length(NEW.to_bch_name) - 4)
|
||||
ELSE NULL
|
||||
END
|
||||
) IS NOT NULL
|
||||
AND NEW.to_bch_name IS NOT NULL;
|
||||
|
||||
-- UNFRIEND/UNCONTACT/UNFOLLOW:
|
||||
-- удаляем соответствующее "позитивное" состояние
|
||||
DELETE FROM connections_state
|
||||
WHERE login = NEW.login
|
||||
AND to_login = NEW.to_login
|
||||
AND to_login = COALESCE(
|
||||
NEW.to_login,
|
||||
CASE
|
||||
WHEN NEW.to_bch_name IS NOT NULL
|
||||
AND length(NEW.to_bch_name) > 4
|
||||
AND substr(NEW.to_bch_name, length(NEW.to_bch_name) - 3, 1) = '-'
|
||||
THEN substr(NEW.to_bch_name, 1, length(NEW.to_bch_name) - 4)
|
||||
ELSE NULL
|
||||
END
|
||||
)
|
||||
AND rel_type = CASE NEW.msg_sub_type
|
||||
WHEN %d THEN %d
|
||||
WHEN %d THEN %d
|
||||
WHEN %d THEN %d
|
||||
ELSE rel_type
|
||||
END
|
||||
AND COALESCE(
|
||||
NEW.to_login,
|
||||
CASE
|
||||
WHEN NEW.to_bch_name IS NOT NULL
|
||||
AND length(NEW.to_bch_name) > 4
|
||||
AND substr(NEW.to_bch_name, length(NEW.to_bch_name) - 3, 1) = '-'
|
||||
THEN substr(NEW.to_bch_name, 1, length(NEW.to_bch_name) - 4)
|
||||
ELSE NULL
|
||||
END
|
||||
) IS NOT NULL
|
||||
AND NEW.msg_sub_type IN (%d, %d, %d);
|
||||
END;
|
||||
""".formatted(
|
||||
FRIEND, CONTACT, FOLLOW,
|
||||
FRIEND, CONTACT, FOLLOW,
|
||||
FRIEND, CONTACT,
|
||||
|
||||
UNFRIEND, FRIEND,
|
||||
UNCONTACT, CONTACT,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user