From 3915fa786c49c04d881c5d5a1e287c4d852568fd Mon Sep 17 00:00:00 2001 From: Ivan Velichko Date: Sat, 9 Mar 2024 20:23:31 +0000 Subject: [PATCH] content authoring WIP --- cmd/content/create.go | 57 +++++++++++++++++++++++++++++++++----- internal/api/challenges.go | 28 +++++++++++++++++++ internal/api/client.go | 41 +++++++++++++++++++++++++++ internal/api/content.go | 25 +++++++++++++++++ 4 files changed, 144 insertions(+), 7 deletions(-) create mode 100644 internal/api/challenges.go create mode 100644 internal/api/content.go diff --git a/cmd/content/create.go b/cmd/content/create.go index 55afd22..d595bbd 100644 --- a/cmd/content/create.go +++ b/cmd/content/create.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/charmbracelet/huh" + "github.com/skratchdot/open-golang/open" "github.com/spf13/cobra" "github.com/iximiuz/labctl/internal/api" @@ -135,14 +136,56 @@ func runCreateContent(ctx context.Context, cli labcli.CLI, opts *createOptions) } func createChallenge(ctx context.Context, cli labcli.CLI, opts *createOptions) error { - // ch, err := cli.Client().CreateChallenge(ctx, labcli.CreateChallengeRequest{ - // Name: opts.name, - // }) - // if err != nil { - // return fmt.Errorf("couldn't create challenge: %w", err) - // } + ch, err := cli.Client().CreateChallenge(ctx, api.CreateChallengeRequest{ + Name: opts.name, + }) + if err != nil { + return fmt.Errorf("couldn't create challenge: %w", err) + } - return nil + cli.PrintAux("Created a new challenge %s\n", ch.PageURL) + if err := open.Run(ch.PageURL); err != nil { + cli.PrintAux("Couldn't open the browser. Copy the above URL into a browser manually.\n") + } + + if err := cli.Client().PutMarkdown(ctx, api.PutMarkdownRequest{ + Kind: "challenge", + Name: opts.name, + Content: `--- +title: Sample Challenge +description: | + This is a sample challenge. + +kind: challenge +playground: docker + +createdAt: 2024-01-01 +updatedAt: 2024-02-09 + +difficulty: medium + +categories: + - containers + +tagz: + - containerd + - ctr + - docker + +tasks: + init_run_container_labs_are_fun: + init: true + run: | + docker run -q -d --name labs-are-fun busybox sleep 999999 +--- +# Sample Challenge + +This is a sample challenge. You can edit this file in ... .`, + }); err != nil { + return fmt.Errorf("couldn't create a sample markdown file: %w", err) + } + + return labcli.NewStatusError(0, "Happy authoring!") } func createTutorial(ctx context.Context, cli labcli.CLI, opts *createOptions) error { diff --git a/internal/api/challenges.go b/internal/api/challenges.go new file mode 100644 index 0000000..301ca05 --- /dev/null +++ b/internal/api/challenges.go @@ -0,0 +1,28 @@ +package api + +import ( + "context" +) + +type Challenge struct { + CreatedAt string `json:"createdAt"` + UpdatedAt string `json:"updatedAt"` + + Name string `json:"name"` + + PageURL string `json:"pageUrl"` +} + +type CreateChallengeRequest struct { + Name string `json:"name"` +} + +func (c *Client) CreateChallenge(ctx context.Context, req CreateChallengeRequest) (*Challenge, error) { + body, err := toJSONBody(req) + if err != nil { + return nil, err + } + + var ch Challenge + return &ch, c.PostInto(ctx, "/challenges", nil, nil, body, &ch) +} diff --git a/internal/api/client.go b/internal/api/client.go index 0b4e648..d580955 100644 --- a/internal/api/client.go +++ b/internal/api/client.go @@ -124,6 +124,47 @@ func (c *Client) PostInto( return err } +func (c *Client) Put( + ctx context.Context, + path string, + query url.Values, + headers http.Header, + body io.Reader, +) (*http.Response, error) { + req, err := c.newRequest(ctx, http.MethodPut, path, query, headers, body) + if err != nil { + return nil, err + } + + return c.doRequest(req) +} + +func (c *Client) PutInto( + ctx context.Context, + path string, + query url.Values, + headers http.Header, + body io.Reader, + into any, +) error { + req, err := c.newRequest(ctx, http.MethodPut, path, query, headers, body) + if err != nil { + return err + } + + resp, err := c.doRequest(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if err := json.NewDecoder(resp.Body).Decode(into); err != nil { + return err + } + + return err +} + func (c *Client) Delete( ctx context.Context, path string, diff --git a/internal/api/content.go b/internal/api/content.go new file mode 100644 index 0000000..6ff5733 --- /dev/null +++ b/internal/api/content.go @@ -0,0 +1,25 @@ +package api + +import ( + "context" +) + +type PutMarkdownRequest struct { + Kind string `json:"kind"` + Name string `json:"name"` + Content string `json:"content"` +} + +func (c *Client) PutMarkdown(ctx context.Context, req PutMarkdownRequest) error { + body, err := toJSONBody(req) + if err != nil { + return err + } + + resp, err := c.Put(ctx, "/content/markdown", nil, nil, body) + if err != nil { + return err + } + resp.Body.Close() + return nil +}