Skip to content

Commit e54d55d

Browse files
authored
Merge pull request #449 from twitch-rs/feat/ccls
feat: add `Get Content Classification Labels`
2 parents 13e2c4c + 52c5f77 commit e54d55d

File tree

6 files changed

+302
-2
lines changed

6 files changed

+302
-2
lines changed

src/helix/client/client_ext.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,6 +1578,71 @@ impl<'client, C: crate::HttpClient + Sync + 'client> HelixClient<'client, C> {
15781578
.data)
15791579
}
15801580

1581+
/// Get information about Twitch content classification labels, see [`get_content_classification_labels_for_locale`](HelixClient::get_content_classification_labels_for_locale) to get the labels in a specific locale.
1582+
///
1583+
/// # Examples
1584+
///
1585+
/// ```rust, no_run
1586+
/// # #[tokio::main]
1587+
/// # async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
1588+
/// # let client: helix::HelixClient<'static, twitch_api::client::DummyHttpClient> = helix::HelixClient::default();
1589+
/// # let token = twitch_oauth2::AccessToken::new("validtoken".to_string());
1590+
/// # let token = twitch_oauth2::UserToken::from_existing(&client, token, None, None).await?;
1591+
/// use twitch_api::helix;
1592+
///
1593+
/// let labels: Vec<helix::ccls::ContentClassificationLabel> = client
1594+
/// .get_content_classification_labels(&token)
1595+
/// .await?;
1596+
/// # Ok(()) }
1597+
/// ```
1598+
pub async fn get_content_classification_labels<'b, T>(
1599+
&'client self,
1600+
token: &'client T,
1601+
) -> Result<Vec<helix::ccls::ContentClassificationLabel>, ClientError<C>>
1602+
where
1603+
T: TwitchToken + Send + Sync + ?Sized,
1604+
{
1605+
self.req_get(
1606+
helix::ccls::GetContentClassificationLabelsRequest::new(),
1607+
token,
1608+
)
1609+
.await
1610+
.map(|res| res.data)
1611+
}
1612+
1613+
/// Get information about Twitch content classification labels for a specific locale.
1614+
///
1615+
/// # Examples
1616+
///
1617+
/// ```rust, no_run
1618+
/// # #[tokio::main]
1619+
/// # async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
1620+
/// # let client: helix::HelixClient<'static, twitch_api::client::DummyHttpClient> = helix::HelixClient::default();
1621+
/// # let token = twitch_oauth2::AccessToken::new("validtoken".to_string());
1622+
/// # let token = twitch_oauth2::UserToken::from_existing(&client, token, None, None).await?;
1623+
/// use twitch_api::helix;
1624+
///
1625+
/// let labels: Vec<helix::ccls::ContentClassificationLabel> = client
1626+
/// .get_content_classification_labels_for_locale("fi-FI", &token)
1627+
/// .await?;
1628+
/// # Ok(()) }
1629+
/// ```
1630+
pub async fn get_content_classification_labels_for_locale<'b, T>(
1631+
&'client self,
1632+
locale: impl Into<Cow<'b, str>> + 'b + Send,
1633+
token: &'client T,
1634+
) -> Result<Vec<helix::ccls::ContentClassificationLabel>, ClientError<C>>
1635+
where
1636+
T: TwitchToken + Send + Sync + ?Sized,
1637+
{
1638+
self.req_get(
1639+
helix::ccls::GetContentClassificationLabelsRequest::locale(locale),
1640+
token,
1641+
)
1642+
.await
1643+
.map(|res| res.data)
1644+
}
1645+
15811646
#[cfg(feature = "eventsub")]
15821647
/// Create an [EventSub](crate::eventsub) subscription
15831648
pub async fn create_eventsub_subscription<T, E: crate::eventsub::EventSubscription + Send>(
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
//! Gets information about Twitch content classification labels.
2+
//! [`get-content-classification-labels`](https://dev.twitch.tv/docs/api/reference#get-content-classification-labels)
3+
//!
4+
//! # Accessing the endpoint
5+
//!
6+
//! ## Request: [GetContentClassificationLabelsRequest]
7+
//!
8+
//! To use this endpoint, construct a [`GetContentClassificationLabelsRequest`] with the [`GetContentClassificationLabelsRequest::new()`] or [`GetContentClassificationLabelsRequest::locale()`] methods.
9+
//!
10+
//! ```rust, no_run
11+
//! use twitch_api::helix::ccls::get_content_classification_labels;
12+
//! let request =
13+
//! get_content_classification_labels::GetContentClassificationLabelsRequest::new();
14+
//! // Get content classification labels for a specific locale
15+
//! let request = get_content_classification_labels::GetContentClassificationLabelsRequest::locale("es-MX");
16+
//! ```
17+
//!
18+
//! ## Response: [ContentClassificationLabel]
19+
//!
20+
//! Send the request to receive the response with [`HelixClient::req_get()`](helix::HelixClient::req_get).
21+
//!
22+
//! ```rust, no_run
23+
//! use twitch_api::helix::{self, ccls::get_content_classification_labels};
24+
//! # use twitch_api::client;
25+
//! # #[tokio::main]
26+
//! # async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
27+
//! # let client: helix::HelixClient<'static, client::DummyHttpClient> = helix::HelixClient::default();
28+
//! # let token = twitch_oauth2::AccessToken::new("validtoken".to_string());
29+
//! # let token = twitch_oauth2::UserToken::from_existing(&client, token, None, None).await?;
30+
//! let request = get_content_classification_labels::GetContentClassificationLabelsRequest::new();
31+
//! let response: Vec<get_content_classification_labels::ContentClassificationLabel> = client.req_get(request, &token).await?.data;
32+
//! # Ok(())
33+
//! # }
34+
//! ```
35+
//!
36+
//! You can also get the [`http::Request`] with [`request.create_request(&token, &client_id)`](helix::RequestGet::create_request)
37+
//! and parse the [`http::Response`] with [`GetContentClassificationLabelsRequest::parse_response(None, &request.get_uri(), response)`](GetContentClassificationLabelsRequest::parse_response)
38+
use super::*;
39+
use helix::RequestGet;
40+
41+
/// Query Parameters for [Get Content Classification Labels](super::get_content_classification_labels)
42+
///
43+
/// [`get-content-classification-labels`](https://dev.twitch.tv/docs/api/reference#get-content-classification-labels)
44+
#[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)]
45+
#[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))]
46+
#[must_use]
47+
#[non_exhaustive]
48+
pub struct GetContentClassificationLabelsRequest<'a> {
49+
/// Locale for the Content Classification Labels. You may specify a maximum of 1 locale. Default: `"en-US"`
50+
///
51+
/// Supported locales: `"bg-BG", "cs-CZ", "da-DK", "da-DK", "de-DE", "el-GR", "en-GB", "en-US", "es-ES", "es-MX", "fi-FI", "fr-FR", "hu-HU", "it-IT", "ja-JP", "ko-KR", "nl-NL", "no-NO", "pl-PL", "pt-BT", "pt-PT", "ro-RO", "ru-RU", "sk-SK", "sv-SE", "th-TH", "tr-TR", "vi-VN", "zh-CN", "zh-TW"`
52+
#[cfg_attr(feature = "typed-builder", builder(default, setter(into)))]
53+
#[cfg_attr(feature = "deser_borrow", serde(borrow = "'a"))]
54+
pub locale: Option<Cow<'a, str>>,
55+
}
56+
57+
impl<'a> GetContentClassificationLabelsRequest<'a> {
58+
/// Request content classification labels for some locale
59+
pub fn locale(locale: impl Into<Cow<'a, str>>) -> Self {
60+
Self {
61+
locale: Some(locale.into()),
62+
}
63+
}
64+
65+
/// Returns an new [`GetContentClassificationLabelsRequest`]
66+
pub fn new() -> Self { Self::default() }
67+
}
68+
69+
/// Return Values for [Get Content Classification Labels](super::get_content_classification_labels)
70+
///
71+
/// [`get-content-classification-labels`](https://dev.twitch.tv/docs/api/reference#get-content-classification-labels)
72+
#[derive(PartialEq, Eq, Deserialize, Serialize, Debug, Clone)]
73+
#[cfg_attr(feature = "deny_unknown_fields", serde(deny_unknown_fields))]
74+
#[non_exhaustive]
75+
pub struct ContentClassificationLabel {
76+
/// Unique identifier for the CCL.
77+
pub id: types::ContentClassificationId,
78+
/// Localized description of the CCL.
79+
pub description: String,
80+
/// Localized name of the CCL.
81+
pub name: String,
82+
}
83+
84+
impl Request for GetContentClassificationLabelsRequest<'_> {
85+
type Response = Vec<ContentClassificationLabel>;
86+
87+
const PATH: &'static str = "content_classification_labels";
88+
#[cfg(feature = "twitch_oauth2")]
89+
const SCOPE: twitch_oauth2::Validator = twitch_oauth2::validator![];
90+
}
91+
92+
impl RequestGet for GetContentClassificationLabelsRequest<'_> {}
93+
94+
#[cfg(test)]
95+
#[test]
96+
fn test_request() {
97+
use helix::*;
98+
let req = GetContentClassificationLabelsRequest::new();
99+
100+
// From api call
101+
let data = br#"
102+
{
103+
"data": [
104+
{
105+
"description": "Discussions or debates about politics or sensitive social issues such as elections, civic integrity, military conflict, and civil rights in a polarizing manner.",
106+
"id": "DebatedSocialIssuesAndPolitics",
107+
"name": "Politics and Sensitive Social Issues"
108+
},
109+
{
110+
"description": "Excessive tobacco glorification or promotion, any marijuana consumption/use, legal drug and alcohol induced intoxication, discussions of illegal drugs.",
111+
"id": "DrugsIntoxication",
112+
"name": "Drugs, Intoxication, or Excessive Tobacco Use"
113+
},
114+
{
115+
"description": "Participating in online or in-person gambling, poker or fantasy sports, that involve the exchange of real money.",
116+
"id": "Gambling",
117+
"name": "Gambling"
118+
},
119+
{
120+
"description": "Games that are rated Mature or less suitable for a younger audience.",
121+
"id": "MatureGame",
122+
"name": "Mature-rated game"
123+
},
124+
{
125+
"description": "Prolonged, and repeated use of obscenities, profanities, and vulgarities, especially as a regular part of speech.",
126+
"id": "ProfanityVulgarity",
127+
"name": "Significant Profanity or Vulgarity"
128+
},
129+
{
130+
"description": "Content that focuses on sexualized physical attributes and activities, sexual topics, or experiences.",
131+
"id": "SexualThemes",
132+
"name": "Sexual Themes"
133+
},
134+
{
135+
"description": "Simulations and/or depictions of realistic violence, gore, extreme injury, or death.",
136+
"id": "ViolentGraphic",
137+
"name": "Violent and Graphic Depictions"
138+
}
139+
]
140+
}
141+
"#
142+
.to_vec();
143+
144+
let http_response = http::Response::builder().body(data).unwrap();
145+
146+
let uri = req.get_uri().unwrap();
147+
assert_eq!(
148+
uri.to_string(),
149+
"https://api.twitch.tv/helix/content_classification_labels?"
150+
);
151+
152+
let res = GetContentClassificationLabelsRequest::parse_response(Some(req), &uri, http_response)
153+
.unwrap()
154+
.data;
155+
156+
assert_eq!(res.len(), 7);
157+
158+
assert_eq!(res[0].description, "Discussions or debates about politics or sensitive social issues such as elections, civic integrity, military conflict, and civil rights in a polarizing manner.");
159+
assert_eq!(res[0].name, "Politics and Sensitive Social Issues");
160+
161+
assert_eq!(
162+
res[0].id,
163+
types::ContentClassificationId::DebatedSocialIssuesAndPolitics
164+
);
165+
assert_eq!(res[1].id, types::ContentClassificationId::DrugsIntoxication);
166+
assert_eq!(res[2].id, types::ContentClassificationId::Gambling);
167+
assert_eq!(res[3].id, types::ContentClassificationId::MatureGame);
168+
assert_eq!(
169+
res[4].id,
170+
types::ContentClassificationId::ProfanityVulgarity
171+
);
172+
assert_eq!(res[5].id, types::ContentClassificationId::SexualThemes);
173+
assert_eq!(res[6].id, types::ContentClassificationId::ViolentGraphic);
174+
}
175+
176+
#[cfg(test)]
177+
#[test]
178+
fn test_request_locale() {
179+
use helix::*;
180+
let req = GetContentClassificationLabelsRequest::locale("th-TH");
181+
182+
let uri = req.get_uri().unwrap();
183+
assert_eq!(
184+
uri.to_string(),
185+
"https://api.twitch.tv/helix/content_classification_labels?locale=th-TH"
186+
);
187+
}

