Skip to main content

twitch_oauth2/
scopes.rs

1//! Module for all possible scopes in twitch.
2pub mod validator;
3pub use validator::Validator;
4
5use serde_derive::{Deserialize, Serialize};
6use std::borrow::Cow;
7
8macro_rules! scope_impls {
9    (@omit #[deprecated($depr:tt)] $i:ident) => {
10        #[cfg(_internal_never)]
11        Self::$i
12    };
13    (@omit $i:ident) => {
14        Self::$i
15    };
16
17    ($($(#[cfg(($cfg:meta))])* $(#[deprecated($depr:meta)])? $i:ident,scope: $rename:literal, doc: $doc:literal);* $(;)? ) => {
18        #[doc = "Scopes for twitch."]
19        #[doc = ""]
20        #[doc = "<https://dev.twitch.tv/docs/authentication/scopes/>"]
21        #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
22        #[non_exhaustive]
23        #[serde(from = "String")]
24        #[serde(into = "String")]
25        pub enum Scope {
26            $(
27                $(#[cfg($cfg)])*
28                $(#[deprecated($depr)])*
29                #[doc = $doc]
30                #[doc = "\n\n"]
31                #[doc = "`"]
32                #[doc = $rename]
33                #[doc = "`"]
34                #[serde(rename = $rename)] // Is this even needed?
35                $i,
36            )*
37            #[doc = "Other scope that is not implemented."]
38            Other(Cow<'static, str>),
39        }
40
41        impl std::fmt::Display for Scope {
42            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43                #![allow(deprecated)]
44
45                f.write_str(match self {
46                    Scope::Other(s) => &s,
47                    $(
48                        $(#[cfg($cfg)])*
49                        Scope::$i => $rename,
50                    )*
51                })
52            }
53        }
54
55        impl Scope {
56            #[doc = "Get a vec of all defined twitch [Scopes][Scope]."]
57            #[doc = "\n\n"]
58            #[doc = "Please note that this may not work for you, as some auth flows and \"apis\" don't accept all scopes"]
59            pub fn all() -> Vec<Scope> {
60                vec![
61                    $(
62                        scope_impls!(@omit $(#[deprecated($depr)])* $i),
63                    )*
64                ]
65            }
66
67            #[doc = "Get a slice of all defined twitch [Scopes][Scope]."]
68            #[doc = "\n\n"]
69            #[doc = "Please note that this may not work for you, as some auth flows and \"apis\" don't accept all scopes"]
70            pub const fn all_slice() -> &'static [Scope] {
71                &[
72                    $(
73                        scope_impls!(@omit $(#[deprecated($depr)])* $i),
74                    )*
75                ]
76            }
77
78            #[doc = "Get a description for the token"]
79            pub const fn description(&self) -> &'static str {
80                #![allow(deprecated)]
81
82                match self {
83
84                    $(
85                        $(#[cfg($cfg)])*
86                        Self::$i => $doc,
87                    )*
88                    _ => "unknown scope"
89                }
90            }
91
92            #[doc = "Make a scope from a cow string"]
93            pub fn parse<C>(s: C) -> Scope where C: Into<Cow<'static, str>> {
94                #![allow(deprecated)]
95                use std::borrow::Borrow;
96                let s = s.into();
97                match s.borrow() {
98
99                    $(
100                        $(#[cfg($cfg)])*
101                        $rename => {Scope::$i}
102                    )*,
103                    _ => Scope::Other(s)
104                }
105            }
106
107            /// Get the scope as a borrowed string.
108            pub fn as_str(&self) -> &str {
109                #![allow(deprecated)]
110                match self {
111                    $(
112                        $(#[cfg($cfg)])*
113                        Scope::$i => $rename,
114                    )*
115                    Self::Other(c) => c.as_ref()
116                }
117            }
118
119            /// Get the scope as a static string slice.
120            ///
121            /// ## Panics
122            ///
123            /// This function panics if the scope can't be represented as a static string slice
124            pub const fn as_static_str(&self) -> &'static str {
125                #![allow(deprecated)]
126                match self {
127                    $(
128                        $(#[cfg($cfg)])*
129                        Scope::$i => $rename,
130                    )*
131                    Self::Other(Cow::Borrowed(s)) => s,
132                    _ => panic!(),
133                }
134            }
135        }
136        #[test]
137        #[cfg(test)]
138        fn sorted() {
139            // Deprecated items come at the end, ignore them.
140            let n_deprecated = [$(
141                $(stringify!($depr),)*
142            )*].len();
143            let slice = [$(
144                $(#[cfg($cfg)])*
145                $rename,
146            )*];
147            let n_scopes = slice.len();
148            let slice = &slice[..(n_scopes - n_deprecated)];
149            let mut slice_sorted = [$(
150                $(#[cfg($cfg)])*
151                $rename,
152            )*];
153            let slice_sorted = &mut slice_sorted[..(n_scopes - n_deprecated)];
154            slice_sorted.sort();
155            for (scope, sorted) in slice.iter().zip(slice_sorted.iter()) {
156                assert_eq!(scope, sorted);
157            }
158            assert_eq!(slice, slice_sorted);
159        }
160    };
161}
162
163/*
164Extract from the Twitch docs (https://dev.twitch.tv/docs/authentication/scopes/) by pasting in the DevTools:
165
166copy(
167  (() => {
168    let tbl = $$("tbody")
169      .map((tb) => [...tb.children])
170      .flat()
171      .map((tr) => [
172        tr.children[0].textContent,
173        tr.children[1].firstChild.textContent.trim(),
174      ])
175      .map(([name, desc]) => [
176        name
177          .split(/[:_-]/)
178          .map((x) => x[0].toUpperCase() + x.slice(1))
179          .join("") + ", ",
180        'scope: "' + name + '", ',
181        "doc: " + JSON.stringify(desc) + ";",
182      ])
183      .sort((a, b) => a[0] > b[0]);
184    let [l0, l1] = tbl.reduce(
185      (acc, cur) => [
186        Math.max(acc[0], cur[0].length),
187        Math.max(acc[1], cur[1].length),
188      ],
189      [0, 0],
190    );
191    return tbl
192      .map(([a, b, c]) => `    ${a.padRight(l0, " ")}${b.padRight(l1, " ")}${c}`)
193      .join("\n");
194  })(),
195);
196*/
197
198scope_impls!(
199    AnalyticsReadExtensions,        scope: "analytics:read:extensions",         doc: "View analytics data for the Twitch Extensions owned by the authenticated account.";
200    AnalyticsReadGames,             scope: "analytics:read:games",              doc: "View analytics data for the games owned by the authenticated account.";
201    BitsRead,                       scope: "bits:read",                         doc: "View Bits information for a channel.";
202    ChannelBot,                     scope: "channel:bot",                       doc: "Joins your channel’s chatroom as a bot user, and perform chat-related actions as that user.";
203    ChannelEditCommercial,          scope: "channel:edit:commercial",           doc: "Run commercials on a channel.";
204    ChannelManageAds,               scope: "channel:manage:ads",                doc: "Manage ads schedule on a channel.";
205    ChannelManageBroadcast,         scope: "channel:manage:broadcast",          doc: "Manage a channel’s broadcast configuration, including updating channel configuration and managing stream markers and stream tags.";
206    ChannelManageClips,             scope: "channel:manage:clips",              doc: "Manage Clips for a channel.";
207    ChannelManageExtensions,        scope: "channel:manage:extensions",         doc: "Manage a channel’s Extension configuration, including activating Extensions.";
208    ChannelManageGuestStar,         scope: "channel:manage:guest_star",         doc: "Manage Guest Star for your channel.";
209    ChannelManageModerators,        scope: "channel:manage:moderators",         doc: "Add or remove the moderator role from users in your channel.";
210    ChannelManagePolls,             scope: "channel:manage:polls",              doc: "Manage a channel’s polls.";
211    ChannelManagePredictions,       scope: "channel:manage:predictions",        doc: "Manage of channel’s Channel Points Predictions";
212    ChannelManageRaids,             scope: "channel:manage:raids",              doc: "Manage a channel raiding another channel.";
213    ChannelManageRedemptions,       scope: "channel:manage:redemptions",        doc: "Manage Channel Points custom rewards and their redemptions on a channel.";
214    ChannelManageSchedule,          scope: "channel:manage:schedule",           doc: "Manage a channel’s stream schedule.";
215    ChannelManageVideos,            scope: "channel:manage:videos",             doc: "Manage a channel’s videos, including deleting videos.";
216    ChannelManageVips,              scope: "channel:manage:vips",               doc: "Add or remove the VIP role from users in your channel.";
217    ChannelModerate,                scope: "channel:moderate",                  doc: "Perform moderation actions in a channel.";
218    ChannelReadAds,                 scope: "channel:read:ads",                  doc: "Read the ads schedule and details on your channel.";
219    ChannelReadCharity,             scope: "channel:read:charity",              doc: "Read charity campaign details and user donations on your channel.";
220    ChannelReadEditors,             scope: "channel:read:editors",              doc: "View a list of users with the editor role for a channel.";
221    ChannelReadGoals,               scope: "channel:read:goals",                doc: "View Creator Goals for a channel.";
222    ChannelReadGuestStar,           scope: "channel:read:guest_star",           doc: "Read Guest Star details for your channel.";
223    ChannelReadHypeTrain,           scope: "channel:read:hype_train",           doc: "View Hype Train information for a channel.";
224    ChannelReadPolls,               scope: "channel:read:polls",                doc: "View a channel’s polls.";
225    ChannelReadPredictions,         scope: "channel:read:predictions",          doc: "View a channel’s Channel Points Predictions.";
226    ChannelReadRedemptions,         scope: "channel:read:redemptions",          doc: "View Channel Points custom rewards and their redemptions on a channel.";
227    ChannelReadStreamKey,           scope: "channel:read:stream_key",           doc: "View an authorized user’s stream key.";
228    ChannelReadSubscriptions,       scope: "channel:read:subscriptions",        doc: "View a list of all subscribers to a channel and check if a user is subscribed to a channel.";
229    ChannelReadVips,                scope: "channel:read:vips",                 doc: "Read the list of VIPs in your channel.";
230    ChatEdit,                       scope: "chat:edit",                         doc: "Send chat messages to a chatroom using an IRC connection.";
231    ChatRead,                       scope: "chat:read",                         doc: "View chat messages sent in a chatroom using an IRC connection.";
232    ClipsEdit,                      scope: "clips:edit",                        doc: "Manage Clips for a channel.";
233    EditorManageClips,              scope: "editor:manage:clips",               doc: "Manage Clips as an editor.";
234    ModerationRead,                 scope: "moderation:read",                   doc: "View a channel’s moderation data including Moderators, Bans, Timeouts, and Automod settings.";
235    ModeratorManageAnnouncements,   scope: "moderator:manage:announcements",    doc: "Send announcements in channels where you have the moderator role.";
236    ModeratorManageAutoMod,         scope: "moderator:manage:automod",          doc: "Manage messages held for review by AutoMod in channels where you are a moderator.";
237    ModeratorManageAutomodSettings, scope: "moderator:manage:automod_settings", doc: "Manage a broadcaster’s AutoMod settings.";
238    ModeratorManageBannedUsers,     scope: "moderator:manage:banned_users",     doc: "Ban and unban users.";
239    ModeratorManageBlockedTerms,    scope: "moderator:manage:blocked_terms",    doc: "Manage a broadcaster’s list of blocked terms.";
240    ModeratorManageChatMessages,    scope: "moderator:manage:chat_messages",    doc: "Delete chat messages in channels where you have the moderator role";
241    ModeratorManageChatSettings,    scope: "moderator:manage:chat_settings",    doc: "Manage a broadcaster’s chat room settings.";
242    ModeratorManageGuestStar,       scope: "moderator:manage:guest_star",       doc: "Manage Guest Star for channels where you are a Guest Star moderator.";
243    ModeratorManageShieldMode,      scope: "moderator:manage:shield_mode",      doc: "Manage a broadcaster’s Shield Mode status.";
244    ModeratorManageShoutouts,       scope: "moderator:manage:shoutouts",        doc: "Manage a broadcaster’s shoutouts.";
245    ModeratorManageSuspiciousUsers, scope: "moderator:manage:suspicious_users", doc: "Manage suspicious user statuses in channels where the user has the moderator role.";
246    ModeratorManageUnbanRequests,   scope: "moderator:manage:unban_requests",   doc: "Manage a broadcaster’s unban requests.";
247    ModeratorManageWarnings,        scope: "moderator:manage:warnings",         doc: "Warn users in channels where you have the moderator role.";
248    ModeratorReadAutomodSettings,   scope: "moderator:read:automod_settings",   doc: "View a broadcaster’s AutoMod settings.";
249    ModeratorReadBannedUsers,       scope: "moderator:read:banned_users",       doc: "Read the list of bans or unbans in channels where you have the moderator role.";
250    ModeratorReadBlockedTerms,      scope: "moderator:read:blocked_terms",      doc: "View a broadcaster’s list of blocked terms.";
251    ModeratorReadChatMessages,      scope: "moderator:read:chat_messages",      doc: "Read deleted chat messages in channels where you have the moderator role.";
252    ModeratorReadChatSettings,      scope: "moderator:read:chat_settings",      doc: "View a broadcaster’s chat room settings.";
253    ModeratorReadChatters,          scope: "moderator:read:chatters",           doc: "View the chatters in a broadcaster’s chat room.";
254    ModeratorReadFollowers,         scope: "moderator:read:followers",          doc: "Read the followers of a broadcaster.";
255    ModeratorReadGuestStar,         scope: "moderator:read:guest_star",         doc: "Read Guest Star details for channels where you are a Guest Star moderator.";
256    ModeratorReadModerators,        scope: "moderator:read:moderators",         doc: "Read the list of moderators in channels where you have the moderator role.";
257    ModeratorReadShieldMode,        scope: "moderator:read:shield_mode",        doc: "View a broadcaster’s Shield Mode status.";
258    ModeratorReadShoutouts,         scope: "moderator:read:shoutouts",          doc: "View a broadcaster’s shoutouts.";
259    ModeratorReadSuspiciousUsers,   scope: "moderator:read:suspicious_users",   doc: "Read chat messages from suspicious users and see users flagged as suspicious in channels where the user has the moderator role.";
260    ModeratorReadUnbanRequests,     scope: "moderator:read:unban_requests",     doc: "View a broadcaster’s unban requests.";
261    ModeratorReadVips,              scope: "moderator:read:vips",               doc: "Read the list of VIPs in channels where you have the moderator role.";
262    ModeratorReadWarnings,          scope: "moderator:read:warnings",           doc: "Read warnings in channels where you have the moderator role.";
263    UserBot,                        scope: "user:bot",                          doc: "Join a specified chat channel as your user and appear as a bot, and perform chat-related actions as your user.";
264    UserEdit,                       scope: "user:edit",                         doc: "Manage a user object.";
265    UserEditBroadcast,              scope: "user:edit:broadcast",               doc: "View and edit a user’s broadcasting configuration, including Extension configurations.";
266    UserManageBlockedUsers,         scope: "user:manage:blocked_users",         doc: "Manage the block list of a user.";
267    UserManageChatColor,            scope: "user:manage:chat_color",            doc: "Update the color used for the user’s name in chat.";
268    UserManageWhispers,             scope: "user:manage:whispers",              doc: "Receive whispers sent to your user, and send whispers on your user’s behalf.";
269    UserReadBlockedUsers,           scope: "user:read:blocked_users",           doc: "View the block list of a user.";
270    UserReadBroadcast,              scope: "user:read:broadcast",               doc: "View a user’s broadcasting configuration, including Extension configurations.";
271    UserReadChat,                   scope: "user:read:chat",                    doc: "Receive chatroom messages and informational notifications relating to a channel’s chatroom.";
272    UserReadEmail,                  scope: "user:read:email",                   doc: "View a user’s email address.";
273    UserReadEmotes,                 scope: "user:read:emotes",                  doc: "View emotes available to a user";
274    UserReadFollows,                scope: "user:read:follows",                 doc: "View the list of channels a user follows.";
275    UserReadModeratedChannels,      scope: "user:read:moderated_channels",      doc: "Read the list of channels you have moderator privileges in.";
276    UserReadSubscriptions,          scope: "user:read:subscriptions",           doc: "View if an authorized user is subscribed to specific channels.";
277    UserReadWhispers,               scope: "user:read:whispers",                doc: "Receive whispers sent to your user.";
278    UserWriteChat,                  scope: "user:write:chat",                   doc: "Send chat messages to a chatroom.";
279    WhispersRead,                   scope: "whispers:read",                     doc: "Receive whisper messages for your user using PubSub.";
280
281    // Deprecated/removed scopes:
282
283    #[deprecated(note = "Use `ChannelReadSubscriptions` (`channel:read:subscriptions`) instead")]
284    ChannelSubscriptions,           scope: "channel_subscriptions",             doc: "Read all subscribers to your channel.";
285    #[deprecated(note = "Not used anymore, see https://discuss.dev.twitch.tv/t/deprecation-of-create-and-delete-follows-api-endpoints/32351")]
286    UserEditFollows,                scope: "user:edit:follows",                 doc: "\\[DEPRECATED\\] Was previously used for “Create User Follows” and “Delete User Follows.";
287    #[deprecated(note = "Use `UserManageWhispers` (`user:manage:whispers`) instead")]
288    WhispersEdit,                   scope: "whispers:edit",                     doc: "\\[DEPRECATED\\] Send whisper messages.";
289);
290
291impl Scope {
292    /// Get the scope as a [validator](Validator).
293    pub const fn to_validator(self) -> Validator { Validator::scope(self) }
294}
295
296impl std::borrow::Borrow<str> for Scope {
297    fn borrow(&self) -> &str { self.as_str() }
298}
299
300impl From<String> for Scope {
301    fn from(s: String) -> Self { Scope::parse(s) }
302}
303
304impl From<Scope> for String {
305    fn from(s: Scope) -> Self { s.to_string() }
306}
307
308#[cfg(test)]
309mod tests {
310    use super::*;
311    #[test]
312    fn custom_scope() {
313        assert_eq!(
314            Scope::Other(Cow::from("custom_scope")),
315            Scope::parse("custom_scope")
316        )
317    }
318
319    #[test]
320    fn roundabout() {
321        for scope in Scope::all() {
322            assert_eq!(scope, Scope::parse(scope.to_string()))
323        }
324    }
325
326    #[test]
327    #[allow(deprecated)]
328    fn no_deprecated() {
329        for scope in Scope::all() {
330            assert!(scope != Scope::ChannelSubscriptions)
331        }
332    }
333}