diff options
author | Matthias Wahl <mfelsche@users.noreply.github.com> | 2022-04-19 16:58:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-19 16:58:29 +0200 |
commit | 0941fd5190f37d0e47844fb21b04c124b796ea94 (patch) | |
tree | 1abbd56c1db0994a7a33440fefc05f2a712deb94 | |
parent | e24bb4b67c3f990b745d4365dbfcb3805fdd41e8 (diff) |
Support for Updating gists via PATCH (#195)
* Support Updating Gists via Patch
* Add documentation to gist builder methods.
* Ensure that we don't delete files by accident when misusing the builder for updating gist files.
-rw-r--r-- | src/api/gists.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/api/gists.rs b/src/api/gists.rs index 4695b57..88948a6 100644 --- a/src/api/gists.rs +++ b/src/api/gists.rs @@ -20,6 +20,7 @@ impl<'octo> GistsHandler<'octo> { } /// Create a new gist. + /// /// ```no_run /// # async fn run() -> octocrab::Result<()> { /// let gitignore = octocrab::instance() @@ -38,7 +39,31 @@ impl<'octo> GistsHandler<'octo> { CreateGistBuilder::new(self.crab) } + /// Update an existing gist. + /// + /// ```no_run + /// # async fn run() -> octocrab::Result<()> { + /// let gitignore = octocrab::instance() + /// .gists() + /// .update("aa5a315d61ae9438b18d") + /// // Optional Parameters + /// .description("Updated!") + /// .file("hello_world.rs") + /// .rename_to("fibonacci.rs") + /// .with_content("fn main() {\n println!(\"I should be a Fibonacci!\");\n}") + /// .file("delete_me.rs") + /// .delete() + /// .send() + /// .await?; + /// # Ok(()) + /// # } + /// ``` + pub fn update(&self, id: impl AsRef<str>) -> UpdateGistBuilder<'octo> { + UpdateGistBuilder::new(self.crab, format!("gists/{id}", id=id.as_ref())) + } + /// Get a single gist. + /// /// ```no_run /// # async fn run() -> octocrab::Result<()> { /// let gist = octocrab::instance().gists().get("00000000000000000000000000000000").await?; @@ -106,16 +131,19 @@ impl<'octo> CreateGistBuilder<'octo> { } } + /// Set a description for the gist to be created. pub fn description(mut self, description: impl Into<String>) -> Self { self.data.description = Some(description.into()); self } + /// Set the `public` flag of the gist to be created. pub fn public(mut self, public: bool) -> Self { self.data.public = Some(public); self } + /// Add a file to the gist with `filename` and `content`. pub fn file(mut self, filename: impl Into<String>, content: impl Into<String>) -> Self { let file = CreateGistFile { filename: Default::default(), @@ -125,6 +153,7 @@ impl<'octo> CreateGistBuilder<'octo> { self } + /// Send the `CreateGist` request to Github for execution. pub async fn send(self) -> Result<Gist> { self.crab.post("gists", Some(&self.data)).await } @@ -145,3 +174,119 @@ struct CreateGistFile { filename: Option<String>, content: String, } + +#[derive(Debug)] +pub struct UpdateGistBuilder<'octo> { + crab: &'octo Octocrab, + gist_path: String, + data: UpdateGist +} + +impl<'octo> UpdateGistBuilder<'octo> { + fn new(crab: &'octo Octocrab, gist_path: String) -> Self { + Self { + crab, + gist_path, + data: Default::default() + } + } + + /// Update the description of the the gist with the content provided by `description`. + pub fn description(mut self, description: impl Into<String>) -> Self { + self.data.description = Some(description.into()); + self + } + + /// Update the file with the `filename`. + /// + /// The update operation is chosen in further calls to the returned builder. + pub fn file(self, filename: impl Into<String>) -> UpdateGistFileBuilder<'octo> { + UpdateGistFileBuilder::new(self, filename) + } + + /// Send the `UpdateGist` command to Github for execution. + pub async fn send(self) -> Result<Gist> { + self.crab.patch(self.gist_path, Some(&self.data)).await + } +} + +#[derive(Debug, Default, Serialize)] +struct UpdateGist { + #[serde(skip_serializing_if = "Option::is_none")] + description: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] + files: Option<BTreeMap<String, Option<UpdateGistFile>>> +} + +#[derive(Debug, Default, Serialize)] +pub struct UpdateGistFile { + filename: Option<String>, + content: Option<String> +} + +pub struct UpdateGistFileBuilder<'octo> { + builder: UpdateGistBuilder<'octo>, + filename: String, + file: Option<UpdateGistFile>, + ready: bool +} + +impl<'octo> UpdateGistFileBuilder<'octo> { + fn new(builder: UpdateGistBuilder<'octo>, filename: impl Into<String>) -> Self { + Self { + builder, + filename: filename.into(), + file: None, + ready: false + } + } + + fn build(mut self) -> UpdateGistBuilder<'octo> { + if self.ready { + self.builder.data.files.get_or_insert_with(BTreeMap::new).insert(self.filename, self.file); + } + self.builder + } + + /// Delete the file from the gist. + pub fn delete(mut self) -> UpdateGistBuilder<'octo> { + self.ready = true; + self.file = None; + self.build() + } + + /// Rename the file to `filename`. + pub fn rename_to(mut self, filename: impl Into<String>) -> Self { + self.ready = true; + self.file.get_or_insert_with(Default::default).filename = Some(filename.into()); + self + } + + /// Update the content of the file and overwrite it with `content`. + pub fn with_content(mut self, content: impl Into<String>) -> Self { + self.ready = true; + self.file.get_or_insert_with(Default::default).content = Some(content.into()); + self + } + + /// Overwrite the Description of the gist with `description`. + /// + /// This will finalize the update operation and will continue to operate on the gist itself. + pub fn description(self, description: impl Into<String>) -> UpdateGistBuilder<'octo> { + self.build().description(description) + } + + /// Update the next file identified by `filename`. + /// + /// This will finalize the update operation and will continue to operate on the gist itself. + pub fn file(self, filename: impl Into<String>) -> UpdateGistFileBuilder<'octo> { + self.build().file(filename) + } + + /// Send the `UpdateGist` command to Github for execution. + /// + /// This will finalize the update operation before sending. + pub async fn send(self) -> Result<Gist> { + self.build().send().await + } +} |