You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
6.3 KiB
173 lines
6.3 KiB
#include "memberpropsdialog.h" |
|
#include "../db/db_manager.h" |
|
#include "../transport/gui_bridge.h" |
|
#include <QVBoxLayout> |
|
#include <QHBoxLayout> |
|
#include <QPushButton> |
|
#include <QLabel> |
|
#include <QMessageBox> |
|
#include <cstring> |
|
|
|
extern "C" { |
|
#include "../../../src/chat/chat_core.h" |
|
#include "../../../src/chat/chat_member.h" |
|
#include "../../../lib/mem.h" |
|
} |
|
|
|
MemberPropsDialog::MemberPropsDialog(DbManager* db, const QString& channelId, |
|
uint64_t nodeId, const QString& memberName, |
|
uint8_t flags, QWidget* parent) |
|
: QDialog(parent) |
|
, m_db(db) |
|
, m_channelId(channelId) |
|
, m_nodeId(nodeId) |
|
, m_flags(flags) |
|
{ |
|
setWindowTitle("Member Properties"); |
|
setMinimumWidth(340); |
|
setModal(true); |
|
|
|
/* channel private key (for enabling admin/super checkboxes) */ |
|
auto chs = m_db->getChannels(); |
|
for (const auto& ch : chs) { |
|
if (ch.channelId == channelId) { |
|
m_edPrivkey = ch.ed25519_privkey; |
|
break; |
|
} |
|
} |
|
bool haveKey = (m_edPrivkey.size() == 32); |
|
bool isOwn = (m_nodeId == (uint64_t)m_db->myNodeId()); |
|
|
|
bool isAdmin = (m_flags & CHAT_MEMBER_FLAG_ADMIN) != 0; |
|
bool isSuper = (m_flags & CHAT_MEMBER_FLAG_SUPERNODE) != 0; |
|
|
|
/* load current nick and version from DB (local_nick is local-only, ver is in adm_tags) */ |
|
QString curNick; |
|
m_currentVer = 0; |
|
if (m_db->m_db) { |
|
QString tbl = m_db->peersTableName(channelId); |
|
QByteArray sql = QString( |
|
"SELECT adm_tags, local_nick FROM \"%1\" WHERE node_id=?" |
|
).arg(tbl).toUtf8(); |
|
sqlite3_stmt* st = nullptr; |
|
if (sqlite3_prepare_v2(m_db->m_db, sql.constData(), -1, &st, nullptr) == SQLITE_OK) { |
|
sqlite3_bind_int64(st, 1, (sqlite3_int64)nodeId); |
|
if (sqlite3_step(st) == SQLITE_ROW) { |
|
const char* tags = (const char*)sqlite3_column_text(st, 0); |
|
if (tags) { |
|
const char* vp = strstr(tags, "\"ver\":\""); |
|
if (vp) { vp += 7; m_currentVer = atoi(vp); } |
|
} |
|
curNick = DbManager::colText(st, 1); |
|
} |
|
sqlite3_finalize(st); |
|
} |
|
} |
|
|
|
auto* layout = new QVBoxLayout(this); |
|
layout->setSpacing(12); |
|
layout->setContentsMargins(20, 16, 20, 16); |
|
|
|
auto* title = new QLabel( |
|
QString("Node: 0x%1").arg(nodeId, 16, 16, QChar('0')) + |
|
(memberName.isEmpty() ? "" : QString(" (%1)").arg(memberName)), |
|
this); |
|
title->setStyleSheet("font-weight: bold; font-size: 13px;"); |
|
layout->addWidget(title); |
|
|
|
m_nickEdit = new QLineEdit(this); |
|
m_nickEdit->setPlaceholderText("Local nickname..."); |
|
m_nickEdit->setText(curNick); |
|
m_nickEdit->setEnabled(!isOwn); |
|
layout->addWidget(m_nickEdit); |
|
|
|
m_adminCb = new QCheckBox("Admin", this); |
|
m_adminCb->setChecked(isAdmin); |
|
m_adminCb->setEnabled(haveKey); |
|
layout->addWidget(m_adminCb); |
|
|
|
m_superCb = new QCheckBox("Supernode", this); |
|
m_superCb->setChecked(isSuper); |
|
m_superCb->setEnabled(haveKey); |
|
layout->addWidget(m_superCb); |
|
|
|
m_storageCb = new QCheckBox("Storage (priority attachment keeper)", this); |
|
m_storageCb->setEnabled(haveKey); |
|
layout->addWidget(m_storageCb); |
|
|
|
if (!haveKey) { |
|
auto* hint = new QLabel("(Admin/Super require channel private key)", this); |
|
hint->setStyleSheet("color: gray; font-size: 11px;"); |
|
layout->addWidget(hint); |
|
} |
|
|
|
layout->addStretch(); |
|
|
|
auto* btnLayout = new QHBoxLayout(); |
|
btnLayout->addStretch(); |
|
|
|
auto* cancelBtn = new QPushButton("Cancel", this); |
|
cancelBtn->setFixedWidth(90); |
|
cancelBtn->setStyleSheet( |
|
"QPushButton { border: 1px solid palette(mid); border-radius: 4px;" |
|
" padding: 6px 16px; font-size: 13px; background: palette(button); }" |
|
"QPushButton:hover { background: palette(light); }"); |
|
connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); |
|
btnLayout->addWidget(cancelBtn); |
|
|
|
auto* saveBtn = new QPushButton("Save", this); |
|
saveBtn->setFixedWidth(90); |
|
saveBtn->setDefault(true); |
|
saveBtn->setStyleSheet( |
|
"QPushButton { border: none; border-radius: 4px;" |
|
" padding: 6px 16px; font-size: 13px; font-weight: bold;" |
|
" background: #3390EC; color: white; }" |
|
"QPushButton:hover { background: #2B7ED4; }" |
|
"QPushButton:disabled { background: palette(mid); color: palette(midlight); }"); |
|
connect(saveBtn, &QPushButton::clicked, this, &MemberPropsDialog::onSave); |
|
btnLayout->addWidget(saveBtn); |
|
|
|
layout->addLayout(btnLayout); |
|
} |
|
|
|
void MemberPropsDialog::onSave() { |
|
if (!m_db->m_db) return; |
|
|
|
/* local_nick — always save local (unsigned, local only) */ |
|
QString nick = m_nickEdit->text().trimmed(); |
|
QString tbl = m_db->peersTableName(m_channelId); |
|
QByteArray nickSql = QString( |
|
"UPDATE \"%1\" SET local_nick=? WHERE node_id=?" |
|
).arg(tbl).toUtf8(); |
|
sqlite3_stmt* ns = nullptr; |
|
if (sqlite3_prepare_v2(m_db->m_db, nickSql.constData(), -1, &ns, nullptr) == SQLITE_OK) { |
|
sqlite3_bind_text(ns, 1, nick.isEmpty() ? nullptr : nick.toUtf8().constData(), |
|
-1, nick.isEmpty() ? SQLITE_STATIC : SQLITE_TRANSIENT); |
|
sqlite3_bind_int64(ns, 2, (sqlite3_int64)m_nodeId); |
|
sqlite3_step(ns); |
|
sqlite3_finalize(ns); |
|
} |
|
|
|
/* signed fields — через chat_member_tags_commit_trampoline */ |
|
if (m_edPrivkey.size() != 32) { accept(); return; } |
|
|
|
int ver = m_currentVer + 1; |
|
QString json; |
|
json += QString("{\"ver\":\"%1\"").arg(ver); |
|
json += QString(",\"admin\":\"%1\"").arg(m_adminCb->isChecked() ? "yes" : "no"); |
|
json += QString(",\"supernode\":\"%1\"").arg(m_superCb->isChecked() ? "yes" : "no"); |
|
json += QString(",\"storage\":\"%1\"").arg(m_storageCb->isChecked() ? "yes" : "no"); |
|
json += "}"; |
|
|
|
struct chat_member_tags_req* req = (struct chat_member_tags_req*) |
|
u_calloc(1, sizeof(struct chat_member_tags_req)); |
|
if (!req) { accept(); return; } |
|
|
|
QByteArray ch_id_utf8 = m_channelId.toUtf8(); |
|
strncpy(req->ch_id, ch_id_utf8.constData(), sizeof(req->ch_id) - 1); |
|
req->node_id = m_nodeId; |
|
strncpy(req->json, json.toUtf8().constData(), sizeof(req->json) - 1); |
|
|
|
gui_bridge_post_uasync_fn(chat_member_tags_commit_trampoline, req); |
|
accept(); |
|
}
|
|
|