1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

Merge pull request #2346 from PKEv:save_avatar_in_DB

Save avatar in DB
add import avatars
update delete avatar action
correct import avatar for user without history
add multithreaded
make import run once
This commit is contained in:
Zetok Zalbavar 2015-10-20 21:01:20 +01:00
commit c07aee18ad
No known key found for this signature in database
GPG Key ID: C953D3880212068A
9 changed files with 162 additions and 84 deletions

View File

@ -292,7 +292,7 @@ void Core::start()
emit idSet(id); emit idSet(id);
// tox core is already decrypted // tox core is already decrypted
if (Settings::getInstance().getEnableLogging() && Nexus::getProfile()->isEncrypted()) if (Nexus::getProfile()->isEncrypted())
checkEncryptedHistory(); checkEncryptedHistory();
loadFriends(); loadFriends();
@ -329,6 +329,7 @@ void Core::start()
toxav_register_audio_callback(toxav, playCallAudio, this); toxav_register_audio_callback(toxav, playCallAudio, this);
toxav_register_video_callback(toxav, playCallVideo, this); toxav_register_video_callback(toxav, playCallVideo, this);
HistoryKeeper::getInstance()->importAvatarToDatabase(getSelfId().toString().left(64));
QPixmap pic = Settings::getInstance().getSavedAvatar(getSelfId().toString()); QPixmap pic = Settings::getInstance().getSavedAvatar(getSelfId().toString());
if (!pic.isNull() && !pic.size().isEmpty()) if (!pic.isNull() && !pic.size().isEmpty())
{ {

View File

@ -144,7 +144,6 @@ void Core::checkEncryptedHistory()
if (pw.isEmpty()) if (pw.isEmpty())
{ {
Settings::getInstance().setEnableLogging(false); Settings::getInstance().setEnableLogging(false);
HistoryKeeper::resetInstance();
return; return;
} }
else else

View File

@ -25,6 +25,7 @@
#include "widget/gui.h" #include "widget/gui.h"
#include "src/core/core.h" #include "src/core/core.h"
#include "src/persistence/settings.h" #include "src/persistence/settings.h"
#include "src/persistence/historykeeper.h"
Friend::Friend(uint32_t FriendId, const ToxId &UserId) Friend::Friend(uint32_t FriendId, const ToxId &UserId)
: userName{Core::getInstance()->getPeerName(UserId)}, : userName{Core::getInstance()->getPeerName(UserId)},
@ -39,6 +40,7 @@ Friend::Friend(uint32_t FriendId, const ToxId &UserId)
widget = new FriendWidget(friendId, getDisplayedName()); widget = new FriendWidget(friendId, getDisplayedName());
chatForm = new ChatForm(this); chatForm = new ChatForm(this);
HistoryKeeper::getInstance()->importAvatarToDatabase(UserId.publicKey);
} }
Friend::~Friend() Friend::~Friend()

View File

@ -26,17 +26,21 @@ PlainDb::PlainDb(const QString &db_name, QList<QString> initList)
{ {
db = new QSqlDatabase(); db = new QSqlDatabase();
*db = QSqlDatabase::addDatabase("QSQLITE"); *db = QSqlDatabase::addDatabase("QSQLITE");
db->setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE=1");
db->setDatabaseName(db_name); db->setDatabaseName(db_name);
if (!db->open()) if (!db->open())
{ {
qWarning() << QString("Can't open file: %1, history will not be saved!").arg(db_name); qWarning() << QString("Can't open file: %1, history will not be saved!").arg(db_name);
db->setDatabaseName(":memory:"); db->setDatabaseName(":memory:");
db->setConnectOptions();
db->open(); db->open();
} }
for (const QString &cmd : initList) for (const QString &cmd : initList)
{
db->exec(cmd); db->exec(cmd);
}
} }
PlainDb::~PlainDb() PlainDb::~PlainDb()

View File

