From 0184cd1625904d78cccec06025400bc909d5b9df Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Thu, 11 Nov 2021 15:59:05 -0800 Subject: [PATCH] Add admin utilities for adding projects --- src/admintools/adminproject.go | 231 +++++++++++++++++++++++++++++++++ src/admintools/admintools.go | 2 + src/website/project_helper.go | 2 +- src/website/routes.go | 10 +- src/website/website.go | 2 +- 5 files changed, 240 insertions(+), 7 deletions(-) create mode 100644 src/admintools/adminproject.go diff --git a/src/admintools/adminproject.go b/src/admintools/adminproject.go new file mode 100644 index 00000000..a6234226 --- /dev/null +++ b/src/admintools/adminproject.go @@ -0,0 +1,231 @@ +package admintools + +import ( + "context" + "fmt" + + "git.handmade.network/hmn/hmn/src/db" + "git.handmade.network/hmn/hmn/src/models" + "git.handmade.network/hmn/hmn/src/parsing" + "git.handmade.network/hmn/hmn/src/website" + "github.com/spf13/cobra" +) + +func addProjectCommands(adminCommand *cobra.Command) { + projectCommand := &cobra.Command{ + Use: "project", + Short: "Admin commands for managing projects", + } + adminCommand.AddCommand(projectCommand) + + addCreateProjectCommand(projectCommand) + addProjectTagCommand(projectCommand) +} + +func addCreateProjectCommand(projectCommand *cobra.Command) { + createProjectCommand := &cobra.Command{ + Use: "create", + Short: "Create a new project", + Run: func(cmd *cobra.Command, args []string) { + name, _ := cmd.Flags().GetString("name") + slug, _ := cmd.Flags().GetString("slug") + blurb, _ := cmd.Flags().GetString("blurb") + description, _ := cmd.Flags().GetString("description") + personal, _ := cmd.Flags().GetBool("personal") + userIDs, _ := cmd.Flags().GetIntSlice("userids") + + descParsed := parsing.ParseMarkdown(description, parsing.ForumRealMarkdown) + + ctx := context.Background() + conn := db.NewConnPool(1, 1) + defer conn.Close() + + tx, err := conn.Begin(ctx) + if err != nil { + panic(err) + } + defer tx.Rollback(ctx) + + p, err := website.FetchProject(ctx, tx, nil, models.HMNProjectID, website.ProjectsQuery{ + IncludeHidden: true, + }) + if err != nil { + panic(err) + } + hmn := p.Project + + newProjectID, err := db.QueryInt(ctx, tx, + ` + INSERT INTO handmade_project ( + slug, + name, + blurb, + description, + color_1, + color_2, + featured, + hidden, + descparsed, + blog_enabled, + forum_enabled, + all_last_updated, + annotation_last_updated, + blog_last_updated, + forum_last_updated, + lifecycle, + date_approved, + date_created, + bg_flags, + library_enabled, + personal + ) VALUES ( + $1, -- slug + $2, -- name + $3, -- blurb + $4, -- description + $5, -- color_1 + $6, -- color_2 + FALSE, -- featured + FALSE, -- hidden + $7, -- descparsed + FALSE, -- blog_enabled + FALSE, -- forum_enabled + NOW(), -- all_last_updated + 'epoch', -- annotation_last_updated + 'epoch', -- blog_last_updated + 'epoch', -- forum_last_updated + $8, -- lifecycle + NOW(), -- date_approved + NOW(), -- date_created + 0, -- bg_flags + FALSE, -- library_enabled + $9 -- personal + ) + RETURNING id + `, + slug, + name, + blurb, + description, + hmn.Color1, + hmn.Color2, + descParsed, + models.ProjectLifecycleActive, + personal, + ) + if err != nil { + panic(err) + } + + for _, userID := range userIDs { + _, err := tx.Exec(ctx, + ` + INSERT INTO handmade_user_projects (user_id, project_id) + VALUES ($1, $2) + `, + userID, + newProjectID, + ) + if err != nil { + panic(err) + } + } + + err = tx.Commit(ctx) + if err != nil { + panic(err) + } + + fmt.Printf("Created new project with id: %d\n", newProjectID) + }, + } + createProjectCommand.Flags().String("name", "", "") + createProjectCommand.Flags().String("slug", "", "") + createProjectCommand.Flags().String("blurb", "", "") + createProjectCommand.Flags().String("description", "", "") + createProjectCommand.Flags().Bool("personal", true, "") + createProjectCommand.Flags().IntSlice("userids", nil, "") + createProjectCommand.MarkFlagRequired("name") + createProjectCommand.MarkFlagRequired("userids") + projectCommand.AddCommand(createProjectCommand) +} + +func addProjectTagCommand(projectCommand *cobra.Command) { + projectTagCommand := &cobra.Command{ + Use: "tag", + Short: "Create or update a project's tag", + Run: func(cmd *cobra.Command, args []string) { + projectID, _ := cmd.Flags().GetInt("projectid") + tag, _ := cmd.Flags().GetString("tag") + + ctx := context.Background() + conn := db.NewConnPool(1, 1) + defer conn.Close() + + tx, err := conn.Begin(ctx) + if err != nil { + panic(err) + } + defer tx.Rollback(ctx) + + p, err := website.FetchProject(ctx, tx, nil, projectID, website.ProjectsQuery{ + IncludeHidden: true, + }) + if err != nil { + panic(err) + } + + if p.Project.TagID == nil { + // Create a tag + tagID, err := db.QueryInt(ctx, tx, + ` + INSERT INTO tags (text) VALUES ($1) + RETURNING id + `, + tag, + ) + if err != nil { + panic(err) + } + + // Attach it to the project + _, err = tx.Exec(ctx, + ` + UPDATE handmade_project + SET tag = $1 + WHERE id = $2 + `, + tagID, projectID, + ) + if err != nil { + panic(err) + } + } else { + // Update the text of an existing one + _, err := tx.Exec(ctx, + ` + UPDATE tags + SET text = $1 + WHERE id = (SELECT tag FROM handmade_project WHERE id = $2) + `, + tag, projectID, + ) + if err != nil { + panic(err) + } + } + + err = tx.Commit(ctx) + if err != nil { + panic(err) + } + + fmt.Printf("Project now has tag: %s\n", tag) + }, + } + projectTagCommand.Flags().Int("projectid", 0, "") + projectTagCommand.Flags().String("tag", "", "") + projectTagCommand.MarkFlagRequired("projectid") + projectTagCommand.MarkFlagRequired("tag") + projectCommand.AddCommand(projectTagCommand) +} diff --git a/src/admintools/admintools.go b/src/admintools/admintools.go index 6f76b282..1d09de3f 100644 --- a/src/admintools/admintools.go +++ b/src/admintools/admintools.go @@ -297,4 +297,6 @@ func init() { moveThreadsToSubforumCommand.MarkFlagRequired("project_slug") moveThreadsToSubforumCommand.MarkFlagRequired("subforum_slug") adminCommand.AddCommand(moveThreadsToSubforumCommand) + + addProjectCommands(adminCommand) } diff --git a/src/website/project_helper.go b/src/website/project_helper.go index 26e800b9..f74ca983 100644 --- a/src/website/project_helper.go +++ b/src/website/project_helper.go @@ -73,7 +73,7 @@ func FetchProjects( qb.Add(`AND project.id = ANY ($?)`, q.ProjectIDs) } if len(q.Slugs) > 0 { - qb.Add(`AND project.slug = ANY ($?)`, q.Slugs) + qb.Add(`AND (project.slug != '' AND project.slug = ANY ($?))`, q.Slugs) } if len(q.Lifecycles) > 0 { qb.Add(`AND project.lifecycle = ANY($?)`, q.Lifecycles) diff --git a/src/website/routes.go b/src/website/routes.go index e8c31b4c..68e4d0a6 100644 --- a/src/website/routes.go +++ b/src/website/routes.go @@ -28,7 +28,7 @@ import ( "github.com/teacat/noire" ) -func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, perfCollector *perf.PerfCollector) http.Handler { +func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool) http.Handler { router := &Router{} routes := RouteBuilder{ Router: router, @@ -36,7 +36,7 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe return func(c *RequestContext) (res ResponseData) { c.Conn = conn - logPerf := TrackRequestPerf(c, perfCollector) + logPerf := TrackRequestPerf(c) defer logPerf() defer LogContextErrorsFromResponse(c, &res) @@ -52,7 +52,7 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe return func(c *RequestContext) (res ResponseData) { c.Conn = conn - logPerf := TrackRequestPerf(c, perfCollector) + logPerf := TrackRequestPerf(c) defer logPerf() defer LogContextErrorsFromResponse(c, &res) @@ -74,7 +74,7 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe return func(c *RequestContext) (res ResponseData) { c.Conn = conn - logPerf := TrackRequestPerf(c, perfCollector) + logPerf := TrackRequestPerf(c) defer logPerf() defer LogContextErrorsFromResponse(c, &res) @@ -534,7 +534,7 @@ func getCurrentUserAndSession(c *RequestContext, sessionId string) (*models.User const PerfContextKey = "HMNPerf" -func TrackRequestPerf(c *RequestContext, perfCollector *perf.PerfCollector) (after func()) { +func TrackRequestPerf(c *RequestContext) (after func()) { c.Perf = perf.MakeNewRequestPerf(c.Route, c.Req.Method, c.Req.URL.Path) c.ctx = context.WithValue(c.Context(), PerfContextKey, c.Perf) diff --git a/src/website/website.go b/src/website/website.go index 7f5fe4fd..65bf9292 100644 --- a/src/website/website.go +++ b/src/website/website.go @@ -37,7 +37,7 @@ var WebsiteCommand = &cobra.Command{ server := http.Server{ Addr: config.Config.Addr, - Handler: NewWebsiteRoutes(longRequestContext, conn, perfCollector), + Handler: NewWebsiteRoutes(longRequestContext, conn), } backgroundJobsDone := zipJobs(