Hi, I have been successfully using a combination of Couchbase Server with Couchbase Lite/Sync Gateway for Android for about a year now, with a simple sync function JSON that did not utilize any authentication or channels. I am now at the point where it is important to take advantage of that functionality, and I modified your sample code in order to do this (wonderful tutorial, thank you). I am having no problem pushing data to my server, and according to the HTML interface on localhost:4985, my documents are being routed to the proper channels with the proper accesses granted. However, when I push data from device A, and then attempt to pull data on device B I get nothing in return. My hope is that I am simply making a fundamental error in my Sync Function, so I have provided that as my starting point. If you could take a cursory look and let me know if I am making a stupid mistake I would appreciate it greatly. Otherwise, it’s back to the debugging board. Thanks a lot for your help:
{
"log": ["*"],
"databases":{
"test_syncgateway":{
"server":"http://10.0.0.84:8091",
"bucket":"test_syncgateway",
"users": {
"matt": {"password": "test", "admin_channels": ["matt"]},
"bryan": {"password": "test", "admin_channels": ["bryan"]},
"mod": {"password": "test", "admin_roles": ["moderator"]},
"admin": {"password": "test", "admin_roles": ["admin"]}
},
"roles": {
"moderator": {},
"admin": {}
},
"sync":
`
function(doc, oldDoc) {
/*Validation that document has a type*/
if (isCreate()) {
// Don't allow creating a document without a type.
validateNotEmpty("documentType", doc.documentType);
} else if (isUpdate()) {
// Don't allow changing the type of any document.
validateReadOnly("documentType", doc.documentType, oldDoc.documentType);
}
if (getType() == "numbers") {
/* Write access */
var username = doc._deleted ? oldDoc.username : doc.username
try {
// Moderators can create or update lists for other users.
requireRole("moderator");
} catch (e) {
// Users can create or update lists for themselves.
requireUser(username);
}
/* Validation */
if (!isDelete()) {
// Validate required fields.
validateNotEmpty("username", doc.username);
validateNotEmpty("data", doc.data);
if (isCreate()) {
// Validate that the _id is prefixed by owner.
if (!hasPrefix(doc._id, doc.username + ".")) {
throw({forbidden: "task-list id must be prefixed by list username"});
}
} else {
// Don’t allow task-list ownership to be changed.
validateReadOnly("username", doc.username, oldDoc.username);
}
}
/* Routing */
// Add doc to task-list's channel.
channel("numbers." + doc._id);
channel("moderators");
/* Read Access */
// Grant task-list owner access
access(username, "numbers." + doc._id);
access("role:moderator", "numbers." + doc._id);
} else {
// Log invalid document type error.
log("Invalid document type: " + doc.documentType);
throw({forbidden: "Invalid document type: " + doc.documentType});
}
function getType() {
return (isDelete() ? oldDoc.documentType : doc.documentType);
}
function isCreate() {
// Checking false for the Admin UI to work
return ((oldDoc == false) || (oldDoc == null || oldDoc._deleted) && !isDelete());
}
function isUpdate() {
return (!isCreate() && !isDelete());
}
function isDelete() {
return (doc._deleted == true);
}
function validateNotEmpty(key, value) {
if (!value) {
throw({forbidden: key + " is not provided."});
}
}
function validateReadOnly(name, value, oldValue) {
if (value != oldValue) {
throw({forbidden: name + " is read-only."});
}
}
// Checks whether the provided value starts with the specified prefix
function hasPrefix(value, prefix) {
if (value && prefix) {
return value.substring(0, prefix.length) == prefix
} else {
return false
}
}
}
`
}
}
}