SHA256
Каналы: создавать профиль одним блоком
This commit is contained in:
@@ -36,7 +36,7 @@ function renderAvatarPreview(slot, avatar, title) {
|
||||
slot.innerHTML = '';
|
||||
const wrap = document.createElement('div');
|
||||
wrap.className = 'channel-profile-avatar';
|
||||
wrap.style.setProperty('--channel-avatar-size', '82px');
|
||||
wrap.style.setProperty('--channel-avatar-size', '104px');
|
||||
if (avatar?.ar) {
|
||||
const img = document.createElement('img');
|
||||
img.alt = 'Аватар канала';
|
||||
@@ -180,25 +180,17 @@ export function render({ navigate }) {
|
||||
errorEl.textContent = '';
|
||||
|
||||
try {
|
||||
const createResult = await authService.addBlockCreateChannel({
|
||||
await authService.addBlockCreateChannel({
|
||||
login,
|
||||
storagePwd,
|
||||
channelName: normalizeChannelDisplayName(check.name),
|
||||
channelDescription: '',
|
||||
channelDescription: check.description,
|
||||
channelProfileTitle: check.title,
|
||||
channelAvatar: selectedAvatar,
|
||||
channelType: CHANNEL_TYPE_PUBLIC,
|
||||
channelTypeVersion: 1,
|
||||
});
|
||||
if (check.title || check.description || selectedAvatar?.ar) {
|
||||
await authService.addBlockChannelMeta({
|
||||
login,
|
||||
storagePwd,
|
||||
channel: createResult.channel,
|
||||
title: check.title,
|
||||
description: check.description,
|
||||
avatar: selectedAvatar,
|
||||
});
|
||||
if (selectedAvatar?.ar) markArweaveAttachmentPlaced(login, selectedAvatar);
|
||||
}
|
||||
if (selectedAvatar?.ar) markArweaveAttachmentPlaced(login, selectedAvatar);
|
||||
|
||||
persistCreateSuccessFlash(`Канал "${normalizeChannelDisplayName(check.name)}" создан.`);
|
||||
navigate('channels-list');
|
||||
|
||||
@@ -65,6 +65,7 @@ const CHANNEL_TYPE_PUBLIC = 1;
|
||||
const CHANNEL_TYPE_PERSONAL = 100;
|
||||
const CHANNEL_TYPE_GROUP = 200;
|
||||
const CHANNEL_TYPE_VERSION_DEFAULT = 1;
|
||||
const CREATE_CHANNEL_DESCRIPTION_MAX_BYTES = 2048;
|
||||
const SESSION_TYPE_CLIENT = 1;
|
||||
const SESSION_TYPE_WALLET = 50;
|
||||
const SESSION_TYPE_HOMESERVER = 100;
|
||||
@@ -691,10 +692,10 @@ function makeConnectionBodyBytes({
|
||||
}
|
||||
|
||||
function normalizeChannelDescription(value) {
|
||||
const text = String(value == null ? '' : value).trim().replace(/\s+/g, ' ');
|
||||
const text = String(value == null ? '' : value).trim().replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
||||
const bytes = utf8Bytes(text);
|
||||
if (bytes.length > 200) {
|
||||
throw new Error('Описание канала слишком длинное: максимум 200 символов.');
|
||||
if (bytes.length > CREATE_CHANNEL_DESCRIPTION_MAX_BYTES) {
|
||||
throw new Error('Описание канала слишком длинное: максимум 2048 байт.');
|
||||
}
|
||||
return text;
|
||||
}
|
||||
@@ -771,8 +772,8 @@ function makeCreateChannelBodyBytes({
|
||||
}
|
||||
|
||||
const descriptionBytes = utf8Bytes(cleanDescription);
|
||||
if (descriptionBytes.length > 200) {
|
||||
throw new Error('Описание канала слишком длинное: максимум 200 символов.');
|
||||
if (descriptionBytes.length > CREATE_CHANNEL_DESCRIPTION_MAX_BYTES) {
|
||||
throw new Error('Описание канала слишком длинное: максимум 2048 байт.');
|
||||
}
|
||||
const typeVer = Number(channelTypeVersion);
|
||||
if (!Number.isFinite(typeCode) || typeCode < 0 || typeCode > 65535) {
|
||||
@@ -796,31 +797,6 @@ function makeCreateChannelBodyBytes({
|
||||
);
|
||||
}
|
||||
|
||||
function makeCreateChannelBodyBytesLegacy({
|
||||
lineCode,
|
||||
prevLineNumber,
|
||||
prevLineHashHex,
|
||||
thisLineNumber,
|
||||
channelName,
|
||||
}) {
|
||||
const check = validatePersonalChannelName(channelName);
|
||||
if (!check.ok) throw new Error(check.error);
|
||||
const cleanName = check.normalized;
|
||||
const nameBytes = utf8Bytes(cleanName);
|
||||
if (nameBytes.length < 1 || nameBytes.length > 255) {
|
||||
throw new Error('Channel name must be 1..255 bytes');
|
||||
}
|
||||
|
||||
return concatBytes(
|
||||
int32Bytes(lineCode),
|
||||
int32Bytes(prevLineNumber),
|
||||
hexToBytes(normalizeHex32(prevLineHashHex)),
|
||||
int32Bytes(thisLineNumber),
|
||||
int8Byte(nameBytes.length),
|
||||
nameBytes,
|
||||
);
|
||||
}
|
||||
|
||||
function makeTextPostBodyBytes({ lineCode, prevLineNumber, prevLineHashHex, thisLineNumber, text }) {
|
||||
const message = String(text || '').trim();
|
||||
if (!message) throw new Error('Message text is required');
|
||||
@@ -2084,6 +2060,8 @@ export class AuthService {
|
||||
login,
|
||||
channelName,
|
||||
channelDescription = '',
|
||||
channelProfileTitle = '',
|
||||
channelAvatar = null,
|
||||
channelType = CHANNEL_TYPE_PUBLIC,
|
||||
channelTypeVersion = CHANNEL_TYPE_VERSION_DEFAULT,
|
||||
storagePwd,
|
||||
@@ -2099,7 +2077,13 @@ export class AuthService {
|
||||
throw new Error(typeCode === CHANNEL_TYPE_PERSONAL ? nameCheck.error : channelNameErrorText(nameCheck.code));
|
||||
}
|
||||
const cleanChannelName = normalizeChannelDisplayName(nameCheck.normalized);
|
||||
const cleanChannelDescription = normalizeChannelDescription(channelDescription);
|
||||
const cleanChannelDescription = typeCode === CHANNEL_TYPE_PUBLIC
|
||||
? composeChannelMetaText({
|
||||
title: channelProfileTitle,
|
||||
description: channelDescription,
|
||||
avatar: channelAvatar,
|
||||
})
|
||||
: normalizeChannelDescription(channelDescription);
|
||||
const channelSlug = toCanonicalChannelSlug(cleanChannelName);
|
||||
const typeVersion = Number(channelTypeVersion);
|
||||
const key = `create-channel:${cleanLogin}:${typeCode}:${channelSlug || cleanChannelName.toLowerCase()}`;
|
||||
@@ -2131,51 +2115,23 @@ export class AuthService {
|
||||
thisLineNumber = createdChannels.length + 1;
|
||||
}
|
||||
|
||||
let payload;
|
||||
try {
|
||||
payload = await this.addBlockSigned({
|
||||
login: cleanLogin,
|
||||
storagePwd,
|
||||
msgType: MSG_TYPE_TECH,
|
||||
msgSubType: MSG_SUBTYPE_TECH_CREATE_CHANNEL,
|
||||
msgVersion: CREATE_CHANNEL_BODY_VERSION,
|
||||
bodyBytes: makeCreateChannelBodyBytes({
|
||||
lineCode: 0,
|
||||
prevLineNumber,
|
||||
prevLineHashHex,
|
||||
thisLineNumber,
|
||||
channelName: cleanChannelName,
|
||||
channelDescription: cleanChannelDescription,
|
||||
channelType: typeCode,
|
||||
channelTypeVersion: typeVersion,
|
||||
}),
|
||||
});
|
||||
} catch (error) {
|
||||
const rawCode = String(error?.code || '').toUpperCase();
|
||||
const rawText = String(error?.message || '').toLowerCase();
|
||||
const isLegacyFormatMismatch = (
|
||||
rawCode === 'BAD_BLOCK_FORMAT' ||
|
||||
rawText.includes('bad_block_format') ||
|
||||
rawText.includes('некорректный формат блока')
|
||||
);
|
||||
if (!isLegacyFormatMismatch) throw error;
|
||||
|
||||
// Совместимость со старыми серверами, где CreateChannel body без description/type.
|
||||
payload = await this.addBlockSigned({
|
||||
login: cleanLogin,
|
||||
storagePwd,
|
||||
msgType: MSG_TYPE_TECH,
|
||||
msgSubType: MSG_SUBTYPE_TECH_CREATE_CHANNEL,
|
||||
msgVersion: 1,
|
||||
bodyBytes: makeCreateChannelBodyBytesLegacy({
|
||||
lineCode: 0,
|
||||
prevLineNumber,
|
||||
prevLineHashHex,
|
||||
thisLineNumber,
|
||||
channelName: cleanChannelName,
|
||||
}),
|
||||
});
|
||||
}
|
||||
const payload = await this.addBlockSigned({
|
||||
login: cleanLogin,
|
||||
storagePwd,
|
||||
msgType: MSG_TYPE_TECH,
|
||||
msgSubType: MSG_SUBTYPE_TECH_CREATE_CHANNEL,
|
||||
msgVersion: CREATE_CHANNEL_BODY_VERSION,
|
||||
bodyBytes: makeCreateChannelBodyBytes({
|
||||
lineCode: 0,
|
||||
prevLineNumber,
|
||||
prevLineHashHex,
|
||||
thisLineNumber,
|
||||
channelName: cleanChannelName,
|
||||
channelDescription: cleanChannelDescription,
|
||||
channelType: typeCode,
|
||||
channelTypeVersion: typeVersion,
|
||||
}),
|
||||
});
|
||||
|
||||
const selector = {
|
||||
ownerBlockchainName: blockchainName,
|
||||
|
||||
Reference in New Issue
Block a user