Plugin - Interactive form, button and endpoint

edit:

I modified id of the plugin in code on both function… by the plugin name. The button try to send the message to an url with an id, not the name of the plugin.


Hi,

I made a plugin, i would to add an interactive mode to simplify usage instead of using slash commands. I use a docker image.

I try to understand but it’s not easy with matterpoll source, i would to have more comment in code to understand, and i add it’s a big plugin. Not the simpliest.

If i well understand, i must post a form with buttons, in this button i will set an address… this address must be an endpoint ? right?

If i read documentation about v4 this endpoint must be set in a yaml, there is no other way ? I don’t use make at all but a custom bash to compile and package. It’s because i compile most of time for c# under visual studio, i’m not habit with linux compiling.

I tried to remove almost everything ot understand the role of each part

On activate part, i start a func with something like:

    r := mux.NewRouter()
    r.HandleFunc("/api/v4/posts/{plugin code}/actions/meuporg", p.MeuporgHandler)    
   return r

On my command i create a post with (i have a problem with the root.manifest) and in URL i tried two things, a local IP + a context (commented) and a path like in matterpoll:

unc (p *FlowWatcherPlugin) SendTest(channelID string)*model.AppError{
	p.API.LogDebug("SendTest")

	post := &model.Post{
		UserId:    p.botUserID,
		ChannelId: channelID,
		Message:   "This is just a test.",			
	}

	actions := []*model.PostAction{}

	fooAction:=&model.PostAction{
			Id:    fmt.Sprintf("meuporg"),
			Name:  "answer",
			Type:  model.PostActionTypeButton,
			Style: "default",
			Integration: &model.PostActionIntegration{

				URL: "/api/v4/posts/fio9dg5xsf83fb4xwz47xr75ch/actions/meuporg",
/*
                                URL: "http://127.0.0.1:{port}",
				Context: map[string]any{
					"action": "do_something_ephemeral",
					},			*/
				},
			}


	actions = append(actions, fooAction	)


	slackAttach :=	[]*model.SlackAttachment{{
		//AuthorName: "authorName",
		Title:      "p.Question",
		Text : "Actions realisables",

		Actions:    actions,
	}}


	model.ParseSlackAttachment(post, slackAttach)

	if _, err := p.API.CreatePost(post); err != nil {
		p.API.LogDebug(
			"We could not create the form post",
			"user_id", post.UserId,
			"err", err.Error(),
		)
	}

	return nil
}

In theory it’s just a message with one button, and only one action possible.

I got an error in logs:

..."msg":"Action integration error.","caller":"web/context.go:113","path":"/api/v4/posts/fio9dg5xsf83fb4xwz47xr75ch/actions/meuporg","request_id":"9nihrx7edf8p8mqternyf834be","ip_addr":"172.23.0.1","user_id":"ujtnkspj9i8bdqiwc9hwpufhfo","method":"POST","err_where":"DoActionRequest","http_code":400,"error":"DoActionRequest: Action integration error., status=405"}

I ask myself also by writing this, if plugin id doesn’t change each time i overwrite it by uploading with the IHM.

If there is a way to not using endpoint, i prefer.

Best regards.

Hi @Daerlnaxe! Welcome to the Mattermost community forums!

It sounds like you’re making great progress on your plugin. For adding interactive buttons, you’re on the right track with the endpoint. You can define custom endpoints in the plugin’s manifest.json file, and more details on handling interactive message buttons can be found in the Mattermost plugin documentation. Keep going, and feel free to reach out if you have more questions!

1 Like

Hi thanks you for the answer.

For the while i can’t test, but i will try later. I don’t have a manifest.json, but a plugin.json… i saw in documentation there were 4 points perhaps a mistranslation on my side but i thought it was mandatory to cover the four, this is why i would to try by code only. I will take a look.

What i saw:

  • You can have an endpoint with /plugins/pluginname/ by handle it in server part
  • If i use gorilla mux on the same structure , it says this endpoint is not define…
  • If i try on /api/v4/{idk if it’s a uuid|hash|or pluginname} it fails.

For the first point, i took an old advice from someone on this forum, i can handle here:

func (p *FlowWatcherPlugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) {
//---
}

If i can’t make an endpoint with gorilla i will use this way to begin.


Edit:

Reading again the doc, i understand more. I was sure ServeHTTP must be mixed with endpoint with Gorilla Mux, or perhaps it’s normal but not as i thought it must be.

I tried to use interactive message and with the example, the button (log) try to reach /api/v4/pluginID/… Perhaps my problem is here.

I will take a look about MessageHasBeenPosted

" is invoked after the message has been committed to the database. If you need to modify or reject the post, see MessageWillBePosted Note that this method will be called for posts created by plugins, including the plugin that created the post."

It could be interesting… i don’t need rest api.


edit2

Ok with a dialog i can reach /plugins/{plugin name}/suffix.
I’m not sure how to deal with it now :smiley:


edit 3:

it’s ok i have the payload, i use a check on r.URL.Path => handleMethod, i received a json i decoded just to see the content, for the while with :

	buf := new(bytes.Buffer)
	buf.ReadFrom(r.Body)
	respBytes := buf.String()

	respString := string(respBytes)


	p.API.LogDebug(respString)

Hi @Daerlnaxe! It sounds like you’re making excellent progress and gaining a deeper understanding of how everything connects. Great job on getting the payload successfully! For handling the path and decoding the JSON payload, your approach with r.URL.Path and handleMethod looks solid.

If you want to refine the process further, you could also use json.NewDecoder(r.Body).Decode(&yourStruct) to directly map the JSON into a struct, which can make it easier to work with specific fields. As for the /plugins/{plugin_name}/suffix path, you’re right on track there. Keep experimenting, and let me know if you need more help with the next steps!