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) { for (auto [user, canEdit] : filtered) {
_admins.push_back(user); _admins.emplace_back(user);
if (canEdit) { 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->setAdminsCanEdit(std::move(_adminsCanEdit));
memento->setSearchQuery(std::move(_searchQuery)); memento->setSearchQuery(std::move(_searchQuery));
if (!_filterChanged) { if (!_filterChanged) {
memento->setItems(std::move(_items), std::move(_itemsByIds), _upLoaded, _downLoaded); memento->setItems(
memento->setIdManager(std::move(_idManager)); 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. _upLoaded = _downLoaded = true; // Don't load or handle anything anymore.
} }
@ -540,8 +545,9 @@ void InnerWidget::restoreState(not_null<SectionMemento*> memento) {
_items = memento->takeItems(); _items = memento->takeItems();
for (auto &item : _items) { for (auto &item : _items) {
item.refreshView(this); item.refreshView(this);
_itemsByData.emplace(item->data(), item.get());
} }
_itemsByIds = memento->takeItemsByIds(); _eventIds = memento->takeEventIds();
if (auto manager = memento->takeIdManager()) { if (auto manager = memento->takeIdManager()) {
_idManager = std::move(manager); _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. // When loading items down we add them to a new vector and copy _items after them.
auto newItemsForDownDirection = std::vector<OwnedItem>(); auto newItemsForDownDirection = std::vector<OwnedItem>();
auto oldItemsCount = _items.size(); auto oldItemsCount = _items.size();
auto &addToItems = (direction == Direction::Up) ? _items : newItemsForDownDirection; auto &addToItems = (direction == Direction::Up)
? _items
: newItemsForDownDirection;
addToItems.reserve(oldItemsCount + events.size() * 2); addToItems.reserve(oldItemsCount + events.size() * 2);
for_const (auto &event, events) { for (const auto &event : events) {
Assert(event.type() == mtpc_channelAdminLogEvent); event.match([&](const MTPDchannelAdminLogEvent &data) {
const auto &data = event.c_channelAdminLogEvent(); const auto id = data.vid.v;
const auto id = data.vid.v; if (_eventIds.find(id) != _eventIds.end()) {
if (_itemsByIds.find(id) != _itemsByIds.cend()) { return;
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]);
} }
}
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()); auto newItemsCount = _items.size() + ((direction == Direction::Up) ? 0 : newItemsForDownDirection.size());
if (newItemsCount != oldItemsCount) { if (newItemsCount != oldItemsCount) {
@ -662,11 +670,11 @@ void InnerWidget::addEvents(Direction direction, const QVector<MTPChannelAdminLo
} }
void InnerWidget::updateMinMaxIds() { void InnerWidget::updateMinMaxIds() {
if (_itemsByIds.empty() || _filterChanged) { if (_eventIds.empty() || _filterChanged) {
_maxId = _minId = 0; _maxId = _minId = 0;
} else { } else {
_maxId = (--_itemsByIds.end())->first; _maxId = *_eventIds.rbegin();
_minId = _itemsByIds.begin()->first; _minId = *_eventIds.begin();
if (_minId == 1) { if (_minId == 1) {
_upLoaded = true; _upLoaded = true;
} }
@ -836,7 +844,8 @@ void InnerWidget::clearAfterFilterChange() {
_selectedText = TextSelection(); _selectedText = TextSelection();
_filterChanged = false; _filterChanged = false;
_items.clear(); _items.clear();
_itemsByIds.clear(); _eventIds.clear();
_itemsByData.clear();
_idManager = nullptr; _idManager = nullptr;
_idManager = _history->adminLogIdManager(); _idManager = _history->adminLogIdManager();
updateEmptyText(); updateEmptyText();
@ -1133,7 +1142,9 @@ void InnerWidget::suggestRestrictUser(not_null<UserData*> user) {
auto weak = QPointer<InnerWidget>(this); auto weak = QPointer<InnerWidget>(this);
auto weakBox = std::make_shared<QPointer<EditRestrictedBox>>(); auto weakBox = std::make_shared<QPointer<EditRestrictedBox>>();
auto box = Box<EditRestrictedBox>(_channel, user, hasAdminRights, currentRights); 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) { if (weak) {
weak->restrictUser(user, oldRights, newRights); weak->restrictUser(user, oldRights, newRights);
} }
@ -1148,7 +1159,10 @@ void InnerWidget::suggestRestrictUser(not_null<UserData*> user) {
if (base::contains(_admins, user)) { if (base::contains(_admins, user)) {
editRestrictions(true, MTP_chatBannedRights(MTP_flags(0), MTP_int(0))); editRestrictions(true, MTP_chatBannedRights(MTP_flags(0), MTP_int(0)));
} else { } 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); Expects(result.type() == mtpc_channels_channelParticipant);
auto &participant = result.c_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. // for each found userpic (from the top to the bottom) using enumerateItems() method.
// //
// Method has "bool (*Method)(not_null<Element*> view, int userpicTop)" signature // 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> template <typename Method>
void enumerateUserpics(Method method); void enumerateUserpics(Method method);
@ -198,7 +198,7 @@ private:
// for each found date element (from the bottom to the top) using enumerateItems() method. // 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 // 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> template <typename Method>
void enumerateDates(Method method); void enumerateDates(Method method);
@ -206,8 +206,8 @@ private:
not_null<ChannelData*> _channel; not_null<ChannelData*> _channel;
not_null<History*> _history; not_null<History*> _history;
std::vector<OwnedItem> _items; std::vector<OwnedItem> _items;
std::map<uint64, not_null<Element*>> _itemsByIds; std::set<uint64> _eventIds;
std::map<not_null<HistoryItem*>, not_null<Element*>, std::less<>> _itemsByData; std::map<not_null<const HistoryItem*>, not_null<Element*>> _itemsByData;
int _itemsTop = 0; int _itemsTop = 0;
int _itemsWidth = 0; int _itemsWidth = 0;
int _itemsHeight = 0; int _itemsHeight = 0;

View File

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