// Converts a JS string or array into a Go string array. func ottoValueToStringArray(value otto.Value) []string { nativeValue, _ := value.Export() result := base.ValueToStringArray(nativeValue) if result == nil && !value.IsNull() && !value.IsUndefined() { base.Warn("SyncRunner: Non-string, non-array passed to JS callback: %s", value) } return result }
// Calls the JS sync function to assign the doc to channels, grant users // access to channels, and reject invalid documents. func (db *Database) getChannelsAndAccess(doc *document, body Body, revID string) (result base.Set, access channels.AccessMap, roles channels.AccessMap, oldJson string, err error) { base.LogTo("CRUD+", "Invoking sync on doc %q rev %s", doc.ID, body["_rev"]) // Get the parent revision, to pass to the sync function: var oldJsonBytes []byte if oldJsonBytes, err = db.getAncestorJSON(doc, revID); err != nil { return } oldJson = string(oldJsonBytes) if db.ChannelMapper != nil { // Call the ChannelMapper: var output *channels.ChannelMapperOutput output, err = db.ChannelMapper.MapToChannelsAndAccess(body, oldJson, makeUserCtx(db.user)) if err == nil { result = output.Channels access = output.Access roles = output.Roles err = output.Rejection if err != nil { base.Logf("Sync fn rejected: new=%+v old=%s --> %s", body, oldJson, err) } else if !validateAccessMap(access) || !validateRoleAccessMap(roles) { err = base.HTTPErrorf(500, "Error in JS sync function") } } else { base.Warn("Sync fn exception: %+v; doc = %s", err, body) err = base.HTTPErrorf(500, "Exception in JS sync function") } } else { // No ChannelMapper so by default use the "channels" property: value := body["channels"] if value != nil { array := base.ValueToStringArray(value) result, err = channels.SetFromArray(array, channels.KeepStar) } } return }