allow plugins to alter request/response

This commit is contained in:
Felix Ableitner 2024-05-04 01:01:18 +02:00
parent 9f2366474a
commit bc7331b613
3 changed files with 41 additions and 21 deletions

View file

@ -764,13 +764,14 @@ test("Fetch post with redirect", async () => {
expect(gammaPost2.post).toBeDefined();
});
test("Create a post", async () => {
test.only("Plugin test", async () => {
let community = await createCommunity(epsilon);
let postRes = createPost(
epsilon,
community.community_view.community.id,
"https://example.com/",
"plugin should block this",
"body",
"foobar",
);
await expect(postRes).rejects.toStrictEqual(Error("plugin_error"));
expect((await postRes).post_view.post.name).toBe("Hello plugin!");
});

View file

@ -55,10 +55,12 @@ use webmention::{Webmention, WebmentionError};
#[tracing::instrument(skip(context))]
pub async fn create_post(
data: Json<CreatePost>,
mut data: Json<CreatePost>,
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<PostResponse>> {
plugin_hook("api_before_create_post", &mut (*data))?;
let local_site = LocalSite::read(&mut context.pool()).await?;
honeypot_check(&data.honeypot)?;
@ -126,8 +128,6 @@ pub async fn create_post(
}
};
plugin_hook("api_before_create_post", data.clone())?;
let post_form = PostInsertForm::builder()
.name(data.name.trim().to_string())
.url(url)
@ -161,8 +161,6 @@ pub async fn create_post(
.await
.with_lemmy_type(LemmyErrorType::CouldntCreatePost)?;
plugin_hook("api_after_create_post", updated_post.clone())?;
generate_post_link_metadata(
updated_post.clone(),
custom_thumbnail,
@ -207,11 +205,17 @@ pub async fn create_post(
}
};
build_post_response(&context, community_id, &local_user_view.person, post_id).await
let mut res = build_post_response(&context, community_id, &local_user_view.person, post_id)
.await?
.0;
plugin_hook("api_after_create_post", &mut res)?;
Ok(Json(res))
}
fn load_plugins() -> LemmyResult<Plugin> {
// TODO: make dir configurable via env var
// TODO: should only read fs once at startup for performance
let plugin_paths = read_dir("example_plugin")?;
let mut wasm_files = vec![];
@ -226,13 +230,20 @@ fn load_plugins() -> LemmyResult<Plugin> {
Ok(plugin)
}
fn plugin_hook<T: Serialize>(name: &'static str, data: T) -> LemmyResult<()> {
fn plugin_hook<T: Serialize + for<'de> serde::Deserialize<'de> + Clone>(
name: &'static str,
data: &mut T,
) -> LemmyResult<()> {
let mut plugin = load_plugins()?;
if plugin.function_exists(name) {
let res = plugin
.call::<extism_convert::Json<T>, &str>(name, data.into())
.map_err(|e| LemmyErrorType::PluginError(e.to_string()));
println!("{}", res?);
*data = plugin
.call::<extism_convert::Json<T>, extism_convert::Json<T>>(name, (*data).clone().into())
.map_err(|e| {
dbg!(&e);
LemmyErrorType::PluginError(e.to_string())
})?
.0
.into();
}
Ok(())
}

View file

@ -2,13 +2,18 @@ package main
import (
"github.com/extism/go-pdk"
"errors"
)
type CreatePost struct {
Name string `json:"name"`
Body string `json:"body"`
// skipping other fields for now
Body *string `json:"body,omitempty"`
Community_id int32 `json:"community_id"`
Url *string `json:"url,omitempty"`
Alt_text *string `json:"alt_text,omitempty"`
Honeypot *string `json:"honeypot,omitempty"`
Nsfw *bool `json:"nsfw,omitempty"`
Language_id *int32 `json:"language_id,omitempty"`
Custom_thumbnail *string `json:"custom_thumbnail,omitempty"`
}
//export api_before_create_post
@ -20,12 +25,15 @@ func api_before_create_post() int32 {
pdk.SetError(err)
return 1
}
if params.Body == "plugin should block this" {
pdk.SetError(errors.New("blocked by plugin"))
if params.Name == "foobar" {
params.Name = "Hello plugin!"
}
// use json output helper, which automatically marshals your struct to the plugin output
err = pdk.OutputJSON(params)
if err != nil {
pdk.SetError(err)
return 1
}
greeting := `Created post "` + params.Name + `"!`
pdk.OutputString(greeting)
return 0
}