src/helix/endpoints/ccls/mod.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//! Helix endpoints regarding content classification cabels
2+
//!
3+
//! # Examples
4+
//!
5+
//! ```rust,no_run
6+
//! # use twitch_api::helix::{HelixClient, ccls::GetContentClassificationLabelsRequest};
7+
//! # #[tokio::main]
8+
//! # async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
9+
//! let client = HelixClient::default();
10+
//! # let _: &HelixClient<twitch_api::DummyHttpClient> = &client;
11+
//! # let token = twitch_oauth2::AccessToken::new("validtoken".to_string());
12+
//! # let token = twitch_oauth2::UserToken::from_existing(&client, token, None, None).await?;
13+
//! let req = GetContentClassificationLabelsRequest::new();
14+
//!
15+
//! println!("{:?}", &client.req_get(req, &token).await?.data);
16+
//! # Ok(())
17+
//! # }
18+
//! ```
19+
//!
20+
//! # Implemented endpoints
21+
//!
22+
//! <!-- generate with "cargo xtask overview" (with a nightly toolchain) -->
23+
//! <!-- BEGIN-OVERVIEW -->
24+
//! <details open><summary style="cursor: pointer">CCLs 🟢 1/1</summary>
25+
//!
26+
//! | Endpoint | Helper | Module |
27+
//! |---|---|---|
28+
//! | [Get Content Classification Labels](https://dev.twitch.tv/docs/api/reference#get-content-classification-labels) | [`HelixClient::get_content_classification_labels`](crate::helix::HelixClient::get_content_classification_labels), [`HelixClient::get_content_classification_labels_for_locale`](crate::helix::HelixClient::get_content_classification_labels_for_locale) | [`get_content_classification_labels`] |
29+
//!
30+
//! </details>
31+
//!
32+
//! <!-- END-OVERVIEW -->
33+
34+
use crate::{
35+
helix::{self, Request},
36+
types,
37+
};
38+
use serde_derive::{Deserialize, Serialize};
39+
use std::borrow::Cow;
40+
41+
pub mod get_content_classification_labels;
42+
43+
#[doc(inline)]
44+
pub use get_content_classification_labels::{
45+
ContentClassificationLabel, GetContentClassificationLabelsRequest,
46+
};

