Add Users endpoints to API
This commit is contained in:
parent
55b5f772fe
commit
695e998b1f
|
@ -29,6 +29,7 @@ import (
|
|||
"go.fifitido.net/twitch/api/streams"
|
||||
"go.fifitido.net/twitch/api/subscriptions"
|
||||
"go.fifitido.net/twitch/api/teams"
|
||||
"go.fifitido.net/twitch/api/users"
|
||||
)
|
||||
|
||||
const HelixBaseUrl = "https://api.twitch.tv/helix"
|
||||
|
@ -62,6 +63,7 @@ type API struct {
|
|||
Streams *streams.Streams
|
||||
Subscriptions *subscriptions.Subscriptions
|
||||
Teams *teams.Teams
|
||||
Users *users.Users
|
||||
}
|
||||
|
||||
func New(client *http.Client, baseUrl *url.URL) *API {
|
||||
|
@ -94,6 +96,7 @@ func New(client *http.Client, baseUrl *url.URL) *API {
|
|||
Streams: streams.New(client, baseUrl),
|
||||
Subscriptions: subscriptions.New(client, baseUrl),
|
||||
Teams: teams.New(client, baseUrl),
|
||||
Users: users.New(client, baseUrl),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
)
|
||||
|
||||
type BlockUserParams struct {
|
||||
// The ID of the user to block. The API ignores the request if the broadcaster has already blocked the user.
|
||||
TargetUserID string `url:"target_user_id"`
|
||||
|
||||
// The location where the harassment took place that is causing the brodcaster to block the user. Possible values are:
|
||||
//
|
||||
// chat, whisper
|
||||
SourceContext *string `url:"source_context,omitempty"`
|
||||
|
||||
// The reason that the broadcaster is blocking the user. Possible values are:
|
||||
//
|
||||
// harassment, spam, other
|
||||
Reason *string `url:"reason,omitempty"`
|
||||
}
|
||||
|
||||
// Blocks the specified user from interacting with or having contact with the broadcaster.
|
||||
// The user ID in the OAuth token identifies the broadcaster who is blocking the user.
|
||||
//
|
||||
// To learn more about blocking users,
|
||||
// see Block Other Users on Twitch: https://help.twitch.tv/s/article/how-to-manage-harassment-in-chat?language=en_US#BlockWhispersandMessagesfromStrangers
|
||||
//
|
||||
// Requires a user access token that includes the user:manage:blocked_users scope.
|
||||
func (u *Users) BlockUser(ctx context.Context, params *BlockUserParams) error {
|
||||
v, _ := query.Values(params)
|
||||
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users/blocks", RawQuery: v.Encode()})
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPut, endpoint.String(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := u.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
)
|
||||
|
||||
type GetUserActiveExtensionsParams struct {
|
||||
// The ID of the broadcaster whose active extensions you want to get.
|
||||
//
|
||||
// This parameter is required if you specify an app access token and is optional if you specify a user access token.
|
||||
// If you specify a user access token and don’t specify this parameter, the API uses the user ID from the access token.
|
||||
UserID string `url:"user_id,omitempty"`
|
||||
}
|
||||
|
||||
type GetUserActiveExtensionsResponse struct {
|
||||
// The active extensions that the broadcaster has installed.
|
||||
Data []ActiveExtension `json:"data"`
|
||||
}
|
||||
|
||||
// Gets the active extensions that the broadcaster has installed for each configuration.
|
||||
//
|
||||
// NOTE: To include extensions that you have under development,
|
||||
// you must specify a user access token that includes the user:read:broadcast or user:edit:broadcast scope.
|
||||
//
|
||||
// Requires an app access token or user access token.
|
||||
func (u *Users) GetUserActiveExtensions(ctx context.Context, params *GetUserActiveExtensionsParams) (*GetUserActiveExtensionsResponse, error) {
|
||||
v, _ := query.Values(params)
|
||||
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users/extensions", RawQuery: v.Encode()})
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := u.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
var data GetUserActiveExtensionsResponse
|
||||
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &data, nil
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
"go.fifitido.net/twitch/api/types"
|
||||
)
|
||||
|
||||
type GetUserBlockListParams struct {
|
||||
// The ID of the broadcaster whose list of blocked users you want to get.
|
||||
BroadcasterID string `url:"broadcaster_id"`
|
||||
|
||||
// The maximum number of items to return per page in the response.
|
||||
// The minimum page size is 1 item per page and the maximum is 100.
|
||||
// The default is 20.
|
||||
First *int `url:"first,omitempty"`
|
||||
|
||||
// The cursor used to get the next page of results.
|
||||
// The Pagination object in the response contains the cursor’s value.
|
||||
// Read More: https://dev.twitch.tv/docs/api/guide#pagination
|
||||
After *types.Cursor `url:"after,omitempty"`
|
||||
}
|
||||
|
||||
type GetUserBlockListResponse struct {
|
||||
// The list of blocked users. The list is in descending order by when the user was blocked.
|
||||
Data []struct {
|
||||
// An ID that identifies the blocked user.
|
||||
UserID string `json:"user_id"`
|
||||
|
||||
// The blocked user’s login name.
|
||||
UserLogin string `json:"user_login"`
|
||||
|
||||
// The blocked user’s display name.
|
||||
DisplayName string `json:"display_name"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// Gets the list of users that the broadcaster has blocked.
|
||||
// Read More: https://help.twitch.tv/s/article/how-to-manage-harassment-in-chat?language=en_US#BlockWhispersandMessagesfromStrangers
|
||||
//
|
||||
// Requires a user access token that includes the user:read:blocked_users scope.
|
||||
func (u *Users) GetUserBlockList(ctx context.Context, params *GetUserBlockListParams) (*GetUserBlockListResponse, error) {
|
||||
v, _ := query.Values(params)
|
||||
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users/blocks", RawQuery: v.Encode()})
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := u.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
var data GetUserBlockListResponse
|
||||
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &data, nil
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type GetUserExtensionsResponse struct {
|
||||
// The list of extensions that the user has installed.
|
||||
Data []struct {
|
||||
// An ID that identifies the extension.
|
||||
ID string `json:"id"`
|
||||
|
||||
// The extension's version.
|
||||
Version string `json:"version"`
|
||||
|
||||
// The extension's name.
|
||||
Name string `json:"name"`
|
||||
|
||||
// A Boolean value that determines whether the extension is configured and can be activated. Is true if the extension is configured and can be activated.
|
||||
CanActivate bool `json:"can_activate"`
|
||||
|
||||
// The extension types that you can activate for this extension. Possible values are:
|
||||
//
|
||||
// component, mobile, overlay, panel
|
||||
Type []string `json:"type"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// Gets a list of all extensions (both active and inactive) that the broadcaster has installed.
|
||||
// The user ID in the access token identifies the broadcaster.
|
||||
//
|
||||
// Requires a user access token that includes the user:read:broadcast or user:edit:broadcast scope.
|
||||
// To include inactive extensions, you must include the user:edit:broadcast scope.
|
||||
func (u *Users) GetUserExtensions(ctx context.Context) (*GetUserExtensionsResponse, error) {
|
||||
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users/extensions/list"})
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := u.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
var data GetUserExtensionsResponse
|
||||
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &data, nil
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
)
|
||||
|
||||
type GetUsersParams struct {
|
||||
// The ID of the user to get.
|
||||
// To specify more than one user, include the id parameter for each user to get. For example, id=1234&id=5678.
|
||||
// The maximum number of IDs you may specify is 100.
|
||||
IDs []string `url:"id,omitempty"`
|
||||
|
||||
// The login name of the user to get.
|
||||
// To specify more than one user, include the login parameter for each user to get. For example, login=foo&login=bar.
|
||||
// The maximum number of login names you may specify is 100.
|
||||
Logins []string `url:"login,omitempty"`
|
||||
}
|
||||
|
||||
type GetUsersResponse struct {
|
||||
// The list of users.
|
||||
Data []User `json:"data"`
|
||||
}
|
||||
|
||||
// Gets information about one or more users.
|
||||
//
|
||||
// You may look up users using their user ID, login name, or both but the sum total of the number of users you may look up is 100.
|
||||
// For example, you may specify 50 IDs and 50 names or 100 IDs or names, but you cannot specify 100 IDs and 100 names.
|
||||
//
|
||||
// If you don’t specify IDs or login names, the request returns information about the user in the access token if you specify a user access token.
|
||||
//
|
||||
// To include the user’s verified email address in the response, you must use a user access token that includes the user:read:email scope.
|
||||
//
|
||||
// Requires an app access token or user access token.
|
||||
func (u *Users) GetUsers(ctx context.Context, params *GetUsersParams) (*GetUsersResponse, error) {
|
||||
v, _ := query.Values(params)
|
||||
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users", RawQuery: v.Encode()})
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := u.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
var data GetUsersResponse
|
||||
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &data, nil
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
package users
|
||||
|
||||
import "time"
|
||||
|
||||
type User struct {
|
||||
// An ID that identifies the user.
|
||||
ID string `json:"id"`
|
||||
|
||||
// The user's login name.
|
||||
Login string `json:"login"`
|
||||
|
||||
// The user's display name.
|
||||
DisplayName string `json:"display_name"`
|
||||
|
||||
// The type of user. Possible values are:
|
||||
//
|
||||
// admin — Twitch administrator
|
||||
//
|
||||
// global_mod
|
||||
//
|
||||
// staff — Twitch staff
|
||||
//
|
||||
// "" — Normal user
|
||||
Type Type `json:"type"`
|
||||
|
||||
// The type of broadcaster. Possible values are:
|
||||
//
|
||||
// affiliate — An affiliate broadcaster
|
||||
//
|
||||
// partner — A partner broadcaster
|
||||
//
|
||||
// "" — A normal broadcaster
|
||||
BroadcasterType BroadcasterType `json:"broadcaster_type"`
|
||||
|
||||
// The user's description of their channel.
|
||||
Description string `json:"description"`
|
||||
|
||||
// A URL to the user's profile image.
|
||||
ProfileImageUrl string `json:"profile_image_url"`
|
||||
|
||||
// A URL to the user's offline image.
|
||||
OfflineImageUrl string `json:"offline_image_url"`
|
||||
|
||||
// The user's verified email address. The object includes this field only if the user access token includes the user:read:email scope.
|
||||
//
|
||||
// If the request contains more than one user, only the user associated with the access token that provided consent will include an email address —
|
||||
// the email address for all other users will be empty.
|
||||
Email *string `json:"email"`
|
||||
|
||||
// The UTC date and time that the user's account was created. The timestamp is in RFC3339 format.
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type Type string
|
||||
|
||||
const (
|
||||
// Twitch administrator
|
||||
TypeAdmin Type = "admin"
|
||||
|
||||
// Twitch global moderator
|
||||
TypeGlobalMod Type = "global_mod"
|
||||
|
||||
// Twitch staff
|
||||
TypeStaff Type = "staff"
|
||||
|
||||
// Normal user
|
||||
TypeNormal Type = ""
|
||||
)
|
||||
|
||||
type BroadcasterType string
|
||||
|
||||
const (
|
||||
// An affiliate broadcaster
|
||||
BroadcasterTypeAffiliate BroadcasterType = "affiliate"
|
||||
|
||||
// A partner broadcaster
|
||||
BroadcasterTypePartner BroadcasterType = "partner"
|
||||
|
||||
// A normal broadcaster
|
||||
BroadcasterTypeNormal BroadcasterType = ""
|
||||
)
|
||||
|
||||
type ActiveExtension struct {
|
||||
// A dictionary that contains the data for a panel extension.
|
||||
// The dictionary’s key is a sequential number beginning with 1.
|
||||
// The following fields contain the panel’s data for each key.
|
||||
Panel map[string]ExtensionData `json:"panel"`
|
||||
|
||||
// A dictionary that contains the data for a video-overlay extension.
|
||||
// The dictionary’s key is a sequential number beginning with 1.
|
||||
// The following fields contain the overlay’s data for each key.
|
||||
Overlay map[string]ExtensionData `json:"overlay"`
|
||||
|
||||
// A dictionary that contains the data for a video-component extension.
|
||||
// The dictionary’s key is a sequential number beginning with 1.
|
||||
// The following fields contain the component’s data for each key.
|
||||
Component map[string]ComponentExtensionData `json:"component"`
|
||||
}
|
||||
|
||||
type ExtensionData struct {
|
||||
// A Boolean value that determines the extension’s activation state. If false, the user has not configured this panel extension.
|
||||
Active bool `json:"active"`
|
||||
|
||||
// An ID that identifies the extension.
|
||||
ID string `json:"id"`
|
||||
|
||||
// The extension’s version.
|
||||
Version string `json:"version"`
|
||||
|
||||
// The extension’s name.
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type ComponentExtensionData struct {
|
||||
ExtensionData `json:",inline"`
|
||||
|
||||
// The x-coordinate where the extension is placed.
|
||||
X int `json:"x"`
|
||||
|
||||
// The y-coordinate where the extension is placed.
|
||||
Y int `json:"y"`
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// Removes the user from the broadcaster’s list of blocked users.
|
||||
// The user ID in the OAuth token identifies the broadcaster who’s removing the block.
|
||||
//
|
||||
// Requires a user access token that includes the user:manage:blocked_users scope.
|
||||
func (u *Users) UnblockUser(ctx context.Context, targetUserID string) error {
|
||||
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users/blocks", RawQuery: url.Values{"target_user_id": {targetUserID}}.Encode()})
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, endpoint.String(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := u.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
)
|
||||
|
||||
type UpdateUserParams struct {
|
||||
// The string to update the channel’s description to. The description is limited to a maximum of 300 characters.
|
||||
//
|
||||
// To remove the description, specify this parameter but don’t set it’s value (for example, ?description=).
|
||||
Description *string `url:"description,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateUserResponse struct {
|
||||
// A list contains the single user that you updated.
|
||||
Data []User `json:"data"`
|
||||
}
|
||||
|
||||
// Updates the specified user’s information. The user ID in the OAuth token identifies the user whose information you want to update.
|
||||
//
|
||||
// To include the user’s verified email address in the response, the user access token must also include the user:read:email scope.
|
||||
//
|
||||
// Requires a user access token that includes the user:edit scope.
|
||||
func (u *Users) UpdateUser(ctx context.Context, params *UpdateUserParams) (*UpdateUserResponse, error) {
|
||||
v, _ := query.Values(params)
|
||||
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users", RawQuery: v.Encode()})
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPatch, endpoint.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := u.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
var data UpdateUserResponse
|
||||
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &data, nil
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package users
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type UpdateUserExtensionsRequest struct {
|
||||
// The extensions to update. The data field is a dictionary of extension types.
|
||||
// The dictionary’s possible keys are: panel, overlay, or component.
|
||||
// The key’s value is a dictionary of extensions.
|
||||
//
|
||||
// For the extension’s dictionary, the key is a sequential number beginning with 1.
|
||||
// For panel and overlay extensions, the key’s value is an object that contains the following fields:
|
||||
// active (true/false), id (the extension’s ID), and version (the extension’s version).
|
||||
//
|
||||
// For component extensions, the key’s value includes the above fields plus the x and y fields,
|
||||
// which identify the coordinate where the extension is placed.
|
||||
Data map[string]map[string]interface{} `json:"data"`
|
||||
}
|
||||
|
||||
type UpdateUserExtensionsResponse struct {
|
||||
// The extensions that the broadcaster updated.
|
||||
Data []ActiveExtension `json:"data"`
|
||||
}
|
||||
|
||||
// Updates an installed extension’s information. You can update the extension’s activation state, ID, and version number.
|
||||
// The user ID in the access token identifies the broadcaster whose extensions you’re updating.
|
||||
//
|
||||
// NOTE: If you try to activate an extension under multiple extension types, the last write wins (and there is no guarantee of write order).
|
||||
//
|
||||
// Requires a user access token that includes the user:edit:broadcast scope.
|
||||
func (u *Users) UpdateUserExtensions(ctx context.Context, body *UpdateUserExtensionsRequest) (*UpdateUserExtensionsResponse, error) {
|
||||
endpoint := u.baseUrl.ResolveReference(&url.URL{Path: "users/extensions"})
|
||||
|
||||
r, w := io.Pipe()
|
||||
|
||||
go func() {
|
||||
if err := json.NewEncoder(w).Encode(body); err != nil {
|
||||
w.CloseWithError(err)
|
||||
} else {
|
||||
w.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPatch, endpoint.String(), r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := u.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
var data UpdateUserExtensionsResponse
|
||||
if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &data, nil
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package users
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type Users struct {
|
||||
client *http.Client
|
||||
baseUrl *url.URL
|
||||
}
|
||||
|
||||
func New(client *http.Client, baseUrl *url.URL) *Users {
|
||||
return &Users{
|
||||
client: client,
|
||||
baseUrl: baseUrl,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue