diff --git a/src/hmnurl/hmnurl_test.go b/src/hmnurl/hmnurl_test.go index 2b9d8e1..bd35d3c 100644 --- a/src/hmnurl/hmnurl_test.go +++ b/src/hmnurl/hmnurl_test.go @@ -32,10 +32,6 @@ func TestHomepage(t *testing.T) { AssertSubdomain(t, BuildProjectHomepage("hero"), "hero") } -func TestProjectIndex(t *testing.T) { - AssertRegexMatch(t, BuildProjectIndex(), RegexProjectIndex, nil) -} - func TestShowcase(t *testing.T) { AssertRegexMatch(t, BuildShowcase(), RegexShowcase, nil) } @@ -70,6 +66,10 @@ func TestLogoutAction(t *testing.T) { AssertRegexMatch(t, BuildLogoutAction(), RegexLogoutAction, nil) } +func TestRegister(t *testing.T) { + AssertRegexMatch(t, BuildRegister(), RegexRegister, nil) +} + func TestStaticPages(t *testing.T) { AssertRegexMatch(t, BuildManifesto(), RegexManifesto, nil) AssertRegexMatch(t, BuildAbout(), RegexAbout, nil) @@ -94,6 +94,20 @@ func TestFeed(t *testing.T) { assert.Panics(t, func() { BuildFeedWithPage(0) }) } +func TestProjectIndex(t *testing.T) { + AssertRegexMatch(t, BuildProjectIndex(1), RegexProjectIndex, nil) + AssertRegexMatch(t, BuildProjectIndex(2), RegexProjectIndex, map[string]string{"page": "2"}) + assert.Panics(t, func() { BuildProjectIndex(0) }) +} + +func TestProjectNew(t *testing.T) { + AssertRegexMatch(t, BuildProjectNew(), RegexProjectNew, nil) +} + +func TestProjectNotApproved(t *testing.T) { + AssertRegexMatch(t, BuildProjectNotApproved("test"), RegexProjectNotApproved, map[string]string{"slug": "test"}) +} + func TestPodcast(t *testing.T) { AssertRegexMatch(t, BuildPodcast(""), RegexPodcast, nil) AssertSubdomain(t, BuildPodcast(""), "") diff --git a/src/hmnurl/urls.go b/src/hmnurl/urls.go index 6c2cd37..0160f86 100644 --- a/src/hmnurl/urls.go +++ b/src/hmnurl/urls.go @@ -16,8 +16,6 @@ Any function in this package whose name starts with Build is required to be cove This helps ensure that we don't generate URLs that can't be routed. */ -// TODO(asaf): Make this whole file only crash in Dev - var RegexHomepage = regexp.MustCompile("^/$") func BuildHomepage() string { @@ -29,13 +27,6 @@ func BuildProjectHomepage(projectSlug string) string { return ProjectUrl("/", nil, projectSlug) } -var RegexProjectIndex = regexp.MustCompile("^/projects$") - -func BuildProjectIndex() string { - defer CatchPanic() - return Url("/projects", nil) -} - var RegexShowcase = regexp.MustCompile("^/showcase$") func BuildShowcase() string { @@ -80,6 +71,13 @@ func BuildLogoutAction() string { return Url("/logout", nil) } +var RegexRegister = regexp.MustCompile("^/_register$") + +func BuildRegister() string { + defer CatchPanic() + return Url("/_register", nil) +} + /* * Static Pages */ @@ -186,6 +184,40 @@ func BuildAtomFeedForShowcase() string { return Url("/atom/showcase", nil) } +/* +* Projects + */ + +var RegexProjectIndex = regexp.MustCompile("^/projects(/(?P.+)?)?$") + +func BuildProjectIndex(page int) string { + defer CatchPanic() + if page < 1 { + panic(oops.New(nil, "page must be >= 1")) + } + if page == 1 { + return Url("/projects", nil) + } else { + return Url(fmt.Sprintf("/projects/%d", page), nil) + } +} + +var RegexProjectNew = regexp.MustCompile("^/projects/new$") + +func BuildProjectNew() string { + defer CatchPanic() + + return Url("/projects/new", nil) +} + +var RegexProjectNotApproved = regexp.MustCompile("^/p/(?P.+)$") + +func BuildProjectNotApproved(slug string) string { + defer CatchPanic() + + return Url(fmt.Sprintf("/p/%s", slug), nil) +} + /* * Podcast */ diff --git a/src/models/project.go b/src/models/project.go index 236908b..193b5f3 100644 --- a/src/models/project.go +++ b/src/models/project.go @@ -24,15 +24,26 @@ const ( ProjectLifecycleLTS ) +// NOTE(asaf): Just checking the lifecycle is not sufficient. Visible projects also must have flags = 0. +var VisibleProjectLifecycles = []ProjectLifecycle{ + ProjectLifecycleActive, + ProjectLifecycleHiatus, + ProjectLifecycleLTSRequired, // NOTE(asaf): LTS means complete + ProjectLifecycleLTS, +} + +const RecentProjectUpdateTimespanSec = 60 * 60 * 24 * 28 // NOTE(asaf): Four weeks + type Project struct { ID int `db:"id"` ForumID *int `db:"forum_id"` - Slug string `db:"slug"` - Name string `db:"name"` - Blurb string `db:"blurb"` - Description string `db:"description"` + Slug string `db:"slug"` + Name string `db:"name"` + Blurb string `db:"blurb"` + Description string `db:"description"` + ParsedDescription string `db:"descparsed"` Lifecycle ProjectLifecycle `db:"lifecycle"` // TODO(asaf): Ensure we only fetch projects in the correct lifecycle phase everywhere. @@ -42,6 +53,8 @@ type Project struct { LogoLight string `db:"logolight"` LogoDark string `db:"logodark"` + Flags int `db:"flags"` // NOTE(asaf): Flags is currently only used to mark a project as hidden. Flags == 1 means hidden. Flags == 0 means visible. + Featured bool `db:"featured"` DateApproved time.Time `db:"date_approved"` AllLastUpdated time.Time `db:"all_last_updated"` } diff --git a/src/templates/mapping.go b/src/templates/mapping.go index ba0f7a7..80244b5 100644 --- a/src/templates/mapping.go +++ b/src/templates/mapping.go @@ -51,17 +51,50 @@ func (p *Post) AddUrls(projectSlug string, subforums []string, threadId int, pos p.QuoteUrl = hmnurl.BuildForumPostQuote(projectSlug, subforums, threadId, postId) } -func ProjectToTemplate(p *models.Project) Project { - return Project{ - Name: p.Name, - Subdomain: p.Subdomain(), - Color1: p.Color1, - Color2: p.Color2, - Url: hmnurl.BuildProjectHomepage(p.Slug), - Blurb: p.Blurb, +var LifecycleBadgeClasses = map[models.ProjectLifecycle]string{ + models.ProjectLifecycleUnapproved: "", + models.ProjectLifecycleApprovalRequired: "", + models.ProjectLifecycleActive: "", + models.ProjectLifecycleHiatus: "notice-hiatus", + models.ProjectLifecycleDead: "notice-dead", + models.ProjectLifecycleLTSRequired: "", + models.ProjectLifecycleLTS: "notice-lts", +} - LogoLight: hmnurl.BuildUserFile(p.LogoLight), - LogoDark: hmnurl.BuildUserFile(p.LogoDark), +var LifecycleBadgeStrings = map[models.ProjectLifecycle]string{ + models.ProjectLifecycleUnapproved: "", + models.ProjectLifecycleApprovalRequired: "", + models.ProjectLifecycleActive: "", + models.ProjectLifecycleHiatus: "On Hiatus", + models.ProjectLifecycleDead: "Dead", + models.ProjectLifecycleLTSRequired: "", + models.ProjectLifecycleLTS: "Complete", +} + +func ProjectToTemplate(p *models.Project, theme string) Project { + logo := p.LogoLight + if theme == "dark" { + logo = p.LogoDark + } + var url string + if p.Lifecycle == models.ProjectLifecycleUnapproved || p.Lifecycle == models.ProjectLifecycleApprovalRequired { + url = hmnurl.BuildProjectNotApproved(p.Slug) + } else { + url = hmnurl.BuildProjectHomepage(p.Slug) + } + return Project{ + Name: p.Name, + Subdomain: p.Subdomain(), + Color1: p.Color1, + Color2: p.Color2, + Url: url, + Blurb: p.Blurb, + ParsedDescription: template.HTML(p.ParsedDescription), + + Logo: hmnurl.BuildUserFile(logo), + + LifecycleBadgeClass: LifecycleBadgeClasses[p.Lifecycle], + LifecycleString: LifecycleBadgeStrings[p.Lifecycle], IsHMN: p.IsHMN(), diff --git a/src/templates/src/atom.xml b/src/templates/src/atom.xml index 9e028e2..e437b78 100644 --- a/src/templates/src/atom.xml +++ b/src/templates/src/atom.xml @@ -37,7 +37,7 @@ {{ .ProfileUrl }} {{ end }} - {{ .LogoLight }} + {{ .Logo }} {{ .Blurb }} {{ end }} diff --git a/src/templates/src/include/header.html b/src/templates/src/include/header.html index 9951a0e..c907acf 100644 --- a/src/templates/src/include/header.html +++ b/src/templates/src/include/header.html @@ -1,5 +1,4 @@
- {{/* TODO: All the URLs in here are wrong. */}}
{{ if .User }} {{ if .User.IsSuperuser }} @@ -31,19 +30,22 @@
{{ end }} -