Compare commits
5 Commits
6307589ee4
...
f8e7779b7d
Author | SHA1 | Date |
---|---|---|
Asaf Gartner | f8e7779b7d | |
Asaf Gartner | 321089ea8e | |
Asaf Gartner | 88776cbb72 | |
Asaf Gartner | 12eb172f98 | |
Asaf Gartner | 83ef51374d |
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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$`)
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
});
|
||||
|
||||
// Do live Markdown previews
|
||||
initLiveMarkdown({ inputEl: textField, previewEl: preview });
|
||||
let doMarkdown = initLiveMarkdown({ inputEl: textField, previewEl: preview });
|
||||
|
||||
/*
|
||||
/ Asset upload
|
||||
|
|
|
@ -102,5 +102,7 @@
|
|||
|
||||
doMarkdown();
|
||||
inputEl.addEventListener('input', () => doMarkdown());
|
||||
|
||||
return doMarkdown;
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -227,7 +227,7 @@
|
|||
});
|
||||
projectForm.addEventListener('submit', () => clearDescription());
|
||||
|
||||
initLiveMarkdown({ inputEl: description, previewEl: descPreview });
|
||||
let doMarkdown = initLiveMarkdown({ inputEl: description, previewEl: descPreview });
|
||||
|
||||
//////////////////////
|
||||
// Owner management //
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue