Groupme -> Matrix Images
This commit is contained in:
parent
7d6847fd3b
commit
4e2c73efe3
@ -25,6 +25,9 @@
|
||||
* [x] Plain text
|
||||
* [ ] Formatted messages
|
||||
* [ ] Media/files
|
||||
* [x] Images
|
||||
* [ ] Videos
|
||||
* [ ] Other Files
|
||||
* [ ] Location messages
|
||||
* [ ] Contact messages
|
||||
* [ ] Replies
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/karmanyaahm/groupme"
|
||||
)
|
||||
@ -31,3 +33,26 @@ func (m *Message) Value() (driver.Value, error) {
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
//DownloadImage helper function to download image from groupme;
|
||||
// append .large/.preview/.avatar to get various sizes
|
||||
func DownloadImage(URL string) (bytes *[]byte, mime string, err error) {
|
||||
//TODO check its actually groupme?
|
||||
response, err := http.Get(URL)
|
||||
if err != nil {
|
||||
return nil, "", errors.New("Failed to download avatar: " + err.Error())
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
image, err := ioutil.ReadAll(response.Body)
|
||||
bytes = &image
|
||||
if err != nil {
|
||||
return nil, "", errors.New("Failed to read downloaded image:" + err.Error())
|
||||
}
|
||||
|
||||
mime = response.Header.Get("Content-Type")
|
||||
if len(mime) == 0 {
|
||||
mime = http.DetectContentType(image)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
388
portal.go
388
portal.go
@ -30,6 +30,7 @@ import (
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@ -1258,6 +1259,219 @@ func (portal *Portal) sendMessageDirect(intent *appservice.IntentAPI, eventType
|
||||
}
|
||||
}
|
||||
|
||||
func (portal *Portal) handleAttachment(intent *appservice.IntentAPI, attachment *groupme.Attachment, ts int64) error {
|
||||
switch attachment.Type {
|
||||
case "image":
|
||||
imgData, mime, err := groupmeExt.DownloadImage(attachment.URL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load media info: %w", err)
|
||||
}
|
||||
|
||||
var width, height int
|
||||
if strings.HasPrefix(mime, "image/") {
|
||||
cfg, _, _ := image.DecodeConfig(bytes.NewReader(*imgData))
|
||||
width, height = cfg.Width, cfg.Height
|
||||
}
|
||||
data, uploadMimeType, file := portal.encryptFile(*imgData, mime)
|
||||
|
||||
uploaded, err := portal.uploadWithRetry(intent, data, uploadMimeType, MediaUploadRetries)
|
||||
if err != nil {
|
||||
if errors.Is(err, mautrix.MTooLarge) {
|
||||
return errors.New("homeserver rejected too large file")
|
||||
} else if httpErr := err.(mautrix.HTTPError); httpErr.IsStatus(413) {
|
||||
return errors.New("proxy rejected too large file")
|
||||
} else {
|
||||
return fmt.Errorf("failed to upload media: %w", err)
|
||||
}
|
||||
}
|
||||
attachmentUrl, _ := url.Parse(attachment.URL)
|
||||
urlParts := strings.Split(attachmentUrl.Path, ".")
|
||||
var fname1, fname2 string
|
||||
if len(urlParts) == 2 {
|
||||
fname1, fname2 = urlParts[1], urlParts[0]
|
||||
} else if len(urlParts) > 2 {
|
||||
fname1, fname2 = urlParts[2], urlParts[1]
|
||||
} //TODO abstract groupme url parsing in groupmeExt
|
||||
fname := fmt.Sprintf("%s.%s", fname1, fname2)
|
||||
|
||||
content := &event.MessageEventContent{
|
||||
Body: fname,
|
||||
File: file,
|
||||
Info: &event.FileInfo{
|
||||
Size: len(data),
|
||||
MimeType: mime,
|
||||
Width: width,
|
||||
Height: height,
|
||||
//Duration: int(msg.length),
|
||||
},
|
||||
}
|
||||
if content.File != nil {
|
||||
content.File.URL = uploaded.ContentURI.CUString()
|
||||
} else {
|
||||
content.URL = uploaded.ContentURI.CUString()
|
||||
}
|
||||
//TODO thumbnail since groupme supports it anyway
|
||||
content.MsgType = event.MsgImage
|
||||
_, _ = intent.UserTyping(portal.MXID, false, 0)
|
||||
|
||||
eventType := event.EventMessage
|
||||
|
||||
_, err = portal.sendMessage(intent, eventType, content, ts)
|
||||
if err != nil {
|
||||
portal.log.Errorfln("Failed to handle message %s: %v", "TODOID", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
default:
|
||||
portal.log.Warnln("Unable to handle groupme attachment type", attachment.Type)
|
||||
return fmt.Errorf("Unable to handle groupme attachment type %s", attachment.Type)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (portal *Portal) HandleMediaMessage(source *User, msg mediaMessage) {
|
||||
// intent := portal.startHandling(source, msg.info)
|
||||
// if intent == nil {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// data, err := msg.download()
|
||||
// if err == whatsapp.ErrMediaDownloadFailedWith404 || err == whatsapp.ErrMediaDownloadFailedWith410 {
|
||||
// portal.log.Warnfln("Failed to download media for %s: %v. Calling LoadMediaInfo and retrying download...", msg.info.Id, err)
|
||||
// _, err = source.Conn.LoadMediaInfo(msg.info.RemoteJid, msg.info.Id, msg.info.FromMe)
|
||||
// if err != nil {
|
||||
// portal.sendMediaBridgeFailure(source, intent, msg.info, fmt.Errorf("failed to load media info: %w", err))
|
||||
// return
|
||||
// }
|
||||
// data, err = msg.download()
|
||||
// }
|
||||
// if err == whatsapp.ErrNoURLPresent {
|
||||
// portal.log.Debugfln("No URL present error for media message %s, ignoring...", msg.info.Id)
|
||||
// return
|
||||
// } else if err != nil {
|
||||
// portal.sendMediaBridgeFailure(source, intent, msg.info, err)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// var width, height int
|
||||
// if strings.HasPrefix(msg.mimeType, "image/") {
|
||||
// cfg, _, _ := image.DecodeConfig(bytes.NewReader(data))
|
||||
// width, height = cfg.Width, cfg.Height
|
||||
// }
|
||||
//
|
||||
// data, uploadMimeType, file := portal.encryptFile(data, msg.mimeType)
|
||||
//
|
||||
// uploaded, err := portal.uploadWithRetry(intent, data, uploadMimeType, MediaUploadRetries)
|
||||
// if err != nil {
|
||||
// if errors.Is(err, mautrix.MTooLarge) {
|
||||
// portal.sendMediaBridgeFailure(source, intent, msg.info, errors.New("homeserver rejected too large file"))
|
||||
// } else if httpErr := err.(mautrix.HTTPError); httpErr.IsStatus(413) {
|
||||
// portal.sendMediaBridgeFailure(source, intent, msg.info, errors.New("proxy rejected too large file"))
|
||||
// } else {
|
||||
// portal.sendMediaBridgeFailure(source, intent, msg.info, fmt.Errorf("failed to upload media: %w", err))
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if msg.fileName == "" {
|
||||
// mimeClass := strings.Split(msg.mimeType, "/")[0]
|
||||
// switch mimeClass {
|
||||
// case "application":
|
||||
// msg.fileName = "file"
|
||||
// default:
|
||||
// msg.fileName = mimeClass
|
||||
// }
|
||||
//
|
||||
// exts, _ := mime.ExtensionsByType(msg.mimeType)
|
||||
// if exts != nil && len(exts) > 0 {
|
||||
// msg.fileName += exts[0]
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// content := &event.MessageEventContent{
|
||||
// Body: msg.fileName,
|
||||
// File: file,
|
||||
// Info: &event.FileInfo{
|
||||
// Size: len(data),
|
||||
// MimeType: msg.mimeType,
|
||||
// Width: width,
|
||||
// Height: height,
|
||||
// Duration: int(msg.length),
|
||||
// },
|
||||
// }
|
||||
// if content.File != nil {
|
||||
// content.File.URL = uploaded.ContentURI.CUString()
|
||||
// } else {
|
||||
// content.URL = uploaded.ContentURI.CUString()
|
||||
// }
|
||||
// portal.SetReply(content, msg.context)
|
||||
//
|
||||
// if msg.thumbnail != nil && portal.bridge.Config.Bridge.WhatsappThumbnail {
|
||||
// thumbnailMime := http.DetectContentType(msg.thumbnail)
|
||||
// thumbnailCfg, _, _ := image.DecodeConfig(bytes.NewReader(msg.thumbnail))
|
||||
// thumbnailSize := len(msg.thumbnail)
|
||||
// thumbnail, thumbnailUploadMime, thumbnailFile := portal.encryptFile(msg.thumbnail, thumbnailMime)
|
||||
// uploadedThumbnail, err := intent.UploadBytes(thumbnail, thumbnailUploadMime)
|
||||
// if err != nil {
|
||||
// portal.log.Warnfln("Failed to upload thumbnail for %s: %v", msg.info.Id, err)
|
||||
// } else if uploadedThumbnail != nil {
|
||||
// if thumbnailFile != nil {
|
||||
// thumbnailFile.URL = uploadedThumbnail.ContentURI.CUString()
|
||||
// content.Info.ThumbnailFile = thumbnailFile
|
||||
// } else {
|
||||
// content.Info.ThumbnailURL = uploadedThumbnail.ContentURI.CUString()
|
||||
// }
|
||||
// content.Info.ThumbnailInfo = &event.FileInfo{
|
||||
// Size: thumbnailSize,
|
||||
// Width: thumbnailCfg.Width,
|
||||
// Height: thumbnailCfg.Height,
|
||||
// MimeType: thumbnailMime,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// switch strings.ToLower(strings.Split(msg.mimeType, "/")[0]) {
|
||||
// case "image":
|
||||
// if !msg.sendAsSticker {
|
||||
// content.MsgType = event.MsgImage
|
||||
// }
|
||||
// case "video":
|
||||
// content.MsgType = event.MsgVideo
|
||||
// case "audio":
|
||||
// content.MsgType = event.MsgAudio
|
||||
// default:
|
||||
// content.MsgType = event.MsgFile
|
||||
// }
|
||||
//
|
||||
// _, _ = intent.UserTyping(portal.MXID, false, 0)
|
||||
// ts := int64(msg.info.Timestamp * 1000)
|
||||
// eventType := event.EventMessage
|
||||
// if msg.sendAsSticker {
|
||||
// eventType = event.EventSticker
|
||||
// }
|
||||
// resp, err := portal.sendMessage(intent, eventType, content, ts)
|
||||
// if err != nil {
|
||||
// portal.log.Errorfln("Failed to handle message %s: %v", msg.info.Id, err)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if len(msg.caption) > 0 {
|
||||
// captionContent := &event.MessageEventContent{
|
||||
// Body: msg.caption,
|
||||
// MsgType: event.MsgNotice,
|
||||
// }
|
||||
//
|
||||
// portal.bridge.Formatter.ParseWhatsApp(captionContent, msg.context.MentionedJID)
|
||||
//
|
||||
// _, err := portal.sendMessage(intent, event.EventMessage, captionContent, ts)
|
||||
// if err != nil {
|
||||
// portal.log.Warnfln("Failed to handle caption of message %s: %v", msg.info.Id, err)
|
||||
// }
|
||||
// // TODO store caption mxid?
|
||||
// }
|
||||
//
|
||||
// portal.finishHandling(source, msg.info.Source, resp.EventID)
|
||||
}
|
||||
|
||||
func (portal *Portal) HandleTextMessage(source *User, message *groupme.Message) {
|
||||
intent := portal.startHandling(source, message)
|
||||
if intent == nil {
|
||||
@ -1268,6 +1482,12 @@ func (portal *Portal) HandleTextMessage(source *User, message *groupme.Message)
|
||||
Body: message.Text,
|
||||
MsgType: event.MsgText,
|
||||
}
|
||||
for _, a := range message.Attachments {
|
||||
err := portal.handleAttachment(intent, a, message.CreatedAt.ToTime().Unix())
|
||||
if err != nil {
|
||||
portal.sendMediaBridgeFailure(source, intent, *message, err)
|
||||
}
|
||||
}
|
||||
|
||||
// portal.bridge.Formatter.ParseWhatsApp(content, message.ContextInfo.MentionedJID)
|
||||
// portal.SetReply(content, message.ContextInfo)
|
||||
@ -1384,18 +1604,18 @@ func (portal *Portal) HandleTextMessage(source *User, message *groupme.Message)
|
||||
// portal.finishHandling(source, message.Info.Source, resp.EventID)
|
||||
//}
|
||||
|
||||
//func (portal *Portal) sendMediaBridgeFailure(source *User, intent *appservice.IntentAPI, info whatsapp.MessageInfo, bridgeErr error) {
|
||||
// portal.log.Errorfln("Failed to bridge media for %s: %v", info.Id, bridgeErr)
|
||||
// resp, err := portal.sendMessage(intent, event.EventMessage, &event.MessageEventContent{
|
||||
// MsgType: event.MsgNotice,
|
||||
// Body: "Failed to bridge media",
|
||||
// }, int64(info.Timestamp*1000))
|
||||
// if err != nil {
|
||||
// portal.log.Errorfln("Failed to send media download error message for %s: %v", info.Id, err)
|
||||
// } else {
|
||||
// portal.finishHandling(source, info.Source, resp.EventID)
|
||||
// }
|
||||
//}
|
||||
func (portal *Portal) sendMediaBridgeFailure(source *User, intent *appservice.IntentAPI, message groupme.Message, bridgeErr error) {
|
||||
portal.log.Errorfln("Failed to bridge media for %s: %v", message.UserID.String(), bridgeErr)
|
||||
resp, err := portal.sendMessage(intent, event.EventMessage, &event.MessageEventContent{
|
||||
MsgType: event.MsgNotice,
|
||||
Body: "Failed to bridge media",
|
||||
}, int64(message.CreatedAt.ToTime().Unix()*1000))
|
||||
if err != nil {
|
||||
portal.log.Errorfln("Failed to send media download error message for %s: %v", message.UserID.String(), err)
|
||||
} else {
|
||||
portal.finishHandling(source, &message, resp.EventID)
|
||||
}
|
||||
}
|
||||
|
||||
func (portal *Portal) encryptFile(data []byte, mimeType string) ([]byte, string, *event.EncryptedFileInfo) {
|
||||
if !portal.Encrypted {
|
||||
@ -1504,150 +1724,6 @@ func (portal *Portal) uploadWithRetry(intent *appservice.IntentAPI, data []byte,
|
||||
}
|
||||
}
|
||||
|
||||
func (portal *Portal) HandleMediaMessage(source *User, msg mediaMessage) {
|
||||
// intent := portal.startHandling(source, msg.info)
|
||||
// if intent == nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
// data, err := msg.download()
|
||||
// if err == whatsapp.ErrMediaDownloadFailedWith404 || err == whatsapp.ErrMediaDownloadFailedWith410 {
|
||||
// portal.log.Warnfln("Failed to download media for %s: %v. Calling LoadMediaInfo and retrying download...", msg.info.Id, err)
|
||||
// _, err = source.Conn.LoadMediaInfo(msg.info.RemoteJid, msg.info.Id, msg.info.FromMe)
|
||||
// if err != nil {
|
||||
// portal.sendMediaBridgeFailure(source, intent, msg.info, fmt.Errorf("failed to load media info: %w", err))
|
||||
// return
|
||||
// }
|
||||
// data, err = msg.download()
|
||||
// }
|
||||
// if err == whatsapp.ErrNoURLPresent {
|
||||
// portal.log.Debugfln("No URL present error for media message %s, ignoring...", msg.info.Id)
|
||||
// return
|
||||
// } else if err != nil {
|
||||
// portal.sendMediaBridgeFailure(source, intent, msg.info, err)
|
||||
// return
|
||||
// }
|
||||
|
||||
// var width, height int
|
||||
// if strings.HasPrefix(msg.mimeType, "image/") {
|
||||
// cfg, _, _ := image.DecodeConfig(bytes.NewReader(data))
|
||||
// width, height = cfg.Width, cfg.Height
|
||||
// }
|
||||
|
||||
// data, uploadMimeType, file := portal.encryptFile(data, msg.mimeType)
|
||||
|
||||
// uploaded, err := portal.uploadWithRetry(intent, data, uploadMimeType, MediaUploadRetries)
|
||||
// if err != nil {
|
||||
// if errors.Is(err, mautrix.MTooLarge) {
|
||||
// portal.sendMediaBridgeFailure(source, intent, msg.info, errors.New("homeserver rejected too large file"))
|
||||
// } else if httpErr := err.(mautrix.HTTPError); httpErr.IsStatus(413) {
|
||||
// portal.sendMediaBridgeFailure(source, intent, msg.info, errors.New("proxy rejected too large file"))
|
||||
// } else {
|
||||
// portal.sendMediaBridgeFailure(source, intent, msg.info, fmt.Errorf("failed to upload media: %w", err))
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
// if msg.fileName == "" {
|
||||
// mimeClass := strings.Split(msg.mimeType, "/")[0]
|
||||
// switch mimeClass {
|
||||
// case "application":
|
||||
// msg.fileName = "file"
|
||||
// default:
|
||||
// msg.fileName = mimeClass
|
||||
// }
|
||||
|
||||
// exts, _ := mime.ExtensionsByType(msg.mimeType)
|
||||
// if exts != nil && len(exts) > 0 {
|
||||
// msg.fileName += exts[0]
|
||||
// }
|
||||
// }
|
||||
|
||||
// content := &event.MessageEventContent{
|
||||
// Body: msg.fileName,
|
||||
// File: file,
|
||||
// Info: &event.FileInfo{
|
||||
// Size: len(data),
|
||||
// MimeType: msg.mimeType,
|
||||
// Width: width,
|
||||
// Height: height,
|
||||
// Duration: int(msg.length),
|
||||
// },
|
||||
// }
|
||||
// if content.File != nil {
|
||||
// content.File.URL = uploaded.ContentURI.CUString()
|
||||
// } else {
|
||||
// content.URL = uploaded.ContentURI.CUString()
|
||||
// }
|
||||
// portal.SetReply(content, msg.context)
|
||||
|
||||
// if msg.thumbnail != nil && portal.bridge.Config.Bridge.WhatsappThumbnail {
|
||||
// thumbnailMime := http.DetectContentType(msg.thumbnail)
|
||||
// thumbnailCfg, _, _ := image.DecodeConfig(bytes.NewReader(msg.thumbnail))
|
||||
// thumbnailSize := len(msg.thumbnail)
|
||||
// thumbnail, thumbnailUploadMime, thumbnailFile := portal.encryptFile(msg.thumbnail, thumbnailMime)
|
||||
// uploadedThumbnail, err := intent.UploadBytes(thumbnail, thumbnailUploadMime)
|
||||
// if err != nil {
|
||||
// portal.log.Warnfln("Failed to upload thumbnail for %s: %v", msg.info.Id, err)
|
||||
// } else if uploadedThumbnail != nil {
|
||||
// if thumbnailFile != nil {
|
||||
// thumbnailFile.URL = uploadedThumbnail.ContentURI.CUString()
|
||||
// content.Info.ThumbnailFile = thumbnailFile
|
||||
// } else {
|
||||
// content.Info.ThumbnailURL = uploadedThumbnail.ContentURI.CUString()
|
||||
// }
|
||||
// content.Info.ThumbnailInfo = &event.FileInfo{
|
||||
// Size: thumbnailSize,
|
||||
// Width: thumbnailCfg.Width,
|
||||
// Height: thumbnailCfg.Height,
|
||||
// MimeType: thumbnailMime,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// switch strings.ToLower(strings.Split(msg.mimeType, "/")[0]) {
|
||||
// case "image":
|
||||
// if !msg.sendAsSticker {
|
||||
// content.MsgType = event.MsgImage
|
||||
// }
|
||||
// case "video":
|
||||
// content.MsgType = event.MsgVideo
|
||||
// case "audio":
|
||||
// content.MsgType = event.MsgAudio
|
||||
// default:
|
||||
// content.MsgType = event.MsgFile
|
||||
// }
|
||||
|
||||
// _, _ = intent.UserTyping(portal.MXID, false, 0)
|
||||
// ts := int64(msg.info.Timestamp * 1000)
|
||||
// eventType := event.EventMessage
|
||||
// if msg.sendAsSticker {
|
||||
// eventType = event.EventSticker
|
||||
// }
|
||||
// resp, err := portal.sendMessage(intent, eventType, content, ts)
|
||||
// if err != nil {
|
||||
// portal.log.Errorfln("Failed to handle message %s: %v", msg.info.Id, err)
|
||||
// return
|
||||
// }
|
||||
|
||||
// if len(msg.caption) > 0 {
|
||||
// captionContent := &event.MessageEventContent{
|
||||
// Body: msg.caption,
|
||||
// MsgType: event.MsgNotice,
|
||||
// }
|
||||
|
||||
// portal.bridge.Formatter.ParseWhatsApp(captionContent, msg.context.MentionedJID)
|
||||
|
||||
// _, err := portal.sendMessage(intent, event.EventMessage, captionContent, ts)
|
||||
// if err != nil {
|
||||
// portal.log.Warnfln("Failed to handle caption of message %s: %v", msg.info.Id, err)
|
||||
// }
|
||||
// // TODO store caption mxid?
|
||||
// }
|
||||
|
||||
// portal.finishHandling(source, msg.info.Source, resp.EventID)
|
||||
}
|
||||
|
||||
func makeMessageID() *string {
|
||||
b := make([]byte, 10)
|
||||
rand.Read(b)
|
||||
|
20
puppet.go
20
puppet.go
@ -18,8 +18,6 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@ -30,6 +28,7 @@ import (
|
||||
"maunium.net/go/mautrix/id"
|
||||
|
||||
"github.com/karmanyaahm/matrix-groupme-go/database"
|
||||
"github.com/karmanyaahm/matrix-groupme-go/groupmeExt"
|
||||
"github.com/karmanyaahm/matrix-groupme-go/types"
|
||||
whatsappExt "github.com/karmanyaahm/matrix-groupme-go/whatsapp-ext"
|
||||
)
|
||||
@ -199,24 +198,13 @@ func (puppet *Puppet) UpdateAvatar(source *User, avatar string) bool {
|
||||
}
|
||||
|
||||
//TODO check its actually groupme?
|
||||
response, err := http.Get(avatar + ".large")
|
||||
image, mime, err := groupmeExt.DownloadImage(avatar + ".large")
|
||||
if err != nil {
|
||||
puppet.log.Warnln("Failed to download avatar:", err)
|
||||
return false
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
image, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
puppet.log.Warnln("Failed to read downloaded avatar:", err)
|
||||
puppet.log.Warnln(err)
|
||||
return false
|
||||
}
|
||||
|
||||
mime := response.Header.Get("Content-Type")
|
||||
if len(mime) == 0 {
|
||||
mime = http.DetectContentType(image)
|
||||
}
|
||||
resp, err := puppet.DefaultIntent().UploadBytes(image, mime)
|
||||
resp, err := puppet.DefaultIntent().UploadBytes(*image, mime)
|
||||
if err != nil {
|
||||
puppet.log.Warnln("Failed to upload avatar:", err)
|
||||
return false
|
||||
|
Loading…
Reference in New Issue
Block a user