Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 15b08ca5 authored by Patrick Lang's avatar Patrick Lang Committed by GitHub
Browse files

#16 store uid correctly when creating related to entries (#17)

* Ignore RELATED-TO when entry links to itself
Closes #14

* Fixed issue with setting a wrong UID that could cause problematic self-references when uploading to the server again
Closes #16

* Fixed test
parent 9d57f4c3
Loading
Loading
Loading
Loading
+140 −1
Original line number Diff line number Diff line
@@ -92,6 +92,146 @@ class JtxCollectionTest {
        assertEquals(1, icalobjects.size)
    }

    @Test
    fun updateRelatedTo_check_update_of_linkedId_CHILD_to_PARENT_is_present() {
        JtxCollection.create(testAccount, client, cv)
        val collections = JtxCollection.find(testAccount, client, context, TestJtxCollection.Factory, null, null)

        // insert 2 icalobjects
        val parentCV = ContentValues().apply {
            put(JtxContract.JtxICalObject.SUMMARY, "summary")
            put(JtxContract.JtxICalObject.COMPONENT, JtxContract.JtxICalObject.Component.VJOURNAL.name)
            put(JtxContract.JtxICalObject.UID, "AAA")
            put(JtxContract.JtxICalObject.ICALOBJECT_COLLECTIONID, collections[0].id)
        }
        val parentUri = client.insert(JtxContract.JtxICalObject.CONTENT_URI.asSyncAdapter(testAccount), parentCV)
        val childCV = ContentValues().apply {
            put(JtxContract.JtxICalObject.SUMMARY, "summary")
            put(JtxContract.JtxICalObject.COMPONENT, JtxContract.JtxICalObject.Component.VJOURNAL.name)
            put(JtxContract.JtxICalObject.UID, "BBB")
            put(JtxContract.JtxICalObject.ICALOBJECT_COLLECTIONID, collections[0].id)
        }
        val childUri = client.insert(JtxContract.JtxICalObject.CONTENT_URI.asSyncAdapter(testAccount), childCV)

        val icalobjects = collections[0].queryICalObjects(null, null)
        assertEquals(2, icalobjects.size)

        // link one of them to the other with PARENT reltype
        val parentRelCV = ContentValues().apply {
            put(JtxContract.JtxRelatedto.ICALOBJECT_ID, childUri?.lastPathSegment)
            put(JtxContract.JtxRelatedto.TEXT, "AAA")
            put(JtxContract.JtxRelatedto.RELTYPE, JtxContract.JtxRelatedto.Reltype.PARENT.name)
        }
        client.insert(JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(testAccount), parentRelCV)

        // update related to and check
        collections[0].updateRelatedTo()

        // check child to parent
        client.query(
            JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(testAccount),
            arrayOf(JtxContract.JtxRelatedto.ICALOBJECT_ID, JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, JtxContract.JtxRelatedto.TEXT, JtxContract.JtxRelatedto.RELTYPE),
            "${JtxContract.JtxRelatedto.ICALOBJECT_ID} = ?",
            arrayOf(childUri?.lastPathSegment),
            null
        ).use {
            assertNotNull(it)
            assertEquals(1, it?.count)
            it?.moveToFirst()
            assertEquals(childUri?.lastPathSegment?.toLong(), it?.getLong(0))   // ICALOBJECT_ID
            assertEquals(parentUri?.lastPathSegment?.toLong(), it?.getLong(1))   // LINKEDICALOBJECT_ID
            assertEquals("AAA", it?.getString(2))   // TEXT (UID)
            assertEquals(JtxContract.JtxRelatedto.Reltype.PARENT.name, it?.getString(3))
        }

        // check parent to child
        client.query(
            JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(testAccount),
            arrayOf(JtxContract.JtxRelatedto.ICALOBJECT_ID, JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, JtxContract.JtxRelatedto.TEXT, JtxContract.JtxRelatedto.RELTYPE),
            "${JtxContract.JtxRelatedto.ICALOBJECT_ID} = ?",
            arrayOf(parentUri?.lastPathSegment),
            null
        ).use {
            assertNotNull(it)
            assertEquals(1, it?.count)
            it?.moveToFirst()
            assertEquals(parentUri?.lastPathSegment?.toLong(), it?.getLong(0))   // ICALOBJECT_ID
            assertEquals(childUri?.lastPathSegment?.toLong(), it?.getLong(1))   // LINKEDICALOBJECT_ID
            assertEquals("BBB", it?.getString(2))   // TEXT (UID)
            assertEquals(JtxContract.JtxRelatedto.Reltype.CHILD.name, it?.getString(3))
        }
    }

    @Test
    fun updateRelatedTo_check_update_of_linkedId_PARENT_TO_CHILD_is_present() {
        JtxCollection.create(testAccount, client, cv)
        val collections = JtxCollection.find(testAccount, client, context, TestJtxCollection.Factory, null, null)

        // insert 2 icalobjects
        val parentCV = ContentValues().apply {
            put(JtxContract.JtxICalObject.SUMMARY, "summary")
            put(JtxContract.JtxICalObject.COMPONENT, JtxContract.JtxICalObject.Component.VJOURNAL.name)
            put(JtxContract.JtxICalObject.UID, "AAA")
            put(JtxContract.JtxICalObject.ICALOBJECT_COLLECTIONID, collections[0].id)
        }
        val parentUri = client.insert(JtxContract.JtxICalObject.CONTENT_URI.asSyncAdapter(testAccount), parentCV)
        val childCV = ContentValues().apply {
            put(JtxContract.JtxICalObject.SUMMARY, "summary")
            put(JtxContract.JtxICalObject.COMPONENT, JtxContract.JtxICalObject.Component.VJOURNAL.name)
            put(JtxContract.JtxICalObject.UID, "BBB")
            put(JtxContract.JtxICalObject.ICALOBJECT_COLLECTIONID, collections[0].id)
        }
        val childUri = client.insert(JtxContract.JtxICalObject.CONTENT_URI.asSyncAdapter(testAccount), childCV)

        val icalobjects = collections[0].queryICalObjects(null, null)
        assertEquals(2, icalobjects.size)

        // link one of them to the other with PARENT reltype
        val parent2childRelCV = ContentValues().apply {
            put(JtxContract.JtxRelatedto.ICALOBJECT_ID, parentUri?.lastPathSegment)
            put(JtxContract.JtxRelatedto.TEXT, "BBB")
            put(JtxContract.JtxRelatedto.RELTYPE, JtxContract.JtxRelatedto.Reltype.CHILD.name)
        }
        client.insert(JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(testAccount), parent2childRelCV)

        // update related to and check
        collections[0].updateRelatedTo()

        // check child to parent
        client.query(
            JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(testAccount),
            arrayOf(JtxContract.JtxRelatedto.ICALOBJECT_ID, JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, JtxContract.JtxRelatedto.TEXT, JtxContract.JtxRelatedto.RELTYPE),
            "${JtxContract.JtxRelatedto.ICALOBJECT_ID} = ?",
            arrayOf(parentUri?.lastPathSegment),
            null
        ).use {
            assertNotNull(it)
            assertEquals(1, it?.count)
            it?.moveToFirst()
            assertEquals(parentUri?.lastPathSegment?.toLong(), it?.getLong(0))   // ICALOBJECT_ID
            assertEquals(childUri?.lastPathSegment?.toLong(), it?.getLong(1))   // LINKEDICALOBJECT_ID
            assertEquals("BBB", it?.getString(2))   // TEXT (UID)
            assertEquals(JtxContract.JtxRelatedto.Reltype.CHILD.name, it?.getString(3))
        }

        // check parent to child
        client.query(
            JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(testAccount),
            arrayOf(JtxContract.JtxRelatedto.ICALOBJECT_ID, JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, JtxContract.JtxRelatedto.TEXT, JtxContract.JtxRelatedto.RELTYPE),
            "${JtxContract.JtxRelatedto.ICALOBJECT_ID} = ?",
            arrayOf(childUri?.lastPathSegment),
            null
        ).use {
            assertNotNull(it)
            assertEquals(1, it?.count)
            it?.moveToFirst()
            assertEquals(childUri?.lastPathSegment?.toLong(), it?.getLong(0))   // ICALOBJECT_ID
            assertEquals(parentUri?.lastPathSegment?.toLong(), it?.getLong(1))   // LINKEDICALOBJECT_ID
            assertEquals("AAA", it?.getString(2))   // TEXT (UID)
            assertEquals(JtxContract.JtxRelatedto.Reltype.PARENT.name, it?.getString(3))
        }
    }

    @Test
    fun getICSForCollection_test() {
        val collectionUri = JtxCollection.create(testAccount, client, cv)
@@ -115,7 +255,6 @@ class JtxCollectionTest {
        client.insert(JtxContract.JtxICalObject.CONTENT_URI.asSyncAdapter(testAccount), cv2)

        val ics = collections[0].getICSForCollection()

        assertTrue(ics.contains(Regex("BEGIN:VCALENDAR(\\n*|\\r*|\\t*|.*)*END:VCALENDAR")))
        assertTrue(ics.contains("PRODID:+//IDN bitfire.at//ical4android"))
        assertTrue(ics.contains("SUMMARY:summary"))
+18 −35
Original line number Diff line number Diff line
@@ -175,18 +175,8 @@ open class JtxCollection<out T: JtxICalObject>(val account: Account,
                        val idOfthisUid = idOfthisUidCursor.getLong(0)

                        val updateContentValues = ContentValues()
                        updateContentValues.put(
                            JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID,
                            idOfthisUid
                        )

                        client.update(
                            JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(
                                account
                            ),
                            updateContentValues,
                            "${JtxContract.JtxRelatedto.TEXT} = ? AND ${JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID} = ?",
                            arrayOf(uid2upddate, "0")
                        updateContentValues.put(JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, idOfthisUid)
                        client.update(JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(account), updateContentValues,"${JtxContract.JtxRelatedto.TEXT} = ? AND ${JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID} = ?", arrayOf(uid2upddate, "0")
                        )
                    }
                }
@@ -198,27 +188,24 @@ open class JtxCollection<out T: JtxICalObject>(val account: Account,
        client.query(JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(account), arrayOf(JtxContract.JtxRelatedto.ICALOBJECT_ID, JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, JtxContract.JtxRelatedto.RELTYPE), "${JtxContract.JtxRelatedto.RELTYPE} = ?", arrayOf(JtxContract.JtxRelatedto.Reltype.PARENT.name), null).use {
                cursorAllLinkedParents ->
            while (cursorAllLinkedParents?.moveToNext() == true) {
                val icalObjectId = cursorAllLinkedParents.getString(0)
                val linkedIcalObjectId = cursorAllLinkedParents.getString(1)
                val childId = cursorAllLinkedParents.getString(0)
                val parentId = cursorAllLinkedParents.getString(1)

                client.query(JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(account), arrayOf(JtxContract.JtxRelatedto.ICALOBJECT_ID, JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, JtxContract.JtxRelatedto.RELTYPE), "${JtxContract.JtxRelatedto.ICALOBJECT_ID} = ? AND ${JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID} = ? AND ${JtxContract.JtxRelatedto.RELTYPE} = ?", arrayOf(linkedIcalObjectId.toString(), icalObjectId.toString(), JtxContract.JtxRelatedto.Reltype.CHILD.name), null).use {  cursor ->
                client.query(JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(account), arrayOf(JtxContract.JtxRelatedto.ICALOBJECT_ID, JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, JtxContract.JtxRelatedto.RELTYPE), "${JtxContract.JtxRelatedto.ICALOBJECT_ID} = ? AND ${JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID} = ? AND ${JtxContract.JtxRelatedto.RELTYPE} = ?", arrayOf(parentId.toString(), childId.toString(), JtxContract.JtxRelatedto.Reltype.CHILD.name), null).use {  cursor ->
                    // if the query does not bring any result, then we insert the opposite relationship
                    if (cursor?.moveToFirst() == false) {

                        //get the UID of the linked entry
                        client.query(JtxContract.JtxICalObject.CONTENT_URI.asSyncAdapter(account), arrayOf(JtxContract.JtxICalObject.UID), "${JtxContract.JtxICalObject.ID} = ?", arrayOf(linkedIcalObjectId.toString()), null).use {
                        client.query(JtxContract.JtxICalObject.CONTENT_URI.asSyncAdapter(account), arrayOf(JtxContract.JtxICalObject.UID), "${JtxContract.JtxICalObject.ID} = ?", arrayOf(childId.toString()), null).use {
                                foundIcalObjectCursor ->

                            if (foundIcalObjectCursor?.moveToFirst() == true) {
                                val uid = foundIcalObjectCursor.getString(0)

                                val childUID = foundIcalObjectCursor.getString(0)
                                val cv = ContentValues().apply {
                                    put(JtxContract.JtxRelatedto.ICALOBJECT_ID, linkedIcalObjectId)
                                    put(JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, icalObjectId)
                                    put(JtxContract.JtxRelatedto.ICALOBJECT_ID, parentId)
                                    put(JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, childId)
                                    put(JtxContract.JtxRelatedto.RELTYPE, JtxContract.JtxRelatedto.Reltype.CHILD.name)
                                    put(JtxContract.JtxRelatedto.TEXT, uid)
                                    put(JtxContract.JtxRelatedto.TEXT, childUID)
                                }

                                client.insert(JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(account), cv)
                            }
                        }
@@ -233,30 +220,27 @@ open class JtxCollection<out T: JtxICalObject>(val account: Account,
                cursorAllLinkedParents ->
            while (cursorAllLinkedParents?.moveToNext() == true) {

                val icalObjectId = cursorAllLinkedParents.getLong(0)
                val linkedIcalObjectId = cursorAllLinkedParents.getLong(1)
                val parentId = cursorAllLinkedParents.getLong(0)
                val childId = cursorAllLinkedParents.getLong(1)

                client.query(JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(account), arrayOf(JtxContract.JtxRelatedto.ICALOBJECT_ID, JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, JtxContract.JtxRelatedto.RELTYPE), "${JtxContract.JtxRelatedto.ICALOBJECT_ID} = ? AND ${JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID} = ? AND ${JtxContract.JtxRelatedto.RELTYPE} = ?", arrayOf(linkedIcalObjectId.toString(), icalObjectId.toString(), JtxContract.JtxRelatedto.Reltype.PARENT.name), null).use {
                client.query(JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(account), arrayOf(JtxContract.JtxRelatedto.ICALOBJECT_ID, JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, JtxContract.JtxRelatedto.RELTYPE), "${JtxContract.JtxRelatedto.ICALOBJECT_ID} = ? AND ${JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID} = ? AND ${JtxContract.JtxRelatedto.RELTYPE} = ?", arrayOf(childId.toString(), parentId.toString(), JtxContract.JtxRelatedto.Reltype.PARENT.name), null).use {
                        cursor ->

                    // if the query does not bring any result, then we insert the opposite relationship
                    if (cursor?.moveToFirst() == false) {

                        //get the UID of the linked entry
                        client.query(JtxContract.JtxICalObject.CONTENT_URI.asSyncAdapter(account), arrayOf(JtxContract.JtxICalObject.UID), "${JtxContract.JtxICalObject.ID} = ?", arrayOf(linkedIcalObjectId.toString()), null).use {
                        client.query(JtxContract.JtxICalObject.CONTENT_URI.asSyncAdapter(account), arrayOf(JtxContract.JtxICalObject.UID), "${JtxContract.JtxICalObject.ID} = ?", arrayOf(parentId.toString()), null).use {
                                foundIcalObjectCursor ->

                            if(foundIcalObjectCursor?.moveToFirst() == true) {

                                val uid = foundIcalObjectCursor.getString(0)

                                val parentUID = foundIcalObjectCursor.getString(0)
                                val cv = ContentValues().apply {
                                    put(JtxContract.JtxRelatedto.ICALOBJECT_ID, linkedIcalObjectId)
                                    put(JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, icalObjectId)
                                    put(JtxContract.JtxRelatedto.ICALOBJECT_ID, childId)
                                    put(JtxContract.JtxRelatedto.LINKEDICALOBJECT_ID, parentId)
                                    put(JtxContract.JtxRelatedto.RELTYPE, JtxContract.JtxRelatedto.Reltype.PARENT.name)
                                    put(JtxContract.JtxRelatedto.TEXT, uid)
                                    put(JtxContract.JtxRelatedto.TEXT, parentUID)
                                }

                                client.insert(JtxContract.JtxRelatedto.CONTENT_URI.asSyncAdapter(account), cv)
                            }
                        }
@@ -266,7 +250,6 @@ open class JtxCollection<out T: JtxICalObject>(val account: Account,
        }
    }


    /**
     * @return a string with all JtxICalObjects within the collection as iCalendar
     */
+0 −1
Original line number Diff line number Diff line
@@ -1209,7 +1209,6 @@ duration?.let(props::add)
            )
        }


        this.relatedTo.forEach { related ->
            val relatedToContentValues = ContentValues().apply {
                put(JtxContract.JtxRelatedto.ICALOBJECT_ID, id)