feat(GODT-2576): Forward flag support

Add routes to mark messages as forwarded.
This commit is contained in:
Leander Beernaert
2023-11-13 15:57:11 +01:00
committed by LBeernaertProton
parent fb55d3bd8b
commit d2fbf42bb0
6 changed files with 145 additions and 3 deletions

View File

@@ -108,6 +108,62 @@ func (c *Client) MarkMessagesRead(ctx context.Context, messageIDs ...string) err
return nil
}
func (c *Client) MarkMessagesForwarded(ctx context.Context, messageIDs ...string) error {
type subResponse struct {
Response APIError
ID string
}
var response struct {
Code int
Responses []subResponse
}
for _, page := range xslices.Chunk(messageIDs, maxPageSize) {
if err := c.do(ctx, func(r *resty.Request) (*resty.Response, error) {
return r.SetBody(MessageActionReq{IDs: page}).SetResult(&response).Put("/mail/v4/messages/forward")
}); err != nil {
return err
}
for _, r := range response.Responses {
if r.Response.Code != SuccessCode {
return fmt.Errorf("failed to mark message %v as forwarded", r.ID)
}
}
}
return nil
}
func (c *Client) MarkMessagesUnForwarded(ctx context.Context, messageIDs ...string) error {
type subResponse struct {
Response APIError
ID string
}
var response struct {
Code int
Responses []subResponse
}
for _, page := range xslices.Chunk(messageIDs, maxPageSize) {
if err := c.do(ctx, func(r *resty.Request) (*resty.Response, error) {
return r.SetBody(MessageActionReq{IDs: page}).SetResult(&response).Put("/mail/v4/messages/unforward")
}); err != nil {
return err
}
for _, r := range response.Responses {
if r.Response.Code != SuccessCode {
return fmt.Errorf("failed to unmark message %v as forwarded", r.ID)
}
}
}
return nil
}
func (c *Client) MarkMessagesUnread(ctx context.Context, messageIDs ...string) error {
for _, page := range xslices.Chunk(messageIDs, maxPageSize) {
req := MessageActionReq{IDs: page}

View File

@@ -514,6 +514,30 @@ func (b *Backend) SetMessagesRead(userID string, read bool, messageIDs ...string
})
})
}
func (b *Backend) SetMessagesForwarded(userID string, forwarded bool, messageIDs ...string) error {
return b.withAcc(userID, func(acc *account) error {
return b.withMessages(func(messages map[string]*message) error {
for _, messageID := range messageIDs {
if forwarded {
messages[messageID].flags |= proton.MessageFlagForwarded
} else {
messages[messageID].flags &= ^proton.MessageFlagForwarded
}
updateID, err := b.newUpdate(&messageUpdated{messageID: messageID})
if err != nil {
return err
}
acc.updateIDs = append(acc.updateIDs, updateID)
}
return nil
})
})
}
func (b *Backend) LabelMessages(userID, labelID string, messageIDs ...string) error {
return b.labelMessages(userID, labelID, true, messageIDs...)
}

View File

@@ -186,8 +186,9 @@ func (msg *message) toMetadata(attData map[string][]byte, att map[string]*attach
ReplyTos: msg.replytos,
Size: messageSize,
Flags: msg.flags,
Unread: proton.Bool(msg.unread),
Flags: msg.flags,
Unread: proton.Bool(msg.unread),
IsForwarded: msg.flags&proton.MessageFlagForwarded != 0,
NumAttachments: len(attData),
}

View File

@@ -13,6 +13,7 @@ import (
"github.com/ProtonMail/gluon/rfc822"
"github.com/ProtonMail/go-proton-api"
"github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/bradenaw/juniper/xslices"
"github.com/gin-gonic/gin"
"golang.org/x/exp/slices"
)
@@ -224,6 +225,62 @@ func (s *Server) handlePutMailMessagesUnread() gin.HandlerFunc {
}
}
func (s *Server) handlePutMailMessagesForwarded() gin.HandlerFunc {
return func(c *gin.Context) {
var req proton.MessageActionReq
if err := c.BindJSON(&req); err != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}
if err := s.b.SetMessagesForwarded(c.GetString("UserID"), true, req.IDs...); err != nil {
c.AbortWithStatus(http.StatusUnprocessableEntity)
return
}
c.JSON(http.StatusOK, gin.H{
"Code": 1001,
"Responses": xslices.Map(req.IDs, func(id string) any {
return gin.H{
"ID": id,
"Response": gin.H{
"Code": 1000,
},
}
}),
})
}
}
func (s *Server) handlePutMailMessagesUnforwarded() gin.HandlerFunc {
return func(c *gin.Context) {
var req proton.MessageActionReq
if err := c.BindJSON(&req); err != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}
if err := s.b.SetMessagesForwarded(c.GetString("UserID"), false, req.IDs...); err != nil {
c.AbortWithStatus(http.StatusUnprocessableEntity)
return
}
c.JSON(http.StatusOK, gin.H{
"Code": 1001,
"Responses": xslices.Map(req.IDs, func(id string) any {
return gin.H{
"ID": id,
"Response": gin.H{
"Code": 1000,
},
}
}),
})
}
}
func (s *Server) handlePutMailMessagesLabel() gin.HandlerFunc {
return func(c *gin.Context) {
var req proton.LabelMessagesReq

View File

@@ -101,6 +101,8 @@ func initRouter(s *Server) {
messages.POST("/import", s.handlePutMailMessagesImport())
messages.PUT("/delete", s.handleDeleteMailMessages())
messages.GET("/count", s.handleMessageGroupCount())
messages.PUT("/forward", s.handlePutMailMessagesForwarded())
messages.PUT("/unforward", s.handlePutMailMessagesUnforwarded())
}
if attachments := mail.Group("/attachments"); attachments != nil {

View File

@@ -362,6 +362,8 @@ func TestServer_Events(t *testing.T) {
// Mark a message as read.
require.NoError(t, c.MarkMessagesRead(ctx, messageIDs[0]))
// Mark a message as forwarded
require.NoError(t, c.MarkMessagesForwarded(ctx, messageIDs[0]))
// The message should eventually be read.
require.Eventually(t, func() bool {
@@ -375,7 +377,7 @@ func TestServer_Events(t *testing.T) {
return false
}
return !bool(event.Messages[0].Message.Unread)
return !bool(event.Messages[0].Message.Unread) && bool(event.Messages[0].Message.IsForwarded)
}, 5*time.Second, time.Millisecond*100)
// Add another message to archive.