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

View File

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

View File

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

View File

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

View File

@ -28,6 +28,7 @@
#include <QDir>
#include <QSqlQuery>
#include <QVariant>
#include <QBuffer>
#include <QDebug>
#include <QTemporaryFile>
@ -35,9 +36,11 @@
#include "src/persistence/db/encrypteddb.h"
static HistoryKeeper *historyInstance = nullptr;
QMutex HistoryKeeper::historyMutex;
HistoryKeeper *HistoryKeeper::getInstance()
{
historyMutex.lock();
if (historyInstance == nullptr)
{
QList<QString> initLst;
@ -50,25 +53,23 @@ HistoryKeeper *HistoryKeeper::getInstance()
QString path(":memory:");
GenericDdInterface *dbIntf;
if (Settings::getInstance().getEnableLogging())
if (Nexus::getProfile()->isEncrypted())
{
if (Nexus::getProfile()->isEncrypted())
{
path = getHistoryPath();
dbIntf = new EncryptedDb(path, initLst);
path = getHistoryPath();
dbIntf = new EncryptedDb(path, initLst);
historyInstance = new HistoryKeeper(dbIntf);
return historyInstance;
}
else
{
path = getHistoryPath();
}
historyInstance = new HistoryKeeper(dbIntf);
return historyInstance;
}
else
{
path = getHistoryPath();
}
dbIntf = new PlainDb(path, initLst);
historyInstance = new HistoryKeeper(dbIntf);
}
historyMutex.unlock();
return historyInstance;
}
@ -78,7 +79,7 @@ bool HistoryKeeper::checkPassword(const TOX_PASS_KEY &passkey, int encrypted)
if (!Settings::getInstance().getEnableLogging() && (encrypted == -1))
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 true;
@ -95,10 +96,12 @@ HistoryKeeper::HistoryKeeper(GenericDdInterface *db_) :
name -- chat's name (for user to user conversation it is opposite user public key)
ctype -- chat type, reserved for group chats
alisases:
aliases:
* user_id -> id map
id -- auto-incrementing number
name -- user's public key
id -- auto-incrementing number
user_id -- user's public key
av_hash -- hash of user's avatar
avatar -- user's avatar
history:
id -- auto-incrementing number
@ -126,14 +129,33 @@ HistoryKeeper::HistoryKeeper(GenericDdInterface *db_) :
}
}
//check table stuct
ans = db->exec("PRAGMA table_info(\"history\")");
ans = db->exec("PRAGMA table_info (\"history\")");
ans.seek(5);
if (!ans.value(1).toString().contains("alias"))
{
//add collum in table
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();
updateAliases();
@ -146,6 +168,24 @@ HistoryKeeper::HistoryKeeper(GenericDdInterface *db_) :
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()
{
delete db;
@ -455,21 +495,84 @@ bool HistoryKeeper::isFileExist()
return file.exists();
}
bool HistoryKeeper::removeHistory(int encrypted)
void HistoryKeeper::removeHistory()
{
resetInstance();
QString path = getHistoryPath(QString(), encrypted);
QFile DbFile(path);
return DbFile.remove();
db->exec("BEGIN TRANSACTION;");
db->exec("DELETE FROM sent_status;");
db->exec("DELETE FROM history;");
db->exec("COMMIT TRANSACTION;");
}
QList<HistoryKeeper::HistMessage> HistoryKeeper::exportMessagesDeleteFile(int encrypted)
QList<HistoryKeeper::HistMessage> HistoryKeeper::exportMessagesDeleteFile()
{
auto msgs = getInstance()->exportMessages();
qDebug() << "Messages exported";
if (!removeHistory(encrypted))
qWarning() << "couldn't delete old log file!";
getInstance()->removeHistory();
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 <QList>
#include <QDateTime>
#include <QPixmap>
#include <QMutex>
#include <tox/toxencryptsave.h>
class GenericDdInterface;
@ -32,6 +34,7 @@ class HistoryKeeper
{
public:
enum ChatType {ctSingle = 0, ctGroup};
static QMutex historyMutex;
struct HistMessage
{
@ -56,8 +59,8 @@ public:
static bool checkPassword(const TOX_PASS_KEY& passkey, int encrypted = -1);
static bool isFileExist();
static void renameHistory(QString from, QString to);
static bool removeHistory(int encrypted = -1);
static QList<HistMessage> exportMessagesDeleteFile(int encrypted = -1);
void removeHistory();
static QList<HistMessage> exportMessagesDeleteFile();
void removeFriendHistory(const QString& chat);
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 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:
HistoryKeeper(GenericDdInterface *db_);
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);
ChatType convertToChatType(int);
bool needImport = false; // must be deleted with "importAvatarToDatabase"
GenericDdInterface *db;
QMap<QString, int> aliases;
QMap<QString, QPair<int, ChatType>> chats;

View File

@ -26,6 +26,7 @@
#include "src/widget/gui.h"
#include "src/persistence/profilelocker.h"
#include "src/persistence/settingsserializer.h"
#include "src/persistence/historykeeper.h"
#include "src/nexus.h"
#include "src/persistence/profile.h"
#ifdef QTOX_PLATFORM_EXT
@ -533,59 +534,22 @@ QString Settings::getSettingsDirPath()
QPixmap Settings::getSavedAvatar(const QString &ownerId)
{
QDir dir(getSettingsDirPath());
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;
return HistoryKeeper::getInstance()->getSavedAvatar(ownerId);
}
void Settings::saveAvatar(QPixmap& pic, const QString& ownerId)
{
QDir dir(getSettingsDirPath());
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");
HistoryKeeper::getInstance()->saveAvatar(pic,ownerId);
}
void Settings::saveAvatarHash(const QByteArray& hash, const QString& ownerId)
{
QDir dir(getSettingsDirPath());
dir.mkdir("avatars/");
QFile file(dir.filePath("avatars/"+ownerId.left(64)+".hash"));
if (!file.open(QIODevice::WriteOnly))
return;
file.write(hash);
file.close();
HistoryKeeper::getInstance()->saveAvatarHash(hash,ownerId);
}
QByteArray Settings::getAvatarHash(const QString& ownerId)
{
QDir dir(getSettingsDirPath());
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;
return HistoryKeeper::getInstance()->getAvatarHash(ownerId);
}
const QList<DhtServer>& Settings::getDhtServerList() const

View File

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

View File

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