github.com/diamondburned/arikawa/v2@v2.1.0/api/message_reaction.go (about)

     1  package api
     2  
     3  import (
     4  	"github.com/diamondburned/arikawa/v2/discord"
     5  	"github.com/diamondburned/arikawa/v2/internal/intmath"
     6  	"github.com/diamondburned/arikawa/v2/utils/httputil"
     7  )
     8  
     9  const MaxMessageReactionFetchLimit = 100
    10  
    11  // React creates a reaction for the message.
    12  //
    13  // This endpoint requires the READ_MESSAGE_HISTORY permission to be present on
    14  // the current user. Additionally, if nobody else has reacted to the message
    15  // using this emoji, this endpoint requires the 'ADD_REACTIONS' permission to
    16  // be present on the current user.
    17  func (c *Client) React(
    18  	channelID discord.ChannelID,
    19  	messageID discord.MessageID, emoji discord.APIEmoji) error {
    20  
    21  	return c.FastRequest(
    22  		"PUT",
    23  		EndpointChannels+channelID.String()+
    24  			"/messages/"+messageID.String()+
    25  			"/reactions/"+emoji.PathString()+"/@me",
    26  	)
    27  }
    28  
    29  // Unreact removes a reaction the current user has made for the message.
    30  func (c *Client) Unreact(
    31  	channelID discord.ChannelID,
    32  	messageID discord.MessageID, emoji discord.APIEmoji) error {
    33  
    34  	return c.DeleteUserReaction(channelID, messageID, 0, emoji)
    35  }
    36  
    37  // Reactions returns a list of users that reacted with the passed Emoji. This
    38  // method automatically paginates until it reaches the passed limit, or, if the
    39  // limit is set to 0, has fetched all users within the passed range.
    40  //
    41  // As the underlying endpoint has a maximum of 100 users per request, at
    42  // maximum a total of limit/100 rounded up requests will be made, although they
    43  // may be less, if no more guilds are available.
    44  //
    45  // When fetching the users, those with the smallest ID will be fetched first.
    46  func (c *Client) Reactions(
    47  	channelID discord.ChannelID,
    48  	messageID discord.MessageID,
    49  	emoji discord.APIEmoji, limit uint) ([]discord.User, error) {
    50  
    51  	return c.ReactionsAfter(channelID, messageID, 0, emoji, limit)
    52  }
    53  
    54  // ReactionsBefore returns a list of users that reacted with the passed Emoji.
    55  // This method automatically paginates until it reaches the passed limit, or,
    56  // if the limit is set to 0, has fetched all users with an id smaller than
    57  // before.
    58  //
    59  // As the underlying endpoint has a maximum of 100 users per request, at
    60  // maximum a total of limit/100 rounded up requests will be made, although they
    61  // may be less, if no more guilds are available.
    62  func (c *Client) ReactionsBefore(
    63  	channelID discord.ChannelID,
    64  	messageID discord.MessageID,
    65  	before discord.UserID,
    66  	emoji discord.APIEmoji, limit uint) ([]discord.User, error) {
    67  
    68  	users := make([]discord.User, 0, limit)
    69  
    70  	fetch := uint(MaxMessageReactionFetchLimit)
    71  
    72  	unlimited := limit == 0
    73  
    74  	for limit > 0 || unlimited {
    75  		if limit > 0 {
    76  			// Only fetch as much as we need. Since limit gradually decreases,
    77  			// we only need to fetch intmath.Min(fetch, limit).
    78  			fetch = uint(intmath.Min(MaxMessageReactionFetchLimit, int(limit)))
    79  			limit -= fetch
    80  		}
    81  
    82  		r, err := c.reactionsRange(channelID, messageID, before, 0, emoji, fetch)
    83  		if err != nil {
    84  			return users, err
    85  		}
    86  		users = append(r, users...)
    87  
    88  		if len(r) < MaxMessageReactionFetchLimit {
    89  			break
    90  		}
    91  
    92  		before = r[0].ID
    93  	}
    94  
    95  	if len(users) == 0 {
    96  		return nil, nil
    97  	}
    98  
    99  	return users, nil
   100  }
   101  
   102  // ReactionsAfter returns a list of users that reacted with the passed Emoji.
   103  // This method automatically paginates until it reaches the passed limit, or,
   104  // if the limit is set to 0, has fetched all users with an id higher than
   105  // after.
   106  //
   107  // As the underlying endpoint has a maximum of 100 users per request, at
   108  // maximum a total of limit/100 rounded up requests will be made, although they
   109  // may be less, if no more guilds are available.
   110  func (c *Client) ReactionsAfter(
   111  	channelID discord.ChannelID,
   112  	messageID discord.MessageID,
   113  	after discord.UserID,
   114  	emoji discord.APIEmoji, limit uint) ([]discord.User, error) {
   115  
   116  	users := make([]discord.User, 0, limit)
   117  
   118  	fetch := uint(MaxMessageReactionFetchLimit)
   119  
   120  	unlimited := limit == 0
   121  
   122  	for limit > 0 || unlimited {
   123  		if limit > 0 {
   124  			// Only fetch as much as we need. Since limit gradually decreases,
   125  			// we only need to fetch intmath.Min(fetch, limit).
   126  			fetch = uint(intmath.Min(MaxMessageReactionFetchLimit, int(limit)))
   127  			limit -= fetch
   128  		}
   129  
   130  		r, err := c.reactionsRange(channelID, messageID, 0, after, emoji, fetch)
   131  		if err != nil {
   132  			return users, err
   133  		}
   134  		users = append(users, r...)
   135  
   136  		if len(r) < MaxMessageReactionFetchLimit {
   137  			break
   138  		}
   139  
   140  		after = r[len(r)-1].ID
   141  	}
   142  
   143  	if len(users) == 0 {
   144  		return nil, nil
   145  	}
   146  
   147  	return users, nil
   148  }
   149  
   150  // reactionsRange get users before and after IDs. Before, after, and limit are
   151  // optional. A maximum limit of only 100 reactions could be returned.
   152  func (c *Client) reactionsRange(
   153  	channelID discord.ChannelID,
   154  	messageID discord.MessageID,
   155  	before, after discord.UserID,
   156  	emoji discord.APIEmoji, limit uint) ([]discord.User, error) {
   157  
   158  	switch {
   159  	case limit == 0:
   160  		limit = 25
   161  	case limit > 100:
   162  		limit = 100
   163  	}
   164  
   165  	var param struct {
   166  		Before discord.UserID `schema:"before,omitempty"`
   167  		After  discord.UserID `schema:"after,omitempty"`
   168  
   169  		Limit uint `schema:"limit"`
   170  	}
   171  
   172  	param.Before = before
   173  	param.After = after
   174  	param.Limit = limit
   175  
   176  	var users []discord.User
   177  	return users, c.RequestJSON(
   178  		&users, "GET", EndpointChannels+channelID.String()+
   179  			"/messages/"+messageID.String()+
   180  			"/reactions/"+emoji.PathString(),
   181  		httputil.WithSchema(c, param),
   182  	)
   183  }
   184  
   185  // DeleteReaction deletes another user's reaction.
   186  //
   187  // This endpoint requires the MANAGE_MESSAGES permission to be present on the
   188  // current user.
   189  func (c *Client) DeleteUserReaction(
   190  	channelID discord.ChannelID,
   191  	messageID discord.MessageID,
   192  	userID discord.UserID,
   193  	emoji discord.APIEmoji) error {
   194  
   195  	var user = "@me"
   196  	if userID > 0 {
   197  		user = userID.String()
   198  	}
   199  
   200  	return c.FastRequest(
   201  		"DELETE",
   202  		EndpointChannels+channelID.String()+
   203  			"/messages/"+messageID.String()+
   204  			"/reactions/"+emoji.PathString()+"/"+user,
   205  	)
   206  }
   207  
   208  // DeleteReactions deletes all the reactions for a given emoji on a message.
   209  //
   210  // This endpoint requires the MANAGE_MESSAGES permission to be present on the
   211  // current user.
   212  // Fires a Message Reaction Remove Emoji Gateway event.
   213  func (c *Client) DeleteReactions(
   214  	channelID discord.ChannelID, messageID discord.MessageID, emoji discord.APIEmoji) error {
   215  
   216  	return c.FastRequest(
   217  		"DELETE",
   218  		EndpointChannels+channelID.String()+
   219  			"/messages/"+messageID.String()+
   220  			"/reactions/"+emoji.PathString(),
   221  	)
   222  }
   223  
   224  // DeleteAllReactions deletes all reactions on a message.
   225  //
   226  // This endpoint requires the MANAGE_MESSAGES permission to be present on the
   227  // current user.
   228  // Fires a Message Reaction Remove All Gateway event.
   229  func (c *Client) DeleteAllReactions(
   230  	channelID discord.ChannelID, messageID discord.MessageID) error {
   231  
   232  	return c.FastRequest(
   233  		"DELETE",
   234  		EndpointChannels+channelID.String()+"/messages/"+messageID.String()+"/reactions",
   235  	)
   236  }