@ -28,6 +28,7 @@
#include <QDir> #include <QDir>
#include <QSqlQuery> #include <QSqlQuery>
#include <QVariant> #include <QVariant>
#include <QBuffer>
#include <QDebug> #include <QDebug>
#include <QTemporaryFile> #include <QTemporaryFile>
@ -35,9 +36,11 @@
#include "src/persistence/db/encrypteddb.h" #include "src/persistence/db/encrypteddb.h"
static HistoryKeeper *historyInstance = nullptr; static HistoryKeeper *historyInstance = nullptr;
QMutex HistoryKeeper::historyMutex;
HistoryKeeper *HistoryKeeper::getInstance() HistoryKeeper *HistoryKeeper::getInstance()
{ {
historyMutex.lock();
if (historyInstance == nullptr) if (historyInstance == nullptr)
{ {
QList<QString> initLst; QList<QString> initLst;
@ -50,8 +53,6 @@ HistoryKeeper *HistoryKeeper::getInstance()
QString path(":memory:"); QString path(":memory:");
GenericDdInterface *dbIntf; GenericDdInterface *dbIntf;
if (Settings::getInstance().getEnableLogging())
{
if (Nexus::getProfile()->isEncrypted()) if (Nexus::getProfile()->isEncrypted())
{ {
path = getHistoryPath(); path = getHistoryPath();
@ -64,11 +65,11 @@ HistoryKeeper *HistoryKeeper::getInstance()
{ {
path = getHistoryPath(); path = getHistoryPath();
} }
}
dbIntf = new PlainDb(path, initLst); dbIntf = new PlainDb(path, initLst);
historyInstance = new HistoryKeeper(dbIntf); historyInstance = new HistoryKeeper(dbIntf);
} }
historyMutex.unlock();
return historyInstance; return historyInstance;
} }
@ -78,7 +79,7 @@ bool HistoryKeeper::checkPassword(const TOX_PASS_KEY &passkey, int encrypted)
if (!Settings::getInstance().getEnableLogging() && (encrypted == -1)) if (!Settings::getInstance().getEnableLogging() && (encrypted == -1))
return true; return true;
if ((encrypted == 1) || (encrypted == -1 && Nexus::getProfile()->isEncrypted())) if ((encrypted == 1) || (encrypted == -1))
return EncryptedDb::check(passkey, getHistoryPath(Nexus::getProfile()->getName(), encrypted)); return EncryptedDb::check(passkey, getHistoryPath(Nexus::getProfile()->getName(), encrypted));
return true; return true;
@ -95,10 +96,12 @@ HistoryKeeper::HistoryKeeper(GenericDdInterface *db_) :
name -- chat's name (for user to user conversation it is opposite user public key) name -- chat's name (for user to user conversation it is opposite user public key)
ctype -- chat type, reserved for group chats ctype -- chat type, reserved for group chats
alisases: aliases:
* user_id -> id map * user_id -> id map
id -- auto-incrementing number id -- auto-incrementing number
name -- user's public key user_id -- user's public key
av_hash -- hash of user's avatar
avatar -- user's avatar
history: history:
id -- auto-incrementing number id -- auto-incrementing number
@ -126,14 +129,33 @@ HistoryKeeper::HistoryKeeper(GenericDdInterface *db_) :
} }
} }
//check table stuct //check table stuct
ans = db->exec("PRAGMA table_info(\"history\")"); ans = db->exec("PRAGMA table_info (\"history\")");
ans.seek(5); ans.seek(5);
if (!ans.value(1).toString().contains("alias")) if (!ans.value(1).toString().contains("alias"))
{ {
//add collum in table //add collum in table
db->exec("ALTER TABLE history ADD COLUMN alias TEXT"); db->exec("ALTER TABLE history ADD COLUMN alias TEXT");
qDebug() << "Struct DB updated: Added column alias in table history.";
} }
ans.clear();
ans = db->exec("PRAGMA table_info('aliases')");
ans.seek(2);
if (!ans.value(1).toString().contains("av_hash"))
{
//add collum in table
db->exec("ALTER TABLE aliases ADD COLUMN av_hash BLOB");
qDebug() << "Struct DB updated: Added column av_hash in table aliases.";
}
ans.seek(3);
if (!ans.value(1).toString().contains("avatar"))
{
//add collum in table
needImport = true;
db->exec("ALTER TABLE aliases ADD COLUMN avatar BLOB");
qDebug() << "Struct DB updated: Added column avatar in table aliases.";
}
updateChatsID(); updateChatsID();
updateAliases(); updateAliases();
@ -146,6 +168,24 @@ HistoryKeeper::HistoryKeeper(GenericDdInterface *db_) :
messageID = sqlAnswer.value(0).toLongLong(); messageID = sqlAnswer.value(0).toLongLong();
} }
void HistoryKeeper::importAvatarToDatabase(const QString& ownerId)
{
if (needImport)
{
QString puth (Settings::getInstance().getSettingsDirPath() +
QString("avatars") + QDir::separator() +
ownerId +".png");
qDebug() << QString("Try import avatar for: %1.").arg(ownerId);
getAliasID(ownerId);
if (QFile::exists(puth) && !hasAvatar(ownerId))
{
QPixmap pic(puth);
saveAvatar(pic,ownerId);
qDebug() << QString("Import avatar for: %1.").arg(ownerId);
}
}
}
HistoryKeeper::~HistoryKeeper() HistoryKeeper::~HistoryKeeper()
{ {
delete db; delete db;
@ -455,21 +495,84 @@ bool HistoryKeeper::isFileExist()
return file.exists(); return file.exists();
} }
bool HistoryKeeper::removeHistory(int encrypted) void HistoryKeeper::removeHistory()
{ {
resetInstance(); db->exec("BEGIN TRANSACTION;");
db->exec("DELETE FROM sent_status;");
QString path = getHistoryPath(QString(), encrypted); db->exec("DELETE FROM history;");
QFile DbFile(path); db->exec("COMMIT TRANSACTION;");
return DbFile.remove();
} }
QList<HistoryKeeper::HistMessage> HistoryKeeper::exportMessagesDeleteFile(int encrypted) QList<HistoryKeeper::HistMessage> HistoryKeeper::exportMessagesDeleteFile()
{ {
auto msgs = getInstance()->exportMessages(); auto msgs = getInstance()->exportMessages();
qDebug() << "Messages exported"; qDebug() << "Messages exported";
if (!removeHistory(encrypted)) getInstance()->removeHistory();
qWarning() << "couldn't delete old log file!";
return msgs; return msgs;
} }
void HistoryKeeper::removeAvatar(const QString& ownerId)
{
QSqlQuery query;
query.prepare("UPDATE aliases SET avatar=NULL, av_hash=NULL WHERE user_id = (:id)");
query.bindValue(":id", ownerId.left(64));
query.exec();
}
bool HistoryKeeper::hasAvatar(const QString& ownerId)
{
QSqlQuery sqlAnswer = db->exec(QString("SELECT avatar FROM aliases WHERE user_id= '%1'").arg(ownerId.left(64)));
if (sqlAnswer.first() && sqlAnswer.value(0).toByteArray()!=NULL)
{
return true;
}
return false;
}
void HistoryKeeper::saveAvatar(QPixmap& pic, const QString& ownerId)
{
QByteArray bArray;
QBuffer buffer(&bArray);
buffer.open(QIODevice::WriteOnly);
pic.save(&buffer, "PNG");
QSqlQuery query;
query.prepare("UPDATE aliases SET avatar=:image WHERE user_id = (:id)");
query.bindValue(":image", bArray);
query.bindValue(":id", ownerId.left(64));
query.exec();
}
QPixmap HistoryKeeper::getSavedAvatar(const QString &ownerId)
{
QByteArray bArray;
QPixmap pixmap = QPixmap();
QSqlQuery sqlAnswer = db->exec(QString("SELECT avatar FROM aliases WHERE user_id= '%1'").arg(ownerId.left(64)));
if (sqlAnswer.first())
{
bArray = sqlAnswer.value(0).toByteArray();
pixmap.loadFromData(bArray);
}
return pixmap;
}
void HistoryKeeper::saveAvatarHash(const QByteArray& hash, const QString& ownerId)
{
QSqlQuery query;
query.prepare("UPDATE aliases SET av_hash=:hash WHERE user_id = (:id)");
query.bindValue(":hash", QString(hash.toBase64()));
query.bindValue(":id", ownerId.left(64));
query.exec();
}
QByteArray HistoryKeeper::getAvatarHash(const QString& ownerId)
{
QByteArray bArray;
QSqlQuery sqlAnswer = db->exec(QString("SELECT avatar FROM aliases WHERE user_id= '%1'").arg(ownerId.left(64)));
if (sqlAnswer.first())
{
bArray = sqlAnswer.value(0).toByteArray();
}
return bArray;
}

