From 435ee6d0f176cbfe043fb8eb417563bbd89b0606 Mon Sep 17 00:00:00 2001 From: Lucas TESSON Date: Thu, 12 Dec 2024 11:00:53 +0100 Subject: [PATCH] docs: add API extension documentation for a plugin that modifies challenges --- examples/extend/main.go | 98 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 examples/extend/main.go diff --git a/examples/extend/main.go b/examples/extend/main.go new file mode 100644 index 0000000..22daa73 --- /dev/null +++ b/examples/extend/main.go @@ -0,0 +1,98 @@ +package main + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "log" + "net/http" + + "github.com/ctfer-io/go-ctfd/api" +) + +const ( + url = "http://localhost:8000" + apiKey = "ctfd_xxx" +) + +func main() { + ctx := context.Background() + cli := api.NewClient(url, "", "", apiKey) + + chall, err := PostChallenges(cli, ctx, &MyPluginPostChallengeParams{ + PostChallengesParams: api.PostChallengesParams{ + Name: "My challenge", + Description: "Super duper description", + Category: "Misc", + Value: 500, + Type: "standard", + }, + NewField1: "some content", + NewField2: map[string]bool{ + "one": true, + "two": false, + }, + }) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("[%d] new_field3: %v\n", chall.ID, chall.NewField3) +} + +type MyPluginPostChallengeParams struct { + api.PostChallengesParams + + NewField1 string `json:"new_field1"` + NewField2 map[string]bool `json:"new_field2,omitempty"` +} + +// ... other structs required for your use case + +type MyPluginChallenge struct { + api.Challenge + + NewField1 string `json:"new_field1"` + NewField2 map[string]bool `json:"new_field2,omitempty"` + NewField3 int `json:"new_field3"` +} + +func PostChallenges(client *api.Client, ctx context.Context, params *MyPluginPostChallengeParams) (*MyPluginChallenge, error) { + if params == nil { + params = &MyPluginPostChallengeParams{} + } + // ... default any value if required, check values (e.g. integer boundaries) + + // Create your API object + chall := &MyPluginChallenge{} + + // Make the call + buf := &bytes.Buffer{} + if err := json.NewEncoder(buf).Encode(params); err != nil { + return nil, err + } + req, _ := http.NewRequestWithContext(ctx, http.MethodPost, "/api/v1/plugins/my_plugin/challenges", nil) + res, err := client.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + + // Decode the response + resp := api.Response{ + Data: chall, + } + if err := json.NewDecoder(res.Body).Decode(&resp); err != nil { + return nil, err + } + + // ... do any API check you would like to + + return chall, nil +} + +// ... other methods required for your use case + +// you can even go further and implement your custom client that +// fit your plugin API needs ! :confetti_ball: