Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SendBird create GroupChannel with file as cover

I'm trying to create a group Channel with a cover photo,

this.sendBirdInstance.GroupChannel.createChannelWithUserIds(userIds, true, this.groupName, this.groupPhotoFile, '', function (createdChannel, error) {
...
}

According to the documentation I can add a url or a file

coverUrl : the file or URL of the cover image, which you can fetch to render into the UI.

But when adding a file, I'm always getting : "SendBirdException", code: 800110, message: "Invalid arguments."

Is there a way to create a group with a file instead of a url (since I want the user to upload the file) ?

Thanks,

like image 959
Dany Y Avatar asked Sep 04 '17 12:09

Dany Y


1 Answers

As you have already experienced (I saw that you have created an issue in GitHub several days ago) the support of SendBird is kinda unreliable.

The fact that they offer just a minified version of their JavaScript SDK (which personally I find very poor) is helping either.

Anyway, I could isolate the createChannelWithUserIds function:

! function (e, n) {
    // ... 
}(this, function () {
    // ... 
    var h = function (e) {
        for (var n in e) if (e.hasOwnProperty(n)) return !1;
        return Array.isArray(e) ? JSON.stringify(e) === JSON.stringify([]) : JSON.stringify(e) === JSON.stringify({})
    },
    // ... 
    A = function () { // it returns SendBird function
        // ... 
        var w = function (e) { // w is this.GroupChannel
            // ... 
            w.createChannelWithUserIds = function () {
                // ...
                // here comes the param validation (I've added spaces for a better lecture):
                if (!Array.isArray(e) || "boolean" != typeof n || "string" != typeof t && null !== t && void 0 !== t || "string" != typeof r && h(r) && null !== r && void 0 !== r || "string" != typeof a && null !== a && void 0 !== a || "string" != typeof i && null !== i && void 0 !== i) return void U(null, new p("Invalid arguments.", J.INVALID_PARAMETER), s);
                // It will return "Invalid arguments." if any of the conditions evaluates to true       
                // ... 
            }
        }
    }
    return function () {
        // ... 
    }().SendBird
});

You are using the function like this:

createChannelWithUserIds(o, n, t, r, a, s); 

So the fourth parameter (r) is coverURL: the file with the cover picture (this.groupPhotoFile);

Its validation is basically saying that:

"string" != typeof r    // if `r` is not a string (a URL)
&& h(r)                 // and the returned value of function h(r) is true
&& null !== r           // and it is not null
&& void 0 !== r         // and it is not undefined

that parameter is invalid.

Your file is not a string, not null and not undefined, so everything boils down to the h() function:

var h = function (e) {
    for (var n in e) if (e.hasOwnProperty(n)) return !1;
    return Array.isArray(e) ? JSON.stringify(e) === JSON.stringify([]) : JSON.stringify(e) === JSON.stringify({})
}

The function above check in first place if the object has any property what is a member of the object itself (i.e. not properties belonging to the prototype chain). Then, if it doesn't have any own property, it checks if the stringify object/array is equal to an empty object/array.

I can't say what is the intention of the developers when validating files though this function, but a standard FILE object:

  • has properties in its prototype chain, but not directly assigned to the instance, so the first condition is true.
  • when stringify returns a empty object in all major browsers nowadays (it was not always like so), so the second condition is also true.

As we saw before, we need h() to return false: the validation fails if it returns true.

To fix this behavior you could change the h() function to something like:

var h = function( e ){
    return !(e instanceof File);
    // or return e.constructor != File;
    // or return Object.getPrototypeOf( e ) != File.prototype );
    // or return e.__proto__ != File.prototype )
    // or return e.constructor.prototype != File.prototype )
}

but I won't mess with it. It could be used in future versions with a different purpose.

So your best bet is to change the createChannelWithUserIds() function to:

  • remove the call to the h() function from the validation.
  • replace it with a call to your own file validation

To do that, you could override the function in a SendBird instance:

var sb = new SendBird( { appId: ... } );

sb.GroupChannel.createChannelWithUserIds = function(){ ... };

But it is not guarantee to work and could break in future releases, so I would just edit the SendBird.min.js file. In other words, replace:

if(!Array.isArray(e)||"boolean"!=typeof n||"string"!=typeof t&&null!==t&&void 0!==t||"string"!=typeof r&&h(r)&&null!==r&&void 0!==r||"string"!=typeof a&&null!==a&&void 0!==a||"string"!=typeof i&&null!==i&&void 0!==i)return void U(null,new p("Invalid arguments.",J.INVALID_PARAMETER),s);

with:

if(!Array.isArray(e)||"boolean"!=typeof n||"string"!=typeof t&&null!==t&&void 0!==t||"string"!=typeof a&&null!==a&&void 0!==a||"string"!=typeof i&&null!==i&&void 0!==i)return void U(null,new p("Invalid arguments.",J.INVALID_PARAMETER),s);

In the current version (v3.0.41) you will find two coincidences of the code above: one for createChannel and other for createChannelWithUserIds, you can replace both.

Of course, editing the .js file is annoying because you will need to take care to replace the code everytime you upgrade SendGrid. You could create an automatic task inside your CI pipeline to do it for you, thought.

Hopefully, the SendGrid developers will acknowledge your issue and fix it in a future release.

like image 156
David Avatar answered Oct 17 '22 22:10

David