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(); expect(gammaPost2.post).toBeDefined();
}); });
test("Create a post", async () => { test.only("Plugin test", async () => {
let community = await createCommunity(epsilon); let community = await createCommunity(epsilon);
let postRes = createPost( let postRes = createPost(
epsilon, epsilon,
community.community_view.community.id, community.community_view.community.id,
"https://example.com/", "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))] #[tracing::instrument(skip(context))]
pub async fn create_post( pub async fn create_post(
data: Json<CreatePost>, mut data: Json<CreatePost>,
context: Data<LemmyContext>, context: Data<LemmyContext>,
local_user_view: LocalUserView, local_user_view: LocalUserView,
) -> LemmyResult<Json<PostResponse>> { ) -> LemmyResult<Json<PostResponse>> {
plugin_hook("api_before_create_post", &mut (*data))?;
let local_site = LocalSite::read(&mut context.pool()).await?; let local_site = LocalSite::read(&mut context.pool()).await?;
honeypot_check(&data.honeypot)?; 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() let post_form = PostInsertForm::builder()
.name(data.name.trim().to_string()) .name(data.name.trim().to_string())
.url(url) .url(url)
@ -161,8 +161,6 @@ pub async fn create_post(
.await .await
.with_lemmy_type(LemmyErrorType::CouldntCreatePost)?; .with_lemmy_type(LemmyErrorType::CouldntCreatePost)?;
plugin_hook("api_after_create_post", updated_post.clone())?;
generate_post_link_metadata( generate_post_link_metadata(
updated_post.clone(), updated_post.clone(),
custom_thumbnail, 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> { fn load_plugins() -> LemmyResult<Plugin> {
// TODO: make dir configurable via env var // 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 plugin_paths = read_dir("example_plugin")?;
let mut wasm_files = vec![]; let mut wasm_files = vec![];
@ -226,13 +230,20 @@ fn load_plugins() -> LemmyResult<Plugin> {
Ok(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()?; let mut plugin = load_plugins()?;
if plugin.function_exists(name) { if plugin.function_exists(name) {
let res = plugin *data = plugin
.call::<extism_convert::Json<T>, &str>(name, data.into()) .call::<extism_convert::Json<T>, extism_convert::Json<T>>(name, (*data).clone().into())
.map_err(|e| LemmyErrorType::PluginError(e.to_string())); .map_err(|e| {
println!("{}", res?); dbg!(&e);
LemmyErrorType::PluginError(e.to_string())
})?
.0
.into();
} }
Ok(()) Ok(())
} }

View file

@ -2,13 +2,18 @@ package main
import ( import (
"github.com/extism/go-pdk" "github.com/extism/go-pdk"
"errors"
) )
type CreatePost struct { type CreatePost struct {
Name string `json:"name"` Name string `json:"name"`
Body string `json:"body"` Body *string `json:"body,omitempty"`
// skipping other fields for now 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 //export api_before_create_post
@ -20,12 +25,15 @@ func api_before_create_post() int32 {
pdk.SetError(err) pdk.SetError(err)
return 1 return 1
} }
if params.Body == "plugin should block this" { if params.Name == "foobar" {
pdk.SetError(errors.New("blocked by plugin")) 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 return 1
} }
greeting := `Created post "` + params.Name + `"!`
pdk.OutputString(greeting)
return 0 return 0
} }