Compare commits

...

5 Commits

Author SHA1 Message Date
Asaf Gartner f8e7779b7d Fixed discord linking issue 2021-12-21 08:14:51 +02:00
Asaf Gartner 321089ea8e Fixed forum editor file upload issue 2021-12-21 07:13:02 +02:00
Asaf Gartner 88776cbb72 Fixed user profile url double-escaping 2021-12-21 06:24:05 +02:00
Asaf Gartner 12eb172f98 Log out user after setting status to 'banned' 2021-12-21 06:07:55 +02:00
Asaf Gartner 83ef51374d Added admin script to upload project logos to S3 2021-12-21 06:04:20 +02:00
7 changed files with 150 additions and 15 deletions

View File

@ -1,16 +1,23 @@
package admintools
import (
"bytes"
"context"
"errors"
"fmt"
"image"
"net/http"
"os"
"path"
"strconv"
"strings"
"time"
"git.handmade.network/hmn/hmn/src/assets"
"git.handmade.network/hmn/hmn/src/auth"
"git.handmade.network/hmn/hmn/src/db"
"git.handmade.network/hmn/hmn/src/email"
"git.handmade.network/hmn/hmn/src/hmndata"
"git.handmade.network/hmn/hmn/src/logging"
"git.handmade.network/hmn/hmn/src/models"
"git.handmade.network/hmn/hmn/src/oops"
@ -353,5 +360,135 @@ func init() {
moveThreadsToSubforumCommand.MarkFlagRequired("subforum_slug")
adminCommand.AddCommand(moveThreadsToSubforumCommand)
uploadProjectLogos := &cobra.Command{
Use: "uploadprojectlogos",
Short: "Uploads project imagefiles to S3 and replaces them with assets",
Run: func(cmd *cobra.Command, args []string) {
ctx := context.Background()
conn := db.NewConnPool(1, 1)
defer conn.Close()
allProjects, err := db.Query(ctx, conn, models.Project{}, `SELECT $columns FROM handmade_project`)
if err != nil {
panic(oops.New(err, "Failed to fetch projects from db"))
}
var fixupProjects []*models.Project
numImages := 0
for _, project := range allProjects {
p := project.(*models.Project)
if p.LogoLight != "" || p.LogoDark != "" {
fixupProjects = append(fixupProjects, p)
}
if p.LogoLight != "" {
numImages += 1
}
if p.LogoDark != "" {
numImages += 1
}
}
fmt.Printf("%d images to upload\n", numImages)
uploadImage := func(ctx context.Context, conn db.ConnOrTx, filepath string, owner *models.User) *models.Asset {
filepath = "./public/media/" + filepath
contents, err := os.ReadFile(filepath)
if err != nil {
panic(oops.New(err, fmt.Sprintf("Failed to read file: %s", filepath)))
}
width := 0
height := 0
fileExtensionOverrides := []string{".svg"}
fileExt := strings.ToLower(path.Ext(filepath))
tryDecode := true
for _, ext := range fileExtensionOverrides {
if fileExt == ext {
tryDecode = false
}
}
if tryDecode {
config, _, err := image.DecodeConfig(bytes.NewReader(contents))
if err != nil {
panic(oops.New(err, fmt.Sprintf("Failed to decode file: %s", filepath)))
}
width = config.Width
height = config.Height
}
mime := http.DetectContentType(contents)
filename := path.Base(filepath)
asset, err := assets.Create(ctx, conn, assets.CreateInput{
Content: contents,
Filename: filename,
ContentType: mime,
UploaderID: &owner.ID,
Width: width,
Height: height,
})
if err != nil {
panic(oops.New(err, "Failed to create asset"))
}
return asset
}
for _, p := range fixupProjects {
owners, err := hmndata.FetchProjectOwners(ctx, conn, p.ID)
if err != nil {
panic(oops.New(err, "Failed to fetch project owners"))
}
if len(owners) == 0 {
fmt.Printf("PROBLEM!! Project %d (%s) doesn't have owners!!\n", p.ID, p.Name)
continue
}
if p.LogoLight != "" {
lightAsset := uploadImage(ctx, conn, p.LogoLight, owners[0])
_, err := conn.Exec(ctx,
`
UPDATE handmade_project
SET
logolight_asset_id = $2,
logolight = NULL
WHERE
id = $1
`,
p.ID,
lightAsset.ID,
)
if err != nil {
panic(oops.New(err, "Failed to update project"))
}
numImages -= 1
fmt.Printf(".")
}
if p.LogoDark != "" {
darkAsset := uploadImage(ctx, conn, p.LogoDark, owners[0])
_, err := conn.Exec(ctx,
`
UPDATE handmade_project
SET
logodark_asset_id = $2,
logodark = NULL
WHERE
id = $1
`,
p.ID,
darkAsset.ID,
)
if err != nil {
panic(oops.New(err, "Failed to update project"))
}
numImages -= 1
fmt.Printf(".")
}
}
fmt.Printf("\nDone! %d images not patched for some reason.\n\n", numImages)
},
}
adminCommand.AddCommand(uploadProjectLogos)
addProjectCommands(adminCommand)
}

View File

@ -13,7 +13,6 @@ import (
"net/textproto"
"net/url"
"strconv"
"strings"
"git.handmade.network/hmn/hmn/src/config"
"git.handmade.network/hmn/hmn/src/hmnurl"
@ -301,16 +300,7 @@ func ExchangeOAuthCode(ctx context.Context, code, redirectURI string) (*OAuthCod
bodyStr := body.Encode()
res, err := doWithRateLimiting(ctx, name, func(ctx context.Context) *http.Request {
req, err := http.NewRequestWithContext(
ctx,
http.MethodPost,
"https://discord.com/api/oauth2/token",
strings.NewReader(bodyStr),
)
if err != nil {
panic(err)
}
req.Header.Add("User-Agent", UserAgent)
req := makeRequest(ctx, http.MethodPost, "/oauth2/token", []byte(bodyStr))
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
return req
@ -613,7 +603,7 @@ func GetAuthorizeUrl(state string) string {
params.Set("scope", "identify")
params.Set("state", state)
params.Set("redirect_uri", hmnurl.BuildDiscordOAuthCallback())
return fmt.Sprintf("https://discord.com/api/oauth2/authorize?%s", params.Encode())
return fmt.Sprintf("%s?%s", buildUrl("/oauth2/authorize"), params.Encode())
}
type FileUpload struct {

View File

@ -189,7 +189,7 @@ func BuildUserProfile(username string) string {
if len(username) == 0 {
panic(oops.New(nil, "Username must not be blank"))
}
return Url("/m/"+url.PathEscape(username), nil)
return Url("/m/"+username, nil)
}
var RegexUserSettings = regexp.MustCompile(`^/settings$`)

View File

@ -116,7 +116,7 @@
});
// Do live Markdown previews
initLiveMarkdown({ inputEl: textField, previewEl: preview });
let doMarkdown = initLiveMarkdown({ inputEl: textField, previewEl: preview });
/*
/ Asset upload

View File

@ -102,5 +102,7 @@
doMarkdown();
inputEl.addEventListener('input', () => doMarkdown());
return doMarkdown;
}
</script>

View File

@ -227,7 +227,7 @@
});
projectForm.addEventListener('submit', () => clearDescription());
initLiveMarkdown({ inputEl: description, previewEl: descPreview });
let doMarkdown = initLiveMarkdown({ inputEl: description, previewEl: descPreview });
//////////////////////
// Owner management //

View File

@ -481,6 +481,12 @@ func UserProfileAdminSetStatus(c *RequestContext) ResponseData {
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update user status"))
}
if desiredStatus == models.UserStatusBanned {
err = auth.DeleteSessionForUser(c.Context(), c.Conn, c.Req.Form.Get("username"))
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to log out user"))
}
}
res := c.Redirect(hmnurl.BuildUserProfile(c.Req.Form.Get("username")), http.StatusSeeOther)
res.AddFutureNotice("success", "Successfully set status")
return res