diff --git a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/channels/Net_GetMessageThread_Handler.java b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/channels/Net_GetMessageThread_Handler.java index fe10d183..d86af517 100644 --- a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/channels/Net_GetMessageThread_Handler.java +++ b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/channels/Net_GetMessageThread_Handler.java @@ -214,8 +214,12 @@ public class Net_GetMessageThread_Handler implements JsonMessageHandler { first.setCreatedAtMs(base.createdAtMs); versions.add(first); - if (row.msgSubType == MsgSubType.TEXT_REPLY || ChannelsReadSupport.supportsEditPostVersions(row.msgSubType)) { - short editType = row.msgSubType == MsgSubType.TEXT_REPLY ? MsgSubType.TEXT_EDIT_REPLY : MsgSubType.TEXT_EDIT_POST; + if (row.msgSubType == MsgSubType.TEXT_REPLY + || row.msgSubType == MsgSubType.TEXT_RATING + || ChannelsReadSupport.supportsEditPostVersions(row.msgSubType)) { + short editType = (row.msgSubType == MsgSubType.TEXT_REPLY || row.msgSubType == MsgSubType.TEXT_RATING) + ? MsgSubType.TEXT_EDIT_REPLY + : MsgSubType.TEXT_EDIT_POST; for (PostRow edit : findEdits(c, row.bchName, row.blockNumber, row.blockHash, editType)) { ChannelsReadSupport.TextInfo et = ChannelsReadSupport.parseTextAndTime(edit.blockBytes); Net_GetChannelMessages_Response.VersionItem v = new Net_GetChannelMessages_Response.VersionItem(); diff --git a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/channels/Net_GetPersonalDiary_Handler.java b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/channels/Net_GetPersonalDiary_Handler.java index 0f9fc5cd..2b2d6021 100644 --- a/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/channels/Net_GetPersonalDiary_Handler.java +++ b/SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/channels/Net_GetPersonalDiary_Handler.java @@ -128,17 +128,26 @@ public class Net_GetPersonalDiary_Handler implements JsonMessageHandler { item.setAuthorLogin(rs.getString("login")); item.setAuthorBlockchainName(rs.getString("bch_name")); item.setCreatedAtMs(entry.timestamp * 1000L); - item.setText(statusBody.message == null ? "" : statusBody.message); item.setLikesCount(0); item.setLikedByMe(false); item.setRepliesCount(0); item.setRatingsCount(0); - item.setVersionsTotal(1); - item.setVersions(new ArrayList<>()); item.setTargetBlockchainName(statusBody.toBchName()); item.setTargetBlockNumber(statusBody.toBlockGlobalNumber()); item.setTargetBlockHash(ChannelsReadSupport.toHex(statusBody.toBlockHashBytes())); + List versions = loadVersionsForDiaryItem( + c, + rs.getString("bch_name"), + rs.getInt("block_number"), + rs.getBytes("block_hash"), + statusBody.message == null ? "" : statusBody.message, + entry.timestamp * 1000L + ); + item.setVersions(versions); + item.setVersionsTotal(versions.size()); + item.setText(versions.get(versions.size() - 1).getText()); + fillTargetDetails(c, item, statusBody.toBchName(), statusBody.toBlockGlobalNumber(), statusBody.toBlockHashBytes()); out.add(item); } @@ -147,6 +156,56 @@ public class Net_GetPersonalDiary_Handler implements JsonMessageHandler { return out; } + private List loadVersionsForDiaryItem(Connection c, + String ownerBch, + int originalBlockNumber, + byte[] originalBlockHash, + String originalText, + long originalCreatedAtMs) throws Exception { + List versions = new ArrayList<>(); + + Net_GetChannelMessages_Response.VersionItem first = new Net_GetChannelMessages_Response.VersionItem(); + first.setVersionIndex(1); + first.setBlockNumber(originalBlockNumber); + first.setBlockHash(ChannelsReadSupport.toHex(originalBlockHash)); + first.setText(originalText == null ? "" : originalText); + first.setCreatedAtMs(originalCreatedAtMs); + versions.add(first); + + try (PreparedStatement ps = c.prepareStatement(""" + SELECT block_number, block_hash, block_bytes + FROM blocks + WHERE bch_name = ? + AND msg_type = ? + AND msg_sub_type = ? + AND to_block_number = ? + AND to_block_hash = ? + AND (to_bch_name = ? OR to_bch_name IS NULL OR to_bch_name = '') + ORDER BY block_number ASC + """)) { + ps.setString(1, ownerBch); + ps.setInt(2, ChannelsReadSupport.MSG_TYPE_TEXT); + ps.setInt(3, shine.db.MsgSubType.TEXT_EDIT_REPLY); + ps.setInt(4, originalBlockNumber); + ps.setBytes(5, originalBlockHash); + ps.setString(6, ownerBch); + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + ChannelsReadSupport.TextInfo editText = ChannelsReadSupport.parseTextAndTime(rs.getBytes("block_bytes")); + Net_GetChannelMessages_Response.VersionItem item = new Net_GetChannelMessages_Response.VersionItem(); + item.setVersionIndex(versions.size() + 1); + item.setBlockNumber(rs.getInt("block_number")); + item.setBlockHash(ChannelsReadSupport.toHex(rs.getBytes("block_hash"))); + item.setText(editText.text); + item.setCreatedAtMs(editText.createdAtMs); + versions.add(item); + } + } + } + + return versions; + } + private void fillTargetDetails(Connection c, Net_GetChannelMessages_Response.MessageItem item, String targetBch, diff --git a/VERSION.properties b/VERSION.properties index add3d2c3..12542726 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.5.24 -server.version=1.4.9 +client.version=1.5.25 +server.version=1.4.10 diff --git a/shine-UI/js/pages/channel-thread-view.js b/shine-UI/js/pages/channel-thread-view.js index 918e99bb..cefcea25 100644 --- a/shine-UI/js/pages/channel-thread-view.js +++ b/shine-UI/js/pages/channel-thread-view.js @@ -24,6 +24,7 @@ import { loadProfileSnapshot } from '../services/user-profile-params.js'; import { extractLoginFromBlockchainName, makeProfileRoute, makeShineChannelRoute, makeShineMessageRoute } from '../services/shine-routes.js'; export const pageMeta = { id: 'channel-thread-view', title: 'Тред' }; +const MSG_SUBTYPE_TEXT_POST = 10; const MSG_SUBTYPE_TEXT_RATING = 30; const MSG_SUBTYPE_TEXT_ENTRYPOINT = 100; const MSG_SUBTYPE_TEXT_EXERCISE = 110; @@ -247,6 +248,13 @@ function getChannelMessageTypeMeta(msgSubType) { } } +function isEditableAsChannelPostSubType(msgSubType) { + return Number(msgSubType || 0) === MSG_SUBTYPE_TEXT_POST + || Number(msgSubType || 0) === MSG_SUBTYPE_TEXT_EXERCISE + || Number(msgSubType || 0) === MSG_SUBTYPE_TEXT_SERVICE + || Number(msgSubType || 0) === MSG_SUBTYPE_TEXT_COURSE; +} + function extractChannelContextFromThreadPayload(payload) { const focusInfo = payload?.focus?.channelInfo; if (focusInfo?.ownerBlockchainName && focusInfo?.channelRoot?.blockNumber != null) { @@ -455,10 +463,10 @@ function openBlockchainDetailsModal(details) { function resolveNodeText(node) { return firstNonEmptyText( + latestVersionText(node?.versions), node?.text, node?.message, node?.body, - latestVersionText(node?.versions), ); } @@ -751,8 +759,8 @@ function renderNodeCard(node, heading, handlers, localNumber) { const replies = Number(node?.repliesCount || 0); const ratings = Number(node?.ratingsCount || 0); const isOwnMessage = String(node?.authorLogin || '').trim().toLowerCase() === String(state.session.login || '').trim().toLowerCase(); - const isChannelPost = Number(node?.channelInfo?.channelRoot?.blockNumber) >= 0; const msgSubType = Number(node?.msgSubType || 0); + const isChannelPost = isEditableAsChannelPostSubType(msgSubType); const isRating = msgSubType === MSG_SUBTYPE_TEXT_RATING; const repostTarget = msgSubType === 50 ? buildRepostTargetFromNode(node) : null; const parsedText = parseMessageAttachments(text); diff --git a/shine-UI/js/pages/channel-view.js b/shine-UI/js/pages/channel-view.js index 3530fa0d..c4bd8ef7 100644 --- a/shine-UI/js/pages/channel-view.js +++ b/shine-UI/js/pages/channel-view.js @@ -2246,7 +2246,8 @@ export function render({ navigate, route }) { const onEditPost = async (messageRef, text) => { const { login, storagePwd } = requireSigningSession(); - if (!activeSelector?.ownerBlockchainName || activeSelector.channelRootBlockNumber == null) { + const isDiaryEdit = isDiarySelector(activeSelector); + if (!isDiaryEdit && (!activeSelector?.ownerBlockchainName || activeSelector.channelRootBlockNumber == null)) { throw new Error('Идентификатор канала не готов.'); } await authService.addBlockEditMessage({ @@ -2254,8 +2255,8 @@ export function render({ navigate, route }) { storagePwd, message: messageRef, text, - isChannelPost: true, - channel: activeSelector, + isChannelPost: !isDiaryEdit, + channel: isDiaryEdit ? null : activeSelector, }); softHaptic(12); showToast('Сообщение обновлено');