Hello community, here is the log from the commit of package leechcraft for openSUSE:Factory checked in at 2020-04-02 17:43:19 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/leechcraft (Old) and /work/SRC/openSUSE:Factory/.leechcraft.new.3248 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "leechcraft" Thu Apr 2 17:43:19 2020 rev:57 rq:790703 version:0.6.70+git.13641.g995b95b3d4 Changes: -------- --- /work/SRC/openSUSE:Factory/leechcraft/leechcraft-doc.changes 2020-02-04 19:52:54.897306261 +0100 +++ /work/SRC/openSUSE:Factory/.leechcraft.new.3248/leechcraft-doc.changes 2020-04-02 17:43:22.785397159 +0200 @@ -1,0 +2,6 @@ +Tue Mar 31 17:33:47 UTC 2020 - Dmitriy Perlow <dap.darkn...@gmail.com> + +- Updated to 0.6.70-13641-g995b95b3d4 snapshot: + * There will not be source-url till Saturday. + +------------------------------------------------------------------- --- /work/SRC/openSUSE:Factory/leechcraft/leechcraft.changes 2020-03-11 18:56:12.711698101 +0100 +++ /work/SRC/openSUSE:Factory/.leechcraft.new.3248/leechcraft.changes 2020-04-02 17:43:22.841397202 +0200 @@ -1,0 +2,7 @@ +Tue Mar 31 17:33:47 UTC 2020 - Dmitriy Perlow <dap.darkn...@gmail.com> + +- Updated to 0.6.70-13641-g995b95b3d4 snapshot: + * MaxMindDB instead of GeoIP; + * There will not be source-url till Saturday. + +------------------------------------------------------------------- Old: ---- leechcraft-0.6.70-13605-g8cd066ad6a.tar.xz New: ---- leechcraft-0.6.70-13641-g995b95b3d4.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ leechcraft-doc.spec ++++++ --- /var/tmp/diff_new_pack.6SX5wU/_old 2020-04-02 17:43:23.561397761 +0200 +++ /var/tmp/diff_new_pack.6SX5wU/_new 2020-04-02 17:43:23.561397761 +0200 @@ -1,7 +1,7 @@ # # spec file for package leechcraft-doc # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2020 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,20 +12,20 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via https://bugs.opensuse.org/ +# Please submit bugfixes or comments via http://bugs.opensuse.org/ # -%define LEECHCRAFT_VERSION 0.6.70-13605-g8cd066ad6a +%define LEECHCRAFT_VERSION 0.6.70-13641-g995b95b3d4 Name: leechcraft-doc -Version: 0.6.70+git.13605.g8cd066ad6a +Version: 0.6.70+git.13641.g995b95b3d4 Release: 0 Summary: Modular Internet Client Documentation License: BSL-1.0 Group: Development/Libraries/Other URL: http://leechcraft.org -Source0: https://dist.leechcraft.org/LeechCraft/0.6.75/leechcraft-%{LEECHCRAFT_VERSION}.tar.xz +Source0: leechcraft-%{LEECHCRAFT_VERSION}.tar.xz BuildRequires: doxygen >= 1.8.3.1 BuildRequires: fdupes ++++++ leechcraft.spec ++++++ --- /var/tmp/diff_new_pack.6SX5wU/_old 2020-04-02 17:43:23.581397776 +0200 +++ /var/tmp/diff_new_pack.6SX5wU/_new 2020-04-02 17:43:23.585397779 +0200 @@ -1,7 +1,7 @@ # # spec file for package leechcraft # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2020 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,7 +12,7 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via https://bugs.opensuse.org/ +# Please submit bugfixes or comments via http://bugs.opensuse.org/ # @@ -24,7 +24,7 @@ %define qml_dir %{_datadir}/leechcraft/qml5 %define so_ver -qt5-0_6_75 -%define LEECHCRAFT_VERSION 0.6.70-13605-g8cd066ad6a +%define LEECHCRAFT_VERSION 0.6.70-13641-g995b95b3d4 %define db_postfix %{so_ver}_1 %define gui_postfix %{so_ver}_1 @@ -43,14 +43,14 @@ %define xsd_postfix %{so_ver} Name: leechcraft -Version: 0.6.70+git.13605.g8cd066ad6a +Version: 0.6.70+git.13641.g995b95b3d4 Release: 0 Summary: Modular Internet Client License: BSL-1.0 Group: Productivity/Networking/Other URL: http://leechcraft.org -Source0: https://dist.leechcraft.org/LeechCraft/0.6.75/leechcraft-%{LEECHCRAFT_VERSION}.tar.xz +Source0: leechcraft-%{LEECHCRAFT_VERSION}.tar.xz Source4: %{name}-rpmlintrc Source8: leechcraft-session.1 Source9: lc_plugin_wrapper-qt5.1 @@ -125,6 +125,7 @@ BuildRequires: pkgconfig(libcurl) BuildRequires: pkgconfig(libguess) BuildRequires: pkgconfig(libidn) +BuildRequires: pkgconfig(libmaxminddb) BuildRequires: pkgconfig(libmtp) BuildRequires: pkgconfig(libnl-3.0) BuildRequires: pkgconfig(libotr) @@ -2428,6 +2429,7 @@ -DENABLE_TEXTOGROOSE=True \ %ifarch %ix86 x86_64 %arm ppc64le -DENABLE_TORRENT=True \ + -DENABLE_BITTORRENT_GEOIP=True \ %else -DENABLE_TORRENT=False \ %endif ++++++ _service ++++++ --- /var/tmp/diff_new_pack.6SX5wU/_old 2020-04-02 17:43:23.621397807 +0200 +++ /var/tmp/diff_new_pack.6SX5wU/_new 2020-04-02 17:43:23.621397807 +0200 @@ -1,7 +1,7 @@ <services> <service name="verify_file" mode="buildtime"> - <param name="file">leechcraft-0.6.70-13605-g8cd066ad6a.tar.xz</param> + <param name="file">leechcraft-0.6.70-13641-g995b95b3d4.tar.xz</param> <param name="verifier">sha1</param> - <param name="checksum">91b4699050fe165378998fc525057d99a4f3ec4e</param> + <param name="checksum">6386baadc409762f05bc4b16089bdb96f19c9fcd</param> </service> </services> ++++++ leechcraft-0.6.70-13605-g8cd066ad6a.tar.xz -> leechcraft-0.6.70-13641-g995b95b3d4.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/core/CMakeLists.txt new/leechcraft-0.6.70-13641-g995b95b3d4/src/core/CMakeLists.txt --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/core/CMakeLists.txt 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/core/CMakeLists.txt 2020-03-31 20:44:18.000000000 +0200 @@ -94,6 +94,7 @@ loadprocessbase.cpp loadprogressreporter.cpp splashscreen.cpp + tagsstorage.cpp loaders/ipluginloader.cpp loaders/sopluginloader.cpp ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/core/tagsmanager.cpp new/leechcraft-0.6.70-13641-g995b95b3d4/src/core/tagsmanager.cpp --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/core/tagsmanager.cpp 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/core/tagsmanager.cpp 2020-03-31 20:44:18.000000000 +0200 @@ -31,18 +31,24 @@ #include <stdexcept> #include <algorithm> #include <QStringList> -#include <QSettings> #include <QCoreApplication> +#include <QSettings> #include <QtDebug> #include <util/sll/prelude.h> +#include <util/sll/qtutil.h> #include <util/tags/tagscompleter.h> using namespace LC; TagsManager::TagsManager () { - ReadSettings (); + MigrateToDb (); + + for (const auto& [id, name] : Storage_.GetAllTags ()) + Tags_ [id] = name; + GetID (tr ("untagged")); + Util::TagsCompleter::SetModel (GetModel ()); } @@ -110,13 +116,12 @@ QStringList TagsManager::Split (const QString& string) const { return Util::Map (string.split (";", QString::SkipEmptyParts), - [] (const QString& s) { return s.trimmed (); }); // TODO gcc 6 + [] (QString& s) { return std::move (s).trimmed (); }); } -QStringList TagsManager::SplitToIDs (const QString& string) +QList<ITagsManager::tag_id> TagsManager::SplitToIDs (const QString& string) { - return Util::Map (Split (string), - [this] (const QString& tag) { return GetID (tag.simplified ()); }); // TODO gcc 6 + return GetIDs (Split (string)); } QString TagsManager::Join (const QStringList& tags) const @@ -135,6 +140,8 @@ { const auto& uuid = QUuid::createUuid (); + Storage_.AddTag (uuid, tag); + auto updated = Tags_; auto pos = updated.insert (uuid, tag); const auto dist = std::distance (updated.begin (), pos); @@ -143,8 +150,6 @@ Tags_ = std::move (updated); endInsertRows (); - WriteSettings (); - emit tagsUpdated (GetAllTags ()); return uuid.toString (); @@ -155,10 +160,14 @@ if (!index.isValid ()) return; + const auto pos = Tags_.begin () + index.row (); + + Storage_.DeleteTag (pos.key ()); + beginRemoveRows (QModelIndex (), index.row (), index.row ()); - Tags_.erase (Tags_.begin () + index.row ()); + Tags_.erase (pos); endRemoveRows (); - WriteSettings (); + emit tagsUpdated (GetAllTags ()); } @@ -170,9 +179,9 @@ auto pos = Tags_.begin () + index.row (); *pos = newTag; - emit dataChanged (index, index); + Storage_.SetTagName (pos.key (), newTag); - WriteSettings (); + emit dataChanged (index, index); emit tagsUpdated (GetAllTags ()); } @@ -187,26 +196,21 @@ return this; } -void TagsManager::ReadSettings () +// TODO post 0.6.75 drop this +void TagsManager::MigrateToDb () { QSettings settings (QCoreApplication::organizationName (), QCoreApplication::applicationName ()); settings.beginGroup ("Tags"); - Tags_ = settings.value ("Dict").value<TagsDictionary_t> (); - if (!Tags_.isEmpty ()) + if (!settings.value ("Migrated").toBool ()) { - beginInsertRows (QModelIndex (), 0, Tags_.size () - 1); - endInsertRows (); - } - settings.endGroup (); -} + const auto& tags = settings.value ("Dict").value<TagsDictionary_t> (); -void TagsManager::WriteSettings () const -{ - QSettings settings (QCoreApplication::organizationName (), - QCoreApplication::applicationName ()); - settings.beginGroup ("Tags"); - settings.setValue ("Dict", QVariant::fromValue<TagsDictionary_t> (Tags_)); + qDebug () << Q_FUNC_INFO << "migrating" << tags.size () << "tags to the DB"; + + for (const auto& [id, name] : Util::Stlize (tags)) + Storage_.AddTag (id, name); + settings.setValue ("Migrated", true); + } settings.endGroup (); } - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/core/tagsmanager.h new/leechcraft-0.6.70-13641-g995b95b3d4/src/core/tagsmanager.h --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/core/tagsmanager.h 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/core/tagsmanager.h 2020-03-31 20:44:18.000000000 +0200 @@ -35,6 +35,7 @@ #include <QString> #include <QMetaType> #include "interfaces/core/itagsmanager.h" +#include "tagsstorage.h" namespace LC { @@ -49,31 +50,31 @@ typedef QMap<QUuid, QString> TagsDictionary_t; private: TagsDictionary_t Tags_; + TagsStorage Storage_; public: static TagsManager& Instance (); - int columnCount (const QModelIndex&) const; - QVariant data (const QModelIndex&, int) const; - QModelIndex index (int, int, const QModelIndex&) const; - QModelIndex parent (const QModelIndex&) const; - int rowCount (const QModelIndex&) const; + int columnCount (const QModelIndex&) const override; + QVariant data (const QModelIndex&, int) const override; + QModelIndex index (int, int, const QModelIndex&) const override; + QModelIndex parent (const QModelIndex&) const override; + int rowCount (const QModelIndex&) const override; - tag_id GetID (const QString&); - QString GetTag (tag_id) const; - QStringList GetAllTags () const; - QStringList Split (const QString&) const; - QStringList SplitToIDs (const QString&); - QString Join (const QStringList&) const; - QString JoinIDs (const QStringList&) const; - QAbstractItemModel* GetModel (); - QObject* GetQObject (); + tag_id GetID (const QString&) override; + QString GetTag (tag_id) const override; + QStringList GetAllTags () const override; + QStringList Split (const QString&) const override; + QList<tag_id> SplitToIDs (const QString&) override; + QString Join (const QStringList&) const override; + QString JoinIDs (const QStringList&) const override; + QAbstractItemModel* GetModel () override; + QObject* GetQObject () override; void RemoveTag (const QModelIndex&); void SetTag (const QModelIndex&, const QString&); private: tag_id InsertTag (const QString&); - void ReadSettings (); - void WriteSettings () const; + void MigrateToDb (); signals: void tagsUpdated (const QStringList&); }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/core/tagsstorage.cpp new/leechcraft-0.6.70-13641-g995b95b3d4/src/core/tagsstorage.cpp --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/core/tagsstorage.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/core/tagsstorage.cpp 2020-03-31 20:44:18.000000000 +0200 @@ -0,0 +1,104 @@ +/********************************************************************** + * LeechCraft - modular cross-platform feature rich internet client. + * Copyright (C) 2006-2014 Georg Rudoy + * + * Boost Software License - Version 1.0 - August 17th, 2003 + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **********************************************************************/ + +#include "tagsstorage.h" +#include <QDir> +#include <QSqlError> +#include <util/db/oral/oral.h> +#include <util/db/dblock.h> +#include <util/db/util.h> +#include <util/sll/prelude.h> +#include <util/sys/paths.h> + +namespace LC +{ + struct TagsStorage::Record + { + Util::oral::Unique<Util::oral::NotNull<QByteArray>> Id_; + Util::oral::NotNull<QString> Name_; + + static QString ClassName () + { + return "Tags"; + } + }; +} + +BOOST_FUSION_ADAPT_STRUCT (LC::TagsStorage::Record, + Id_, + Name_) + +namespace LC +{ + namespace sph = Util::oral::sph; + + TagsStorage::TagsStorage (QObject *parent) + : QObject { parent } + , DB_ { QSqlDatabase::addDatabase ("QSQLITE", + Util::GenConnectionName ("org.LeechCraft.Core.TagsStorage")) } + { + const auto& coreDir = Util::GetUserDir (Util::UserDir::LC, "core"); + DB_.setDatabaseName (coreDir.filePath ("core.db")); + + if (!DB_.open ()) + { + qWarning () << Q_FUNC_INFO + << "cannot open the database"; + Util::DBLock::DumpError (DB_.lastError ()); + throw std::runtime_error { "Cannot create database" }; + } + + Util::RunTextQuery (DB_, "PRAGMA synchronous = NORMAL;"); + Util::RunTextQuery (DB_, "PRAGMA journal_mode = WAL;"); + + Record_ = Util::oral::AdaptPtr<Record> (DB_); + } + + void TagsStorage::AddTag (const Id& id, const QString& name) + { + Record_->Insert ({ id.toByteArray (), name }); + } + + void TagsStorage::DeleteTag (const Id& id) + { + Record_->DeleteBy (sph::f<&Record::Id_> == id.toByteArray ()); + } + + void TagsStorage::SetTagName (const Id& id, const QString& newName) + { + Record_->Update (sph::f<&Record::Name_> = newName, + sph::f<&Record::Id_> == id.toByteArray ()); + } + + QList<QPair<TagsStorage::Id, QString>> TagsStorage::GetAllTags () const + { + return Util::Map (Record_->Select (), + [] (const Record& rec) { return QPair { QUuid { QString::fromLatin1 (**rec.Id_) }, *rec.Name_ }; }); + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/core/tagsstorage.h new/leechcraft-0.6.70-13641-g995b95b3d4/src/core/tagsstorage.h --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/core/tagsstorage.h 1970-01-01 01:00:00.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/core/tagsstorage.h 2020-03-31 20:44:18.000000000 +0200 @@ -0,0 +1,60 @@ +/********************************************************************** + * LeechCraft - modular cross-platform feature rich internet client. + * Copyright (C) 2006-2014 Georg Rudoy + * + * Boost Software License - Version 1.0 - August 17th, 2003 + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **********************************************************************/ + +#pragma once + +#include <optional> +#include <QObject> +#include <QUuid> +#include <QString> +#include <QList> +#include <QSqlDatabase> +#include <util/db/oral/oralfwd.h> + +namespace LC +{ + class TagsStorage : public QObject + { + public: + struct Record; + private: + QSqlDatabase DB_; + + Util::oral::ObjectInfo_ptr<Record> Record_; + public: + explicit TagsStorage (QObject* = nullptr); + + using Id = QUuid; + + void AddTag (const Id&, const QString&); + void DeleteTag (const Id&); + void SetTagName (const Id&, const QString&); + QList<QPair<Id, QString>> GetAllTags () const; + }; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/interfaces/core/itagsmanager.h new/leechcraft-0.6.70-13641-g995b95b3d4/src/interfaces/core/itagsmanager.h --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/interfaces/core/itagsmanager.h 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/interfaces/core/itagsmanager.h 2020-03-31 20:44:18.000000000 +0200 @@ -132,7 +132,7 @@ * @param[in] string String with tags. * @return The list of the tags IDs. */ - virtual QStringList SplitToIDs (const QString& string) = 0; + virtual QList<tag_id> SplitToIDs (const QString& string) = 0; /** @brief Joins the given tags into one string that's suitable to * display to the user. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/channelsmodel.cpp new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/channelsmodel.cpp --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/channelsmodel.cpp 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/channelsmodel.cpp 2020-03-31 20:44:18.000000000 +0200 @@ -73,6 +73,11 @@ this, [this] (const Channel& channel) { AddChannel (channel.ToShort ()); }); connect (&StorageBackendManager::Instance (), + &StorageBackendManager::channelUnreadCountUpdated, + this, + &ChannelsModel::UpdateChannelUnreadCount, + Qt::QueuedConnection); + connect (&StorageBackendManager::Instance (), &StorageBackendManager::channelDataUpdated, this, &ChannelsModel::UpdateChannelData, @@ -327,17 +332,29 @@ emit dataChanged (index (i, 0), index (i, columnCount () - 1)); } - void ChannelsModel::UpdateChannelData (const Channel& channel) + void ChannelsModel::UpdateChannelUnreadCount (IDType_t cid, int count) { - const auto cid = channel.ChannelID_; - const auto pos = std::find_if (Channels_.begin (), Channels_.end (), [cid] (const ChannelShort& cs) { return cs.ChannelID_ == cid; }); if (pos == Channels_.end ()) return; + pos->Unread_ = count; + + const auto idx = pos - Channels_.begin (); + emit dataChanged (index (idx, 0), index (idx, 2)); + } + + void ChannelsModel::UpdateChannelData (const Channel& channel) + { + const auto pos = std::find_if (Channels_.begin (), Channels_.end (), + [&channel] (const ChannelShort& cs) { return cs.ChannelID_ == channel.ChannelID_; }); + if (pos == Channels_.end ()) + return; + + auto unreadCount = pos->Unread_; *pos = channel.ToShort (); - pos->Unread_ = StorageBackendManager::Instance ().MakeStorageBackendForThread ()->GetUnreadItemsCount (cid); + pos->Unread_ = unreadCount; const auto idx = pos - Channels_.begin (); emit dataChanged (index (idx, 0), index (idx, 2)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/channelsmodel.h new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/channelsmodel.h --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/channelsmodel.h 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/channelsmodel.h 2020-03-31 20:44:18.000000000 +0200 @@ -79,6 +79,7 @@ void HandleFeedErrorsChanged (IDType_t); + void UpdateChannelUnreadCount (IDType_t, int); void UpdateChannelData (const Channel&); void AddChannel (const ChannelShort&); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/dumbstorage.h new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/dumbstorage.h --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/dumbstorage.h 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/dumbstorage.h 2020-03-31 20:44:18.000000000 +0200 @@ -74,9 +74,9 @@ void RemoveItems (const QSet<IDType_t>&) override {} void RemoveChannel (IDType_t) override {} void RemoveFeed (IDType_t) override {} - bool UpdateFeedsStorage (int, int) override { return {}; } - bool UpdateChannelsStorage (int, int) override { return {}; } - bool UpdateItemsStorage (int, int) override { return {}; } + bool UpdateFeedsStorage (int) override { return {}; } + bool UpdateChannelsStorage (int) override { return {}; } + bool UpdateItemsStorage (int) override { return {}; } void ToggleChannelUnread (IDType_t, bool) override {} QList<ITagsManager::tag_id> GetItemTags (IDType_t) override { return {}; } void SetItemTags (IDType_t, const QList<ITagsManager::tag_id>&) override {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/feedsettings.cpp new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/feedsettings.cpp --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/feedsettings.cpp 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/feedsettings.cpp 2020-03-31 20:44:18.000000000 +0200 @@ -142,10 +142,14 @@ const auto& storage = StorageBackendManager::Instance ().MakeStorageBackendForThread (); const auto itm = Proxy_->GetTagsManager (); - storage->SetChannelTags (Index_.data (ChannelRoles::ChannelID).value<IDType_t> (), - itm->GetIDs (itm->Split (Ui_.ChannelTags_->text ()))); - storage->SetFeedTags (Index_.data (ChannelRoles::FeedID).value<IDType_t> (), - itm->GetIDs (itm->Split (Ui_.FeedTags_->text ()))); + + const auto& channelTags = Ui_.ChannelTags_->text (); + storage->SetChannelTags (Index_.data (ChannelRoles::ChannelID).value<IDType_t> (), itm->SplitToIDs (channelTags)); + + auto feedTags = Ui_.FeedTags_->text (); + if (feedTags.isEmpty ()) + feedTags = channelTags; + storage->SetFeedTags (Index_.data (ChannelRoles::FeedID).value<IDType_t> (), itm->SplitToIDs (feedTags)); storage->SetFeedSettings ({ Index_.data (ChannelRoles::FeedID).value<IDType_t> (), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/itemslistmodel.cpp new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/itemslistmodel.cpp --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/itemslistmodel.cpp 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/itemslistmodel.cpp 2020-03-31 20:44:18.000000000 +0200 @@ -71,11 +71,15 @@ connect (&StorageBackendManager::Instance (), &StorageBackendManager::itemsRemoved, this, - &ItemsListModel::handleItemsRemoved); + &ItemsListModel::HandleItemsRemoved); connect (&StorageBackendManager::Instance (), &StorageBackendManager::itemDataUpdated, this, - &ItemsListModel::handleItemDataUpdated); + &ItemsListModel::HandleItemDataUpdated); + connect (&StorageBackendManager::Instance (), + &StorageBackendManager::itemReadStatusUpdated, + this, + &ItemsListModel::HandleItemReadStatusUpdated); } int ItemsListModel::GetSelectedRow () const @@ -437,27 +441,49 @@ return SB_.localData (); } - void ItemsListModel::reset (IDType_t channelId) + void ItemsListModel::HandleItemsRemoved (const QSet<IDType_t>& items) { - Reset (channelId); + RemoveItems (items); } - void ItemsListModel::selected (const QModelIndex& index) + void ItemsListModel::HandleItemDataUpdated (const Item& item) { - Selected (index); + if (item.ChannelID_ != CurrentChannel_) + return; + + ItemDataUpdated (item); } - void ItemsListModel::handleItemsRemoved (const QSet<IDType_t>& items) + void ItemsListModel::HandleItemReadStatusUpdated (IDType_t channelId, IDType_t itemId, bool unread) { - RemoveItems (items); + if (channelId != CurrentChannel_) + return; + + const auto pos = std::find_if (CurrentItems_.begin (), CurrentItems_.end (), + [&itemId] (const ItemShort& itemShort) { return itemShort.ItemID_ == itemId; }); + if (pos == CurrentItems_.end ()) + { + qWarning () << Q_FUNC_INFO + << "unable to find" + << channelId + << itemId; + return; + } + + pos->Unread_ = unread; + + int distance = std::distance (CurrentItems_.begin (), pos); + emit dataChanged (index (distance, 0), index (distance, 1)); } - void ItemsListModel::handleItemDataUpdated (const Item& item, const Channel& channel) + void ItemsListModel::reset (IDType_t channelId) { - if (channel.ChannelID_ != CurrentChannel_) - return; + Reset (channelId); + } - ItemDataUpdated (item); + void ItemsListModel::selected (const QModelIndex& index) + { + Selected (index); } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/itemslistmodel.h new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/itemslistmodel.h --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/itemslistmodel.h 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/itemslistmodel.h 2020-03-31 20:44:18.000000000 +0200 @@ -86,13 +86,12 @@ int rowCount (const QModelIndex& = QModelIndex ()) const override; private: StorageBackend_ptr GetSB () const; + void HandleItemsRemoved (const QSet<IDType_t>&); + void HandleItemDataUpdated (const Item&); + void HandleItemReadStatusUpdated (IDType_t, IDType_t, bool); public slots: void reset (IDType_t) override; void selected (const QModelIndex&) override; - private slots: - void handleItemsRemoved (const QSet<IDType_t>&); - - void handleItemDataUpdated (const Item&, const Channel&); }; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/sqlstoragebackend.cpp new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/sqlstoragebackend.cpp --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/sqlstoragebackend.cpp 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/sqlstoragebackend.cpp 2020-03-31 20:44:18.000000000 +0200 @@ -78,30 +78,60 @@ { QStringList TagsList_; + Tags () = default; + + Tags (QStringList tags) + : TagsList_ { std::move (tags) } + { + } + + operator QStringList () const + { + return TagsList_; + } + using BaseType = QString; + // need to migrate off this in the next schema migration + static const BaseType EmptyMarker_; + BaseType ToBaseType () const { + if (TagsList_.isEmpty ()) + return EmptyMarker_; + static const auto itm = Util::CoreProxyHolder::Get ()->GetTagsManager (); return itm->Join (TagsList_); } static Tags FromBaseType (const BaseType& var) { + if (var == EmptyMarker_) + return {}; + static const auto itm = Util::CoreProxyHolder::Get ()->GetTagsManager (); return { itm->Split (var) }; } - - operator QStringList () const - { - return TagsList_; - } }; + const QString Tags::EmptyMarker_ = "<<<null>>>"; + struct Image { QImage Image_; + Image () = default; + + Image (QImage image) + : Image_ { std::move (image) } + { + } + + operator QImage () const + { + return Image_; + } + using BaseType = QByteArray; BaseType ToBaseType () const @@ -123,17 +153,24 @@ result.loadFromData (var, "PNG"); return { result }; } - - operator QImage () const - { - return Image_; - } }; struct ItemCategories { QStringList Categories_; + ItemCategories () = default; + + ItemCategories (QStringList cats) + : Categories_ { std::move (cats) } + { + } + + operator QStringList () const + { + return Categories_; + } + using BaseType = QString; BaseType ToBaseType () const @@ -145,16 +182,23 @@ { return { var.split ("<<<", QString::SkipEmptyParts) }; } - - operator QStringList () const - { - return Categories_; - } }; struct GeoCoord { - double Coord_; + double Coord_ = 0; + + GeoCoord () = default; + + GeoCoord (double c) + : Coord_ { c } + { + } + + operator double () const + { + return Coord_; + } using BaseType = QString; @@ -167,11 +211,6 @@ { return { var.toDouble () }; } - - operator double () const - { - return Coord_; - } }; template<typename OralType, typename Src> @@ -371,7 +410,7 @@ struct SQLStorageBackend::Feed2TagsR { - oral::References<&FeedR::FeedID_> FeedID_; + oral::Unique<oral::References<&FeedR::FeedID_>> FeedID_; oral::NotNull<Tags> Tags_; static QString ClassName () @@ -486,7 +525,7 @@ lock.Good (); if (const auto& item = GetItem (id)) - emit itemDataUpdated (*item, GetChannel (item->ChannelID_)); + emit itemDataUpdated (*item); } QList<IDType_t> SQLStorageBackend::GetItemsForTag (const ITagsManager::tag_id& tag) @@ -725,10 +764,11 @@ auto removeByDate = Items_->Select (sph::fields<&ItemR::ItemID_>, sph::f<&ItemR::ChannelID_> == channelId && + sph::f<&ItemR::Unread_> == false && sph::f<&ItemR::PubDate_> < cutoff); auto removeByCount = Items_->Select.Build () .Select (sph::fields<&ItemR::ItemID_>) - .Where (sph::f<&ItemR::ChannelID_> == channelId) + .Where (sph::f<&ItemR::ChannelID_> == channelId && sph::f<&ItemR::Unread_> == false) .Order (oral::OrderBy<sph::desc<&ItemR::PubDate_>>) .Offset (number) (); @@ -742,8 +782,6 @@ for (auto id : removedIds) Items_->DeleteBy (sph::f<&ItemR::ItemID_> == id); lock.Good (); - - emit channelDataUpdated (GetChannel (channelId)); } std::optional<QImage> SQLStorageBackend::GetChannelPixmap (IDType_t channelId) const @@ -755,31 +793,37 @@ { // TODO no need for value_or when oral will support setting NULL Channels_->Update (sph::f<&ChannelR::Pixmap_> = img.value_or (QImage {}), sph::f<&ChannelR::ChannelID_> == id); + emit channelDataUpdated (GetChannel (id)); } void SQLStorageBackend::SetChannelFavicon (IDType_t id, const std::optional<QImage>& img) { Channels_->Update (sph::f<&ChannelR::Favicon_> = img.value_or (QImage {}), sph::f<&ChannelR::ChannelID_> == id); + emit channelDataUpdated (GetChannel (id)); } void SQLStorageBackend::SetChannelTags (IDType_t id, const QStringList& tagIds) { Channels_->Update (sph::f<&ChannelR::Tags_> = tagIds, sph::f<&ChannelR::ChannelID_> == id); + emit channelDataUpdated (GetChannel (id)); } void SQLStorageBackend::SetChannelDisplayTitle (IDType_t id, const QString& displayTitle) { Channels_->Update (sph::f<&ChannelR::DisplayTitle_> = displayTitle, sph::f<&ChannelR::ChannelID_> == id); + emit channelDataUpdated (GetChannel (id)); } void SQLStorageBackend::SetChannelTitle (IDType_t id, const QString& title) { Channels_->Update (sph::f<&ChannelR::Title_> = title, sph::f<&ChannelR::ChannelID_> == id); + emit channelDataUpdated (GetChannel (id)); } void SQLStorageBackend::SetChannelLink (IDType_t id, const QString& link) { Channels_->Update (sph::f<&ChannelR::URL_> = link, sph::f<&ChannelR::ChannelID_> == id); + emit channelDataUpdated (GetChannel (id)); } items_shorts_t SQLStorageBackend::GetItems (IDType_t channelId) const @@ -862,9 +906,7 @@ WriteEnclosures (item.Enclosures_); WriteMRSSEntries (item.MRSSEntries_); - const auto& channel = GetChannel (item.ChannelID_); - emit itemDataUpdated (item, channel); - emit channelDataUpdated (channel); + emit itemDataUpdated (item); } void SQLStorageBackend::SetItemUnread (IDType_t itemId, bool unread) @@ -873,10 +915,9 @@ if (const auto& fullItem = GetItem (itemId)) { - const auto& channel = GetChannel (fullItem->ChannelID_); - - emit itemDataUpdated (*fullItem, channel); - emit channelDataUpdated (channel); + const auto channelId = fullItem->ChannelID_; + emit itemReadStatusUpdated (channelId, itemId, unread); + emit channelUnreadCountUpdated (channelId, GetUnreadItemsCount (channelId)); } } @@ -897,9 +938,8 @@ emit hookItemAdded (std::make_shared<Util::DefaultHookProxy> (), item); - const auto& channel = GetChannel (item.ChannelID_); - emit itemDataUpdated (item, channel); - emit channelDataUpdated (channel); + emit itemDataUpdated (item); + emit channelUnreadCountUpdated (item.ChannelID_, GetUnreadItemsCount (item.ChannelID_)); } void SQLStorageBackend::RemoveItems (const QSet<IDType_t>& items) @@ -925,7 +965,7 @@ emit itemsRemoved ({ items }); for (const auto& cid : modifiedChannels) - emit channelDataUpdated (GetChannel (cid)); + emit channelUnreadCountUpdated (cid, GetUnreadItemsCount (cid)); } void SQLStorageBackend::RemoveChannel (IDType_t channelId) @@ -948,40 +988,63 @@ void SQLStorageBackend::ToggleChannelUnread (IDType_t channelId, bool state) { - const auto& oldItems = GetFullItems (channelId); + const auto oldItems = Items_->Select (sph::fields<&ItemR::ItemID_, &ItemR::Unread_>, + sph::f<&ItemR::ChannelID_> == channelId); Items_->Update (sph::f<&ItemR::Unread_> = state, sph::f<&ItemR::ChannelID_> == channelId); - const auto& channel = GetChannel (channelId); - emit channelDataUpdated (channel); - for (auto& oldItem : oldItems) - if (oldItem->Unread_ != state) - { - oldItem->Unread_ = state; - emit itemDataUpdated (*oldItem, channel); - } + emit channelUnreadCountUpdated (channelId, state ? oldItems.size () : 0); + + for (const auto& [itemId, oldState] : oldItems) + if (oldState != state) + emit itemReadStatusUpdated (channelId, itemId, state); } - bool SQLStorageBackend::UpdateFeedsStorage (int, int) + bool SQLStorageBackend::UpdateFeedsStorage (int from) { + Util::DBLock lock { DB_ }; + lock.Init (); + try + { + if (from <= 1) + { + qDebug () << Q_FUNC_INFO << "migrating tags"; + + const auto& feedsTags = Feeds2Tags_->Select (); + + Util::RunTextQuery (DB_, "DROP TABLE " + Feed2TagsR::ClassName ()); + + Feeds2Tags_ = Type_ == SBSQLite ? + oral::AdaptPtr<Feed2TagsR, oral::SQLiteImplFactory> (DB_) : + oral::AdaptPtr<Feed2TagsR, oral::PostgreSQLImplFactory> (DB_); + + for (const auto& [feedId, tags] : feedsTags) + SetFeedTags (*feedId, tags->TagsList_); + } + } + catch (const std::exception& e) + { + qWarning () << Q_FUNC_INFO + << e.what (); + return false; + } + lock.Good (); return true; } - bool SQLStorageBackend::UpdateChannelsStorage (int oldV, int newV) + bool SQLStorageBackend::UpdateChannelsStorage (int) { - if (oldV != newV) - qCritical () << Q_FUNC_INFO - << "support for old channel storage tables dropped"; - return oldV == newV; + qCritical () << Q_FUNC_INFO + << "support for old channel storage tables dropped"; + return false; } - bool SQLStorageBackend::UpdateItemsStorage (int oldV, int newV) + bool SQLStorageBackend::UpdateItemsStorage (int) { - if (oldV != newV) - qCritical () << Q_FUNC_INFO - << "support for old items storage tables dropped"; - return oldV == newV; + qCritical () << Q_FUNC_INFO + << "support for old items storage tables dropped"; + return false; } void SQLStorageBackend::WriteEnclosures (const QList<Enclosure>& enclosures) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/sqlstoragebackend.h new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/sqlstoragebackend.h --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/sqlstoragebackend.h 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/sqlstoragebackend.h 2020-03-31 20:44:18.000000000 +0200 @@ -122,9 +122,9 @@ void RemoveItems (const QSet<IDType_t>&) override; void RemoveChannel (IDType_t) override; void RemoveFeed (IDType_t) override; - bool UpdateFeedsStorage (int, int) override; - bool UpdateChannelsStorage (int, int) override; - bool UpdateItemsStorage (int, int) override; + bool UpdateFeedsStorage (int) override; + bool UpdateChannelsStorage (int) override; + bool UpdateItemsStorage (int) override; void ToggleChannelUnread (IDType_t, bool) override; QList<ITagsManager::tag_id> GetItemTags (IDType_t) override; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/storagebackend.h new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/storagebackend.h --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/storagebackend.h 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/storagebackend.h 2020-03-31 20:44:18.000000000 +0200 @@ -374,11 +374,10 @@ * stored in application settings is lower than newer one. * * @param[in] oldV Old storage version. - * @param[in] newV New storage version. * * @return true if update successful, else false. */ - virtual bool UpdateFeedsStorage (int oldV, int newV) = 0; + virtual bool UpdateFeedsStorage (int oldV) = 0; /** @brief Update channels storage section. * @@ -386,11 +385,10 @@ * stored in application settings is lower than newer one. * * @param[in] oldV Old storage version. - * @param[in] newV New storage version. * * @return true if update successful, else false. */ - virtual bool UpdateChannelsStorage (int oldV, int newV) = 0; + virtual bool UpdateChannelsStorage (int oldV) = 0; /** @brief Update items storage section. * @@ -398,11 +396,10 @@ * stored in application settings is lower than newer one. * * @param[in] oldV Old storage version. - * @param[in] newV New storage version. * * @return true if update successful, else false. */ - virtual bool UpdateItemsStorage (int oldV, int newV) = 0; + virtual bool UpdateItemsStorage (int oldV) = 0; /** @brief Toggle channel state. * @@ -430,7 +427,7 @@ * * This signal is emitted when a channel is updated. * - * @warning StorageBackendManager::channelDataUpdated() should + * @warning StorageBackendManager::channelUnreadCountUpdated() should * be used instead as it collects the signal from all * instantiated storage managers. * @@ -438,7 +435,11 @@ * * @sa StorageBackendManager */ - void channelDataUpdated (const Channel& channel) const; + void channelUnreadCountUpdated (IDType_t channelId, int unreadCount) const; + + void channelDataUpdated (const Channel&) const; + + void itemReadStatusUpdated (IDType_t channelId, IDType_t itemId, bool unread) const; /** @brief Notifies about updated item information. * @@ -449,12 +450,10 @@ * instantiated storage managers. * * @param[out] item Pointer to the updated item. - * @param[out] channel Pointer to the channel containing updated - * item. * * @sa StorageBackendManager */ - void itemDataUpdated (const Item& item, const Channel& channel) const; + void itemDataUpdated (const Item& item) const; /** @brief Notifies that a number of items was removed. * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/storagebackendmanager.cpp new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/storagebackendmanager.cpp --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/storagebackendmanager.cpp 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/storagebackendmanager.cpp 2020-03-31 20:44:18.000000000 +0200 @@ -67,14 +67,17 @@ return StorageCreationResult_t::Left ({ s.what () }); } - const int feedsTable = 1; + const int feedsTable = 2; const int channelsTable = 2; const int itemsTable = 6; auto runUpdate = [this, &strType] (auto updater, const char *suffix, int targetVersion) { const auto curVersion = XmlSettingsManager::Instance ()->Property (strType + suffix, targetVersion).toInt (); - if (!std::invoke (updater, PrimaryStorageBackend_.get (), curVersion, targetVersion)) + if (curVersion == targetVersion) + return true; + + if (!std::invoke (updater, PrimaryStorageBackend_.get (), curVersion)) return false; XmlSettingsManager::Instance ()->setProperty (strType + suffix, targetVersion); @@ -126,10 +129,18 @@ this, &StorageBackendManager::channelAdded); connect (backendPtr, + &StorageBackend::channelUnreadCountUpdated, + this, + &StorageBackendManager::channelUnreadCountUpdated); + connect (backendPtr, &StorageBackend::channelDataUpdated, this, &StorageBackendManager::channelDataUpdated); connect (backendPtr, + &StorageBackend::itemReadStatusUpdated, + this, + &StorageBackendManager::itemReadStatusUpdated); + connect (backendPtr, &StorageBackend::itemDataUpdated, this, &StorageBackendManager::itemDataUpdated); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/storagebackendmanager.h new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/storagebackendmanager.h --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/aggregator/storagebackendmanager.h 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/aggregator/storagebackendmanager.h 2020-03-31 20:44:18.000000000 +0200 @@ -76,7 +76,11 @@ * * @param[out] channel Pointer to the updated channel. */ - void channelDataUpdated (const Channel& channel) const; + void channelUnreadCountUpdated (IDType_t channelId, int unreadCount) const; + + void channelDataUpdated (const Channel&) const; + + void itemReadStatusUpdated (IDType_t channelId, IDType_t itemId, bool unread) const; /** @brief Notifies about updated item information. * @@ -84,10 +88,8 @@ * the instantiated StorageBackend objects. * * @param[out] item Pointer to the updated item. - * @param[out] channel Pointer to the channel containing updated - * item. */ - void itemDataUpdated (const Item& item, const Channel& channel) const; + void itemDataUpdated (const Item& item) const; /** @brief Notifies that a number of items was removed. * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/bittorrent/CMakeLists.txt new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/bittorrent/CMakeLists.txt --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/bittorrent/CMakeLists.txt 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/bittorrent/CMakeLists.txt 2020-03-31 20:44:18.000000000 +0200 @@ -12,10 +12,10 @@ if (ENABLE_BITTORRENT_GEOIP) add_definitions (-DENABLE_GEOIP) - find_package (GeoIP REQUIRED) + find_package (MaxMindDB REQUIRED) else () - set (GEOIP_INCLUDE_DIRS) - set (GEOIP_LIBRARIES) + set (MMDB_INCLUDE_DIRS) + set (MMDB_LIBRARIES) endif () include_directories (${CMAKE_CURRENT_BINARY_DIR} @@ -23,7 +23,7 @@ ${Boost_INCLUDE_DIR} ${LibtorrentRasterbar_INCLUDE_DIRS} ${LEECHCRAFT_INCLUDE_DIR} - ${GEOIP_INCLUDE_DIRS} + ${MMDB_INCLUDE_DIRS} ) set (SRCS @@ -149,7 +149,7 @@ ${QT_LIBRARIES} ${LibtorrentRasterbar_LIBRARIES} ${LEECHCRAFT_LIBRARIES} - ${GEOIP_LIBRARIES} + ${MMDB_LIBRARIES} ) install (TARGETS leechcraft_bittorrent DESTINATION ${LC_PLUGINS_DEST}) install (FILES torrentsettings.xml DESTINATION ${LC_SETTINGS_DEST}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/bittorrent/cmake/FindGeoIP.cmake new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/bittorrent/cmake/FindGeoIP.cmake --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/bittorrent/cmake/FindGeoIP.cmake 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/bittorrent/cmake/FindGeoIP.cmake 1970-01-01 01:00:00.000000000 +0100 @@ -1,67 +0,0 @@ -# -# - Find GeoIP -# Find the native GEOIP includes and library -# -# GEOIP_INCLUDE_DIRS - where to find GeoIP.h, etc. -# GEOIP_LIBRARIES - List of libraries when using GeoIP. -# GEOIP_FOUND - True if GeoIP found. -# GEOIP_DLL_DIR - (Windows) Path to the GeoIP DLL. -# GEOIP_DLL - (Windows) Name of the GeoIP DLL. - - -IF (GEOIP_INCLUDE_DIRS) - # Already in cache, be silent - SET(GEOIP_FIND_QUIETLY TRUE) -ENDIF (GEOIP_INCLUDE_DIRS) - -find_package(PkgConfig) -pkg_search_module(GEOIP geoip) - -FIND_PATH(GEOIP_INCLUDE_DIR GeoIP.h - HINTS - "${GEOIP_INCLUDEDIR}" - "${GEOIP_HINTS}/include" -) - -SET(GEOIP_NAMES GeoIP libGeoIP-1) -FIND_LIBRARY(GEOIP_LIBRARY NAMES ${GEOIP_NAMES} - HINTS - "${GEOIP_LIBDIR}" - "${GEOIP_HINTS}/lib" - ) - -# handle the QUIETLY and REQUIRED arguments and set GEOIP_FOUND to TRUE if -# all listed variables are TRUE -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(GEOIP DEFAULT_MSG GEOIP_LIBRARY GEOIP_INCLUDE_DIR) - -IF(GEOIP_FOUND) - SET(GEOIP_LIBRARIES ${GEOIP_LIBRARY} ) - SET(GEOIP_INCLUDE_DIRS ${GEOIP_INCLUDE_DIR} ) - INCLUDE(CheckFunctionExists) - SET(CMAKE_REQUIRED_INCLUDES ${GEOIP_INCLUDE_DIRS}) - SET(CMAKE_REQUIRED_LIBRARIES ${GEOIP_LIBRARIES}) - CHECK_FUNCTION_EXISTS("GeoIP_country_name_by_ipnum_v6" HAVE_GEOIP_V6) - SET(CMAKE_REQUIRED_INCLUDES "") - SET(CMAKE_REQUIRED_LIBRARIES "") - if (WIN32) - set ( GEOIP_DLL_DIR "${GEOIP_HINTS}/bin" - CACHE PATH "Path to the GeoIP DLL" - ) - file( GLOB _geoip_dll RELATIVE "${GEOIP_DLL_DIR}" - "${GEOIP_DLL_DIR}/libGeoIP-*.dll" - ) - set ( GEOIP_DLL ${_geoip_dll} - # We're storing filenames only. Should we use STRING instead? - CACHE FILEPATH "GeoIP DLL file name" - ) - mark_as_advanced( GEOIP_DLL_DIR GEOIP_DLL ) - endif() -ELSE(GEOIP_FOUND) - SET(GEOIP_LIBRARIES ) - SET(GEOIP_INCLUDE_DIRS ) - SET(GEOIP_DLL_DIR ) - SET(GEOIP_DLL ) -ENDIF(GEOIP_FOUND) - -MARK_AS_ADVANCED( GEOIP_LIBRARIES GEOIP_INCLUDE_DIRS ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/bittorrent/cmake/FindMaxMindDB.cmake new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/bittorrent/cmake/FindMaxMindDB.cmake --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/bittorrent/cmake/FindMaxMindDB.cmake 1970-01-01 01:00:00.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/bittorrent/cmake/FindMaxMindDB.cmake 2020-03-31 20:44:18.000000000 +0200 @@ -0,0 +1,13 @@ +# - Find libmaxminddb +# Find the native maxminddb includes and library +# +# MMDB_INCLUDE_DIRS +# MMDB_LIBRARIES +# MMDB_FOUND + +find_package(PkgConfig QUIET) +pkg_search_module(MMDB libmaxminddb) + +if (NOT MMDB_FOUND) + message (STATUS "Unable to find libmaxminddb via pkgconfig") +endif () \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/bittorrent/geoip.cpp new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/bittorrent/geoip.cpp --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/bittorrent/geoip.cpp 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/bittorrent/geoip.cpp 2020-03-31 20:44:18.000000000 +0200 @@ -34,17 +34,15 @@ #include <util/sll/monad.h> #ifdef ENABLE_GEOIP -#include <GeoIP.h> +#include <maxminddb.h> #endif -namespace LC -{ -namespace BitTorrent +namespace LC::BitTorrent { #ifdef ENABLE_GEOIP namespace { - boost::optional<QString> FindDB () + std::optional<QString> FindDB () { const QStringList geoipCands { @@ -55,7 +53,7 @@ for (const auto& cand : geoipCands) { - const auto& name = cand + "/GeoIP.dat"; + const auto& name = cand + "/GeoLite2-Country.mmdb"; if (QFile::exists (name)) return { name }; } @@ -69,58 +67,58 @@ using Util::operator>>; const auto maybeImpl = FindDB () >> - [] (const QString& path) -> boost::optional<ImplPtr_t> + [] (const QString& path) -> std::optional<ImplPtr_t> { - const auto geoip = GeoIP_open (path.toStdString ().c_str (), GEOIP_STANDARD); - - qDebug () << Q_FUNC_INFO << "loading GeoIP from" << path << geoip; + qDebug () << Q_FUNC_INFO << "loading GeoIP from" << path; - if (!geoip) + MMDB_s mmdb; + if (int status = MMDB_open (path.toStdString ().c_str (), MMDB_MODE_MMAP, &mmdb); + status != MMDB_SUCCESS) + { + qWarning () << Q_FUNC_INFO + << "unable to load MaxMind DB from:" + << status; return {}; - return { { geoip, &GeoIP_delete } }; + } + + auto ptr = ImplPtr_t { new MMDB_s, &MMDB_close }; + *ptr = mmdb; + return { ptr }; }; Impl_ = maybeImpl.value_or (ImplPtr_t {}); } - namespace - { - boost::optional<QString> Code2Str (const char *code) - { - if (!code) - return {}; - - return QString::fromLatin1 (code, 2).toLower (); - } - } - - boost::optional<QString> GeoIP::GetCountry (const libtorrent::address& addr) const + std::optional<QString> GeoIP::GetCountry (const libtorrent::address& addr) const { if (!Impl_) return {}; - if (addr.is_v4 ()) - return Code2Str (GeoIP_country_code_by_ipnum (Impl_.get (), addr.to_v4 ().to_ulong ())); - - if (addr.is_v6 ()) + int gai_error; + int mmdb_error; + auto entry = MMDB_lookup_string (Impl_.get (), addr.to_string ().c_str (), &gai_error, &mmdb_error); + if (gai_error != 0 || mmdb_error != MMDB_SUCCESS) { - const auto& bytes = addr.to_v6 ().to_bytes (); - - in6_addr in6addr; - - constexpr auto bytesSize = std::tuple_size<std::decay_t<decltype (bytes)>>::value; - static_assert (sizeof (in6addr.__in6_u.__u6_addr8) == bytesSize, - "Unexpected IPv6 address size"); + qWarning () << Q_FUNC_INFO + << "unable to query MMDB for" + << addr.to_string ().c_str (); + return {}; + } - std::copy (bytes.begin (), bytes.end (), &in6addr.__in6_u.__u6_addr8 [0]); + if (!entry.found_entry) + return {}; - return Code2Str (GeoIP_country_code_by_ipnum_v6 (Impl_.get (), in6addr)); + MMDB_entry_data_s entryData; + if (int result = MMDB_get_value (&entry.entry, &entryData, "country", "iso_code", NULL); + result != MMDB_SUCCESS || !entryData.has_data || !entryData.utf8_string) + { + qWarning () << Q_FUNC_INFO + << "unable to query MMDB entry for the country iso code:" + << result + << entryData.has_data; + return {}; } - qWarning () << Q_FUNC_INFO - << "the address is neither IPv4 nor IPv6" - << addr.to_string ().c_str (); - - return {}; + return QString::fromLatin1 (entryData.utf8_string, 2).toLower (); } #else GeoIP::GeoIP () @@ -133,4 +131,3 @@ } #endif } -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/bittorrent/geoip.h new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/bittorrent/geoip.h --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/bittorrent/geoip.h 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/bittorrent/geoip.h 2020-03-31 20:44:18.000000000 +0200 @@ -30,24 +30,21 @@ #pragma once #include <memory> -#include <boost/optional.hpp> +#include <optional> #include <QString> #include <libtorrent/address.hpp> -struct GeoIPTag; +struct MMDB_s; -namespace LC -{ -namespace BitTorrent +namespace LC::BitTorrent { class GeoIP { - using ImplPtr_t = std::shared_ptr<GeoIPTag>; + using ImplPtr_t = std::shared_ptr<MMDB_s>; ImplPtr_t Impl_; public: GeoIP (); - boost::optional<QString> GetCountry (const libtorrent::address&) const; + std::optional<QString> GetCountry (const libtorrent::address&) const; }; } -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/poshuku/plugins/webengineview/cookiessyncer.cpp new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/poshuku/plugins/webengineview/cookiessyncer.cpp --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/plugins/poshuku/plugins/webengineview/cookiessyncer.cpp 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/plugins/poshuku/plugins/webengineview/cookiessyncer.cpp 2020-03-31 20:44:18.000000000 +0200 @@ -40,7 +40,7 @@ : LCJar_ { lcJar } , WebEngineStore_ { weStore } { - WebEngineStore_->loadAllCookies (); + WebEngineStore_->deleteAllCookies (); HandleLCCookiesAdded (LCJar_->allCookies ()); @@ -93,7 +93,7 @@ void CookiesSyncer::HandleWebEngineCookieRemoved (const QNetworkCookie& cookie) { - WebEngine2LCQueue_.removeOne (cookie); + WebEngine2LCQueue_.removeAll (cookie); LCJar_->deleteCookie (cookie); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/util/db/consistencychecker.cpp new/leechcraft-0.6.70-13641-g995b95b3d4/src/util/db/consistencychecker.cpp --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/util/db/consistencychecker.cpp 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/util/db/consistencychecker.cpp 2020-03-31 20:44:18.000000000 +0200 @@ -105,7 +105,10 @@ } QSqlQuery pragma { *db }; - const auto isGood = pragma.exec ("PRAGMA integrity_check;") && + const QString checkQuery = qgetenv ("LC_THOROUGH_SQLITE_CHECK") == "1" ? + "PRAGMA integrity_check;" : + "PRAGMA quick_check;"; + const auto isGood = pragma.exec (checkQuery) && pragma.next () && pragma.value (0) == "ok"; qDebug () << Q_FUNC_INFO diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/util/db/oral/oral.h new/leechcraft-0.6.70-13641-g995b95b3d4/src/util/db/oral/oral.h --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/util/db/oral/oral.h 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/util/db/oral/oral.h 2020-03-31 20:44:18.000000000 +0200 @@ -683,47 +683,6 @@ } }; - template<auto... Ptr> - struct MemberPtrs {}; - - template<auto Ptr> - class ExprTree<ExprType::LeafStaticPlaceholder, MemberPtrs<Ptr>, void> - { - public: - template<typename> - using ValueType_t = MemberPtrType_t<Ptr>; - - template<typename T> - QString ToSql (ToSqlState<T>&) const noexcept - { - return MemberPtrStruct_t<Ptr>::ClassName () + "." + GetFieldName (); - } - - QString GetFieldName () const noexcept - { - return detail::GetFieldNamePtr<Ptr> (); - } - - template<typename T> - QSet<QString> AdditionalTables () const noexcept - { - using Seq = MemberPtrStruct_t<Ptr>; - if constexpr (std::is_same_v<Seq, T>) - return {}; - else - return { Seq::ClassName () }; - } - - template<typename T> - constexpr static bool HasAdditionalTables () noexcept - { - return !std::is_same_v<MemberPtrStruct_t<Ptr>, T>; - } - - template<typename R> - auto operator= (const R&) const noexcept; - }; - template<typename T> class ExprTree<ExprType::LeafData, T, void> { @@ -733,7 +692,7 @@ using ValueType_t = T; ExprTree (const T& t) noexcept - : Data_ (t) + : Data_ (t) { } @@ -758,11 +717,6 @@ } }; - template<> - class ExprTree<ExprType::ConstTrue, void, void> {}; - - constexpr auto ConstTrueTree_v = ExprTree<ExprType::ConstTrue> {}; - template<typename T> constexpr auto AsLeafData (const T& node) noexcept { @@ -772,12 +726,54 @@ return ExprTree<ExprType::LeafData, T> { node }; } + template<auto... Ptr> + struct MemberPtrs {}; + template<auto Ptr> - template<typename R> - auto ExprTree<ExprType::LeafStaticPlaceholder, MemberPtrs<Ptr>, void>::operator= (const R& r) const noexcept + class ExprTree<ExprType::LeafStaticPlaceholder, MemberPtrs<Ptr>, void> { - return AssignList { *this, AsLeafData (r) }; - } + using ExpectedType_t = MemberPtrType_t<Ptr>; + public: + template<typename> + using ValueType_t = ExpectedType_t; + + template<typename T> + QString ToSql (ToSqlState<T>&) const noexcept + { + return MemberPtrStruct_t<Ptr>::ClassName () + "." + GetFieldName (); + } + + QString GetFieldName () const noexcept + { + return detail::GetFieldNamePtr<Ptr> (); + } + + template<typename T> + QSet<QString> AdditionalTables () const noexcept + { + using Seq = MemberPtrStruct_t<Ptr>; + if constexpr (std::is_same_v<Seq, T>) + return {}; + else + return { Seq::ClassName () }; + } + + template<typename T> + constexpr static bool HasAdditionalTables () noexcept + { + return !std::is_same_v<MemberPtrStruct_t<Ptr>, T>; + } + + auto operator= (const ExpectedType_t& r) const noexcept + { + return AssignList { *this, AsLeafData (r) }; + } + }; + + template<> + class ExprTree<ExprType::ConstTrue, void, void> {}; + + constexpr auto ConstTrueTree_v = ExprTree<ExprType::ConstTrue> {}; template<ExprType Type, typename L, typename R> auto MakeExprTree (const L& left, const R& right) noexcept @@ -883,7 +879,7 @@ template<typename> auto HandleExprTree (const ExprTree<ExprType::ConstTrue>&, int lastId = 0) noexcept { - return ExprTreeHandler { QString {}, Void {}, lastId }; + return ExprTreeHandler { "1 = 1", [] (auto&&) {}, lastId }; } template<typename Seq, typename Tree, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/leechcraft-0.6.70-13605-g8cd066ad6a/src/util/network/customcookiejar.h new/leechcraft-0.6.70-13641-g995b95b3d4/src/util/network/customcookiejar.h --- old/leechcraft-0.6.70-13605-g8cd066ad6a/src/util/network/customcookiejar.h 2020-01-11 16:25:31.000000000 +0100 +++ new/leechcraft-0.6.70-13641-g995b95b3d4/src/util/network/customcookiejar.h 2020-03-31 20:44:18.000000000 +0200 @@ -63,7 +63,7 @@ * * @param[in] parent The parent object. */ - CustomCookieJar (QObject *parent = 0); + explicit CustomCookieJar (QObject *parent = nullptr); /** Enables or disables filtering tracking cookies. * @@ -147,7 +147,7 @@ * @param[in] url The url to return cookies for. * @return The list of cookies, dup-free. */ - QList<QNetworkCookie> cookiesForUrl (const QUrl& url) const; + QList<QNetworkCookie> cookiesForUrl (const QUrl& url) const override; /** @brief Adds the cookieList for the given url to the jar. * @@ -157,7 +157,7 @@ * @param[in] url The url to set cookies for. * @return Whether the jar has been modified as the result. */ - bool setCookiesFromUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url); + bool setCookiesFromUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url) override; using QNetworkCookieJar::allCookies; using QNetworkCookieJar::setAllCookies;