jinxapi_github/v1_1_4/request/
repos_add_collaborator.rs

1//! Add a repository collaborator
2//! 
3//! This endpoint triggers [notifications](https://docs.github.com/github/managing-subscriptions-and-notifications-on-github/about-notifications). Creating content too quickly using this endpoint may result in secondary rate limiting. See "[Secondary rate limits](https://docs.github.com/rest/overview/resources-in-the-rest-api#secondary-rate-limits)" and "[Dealing with secondary rate limits](https://docs.github.com/rest/guides/best-practices-for-integrators#dealing-with-secondary-rate-limits)" for details.
4//! 
5//! Adding an outside collaborator may be restricted by enterprise administrators. For more information, see "[Enforcing repository management policies in your enterprise](https://docs.github.com/enterprise-cloud@latest/admin/policies/enforcing-policies-for-your-enterprise/enforcing-repository-management-policies-in-your-enterprise#enforcing-a-policy-for-inviting-outside-collaborators-to-repositories)."
6//! 
7//! For more information on permission levels, see "[Repository permission levels for an organization](https://docs.github.com/github/setting-up-and-managing-organizations-and-teams/repository-permission-levels-for-an-organization#permission-levels-for-repositories-owned-by-an-organization)". There are restrictions on which permissions can be granted to organization members when an organization base role is in place. In this case, the permission being given must be equal to or higher than the org base permission. Otherwise, the request will fail with:
8//! 
9//! ```text
10//! Cannot assign {member} permission of {role name}
11//! ```
12//! 
13//! Note that, if you choose not to pass any parameters, you'll need to set `Content-Length` to zero when calling out to this endpoint. For more information, see "[HTTP verbs](https://docs.github.com/rest/overview/resources-in-the-rest-api#http-verbs)."
14//! 
15//! The invitee will receive a notification that they have been invited to the repository, which they must accept or decline. They may do this via the notifications page, the email they receive, or by using the [repository invitations API endpoints](https://docs.github.com/rest/reference/repos#invitations).
16//! 
17//! **Updating an existing collaborator's permission level**
18//! 
19//! The endpoint can also be used to change the permissions of an existing collaborator without first removing and re-adding the collaborator. To change the permissions, use the same endpoint and pass a different `permission` parameter. The response will be a `204`, with no other indication that the permission level changed.
20//! 
21//! **Rate limits**
22//! 
23//! You are limited to sending 50 invitations to a repository per 24 hour period. Note there is no limit if you are inviting organization members to an organization repository.
24//! 
25//! [API method documentation](https://docs.github.com/rest/reference/repos#add-a-repository-collaborator)
26
27pub struct Content<Body>
28{
29    body: Body,
30    content_type_value: Option<::std::borrow::Cow<'static, [u8]>>,
31}
32
33impl<Body> Content<Body> {
34    pub fn new(body: Body) -> Self {
35        Self { body, content_type_value: None }
36    }
37
38    #[must_use]
39    pub fn with_content_type(mut self, content_type: impl Into<::std::borrow::Cow<'static, [u8]>>) -> Self {
40        self.content_type_value = Some(content_type.into());
41        self
42    }
43
44    fn content_type(&self) -> Option<&[u8]> {
45        self.content_type_value.as_deref()
46    }
47
48    fn into_body(self) -> Body {
49        self.body
50    }
51}
52
53fn url_string(
54    base_url: &str,
55    p_owner: &str,
56    p_repo: &str,
57    p_username: &str,
58) -> Result<String, crate::v1_1_4::ApiError> {
59    let trimmed = if base_url.is_empty() {
60        "https://api.github.com"
61    } else {
62        base_url.trim_end_matches('/')
63    };
64    let mut url = String::with_capacity(trimmed.len() + 42);
65    url.push_str(trimmed);
66    url.push_str("/repos/");
67    ::querylizer::Simple::extend(&mut url, &p_owner, false, &::querylizer::encode_path)?;
68    url.push('/');
69    ::querylizer::Simple::extend(&mut url, &p_repo, false, &::querylizer::encode_path)?;
70    url.push_str("/collaborators/");
71    ::querylizer::Simple::extend(&mut url, &p_username, false, &::querylizer::encode_path)?;
72    Ok(url)
73}
74
75#[cfg(feature = "hyper")]
76pub fn http_builder(
77    base_url: &str,
78    p_owner: &str,
79    p_repo: &str,
80    p_username: &str,
81    h_user_agent: &str,
82    h_accept: ::std::option::Option<&str>,
83) -> Result<::http::request::Builder, crate::v1_1_4::ApiError> {
84    let url = url_string(
85        base_url,
86        p_owner,
87        p_repo,
88        p_username,
89    )?;
90    let mut builder = ::http::request::Request::put(url);
91    builder = builder.header(
92        "User-Agent",
93        &::querylizer::Simple::to_string(&h_user_agent, false, &::querylizer::passthrough)?
94    );
95    if let Some(value) = &h_accept {
96        builder = builder.header(
97            "Accept",
98            &::querylizer::Simple::to_string(value, false, &::querylizer::passthrough)?
99        );
100    }
101    Ok(builder)
102}
103
104#[cfg(feature = "hyper")]
105pub fn hyper_request(
106    mut builder: ::http::request::Builder,
107    content: Content<::hyper::Body>,
108) -> Result<::http::request::Request<::hyper::Body>, crate::v1_1_4::ApiError>
109{
110    if let Some(content_type) = content.content_type() {
111        builder = builder.header(::http::header::CONTENT_TYPE, content_type);
112    }
113    Ok(builder.body(content.into_body())?)
114}
115
116#[cfg(feature = "hyper")]
117impl From<::hyper::Body> for Content<::hyper::Body> {
118    fn from(body: ::hyper::Body) -> Self {
119        Self::new(body)
120    }
121}
122
123#[cfg(feature = "reqwest")]
124pub fn reqwest_builder(
125    base_url: &str,
126    p_owner: &str,
127    p_repo: &str,
128    p_username: &str,
129    h_user_agent: &str,
130    h_accept: ::std::option::Option<&str>,
131) -> Result<::reqwest::Request, crate::v1_1_4::ApiError> {
132    let url = url_string(
133        base_url,
134        p_owner,
135        p_repo,
136        p_username,
137    )?;
138    let reqwest_url = ::reqwest::Url::parse(&url)?;
139    let mut request = ::reqwest::Request::new(::reqwest::Method::PUT, reqwest_url);
140    let headers = request.headers_mut();
141    headers.append(
142        "User-Agent",
143        ::querylizer::Simple::to_string(&h_user_agent, false, &::querylizer::passthrough)?.try_into()?
144    );
145    if let Some(value) = &h_accept {
146        headers.append(
147            "Accept",
148            ::querylizer::Simple::to_string(value, false, &::querylizer::passthrough)?.try_into()?
149        );
150    }
151    Ok(request)
152}
153
154#[cfg(feature = "reqwest")]
155pub fn reqwest_request(
156    mut builder: ::reqwest::Request,
157    content: Content<::reqwest::Body>,
158) -> Result<::reqwest::Request, crate::v1_1_4::ApiError> {
159    if let Some(content_type) = content.content_type() {
160        builder.headers_mut().append(
161            ::reqwest::header::HeaderName::from_static("content-type"),
162            ::reqwest::header::HeaderValue::try_from(content_type)?,
163        );
164    }
165    *builder.body_mut() = Some(content.into_body());
166    Ok(builder)
167}
168
169#[cfg(feature = "reqwest")]
170impl From<::reqwest::Body> for Content<::reqwest::Body> {
171    fn from(body: ::reqwest::Body) -> Self {
172        Self::new(body)
173    }
174}
175
176#[cfg(feature = "reqwest-blocking")]
177pub fn reqwest_blocking_builder(
178    base_url: &str,
179    p_owner: &str,
180    p_repo: &str,
181    p_username: &str,
182    h_user_agent: &str,
183    h_accept: ::std::option::Option<&str>,
184) -> Result<::reqwest::blocking::Request, crate::v1_1_4::ApiError> {
185    let url = url_string(
186        base_url,
187        p_owner,
188        p_repo,
189        p_username,
190    )?;
191    let reqwest_url = ::reqwest::Url::parse(&url)?;
192    let mut request = ::reqwest::blocking::Request::new(::reqwest::Method::PUT, reqwest_url);
193    let headers = request.headers_mut();
194    headers.append(
195        "User-Agent",
196        ::querylizer::Simple::to_string(&h_user_agent, false, &::querylizer::passthrough)?.try_into()?
197    );
198    if let Some(value) = &h_accept {
199        headers.append(
200            "Accept",
201            ::querylizer::Simple::to_string(value, false, &::querylizer::passthrough)?.try_into()?
202        );
203    }
204    Ok(request)
205}
206
207#[cfg(feature = "reqwest-blocking")]
208pub fn reqwest_blocking_request(
209    mut builder: ::reqwest::blocking::Request,
210    content: Content<::reqwest::blocking::Body>,
211) -> Result<::reqwest::blocking::Request, crate::v1_1_4::ApiError> {
212    if let Some(content_type) = content.content_type() {
213        builder.headers_mut().append(
214            ::reqwest::header::HeaderName::from_static("content-type"),
215            ::reqwest::header::HeaderValue::try_from(content_type)?,
216        );
217    }
218    *builder.body_mut() = Some(content.into_body());
219    Ok(builder)
220}
221
222#[cfg(feature = "reqwest-blocking")]
223impl From<::reqwest::blocking::Body> for Content<::reqwest::blocking::Body> {
224    fn from(body: ::reqwest::blocking::Body) -> Self {
225        Self::new(body)
226    }
227}
228
229/// Types for body parameter in [`super::repos_add_collaborator`]
230pub mod body {
231    #[allow(non_snake_case)]
232    #[derive(Clone, Eq, PartialEq, Debug, Default, ::serde::Serialize, ::serde::Deserialize)]
233    pub struct Json<'a> {
234        /// The permission to grant the collaborator. **Only valid on organization-owned repositories.** Can be one of:  
235        /// \* `pull` - can pull, but not push to or administer this repository.  
236        /// \* `push` - can pull and push, but not administer this repository.  
237        /// \* `admin` - can pull, push and administer this repository.  
238        /// \* `maintain` - Recommended for project managers who need to manage the repository without access to sensitive or destructive actions.  
239        /// \* `triage` - Recommended for contributors who need to proactively manage issues and pull requests without write access.  
240        /// \* custom repository role name - A custom repository role, if the owning organization has defined any.
241        #[serde(skip_serializing_if = "Option::is_none", default)]
242        pub permission: ::std::option::Option<::std::borrow::Cow<'a, str>>,
243
244        /// # Example
245        /// 
246        /// ```json
247        /// "\"push\""
248        /// ```
249        #[serde(skip_serializing_if = "Option::is_none", default)]
250        pub permissions: ::std::option::Option<::std::borrow::Cow<'a, str>>,
251
252        #[serde(flatten)]
253        pub additionalProperties: ::std::collections::HashMap<::std::borrow::Cow<'a, str>, ::serde_json::value::Value>
254    }
255
256    #[cfg(feature = "hyper")]
257    impl<'a> TryFrom<&Json<'a>> for super::Content<::hyper::Body> {
258        type Error = crate::v1_1_4::ApiError;
259
260        fn try_from(value: &Json<'a>) -> Result<Self, Self::Error> {
261            Ok(
262                Self::new(::serde_json::to_vec(value)?.into())
263                .with_content_type(&b"application/json"[..])
264            )
265        }
266    }
267
268    #[cfg(feature = "reqwest")]
269    impl<'a> TryFrom<&Json<'a>> for super::Content<::reqwest::Body> {
270        type Error = crate::v1_1_4::ApiError;
271
272        fn try_from(value: &Json<'a>) -> Result<Self, Self::Error> {
273            Ok(
274                Self::new(::serde_json::to_vec(value)?.into())
275                .with_content_type(&b"application/json"[..])
276            )
277        }
278    }
279
280    #[cfg(feature = "reqwest-blocking")]
281    impl<'a> TryFrom<&Json<'a>> for super::Content<::reqwest::blocking::Body> {
282        type Error = crate::v1_1_4::ApiError;
283
284        fn try_from(value: &Json<'a>) -> Result<Self, Self::Error> {
285            Ok(
286                Self::new(::serde_json::to_vec(value)?.into())
287                .with_content_type(&b"application/json"[..])
288            )
289        }
290    }
291}