SHA256
Обновить каналы и перенести черновики
This commit is contained in:
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
client.version=1.12.3
|
client.version=1.12.4
|
||||||
server.version=1.10.1
|
server.version=1.10.1
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# Личный дневник — временно отключён в UI
|
||||||
|
|
||||||
|
Статус: **закомментировано / скрыто из интерфейса**.
|
||||||
|
|
||||||
|
Личный дневник SHiNE не удалён из протокола и серверной части. На текущем этапе он только перестал отображаться пользователю в списке каналов.
|
||||||
|
|
||||||
|
## Что это за функция
|
||||||
|
|
||||||
|
«Дневник» — виртуальный персональный канал пользователя. Он формируется не как обычный канал с отдельной цепочкой постов, а собирается сервером из `STATUS_ACTION` записей пользователя.
|
||||||
|
|
||||||
|
Основной read API:
|
||||||
|
|
||||||
|
- `GetPersonalDiary`
|
||||||
|
|
||||||
|
Связанная документация:
|
||||||
|
|
||||||
|
- `docs/API/06_Channels_Read_API.md` — раздел `GetPersonalDiary`;
|
||||||
|
- `docs/API/09_Operations_Index.md` — операция `GetPersonalDiary`;
|
||||||
|
- `docs/Blockchain/15_STATUS_ACTION_Blocks.md` — действия, из которых собирается дневник;
|
||||||
|
- `docs/Blockchain/CHANGELOG.md` — история добавления функции.
|
||||||
|
|
||||||
|
## Что отключено сейчас
|
||||||
|
|
||||||
|
В `shine-UI/js/pages/channels-list.js` отключён запрос `authService.getPersonalDiary(...)` при построении списка каналов.
|
||||||
|
|
||||||
|
Код оставлен рядом в комментариях, а в `mapApiFeed(...)` передаётся `diaryPayload = null`. Благодаря этому карточка «Дневник» не появляется в разделе каналов.
|
||||||
|
|
||||||
|
## Что намеренно НЕ удалено
|
||||||
|
|
||||||
|
Чтобы не ломать обратную совместимость и сохранить возможность вернуть функцию позже, оставлены:
|
||||||
|
|
||||||
|
- серверная операция `GetPersonalDiary`;
|
||||||
|
- `authService.getPersonalDiary(...)`;
|
||||||
|
- обработка diary-route в `channel-view.js`;
|
||||||
|
- форматы `STATUS_ACTION`;
|
||||||
|
- чтение старых типов сообщений и действий.
|
||||||
|
|
||||||
|
То есть функция сохранена технически, но скрыта из обычной навигации.
|
||||||
|
|
||||||
|
## Как вернуть дневник
|
||||||
|
|
||||||
|
В `shine-UI/js/pages/channels-list.js` вернуть получение `diaryPayload`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
let diaryPayload = null;
|
||||||
|
try {
|
||||||
|
diaryPayload = await authService.getPersonalDiary(state.session.login, 200, 'asc');
|
||||||
|
} catch {
|
||||||
|
diaryPayload = null;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
и убрать временное:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const diaryPayload = null;
|
||||||
|
```
|
||||||
|
|
||||||
|
После этого `mapApiFeed(...)` снова сможет добавить виртуальную карточку дневника в список каналов.
|
||||||
|
|
||||||
|
## Связанные типы контента
|
||||||
|
|
||||||
|
В интерфейсе создания новой записи канала сейчас доступны только:
|
||||||
|
|
||||||
|
- `POST (10)` — Пост;
|
||||||
|
- `TEXT_ENTRYPOINT (100)` — Оглавление канала.
|
||||||
|
|
||||||
|
Варианты `TEXT_EXERCISE (110)`, `TEXT_SERVICE (120)` и `TEXT_COURSE (130)` убраны только из формы создания новой записи. Их константы и обработчики чтения сохранены для совместимости со старыми данными.
|
||||||
@@ -1217,9 +1217,6 @@ function openAddMessageModal({ channelName, onSubmit, navigate, isActive = () =>
|
|||||||
<div class="channel-message-tools">
|
<div class="channel-message-tools">
|
||||||
<select id="channel-message-type" class="input channel-message-type-select">
|
<select id="channel-message-type" class="input channel-message-type-select">
|
||||||
<option value="${10}">Пост</option>
|
<option value="${10}">Пост</option>
|
||||||
<option value="${MSG_SUBTYPE_TEXT_EXERCISE}">Упражнение</option>
|
|
||||||
<option value="${MSG_SUBTYPE_TEXT_SERVICE}">Услуга</option>
|
|
||||||
<option value="${MSG_SUBTYPE_TEXT_COURSE}">Курс</option>
|
|
||||||
<option value="${MSG_SUBTYPE_TEXT_ENTRYPOINT}">Оглавление канала</option>
|
<option value="${MSG_SUBTYPE_TEXT_ENTRYPOINT}">Оглавление канала</option>
|
||||||
</select>
|
</select>
|
||||||
<button class="secondary-btn attachment-trigger-btn" id="channel-message-attach" type="button" aria-label="Добавить вложение" title="Добавить вложение">▣ 📎</button>
|
<button class="secondary-btn attachment-trigger-btn" id="channel-message-attach" type="button" aria-label="Добавить вложение" title="Добавить вложение">▣ 📎</button>
|
||||||
@@ -2211,9 +2208,9 @@ function renderBody(screen, navigate, routeKey, channelData, handlers) {
|
|||||||
} else if (channelData.isOwnChannel) {
|
} else if (channelData.isOwnChannel) {
|
||||||
screen.append(feed, addMessageButton);
|
screen.append(feed, addMessageButton);
|
||||||
} else if (!channelData.isSubscribed && !isStoriesChannel(channelData.channel)) {
|
} else if (!channelData.isSubscribed && !isStoriesChannel(channelData.channel)) {
|
||||||
screen.append(actionButton, feed, backButton);
|
screen.append(feed, actionButton);
|
||||||
} else {
|
} else {
|
||||||
screen.append(feed, backButton);
|
screen.append(feed);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasPendingScrollTarget = pendingScrollByRoute.has(routeKey);
|
const hasPendingScrollTarget = pendingScrollByRoute.has(routeKey);
|
||||||
@@ -2319,32 +2316,19 @@ export function render({ navigate, route, chrome }) {
|
|||||||
const items = [
|
const items = [
|
||||||
{ label: 'О канале', action: () => { if (aboutRoute) navigate(aboutRoute); } },
|
{ label: 'О канале', action: () => { if (aboutRoute) navigate(aboutRoute); } },
|
||||||
];
|
];
|
||||||
if (apiData?.isSubscribed && !apiData?.isOwnChannel) {
|
if (!apiData?.isOwnChannel && !isStoriesChannel(apiData?.channel)) {
|
||||||
|
if (apiData?.isSubscribed) {
|
||||||
items.push({
|
items.push({
|
||||||
label: 'Отписаться от канала',
|
label: 'Отписаться от канала',
|
||||||
danger: true,
|
danger: true,
|
||||||
action: async () => {
|
action: () => unsubscribeFromChannel(apiData),
|
||||||
try {
|
});
|
||||||
const { login, storagePwd } = requireSigningSession();
|
} else {
|
||||||
await authService.addBlockFollowChannel({
|
items.push({
|
||||||
login,
|
label: 'Подписаться на канал',
|
||||||
storagePwd,
|
action: () => subscribeToChannel(apiData),
|
||||||
targetBlockchainName: apiData.selector.ownerBlockchainName,
|
|
||||||
targetBlockNumber: apiData.selector.channelRootBlockNumber,
|
|
||||||
targetBlockHashHex: apiData.selector.channelRootBlockHash,
|
|
||||||
unfollow: true,
|
|
||||||
});
|
});
|
||||||
if (disposed) return;
|
|
||||||
const feed = await authService.listSubscriptionsFeed(login, 200);
|
|
||||||
if (disposed) return;
|
|
||||||
setChannelsFeed(feed, state.channelsIndex);
|
|
||||||
showToast('Вы отписались от канала');
|
|
||||||
void refresh();
|
|
||||||
} catch (error) {
|
|
||||||
showStatus(toUserMessage(error, 'Не удалось отписаться от канала.'));
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
},
|
},
|
||||||
@@ -2373,6 +2357,77 @@ export function render({ navigate, route, chrome }) {
|
|||||||
return { login, storagePwd };
|
return { login, storagePwd };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const subscribeToChannel = async (apiData, event = null) => {
|
||||||
|
animatePress(event?.currentTarget);
|
||||||
|
try {
|
||||||
|
const { login, storagePwd } = requireSigningSession();
|
||||||
|
if (!apiData?.selector) throw new Error('Не удалось определить канал для подписки.');
|
||||||
|
const targetName = `${apiData.channel?.ownerName || 'user'}/${apiData.channel?.name || 'channel'}`;
|
||||||
|
const ok = window.confirm(`Подписаться на канал ${targetName}?`);
|
||||||
|
if (!ok) return;
|
||||||
|
|
||||||
|
await authService.addBlockFollowChannel({
|
||||||
|
login,
|
||||||
|
storagePwd,
|
||||||
|
targetBlockchainName: apiData.selector.ownerBlockchainName,
|
||||||
|
targetBlockNumber: apiData.selector.channelRootBlockNumber,
|
||||||
|
targetBlockHashHex: apiData.selector.channelRootBlockHash,
|
||||||
|
unfollow: false,
|
||||||
|
});
|
||||||
|
if (disposed) return;
|
||||||
|
|
||||||
|
const readSettingKey = buildChannelSettingsKey(
|
||||||
|
apiData.channel?.ownerBlockchainName || apiData.selector?.ownerBlockchainName,
|
||||||
|
apiData.channel?.name || apiData.channel?.channelName,
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await authService.upsertUserSetting({
|
||||||
|
login,
|
||||||
|
settingType: 1,
|
||||||
|
settingKey: readSettingKey,
|
||||||
|
timeMs: Date.now(),
|
||||||
|
valueText: '',
|
||||||
|
valueNum: Math.max(0, Number(apiData.messagesCount || 0)),
|
||||||
|
storagePwd,
|
||||||
|
});
|
||||||
|
} catch (readStateError) {
|
||||||
|
showStatus(toUserMessage(readStateError, 'Подписка выполнена, но не удалось сохранить, сколько сообщений уже прочитано.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const feed = await authService.listSubscriptionsFeed(login, 200);
|
||||||
|
if (disposed) return;
|
||||||
|
setChannelsFeed(feed, state.channelsIndex);
|
||||||
|
softHaptic(15);
|
||||||
|
showToast('Подписка на канал выполнена');
|
||||||
|
void refresh();
|
||||||
|
} catch (error) {
|
||||||
|
showStatus(toUserMessage(error, 'Не удалось подписаться на канал.'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsubscribeFromChannel = async (apiData) => {
|
||||||
|
try {
|
||||||
|
const { login, storagePwd } = requireSigningSession();
|
||||||
|
if (!apiData?.selector) throw new Error('Не удалось определить канал для отписки.');
|
||||||
|
await authService.addBlockFollowChannel({
|
||||||
|
login,
|
||||||
|
storagePwd,
|
||||||
|
targetBlockchainName: apiData.selector.ownerBlockchainName,
|
||||||
|
targetBlockNumber: apiData.selector.channelRootBlockNumber,
|
||||||
|
targetBlockHashHex: apiData.selector.channelRootBlockHash,
|
||||||
|
unfollow: true,
|
||||||
|
});
|
||||||
|
if (disposed) return;
|
||||||
|
const feed = await authService.listSubscriptionsFeed(login, 200);
|
||||||
|
if (disposed) return;
|
||||||
|
setChannelsFeed(feed, state.channelsIndex);
|
||||||
|
showToast('Вы отписались от канала');
|
||||||
|
void refresh();
|
||||||
|
} catch (error) {
|
||||||
|
showStatus(toUserMessage(error, 'Не удалось отписаться от канала.'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const onToggleLike = async (messageRef, action) => {
|
const onToggleLike = async (messageRef, action) => {
|
||||||
const actionKey = makeReactionActionKey(messageRef);
|
const actionKey = makeReactionActionKey(messageRef);
|
||||||
if (!actionKey) {
|
if (!actionKey) {
|
||||||
@@ -2774,53 +2829,7 @@ export function render({ navigate, route, chrome }) {
|
|||||||
throw new Error(toUserMessage(error, 'Не удалось изменить сообщение.'));
|
throw new Error(toUserMessage(error, 'Не удалось изменить сообщение.'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSubscribeChannel: async (event) => {
|
onSubscribeChannel: (event) => subscribeToChannel(apiData, event),
|
||||||
animatePress(event?.currentTarget);
|
|
||||||
try {
|
|
||||||
const { login, storagePwd } = requireSigningSession();
|
|
||||||
if (!apiData.selector) throw new Error('Не удалось определить канал для подписки.');
|
|
||||||
const targetName = `${apiData.channel?.ownerName || 'user'}/${apiData.channel?.name || 'channel'}`;
|
|
||||||
const ok = window.confirm(`Подписаться на канал ${targetName}?`);
|
|
||||||
if (!ok) return;
|
|
||||||
|
|
||||||
await authService.addBlockFollowChannel({
|
|
||||||
login,
|
|
||||||
storagePwd,
|
|
||||||
targetBlockchainName: apiData.selector.ownerBlockchainName,
|
|
||||||
targetBlockNumber: apiData.selector.channelRootBlockNumber,
|
|
||||||
targetBlockHashHex: apiData.selector.channelRootBlockHash,
|
|
||||||
unfollow: false,
|
|
||||||
});
|
|
||||||
if (disposed) return;
|
|
||||||
|
|
||||||
const readSettingKey = buildChannelSettingsKey(
|
|
||||||
apiData.channel?.ownerBlockchainName || apiData.selector?.ownerBlockchainName,
|
|
||||||
apiData.channel?.name || apiData.channel?.channelName,
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
await authService.upsertUserSetting({
|
|
||||||
login,
|
|
||||||
settingType: 1,
|
|
||||||
settingKey: readSettingKey,
|
|
||||||
timeMs: Date.now(),
|
|
||||||
valueText: '',
|
|
||||||
valueNum: Math.max(0, Number(apiData.messagesCount || 0)),
|
|
||||||
storagePwd,
|
|
||||||
});
|
|
||||||
} catch (readStateError) {
|
|
||||||
showStatus(toUserMessage(readStateError, 'Подписка выполнена, но не удалось сохранить, сколько сообщений уже прочитано.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
const feed = await authService.listSubscriptionsFeed(login, 200);
|
|
||||||
if (disposed) return;
|
|
||||||
setChannelsFeed(feed, state.channelsIndex);
|
|
||||||
softHaptic(15);
|
|
||||||
showToast('Подписка на канал выполнена');
|
|
||||||
void refresh();
|
|
||||||
} catch (error) {
|
|
||||||
showStatus(toUserMessage(error, 'Не удалось подписаться на канал.'));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (disposed || seq !== refreshSeq) return;
|
if (disposed || seq !== refreshSeq) return;
|
||||||
|
|||||||
@@ -1067,12 +1067,18 @@ async function loadFeedAndRender({ screen, listState, contentEl, navigate }) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const feed = await authService.listSubscriptionsFeed(state.session.login, 200);
|
const feed = await authService.listSubscriptionsFeed(state.session.login, 200);
|
||||||
let diaryPayload = null;
|
|
||||||
try {
|
// FEATURE DISABLED: personal Diary is intentionally hidden from the Channels UI.
|
||||||
diaryPayload = await authService.getPersonalDiary(state.session.login, 200, 'asc');
|
// The server/API implementation is preserved so the feature can be restored later.
|
||||||
} catch {
|
// See: docs/закомментировано/Личный_дневник.md
|
||||||
diaryPayload = null;
|
// let diaryPayload = null;
|
||||||
}
|
// try {
|
||||||
|
// diaryPayload = await authService.getPersonalDiary(state.session.login, 200, 'asc');
|
||||||
|
// } catch {
|
||||||
|
// diaryPayload = null;
|
||||||
|
// }
|
||||||
|
const diaryPayload = null;
|
||||||
|
|
||||||
const groups = mapApiFeed(feed, listState.notificationsState, diaryPayload);
|
const groups = mapApiFeed(feed, listState.notificationsState, diaryPayload);
|
||||||
|
|
||||||
listState.channels = toListModel(groups);
|
listState.channels = toListModel(groups);
|
||||||
|
|||||||
Reference in New Issue
Block a user