Branch 'kolab/integration/4.13.0' - 2 commits - akonadi/calendar

Sandro Knauß knauss at kolabsys.com
Thu Mar 5 15:15:47 CET 2015


 akonadi/calendar/incidencechanger.cpp           |   59 +++++-
 akonadi/calendar/tests/incidencechangertest.cpp |  219 ++++++++++++++++++++++++
 2 files changed, 273 insertions(+), 5 deletions(-)

New commits:
commit d204ffcb187c762a089091b40adadca9b6353b11
Author: Sandro Knauß <knauss at kolabsys.com>
Date:   Thu Mar 5 15:12:20 2015 +0100

    Only alarm modifications should not trigger a out-of-sync event
    
    Users should be able to set their own alarm settings for events without
    triggering a out-of-sync dialog.
    
    KOLAB #1386

diff --git a/akonadi/calendar/incidencechanger.cpp b/akonadi/calendar/incidencechanger.cpp
index a038ced..8f51cef 100644
--- a/akonadi/calendar/incidencechanger.cpp
+++ b/akonadi/calendar/incidencechanger.cpp
@@ -69,6 +69,20 @@ bool weAreOrganizer(Incidence::Ptr incidence)
     return Akonadi::CalendarUtils::thatIsMe(email);
 }
 
+bool allowedModificationsWithoutRevisionUpdate(Incidence::Ptr incidence)
+{
+    // Modifications that are per user allowd without getting outofsync with organisator
+    // * if only alarm settings are modified.
+    const QSet<KCalCore::IncidenceBase::Field> dirtyFields = incidence->dirtyFields();
+    QSet<KCalCore::IncidenceBase::Field> alarmOnlyModify;
+    alarmOnlyModify << IncidenceBase::FieldAlarms << IncidenceBase::FieldLastModified;
+    if (dirtyFields == alarmOnlyModify) {
+        return true;
+    }
+
+    return false;
+}
+
 namespace Akonadi {
 // Does a queued emit, with QMetaObject::invokeMethod
 static void emitCreateFinished(IncidenceChanger *changer,
@@ -558,6 +572,11 @@ void IncidenceChanger::Private::handleInvitationsBeforeChange(const Change::Ptr
                 break;
             }
 
+            if (allowedModificationsWithoutRevisionUpdate(newIncidence)) {
+                change->emitUserDialogClosedBeforeChange(ITIPHandlerHelper::ResultSuccess);
+                return;
+            }
+
             if (RUNNING_UNIT_TESTS && !weAreOrganizer(newIncidence)) {
                 // This is a bit of a workaround when running tests. I don't want to show the
                 // "You're not organizer, do you want to modify event?" dialog in unit-tests, but want
@@ -679,6 +698,10 @@ void IncidenceChanger::Private::handleInvitationsAfterChange(const Change::Ptr &
                 break;
             }
 
+            if (allowedModificationsWithoutRevisionUpdate(newIncidence)) {
+                break;
+            }
+
             if (!neverSend && !alwaysSend && mInvitationStatusByAtomicOperation.contains(change->atomicOperationId)) {
                 handler->setDefaultAction(actionFromStatus(mInvitationStatusByAtomicOperation.value(change->atomicOperationId)));
             }
@@ -1028,9 +1051,11 @@ void IncidenceChanger::Private::performModification2(int changeId, ITIPHandlerHe
     }
 
     Incidence::Ptr incidence = CalendarUtils::incidence(newItem);
-    {   // increment revision ( KCalCore revision, not akonadi )
-        const int revision = incidence->revision();
-        incidence->setRevision(revision + 1);
+    {
+        if (!allowedModificationsWithoutRevisionUpdate(incidence)) {        // increment revision ( KCalCore revision, not akonadi )
+            const int revision = incidence->revision();
+            incidence->setRevision(revision + 1);
+        }
 
         //Reset attendee status, when resceduling
         QSet<IncidenceBase::Field> resetPartStatus;
diff --git a/akonadi/calendar/tests/incidencechangertest.cpp b/akonadi/calendar/tests/incidencechangertest.cpp
index 1766d9d..2cce1ed 100644
--- a/akonadi/calendar/tests/incidencechangertest.cpp
+++ b/akonadi/calendar/tests/incidencechangertest.cpp
@@ -377,6 +377,48 @@ private Q_SLOTS:
         }
     }
 
+    void testModifyingAlarmSettings()
+    {
+        // A user should be able to change alarm settings independently
+        // do not trigger a revision increment
+        // kolab #1386
+        Item item;
+        item.setMimeType(Event::eventMimeType());
+        Incidence::Ptr incidence = Incidence::Ptr(new Event());
+        incidence->setUid(QLatin1String("test123uid"));
+        incidence->setSummary(QLatin1String("summary"));
+        incidence->setOrganizer(Person::Ptr(new Person(QLatin1String("orga"), QLatin1String("orga at dev.nul"))));
+        incidence->setDirtyFields(QSet<IncidenceBase::Field>());
+        item.setPayload<KCalCore::Incidence::Ptr>(incidence);
+        ItemCreateJob *job = new ItemCreateJob(item, mCollection, this);
+        AKVERIFYEXEC(job);
+        item = job->item();
+        Alarm::Ptr alarm = Alarm::Ptr(new Alarm(incidence.data()));
+        alarm->setStartOffset(Duration(-15));
+        alarm->setType(Alarm::Display);
+        incidence->addAlarm(alarm);
+        item.setPayload<KCalCore::Incidence::Ptr>(incidence);
+
+        mChanger->setRespectsCollectionRights(true);
+        const int changeId = mChanger->modifyIncidence(item);
+        QVERIFY(changeId != -1);
+
+        mIncidencesToModify = 1;
+        mExpectedResultByChangeId.insert(changeId, IncidenceChanger::ResultCodeSuccess);
+        waitForSignals();
+        ItemFetchJob *fetchJob = new ItemFetchJob(item, this);
+        fetchJob->fetchScope().fetchFullPayload();
+        AKVERIFYEXEC(fetchJob);
+        QVERIFY(fetchJob->items().count() == 1);
+        Item fetchedItem = fetchJob->items().first();
+        QVERIFY(fetchedItem.isValid());
+        QVERIFY(fetchedItem.hasPayload<KCalCore::Incidence::Ptr>());
+        Incidence::Ptr incidence2 = fetchedItem.payload<KCalCore::Incidence::Ptr>();
+        QCOMPARE(incidence2->alarms().count(), 1);
+        QCOMPARE(incidence2->revision(), 0);
+        delete fetchJob;
+    }
+
     void testModifyRescedule_data()
     {
         // When a event is resceduled than all attendees part status should set to NEEDS-ACTION


commit caa4b133ac0dbb9c796108f1a3869f0f443e2940
Author: Sandro Knauß <knauss at kolabsys.com>
Date:   Thu Mar 5 15:05:25 2015 +0100

    rescedule event triggers attendee status to NEEDS-ACTION
    
    If an event is resceduled ( date or location) all attendees should be
    ask again, for there status. Therefore the partStatus should be set back
    to NEEDS-ACTION
    
    KOLAB: #4533

diff --git a/akonadi/calendar/incidencechanger.cpp b/akonadi/calendar/incidencechanger.cpp
index 0d0bddd..a038ced 100644
--- a/akonadi/calendar/incidencechanger.cpp
+++ b/akonadi/calendar/incidencechanger.cpp
@@ -63,6 +63,12 @@ ITIPHandlerDialogDelegate::Action actionFromStatus(ITIPHandlerHelper::SendResult
     }
 }
 
+bool weAreOrganizer(Incidence::Ptr incidence)
+{
+    const QString email = incidence->organizer()->email();
+    return Akonadi::CalendarUtils::thatIsMe(email);
+}
+
 namespace Akonadi {
 // Does a queued emit, with QMetaObject::invokeMethod
 static void emitCreateFinished(IncidenceChanger *changer,
@@ -552,8 +558,7 @@ void IncidenceChanger::Private::handleInvitationsBeforeChange(const Change::Ptr
                 break;
             }
 
-            const bool weAreOrganizer = Akonadi::CalendarUtils::thatIsMe(newIncidence->organizer()->email());
-            if (RUNNING_UNIT_TESTS && !weAreOrganizer) {
+            if (RUNNING_UNIT_TESTS && !weAreOrganizer(newIncidence)) {
                 // This is a bit of a workaround when running tests. I don't want to show the
                 // "You're not organizer, do you want to modify event?" dialog in unit-tests, but want
                 // to emulate a "yes" and a "no" press.
@@ -1026,6 +1031,25 @@ void IncidenceChanger::Private::performModification2(int changeId, ITIPHandlerHe
     {   // increment revision ( KCalCore revision, not akonadi )
         const int revision = incidence->revision();
         incidence->setRevision(revision + 1);
+
+        //Reset attendee status, when resceduling
+        QSet<IncidenceBase::Field> resetPartStatus;
+        resetPartStatus << IncidenceBase::FieldDtStart
+                        << IncidenceBase::FieldDtEnd
+                        << IncidenceBase::FieldDtStart
+                        << IncidenceBase::FieldLocation
+                        << IncidenceBase::FieldDtDue
+                        << IncidenceBase::FieldDuration
+                        << IncidenceBase::FieldRecurrence;
+        if (!(incidence->dirtyFields() & resetPartStatus).isEmpty() && weAreOrganizer(incidence)) {
+            foreach (const Attendee::Ptr &attendee, incidence->attendees()) {
+                if ( attendee->role() != Attendee::NonParticipant &&
+                    attendee->status() != Attendee::Delegated && !Akonadi::CalendarUtils::thatIsMe(attendee)) {
+                    attendee->setStatus(Attendee::NeedsAction);
+                    attendee->setRSVP(true);
+                }
+            }
+        }
     }
 
     // Dav Fix
diff --git a/akonadi/calendar/tests/incidencechangertest.cpp b/akonadi/calendar/tests/incidencechangertest.cpp
index 2d8d388..1766d9d 100644
--- a/akonadi/calendar/tests/incidencechangertest.cpp
+++ b/akonadi/calendar/tests/incidencechangertest.cpp
@@ -29,6 +29,7 @@
 #include <akonadi/itemfetchjob.h>
 #include <akonadi/itemcreatejob.h>
 #include <akonadi/itemfetchscope.h>
+#include <akonadi/itemdeletejob.h>
 
 #include <kcalcore/event.h>
 #include <kcalcore/journal.h>
@@ -46,6 +47,9 @@ Q_DECLARE_METATYPE(QList<Akonadi::Collection::Rights>)
 Q_DECLARE_METATYPE(QList<Akonadi::IncidenceChanger::ResultCode>)
 Q_DECLARE_METATYPE(KCalCore::RecurrenceRule::PeriodType)
 
+QString s_ourEmail = QLatin1String("unittests at dev.nul"); // change also in kdepimlibs/akonadi/calendar/tests/unittestenv/kdehome/share/config
+QString s_outEmail2 = QLatin1String("identity2 at kde.org");
+
 static Akonadi::Item item()
 {
     Item item;
@@ -373,6 +377,179 @@ private Q_SLOTS:
         }
     }
 
+    void testModifyRescedule_data()
+    {
+        // When a event is resceduled than all attendees part status should set to NEEDS-ACTION
+        // kolab #4533
+        QTest::addColumn<Akonadi::Item>("item");
+        QTest::addColumn<Event::Ptr>("event");
+        QTest::addColumn<bool>("expectReset");
+
+        const Attendee::Ptr us = Attendee::Ptr(new Attendee(QString(), s_ourEmail));
+        us->setStatus(Attendee::Accepted);
+        const Attendee::Ptr mia = Attendee::Ptr(new Attendee(QLatin1String("Mia Wallace"), QLatin1String("mia at dev.nul")));
+        mia->setStatus(Attendee::Declined);
+        mia->setRSVP(false);
+        const Attendee::Ptr vincent = Attendee::Ptr(new Attendee(QLatin1String("Vincent"), QLatin1String("vincent at dev.nul")));
+        vincent->setStatus(Attendee::Delegated);
+        const Attendee::Ptr jules = Attendee::Ptr(new Attendee(QLatin1String("Jules"), QLatin1String("jules at dev.nul")));
+        jules->setStatus(Attendee::Accepted);
+        jules->setRole(Attendee::NonParticipant);
+
+        // we as organizator
+        Item item;
+        item.setMimeType(Event::eventMimeType());
+        Event::Ptr incidence = Event::Ptr(new Event());
+        incidence->setUid(QLatin1String("test123uid"));
+        incidence->setDtStart(KDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), KDateTime::UTC));
+        incidence->setDtEnd(KDateTime(QDate(2006, 1, 8), QTime(14, 0, 0), KDateTime::UTC));
+        incidence->setAllDay(false);
+        incidence->setLocation(QLatin1String("location"));
+        incidence->setOrganizer(Person::Ptr(new Person(QString(), s_ourEmail)));
+        incidence->addAttendee(us);
+        incidence->addAttendee(mia);
+        incidence->addAttendee(vincent);
+        incidence->addAttendee(jules);
+        incidence->setDirtyFields(QSet<IncidenceBase::Field>());
+        item.setPayload<KCalCore::Incidence::Ptr>(incidence);
+
+        {
+            Event::Ptr event = Event::Ptr(new Event(*incidence));
+            event->setDtStart(KDateTime(QDate(2006, 1, 8), QTime(13, 0, 0), KDateTime::UTC));
+            QCOMPARE(event->dirtyFields().count(), 1);
+            QTest::newRow("organizator:start Date") << item << event << true;
+        }
+
+        {
+            Event::Ptr event = Event::Ptr(new Event(*incidence));
+            event->setDtEnd(KDateTime(QDate(2006, 1, 8), QTime(13, 0, 0), KDateTime::UTC));
+            QCOMPARE(event->dirtyFields().count(), 1);
+            QTest::newRow("organizator:end Date") << item << event << true;
+        }
+
+        {
+            Event::Ptr event = Event::Ptr(new Event(*incidence));
+            event->setAllDay(true);
+            QCOMPARE(event->dirtyFields().count(), 2);
+            QTest::newRow("organizator:allDay") << item << event << true;
+        }
+
+        {
+            Event::Ptr event = Event::Ptr(new Event(*incidence));
+            event->setLocation(QLatin1String("location2"));
+            QCOMPARE(event->dirtyFields().count(), 1);
+            QTest::newRow("organizator:location") << item << event << true;
+        }
+
+        {
+            Event::Ptr event = Event::Ptr(new Event(*incidence));
+            event->setSummary(QLatin1String("summary"));
+            QCOMPARE(event->dirtyFields().count(), 1);
+            QTest::newRow("organizator:summary") << item << event << false;
+        }
+
+        //we are normal attendee
+        Item item2;
+        item2.setMimeType(Event::eventMimeType());
+        Event::Ptr incidence2 = Event::Ptr(new Event());
+        incidence2->setUid(QLatin1String("test123uid"));
+        incidence2->setDtStart(KDateTime(QDate(2006, 1, 8), QTime(12, 0, 0), KDateTime::UTC));
+        incidence2->setDtEnd(KDateTime(QDate(2006, 1, 8), QTime(14, 0, 0), KDateTime::UTC));
+        incidence2->setAllDay(false);
+        incidence2->setLocation(QLatin1String("location"));
+        incidence2->setOrganizer(Person::Ptr(new Person(QLatin1String("External organizator"), QLatin1String("exorga at dev.nul"))));
+        incidence2->addAttendee(us);
+        incidence2->addAttendee(mia);
+        incidence2->addAttendee(vincent);
+        incidence2->addAttendee(jules);
+        incidence2->setDirtyFields(QSet<IncidenceBase::Field>());
+        item2.setPayload<KCalCore::Incidence::Ptr>(incidence2);
+
+        {
+            Event::Ptr event = Event::Ptr(new Event(*incidence2));
+            event->setDtStart(KDateTime(QDate(2006, 1, 8), QTime(13, 0, 0), KDateTime::UTC));
+            QTest::newRow("attendee:start Date") << item2 << event << false;
+        }
+
+        {
+            Event::Ptr event = Event::Ptr(new Event(*incidence2));
+            event->setDtEnd(KDateTime(QDate(2006, 1, 8), QTime(13, 0, 0), KDateTime::UTC));
+            QTest::newRow("attendee:end Date") << item2 << event << false;
+        }
+
+        {
+            Event::Ptr event = Event::Ptr(new Event(*incidence2));
+            event->setAllDay(false);
+            QTest::newRow("attendee:allDay") << item2 << event << false;
+        }
+
+        {
+            Event::Ptr event = Event::Ptr(new Event(*incidence2));
+            event->setLocation(QLatin1String("location2"));
+            QTest::newRow("attendee:location") << item2 << event << false;
+        }
+
+        {
+            Event::Ptr event = Event::Ptr(new Event(*incidence2));
+            event->setSummary(QLatin1String("summary"));
+            QTest::newRow("attendee:summary") << item2 << event << false;
+        }
+
+    }
+
+    void testModifyRescedule()
+    {
+        QFETCH(Akonadi::Item, item);
+        QFETCH(Event::Ptr, event);
+        QFETCH(bool, expectReset);
+
+        item.setId(-1);
+        ItemCreateJob *job = new ItemCreateJob(item, mCollection, this);
+        AKVERIFYEXEC(job);
+        item = job->item();
+        item.setPayload<KCalCore::Incidence::Ptr>(event);
+
+        int revision = event->revision();
+
+        mChanger->setRespectsCollectionRights(true);
+        const int changeId = mChanger->modifyIncidence(item);
+        QVERIFY(changeId != -1);
+
+        mIncidencesToModify = 1;
+        mExpectedResultByChangeId.insert(changeId, IncidenceChanger::ResultCodeSuccess);
+        waitForSignals();
+        ItemFetchJob *fetchJob = new ItemFetchJob(item, this);
+        fetchJob->fetchScope().fetchFullPayload();
+        AKVERIFYEXEC(fetchJob);
+        QVERIFY(fetchJob->items().count() == 1);
+        Item fetchedItem = fetchJob->items().first();
+
+        QVERIFY(fetchedItem.isValid());
+        QVERIFY(fetchedItem.hasPayload<KCalCore::Event::Ptr>());
+        Event::Ptr incidence = fetchedItem.payload<KCalCore::Event::Ptr>();
+
+        QCOMPARE(incidence->revision(), revision + 1);
+
+        if (expectReset) {
+            if (incidence->organizer()->email() == s_ourEmail) {
+                QCOMPARE(incidence->attendeeByMail(s_ourEmail)->status(), Attendee::Accepted);
+            } else {
+                QCOMPARE(incidence->attendeeByMail(s_ourEmail)->status(), Attendee::NeedsAction);
+            }
+            QCOMPARE(incidence->attendeeByMail(QLatin1String("mia at dev.nul"))->status(), Attendee::NeedsAction);
+            QCOMPARE(incidence->attendeeByMail(QLatin1String("mia at dev.nul"))->RSVP(), true);
+            QCOMPARE(incidence->attendeeByMail(QLatin1String("vincent at dev.nul"))->status(), Attendee::Delegated);
+            QCOMPARE(incidence->attendeeByMail(QLatin1String("vincent at dev.nul"))->RSVP(), false);
+            QCOMPARE(incidence->attendeeByMail(QLatin1String("jules at dev.nul"))->status(), Attendee::Accepted);
+            QCOMPARE(incidence->attendeeByMail(QLatin1String("jules at dev.nul"))->RSVP(), false);
+        } else {
+            QCOMPARE(incidence->attendeeByMail(s_ourEmail)->status(), Attendee::Accepted);
+            QCOMPARE(incidence->attendeeByMail(QLatin1String("mia at dev.nul"))->status(), Attendee::Declined);
+            QCOMPARE(incidence->attendeeByMail(QLatin1String("vincent at dev.nul"))->status(), Attendee::Delegated);
+            QCOMPARE(incidence->attendeeByMail(QLatin1String("jules at dev.nul"))->status(), Attendee::Accepted);
+        }
+        delete fetchJob;
+    }
     void testMassModifyForConflicts_data()
     {
         QTest::addColumn<Akonadi::Item>("item");




More information about the commits mailing list