[Merge] lp:history-service/staging into lp:history-service
Gustavo Pichorim Boiko
gustavo.boiko at canonical.com
Thu Nov 24 01:57:36 UTC 2016
Debug prints removed, question answered and loops changed on a separate MR.
Diff comments:
>
> === modified file 'Ubuntu/History/historymodel.cpp'
> --- Ubuntu/History/historymodel.cpp 2015-10-08 21:52:59 +0000
> +++ Ubuntu/History/historymodel.cpp 2016-10-20 14:04:14 +0000
> @@ -89,16 +92,98 @@
> case TypeRole:
> result = properties[History::FieldType];
> break;
> - case ParticipantsRole:
> + case ParticipantsRole: {
> + // FIXME: reimplement in a cleaner way
> + History::Participants participants = History::Participants::fromVariantList(properties[History::FieldParticipants].toList());
> if (mMatchContacts) {
> - result = History::ContactMatcher::instance()->contactInfo(properties[History::FieldAccountId].toString(),
> - History::Participants::fromVariantList(properties[History::FieldParticipants].toList()).identifiers());
> + QVariantList finalParticipantsList;
> + QVariantList participantsInfo = History::ContactMatcher::instance()->contactInfo(properties[History::FieldAccountId].toString(),
> + participants.identifiers());
> + int count = 0;
> + Q_FOREACH(const QVariant &participantInfo, participantsInfo) {
> + QVariantMap newMap = participantInfo.toMap();
> + if (participants.at(count).state() != History::ParticipantStateRegular) {
> + count++;
> + continue;
> + }
> + newMap[History::FieldParticipantState] = participants.at(count).state();
> + newMap[History::FieldParticipantRoles] = participants.at(count++).roles();
> + finalParticipantsList << newMap;
> + }
All those Q_FOREACH() comments were addressed here:
https://code.launchpad.net/~phablet-team/history-service/simplify_participant_filtering/+merge/311674
> + result = finalParticipantsList;
> } else {
> //FIXME: handle contact changes
> result = properties[History::FieldParticipants];
> }
> break;
> }
> + case ParticipantsRemotePendingRole: {
> + // FIXME: reimplement in a cleaner way
> + QStringList identifiers;
> + History::Participants participants;
> + // filter remote pending participants
> + Q_FOREACH(const History::Participant &participant, History::Participants::fromVariantList(properties[History::FieldParticipants].toList())) {
> + if (participant.state() == History::ParticipantStateRemotePending) {
> + participants << participant;
> + }
> + }
> +
> + if (mMatchContacts) {
> + QVariantList finalParticipantsList;
> + QVariantList participantsInfo = History::ContactMatcher::instance()->contactInfo(properties[History::FieldAccountId].toString(),
> + participants.identifiers());
> + int count = 0;
> + Q_FOREACH(const QVariant &participantInfo, participantsInfo) {
> + QVariantMap newMap = participantInfo.toMap();
> + newMap[History::FieldParticipantState] = participants.at(count).state();
> + newMap[History::FieldParticipantRoles] = participants.at(count++).roles();
> + finalParticipantsList << newMap;
> + }
> + result = finalParticipantsList;
> + } else {
> + //FIXME: handle contact changes
> + result = participants.identifiers();
> + }
> +
> + break;
> + }
> + case ParticipantsLocalPendingRole: {
> + // FIXME: reimplement in a cleaner way
> + QStringList identifiers;
> + History::Participants participants;
> + Q_FOREACH(const History::Participant &participant, History::Participants::fromVariantList(properties[History::FieldParticipants].toList())) {
> + if (participant.state() == History::ParticipantStateLocalPending) {
> + participants << participant;
> + }
> + }
> +
> + if (mMatchContacts) {
> + QVariantList finalParticipantsList;
> + QVariantList participantsInfo = History::ContactMatcher::instance()->contactInfo(properties[History::FieldAccountId].toString(),
> + identifiers);
> + int count = 0;
> + Q_FOREACH(const QVariant &participantInfo, participantsInfo) {
> + QVariantMap newMap = participantInfo.toMap();
> + newMap[History::FieldParticipantState] = participants.at(count).state();
> + newMap[History::FieldParticipantRoles] = participants.at(count++).roles();
> + finalParticipantsList << newMap;
> + }
> + result = finalParticipantsList;
> + } else {
> + //FIXME: handle contact changes
> + result = identifiers;
> + }
> +
> + break;
> + }
> + case ParticipantIdsRole:
> + result = History::Participants::fromVariantList(properties[History::FieldParticipants].toList()).identifiers();
> + break;
> + case TimestampRole:
> + result = QDateTime::fromString(properties[History::FieldTimestamp].toString(), Qt::ISODate);
> + break;
> + }
> +
> return result;
> }
>
>
> === modified file 'daemon/historydaemon.cpp'
> --- daemon/historydaemon.cpp 2015-11-20 12:53:49 +0000
> +++ daemon/historydaemon.cpp 2016-10-20 14:04:14 +0000
> @@ -414,8 +613,270 @@
> event[History::FieldMissed] = missed;
> event[History::FieldDuration] = duration;
> // FIXME: check what to do when there are more than just one remote participant
> - event[History::FieldRemoteParticipant] = participants[0];
> - writeEvents(QList<QVariantMap>() << event);
> + event[History::FieldRemoteParticipant] = participants[0].toMap()[History::FieldIdentifier];
> + writeEvents(QList<QVariantMap>() << event, properties);
> +}
> +
> +void HistoryDaemon::onTextChannelAvailable(const Tp::TextChannelPtr channel)
> +{
> + // for Rooms we need to explicitly create the thread to allow users to send messages to groups even
> + // before they receive any message.
> + // for other types, we can wait until messages are received
> + if (channel->targetHandleType() == Tp::HandleTypeRoom) {
> + QString accountId = channel->property(History::FieldAccountId).toString();
> + QVariantMap properties = propertiesFromChannel(channel);
> +
> + // first try to fetch the existing thread to see if there is any.
> + QVariantMap thread = threadForProperties(accountId,
> + History::EventTypeText,
> + properties,
> + matchFlagsForChannel(channel),
> + false);
> + if (thread.isEmpty()) {
> + // if there no existing thread, create one
> + properties["Requested"] = channel->isRequested();
> + thread = threadForProperties(accountId,
> + History::EventTypeText,
> + properties,
> + matchFlagsForChannel(channel),
> + true);
> +
> + // write information event including all initial invitees
> + Q_FOREACH(const Tp::ContactPtr contact, channel->groupRemotePendingContacts(false)) {
> + writeInformationEvent(thread, History::InformationTypeInvitationSent, contact->alias());
> + }
> +
> + // update participants only if the thread is not available previously. Otherwise we'll wait for membersChanged event
> + // for reflect in conversation information events for modified participants.
> + updateRoomParticipants(channel);
> + }
> +
> + // write an entry saying you joined the group if 'joined' flag in thread is false and modify that flag.
> + if (!thread[History::FieldChatRoomInfo].toMap()["Joined"].toBool()) {
All the chat room info properties are like that now. Maybe it would be better to do that in a separate MR to be reviewed separate?
> + writeInformationEvent(thread, History::InformationTypeSelfJoined);
> + // update backend
> + updateRoomProperties(channel, QVariantMap{{"Joined", true}});
> + }
> +
> + Tp::AbstractInterface *room_interface = channel->optionalInterface<Tp::Client::ChannelInterfaceRoomInterface>();
> + Tp::AbstractInterface *room_config_interface = channel->optionalInterface<Tp::Client::ChannelInterfaceRoomConfigInterface>();
> + Tp::AbstractInterface *subject_interface = channel->optionalInterface<Tp::Client::ChannelInterfaceSubjectInterface>();
> + ChannelInterfaceRolesInterface *roles_interface = channel->optionalInterface<ChannelInterfaceRolesInterface>();
> +
> + QList<Tp::AbstractInterface*> interfaces;
> + interfaces << room_interface << room_config_interface << subject_interface << roles_interface;
> + for (auto interface : interfaces) {
> + if (interface) {
> + interface->setMonitorProperties(true);
> + interface->setProperty(History::FieldAccountId, accountId);
> + interface->setProperty(History::FieldThreadId, thread[History::FieldThreadId].toString());
> + interface->setProperty(History::FieldType, thread[History::FieldType].toInt());
> + connect(interface, SIGNAL(propertiesChanged(const QVariantMap &,const QStringList &)),
> + SLOT(onRoomPropertiesChanged(const QVariantMap &,const QStringList &)));
> + // update the stored info
> + Q_EMIT interface->propertiesChanged(getInterfaceProperties(interface), QStringList());
> + }
> + }
> +
> + connect(channel.data(), SIGNAL(groupMembersChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)),
> + SLOT(onGroupMembersChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)));
> +
> + connect(roles_interface, SIGNAL(RolesChanged(const HandleRolesMap&, const HandleRolesMap&)), SLOT(onRolesChanged(const HandleRolesMap&, const HandleRolesMap&)));
> + }
> +}
> +
> +void HistoryDaemon::onGroupMembersChanged(const Tp::Contacts &groupMembersAdded,
> + const Tp::Contacts &groupLocalPendingMembersAdded,
> + const Tp::Contacts &groupRemotePendingMembersAdded,
> + const Tp::Contacts &groupMembersRemoved,
> + const Tp::Channel::GroupMemberChangeDetails &details)
> +{
> + Tp::TextChannelPtr channel(qobject_cast<Tp::TextChannel*>(sender()));
> +
> + QVariantMap properties;
> + QVariantMap thread;
> +
> + // information events for members updates.
> + bool hasRemotePendingMembersAdded = groupRemotePendingMembersAdded.size() > 0;
> + bool hasMembersAdded = groupMembersAdded.size() > 0;
> + bool hasMembersRemoved = groupMembersRemoved.size() > 0;
> +
> + if (hasRemotePendingMembersAdded || hasMembersAdded || hasMembersRemoved) {
> + properties = propertiesFromChannel(channel);
> + thread = threadForProperties(channel->property(History::FieldAccountId).toString(),
> + History::EventTypeText,
> + properties,
> + matchFlagsForChannel(channel),
> + false);
> + if (!thread.isEmpty()) {
> + if (hasRemotePendingMembersAdded) {
> + Q_FOREACH (const Tp::ContactPtr& contact, groupRemotePendingMembersAdded) {
> + if (!foundInThread(contact, thread)) {
> + writeInformationEvent(thread, History::InformationTypeInvitationSent, contact->alias());
> + }
> + }
> + }
> + if (hasMembersAdded) {
> + Q_FOREACH (const Tp::ContactPtr& contact, groupMembersAdded) {
> + // if this member was not previously regular member in thread, notify about his join
> + if (!foundAsMemberInThread(contact, thread)) {
> + writeInformationEvent(thread, History::InformationTypeJoined, contact->alias());
> + }
> + }
> + }
> +
> + if (hasMembersRemoved) {
> + if (channel->groupSelfContactRemoveInfo().isValid()) {
> + // evaluate if we are leaving by our own or we are kicked
> + History::InformationType type = History::InformationTypeSelfLeaving;
> + if (channel->groupSelfContactRemoveInfo().hasReason()) {
> + switch (channel->groupSelfContactRemoveInfo().reason()) {
> + case ChannelGroupChangeReasonKicked:
> + type = History::InformationTypeSelfKicked;
> + break;
> + case ChannelGroupChangeReasonGone:
> + type = History::InformationTypeGroupGone;
> + break;
> + }
> + }
> + writeInformationEvent(thread, type);
> + // update backend
> + updateRoomProperties(channel, QVariantMap{{"Joined", false}});
> + }
> + else // don't notify any other group member removal if we are leaving the group
> + {
> + Q_FOREACH (const Tp::ContactPtr& contact, groupMembersRemoved) {
> + // inform about removed members other than us
> + if (contact->id() != channel->groupSelfContact()->id()) {
> + writeInformationEvent(thread, History::InformationTypeLeaving, contact->alias());
> + }
> + }
> + }
> + }
> + }
> + }
> +
> + updateRoomParticipants(channel);
> +}
> +
> +void HistoryDaemon::updateRoomParticipants(const Tp::TextChannelPtr channel)
> +{
> + if (!channel) {
> + return;
> + }
> +
> + QVariantList participants;
> + QStringList contactsAdded;
> +
> + ChannelInterfaceRolesInterface *roles_interface = channel->optionalInterface<ChannelInterfaceRolesInterface>();
> + RolesMap roles;
> + if (roles_interface) {
> + roles = roles_interface->getRoles();
> + }
> +
> + Q_FOREACH(const Tp::ContactPtr contact, channel->groupRemotePendingContacts(false)) {
> + QVariantMap participant;
> + contactsAdded << contact->id();
> + participant[History::FieldIdentifier] = contact->id();
> + participant[History::FieldAlias] = contact->alias();
> + participant[History::FieldParticipantState] = History::ParticipantStateRemotePending;
> + participant[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
> + participants << QVariant::fromValue(participant);
> + }
> + Q_FOREACH(const Tp::ContactPtr contact, channel->groupLocalPendingContacts(false)) {
> + QVariantMap participant;
> + contactsAdded << contact->id();
> + participant[History::FieldIdentifier] = contact->id();
> + participant[History::FieldAlias] = contact->alias();
> + participant[History::FieldParticipantState] = History::ParticipantStateLocalPending;
> + participant[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
> + participants << QVariant::fromValue(participant);
> + }
> +
> + Q_FOREACH(const Tp::ContactPtr contact, channel->groupContacts(false)) {
> + // do not include remote and local pending members
> + if (contactsAdded.contains(contact->id())) {
> + continue;
> + }
> + QVariantMap participant;
> + participant[History::FieldIdentifier] = contact->id();
> + participant[History::FieldAlias] = contact->alias();
> + participant[History::FieldParticipantState] = History::ParticipantStateRegular;
> + participant[History::FieldParticipantRoles] = roles[contact->handle().at(0)];
> + participants << QVariant::fromValue(participant);
> + }
> +
> + QString accountId = channel->property(History::FieldAccountId).toString();
> + QString threadId = channel->targetId();
> + if (mBackend->updateRoomParticipants(accountId, threadId, History::EventTypeText, participants)) {
> + QVariantMap updatedThread = getSingleThread(History::EventTypeText, accountId, threadId, QVariantMap());
> + mDBus.notifyThreadsModified(QList<QVariantMap>() << updatedThread);
> + }
> +}
> +
> +void HistoryDaemon::updateRoomRoles(const Tp::TextChannelPtr &channel, const RolesMap &rolesMap)
> +{
> + if (!channel) {
> + return;
> + }
> +
> + QVariantMap participantsRoles;
> +
> + Q_FOREACH(const Tp::ContactPtr contact, channel->groupRemotePendingContacts(false)) {
> + participantsRoles[contact->id()] = rolesMap[contact->handle().at(0)];
> + }
> + Q_FOREACH(const Tp::ContactPtr contact, channel->groupLocalPendingContacts(false)) {
> + participantsRoles[contact->id()] = rolesMap[contact->handle().at(0)];
> + }
> +
> + Q_FOREACH(const Tp::ContactPtr contact, channel->groupContacts(false)) {
> + if (!participantsRoles.contains(contact->id())) {
> + participantsRoles[contact->id()] = rolesMap[contact->handle().at(0)];
> + }
> + }
> +
> + // update participants roles
> + QString accountId = channel->property(History::FieldAccountId).toString();
> + QString threadId = channel->targetId();
> + if (mBackend->updateRoomParticipantsRoles(accountId, threadId, History::EventTypeText, participantsRoles)) {
> + QVariantMap updatedThread = getSingleThread(History::EventTypeText, accountId, threadId, QVariantMap());
> + mDBus.notifyThreadsModified(QList<QVariantMap>() << updatedThread);
> + }
> +
> + // update self roles in room properties
> + uint selfRoles = rolesMap[channel->groupSelfContact()->handle().at(0)];
> + updateRoomProperties(channel, QVariantMap{{"SelfRoles", selfRoles}});
> +}
> +
> +void HistoryDaemon::onRoomPropertiesChanged(const QVariantMap &properties,const QStringList &invalidated)
> +{
> + QString accountId = sender()->property(History::FieldAccountId).toString();
> + QString threadId = sender()->property(History::FieldThreadId).toString();
> + History::EventType type = (History::EventType)sender()->property(History::FieldType).toInt();
> +
> + // get thread before updating to see if there are changes to insert as information events
> + QVariantMap thread = getSingleThread(type, accountId, threadId, QVariantMap());
> + if (!thread.empty()) {
> + writeRoomChangesInformationEvents(thread, properties);
> + }
> +
> + updateRoomProperties(accountId, threadId, type, properties, invalidated);
> +}
> +
> +void HistoryDaemon::updateRoomProperties(const Tp::TextChannelPtr &channel, const QVariantMap &properties)
> +{
> + QString accountId = channel->property(History::FieldAccountId).toString();
> + QString threadId = channel->targetId();
> + History::EventType type = History::EventTypeText;
> + updateRoomProperties(accountId, threadId, type, properties, QStringList());
> +}
> +
> +void HistoryDaemon::updateRoomProperties(const QString &accountId, const QString &threadId, History::EventType type, const QVariantMap &properties, const QStringList &invalidated)
> +{
> + if (mBackend->updateRoomInfo(accountId, threadId, type, properties, invalidated)) {
> + QVariantMap thread = getSingleThread(type, accountId, threadId, QVariantMap());
> + mDBus.notifyThreadsModified(QList<QVariantMap>() << thread);
> + }
> }
>
> void HistoryDaemon::onMessageReceived(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message)
--
https://code.launchpad.net/~phablet-team/history-service/staging/+merge/308933
Your team Ubuntu Phablet Team is subscribed to branch lp:history-service.
More information about the Ubuntu-reviews
mailing list