Merge branch 'stable'
This commit is contained in:
commit
a6d31d150c
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,6 @@ package backend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/auth"
|
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/auth"
|
||||||
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/bot"
|
|
||||||
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/member"
|
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/member"
|
||||||
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/meta"
|
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/meta"
|
||||||
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/mod"
|
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/mod"
|
||||||
|
@ -21,7 +20,6 @@ func mountRoutes(s *server.Server) {
|
||||||
auth.Mount(s, r)
|
auth.Mount(s, r)
|
||||||
user.Mount(s, r)
|
user.Mount(s, r)
|
||||||
member.Mount(s, r)
|
member.Mount(s, r)
|
||||||
bot.Mount(s, r)
|
|
||||||
meta.Mount(s, r)
|
meta.Mount(s, r)
|
||||||
mod.Mount(s, r)
|
mod.Mount(s, r)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,183 +0,0 @@
|
||||||
package bot
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ed25519"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"codeberg.org/pronounscc/pronouns.cc/backend/db"
|
|
||||||
"codeberg.org/pronounscc/pronouns.cc/backend/log"
|
|
||||||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
"github.com/go-chi/chi/v5"
|
|
||||||
"github.com/go-chi/render"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Bot struct {
|
|
||||||
*server.Server
|
|
||||||
|
|
||||||
publicKey ed25519.PublicKey
|
|
||||||
baseURL string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bot *Bot) UserAvatarURL(u db.User) string {
|
|
||||||
if u.Avatar == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return bot.baseURL + "/media/users/" + u.ID.String() + "/" + *u.Avatar + ".webp"
|
|
||||||
}
|
|
||||||
|
|
||||||
func Mount(srv *server.Server, r chi.Router) {
|
|
||||||
publicKey, err := hex.DecodeString(os.Getenv("DISCORD_PUBLIC_KEY"))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
b := &Bot{
|
|
||||||
Server: srv,
|
|
||||||
publicKey: publicKey,
|
|
||||||
baseURL: os.Getenv("BASE_URL"),
|
|
||||||
}
|
|
||||||
|
|
||||||
r.HandleFunc("/interactions", b.handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bot *Bot) handle(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if !discordgo.VerifyInteraction(r, bot.publicKey) {
|
|
||||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var ev *discordgo.InteractionCreate
|
|
||||||
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&ev); err != nil {
|
|
||||||
http.Error(w, "Bad Request", http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// we can always respond to ping with pong
|
|
||||||
if ev.Type == discordgo.InteractionPing {
|
|
||||||
log.Debug("received ping interaction")
|
|
||||||
render.JSON(w, r, discordgo.InteractionResponse{
|
|
||||||
Type: discordgo.InteractionResponsePong,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if ev.Type != discordgo.InteractionApplicationCommand {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data := ev.ApplicationCommandData()
|
|
||||||
|
|
||||||
switch data.Name {
|
|
||||||
case "Show user's pronouns":
|
|
||||||
bot.userPronouns(w, r, ev)
|
|
||||||
case "Show author's pronouns":
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bot *Bot) userPronouns(w http.ResponseWriter, r *http.Request, ev *discordgo.InteractionCreate) {
|
|
||||||
ctx := r.Context()
|
|
||||||
|
|
||||||
var du *discordgo.User
|
|
||||||
for _, user := range ev.ApplicationCommandData().Resolved.Users {
|
|
||||||
du = user
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if du == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
u, err := bot.DB.DiscordUser(ctx, du.ID)
|
|
||||||
if err != nil {
|
|
||||||
if err == db.ErrUserNotFound {
|
|
||||||
respond(w, r, &discordgo.MessageEmbed{
|
|
||||||
Description: du.String() + " does not have any pronouns set.",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Errorf("getting discord user: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
avatarURL := du.AvatarURL("")
|
|
||||||
if url := bot.UserAvatarURL(u); url != "" {
|
|
||||||
avatarURL = url
|
|
||||||
}
|
|
||||||
name := u.Username
|
|
||||||
if u.DisplayName != nil {
|
|
||||||
name = fmt.Sprintf("%s (%s)", *u.DisplayName, u.Username)
|
|
||||||
}
|
|
||||||
url := bot.baseURL
|
|
||||||
if url != "" {
|
|
||||||
url += "/@" + u.Username
|
|
||||||
}
|
|
||||||
|
|
||||||
e := &discordgo.MessageEmbed{
|
|
||||||
Author: &discordgo.MessageEmbedAuthor{
|
|
||||||
Name: name,
|
|
||||||
IconURL: avatarURL,
|
|
||||||
URL: url,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if u.Bio != nil {
|
|
||||||
e.Fields = append(e.Fields, &discordgo.MessageEmbedField{
|
|
||||||
Name: "Bio",
|
|
||||||
Value: *u.Bio,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fields, err := bot.DB.UserFields(ctx, u.ID)
|
|
||||||
if err != nil {
|
|
||||||
respond(w, r, e)
|
|
||||||
|
|
||||||
log.Errorf("getting user fields: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, field := range fields {
|
|
||||||
var favs []db.FieldEntry
|
|
||||||
|
|
||||||
for _, e := range field.Entries {
|
|
||||||
if e.Status == "favourite" {
|
|
||||||
favs = append(favs, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(favs) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var value string
|
|
||||||
for _, fav := range favs {
|
|
||||||
if len(fav.Value) > 500 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
value += fav.Value + "\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Fields = append(e.Fields, &discordgo.MessageEmbedField{
|
|
||||||
Name: field.Name,
|
|
||||||
Value: value,
|
|
||||||
Inline: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
respond(w, r, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func respond(w http.ResponseWriter, r *http.Request, embeds ...*discordgo.MessageEmbed) {
|
|
||||||
render.JSON(w, r, discordgo.InteractionResponse{
|
|
||||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
|
||||||
Data: &discordgo.InteractionResponseData{
|
|
||||||
Embeds: embeds,
|
|
||||||
Flags: discordgo.MessageFlagsEphemeral,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -16,26 +16,22 @@ writeFileSync("src/icons.ts", `const icons = ${output};\nexport default icons;`)
|
||||||
const goCode1 = `// Generated code. DO NOT EDIT
|
const goCode1 = `// Generated code. DO NOT EDIT
|
||||||
package icons
|
package icons
|
||||||
|
|
||||||
var icons = [...]string{
|
var icons = map[string]struct{}{
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const goCode2 = `}
|
const goCode2 = `}
|
||||||
|
|
||||||
// IsValid returns true if the input is the name of a Bootstrap icon.
|
// IsValid returns true if the input is the name of a Bootstrap icon.
|
||||||
func IsValid(name string) bool {
|
func IsValid(name string) bool {
|
||||||
for i := range icons {
|
_, ok := icons[name]
|
||||||
if icons[i] == name {
|
return ok
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
let goOutput = goCode1;
|
let goOutput = goCode1;
|
||||||
|
|
||||||
keys.forEach((element) => {
|
keys.forEach((element) => {
|
||||||
goOutput += ` "${element}",\n`;
|
goOutput += ` "${element}": {},\n`;
|
||||||
});
|
});
|
||||||
|
|
||||||
goOutput += goCode2;
|
goOutput += goCode2;
|
||||||
|
|
Loading…
Reference in New Issue