Correct way to put deleted document in channels

82 views
Skip to first unread message

Jonas Schmid

unread,
Jul 16, 2015, 5:19:40 AM7/16/15
to mobile-c...@googlegroups.com
I am building a very simple chat to experiment with Couchbase Lite. (You can see it here: https://github.com/jschmid/couchbase-chat)

I have problems with the sync function with deleted documents. When I delete a document, the other users do not see it as deleted. They do not receive the update.

First I had a very simple function that puts chatrooms and messages in channels: https://gist.github.com/jschmid/f0a4e125b9db1fd6f750/b1b553264420b088f37d1b2bae73bf29cc62d178
Then I wanted to prevent other users to delete messages that don't belong to them so I added a check: https://gist.github.com/jschmid/f0a4e125b9db1fd6f750/7f2f5d377937bf83cfa8b8c4735516e76b0afe1a
I realised that the deleted document did not belong to the channel anymore so I added the channel back: https://gist.github.com/jschmid/f0a4e125b9db1fd6f750/033f0be9e4f55f28c67c0ac5daee4701878db630
(You can take a look at the differences: https://gist.github.com/jschmid/f0a4e125b9db1fd6f750/revisions)

Now I am out of ideas and I still do not get notified when a document is deleted somewhere else. Note that I do receive the other updates. Can you please help me with that?

Thanks
Jonas

ajres

unread,
Jul 16, 2015, 5:46:20 AM7/16/15
to mobile-c...@googlegroups.com
Can you provide some sample channel and message documents, it will make it easier to debug this issue.

Andy

Jonas Schmid

unread,
Jul 16, 2015, 5:50:19 AM7/16/15
to mobile-c...@googlegroups.com
Sure!


You can see that the channel names are create with the "chatroom" document IDs.

Jonas Schmid

unread,
Jul 16, 2015, 5:57:14 AM7/16/15
to mobile-c...@googlegroups.com
I noticed something weird (for me)

When I delete messages it works as expected. The deletion is seen by the others. It's only when I try to deleted chatrooms that the other users do not see the deletion.

I guess it's caused by a misconfiguration in the way authorisation is done...

Jonas

Jonas Schmid

unread,
Jul 16, 2015, 6:10:27 AM7/16/15
to mobile-c...@googlegroups.com
It looks like when the document that initially gave access to a channel is deleted, the channel is somehow "removed".

When I look at the gateway web admin, I see that the users who had access to this channel do not have access anymore. Even though I try to maintain it in my "if(deleted)" code.

Can someone from Couchbase confirm that when a document giving access to a channel is removed, this channel is also removed?

ajres

unread,
Jul 16, 2015, 8:24:57 AM7/16/15
to mobile-c...@googlegroups.com
I reproduced your issue for the chatroom document type.

When a document is deleted (contains the _deleted property) any access or role assignments applied in the sync function for that revision are ignored.


This results in all chatroom members loosing access to the chatroom channel and they do not see the deleted revision in their changes feed.

Andy

Jonas Schmid

unread,
Jul 16, 2015, 9:08:46 AM7/16/15
to mobile-c...@googlegroups.com
Thank you Andy,

I now understand. Since the document is deleted, the access rights it has given are revoked and the users do not have access to the channel.

How would you update my structure so that users are notified that the chatroom has been removed? 

I could try using roles, but it would first require me to create a role each time a chatroom is created. Also the access to the role would be given by the document, so when the document is deleted the access to the role is revoked and it does not solve my problem.

Thanks
Jonas

Jens Alfke

unread,
Jul 16, 2015, 12:10:14 PM7/16/15
to mobile-c...@googlegroups.com

On Jul 16, 2015, at 2:19 AM, Jonas Schmid <jonas....@gmail.com> wrote:

I have problems with the sync function with deleted documents. When I delete a document, the other users do not see it as deleted. They do not receive the update.

Usually when this happens it means that your sync function is rejecting deletion (‘tombstone’) revisions.

Deletions are sort of a special case, because a typical deletion revision just looks like {“id”:”xxx”, “_deleted”:true}, with no other properties. A common mistake is to have your sync function require other properties — like “type” or “owner” or whatever — and throw an exception if they’re not present. This will unintentionally reject deletions.

In general the sync function will need to check for (doc._deleted === true) and if so skip any checks for required properties. You do also probably want to look at the oldDoc to validate that it’s legal for the user to delete this document.

—Jens

Jens Alfke

unread,
Jul 16, 2015, 12:12:54 PM7/16/15
to mobile-c...@googlegroups.com

On Jul 16, 2015, at 6:08 AM, Jonas Schmid <jonas....@gmail.com> wrote:

I now understand. Since the document is deleted, the access rights it has given are revoked and the users do not have access to the channel.
How would you update my structure so that users are notified that the chatroom has been removed? 

If the clients had access to the chatroom document before (which they probably would), they’ll see it get updated; either as a deletion or as an empty revision with “_removed”:true as the only property.

—Jens

Jonas Schmid

unread,
Jul 17, 2015, 2:35:43 AM7/17/15
to mobile-c...@googlegroups.com
Thanks Jens for the replies.

As I said in my first post, I do treat the deleted documents as a special case: https://gist.github.com/jschmid/f0a4e125b9db1fd6f750
I triple-checked and I only use the "oldDoc" argument in the "if" so it should be good.

My problem now is that the clients DO NOT see the document getting updated. 
I put a breakpoint in the method called when kCBLReplicationChangeNotification is posted. 
I put a breakpoint in the view "map block", which must be called if the document is updated with "_removed" (I guess).
I get nothing, no notification, nothing. It really is like the sync gateway does not propagate the deletion. 

From my last post in this thread, I get a feeling that the replication is not effective anymore because the users do not have access to the channel anymore once the chatroom has been deleted. 

Let me share an example, with screenshots taken from the SG web admin: I have two users, two chatrooms, each chatroom has two messages. Both users have access to both channels (one channel per chatroom)

We see that each channel has one yellow document, the "chatroom" document, and two regular "messages" documents.


The user1 has access to both channels. user4 also has access to them.


Now I will delete a chatroom from my mobile UI. This effectively deletes the "chatroom" document.


We see now that there are still two channels (we kept the "messages" documents from the deleted chatroom), but one chatroom document is gone, as expected.


But now is the problem. It appears that the user1 does not have access to the channel! 

Since he does not have access to the channel, he will not receive the "deleted" revision, right? 

I guess he must receive the "_removed" document, but that's not the case.


Do I understand something wrong?


Many thanks,

Jonas

Todd Freese

unread,
Jul 17, 2015, 10:56:36 AM7/17/15
to mobile-c...@googlegroups.com
The SG has a web admin? How did I miss this... Are there any docs on this?

Todd

ajres

unread,
Jul 17, 2015, 11:35:06 AM7/17/15
to mobile-c...@googlegroups.com
You might try adding a 'rooms' channel to each user e.g 'user1_rooms'

```

"user1": {

          "password": "user1",

          "admin_channels": ["users","user1-rooms"]

        },

```


Tag chatroom documents with each members rooms channel.

The users will then see the _deleted chatroom revisions in the _changes feed.

Andy

Jonas Schmid

unread,
Jul 17, 2015, 11:44:17 AM7/17/15
to mobile-c...@googlegroups.com
Could not find any doc about it. I found the url in a Couchbase video.


Enjoy

Jonas Schmid

unread,
Jul 17, 2015, 12:03:50 PM7/17/15
to mobile-c...@googlegroups.com
Thanks Andy.

I liked the idea, but the problem stay the same. I still do not see the deletion :/

Jonas

ajres

unread,
Jul 17, 2015, 1:00:36 PM7/17/15
to mobile-c...@googlegroups.com
I'm using this modified version of your sg.json config, this adds a 'user<N>-rooms' channel to each users admin_channels property, the chatroom doc is added to each chatroom members -rooms channel.

{

  "log": ["foo"],

  "databases": {

    "couchbase-chat": {

      "server": "http://localhost:8091/",

      "bucket":"bucket-1",

      "users": {

        "user1": {

          "password": "user1",

          "admin_channels": ["users","user1-rooms"]

        },

        "user2": {

          "password": "user2",

          "admin_channels": ["users","user2-rooms"]

        },

        "user3": {

          "password": "user3",

          "admin_channels": ["users", "user3-rooms"]

        },

        "user4": {

          "password": "user4",

          "admin_channels": ["users","user4-rooms"]

        },

        "admin": {

          "password": "admin",

          "admin_roles": ["admin"]

        }

      },

      "roles": {

        "admin": {

          "admin_channels": ["*"]

        }

      },

      "sync":

      `

function(doc, oldDoc) {

   

  if(doc._deleted) {

    if(oldDoc.type == "chatroom") {

      requireUser(oldDoc.user);

    } else if (oldDoc.type == "message") {

      requireUser(oldDoc.user);

      var roomId = oldDoc.room;

      var messageChannel = "room-" + roomId;

      channel(messageChannel);

    }

    return;

  }

   

  if(doc.type == "chatroom") {

    var roomId = doc._id;

    var roomMembers = doc.members;


 

    for (var i = 0; i < roomMembers.length; i++) {

      var member = roomMembers[i];

      channel(member + "-rooms");

    }


 

    var roomChannel = "room-" + roomId;

    channel(roomChannel);

    access(roomMembers, roomChannel);

  } else if(doc.type == "message") {

    // A user can only update its own messages

    if(oldDoc) {

      requireUser(oldDoc.user);

    }

 

    var roomId = doc.room;

    var messageChannel = "room-" + roomId;

    channel(messageChannel);

  }

}

      `

    }

  }

}


if I start a continuous changes feed:

curl -X GET http://user1:user1@localhost:4984/couchbase-chat/_changes?feed=continuous


Then add a chatroom:


curl -X PUT http://user1:user1@localhost:4984/couchbase-chat/testchannel1 -d '{"members": ["user2","user1","user4"],"name": "still","type": "chatroom","user": "user1"}' -H "Content-Type: application/json"


response:


{"id":"testchannel1","ok":true,"rev":"1-9bda027ae976eaec039a180fd16f3a8d"}


Then delete the chat room:


curl -X PUT http://user1:user1@localhost:4984/couchbase-chat/testchannel1 -d '{"_rev":"1-9bda027ae976eaec039a180fd16f3a8d","_deleted":true}' -H "Content-Type: application/json"


response:


{"id":"testchannel1","ok":true,"rev":"2-e5851b5cb894cb7ff2badf951e21b3f5"}


I see both revisions now on the _changes feed:



{"seq":2,"id":"_user/user1","changes":[]}


{"seq":7,"id":"testchannel1","changes":[{"rev":"1-9bda027ae976eaec039a180fd16f3a8d"}]}


{"seq":8,"id":"testchannel1","deleted":true,"removed":["user1-rooms"],"changes":[{"rev":"2-e5851b5cb894cb7ff2badf951e21b3f5"}]}




Jonas Schmid

unread,
Jul 20, 2015, 3:58:33 AM7/20/15
to mobile-c...@googlegroups.com
Thank you Andy,

You solution works well as you showed.

I tried to be clever by creating the "userX-rooms" channels on the fly inside the sync function, but it does not work that way. If you create the channels in the config it works as expected. 

There is a lot to understand when coming from a regular SQL background, but I really feel it's worth the time.

Thanks!
Jonas
Reply all
Reply to author
Forward
0 new messages