Save hide state in db

master
Jonas Letzbor 2022-10-06 18:31:38 +02:00
parent 6f54ccd44c
commit 2f84fec1a9
11 changed files with 182 additions and 47 deletions

View File

@ -85,6 +85,7 @@ include_directories(
)
TARGET_LINK_LIBRARIES (Nextcloud.app PRIVATE inkview freetype curl sqlite3 stdc++fs)
target_compile_definitions(Nextcloud.app PRIVATE DBVERSION=2 PROGRAMVERSION="1.02")
INSTALL (TARGETS Nextcloud.app)

View File

@ -21,6 +21,12 @@ using std::string;
SqliteConnector::SqliteConnector(const string &DBpath) : _dbpath(DBpath)
{
_fileHandler = std::shared_ptr<FileHandler>(new FileHandler());
// check if migration has to be run
int currentVersion = getDbVersion();
if (currentVersion != DBVERSION) {
runMigration(currentVersion);
}
}
SqliteConnector::~SqliteConnector()
@ -30,6 +36,74 @@ SqliteConnector::~SqliteConnector()
Log::writeInfoLog("closed DB");
}
void SqliteConnector::runMigration(int currentVersion)
{
open();
char* log;
sprintf(log, "Running migration from db version %i to %i (Program version %s)", currentVersion, DBVERSION, PROGRAMVERSION);
Log::writeInfoLog(log);
// currently there are no migrations
// updating to current version
int rs;
sqlite3_stmt *stmt = 0;
rs = sqlite3_prepare_v2(_db, "INSERT INTO 'version' (dbversion) VALUES (?)", -1, &stmt, 0);
rs = sqlite3_bind_int(stmt, 1, DBVERSION);
rs = sqlite3_step(stmt);
if (rs != SQLITE_DONE) {
// this is critical
Log::writeErrorLog(std::string("error inserting into version") + sqlite3_errmsg(_db) + std::string(" (Error Code: ") + std::to_string(rs) + ")");
}
sqlite3_finalize(stmt);
sqlite3_close(_db);
}
int SqliteConnector::getDbVersion()
{
open();
int rs;
sqlite3_stmt *stmt = 0;
int version;
rs = sqlite3_prepare_v2(_db, "SELECT MAX(dbversion) FROM 'version'", -1, &stmt, 0);
while (sqlite3_step(stmt) == SQLITE_ROW)
{
version = sqlite3_column_int(stmt, 0);
}
if (version != 0)
{
sqlite3_finalize(stmt);
sqlite3_close(_db);
return version;
} else {
// this is probably the first start -> the version is up to date and insert the current version
rs = sqlite3_prepare_v2(_db, "INSERT INTO 'version' (dbversion) VALUES (?)", -1, &stmt, 0);
rs = sqlite3_bind_int(stmt, 1, DBVERSION);
rs = sqlite3_step(stmt);
if (rs != SQLITE_DONE) {
Log::writeErrorLog(std::string("error inserting into version") + sqlite3_errmsg(_db) + std::string(" (Error Code: ") + std::to_string(rs) + ")");
}
rs = sqlite3_clear_bindings(stmt);
rs = sqlite3_reset(stmt);
// for compatibility alter the table because at this point db migrations doesn't exist
rs = sqlite3_exec(_db, "ALTER TABLE metadata ADD hide INT DEFAULT 0 NOT NULL", NULL, 0, NULL);
sqlite3_finalize(stmt);
sqlite3_close(_db);
return DBVERSION;
}
}
bool SqliteConnector::open()
{
int rs;
@ -42,7 +116,8 @@ bool SqliteConnector::open()
return false;
}
rs = sqlite3_exec(_db, "CREATE TABLE IF NOT EXISTS metadata (title VARCHAR, localPath VARCHAR, size VARCHAR, fileType VARCHAR, lasteditDate VARCHAR, type INT, state INT, etag VARCHAR, path VARCHAR PRIMARY KEY, parentPath VARCHAR)", NULL, 0, NULL);
rs = sqlite3_exec(_db, "CREATE TABLE IF NOT EXISTS metadata (title VARCHAR, localPath VARCHAR, size VARCHAR, fileType VARCHAR, lasteditDate VARCHAR, type INT, state INT, etag VARCHAR, path VARCHAR PRIMARY KEY, parentPath VARCHAR, hide INT DEFAULT 0 NOT NULL)", NULL, 0, NULL);
rs = sqlite3_exec(_db, "CREATE TABLE IF NOT EXISTS version (dbversion INT)", NULL, 0, NULL);
return true;
}
@ -123,13 +198,16 @@ std::vector<WebDAVItem> SqliteConnector::getItemsChildren(const string &parentPa
int rs;
sqlite3_stmt *stmt = 0;
std::vector<WebDAVItem> items;
std::vector<WebDAVItem> itemsToRemove;
rs = sqlite3_prepare_v2(_db, "SELECT title, localPath, path, size, etag, fileType, lastEditDate, type, state FROM 'metadata' WHERE path=? OR parentPath=? ORDER BY parentPath;", -1, &stmt, 0);
rs = sqlite3_prepare_v2(
_db,
"SELECT title, localPath, path, size, etag, fileType, lastEditDate, type, state, hide FROM 'metadata' WHERE (path=? OR parentPath=?) AND hide <> 2 ORDER BY parentPath;",
-1, &stmt, 0
);
rs = sqlite3_bind_text(stmt, 1, parentPath.c_str(), parentPath.length(), NULL);
rs = sqlite3_bind_text(stmt, 2, parentPath.c_str(), parentPath.length(), NULL);
const int storageLocationLength = (NEXTCLOUD_ROOT_PATH + _fileHandler->getStorageUsername() + "/").length();
const string storageLocation = NEXTCLOUD_ROOT_PATH + _fileHandler->getStorageUsername() + "/";
while (sqlite3_step(stmt) == SQLITE_ROW)
{
WebDAVItem temp;
@ -143,6 +221,7 @@ std::vector<WebDAVItem> SqliteConnector::getItemsChildren(const string &parentPa
temp.lastEditDate = Util::webDAVStringToTm(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 6)));
temp.type = static_cast<Itemtype>(sqlite3_column_int(stmt,7));
temp.state = static_cast<FileState>(sqlite3_column_int(stmt,8));
temp.hide = static_cast<HideState>(sqlite3_column_int(stmt,9));
if (iv_access(temp.localPath.c_str(), W_OK) != 0)
{
@ -150,33 +229,15 @@ std::vector<WebDAVItem> SqliteConnector::getItemsChildren(const string &parentPa
temp.state = FileState::ICLOUD;
}
string direcotryPath = temp.path;
if (direcotryPath.length() >= storageLocationLength) {
direcotryPath = direcotryPath.substr(storageLocationLength);
if (temp.hide == HideState::INOTDEFINED) {
temp.hide = _fileHandler->getHideState(temp.type, storageLocation, temp.path, temp.title);
}
if (temp.type == Itemtype::IFILE && ( _fileHandler->excludeFolder(direcotryPath) || _fileHandler->excludeFile(temp.title))) {
//The file was previously cached and should be excluded from now on
//TODO Maybe an SQL statement with REGEX match should be executed directly after changing the conifg
itemsToRemove.push_back(temp);
} else if (temp.type == Itemtype::IFOLDER && _fileHandler->excludeFolder(direcotryPath)) {
itemsToRemove.push_back(temp);
}
else {
items.push_back(temp);
}
}
sqlite3_finalize(stmt);
sqlite3_close(_db);
for (WebDAVItem itemD : itemsToRemove) {
if (itemD.type == Itemtype::IFOLDER) {
deleteChildren(itemD.path);
} else {
deleteChild(itemD.path, itemD.title);
}
}
return items;
}
@ -199,6 +260,28 @@ void SqliteConnector::deleteChild(const string &path, const string &title)
}
bool SqliteConnector::resetHideState()
{
open();
int rs;
sqlite3_stmt *stmt = 0;
rs = sqlite3_prepare_v2(_db, "UPDATE 'metadata' SET hide=0", -1, &stmt, 0);
rs = sqlite3_step(stmt);
if (rs != SQLITE_DONE)
{
Log::writeErrorLog(sqlite3_errmsg(_db) + std::string(" (Error Code: ") + std::to_string(rs) + ")");
}
rs = sqlite3_clear_bindings(stmt);
rs = sqlite3_reset(stmt);
sqlite3_finalize(stmt);
sqlite3_close(_db);
return true;
}
void SqliteConnector::deleteChildren(const string &parentPath)
{
//TODO missing the onces where parentPath is one folder deeper and also destroyed
@ -232,7 +315,7 @@ bool SqliteConnector::saveItemsChildren(const std::vector<WebDAVItem> &items)
for (auto item : items)
{
rs = sqlite3_prepare_v2(_db, "INSERT INTO 'metadata' (title, localPath, path, size, parentPath, etag, fileType, lastEditDate, type, state) VALUES (?,?,?,?,?,?,?,?,?,?);", -1, &stmt, 0);
rs = sqlite3_prepare_v2(_db, "INSERT INTO 'metadata' (title, localPath, path, size, parentPath, etag, fileType, lastEditDate, type, state, hide) VALUES (?,?,?,?,?,?,?,?,?,?,?);", -1, &stmt, 0);
rs = sqlite3_exec(_db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
rs = sqlite3_bind_text(stmt, 1, item.title.c_str(), item.title.length(), NULL);
rs = sqlite3_bind_text(stmt, 2, item.localPath.c_str(), item.localPath.length(), NULL);
@ -245,6 +328,7 @@ bool SqliteConnector::saveItemsChildren(const std::vector<WebDAVItem> &items)
rs = sqlite3_bind_text(stmt, 8, lastEditDateString.c_str(), lastEditDateString.length(), NULL);
rs = sqlite3_bind_int(stmt, 9, item.type);
rs = sqlite3_bind_int(stmt, 10, item.state);
rs = sqlite3_bind_int(stmt, 11, item.hide);
rs = sqlite3_step(stmt);
if (rs == SQLITE_CONSTRAINT)

View File

@ -31,6 +31,10 @@ public:
bool open();
int getDbVersion();
void runMigration(int currentVersion);
std::string getEtag(const std::string &path);
FileState getState(const std::string &path);
@ -43,6 +47,8 @@ public:
void deleteChild(const std::string &path, const std::string &title);
bool resetHideState();
bool saveItemsChildren(const std::vector<WebDAVItem> &children);
private:

View File

@ -115,6 +115,7 @@ vector<WebDAVItem> WebDAV::getDataStructure(const string &pathUrl)
size_t begin = xmlItem.find(beginItem);
size_t end;
string prefix = NEXTCLOUD_ROOT_PATH + _username + "/";
while (begin != std::string::npos)
{
end = xmlItem.find(endItem);
@ -183,20 +184,11 @@ vector<WebDAVItem> WebDAV::getDataStructure(const string &pathUrl)
tempItem.title = tempItem.title.substr(tempItem.title.find_last_of("/") + 1, tempItem.title.length());
Util::decodeUrl(tempItem.title);
string folderPath = tempItem.path;
string prefix = NEXTCLOUD_ROOT_PATH + _username + "/";
if (tempItem.path.find(prefix) != string::npos) {
folderPath = tempItem.path.substr(prefix.length());
if (tempItem.type == Itemtype::IFILE && folderPath.length() >= tempItem.title.length()) {
folderPath = folderPath.substr(0, folderPath.length() - tempItem.title.length());
}
}
string &pathDecoded = tempItem.path;
Util::decodeUrl(pathDecoded);
tempItem.hide = _fileHandler->getHideState(tempItem.type, prefix,(pathDecoded), tempItem.title);
if (tempItem.type == Itemtype::IFILE && ( !_fileHandler->excludeFolder(folderPath) && !_fileHandler->excludeFile(tempItem.title) ))
tempItems.push_back(tempItem);
else if (tempItem.type == Itemtype::IFOLDER && !_fileHandler->excludeFolder(folderPath))
tempItems.push_back(tempItem);
xmlItem = xmlItem.substr(end + endItem.length());
begin = xmlItem.find(beginItem);
}

View File

@ -28,6 +28,13 @@ enum FileState
IDOWNLOADED
};
enum HideState
{
INOTDEFINED,
ISHOW,
IHIDE
};
struct WebDAVItem : Entry{
std::string etag;
std::string path;
@ -38,6 +45,7 @@ struct WebDAVItem : Entry{
tm lastEditDate = { 0 };
std::string size;
std::string fileType;
HideState hide;
};
#endif

View File

@ -251,7 +251,8 @@ void EventHandler::mainMenuHandler(const int index)
//Info
case 106:
{
Message(ICON_INFORMATION, "Info", "Version 1.02 \n For support please open a ticket at https://github.com/JuanJakobo/Pocketbook-Nextcloud-Client/issues", 1200);
string message;
Message(ICON_INFORMATION, "Info", message.append("Version ").append(PROGRAMVERSION).append("\nFor support please open a ticket at https://github.com/JuanJakobo/Pocketbook-Nextcloud-Client/issues").c_str(), 1200);
break;
}
//Exit
@ -388,6 +389,7 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2)
Util::accessConfig<string>(Action::IWriteString, "ex_pattern",_excludeFileView->getRegex());
Util::accessConfig<string>(Action::IWriteString, "ex_folderPattern",_excludeFileView->getFolderRegex());
Util::accessConfig<int>(Action::IWriteInt, "ex_invertMatch", _excludeFileView->getInvertMatch());
_sqllite.resetHideState();
_excludeFileView.reset();
ShowHourglassForce();
@ -655,6 +657,10 @@ void EventHandler::getLocalFileStructure(std::vector<WebDAVItem> &tempItems)
void EventHandler::downloadFolder(vector<WebDAVItem> &items, int itemID)
{
//Don't sync hidden files
if (items.at(itemID).hide == HideState::IHIDE)
return;
//BanSleep(2000);
string path = items.at(itemID).path;

View File

@ -9,6 +9,7 @@
#include "fileHandler.h"
#include "log.h"
#include "util.h"
#include "webDAVModel.h"
#include <sstream>
#include <regex>
@ -124,6 +125,33 @@ bool FileHandler::excludeFolder(std::string folderName) {
return _invertMatch;
}
HideState FileHandler::getHideState(Itemtype itemType, std::string prefix, std::string path, std::string title = "") {
string folderPath = path;
if (path.find(prefix) != string::npos) {
folderPath = path.substr(prefix.length());
if (itemType == Itemtype::IFILE && folderPath.length() >= title.length()) {
folderPath = folderPath.substr(0, folderPath.length() - title.length());
}
}
folderPath = "/" + folderPath;
if (itemType == Itemtype::IFILE) {
if (!excludeFolder(folderPath) && !excludeFile(title)) {
return HideState::ISHOW;
} else {
return HideState::IHIDE;
}
} else {
if (!excludeFolder(folderPath)) {
return HideState::ISHOW;
} else {
return HideState::IHIDE;
}
}
}
void FileHandler::update(string regex, string folderRegex, string extensions, int invertMatch) {
for (FileHandler *handler : _instances) {
handler->parseConfig(regex, folderRegex, extensions, invertMatch);

View File

@ -9,6 +9,8 @@
#ifndef FILEHANDLER
#define FILEHANDLER
#include "webDAVModel.h"
#include <regex>
#include <string>
#include <vector>
@ -22,6 +24,7 @@ class FileHandler
~FileHandler();
bool excludeFile(std::string filename);
bool excludeFolder(std::string foldername);
HideState getHideState(Itemtype itemType, std::string prefixToStripe, std::string path, std::string title);
std::string getStorageLocation();
std::string getStorageUsername();

View File

@ -14,10 +14,10 @@
using std::string;
std::shared_ptr<ExcludeFileView> ExcludeFileView::_excludeFileViewStatic;
ExcludeFileView* ExcludeFileView::_excludeFileViewStatic;
ExcludeFileView::ExcludeFileView(const irect &contentRect): _contentRect(contentRect)
{
_excludeFileViewStatic.reset(this);
_excludeFileViewStatic = this;
_extensionList = Util::getConfig<string>("ex_extensionList", "");
_regex = Util::getConfig<string>("ex_pattern", "");
@ -77,6 +77,7 @@ ExcludeFileView::ExcludeFileView(const irect &contentRect): _contentRect(content
ExcludeFileView::~ExcludeFileView()
{
CloseFont(_font);
// Pointer cannot be freeded... It would crash when optining the window >~ 2 times (as well as an shared_ptr)
}
int ExcludeFileView::excludeClicked(int x, int y)
@ -176,8 +177,8 @@ void ExcludeFileView::keyboardHandler(char *text)
return;
string s(text);
if (s.empty())
return;
//if (s.empty())
// return;
if (_target == ExcludeFileKeyboardTarget::IEXTENSIONS)
{

View File

@ -54,7 +54,7 @@ public:
int getInvertMatch() { return _invertMatch; };
private:
static std::shared_ptr<ExcludeFileView> _excludeFileViewStatic;
static ExcludeFileView *_excludeFileViewStatic;
int _fontHeight;
ifont *_font;
const irect _contentRect;

View File

@ -17,8 +17,14 @@
using std::vector;
WebDAVView::WebDAVView(const irect &contentRect, vector<WebDAVItem> &items, int page) : ListView(contentRect, page)
WebDAVView::WebDAVView(const irect &contentRect, vector<WebDAVItem> &itemsUnfiltered, int page) : ListView(contentRect, page)
{
vector<WebDAVItem> items;
std::copy_if (itemsUnfiltered.begin(), itemsUnfiltered.end(), std::back_inserter(items), [](WebDAVItem i)
{
return i.hide != HideState::IHIDE;
});
auto pageHeight = 0;
auto contentHeight = _contentRect.h - _footerHeight;
auto entrycount = items.size();