h3poteto/megalodon-rs

Passing media ids to post_status doesn't attach media

esttorhe opened this issue · 6 comments

First of all thanks for the crate; it is working nicely so far.
The issue I'm currently seeing is as follows.

I upload some media like this:

let res = client
        .upload_media(
            "image.jpg".to_string(),
            Some(&UploadMediaInputOptions {
                description: Some("Testing uploading media from Rust".to_string()),
                focus: Some("0, 0".to_string()),
            }),
        )
        .await;
    match res {
        Ok(r) => { 
   // Here I verify that the upload succeeded. I get back a URL that upon inspecting it works and loads the image, and 
  // here I also extract the id 

Then after extracting the id from the upload media I proceed to pass it to a post_status call. Like this:

               let res = client
                    .post_status(
                        "First post from Rust".to_string(),
                        Some(&PostStatusInputOptions {
                            media_ids: Some(vec!["109376236118464732".to_string()]),
                            poll: None,
                            in_reply_to_id: None,
                            sensitive: Some(false),
                            spoiler_text: None,
                            visibility: Some(StatusVisibility::Private),
                            scheduled_at: None,
                            language: Some("en".to_string()),
                            quote_id: None,
                        }),
                    )
                    .await;
                match res {
                    Ok(r) => {
                        println!("{:#?}", r.json);
                    }
                    Err(error) => {
                        eprintln!("Unable to post to Mastodon. ERR: {error:#?}");
                    }
                }

The id passed to the media_ids field is just an example. I'm actually passing the Id extracted from uploading a file first.
The response that I get is a 200; nevertheless when I check Mastodon my post is there but without attachment. And inspecting the result that comes back from the server after posting, it is indeed not returning any attachment with the post.

Considering that I can inspect the resulting URL after upload, I'm guessing that the library is not passing the vector of ids properly into the API call

Thanks

Hmm, this line

params.insert("media_ids", serde_json::to_string(&media_ids).unwrap());

@h3poteto yeah, I cloned the repo locally and was playing with it.
I was able to make it work by changing that line to this:

 params.insert("media_ids[]", "some_id".to_string());

As a test and it worked. Have not been able to make it work with multiple ids.

I need to keep testing, but passing the vector and letting that line run doesn't seem to be working.

If I inspect the params up until that point I get something like this

params = {
    "status": "This is a test",
    "language": "en",
    "sensitive": "true",
    "media_ids": "[\"109388145747341951\",\"109388145815401743\"]",
    "visibility": "unlisted",
}

My guess (and this is what I need to test) is that the serializer parses that as a String value rather than an array.


Out of curiosity, have you successfully attached media to a status post using the library?
I just want to rule out that I'm not doing something wrong here

No, I haven't, I only confirmed uploading media like this example: https://github.com/h3poteto/megalodon-rs/blob/master/examples/mastodon_media.rs


And there are other lines where I'm passing arrays as parameters. So if this bug is resolved, we need to fix these.

Ah, you're right.
I tried the marker endpoint which is using array parameter. The URL was

/api/v1/markers?timeline=["home","notifications"]

This is the cause.

I was able to make it work, but I had to make quite a few changes.

First I changed the API to receive HashMaps with Value instead of String

pub async fn post<T>(
        &self,
        path: &str,
-        params: &HashMap<&str, String>,
+        params: &HashMap<&str, Value>,
        headers: Option<HeaderMap>,
    )

After trying that I got an error from reqwest:

reqwest::Error {
        kind: Builder,
        source: Custom(
            "unsupported value",
        ),
    },

The issue being that request doesn't support Array as part of a form based body.

I had to change the post implementation on APIClient to use json instead:

-let res = req.form(params).send().await?;
+let res = req.json(params).send().await?;

I'll clean up the code the will issue a PR if you think this is a good change.
It propagates changes all over the place because the API now takes Value instead of String, unfortunately; but couldn't figure out any other way to make it work.

Ah, OK. I think it is no problem.
I will check other post APIs after you change it to json.