github.com/diamondburned/arikawa@v1.3.14/api/message_reaction.go (about)

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