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>
 | 
			
		||||
				</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="pt-input-ns">Full description:</div>
 | 
			
		||||
					<div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -146,6 +146,7 @@ type ProjectSettings struct {
 | 
			
		|||
 | 
			
		||||
	Blurb       string
 | 
			
		||||
	Description string
 | 
			
		||||
	LinksText   string
 | 
			
		||||
	Owners      []User
 | 
			
		||||
 | 
			
		||||
	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 {
 | 
			
		||||
		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(
 | 
			
		||||
		&p.Project,
 | 
			
		||||
		p.Owners,
 | 
			
		||||
| 
						 | 
				
			
			@ -504,6 +522,8 @@ func ProjectEdit(c *RequestContext) ResponseData {
 | 
			
		|||
		c.Theme,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	projectSettings.LinksText = LinksToText(projectLinkResult)
 | 
			
		||||
 | 
			
		||||
	var res ResponseData
 | 
			
		||||
	res.MustWriteTemplate("project_edit.html", ProjectEditData{
 | 
			
		||||
		BaseData:        getBaseDataAutocrumb(c, "Edit Project"),
 | 
			
		||||
| 
						 | 
				
			
			@ -558,6 +578,7 @@ type ProjectPayload struct {
 | 
			
		|||
	ProjectID         int
 | 
			
		||||
	Name              string
 | 
			
		||||
	Blurb             string
 | 
			
		||||
	Links             []ParsedLink
 | 
			
		||||
	Description       string
 | 
			
		||||
	ParsedDescription string
 | 
			
		||||
	Lifecycle         models.ProjectLifecycle
 | 
			
		||||
| 
						 | 
				
			
			@ -600,6 +621,7 @@ func ParseProjectEditForm(c *RequestContext) ProjectEditFormResult {
 | 
			
		|||
		res.RejectionReason = "Projects must have a short description"
 | 
			
		||||
		return res
 | 
			
		||||
	}
 | 
			
		||||
	links := ParseLinks(c.Req.Form.Get("links"))
 | 
			
		||||
	description := c.Req.Form.Get("description")
 | 
			
		||||
	parsedDescription := parsing.ParseMarkdown(description, parsing.ForumRealMarkdown)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -650,6 +672,7 @@ func ParseProjectEditForm(c *RequestContext) ProjectEditFormResult {
 | 
			
		|||
	res.Payload = ProjectPayload{
 | 
			
		||||
		Name:              projectName,
 | 
			
		||||
		Blurb:             shortDesc,
 | 
			
		||||
		Links:             links,
 | 
			
		||||
		Description:       description,
 | 
			
		||||
		ParsedDescription: parsedDescription,
 | 
			
		||||
		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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var qb db.QueryBuilder
 | 
			
		||||
	qb.Add(
 | 
			
		||||
	_, err := tx.Exec(ctx,
 | 
			
		||||
		`
 | 
			
		||||
		UPDATE handmade_project SET
 | 
			
		||||
			name = $?,
 | 
			
		||||
			blurb = $?,
 | 
			
		||||
			description = $?,
 | 
			
		||||
			descparsed = $?,
 | 
			
		||||
			lifecycle = $?
 | 
			
		||||
			name = $2,
 | 
			
		||||
			blurb = $3,
 | 
			
		||||
			description = $4,
 | 
			
		||||
			descparsed = $5,
 | 
			
		||||
			lifecycle = $6
 | 
			
		||||
		WHERE id = $1
 | 
			
		||||
		`,
 | 
			
		||||
		payload.ProjectID,
 | 
			
		||||
		payload.Name,
 | 
			
		||||
		payload.Blurb,
 | 
			
		||||
		payload.Description,
 | 
			
		||||
		payload.ParsedDescription,
 | 
			
		||||
		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 {
 | 
			
		||||
		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
 | 
			
		||||
				slug = $2,
 | 
			
		||||
				featured = $3,
 | 
			
		||||
				personal = $4
 | 
			
		||||
				personal = $4,
 | 
			
		||||
				hidden = $5
 | 
			
		||||
			WHERE
 | 
			
		||||
				id = $1
 | 
			
		||||
			`,
 | 
			
		||||
| 
						 | 
				
			
			@ -756,6 +775,7 @@ func updateProject(ctx context.Context, tx pgx.Tx, user *models.User, payload *P
 | 
			
		|||
			payload.Slug,
 | 
			
		||||
			payload.Featured,
 | 
			
		||||
			payload.Personal,
 | 
			
		||||
			payload.Hidden,
 | 
			
		||||
		)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -235,11 +235,7 @@ func UserSettings(c *RequestContext) ResponseData {
 | 
			
		|||
		return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user links"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	linksText := ""
 | 
			
		||||
	for _, ilink := range links {
 | 
			
		||||
		link := ilink.(*models.Link)
 | 
			
		||||
		linksText += fmt.Sprintf("%s %s\n", link.URL, link.Name)
 | 
			
		||||
	}
 | 
			
		||||
	linksText := LinksToText(links)
 | 
			
		||||
 | 
			
		||||
	var tduser *templates.DiscordUser
 | 
			
		||||
	var numUnsavedMessages int
 | 
			
		||||
| 
						 | 
				
			
			@ -365,31 +361,19 @@ func UserSettingsSave(c *RequestContext) ResponseData {
 | 
			
		|||
 | 
			
		||||
	// Process 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)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.Logger.Warn().Err(err).Msg("failed to delete old links")
 | 
			
		||||
	} else {
 | 
			
		||||
		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(),
 | 
			
		||||
				`
 | 
			
		||||
				INSERT INTO handmade_links (name, url, ordering, user_id)
 | 
			
		||||
				VALUES ($1, $2, $3, $4)
 | 
			
		||||
				`,
 | 
			
		||||
				name,
 | 
			
		||||
				url,
 | 
			
		||||
				link.Name,
 | 
			
		||||
				link.Url,
 | 
			
		||||
				i,
 | 
			
		||||
				c.CurrentUser.ID,
 | 
			
		||||
			)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue