Add admin utilities for adding projects

This commit is contained in:
Ben Visness 2021-11-11 15:59:05 -08:00
parent 7bf07c488e
commit 0184cd1625
5 changed files with 240 additions and 7 deletions

View File

@ -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)
}

View File

@ -297,4 +297,6 @@ func init() {
moveThreadsToSubforumCommand.MarkFlagRequired("project_slug")
moveThreadsToSubforumCommand.MarkFlagRequired("subforum_slug")
adminCommand.AddCommand(moveThreadsToSubforumCommand)
addProjectCommands(adminCommand)
}

View File

@ -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)

View File

@ -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)

View File

@ -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(