mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-28 19:58:56 +03:00
Merge pull request #4441 from nextcloud/bugfix/activities-fetch-overload
Bugfix/activities fetch server overload
This commit is contained in:
commit
a86e0908b7
6 changed files with 145 additions and 41 deletions
|
@ -43,7 +43,7 @@ void FileActivityListModel::startFetchJob()
|
||||||
if (!accountState()->isConnected()) {
|
if (!accountState()->isConnected()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setCurrentlyFetching(true);
|
setAndRefreshCurrentlyFetching(true);
|
||||||
|
|
||||||
const QString url(QStringLiteral("ocs/v2.php/apps/activity/api/v2/activity/filter"));
|
const QString url(QStringLiteral("ocs/v2.php/apps/activity/api/v2/activity/filter"));
|
||||||
auto job = new JsonApiJob(accountState()->account(), url, this);
|
auto job = new JsonApiJob(accountState()->account(), url, this);
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "activitydata.h"
|
#include "activitydata.h"
|
||||||
#include "activitylistmodel.h"
|
#include "activitylistmodel.h"
|
||||||
#include "systray.h"
|
#include "systray.h"
|
||||||
|
#include "tray/usermodel.h"
|
||||||
|
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
|
|
||||||
|
@ -95,9 +96,13 @@ void ActivityListModel::setCurrentItem(const int currentItem)
|
||||||
_currentItem = currentItem;
|
_currentItem = currentItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivityListModel::setCurrentlyFetching(bool value)
|
void ActivityListModel::setAndRefreshCurrentlyFetching(bool value)
|
||||||
{
|
{
|
||||||
|
if (_currentlyFetching == value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
_currentlyFetching = value;
|
_currentlyFetching = value;
|
||||||
|
insertOrRemoveDummyFetchingActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ActivityListModel::currentlyFetching() const
|
bool ActivityListModel::currentlyFetching() const
|
||||||
|
@ -353,9 +358,9 @@ int ActivityListModel::rowCount(const QModelIndex &parent) const
|
||||||
bool ActivityListModel::canFetchMore(const QModelIndex &) const
|
bool ActivityListModel::canFetchMore(const QModelIndex &) const
|
||||||
{
|
{
|
||||||
// We need to be connected to be able to fetch more
|
// We need to be connected to be able to fetch more
|
||||||
if (_accountState && _accountState->isConnected()) {
|
if (_accountState && _accountState->isConnected() && Systray::instance()->isOpen()) {
|
||||||
// If the fetching is reported to be done or we are currently fetching we can't fetch more
|
// If the fetching is reported to be done or we are currently fetching we can't fetch more
|
||||||
if (!_doneFetching && !_currentlyFetching) {
|
if (!_doneFetching && !currentlyFetching()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,7 +370,7 @@ bool ActivityListModel::canFetchMore(const QModelIndex &) const
|
||||||
|
|
||||||
void ActivityListModel::startFetchJob()
|
void ActivityListModel::startFetchJob()
|
||||||
{
|
{
|
||||||
if (!_accountState->isConnected()) {
|
if (!_accountState->isConnected() || currentlyFetching()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto *job = new JsonApiJob(_accountState->account(), QLatin1String("ocs/v2.php/apps/activity/api/v2/activity"), this);
|
auto *job = new JsonApiJob(_accountState->account(), QLatin1String("ocs/v2.php/apps/activity/api/v2/activity"), this);
|
||||||
|
@ -378,7 +383,7 @@ void ActivityListModel::startFetchJob()
|
||||||
params.addQueryItem(QLatin1String("limit"), QString::number(50));
|
params.addQueryItem(QLatin1String("limit"), QString::number(50));
|
||||||
job->addQueryParams(params);
|
job->addQueryParams(params);
|
||||||
|
|
||||||
_currentlyFetching = true;
|
setAndRefreshCurrentlyFetching(true);
|
||||||
qCInfo(lcActivity) << "Start fetching activities for " << _accountState->account()->displayName();
|
qCInfo(lcActivity) << "Start fetching activities for " << _accountState->account()->displayName();
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
@ -403,7 +408,7 @@ void ActivityListModel::ingestActivities(const QJsonArray &activities)
|
||||||
ActivityList list;
|
ActivityList list;
|
||||||
|
|
||||||
QDateTime oldestDate = QDateTime::currentDateTime();
|
QDateTime oldestDate = QDateTime::currentDateTime();
|
||||||
oldestDate = oldestDate.addDays(_maxActivitiesDays * -1);
|
oldestDate = oldestDate.addDays(static_cast<qint64>(_maxActivitiesDays) * -1);
|
||||||
|
|
||||||
for (const auto &activ : activities) {
|
for (const auto &activ : activities) {
|
||||||
const auto json = activ.toObject();
|
const auto json = activ.toObject();
|
||||||
|
@ -423,6 +428,86 @@ void ActivityListModel::ingestActivities(const QJsonArray &activities)
|
||||||
}
|
}
|
||||||
|
|
||||||
_activityLists.append(list);
|
_activityLists.append(list);
|
||||||
|
|
||||||
|
if (list.size() > 0) {
|
||||||
|
std::sort(list.begin(), list.end());
|
||||||
|
beginInsertRows({}, _finalList.size(), _finalList.size() + list.size() - 1);
|
||||||
|
_finalList.append(list);
|
||||||
|
endInsertRows();
|
||||||
|
|
||||||
|
appendMoreActivitiesAvailableEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActivityListModel::appendMoreActivitiesAvailableEntry()
|
||||||
|
{
|
||||||
|
const QString moreActivitiesEntryObjectType = QLatin1String("activity_fetch_more_activities");
|
||||||
|
if (_showMoreActivitiesAvailableEntry && !_finalList.isEmpty()
|
||||||
|
&& _finalList.last()._objectType != moreActivitiesEntryObjectType) {
|
||||||
|
Activity a;
|
||||||
|
a._type = Activity::ActivityType;
|
||||||
|
a._accName = _accountState->account()->displayName();
|
||||||
|
a._id = -1;
|
||||||
|
a._objectType = moreActivitiesEntryObjectType;
|
||||||
|
a._subject = tr("For more activities please open the Activity app.");
|
||||||
|
a._dateTime = QDateTime::currentDateTime();
|
||||||
|
|
||||||
|
if (const auto *app = _accountState->findApp(QLatin1String("activity"))) {
|
||||||
|
a._link = app->url();
|
||||||
|
}
|
||||||
|
|
||||||
|
beginInsertRows({}, _finalList.size(), _finalList.size());
|
||||||
|
_finalList.append(a);
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActivityListModel::insertOrRemoveDummyFetchingActivity()
|
||||||
|
{
|
||||||
|
const QString dummyFetchingActivityObjectType = QLatin1String("dummy_fetching_activity");
|
||||||
|
if (_currentlyFetching && _finalList.isEmpty()) {
|
||||||
|
Activity a;
|
||||||
|
a._type = Activity::ActivityType;
|
||||||
|
a._accName = _accountState->account()->displayName();
|
||||||
|
a._id = -2;
|
||||||
|
a._objectType = dummyFetchingActivityObjectType;
|
||||||
|
a._subject = tr("Fetching activities...");
|
||||||
|
a._dateTime = QDateTime::currentDateTime();
|
||||||
|
a._darkIcon = QLatin1String("qrc:///client/theme/colored/change-bordered.svg");
|
||||||
|
a._lightIcon = QLatin1String("qrc:///client/theme/colored/change-bordered.svg");
|
||||||
|
|
||||||
|
beginInsertRows({}, 0, 0);
|
||||||
|
_finalList.prepend(a);
|
||||||
|
endInsertRows();
|
||||||
|
} else if (!_finalList.isEmpty() && _finalList.first()._objectType == dummyFetchingActivityObjectType) {
|
||||||
|
beginRemoveRows({}, 0, 0);
|
||||||
|
_finalList.removeAt(0);
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActivityListModel::clearActivities()
|
||||||
|
{
|
||||||
|
_activityLists.clear();
|
||||||
|
if (!_finalList.isEmpty()) {
|
||||||
|
const auto firstActivityIt = std::find_if(std::begin(_finalList), std::end(_finalList),
|
||||||
|
[&](const Activity &activity) { return activity._type == Activity::ActivityType; });
|
||||||
|
|
||||||
|
if (firstActivityIt != std::end(_finalList)) {
|
||||||
|
const auto lastActivityItReverse = std::find_if(std::rbegin(_finalList), std::rend(_finalList),
|
||||||
|
[&](const Activity &activity) { return activity._type == Activity::ActivityType; });
|
||||||
|
|
||||||
|
const auto lastActivityIt = (lastActivityItReverse + 1).base();
|
||||||
|
|
||||||
|
if (lastActivityIt != std::end(_finalList)) {
|
||||||
|
const int beginRemoveIndex = std::distance(std::begin(_finalList), firstActivityIt);
|
||||||
|
const int endRemoveIndex = std::distance(std::begin(_finalList), lastActivityIt);
|
||||||
|
beginRemoveRows({}, beginRemoveIndex, endRemoveIndex);
|
||||||
|
_finalList.erase(firstActivityIt, std::end(_finalList));
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivityListModel::activitiesReceived(const QJsonDocument &json, int statusCode)
|
void ActivityListModel::activitiesReceived(const QJsonDocument &json, int statusCode)
|
||||||
|
@ -437,12 +522,10 @@ void ActivityListModel::activitiesReceived(const QJsonDocument &json, int status
|
||||||
_doneFetching = true;
|
_doneFetching = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentlyFetching = false;
|
setAndRefreshCurrentlyFetching(false);
|
||||||
|
|
||||||
ingestActivities(activities);
|
ingestActivities(activities);
|
||||||
|
|
||||||
combineActivityLists();
|
|
||||||
|
|
||||||
emit activityJobStatusCode(statusCode);
|
emit activityJobStatusCode(statusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,8 +596,15 @@ void ActivityListModel::removeActivityFromActivityList(Activity activity)
|
||||||
int index = -1;
|
int index = -1;
|
||||||
if (activity._type == Activity::ActivityType) {
|
if (activity._type == Activity::ActivityType) {
|
||||||
index = _activityLists.indexOf(activity);
|
index = _activityLists.indexOf(activity);
|
||||||
if (index != -1)
|
if (index != -1) {
|
||||||
_activityLists.removeAt(index);
|
_activityLists.removeAt(index);
|
||||||
|
const auto indexInFinalList = _finalList.indexOf(activity);
|
||||||
|
if (indexInFinalList != -1) {
|
||||||
|
beginRemoveRows({}, indexInFinalList, indexInFinalList);
|
||||||
|
_finalList.removeAt(indexInFinalList);
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (activity._type == Activity::NotificationType) {
|
} else if (activity._type == Activity::NotificationType) {
|
||||||
index = _notificationLists.indexOf(activity);
|
index = _notificationLists.indexOf(activity);
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
|
@ -744,27 +834,21 @@ void ActivityListModel::combineActivityLists()
|
||||||
if (_activityLists.count() > 0) {
|
if (_activityLists.count() > 0) {
|
||||||
std::sort(_activityLists.begin(), _activityLists.end());
|
std::sort(_activityLists.begin(), _activityLists.end());
|
||||||
resultList.append(_activityLists);
|
resultList.append(_activityLists);
|
||||||
|
|
||||||
if(_showMoreActivitiesAvailableEntry) {
|
|
||||||
Activity a;
|
|
||||||
a._type = Activity::ActivityType;
|
|
||||||
a._accName = _accountState->account()->displayName();
|
|
||||||
a._id = -1;
|
|
||||||
a._subject = tr("For more activities please open the Activity app.");
|
|
||||||
a._dateTime = QDateTime::currentDateTime();
|
|
||||||
|
|
||||||
AccountApp *app = _accountState->findApp(QLatin1String("activity"));
|
|
||||||
if(app) {
|
|
||||||
a._link = app->url();
|
|
||||||
}
|
|
||||||
|
|
||||||
resultList.append(a);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
beginResetModel();
|
if (_finalList.isEmpty() && !resultList.isEmpty()) {
|
||||||
_finalList = resultList;
|
beginInsertRows({}, 0, resultList.size() - 1);
|
||||||
endResetModel();
|
_finalList = resultList;
|
||||||
|
endInsertRows();
|
||||||
|
} else if (!_finalList.isEmpty()) {
|
||||||
|
beginResetModel();
|
||||||
|
_finalList = resultList;
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_activityLists.size() > 0) {
|
||||||
|
appendMoreActivitiesAvailableEntry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ActivityListModel::canFetchActivities() const
|
bool ActivityListModel::canFetchActivities() const
|
||||||
|
@ -774,14 +858,14 @@ bool ActivityListModel::canFetchActivities() const
|
||||||
|
|
||||||
void ActivityListModel::fetchMore(const QModelIndex &)
|
void ActivityListModel::fetchMore(const QModelIndex &)
|
||||||
{
|
{
|
||||||
if (canFetchActivities() && !_currentlyFetching) {
|
if (canFetchActivities()) {
|
||||||
startFetchJob();
|
startFetchJob();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivityListModel::slotRefreshActivity()
|
void ActivityListModel::slotRefreshActivity()
|
||||||
{
|
{
|
||||||
_activityLists.clear();
|
clearActivities();
|
||||||
_doneFetching = false;
|
_doneFetching = false;
|
||||||
_currentItem = 0;
|
_currentItem = 0;
|
||||||
_totalActivitiesFetched = 0;
|
_totalActivitiesFetched = 0;
|
||||||
|
@ -795,11 +879,18 @@ void ActivityListModel::slotRefreshActivity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ActivityListModel::slotRefreshActivityInitial()
|
||||||
|
{
|
||||||
|
if (_activityLists.isEmpty() && !currentlyFetching()) {
|
||||||
|
slotRefreshActivity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ActivityListModel::slotRemoveAccount()
|
void ActivityListModel::slotRemoveAccount()
|
||||||
{
|
{
|
||||||
_finalList.clear();
|
_finalList.clear();
|
||||||
_activityLists.clear();
|
_activityLists.clear();
|
||||||
_currentlyFetching = false;
|
setAndRefreshCurrentlyFetching(false);
|
||||||
_doneFetching = false;
|
_doneFetching = false;
|
||||||
_currentItem = 0;
|
_currentItem = 0;
|
||||||
_totalActivitiesFetched = 0;
|
_totalActivitiesFetched = 0;
|
||||||
|
|
|
@ -111,6 +111,7 @@ public:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void slotRefreshActivity();
|
void slotRefreshActivity();
|
||||||
|
void slotRefreshActivityInitial();
|
||||||
void slotRemoveAccount();
|
void slotRemoveAccount();
|
||||||
void slotTriggerDefaultAction(const int activityIndex);
|
void slotTriggerDefaultAction(const int activityIndex);
|
||||||
void slotTriggerAction(const int activityIndex, const int actionIndex);
|
void slotTriggerAction(const int activityIndex, const int actionIndex);
|
||||||
|
@ -125,7 +126,7 @@ protected:
|
||||||
void activitiesReceived(const QJsonDocument &json, int statusCode);
|
void activitiesReceived(const QJsonDocument &json, int statusCode);
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
void setCurrentlyFetching(bool value);
|
void setAndRefreshCurrentlyFetching(bool value);
|
||||||
bool currentlyFetching() const;
|
bool currentlyFetching() const;
|
||||||
void setDoneFetching(bool value);
|
void setDoneFetching(bool value);
|
||||||
void setHideOldActivities(bool value);
|
void setHideOldActivities(bool value);
|
||||||
|
@ -147,6 +148,11 @@ private:
|
||||||
bool canFetchActivities() const;
|
bool canFetchActivities() const;
|
||||||
|
|
||||||
void ingestActivities(const QJsonArray &activities);
|
void ingestActivities(const QJsonArray &activities);
|
||||||
|
void appendMoreActivitiesAvailableEntry();
|
||||||
|
|
||||||
|
void insertOrRemoveDummyFetchingActivity();
|
||||||
|
|
||||||
|
void clearActivities();
|
||||||
|
|
||||||
ActivityList _activityLists;
|
ActivityList _activityLists;
|
||||||
ActivityList _syncFileItemLists;
|
ActivityList _syncFileItemLists;
|
||||||
|
|
|
@ -137,8 +137,6 @@ void ServerNotificationHandler::slotNotificationsReceived(const QJsonDocument &j
|
||||||
a._talkNotificationData.userAvatar = ai->account()->url().toString() + QStringLiteral("/index.php/avatar/") + a._subjectRichParameters["user"].id + QStringLiteral("/128");
|
a._talkNotificationData.userAvatar = ai->account()->url().toString() + QStringLiteral("/index.php/avatar/") + a._subjectRichParameters["user"].id + QStringLiteral("/128");
|
||||||
}
|
}
|
||||||
|
|
||||||
list.append(a);
|
|
||||||
|
|
||||||
// We want to serve incoming call dialogs to the user for calls that
|
// We want to serve incoming call dialogs to the user for calls that
|
||||||
if(a._objectType == "call" && a._dateTime.secsTo(QDateTime::currentDateTime()) < 120) {
|
if(a._objectType == "call" && a._dateTime.secsTo(QDateTime::currentDateTime()) < 120) {
|
||||||
callList.append(a);
|
callList.append(a);
|
||||||
|
|
|
@ -221,7 +221,7 @@ bool User::checkPushNotificationsAreReady() const
|
||||||
}
|
}
|
||||||
|
|
||||||
void User::slotRefreshImmediately() {
|
void User::slotRefreshImmediately() {
|
||||||
if (_account.data() && _account.data()->isConnected()) {
|
if (_account.data() && _account.data()->isConnected() && Systray::instance()->isOpen()) {
|
||||||
slotRefreshActivities();
|
slotRefreshActivities();
|
||||||
}
|
}
|
||||||
slotRefreshNotifications();
|
slotRefreshNotifications();
|
||||||
|
@ -233,6 +233,7 @@ void User::slotRefresh()
|
||||||
|
|
||||||
if (checkPushNotificationsAreReady()) {
|
if (checkPushNotificationsAreReady()) {
|
||||||
// we are relying on WebSocket push notifications - ignore refresh attempts from UI
|
// we are relying on WebSocket push notifications - ignore refresh attempts from UI
|
||||||
|
slotRefreshActivitiesInitial();
|
||||||
_timeSinceLastCheck[_account.data()].invalidate();
|
_timeSinceLastCheck[_account.data()].invalidate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -249,17 +250,24 @@ void User::slotRefresh()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_account.data() && _account.data()->isConnected()) {
|
if (_account.data() && _account.data()->isConnected()) {
|
||||||
if (!timer.isValid()) {
|
slotRefreshActivitiesInitial();
|
||||||
slotRefreshActivities();
|
|
||||||
}
|
|
||||||
slotRefreshNotifications();
|
slotRefreshNotifications();
|
||||||
timer.start();
|
timer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void User::slotRefreshActivitiesInitial()
|
||||||
|
{
|
||||||
|
if (_account.data()->isConnected() && Systray::instance()->isOpen()) {
|
||||||
|
_activityModel->slotRefreshActivityInitial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void User::slotRefreshActivities()
|
void User::slotRefreshActivities()
|
||||||
{
|
{
|
||||||
_activityModel->slotRefreshActivity();
|
if (_account.data()->isConnected() && Systray::instance()->isOpen()) {
|
||||||
|
_activityModel->slotRefreshActivity();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void User::slotRefreshUserStatus()
|
void User::slotRefreshUserStatus()
|
||||||
|
|
|
@ -102,6 +102,7 @@ public slots:
|
||||||
void slotBuildNotificationDisplay(const ActivityList &list);
|
void slotBuildNotificationDisplay(const ActivityList &list);
|
||||||
void slotBuildIncomingCallDialogs(const ActivityList &list);
|
void slotBuildIncomingCallDialogs(const ActivityList &list);
|
||||||
void slotRefreshNotifications();
|
void slotRefreshNotifications();
|
||||||
|
void slotRefreshActivitiesInitial();
|
||||||
void slotRefreshActivities();
|
void slotRefreshActivities();
|
||||||
void slotRefresh();
|
void slotRefresh();
|
||||||
void slotRefreshUserStatus();
|
void slotRefreshUserStatus();
|
||||||
|
|
Loading…
Reference in a new issue