src/helix/endpoints/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod bits;
2+
pub mod ccls;
23
pub mod channels;
34
pub mod charity;
45
pub mod chat;

src/helix/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@
6363
//!
6464
//! </details>
6565
//!
66-
//! <details><summary style="cursor: pointer">CCLs 🔴 0/1</summary>
66+
//! <details><summary style="cursor: pointer">CCLs 🟢 1/1</summary>
6767
//!
6868
//! | Endpoint | Helper | Module |
6969
//! |---|---|---|
70-
//! | [Get Content Classification Labels](https://dev.twitch.tv/docs/api/reference#get-content-classification-labels) | - | - |
70+
//! | [Get Content Classification Labels](https://dev.twitch.tv/docs/api/reference#get-content-classification-labels) | [`HelixClient::get_content_classification_labels`], [`HelixClient::get_content_classification_labels_for_locale`] | [`ccls::get_content_classification_labels`] |
7171
//!
7272
//! </details>
7373
//!

xtask/src/collect_endpoints/helix.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ pub fn distance(src: &str, tar: &str) -> usize {
264264
"from_logins",
265265
"from_login",
266266
"description",
267+
"for_locale",
267268
];
268269

269270
fn remove_ignored_phrases(s: &str, ignore_phrases: &[&str]) -> String {

0 commit comments

Comments
 (0)