Added project links to project edit page
This commit is contained in:
parent
80f0e3b176
commit
eb32b04437
|
@ -137,6 +137,19 @@
|
||||||
<div class="c--dim f7">Plaintext only. No links or markdown.</div>
|
<div class="c--dim f7">Plaintext only. No links or markdown.</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="edit-form-row">
|
||||||
|
<div class="pt-input-ns">Project links:</div>
|
||||||
|
<div>
|
||||||
|
<textarea class="links" name="links" id="links" maxlength="2048" data-max-chars="2048">
|
||||||
|
{{- .ProjectSettings.LinksText -}}
|
||||||
|
</textarea>
|
||||||
|
<div class="c--dim f7">
|
||||||
|
<div>Relevant links to put on the project page.</div>
|
||||||
|
<div>Format: url [Title] (e.g. <code>http://example.com/ Example Site</code>)</div>
|
||||||
|
<div>(1 per line, 10 max)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="edit-form-row">
|
<div class="edit-form-row">
|
||||||
<div class="pt-input-ns">Full description:</div>
|
<div class="pt-input-ns">Full description:</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -146,6 +146,7 @@ type ProjectSettings struct {
|
||||||
|
|
||||||
Blurb string
|
Blurb string
|
||||||
Description string
|
Description string
|
||||||
|
LinksText string
|
||||||
Owners []User
|
Owners []User
|
||||||
|
|
||||||
LightLogo string
|
LightLogo string
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package website
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.handmade.network/hmn/hmn/src/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ParsedLink struct {
|
||||||
|
Name string
|
||||||
|
Url string
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseLinks(text string) []ParsedLink {
|
||||||
|
lines := strings.Split(text, "\n")
|
||||||
|
res := make([]ParsedLink, 0, len(lines))
|
||||||
|
for _, line := range lines {
|
||||||
|
linkParts := strings.SplitN(line, " ", 2)
|
||||||
|
url := strings.TrimSpace(linkParts[0])
|
||||||
|
name := ""
|
||||||
|
if len(linkParts) > 1 {
|
||||||
|
name = strings.TrimSpace(linkParts[1])
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
res = append(res, ParsedLink{Name: name, Url: url})
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func LinksToText(links []interface{}) string {
|
||||||
|
linksText := ""
|
||||||
|
for _, l := range links {
|
||||||
|
link := l.(*models.Link)
|
||||||
|
linksText += fmt.Sprintf("%s %s\n", link.URL, link.Name)
|
||||||
|
}
|
||||||
|
return linksText
|
||||||
|
}
|
|
@ -496,6 +496,24 @@ func ProjectEdit(c *RequestContext) ResponseData {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, err)
|
return c.ErrorResponse(http.StatusInternalServerError, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.Perf.StartBlock("SQL", "Fetching project links")
|
||||||
|
projectLinkResult, err := db.Query(c.Context(), c.Conn, models.Link{},
|
||||||
|
`
|
||||||
|
SELECT $columns
|
||||||
|
FROM
|
||||||
|
handmade_links as link
|
||||||
|
WHERE
|
||||||
|
link.project_id = $1
|
||||||
|
ORDER BY link.ordering ASC
|
||||||
|
`,
|
||||||
|
p.Project.ID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch project links"))
|
||||||
|
}
|
||||||
|
c.Perf.EndBlock()
|
||||||
|
|
||||||
projectSettings := templates.ProjectToProjectSettings(
|
projectSettings := templates.ProjectToProjectSettings(
|
||||||
&p.Project,
|
&p.Project,
|
||||||
p.Owners,
|
p.Owners,
|
||||||
|
@ -504,6 +522,8 @@ func ProjectEdit(c *RequestContext) ResponseData {
|
||||||
c.Theme,
|
c.Theme,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
projectSettings.LinksText = LinksToText(projectLinkResult)
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("project_edit.html", ProjectEditData{
|
res.MustWriteTemplate("project_edit.html", ProjectEditData{
|
||||||
BaseData: getBaseDataAutocrumb(c, "Edit Project"),
|
BaseData: getBaseDataAutocrumb(c, "Edit Project"),
|
||||||
|
@ -558,6 +578,7 @@ type ProjectPayload struct {
|
||||||
ProjectID int
|
ProjectID int
|
||||||
Name string
|
Name string
|
||||||
Blurb string
|
Blurb string
|
||||||
|
Links []ParsedLink
|
||||||
Description string
|
Description string
|
||||||
ParsedDescription string
|
ParsedDescription string
|
||||||
Lifecycle models.ProjectLifecycle
|
Lifecycle models.ProjectLifecycle
|
||||||
|
@ -600,6 +621,7 @@ func ParseProjectEditForm(c *RequestContext) ProjectEditFormResult {
|
||||||
res.RejectionReason = "Projects must have a short description"
|
res.RejectionReason = "Projects must have a short description"
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
links := ParseLinks(c.Req.Form.Get("links"))
|
||||||
description := c.Req.Form.Get("description")
|
description := c.Req.Form.Get("description")
|
||||||
parsedDescription := parsing.ParseMarkdown(description, parsing.ForumRealMarkdown)
|
parsedDescription := parsing.ParseMarkdown(description, parsing.ForumRealMarkdown)
|
||||||
|
|
||||||
|
@ -650,6 +672,7 @@ func ParseProjectEditForm(c *RequestContext) ProjectEditFormResult {
|
||||||
res.Payload = ProjectPayload{
|
res.Payload = ProjectPayload{
|
||||||
Name: projectName,
|
Name: projectName,
|
||||||
Blurb: shortDesc,
|
Blurb: shortDesc,
|
||||||
|
Links: links,
|
||||||
Description: description,
|
Description: description,
|
||||||
ParsedDescription: parsedDescription,
|
ParsedDescription: parsedDescription,
|
||||||
Lifecycle: lifecycle,
|
Lifecycle: lifecycle,
|
||||||
|
@ -714,28 +737,23 @@ func updateProject(ctx context.Context, tx pgx.Tx, user *models.User, payload *P
|
||||||
payload.OwnerUsernames = append(payload.OwnerUsernames, selfUsername)
|
payload.OwnerUsernames = append(payload.OwnerUsernames, selfUsername)
|
||||||
}
|
}
|
||||||
|
|
||||||
var qb db.QueryBuilder
|
_, err := tx.Exec(ctx,
|
||||||
qb.Add(
|
|
||||||
`
|
`
|
||||||
UPDATE handmade_project SET
|
UPDATE handmade_project SET
|
||||||
name = $?,
|
name = $2,
|
||||||
blurb = $?,
|
blurb = $3,
|
||||||
description = $?,
|
description = $4,
|
||||||
descparsed = $?,
|
descparsed = $5,
|
||||||
lifecycle = $?
|
lifecycle = $6
|
||||||
|
WHERE id = $1
|
||||||
`,
|
`,
|
||||||
|
payload.ProjectID,
|
||||||
payload.Name,
|
payload.Name,
|
||||||
payload.Blurb,
|
payload.Blurb,
|
||||||
payload.Description,
|
payload.Description,
|
||||||
payload.ParsedDescription,
|
payload.ParsedDescription,
|
||||||
payload.Lifecycle,
|
payload.Lifecycle,
|
||||||
)
|
)
|
||||||
if user.IsStaff {
|
|
||||||
qb.Add(`, hidden = $?`, payload.Hidden)
|
|
||||||
}
|
|
||||||
qb.Add(`WHERE id = $?`, payload.ProjectID)
|
|
||||||
|
|
||||||
_, err := tx.Exec(ctx, qb.String(), qb.Args()...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return oops.New(err, "Failed to update project")
|
return oops.New(err, "Failed to update project")
|
||||||
}
|
}
|
||||||
|
@ -748,7 +766,8 @@ func updateProject(ctx context.Context, tx pgx.Tx, user *models.User, payload *P
|
||||||
UPDATE handmade_project SET
|
UPDATE handmade_project SET
|
||||||
slug = $2,
|
slug = $2,
|
||||||
featured = $3,
|
featured = $3,
|
||||||
personal = $4
|
personal = $4,
|
||||||
|
hidden = $5
|
||||||
WHERE
|
WHERE
|
||||||
id = $1
|
id = $1
|
||||||
`,
|
`,
|
||||||
|
@ -756,6 +775,7 @@ func updateProject(ctx context.Context, tx pgx.Tx, user *models.User, payload *P
|
||||||
payload.Slug,
|
payload.Slug,
|
||||||
payload.Featured,
|
payload.Featured,
|
||||||
payload.Personal,
|
payload.Personal,
|
||||||
|
payload.Hidden,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return oops.New(err, "Failed to update project with admin fields")
|
return oops.New(err, "Failed to update project with admin fields")
|
||||||
|
@ -835,6 +855,26 @@ func updateProject(ctx context.Context, tx pgx.Tx, user *models.User, payload *P
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = tx.Exec(ctx, `DELETE FROM handmade_links WHERE project_id = $1`, payload.ProjectID)
|
||||||
|
if err != nil {
|
||||||
|
return oops.New(err, "Failed to delete project links")
|
||||||
|
}
|
||||||
|
for i, link := range payload.Links {
|
||||||
|
_, err = tx.Exec(ctx,
|
||||||
|
`
|
||||||
|
INSERT INTO handmade_links (name, url, ordering, project_id)
|
||||||
|
VALUES ($1, $2, $3, $4)
|
||||||
|
`,
|
||||||
|
link.Name,
|
||||||
|
link.Url,
|
||||||
|
i,
|
||||||
|
payload.ProjectID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return oops.New(err, "Failed to insert new project link")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -235,11 +235,7 @@ func UserSettings(c *RequestContext) ResponseData {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user links"))
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user links"))
|
||||||
}
|
}
|
||||||
|
|
||||||
linksText := ""
|
linksText := LinksToText(links)
|
||||||
for _, ilink := range links {
|
|
||||||
link := ilink.(*models.Link)
|
|
||||||
linksText += fmt.Sprintf("%s %s\n", link.URL, link.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
var tduser *templates.DiscordUser
|
var tduser *templates.DiscordUser
|
||||||
var numUnsavedMessages int
|
var numUnsavedMessages int
|
||||||
|
@ -365,31 +361,19 @@ func UserSettingsSave(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
// Process links
|
// Process links
|
||||||
linksText := form.Get("links")
|
linksText := form.Get("links")
|
||||||
links := strings.Split(linksText, "\n")
|
links := ParseLinks(linksText)
|
||||||
_, err = tx.Exec(c.Context(), `DELETE FROM handmade_links WHERE user_id = $1`, c.CurrentUser.ID)
|
_, err = tx.Exec(c.Context(), `DELETE FROM handmade_links WHERE user_id = $1`, c.CurrentUser.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Warn().Err(err).Msg("failed to delete old links")
|
c.Logger.Warn().Err(err).Msg("failed to delete old links")
|
||||||
} else {
|
} else {
|
||||||
for i, link := range links {
|
for i, link := range links {
|
||||||
link = strings.TrimSpace(link)
|
|
||||||
linkParts := strings.SplitN(link, " ", 2)
|
|
||||||
url := strings.TrimSpace(linkParts[0])
|
|
||||||
name := ""
|
|
||||||
if len(linkParts) > 1 {
|
|
||||||
name = strings.TrimSpace(linkParts[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := tx.Exec(c.Context(),
|
_, err := tx.Exec(c.Context(),
|
||||||
`
|
`
|
||||||
INSERT INTO handmade_links (name, url, ordering, user_id)
|
INSERT INTO handmade_links (name, url, ordering, user_id)
|
||||||
VALUES ($1, $2, $3, $4)
|
VALUES ($1, $2, $3, $4)
|
||||||
`,
|
`,
|
||||||
name,
|
link.Name,
|
||||||
url,
|
link.Url,
|
||||||
i,
|
i,
|
||||||
c.CurrentUser.ID,
|
c.CurrentUser.ID,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue