diff --git a/src/migration/migrations/2021-08-03T021418Z_DropAuthGroups.go b/src/migration/migrations/2021-08-03T021418Z_DropAuthGroups.go new file mode 100644 index 00000000..60b8703e --- /dev/null +++ b/src/migration/migrations/2021-08-03T021418Z_DropAuthGroups.go @@ -0,0 +1,66 @@ +package migrations + +import ( + "context" + "time" + + "git.handmade.network/hmn/hmn/src/migration/types" + "git.handmade.network/hmn/hmn/src/oops" + "github.com/jackc/pgx/v4" +) + +func init() { + registerMigration(DropAuthGroups{}) +} + +type DropAuthGroups struct{} + +func (m DropAuthGroups) Version() types.MigrationVersion { + return types.MigrationVersion(time.Date(2021, 8, 3, 2, 14, 18, 0, time.UTC)) +} + +func (m DropAuthGroups) Name() string { + return "DropAuthGroups" +} + +func (m DropAuthGroups) Description() string { + return "Drop the auth groups table, and related tables" +} + +func (m DropAuthGroups) Up(ctx context.Context, tx pgx.Tx) error { + _, err := tx.Exec(ctx, ` + DROP TABLE handmade_user_projects; + CREATE TABLE handmade_user_projects ( + user_id INT NOT NULL REFERENCES auth_user (id) ON DELETE CASCADE, + project_id INT NOT NULL REFERENCES handmade_project (id) ON DELETE CASCADE, + PRIMARY KEY (user_id, project_id) + ); + + INSERT INTO handmade_user_projects (user_id, project_id) + SELECT agroups.user_id, pg.project_id + FROM + handmade_project_groups AS pg + JOIN auth_group AS ag ON ag.id = pg.group_id + JOIN auth_user_groups AS agroups ON agroups.group_id = ag.id; + `) + if err != nil { + return oops.New(err, "failed to recreate handmade_user_projects") + } + + _, err = tx.Exec(ctx, ` + DROP TABLE auth_group_permissions; + DROP TABLE auth_user_groups; + DROP TABLE handmade_project_groups; + + DROP TABLE auth_group; + `) + if err != nil { + return oops.New(err, "failed to drop group-related tables") + } + + return nil +} + +func (m DropAuthGroups) Down(ctx context.Context, tx pgx.Tx) error { + panic("Implement me") +} diff --git a/src/migration/todo.txt b/src/migration/todo.txt index 553280f8..1168f260 100644 --- a/src/migration/todo.txt +++ b/src/migration/todo.txt @@ -1,10 +1,7 @@ Clean this up once we get the website working --------------------------------------------- TODO: Questionable db tables that we inherited from Django: -* auth_group -* auth_group_permissions * auth_permission -* auth_user_groups * auth_user_user_permissions * django_admin_log * django_content_type diff --git a/src/templates/src/blog_index.html b/src/templates/src/blog_index.html index 2b37f199..2972fdb2 100644 --- a/src/templates/src/blog_index.html +++ b/src/templates/src/blog_index.html @@ -3,36 +3,44 @@ {{ define "content" }}
- + Create Post + {{ if .CanCreatePost }} + + Create Post + {{ end }}
{{ template "pagination.html" .Pagination }}
{{/* TODO: Breadcrumbs, or some other link back to the blog index */}} -{{ range .Posts }} -
- -
- -
- {{ .Author.Name }} — {{ timehtml (relativedate .Date) .Date }} -
-
-
- {{ .Content }} +{{ if .Posts }} + {{ range .Posts }} +
+ +
+ +
+ {{ .Author.Name }} — {{ timehtml (relativedate .Date) .Date }} +
+
+
+ {{ .Content }} +
+
+
+ -
-
-
-
+ {{ end }} +{{ else }} +
There are no blog posts for this project yet.
{{ end }}
- + Create Post + {{ if .CanCreatePost }} + + Create Post + {{ end }}
{{ template "pagination.html" .Pagination }} diff --git a/src/website/blogs.go b/src/website/blogs.go index 78773e1e..85c5111c 100644 --- a/src/website/blogs.go +++ b/src/website/blogs.go @@ -27,7 +27,9 @@ func BlogIndex(c *RequestContext) ResponseData { templates.BaseData Posts []blogIndexEntry Pagination templates.Pagination - NewPostUrl string + + CanCreatePost bool + NewPostUrl string } const postsPerPage = 5 @@ -105,6 +107,23 @@ func BlogIndex(c *RequestContext) ResponseData { baseData := getBaseData(c) baseData.Title = fmt.Sprintf("%s Blog", c.CurrentProject.Name) + canCreate := false + if c.CurrentUser != nil { + isProjectOwner := false + owners, err := FetchProjectOwners(c, c.CurrentProject.ID) + if err != nil { + return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch project owners")) + } + for _, owner := range owners { + if owner.ID == c.CurrentUser.ID { + isProjectOwner = true + break + } + } + + canCreate = c.CurrentUser.IsStaff || isProjectOwner + } + var res ResponseData res.MustWriteTemplate("blog_index.html", blogIndexData{ BaseData: baseData, @@ -118,7 +137,9 @@ func BlogIndex(c *RequestContext) ResponseData { PreviousUrl: hmnurl.BuildBlog(c.CurrentProject.Slug, utils.IntClamp(1, page-1, numPages)), NextUrl: hmnurl.BuildBlog(c.CurrentProject.Slug, utils.IntClamp(1, page+1, numPages)), }, - NewPostUrl: hmnurl.BuildBlogNewThread(c.CurrentProject.Slug), + + CanCreatePost: canCreate, + NewPostUrl: hmnurl.BuildBlogNewThread(c.CurrentProject.Slug), }, c.Perf) return res } diff --git a/src/website/feed.go b/src/website/feed.go index 9e1dca7e..bae6fe62 100644 --- a/src/website/feed.go +++ b/src/website/feed.go @@ -206,32 +206,31 @@ func AtomFeed(c *RequestContext) ResponseData { return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed projects")) } var projectIds []int - projectMap := make(map[int]*templates.Project) + projectMap := make(map[int]int) // map[project id]index in slice for _, p := range projects.ToSlice() { project := p.(*projectResult).Project templateProject := templates.ProjectToTemplate(&project, c.Theme) templateProject.UUID = uuid.NewSHA1(uuid.NameSpaceURL, []byte(templateProject.Url)).URN() projectIds = append(projectIds, project.ID) - projectMap[project.ID] = &templateProject feedData.Projects = append(feedData.Projects, templateProject) + projectMap[project.ID] = len(feedData.Projects) - 1 } c.Perf.EndBlock() c.Perf.StartBlock("SQL", "Fetching project owners") type ownerResult struct { User models.User `db:"auth_user"` - ProjectID int `db:"project_groups.project_id"` + ProjectID int `db:"uproj.project_id"` } owners, err := db.Query(c.Context(), c.Conn, ownerResult{}, ` SELECT $columns FROM - auth_user - INNER JOIN auth_user_groups AS user_groups ON auth_user.id = user_groups.user_id - INNER JOIN handmade_project_groups AS project_groups ON user_groups.group_id = project_groups.group_id + handmade_user_projects AS uproj + JOIN auth_user ON uproj.user_id = auth_user.id WHERE - project_groups.project_id = ANY($1) + uproj.project_id = ANY($1) `, projectIds, ) @@ -240,7 +239,7 @@ func AtomFeed(c *RequestContext) ResponseData { } for _, res := range owners.ToSlice() { owner := res.(*ownerResult) - templateProject := projectMap[owner.ProjectID] + templateProject := &feedData.Projects[projectMap[owner.ProjectID]] templateProject.Owners = append(templateProject.Owners, templates.UserToTemplate(&owner.User, "")) } c.Perf.EndBlock() diff --git a/src/website/project_helper.go b/src/website/project_helper.go index f77b3777..83ba7435 100644 --- a/src/website/project_helper.go +++ b/src/website/project_helper.go @@ -36,10 +36,9 @@ func FetchProjectOwners(c *RequestContext, projectId int) ([]*models.User, error SELECT $columns FROM auth_user - INNER JOIN auth_user_groups AS user_groups ON auth_user.id = user_groups.user_id - INNER JOIN handmade_project_groups AS project_groups ON user_groups.group_id = project_groups.group_id + INNER JOIN handmade_user_projects AS uproj ON uproj.user_id = auth_user.id WHERE - project_groups.project_id = $1 + uproj.project_id = $1 `, projectId, ) diff --git a/src/website/projects.go b/src/website/projects.go index 2d6efaba..5aa8410c 100644 --- a/src/website/projects.go +++ b/src/website/projects.go @@ -106,10 +106,9 @@ func ProjectIndex(c *RequestContext) ResponseData { SELECT $columns FROM handmade_project AS project - INNER JOIN handmade_project_groups AS project_groups ON project_groups.project_id = project.id - INNER JOIN auth_user_groups AS user_groups ON user_groups.group_id = project_groups.group_id + INNER JOIN handmade_user_projects AS uproj ON uproj.project_id = project.id WHERE - user_groups.user_id = $1 + uproj.user_id = $1 `, c.CurrentUser.ID, ) diff --git a/src/website/user.go b/src/website/user.go index 603cc49b..19f2cc2b 100644 --- a/src/website/user.go +++ b/src/website/user.go @@ -91,10 +91,9 @@ func UserProfile(c *RequestContext) ResponseData { SELECT $columns FROM handmade_project AS project - INNER JOIN handmade_project_groups AS project_groups ON project_groups.project_id = project.id - INNER JOIN auth_user_groups AS user_groups ON user_groups.group_id = project_groups.group_id + INNER JOIN handmade_user_projects AS uproj ON uproj.project_id = project.id WHERE - user_groups.user_id = $1 + uproj.user_id = $1 AND ($2 OR (project.flags = 0 AND project.lifecycle = ANY ($3))) `, profileUser.ID,