View File

@ -23,6 +23,8 @@
#include <QMap> #include <QMap>
#include <QList> #include <QList>
#include <QDateTime> #include <QDateTime>
#include <QPixmap>
#include <QMutex>
#include <tox/toxencryptsave.h> #include <tox/toxencryptsave.h>
class GenericDdInterface; class GenericDdInterface;
@ -32,6 +34,7 @@ class HistoryKeeper
{ {
public: public:
enum ChatType {ctSingle = 0, ctGroup}; enum ChatType {ctSingle = 0, ctGroup};
static QMutex historyMutex;
struct HistMessage struct HistMessage
{ {
@ -56,8 +59,8 @@ public:
static bool checkPassword(const TOX_PASS_KEY& passkey, int encrypted = -1); static bool checkPassword(const TOX_PASS_KEY& passkey, int encrypted = -1);
static bool isFileExist(); static bool isFileExist();
static void renameHistory(QString from, QString to); static void renameHistory(QString from, QString to);
static bool removeHistory(int encrypted = -1); void removeHistory();
static QList<HistMessage> exportMessagesDeleteFile(int encrypted = -1); static QList<HistMessage> exportMessagesDeleteFile();
void removeFriendHistory(const QString& chat); void removeFriendHistory(const QString& chat);
qint64 addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent, QString dispName); qint64 addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent, QString dispName);
@ -71,6 +74,17 @@ public:
void setSyncType(Db::syncType sType); void setSyncType(Db::syncType sType);
void saveAvatar(QPixmap& pic, const QString& ownerId);
QPixmap getSavedAvatar(const QString &ownerId);
void saveAvatarHash(const QByteArray& hash, const QString& ownerId);
QByteArray getAvatarHash(const QString& ownerId);
void removeAvatar(const QString& ownerId);
bool hasAvatar(const QString& ownerId);
void importAvatarToDatabase(const QString& ownerId); // may be deleted after all move to new db structure
private: private:
HistoryKeeper(GenericDdInterface *db_); HistoryKeeper(GenericDdInterface *db_);
HistoryKeeper(HistoryKeeper &hk) = delete; HistoryKeeper(HistoryKeeper &hk) = delete;
@ -85,7 +99,7 @@ private:
QList<QString> generateAddChatEntryCmd(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent, QString dispName); QList<QString> generateAddChatEntryCmd(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent, QString dispName);
ChatType convertToChatType(int); ChatType convertToChatType(int);
bool needImport = false; // must be deleted with "importAvatarToDatabase"
GenericDdInterface *db; GenericDdInterface *db;
QMap<QString, int> aliases; QMap<QString, int> aliases;
QMap<QString, QPair<int, ChatType>> chats; QMap<QString, QPair<int, ChatType>> chats;

View File

@ -26,6 +26,7 @@
#include "src/widget/gui.h" #include "src/widget/gui.h"
#include "src/persistence/profilelocker.h" #include "src/persistence/profilelocker.h"
#include "src/persistence/settingsserializer.h" #include "src/persistence/settingsserializer.h"
#include "src/persistence/historykeeper.h"
#include "src/nexus.h" #include "src/nexus.h"
#include "src/persistence/profile.h" #include "src/persistence/profile.h"
#ifdef QTOX_PLATFORM_EXT #ifdef QTOX_PLATFORM_EXT
@ -533,59 +534,22 @@ QString Settings::getSettingsDirPath()
QPixmap Settings::getSavedAvatar(const QString &ownerId) QPixmap Settings::getSavedAvatar(const QString &ownerId)
{ {
QDir dir(getSettingsDirPath()); return HistoryKeeper::getInstance()->getSavedAvatar(ownerId);
QString filePath = dir.filePath("avatars/"+ownerId.left(64)+".png");
QFileInfo info(filePath);
QPixmap pic;
if (!info.exists())
{
QString filePath = dir.filePath("avatar_"+ownerId.left(64));
if (!QFileInfo(filePath).exists()) // try without truncation, for old self avatars
filePath = dir.filePath("avatar_"+ownerId);
pic.load(filePath);
saveAvatar(pic, ownerId);
QFile::remove(filePath);
}
else
{
pic.load(filePath);
}
return pic;
} }
void Settings::saveAvatar(QPixmap& pic, const QString& ownerId) void Settings::saveAvatar(QPixmap& pic, const QString& ownerId)
{ {
QDir dir(getSettingsDirPath()); HistoryKeeper::getInstance()->saveAvatar(pic,ownerId);
dir.mkdir("avatars/");
// ignore nospam (good idea, and also the addFriend funcs which call getAvatar don't have it)
QString filePath = dir.filePath("avatars/"+ownerId.left(64)+".png");
pic.save(filePath, "png");
} }
void Settings::saveAvatarHash(const QByteArray& hash, const QString& ownerId) void Settings::saveAvatarHash(const QByteArray& hash, const QString& ownerId)
{ {
QDir dir(getSettingsDirPath()); HistoryKeeper::getInstance()->saveAvatarHash(hash,ownerId);
dir.mkdir("avatars/");
QFile file(dir.filePath("avatars/"+ownerId.left(64)+".hash"));
if (!file.open(QIODevice::WriteOnly))
return;
file.write(hash);
file.close();
} }
QByteArray Settings::getAvatarHash(const QString& ownerId) QByteArray Settings::getAvatarHash(const QString& ownerId)
{ {
QDir dir(getSettingsDirPath()); return HistoryKeeper::getInstance()->getAvatarHash(ownerId);
dir.mkdir("avatars/");
QFile file(dir.filePath("avatars/"+ownerId.left(64)+".hash"));
if (!file.open(QIODevice::ReadOnly))
return QByteArray();
QByteArray out = file.readAll();
file.close();
return out;
} }
const QList<DhtServer>& Settings::getDhtServerList() const const QList<DhtServer>& Settings::getDhtServerList() const

View File

@ -184,18 +184,13 @@ void ProfileForm::showProfilePictureContextMenu(const QPoint &point)
QPoint pos = profilePicture->mapToGlobal(point); QPoint pos = profilePicture->mapToGlobal(point);
QMenu contextMenu; QMenu contextMenu;
QAction *removeAction = contextMenu.addAction(tr("Remove")); QAction *removeAction = contextMenu.addAction(style()->standardIcon(QStyle::SP_DialogCancelButton), tr("Remove"));
QAction *selectedItem = contextMenu.exec(pos); QAction *selectedItem = contextMenu.exec(pos);
if (selectedItem == removeAction) if (selectedItem == removeAction)
{ {
QString selfPubKey = Core::getInstance()->getSelfId().publicKey; QString selfPubKey = Core::getInstance()->getSelfId().publicKey;
if (!QFile::remove(Settings::getInstance().getSettingsDirPath()+"avatars/"+selfPubKey.left(64)+".png")) HistoryKeeper::getInstance()->removeAvatar(selfPubKey);
{
GUI::showError(tr("Error"), tr("Could not remove avatar."));
return;
}
Core::getInstance()->setAvatar({}); Core::getInstance()->setAvatar({});
} }
} }

View File

@ -55,7 +55,6 @@ PrivacyForm::~PrivacyForm()
void PrivacyForm::onEnableLoggingUpdated() void PrivacyForm::onEnableLoggingUpdated()
{ {
Settings::getInstance().setEnableLogging(bodyUI->cbKeepHistory->isChecked()); Settings::getInstance().setEnableLogging(bodyUI->cbKeepHistory->isChecked());
HistoryKeeper::resetInstance();
Widget::getInstance()->clearAllReceipts(); Widget::getInstance()->clearAllReceipts();
if (!bodyUI->cbKeepHistory->isChecked()) if (!bodyUI->cbKeepHistory->isChecked())
{ {
@ -64,10 +63,7 @@ void PrivacyForm::onEnableLoggingUpdated()
QMessageBox::Yes|QMessageBox::No); QMessageBox::Yes|QMessageBox::No);
if (dialogDelHistory == QMessageBox::Yes) if (dialogDelHistory == QMessageBox::Yes)
{ {
if (!HistoryKeeper::removeHistory()) HistoryKeeper::getInstance()->removeHistory();
{
QMessageBox::critical(0, tr("Error"), tr("Could not delete chat history"), QMessageBox::Ok);
}
} }
} }
} }