Добавить opinion-связи и обновить UI связей в профиле
This commit is contained in:
parent
a53444b863
commit
aa35d87885
@ -15,6 +15,14 @@
|
|||||||
- Дополнительно обязательно вести `Dev_Docs/Blockchain/CHANGELOG.md`: дописывать изменения построчно с указанием даты/времени и хэша коммита, после которого внесено изменение.
|
- Дополнительно обязательно вести `Dev_Docs/Blockchain/CHANGELOG.md`: дописывать изменения построчно с указанием даты/времени и хэша коммита, после которого внесено изменение.
|
||||||
- Перед любым изменением формата блокчейна обязательно заранее предупреждать пользователя, что формат будет изменён.
|
- Перед любым изменением формата блокчейна обязательно заранее предупреждать пользователя, что формат будет изменён.
|
||||||
- Изменять формат блокчейна можно только после явного подтверждения пользователя (без подтверждения формат не менять).
|
- Изменять формат блокчейна можно только после явного подтверждения пользователя (без подтверждения формат не менять).
|
||||||
|
- Добавление любых данных в блокчейн выполнять только через операцию `AddBlock`.
|
||||||
|
- Перед каждым `AddBlock` обязательно проверять/актуализировать текущее состояние вершины блокчейна (`last global number/hash`) и использовать его при формировании блока.
|
||||||
|
|
||||||
|
## Документация личных сообщений (DM)
|
||||||
|
- Актуальная документация по логике личных сообщений находится в `Dev_Docs/Personal_Messages/README.md`.
|
||||||
|
- При любом изменении кода, связанного с личными сообщениями (формат подписанного DM-блока, типы DM-сообщений, правила доставки/ACK/read-receipt, роутинг по сессиям, UI-логика чатов), обязательно обновлять `Dev_Docs/Personal_Messages/README.md`.
|
||||||
|
- Логика личных сообщений в коде должна всегда соответствовать `Dev_Docs/Personal_Messages/README.md`.
|
||||||
|
- Документ по личным сообщениям обязан поддерживаться в актуальном состоянии.
|
||||||
|
|
||||||
## Версионирование
|
## Версионирование
|
||||||
- Единый файл версий проекта: `VERSION.properties` (в корне репозитория).
|
- Единый файл версий проекта: `VERSION.properties` (в корне репозитория).
|
||||||
|
|||||||
@ -107,6 +107,20 @@
|
|||||||
- `CONNECTION_UNCONTACT (21)`
|
- `CONNECTION_UNCONTACT (21)`
|
||||||
- `CONNECTION_FOLLOW (30)`
|
- `CONNECTION_FOLLOW (30)`
|
||||||
- `CONNECTION_UNFOLLOW (31)`
|
- `CONNECTION_UNFOLLOW (31)`
|
||||||
|
- `CONNECTION_SPOUSE (40)`
|
||||||
|
- `CONNECTION_UNSPOUSE (41)`
|
||||||
|
- `CONNECTION_PARENT (50)`
|
||||||
|
- `CONNECTION_UNPARENT (51)`
|
||||||
|
- `CONNECTION_CHILD (52)`
|
||||||
|
- `CONNECTION_UNCHILD (53)`
|
||||||
|
- `CONNECTION_SIBLING (54)`
|
||||||
|
- `CONNECTION_UNSIBLING (55)`
|
||||||
|
- `CONNECTION_KNOWN_PERSON (60)`
|
||||||
|
- `CONNECTION_UNKNOWN_PERSON (61)`
|
||||||
|
- `CONNECTION_SHINE_CONFIRMED (70)`
|
||||||
|
- `CONNECTION_SHINE_UNCONFIRMED (71)`
|
||||||
|
- `CONNECTION_SHINE_SEEN (74)`
|
||||||
|
- `CONNECTION_SHINE_UNSEEN (75)`
|
||||||
|
|
||||||
5. **USER_PARAM (type=4)**
|
5. **USER_PARAM (type=4)**
|
||||||
- `USER_PARAM_TEXT_TEXT (1)`
|
- `USER_PARAM_TEXT_TEXT (1)`
|
||||||
|
|||||||
@ -4,20 +4,16 @@ CONNECTION-тип описывает социальные связи и подп
|
|||||||
|
|
||||||
## Подтипы
|
## Подтипы
|
||||||
|
|
||||||
1. `subType=10` — `CONNECTION_FRIEND`
|
• `10/11` — `close_friend / unclose_friend` (близкий друг)
|
||||||
2. `subType=11` — `CONNECTION_UNFRIEND`
|
• `20/21` — `contact / uncontact` (контакт)
|
||||||
3. `subType=20` — `CONNECTION_CONTACT`
|
• `30/31` — `follow / unfollow` (подписан)
|
||||||
4. `subType=21` — `CONNECTION_UNCONTACT`
|
• `40/41` — `spouse / unspouse` (супруг/супруга)
|
||||||
5. `subType=30` — `CONNECTION_FOLLOW`
|
• `50/51` — `parent / unparent` (родитель)
|
||||||
6. `subType=31` — `CONNECTION_UNFOLLOW`
|
• `52/53` — `child / unchild` (ребёнок)
|
||||||
7. `subType=40` — `CONNECTION_SPOUSE`
|
• `54/55` — `sibling / unsibling` (брат/сестра)
|
||||||
8. `subType=41` — `CONNECTION_UNSPOUSE`
|
• `60/61` — `known_person / unknown_person` (знаю этого человека)
|
||||||
9. `subType=50` — `CONNECTION_PARENT`
|
• `70/71` — `shine_confirmed / shine_unconfirmed` (точно уверен, что сияющий)
|
||||||
10. `subType=51` — `CONNECTION_UNPARENT`
|
• `74/75` — `shine_seen / shine_unseen` (мало знаком, но видел сияющим)
|
||||||
11. `subType=52` — `CONNECTION_CHILD`
|
|
||||||
12. `subType=53` — `CONNECTION_UNCHILD`
|
|
||||||
13. `subType=54` — `CONNECTION_SIBLING`
|
|
||||||
14. `subType=55` — `CONNECTION_UNSIBLING`
|
|
||||||
|
|
||||||
## Общий формат payload
|
## Общий формат payload
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,13 @@
|
|||||||
# История изменений документации блокчейна
|
# История изменений документации блокчейна
|
||||||
|
|
||||||
|
## 2026-05-20 11:34:17 +0300
|
||||||
|
- Базовый коммит-ориентир: `a53444b`.
|
||||||
|
- В `13_CONNECTION_Blocks.md` добавлены новые CONNECTION подтипы:
|
||||||
|
- `60/61` — `known_person / unknown_person` (знаю этого человека);
|
||||||
|
- `70/71` — `shine_confirmed / shine_unconfirmed` (точно уверен, что сияющий);
|
||||||
|
- `74/75` — `shine_seen / shine_unseen` (мало знаком, но видел сияющим).
|
||||||
|
- Обновлён список CONNECTION-подтипов в `Dev_Docs/API/04_Add_Block_to_Blockchain_API.md`.
|
||||||
|
|
||||||
## 2026-05-19 20:30:21 +0300
|
## 2026-05-19 20:30:21 +0300
|
||||||
- Базовый коммит-ориентир: `7986184`.
|
- Базовый коммит-ориентир: `7986184`.
|
||||||
- Уточнён документ `11_TEXT_Blocks.md`: для `TEXT_EDIT_POST` и `TEXT_EDIT_REPLY` зафиксировано, что `textLen=0` допустим и трактуется как логическое удаление сообщения.
|
- Уточнён документ `11_TEXT_Blocks.md`: для `TEXT_EDIT_POST` и `TEXT_EDIT_REPLY` зафиксировано, что `textLen=0` допустим и трактуется как логическое удаление сообщения.
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
## Краткое описание
|
||||||
|
Добавлены новые типы connection-связей в блокчейне и API:
|
||||||
|
- `known_person` (`60/61`)
|
||||||
|
- `shine_confirmed` (`70/71`)
|
||||||
|
- `shine_seen` (`74/75`)
|
||||||
|
|
||||||
|
## Что проверять
|
||||||
|
1. `AddBlock` принимает новые `msg_sub_type` для `type=3`.
|
||||||
|
2. Связи корректно попадают в `connections_state`:
|
||||||
|
- ON создаёт/обновляет запись;
|
||||||
|
- OFF удаляет запись соответствующего ON-типа.
|
||||||
|
3. `GetUserConnectionsGraph` возвращает новые поля:
|
||||||
|
- `outKnownPersons`, `inKnownPersons`
|
||||||
|
- `outShineConfirmed`, `inShineConfirmed`
|
||||||
|
- `outShineSeen`, `inShineSeen`
|
||||||
|
4. Клиент `setUserRelation` принимает `kind`:
|
||||||
|
- `known_person`, `shine_confirmed`, `shine_seen`.
|
||||||
|
|
||||||
|
## Ожидаемый результат
|
||||||
|
Новые связи работают как обычные ON/OFF relation-типы, но не ломают текущие friend/contact/follow и остальные существующие связи.
|
||||||
|
|
||||||
|
## Статус
|
||||||
|
`pending`
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
## Краткое описание
|
||||||
|
Перестроен блок связей в профиле чужого пользователя и добавлен UI для одностороннего "мнения" (`known_person` / `shine_confirmed` / `shine_seen`) с взаимным исключением на уровне UI.
|
||||||
|
|
||||||
|
## Что проверять
|
||||||
|
1. Порядок базовых строк в профиле:
|
||||||
|
- Контакт
|
||||||
|
- Близкий друг
|
||||||
|
- Подписка
|
||||||
|
2. Под этими строками отображается блок мнений:
|
||||||
|
- при отсутствии мнения кнопка `Добавить связь`;
|
||||||
|
- при наличии мнения кнопка `Изменить связи`;
|
||||||
|
- показываются текстовые формулировки для активного мнения.
|
||||||
|
3. В модальном меню:
|
||||||
|
- варианты добавления (синие);
|
||||||
|
- `Убрать мнение` (красная).
|
||||||
|
4. При смене мнения отправляется последовательность:
|
||||||
|
- OFF старой связи,
|
||||||
|
- ON новой связи.
|
||||||
|
5. Для новых мнений показываются только исходящие (`out*`) оценки текущего пользователя (односторонняя логика).
|
||||||
|
|
||||||
|
## Ожидаемый результат
|
||||||
|
Пользователь управляет одним активным мнением через UI, состояние читается корректно и не ломает существующие friend/contact/follow кнопки.
|
||||||
|
|
||||||
|
## Статус
|
||||||
|
`pending`
|
||||||
@ -1,2 +1,2 @@
|
|||||||
client.version=1.2.78
|
client.version=1.2.79
|
||||||
server.version=1.2.72
|
server.version=1.2.73
|
||||||
|
|||||||
@ -28,28 +28,28 @@ function genderText(value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function relationButtonLabel(kind, flags) {
|
function relationButtonLabel(kind, flags) {
|
||||||
if (kind === 'follow') return flags.outFollow ? 'Отписаться' : 'Подписаться';
|
if (kind === 'contact') return flags.outContact ? 'Убрать из контактов' : 'Добавить в контакты';
|
||||||
if (kind === 'friend') return flags.outFriend ? 'Убрать из близких друзей' : 'Добавить в близкие друзья';
|
if (kind === 'friend') return flags.outFriend ? 'Убрать из близких друзей' : 'Добавить в близкие друзья';
|
||||||
return flags.outContact ? 'Убрать из контактов' : 'Добавить в контакты';
|
return flags.outFollow ? 'Отписаться' : 'Подписаться';
|
||||||
}
|
}
|
||||||
|
|
||||||
function relationNextState(kind, flags) {
|
function relationNextState(kind, flags) {
|
||||||
if (kind === 'follow') return !flags.outFollow;
|
if (kind === 'contact') return !flags.outContact;
|
||||||
if (kind === 'friend') return !flags.outFriend;
|
if (kind === 'friend') return !flags.outFriend;
|
||||||
return !flags.outContact;
|
return !flags.outFollow;
|
||||||
}
|
}
|
||||||
|
|
||||||
function relationConfirmLabel(kind) {
|
function relationConfirmLabel(kind) {
|
||||||
if (kind === 'follow') return 'подписку';
|
if (kind === 'contact') return 'контакт';
|
||||||
if (kind === 'friend') return 'статус близкого друга';
|
if (kind === 'friend') return 'статус близкого друга';
|
||||||
return 'контакт';
|
return 'подписку';
|
||||||
}
|
}
|
||||||
|
|
||||||
function relationStateText(kind, flags) {
|
function relationStateText(kind, flags) {
|
||||||
if (kind === 'follow') {
|
if (kind === 'contact') {
|
||||||
if (flags.outFollow && flags.inFollow) return 'Вы взаимно подписаны.';
|
if (flags.outContact && flags.inContact) return 'Вы обменялись контактами.';
|
||||||
if (flags.outFollow) return 'Вы подписаны на этот профиль.';
|
if (flags.outContact) return 'Вы добавили этот профиль в контакты.';
|
||||||
if (flags.inFollow) return 'Этот профиль подписан на вас.';
|
if (flags.inContact) return 'Этот профиль добавил вас в контакты.';
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
if (kind === 'friend') {
|
if (kind === 'friend') {
|
||||||
@ -58,12 +58,52 @@ function relationStateText(kind, flags) {
|
|||||||
if (flags.inFriend) return 'Этот профиль считает вас близким другом.';
|
if (flags.inFriend) return 'Этот профиль считает вас близким другом.';
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
if (flags.outContact && flags.inContact) return 'Вы обменялись контактами.';
|
if (flags.outFollow && flags.inFollow) return 'Вы взаимно подписаны.';
|
||||||
if (flags.outContact) return 'Вы добавили этот профиль в контакты.';
|
if (flags.outFollow) return 'Вы подписаны на этот профиль.';
|
||||||
if (flags.inContact) return 'Этот профиль добавил вас в контакты.';
|
if (flags.inFollow) return 'Этот профиль подписан на вас.';
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function opinionItemsFromFlags(flags) {
|
||||||
|
const items = [];
|
||||||
|
if (flags.outShineSeen) {
|
||||||
|
items.push({
|
||||||
|
kind: 'shine_seen',
|
||||||
|
text: 'вы утверждаете, что очень мало знаете этого человека, но вы видели его сияющим, и всё, что вы о нём знаете, подтверждает это',
|
||||||
|
label: 'видел сияющим',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (flags.outShineConfirmed) {
|
||||||
|
items.push({
|
||||||
|
kind: 'shine_confirmed',
|
||||||
|
text: 'вы утверждаете, что достаточно хорошо знаете этого человека и точно уверены, что этот человек сияющий',
|
||||||
|
label: 'точно сияющий',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (flags.outKnownPerson) {
|
||||||
|
items.push({
|
||||||
|
kind: 'known_person',
|
||||||
|
text: 'вы утверждаете, что просто знаете этого человека',
|
||||||
|
label: 'просто знаю',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveActiveOpinionKind(flags) {
|
||||||
|
if (flags.outShineSeen) return 'shine_seen';
|
||||||
|
if (flags.outShineConfirmed) return 'shine_confirmed';
|
||||||
|
if (flags.outKnownPerson) return 'known_person';
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function opinionLabelByKind(kind) {
|
||||||
|
if (kind === 'shine_seen') return 'мало знаком, но видел сияющим';
|
||||||
|
if (kind === 'shine_confirmed') return 'точно уверен, что сияющий';
|
||||||
|
if (kind === 'known_person') return 'просто знаю человека';
|
||||||
|
return kind;
|
||||||
|
}
|
||||||
|
|
||||||
function renderIdentity(card) {
|
function renderIdentity(card) {
|
||||||
const lines = buildIdentityLines({
|
const lines = buildIdentityLines({
|
||||||
login: card.login,
|
login: card.login,
|
||||||
@ -109,10 +149,12 @@ function renderReadOnlyBadges(card) {
|
|||||||
|
|
||||||
function renderRelations(flags) {
|
function renderRelations(flags) {
|
||||||
const rows = [
|
const rows = [
|
||||||
{ kind: 'follow', text: relationStateText('follow', flags), button: relationButtonLabel('follow', flags) },
|
|
||||||
{ kind: 'friend', text: relationStateText('friend', flags), button: relationButtonLabel('friend', flags) },
|
|
||||||
{ kind: 'contact', text: relationStateText('contact', flags), button: relationButtonLabel('contact', flags) },
|
{ kind: 'contact', text: relationStateText('contact', flags), button: relationButtonLabel('contact', flags) },
|
||||||
|
{ kind: 'friend', text: relationStateText('friend', flags), button: relationButtonLabel('friend', flags) },
|
||||||
|
{ kind: 'follow', text: relationStateText('follow', flags), button: relationButtonLabel('follow', flags) },
|
||||||
];
|
];
|
||||||
|
const opinionItems = opinionItemsFromFlags(flags);
|
||||||
|
const hasOpinion = opinionItems.length > 0;
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="card stack user-relations-list">
|
<div class="card stack user-relations-list">
|
||||||
@ -122,10 +164,65 @@ function renderRelations(flags) {
|
|||||||
<button class="ghost-btn user-rel-action" type="button" data-relation-action="${row.kind}">${escapeHtml(row.button)}</button>
|
<button class="ghost-btn user-rel-action" type="button" data-relation-action="${row.kind}">${escapeHtml(row.button)}</button>
|
||||||
</div>
|
</div>
|
||||||
`).join('')}
|
`).join('')}
|
||||||
|
<div class="user-rel-opinions-wrap ${hasOpinion ? '' : 'is-empty'}">
|
||||||
|
<div class="user-rel-opinions-list">
|
||||||
|
${opinionItems.map((item) => `
|
||||||
|
<div class="user-rel-opinion-item">${escapeHtml(item.text)}</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
<div class="user-rel-opinions-hint">Добавьте одну из этих трёх формулировок.</div>
|
||||||
|
</div>
|
||||||
|
<div class="user-rel-row">
|
||||||
|
<span class="user-rel-text">${hasOpinion ? 'Мнение уже добавлено.' : 'Пока нет дополнительной связи.'}</span>
|
||||||
|
<button class="ghost-btn user-rel-action user-rel-opinion-btn" type="button" data-relation-action="opinion-menu">${hasOpinion ? 'Изменить связи' : 'Добавить связь'}</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openOpinionMenuModal({ flags, onApply }) {
|
||||||
|
const root = document.getElementById('modal-root');
|
||||||
|
if (!root) return;
|
||||||
|
const activeKind = resolveActiveOpinionKind(flags);
|
||||||
|
const items = [
|
||||||
|
{ kind: 'known_person', title: 'просто знаю человека' },
|
||||||
|
{ kind: 'shine_confirmed', title: 'точно уверен, что сияющий' },
|
||||||
|
{ kind: 'shine_seen', title: 'мало знаком, но видел сияющим' },
|
||||||
|
];
|
||||||
|
const rowsHtml = items
|
||||||
|
.filter((item) => item.kind !== activeKind)
|
||||||
|
.map((item) => `<button class="secondary-btn user-opinion-modal-btn is-add" type="button" data-opinion-kind="${item.kind}" data-opinion-mode="set">Добавить: ${item.title}</button>`)
|
||||||
|
.join('');
|
||||||
|
const removeHtml = activeKind
|
||||||
|
? `<button class="secondary-btn user-opinion-modal-btn is-remove" type="button" data-opinion-kind="${activeKind}" data-opinion-mode="remove">Убрать мнение</button>`
|
||||||
|
: '';
|
||||||
|
|
||||||
|
root.innerHTML = `
|
||||||
|
<div class="modal" id="user-opinion-modal">
|
||||||
|
<div class="modal-card stack">
|
||||||
|
<h3 class="modal-title">${activeKind ? 'Изменить связи' : 'Добавить связь'}</h3>
|
||||||
|
<div class="stack">${rowsHtml}${removeHtml}</div>
|
||||||
|
<button class="secondary-btn" type="button" id="user-opinion-modal-close">Закрыть</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const close = () => { root.innerHTML = ''; };
|
||||||
|
root.querySelector('#user-opinion-modal-close')?.addEventListener('click', close);
|
||||||
|
root.querySelector('#user-opinion-modal')?.addEventListener('click', (event) => {
|
||||||
|
if (event.target?.id === 'user-opinion-modal') close();
|
||||||
|
});
|
||||||
|
root.querySelectorAll('[data-opinion-mode]').forEach((btn) => {
|
||||||
|
btn.addEventListener('click', async () => {
|
||||||
|
const nextKind = String(btn.getAttribute('data-opinion-kind') || '').trim();
|
||||||
|
const mode = String(btn.getAttribute('data-opinion-mode') || '').trim();
|
||||||
|
close();
|
||||||
|
if (!nextKind) return;
|
||||||
|
await onApply({ mode, nextKind, activeKind });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function renderReadOnlyParams(card) {
|
function renderReadOnlyParams(card) {
|
||||||
const rows = [
|
const rows = [
|
||||||
{ label: 'Имя', value: card.firstName },
|
{ label: 'Имя', value: card.firstName },
|
||||||
@ -179,14 +276,17 @@ export function render({ navigate, route }) {
|
|||||||
const followBtn = body.querySelector('[data-relation-action="follow"]');
|
const followBtn = body.querySelector('[data-relation-action="follow"]');
|
||||||
const friendBtn = body.querySelector('[data-relation-action="friend"]');
|
const friendBtn = body.querySelector('[data-relation-action="friend"]');
|
||||||
const contactBtn = body.querySelector('[data-relation-action="contact"]');
|
const contactBtn = body.querySelector('[data-relation-action="contact"]');
|
||||||
if (!followBtn || !friendBtn || !contactBtn || !currentFlags) return;
|
const opinionBtn = body.querySelector('[data-relation-action="opinion-menu"]');
|
||||||
|
if (!followBtn || !friendBtn || !contactBtn || !opinionBtn || !currentFlags) return;
|
||||||
const isSelf = currentCard && currentCard.login.toLowerCase() === sessionLogin.toLowerCase();
|
const isSelf = currentCard && currentCard.login.toLowerCase() === sessionLogin.toLowerCase();
|
||||||
followBtn.textContent = relationButtonLabel('follow', currentFlags);
|
|
||||||
friendBtn.textContent = relationButtonLabel('friend', currentFlags);
|
|
||||||
contactBtn.textContent = relationButtonLabel('contact', currentFlags);
|
contactBtn.textContent = relationButtonLabel('contact', currentFlags);
|
||||||
followBtn.disabled = Boolean(isSelf);
|
friendBtn.textContent = relationButtonLabel('friend', currentFlags);
|
||||||
friendBtn.disabled = Boolean(isSelf);
|
followBtn.textContent = relationButtonLabel('follow', currentFlags);
|
||||||
contactBtn.disabled = Boolean(isSelf);
|
contactBtn.disabled = Boolean(isSelf);
|
||||||
|
friendBtn.disabled = Boolean(isSelf);
|
||||||
|
followBtn.disabled = Boolean(isSelf);
|
||||||
|
opinionBtn.textContent = opinionItemsFromFlags(currentFlags).length ? 'Изменить связи' : 'Добавить связь';
|
||||||
|
opinionBtn.disabled = Boolean(isSelf);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refresh() {
|
async function refresh() {
|
||||||
@ -243,6 +343,14 @@ export function render({ navigate, route }) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (kind === 'opinion-menu') {
|
||||||
|
openOpinionMenuModal({
|
||||||
|
flags: currentFlags,
|
||||||
|
onApply: onOpinionApply,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const nextEnabled = relationNextState(kind, currentFlags);
|
const nextEnabled = relationNextState(kind, currentFlags);
|
||||||
const confirmed = window.confirm(
|
const confirmed = window.confirm(
|
||||||
`Изменить ${relationConfirmLabel(kind)} с пользователем ${currentCard.login}?\n` +
|
`Изменить ${relationConfirmLabel(kind)} с пользователем ${currentCard.login}?\n` +
|
||||||
@ -271,13 +379,60 @@ export function render({ navigate, route }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function onOpinionApply({ mode, nextKind, activeKind }) {
|
||||||
|
if (isBusy || !currentCard || !currentFlags) return;
|
||||||
|
if (!sessionLogin) {
|
||||||
|
window.alert('Для изменения связей нужен активный вход.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!state.session.storagePwdInMemory) {
|
||||||
|
window.alert('Нет storagePwd в памяти сессии. Выполните вход заново.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmed = window.confirm(`Изменить мнение о пользователе ${currentCard.login}?`);
|
||||||
|
if (!confirmed) return;
|
||||||
|
|
||||||
|
isBusy = true;
|
||||||
|
status.className = 'status-line';
|
||||||
|
status.textContent = 'Сохранение отношения в блокчейн...';
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (activeKind) {
|
||||||
|
await authService.setUserRelation({
|
||||||
|
login: sessionLogin,
|
||||||
|
toLogin: currentCard.login,
|
||||||
|
kind: activeKind,
|
||||||
|
enabled: false,
|
||||||
|
storagePwd: state.session.storagePwdInMemory,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode === 'set') {
|
||||||
|
await authService.setUserRelation({
|
||||||
|
login: sessionLogin,
|
||||||
|
toLogin: currentCard.login,
|
||||||
|
kind: nextKind,
|
||||||
|
enabled: true,
|
||||||
|
storagePwd: state.session.storagePwdInMemory,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await refresh();
|
||||||
|
} catch (error) {
|
||||||
|
status.className = 'status-line is-unavailable';
|
||||||
|
status.textContent = `Ошибка изменения связи: ${error.message || 'unknown'}`;
|
||||||
|
window.alert(`Не удалось изменить связь: ${error.message || 'unknown'}`);
|
||||||
|
isBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
body.addEventListener('click', (event) => {
|
body.addEventListener('click', (event) => {
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
if (!(target instanceof HTMLElement)) return;
|
if (!(target instanceof HTMLElement)) return;
|
||||||
const actionBtn = target.closest('[data-relation-action]');
|
const actionBtn = target.closest('[data-relation-action]');
|
||||||
const kind = String(actionBtn?.getAttribute('data-relation-action') || '');
|
const kind = String(actionBtn?.getAttribute('data-relation-action') || '');
|
||||||
if (!kind) return;
|
if (!kind) return;
|
||||||
onRelationAction(kind);
|
void onRelationAction(kind);
|
||||||
});
|
});
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
|
|||||||
@ -61,6 +61,9 @@ const CONNECTION_SUBTYPES = Object.freeze({
|
|||||||
parent: { on: 50, off: 51 },
|
parent: { on: 50, off: 51 },
|
||||||
child: { on: 52, off: 53 },
|
child: { on: 52, off: 53 },
|
||||||
sibling: { on: 54, off: 55 },
|
sibling: { on: 54, off: 55 },
|
||||||
|
known_person: { on: 60, off: 61 },
|
||||||
|
shine_confirmed: { on: 70, off: 71 },
|
||||||
|
shine_seen: { on: 74, off: 75 },
|
||||||
});
|
});
|
||||||
|
|
||||||
function normalizeServerUrl(url) {
|
function normalizeServerUrl(url) {
|
||||||
|
|||||||
@ -75,6 +75,12 @@ async function buildRelationsModel(login) {
|
|||||||
inChildren: [],
|
inChildren: [],
|
||||||
outSiblings: [],
|
outSiblings: [],
|
||||||
inSiblings: [],
|
inSiblings: [],
|
||||||
|
outKnownPersons: [],
|
||||||
|
inKnownPersons: [],
|
||||||
|
outShineConfirmed: [],
|
||||||
|
inShineConfirmed: [],
|
||||||
|
outShineSeen: [],
|
||||||
|
inShineSeen: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +123,12 @@ async function buildRelationsModel(login) {
|
|||||||
inChildren: readArray(graph, 'inChildren') || [],
|
inChildren: readArray(graph, 'inChildren') || [],
|
||||||
outSiblings: readArray(graph, 'outSiblings') || [],
|
outSiblings: readArray(graph, 'outSiblings') || [],
|
||||||
inSiblings: readArray(graph, 'inSiblings') || [],
|
inSiblings: readArray(graph, 'inSiblings') || [],
|
||||||
|
outKnownPersons: readArray(graph, 'outKnownPersons') || [],
|
||||||
|
inKnownPersons: readArray(graph, 'inKnownPersons') || [],
|
||||||
|
outShineConfirmed: readArray(graph, 'outShineConfirmed') || [],
|
||||||
|
inShineConfirmed: readArray(graph, 'inShineConfirmed') || [],
|
||||||
|
outShineSeen: readArray(graph, 'outShineSeen') || [],
|
||||||
|
inShineSeen: readArray(graph, 'inShineSeen') || [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +163,12 @@ export async function loadCurrentRelations() {
|
|||||||
inChildren: [],
|
inChildren: [],
|
||||||
outSiblings: [],
|
outSiblings: [],
|
||||||
inSiblings: [],
|
inSiblings: [],
|
||||||
|
outKnownPersons: [],
|
||||||
|
inKnownPersons: [],
|
||||||
|
outShineConfirmed: [],
|
||||||
|
inShineConfirmed: [],
|
||||||
|
outShineSeen: [],
|
||||||
|
inShineSeen: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return buildRelationsModel(login);
|
return buildRelationsModel(login);
|
||||||
@ -170,6 +188,12 @@ export function relationFlagsForTarget(relations, targetLogin) {
|
|||||||
inChild: listContainsLogin(relations?.inChildren, targetLogin),
|
inChild: listContainsLogin(relations?.inChildren, targetLogin),
|
||||||
outSibling: listContainsLogin(relations?.outSiblings, targetLogin),
|
outSibling: listContainsLogin(relations?.outSiblings, targetLogin),
|
||||||
inSibling: listContainsLogin(relations?.inSiblings, targetLogin),
|
inSibling: listContainsLogin(relations?.inSiblings, targetLogin),
|
||||||
|
outKnownPerson: listContainsLogin(relations?.outKnownPersons, targetLogin),
|
||||||
|
inKnownPerson: listContainsLogin(relations?.inKnownPersons, targetLogin),
|
||||||
|
outShineConfirmed: listContainsLogin(relations?.outShineConfirmed, targetLogin),
|
||||||
|
inShineConfirmed: listContainsLogin(relations?.inShineConfirmed, targetLogin),
|
||||||
|
outShineSeen: listContainsLogin(relations?.outShineSeen, targetLogin),
|
||||||
|
inShineSeen: listContainsLogin(relations?.inShineSeen, targetLogin),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -644,6 +644,8 @@
|
|||||||
.avatar-image {
|
.avatar-image {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-image > .avatar-fallback,
|
.avatar-image > .avatar-fallback,
|
||||||
@ -1639,6 +1641,49 @@ textarea.input {
|
|||||||
color: transparent;
|
color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-rel-opinions-wrap {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px dashed rgba(131, 196, 255, 0.45);
|
||||||
|
background: rgba(9, 18, 31, 0.42);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-rel-opinions-wrap.is-empty .user-rel-opinions-list {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-rel-opinions-list {
|
||||||
|
display: grid;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-rel-opinion-item {
|
||||||
|
color: #d7e6ff;
|
||||||
|
line-height: 1.35;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-rel-opinions-hint {
|
||||||
|
color: rgba(173, 199, 236, 0.9);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-opinion-modal-btn {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-opinion-modal-btn.is-add {
|
||||||
|
border-color: rgba(97, 170, 255, 0.7);
|
||||||
|
color: #9fcbff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-opinion-modal-btn.is-remove {
|
||||||
|
border-color: rgba(255, 120, 120, 0.72);
|
||||||
|
color: #ff9b9b;
|
||||||
|
}
|
||||||
|
|
||||||
.tabs {
|
.tabs {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
@ -2219,6 +2264,11 @@ textarea.input {
|
|||||||
background: radial-gradient(circle at 30% 30%, #8a73ff, #4f4bda 58%, #3b2b89);
|
background: radial-gradient(circle at 30% 30%, #8a73ff, #4f4bda 58%, #3b2b89);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.channel-message-avatar.avatar-image {
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.channel-message-author {
|
.channel-message-author {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
|||||||
@ -113,6 +113,21 @@ public final class MsgSubType {
|
|||||||
/** Удалить связь "брат/сестра". */
|
/** Удалить связь "брат/сестра". */
|
||||||
public static final short CONNECTION_UNSIBLING = 55;
|
public static final short CONNECTION_UNSIBLING = 55;
|
||||||
|
|
||||||
|
/** Просто знаю этого человека. */
|
||||||
|
public static final short CONNECTION_KNOWN_PERSON = 60;
|
||||||
|
/** Не знаю этого человека. */
|
||||||
|
public static final short CONNECTION_UNKNOWN_PERSON = 61;
|
||||||
|
|
||||||
|
/** Точно уверен, что сияющий. */
|
||||||
|
public static final short CONNECTION_SHINE_CONFIRMED = 70;
|
||||||
|
/** Не подтверждаю, что сияющий. */
|
||||||
|
public static final short CONNECTION_SHINE_UNCONFIRMED = 71;
|
||||||
|
|
||||||
|
/** Мало знаком, но видел сияющим. */
|
||||||
|
public static final short CONNECTION_SHINE_SEEN = 74;
|
||||||
|
/** Не отмечаю, что видел сияющим. */
|
||||||
|
public static final short CONNECTION_SHINE_UNSEEN = 75;
|
||||||
|
|
||||||
/* ===================== USER_PARAM (msg_type=4) ===================== */
|
/* ===================== USER_PARAM (msg_type=4) ===================== */
|
||||||
|
|
||||||
/** Параметр профиля key/value (обе строки). */
|
/** Параметр профиля key/value (обе строки). */
|
||||||
|
|||||||
@ -16,9 +16,13 @@ import java.util.Objects;
|
|||||||
* FRIEND=10, UNFRIEND=11
|
* FRIEND=10, UNFRIEND=11
|
||||||
* CONTACT=20, UNCONTACT=21
|
* CONTACT=20, UNCONTACT=21
|
||||||
* FOLLOW=30, UNFOLLOW=31
|
* FOLLOW=30, UNFOLLOW=31
|
||||||
|
* SPOUSE=40, UNSPOUSE=41
|
||||||
* PARENT=50, UNPARENT=51
|
* PARENT=50, UNPARENT=51
|
||||||
* CHILD=52, UNCHILD=53
|
* CHILD=52, UNCHILD=53
|
||||||
* SIBLING=54, UNSIBLING=55
|
* SIBLING=54, UNSIBLING=55
|
||||||
|
* KNOWN_PERSON=60, UNKNOWN_PERSON=61
|
||||||
|
* SHINE_CONFIRMED=70, SHINE_UNCONFIRMED=71
|
||||||
|
* SHINE_SEEN=74, SHINE_UNSEEN=75
|
||||||
*
|
*
|
||||||
* bodyBytes (BigEndian), новый формат (toLogin НЕ ХРАНИМ):
|
* bodyBytes (BigEndian), новый формат (toLogin НЕ ХРАНИМ):
|
||||||
* [4] lineCode
|
* [4] lineCode
|
||||||
@ -192,7 +196,13 @@ public final class ConnectionBody implements BodyRecord, BodyHasTarget, BodyHasL
|
|||||||
|| v == (MsgSubType.CONNECTION_CHILD & 0xFFFF)
|
|| v == (MsgSubType.CONNECTION_CHILD & 0xFFFF)
|
||||||
|| v == (MsgSubType.CONNECTION_UNCHILD & 0xFFFF)
|
|| v == (MsgSubType.CONNECTION_UNCHILD & 0xFFFF)
|
||||||
|| v == (MsgSubType.CONNECTION_SIBLING & 0xFFFF)
|
|| v == (MsgSubType.CONNECTION_SIBLING & 0xFFFF)
|
||||||
|| v == (MsgSubType.CONNECTION_UNSIBLING & 0xFFFF);
|
|| v == (MsgSubType.CONNECTION_UNSIBLING & 0xFFFF)
|
||||||
|
|| v == (MsgSubType.CONNECTION_KNOWN_PERSON & 0xFFFF)
|
||||||
|
|| v == (MsgSubType.CONNECTION_UNKNOWN_PERSON & 0xFFFF)
|
||||||
|
|| v == (MsgSubType.CONNECTION_SHINE_CONFIRMED & 0xFFFF)
|
||||||
|
|| v == (MsgSubType.CONNECTION_SHINE_UNCONFIRMED & 0xFFFF)
|
||||||
|
|| v == (MsgSubType.CONNECTION_SHINE_SEEN & 0xFFFF)
|
||||||
|
|| v == (MsgSubType.CONNECTION_SHINE_UNSEEN & 0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -66,6 +66,15 @@ public final class DatabaseInitializer {
|
|||||||
public static final short CONNECTION_SIBLING = 54;
|
public static final short CONNECTION_SIBLING = 54;
|
||||||
public static final short CONNECTION_UNSIBLING = 55;
|
public static final short CONNECTION_UNSIBLING = 55;
|
||||||
|
|
||||||
|
public static final short CONNECTION_KNOWN_PERSON = 60;
|
||||||
|
public static final short CONNECTION_UNKNOWN_PERSON = 61;
|
||||||
|
|
||||||
|
public static final short CONNECTION_SHINE_CONFIRMED = 70;
|
||||||
|
public static final short CONNECTION_SHINE_UNCONFIRMED = 71;
|
||||||
|
|
||||||
|
public static final short CONNECTION_SHINE_SEEN = 74;
|
||||||
|
public static final short CONNECTION_SHINE_UNSEEN = 75;
|
||||||
|
|
||||||
public static void createNewDB(String[] args) {
|
public static void createNewDB(String[] args) {
|
||||||
AppConfig config = AppConfig.getInstance();
|
AppConfig config = AppConfig.getInstance();
|
||||||
String dbPath = config.getParam("db.path");
|
String dbPath = config.getParam("db.path");
|
||||||
|
|||||||
@ -198,6 +198,9 @@ public final class DatabaseTriggersInstaller {
|
|||||||
int PARENT = (int) DatabaseInitializer.CONNECTION_PARENT;
|
int PARENT = (int) DatabaseInitializer.CONNECTION_PARENT;
|
||||||
int CHILD = (int) DatabaseInitializer.CONNECTION_CHILD;
|
int CHILD = (int) DatabaseInitializer.CONNECTION_CHILD;
|
||||||
int SIBLING = (int) DatabaseInitializer.CONNECTION_SIBLING;
|
int SIBLING = (int) DatabaseInitializer.CONNECTION_SIBLING;
|
||||||
|
int KNOWN = (int) DatabaseInitializer.CONNECTION_KNOWN_PERSON;
|
||||||
|
int SHINE_CONF = (int) DatabaseInitializer.CONNECTION_SHINE_CONFIRMED;
|
||||||
|
int SHINE_SEEN = (int) DatabaseInitializer.CONNECTION_SHINE_SEEN;
|
||||||
|
|
||||||
int UNFRIEND = (int) DatabaseInitializer.CONNECTION_UNFRIEND;
|
int UNFRIEND = (int) DatabaseInitializer.CONNECTION_UNFRIEND;
|
||||||
int UNCONTACT = (int) DatabaseInitializer.CONNECTION_UNCONTACT;
|
int UNCONTACT = (int) DatabaseInitializer.CONNECTION_UNCONTACT;
|
||||||
@ -206,13 +209,16 @@ public final class DatabaseTriggersInstaller {
|
|||||||
int UNPARENT = (int) DatabaseInitializer.CONNECTION_UNPARENT;
|
int UNPARENT = (int) DatabaseInitializer.CONNECTION_UNPARENT;
|
||||||
int UNCHILD = (int) DatabaseInitializer.CONNECTION_UNCHILD;
|
int UNCHILD = (int) DatabaseInitializer.CONNECTION_UNCHILD;
|
||||||
int UNSIBLING = (int) DatabaseInitializer.CONNECTION_UNSIBLING;
|
int UNSIBLING = (int) DatabaseInitializer.CONNECTION_UNSIBLING;
|
||||||
|
int UNKNOWN = (int) DatabaseInitializer.CONNECTION_UNKNOWN_PERSON;
|
||||||
|
int SHINE_UNCONF = (int) DatabaseInitializer.CONNECTION_SHINE_UNCONFIRMED;
|
||||||
|
int SHINE_UNSEEN = (int) DatabaseInitializer.CONNECTION_SHINE_UNSEEN;
|
||||||
|
|
||||||
st.executeUpdate("""
|
st.executeUpdate("""
|
||||||
CREATE TRIGGER IF NOT EXISTS trg_blocks_connection_state_ai
|
CREATE TRIGGER IF NOT EXISTS trg_blocks_connection_state_ai
|
||||||
AFTER INSERT ON blocks
|
AFTER INSERT ON blocks
|
||||||
WHEN NEW.msg_type = 3
|
WHEN NEW.msg_type = 3
|
||||||
BEGIN
|
BEGIN
|
||||||
-- FRIEND/CONTACT/FOLLOW/SPOUSE/PARENT/CHILD/SIBLING:
|
-- FRIEND/CONTACT/FOLLOW/SPOUSE/PARENT/CHILD/SIBLING/KNOWN_PERSON/SHINE_*:
|
||||||
-- 1) если записи нет — создаём
|
-- 1) если записи нет — создаём
|
||||||
INSERT OR IGNORE INTO connections_state (
|
INSERT OR IGNORE INTO connections_state (
|
||||||
login, rel_type, to_login, to_bch_name, to_block_number, to_block_hash
|
login, rel_type, to_login, to_bch_name, to_block_number, to_block_hash
|
||||||
@ -233,7 +239,7 @@ public final class DatabaseTriggersInstaller {
|
|||||||
NEW.to_bch_name,
|
NEW.to_bch_name,
|
||||||
NEW.to_block_number,
|
NEW.to_block_number,
|
||||||
NEW.to_block_hash
|
NEW.to_block_hash
|
||||||
WHERE NEW.msg_sub_type IN (%d, %d, %d, %d, %d, %d, %d)
|
WHERE NEW.msg_sub_type IN (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d)
|
||||||
AND COALESCE(
|
AND COALESCE(
|
||||||
NEW.to_login,
|
NEW.to_login,
|
||||||
CASE
|
CASE
|
||||||
@ -264,7 +270,7 @@ public final class DatabaseTriggersInstaller {
|
|||||||
ELSE NULL
|
ELSE NULL
|
||||||
END
|
END
|
||||||
)
|
)
|
||||||
AND NEW.msg_sub_type IN (%d, %d, %d, %d, %d, %d, %d)
|
AND NEW.msg_sub_type IN (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d)
|
||||||
AND COALESCE(
|
AND COALESCE(
|
||||||
NEW.to_login,
|
NEW.to_login,
|
||||||
CASE
|
CASE
|
||||||
@ -277,7 +283,7 @@ public final class DatabaseTriggersInstaller {
|
|||||||
) IS NOT NULL
|
) IS NOT NULL
|
||||||
AND NEW.to_bch_name IS NOT NULL;
|
AND NEW.to_bch_name IS NOT NULL;
|
||||||
|
|
||||||
-- UNFRIEND/UNCONTACT/UNFOLLOW/UNSPOUSE/UNPARENT/UNCHILD/UNSIBLING:
|
-- UNFRIEND/UNCONTACT/UNFOLLOW/UNSPOUSE/UNPARENT/UNCHILD/UNSIBLING/UNKNOWN_PERSON/SHINE_UN*:
|
||||||
-- удаляем соответствующее "позитивное" состояние
|
-- удаляем соответствующее "позитивное" состояние
|
||||||
DELETE FROM connections_state
|
DELETE FROM connections_state
|
||||||
WHERE login = NEW.login
|
WHERE login = NEW.login
|
||||||
@ -299,6 +305,9 @@ public final class DatabaseTriggersInstaller {
|
|||||||
WHEN %d THEN %d
|
WHEN %d THEN %d
|
||||||
WHEN %d THEN %d
|
WHEN %d THEN %d
|
||||||
WHEN %d THEN %d
|
WHEN %d THEN %d
|
||||||
|
WHEN %d THEN %d
|
||||||
|
WHEN %d THEN %d
|
||||||
|
WHEN %d THEN %d
|
||||||
ELSE rel_type
|
ELSE rel_type
|
||||||
END
|
END
|
||||||
AND COALESCE(
|
AND COALESCE(
|
||||||
@ -311,11 +320,11 @@ public final class DatabaseTriggersInstaller {
|
|||||||
ELSE NULL
|
ELSE NULL
|
||||||
END
|
END
|
||||||
) IS NOT NULL
|
) IS NOT NULL
|
||||||
AND NEW.msg_sub_type IN (%d, %d, %d, %d, %d, %d, %d);
|
AND NEW.msg_sub_type IN (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d);
|
||||||
END;
|
END;
|
||||||
""".formatted(
|
""".formatted(
|
||||||
FRIEND, CONTACT, FOLLOW, SPOUSE, PARENT, CHILD, SIBLING,
|
FRIEND, CONTACT, FOLLOW, SPOUSE, PARENT, CHILD, SIBLING, KNOWN, SHINE_CONF, SHINE_SEEN,
|
||||||
FRIEND, CONTACT, FOLLOW, SPOUSE, PARENT, CHILD, SIBLING,
|
FRIEND, CONTACT, FOLLOW, SPOUSE, PARENT, CHILD, SIBLING, KNOWN, SHINE_CONF, SHINE_SEEN,
|
||||||
|
|
||||||
UNFRIEND, FRIEND,
|
UNFRIEND, FRIEND,
|
||||||
UNCONTACT, CONTACT,
|
UNCONTACT, CONTACT,
|
||||||
@ -324,8 +333,11 @@ public final class DatabaseTriggersInstaller {
|
|||||||
UNPARENT, PARENT,
|
UNPARENT, PARENT,
|
||||||
UNCHILD, CHILD,
|
UNCHILD, CHILD,
|
||||||
UNSIBLING, SIBLING,
|
UNSIBLING, SIBLING,
|
||||||
|
UNKNOWN, KNOWN,
|
||||||
|
SHINE_UNCONF, SHINE_CONF,
|
||||||
|
SHINE_UNSEEN, SHINE_SEEN,
|
||||||
|
|
||||||
UNFRIEND, UNCONTACT, UNFOLLOW, UNSPOUSE, UNPARENT, UNCHILD, UNSIBLING
|
UNFRIEND, UNCONTACT, UNFOLLOW, UNSPOUSE, UNPARENT, UNCHILD, UNSIBLING, UNKNOWN, SHINE_UNCONF, SHINE_UNSEEN
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -40,8 +40,10 @@ public final class MsgSubType {
|
|||||||
/* ===================== CONNECTION (msg_type=3) ===================== */
|
/* ===================== CONNECTION (msg_type=3) ===================== */
|
||||||
/**
|
/**
|
||||||
* Совпадает с ConnectionBody:
|
* Совпадает с ConnectionBody:
|
||||||
* SET: CLOSE_FRIEND(=FRIEND)=10, CONTACT=20, FOLLOW=30, SPOUSE=40, PARENT=50, CHILD=52, SIBLING=54
|
* SET: CLOSE_FRIEND(=FRIEND)=10, CONTACT=20, FOLLOW=30, SPOUSE=40, PARENT=50, CHILD=52, SIBLING=54,
|
||||||
* UNSET: UNCLOSE_FRIEND(=UNFRIEND)=11, UNCONTACT=21, UNFOLLOW=31, UNSPOUSE=41, UNPARENT=51, UNCHILD=53, UNSIBLING=55
|
* KNOWN_PERSON=60, SHINE_CONFIRMED=70, SHINE_SEEN=74
|
||||||
|
* UNSET: UNCLOSE_FRIEND(=UNFRIEND)=11, UNCONTACT=21, UNFOLLOW=31, UNSPOUSE=41, UNPARENT=51, UNCHILD=53, UNSIBLING=55,
|
||||||
|
* UNKNOWN_PERSON=61, SHINE_UNCONFIRMED=71, SHINE_UNSEEN=75
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Добавить в близкие друзья (close friend). */
|
/** Добавить в близкие друзья (close friend). */
|
||||||
@ -92,6 +94,24 @@ public final class MsgSubType {
|
|||||||
/** Удалить связь "брат/сестра". */
|
/** Удалить связь "брат/сестра". */
|
||||||
public static final short CONNECTION_UNSIBLING = 55;
|
public static final short CONNECTION_UNSIBLING = 55;
|
||||||
|
|
||||||
|
/** Просто знаю этого человека. */
|
||||||
|
public static final short CONNECTION_KNOWN_PERSON = 60;
|
||||||
|
|
||||||
|
/** Не знаю этого человека. */
|
||||||
|
public static final short CONNECTION_UNKNOWN_PERSON = 61;
|
||||||
|
|
||||||
|
/** Точно уверен, что сияющий. */
|
||||||
|
public static final short CONNECTION_SHINE_CONFIRMED = 70;
|
||||||
|
|
||||||
|
/** Не подтверждаю, что сияющий. */
|
||||||
|
public static final short CONNECTION_SHINE_UNCONFIRMED = 71;
|
||||||
|
|
||||||
|
/** Мало знаком, но видел сияющим. */
|
||||||
|
public static final short CONNECTION_SHINE_SEEN = 74;
|
||||||
|
|
||||||
|
/** Не отмечаю, что видел сияющим. */
|
||||||
|
public static final short CONNECTION_SHINE_UNSEEN = 75;
|
||||||
|
|
||||||
/* ===================== USER_PARAM (msg_type=4) ===================== */
|
/* ===================== USER_PARAM (msg_type=4) ===================== */
|
||||||
|
|
||||||
/** Параметр профиля key/value (обе строки). */
|
/** Параметр профиля key/value (обе строки). */
|
||||||
|
|||||||
@ -55,11 +55,18 @@ public class Net_GetUserConnectionsGraph_Handler implements JsonMessageHandler {
|
|||||||
List<String> inChildren = ConnectionsStateDAO.getInstance().listIncomingByRelTypeCanonical(c, canonicalLogin, MsgSubType.CONNECTION_CHILD);
|
List<String> inChildren = ConnectionsStateDAO.getInstance().listIncomingByRelTypeCanonical(c, canonicalLogin, MsgSubType.CONNECTION_CHILD);
|
||||||
List<String> outSiblings = ConnectionsStateDAO.getInstance().listOutgoingByRelTypeCanonical(c, canonicalLogin, MsgSubType.CONNECTION_SIBLING);
|
List<String> outSiblings = ConnectionsStateDAO.getInstance().listOutgoingByRelTypeCanonical(c, canonicalLogin, MsgSubType.CONNECTION_SIBLING);
|
||||||
List<String> inSiblings = ConnectionsStateDAO.getInstance().listIncomingByRelTypeCanonical(c, canonicalLogin, MsgSubType.CONNECTION_SIBLING);
|
List<String> inSiblings = ConnectionsStateDAO.getInstance().listIncomingByRelTypeCanonical(c, canonicalLogin, MsgSubType.CONNECTION_SIBLING);
|
||||||
|
List<String> outKnownPersons = ConnectionsStateDAO.getInstance().listOutgoingByRelTypeCanonical(c, canonicalLogin, MsgSubType.CONNECTION_KNOWN_PERSON);
|
||||||
|
List<String> inKnownPersons = ConnectionsStateDAO.getInstance().listIncomingByRelTypeCanonical(c, canonicalLogin, MsgSubType.CONNECTION_KNOWN_PERSON);
|
||||||
|
List<String> outShineConfirmed = ConnectionsStateDAO.getInstance().listOutgoingByRelTypeCanonical(c, canonicalLogin, MsgSubType.CONNECTION_SHINE_CONFIRMED);
|
||||||
|
List<String> inShineConfirmed = ConnectionsStateDAO.getInstance().listIncomingByRelTypeCanonical(c, canonicalLogin, MsgSubType.CONNECTION_SHINE_CONFIRMED);
|
||||||
|
List<String> outShineSeen = ConnectionsStateDAO.getInstance().listOutgoingByRelTypeCanonical(c, canonicalLogin, MsgSubType.CONNECTION_SHINE_SEEN);
|
||||||
|
List<String> inShineSeen = ConnectionsStateDAO.getInstance().listIncomingByRelTypeCanonical(c, canonicalLogin, MsgSubType.CONNECTION_SHINE_SEEN);
|
||||||
|
|
||||||
LinkedHashSet<String> allLogins = new LinkedHashSet<>();
|
LinkedHashSet<String> allLogins = new LinkedHashSet<>();
|
||||||
allLogins.add(canonicalLogin);
|
allLogins.add(canonicalLogin);
|
||||||
addAllLogins(allLogins, outFriends, inFriends, outContacts, inContacts, outFollows, inFollows,
|
addAllLogins(allLogins, outFriends, inFriends, outContacts, inContacts, outFollows, inFollows,
|
||||||
outSpouses, inSpouses, outParents, inParents, outChildren, inChildren, outSiblings, inSiblings);
|
outSpouses, inSpouses, outParents, inParents, outChildren, inChildren, outSiblings, inSiblings,
|
||||||
|
outKnownPersons, inKnownPersons, outShineConfirmed, inShineConfirmed, outShineSeen, inShineSeen);
|
||||||
|
|
||||||
Map<String, UserMeta> metaByLogin = loadUserMeta(c, allLogins);
|
Map<String, UserMeta> metaByLogin = loadUserMeta(c, allLogins);
|
||||||
List<String> spouseLogins = mergeUnique(outSpouses, inSpouses);
|
List<String> spouseLogins = mergeUnique(outSpouses, inSpouses);
|
||||||
@ -86,6 +93,12 @@ public class Net_GetUserConnectionsGraph_Handler implements JsonMessageHandler {
|
|||||||
resp.setInChildren(inChildren);
|
resp.setInChildren(inChildren);
|
||||||
resp.setOutSiblings(outSiblings);
|
resp.setOutSiblings(outSiblings);
|
||||||
resp.setInSiblings(inSiblings);
|
resp.setInSiblings(inSiblings);
|
||||||
|
resp.setOutKnownPersons(outKnownPersons);
|
||||||
|
resp.setInKnownPersons(inKnownPersons);
|
||||||
|
resp.setOutShineConfirmed(outShineConfirmed);
|
||||||
|
resp.setInShineConfirmed(inShineConfirmed);
|
||||||
|
resp.setOutShineSeen(outShineSeen);
|
||||||
|
resp.setInShineSeen(inShineSeen);
|
||||||
resp.setParents(toRelativeItems(parentLogins, metaByLogin));
|
resp.setParents(toRelativeItems(parentLogins, metaByLogin));
|
||||||
resp.setChildren(toRelativeItems(childLogins, metaByLogin));
|
resp.setChildren(toRelativeItems(childLogins, metaByLogin));
|
||||||
resp.setSiblings(toRelativeItems(siblingLogins, metaByLogin));
|
resp.setSiblings(toRelativeItems(siblingLogins, metaByLogin));
|
||||||
|
|||||||
@ -21,6 +21,12 @@ public class Net_GetUserConnectionsGraph_Response extends Net_Response {
|
|||||||
private List<String> inChildren = new ArrayList<>();
|
private List<String> inChildren = new ArrayList<>();
|
||||||
private List<String> outSiblings = new ArrayList<>();
|
private List<String> outSiblings = new ArrayList<>();
|
||||||
private List<String> inSiblings = new ArrayList<>();
|
private List<String> inSiblings = new ArrayList<>();
|
||||||
|
private List<String> outKnownPersons = new ArrayList<>();
|
||||||
|
private List<String> inKnownPersons = new ArrayList<>();
|
||||||
|
private List<String> outShineConfirmed = new ArrayList<>();
|
||||||
|
private List<String> inShineConfirmed = new ArrayList<>();
|
||||||
|
private List<String> outShineSeen = new ArrayList<>();
|
||||||
|
private List<String> inShineSeen = new ArrayList<>();
|
||||||
private List<RelativeItem> parents = new ArrayList<>();
|
private List<RelativeItem> parents = new ArrayList<>();
|
||||||
private List<RelativeItem> children = new ArrayList<>();
|
private List<RelativeItem> children = new ArrayList<>();
|
||||||
private List<RelativeItem> siblings = new ArrayList<>();
|
private List<RelativeItem> siblings = new ArrayList<>();
|
||||||
@ -102,6 +108,18 @@ public class Net_GetUserConnectionsGraph_Response extends Net_Response {
|
|||||||
public void setOutSiblings(List<String> outSiblings) { this.outSiblings = outSiblings; }
|
public void setOutSiblings(List<String> outSiblings) { this.outSiblings = outSiblings; }
|
||||||
public List<String> getInSiblings() { return inSiblings; }
|
public List<String> getInSiblings() { return inSiblings; }
|
||||||
public void setInSiblings(List<String> inSiblings) { this.inSiblings = inSiblings; }
|
public void setInSiblings(List<String> inSiblings) { this.inSiblings = inSiblings; }
|
||||||
|
public List<String> getOutKnownPersons() { return outKnownPersons; }
|
||||||
|
public void setOutKnownPersons(List<String> outKnownPersons) { this.outKnownPersons = outKnownPersons; }
|
||||||
|
public List<String> getInKnownPersons() { return inKnownPersons; }
|
||||||
|
public void setInKnownPersons(List<String> inKnownPersons) { this.inKnownPersons = inKnownPersons; }
|
||||||
|
public List<String> getOutShineConfirmed() { return outShineConfirmed; }
|
||||||
|
public void setOutShineConfirmed(List<String> outShineConfirmed) { this.outShineConfirmed = outShineConfirmed; }
|
||||||
|
public List<String> getInShineConfirmed() { return inShineConfirmed; }
|
||||||
|
public void setInShineConfirmed(List<String> inShineConfirmed) { this.inShineConfirmed = inShineConfirmed; }
|
||||||
|
public List<String> getOutShineSeen() { return outShineSeen; }
|
||||||
|
public void setOutShineSeen(List<String> outShineSeen) { this.outShineSeen = outShineSeen; }
|
||||||
|
public List<String> getInShineSeen() { return inShineSeen; }
|
||||||
|
public void setInShineSeen(List<String> inShineSeen) { this.inShineSeen = inShineSeen; }
|
||||||
public List<RelativeItem> getParents() { return parents; }
|
public List<RelativeItem> getParents() { return parents; }
|
||||||
public void setParents(List<RelativeItem> parents) { this.parents = parents; }
|
public void setParents(List<RelativeItem> parents) { this.parents = parents; }
|
||||||
public List<RelativeItem> getChildren() { return children; }
|
public List<RelativeItem> getChildren() { return children; }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user