Fix crash in admin log events.

This commit is contained in:
John Preston 2019-01-13 15:47:00 +04:00
parent 67d12fa6d2
commit b236844c94
3 changed files with 64 additions and 50 deletions

View File

@ -411,9 +411,9 @@ void InnerWidget::requestAdmins() {
});
for (auto [user, canEdit] : filtered) {
_admins.push_back(user);
_admins.emplace_back(user);
if (canEdit) {
_adminsCanEdit.push_back(user);
_adminsCanEdit.emplace_back(user);
}
}
});
@ -530,8 +530,13 @@ void InnerWidget::saveState(not_null<SectionMemento*> memento) {
memento->setAdminsCanEdit(std::move(_adminsCanEdit));
memento->setSearchQuery(std::move(_searchQuery));
if (!_filterChanged) {
memento->setItems(std::move(_items), std::move(_itemsByIds), _upLoaded, _downLoaded);
memento->setIdManager(std::move(_idManager));
memento->setItems(
base::take(_items),
base::take(_eventIds),
_upLoaded,
_downLoaded);
memento->setIdManager(base::take(_idManager));
base::take(_itemsByData);
}
_upLoaded = _downLoaded = true; // Don't load or handle anything anymore.
}
@ -540,8 +545,9 @@ void InnerWidget::restoreState(not_null<SectionMemento*> memento) {
_items = memento->takeItems();
for (auto &item : _items) {
item.refreshView(this);
_itemsByData.emplace(item->data(), item.get());
}
_itemsByIds = memento->takeItemsByIds();
_eventIds = memento->takeEventIds();
if (auto manager = memento->takeIdManager()) {
_idManager = std::move(manager);
}
@ -614,38 +620,40 @@ void InnerWidget::addEvents(Direction direction, const QVector<MTPChannelAdminLo
// When loading items down we add them to a new vector and copy _items after them.
auto newItemsForDownDirection = std::vector<OwnedItem>();
auto oldItemsCount = _items.size();
auto &addToItems = (direction == Direction::Up) ? _items : newItemsForDownDirection;
auto &addToItems = (direction == Direction::Up)
? _items
: newItemsForDownDirection;
addToItems.reserve(oldItemsCount + events.size() * 2);
for_const (auto &event, events) {
Assert(event.type() == mtpc_channelAdminLogEvent);
const auto &data = event.c_channelAdminLogEvent();
const auto id = data.vid.v;
if (_itemsByIds.find(id) != _itemsByIds.cend()) {
continue;
}
auto count = 0;
const auto addOne = [&](OwnedItem item) {
_itemsByIds.emplace(id, item.get());
_itemsByData.emplace(item->data(), item.get());
addToItems.push_back(std::move(item));
++count;
};
GenerateItems(
this,
_history,
_idManager.get(),
data,
addOne);
if (count > 1) {
// Reverse the inner order of the added messages, because we load events
// from bottom to top but inside one event they go from top to bottom.
auto full = addToItems.size();
auto from = full - count;
for (auto i = 0, toReverse = count / 2; i != toReverse; ++i) {
std::swap(addToItems[from + i], addToItems[full - i - 1]);
for (const auto &event : events) {
event.match([&](const MTPDchannelAdminLogEvent &data) {
const auto id = data.vid.v;
if (_eventIds.find(id) != _eventIds.end()) {
return;
}
}
auto count = 0;
const auto addOne = [&](OwnedItem item) {
_eventIds.emplace(id);
_itemsByData.emplace(item->data(), item.get());
addToItems.push_back(std::move(item));
++count;
};
GenerateItems(
this,
_history,
_idManager.get(),
data,
addOne);
if (count > 1) {
// Reverse the inner order of the added messages, because we load events
// from bottom to top but inside one event they go from top to bottom.
auto full = addToItems.size();
auto from = full - count;
for (auto i = 0, toReverse = count / 2; i != toReverse; ++i) {
std::swap(addToItems[from + i], addToItems[full - i - 1]);
}
}
});
}
auto newItemsCount = _items.size() + ((direction == Direction::Up) ? 0 : newItemsForDownDirection.size());
if (newItemsCount != oldItemsCount) {
@ -662,11 +670,11 @@ void InnerWidget::addEvents(Direction direction, const QVector<MTPChannelAdminLo
}
void InnerWidget::updateMinMaxIds() {
if (_itemsByIds.empty() || _filterChanged) {
if (_eventIds.empty() || _filterChanged) {
_maxId = _minId = 0;
} else {
_maxId = (--_itemsByIds.end())->first;
_minId = _itemsByIds.begin()->first;
_maxId = *_eventIds.rbegin();
_minId = *_eventIds.begin();
if (_minId == 1) {
_upLoaded = true;
}
@ -836,7 +844,8 @@ void InnerWidget::clearAfterFilterChange() {
_selectedText = TextSelection();
_filterChanged = false;
_items.clear();
_itemsByIds.clear();
_eventIds.clear();
_itemsByData.clear();
_idManager = nullptr;
_idManager = _history->adminLogIdManager();
updateEmptyText();
@ -1133,7 +1142,9 @@ void InnerWidget::suggestRestrictUser(not_null<UserData*> user) {
auto weak = QPointer<InnerWidget>(this);
auto weakBox = std::make_shared<QPointer<EditRestrictedBox>>();
auto box = Box<EditRestrictedBox>(_channel, user, hasAdminRights, currentRights);
box->setSaveCallback([user, weak, weakBox](const MTPChatBannedRights &oldRights, const MTPChatBannedRights &newRights) {
box->setSaveCallback([=](
const MTPChatBannedRights &oldRights,
const MTPChatBannedRights &newRights) {
if (weak) {
weak->restrictUser(user, oldRights, newRights);
}
@ -1148,7 +1159,10 @@ void InnerWidget::suggestRestrictUser(not_null<UserData*> user) {
if (base::contains(_admins, user)) {
editRestrictions(true, MTP_chatBannedRights(MTP_flags(0), MTP_int(0)));
} else {
request(MTPchannels_GetParticipant(_channel->inputChannel, user->inputUser)).done([=](const MTPchannels_ChannelParticipant &result) {
request(MTPchannels_GetParticipant(
_channel->inputChannel,
user->inputUser
)).done([=](const MTPchannels_ChannelParticipant &result) {
Expects(result.type() == mtpc_channels_channelParticipant);
auto &participant = result.c_channels_channelParticipant();

View File

@ -190,7 +190,7 @@ private:
// for each found userpic (from the top to the bottom) using enumerateItems() method.
//
// Method has "bool (*Method)(not_null<Element*> view, int userpicTop)" signature
// if it returns false the enumeration stops immidiately.
// if it returns false the enumeration stops immediately.
template <typename Method>
void enumerateUserpics(Method method);
@ -198,7 +198,7 @@ private:
// for each found date element (from the bottom to the top) using enumerateItems() method.
//
// Method has "bool (*Method)(not_null<HistoryItem*> item, int itemtop, int dateTop)" signature
// if it returns false the enumeration stops immidiately.
// if it returns false the enumeration stops immediately.
template <typename Method>
void enumerateDates(Method method);
@ -206,8 +206,8 @@ private:
not_null<ChannelData*> _channel;
not_null<History*> _history;
std::vector<OwnedItem> _items;
std::map<uint64, not_null<Element*>> _itemsByIds;
std::map<not_null<HistoryItem*>, not_null<Element*>, std::less<>> _itemsByData;
std::set<uint64> _eventIds;
std::map<not_null<const HistoryItem*>, not_null<Element*>> _itemsByData;
int _itemsTop = 0;
int _itemsWidth = 0;
int _itemsHeight = 0;

View File

@ -150,11 +150,11 @@ public:
void setItems(
std::vector<OwnedItem> &&items,
std::map<uint64, not_null<Element*>> &&itemsByIds,
std::set<uint64> &&eventIds,
bool upLoaded,
bool downLoaded) {
_items = std::move(items);
_itemsByIds = std::move(itemsByIds);
_eventIds = std::move(eventIds);
_upLoaded = upLoaded;
_downLoaded = downLoaded;
}
@ -170,8 +170,8 @@ public:
std::vector<OwnedItem> takeItems() {
return std::move(_items);
}
std::map<uint64, not_null<Element*>> takeItemsByIds() {
return std::move(_itemsByIds);
std::set<uint64> takeEventIds() {
return std::move(_eventIds);
}
std::shared_ptr<LocalIdManager> takeIdManager() {
return std::move(_idManager);
@ -195,7 +195,7 @@ private:
std::vector<not_null<UserData*>> _admins;
std::vector<not_null<UserData*>> _adminsCanEdit;
std::vector<OwnedItem> _items;
std::map<uint64, not_null<Element*>> _itemsByIds;
std::set<uint64> _eventIds;
bool _upLoaded = false;
bool _downLoaded = true;
std::shared_ptr<LocalIdManager> _idManager;