Skip to content

Commit

Permalink
Add support for updating full contents
Browse files Browse the repository at this point in the history
  • Loading branch information
augustuswm committed Apr 16, 2024
1 parent 7443c66 commit 6532004
Show file tree
Hide file tree
Showing 9 changed files with 516 additions and 17 deletions.
71 changes: 71 additions & 0 deletions rfd-api-spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,7 @@
{
"in": "path",
"name": "number",
"description": "The RFD number (examples: 1 or 123)",
"required": true,
"schema": {
"type": "string"
Expand All @@ -1250,6 +1251,52 @@
"$ref": "#/components/responses/Error"
}
}
},
"post": {
"operationId": "set_rfd_content",
"parameters": [
{
"in": "path",
"name": "number",
"description": "The RFD number (examples: 1 or 123)",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RfdUpdateBody"
}
}
},
"required": true
},
"responses": {
"202": {
"description": "successfully enqueued operation",
"content": {
"application/json": {
"schema": {
"title": "Null",
"type": "string",
"enum": [
null
]
}
}
}
},
"4XX": {
"$ref": "#/components/responses/Error"
},
"5XX": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/rfd/{number}/attr/{attr}": {
Expand Down Expand Up @@ -1352,6 +1399,7 @@
{
"in": "path",
"name": "number",
"description": "The RFD number (examples: 1 or 123)",
"required": true,
"schema": {
"type": "string"
Expand Down Expand Up @@ -4505,7 +4553,13 @@
"RfdAttrValue": {
"type": "object",
"properties": {
"message": {
"nullable": true,
"description": "Optional Git commit message to send with this update (recommended)",
"type": "string"
},
"value": {
"description": "Full value to set this attribute to in the existing RFD contents",
"type": "string"
}
},
Expand All @@ -4524,6 +4578,23 @@
"published"
]
},
"RfdUpdateBody": {
"type": "object",
"properties": {
"content": {
"description": "Full Asciidoc content to store for this RFD",
"type": "string"
},
"message": {
"nullable": true,
"description": "Optional Git commit message to send with this update (recommended)",
"type": "string"
}
},
"required": [
"content"
]
},
"RfdVisibility": {
"type": "object",
"properties": {
Expand Down
9 changes: 8 additions & 1 deletion rfd-api/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,7 @@ impl ApiContext {
caller: &ApiCaller,
rfd_number: i32,
content: &str,
message: Option<&str>,
) -> ResourceResult<(), UpdateRfdContentError> {
if caller.any(&[
&ApiPermission::UpdateRfd(rfd_number),
Expand Down Expand Up @@ -831,10 +832,16 @@ impl ApiContext {
Err(ResourceError::DoesNotExist)
}
1 => {
let message = format!(
"{}\n\nSubmitted by {}",
message.unwrap_or("RFD API update"),
caller.id
);

// Unwrap is checked by the location length
let location = github_locations.pop().unwrap();
location
.upsert(&rfd_number.into(), content.as_bytes())
.upsert(&rfd_number.into(), content.as_bytes(), &message)
.await
.map_err(UpdateRfdContentError::GitHub)
.to_resource_result()?;
Expand Down
74 changes: 67 additions & 7 deletions rfd-api/src/endpoints/rfd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use dropshot::{endpoint, HttpError, HttpResponseOk, Path, Query, RequestContext, TypedBody};
use dropshot::{
endpoint, HttpError, HttpResponseAccepted, HttpResponseOk, Path, Query, RequestContext,
TypedBody,
};
use http::StatusCode;
use rfd_data::{
content::{RfdAsciidoc, RfdContent, RfdDocument, RfdMarkdown},
Expand All @@ -28,6 +31,7 @@ use crate::{

#[derive(Debug, Deserialize, JsonSchema)]
pub struct RfdPathParams {
/// The RFD number (examples: 1 or 123)
number: String,
}

Expand Down Expand Up @@ -92,6 +96,58 @@ async fn get_rfd_op(
}
}

#[derive(Debug, Deserialize, JsonSchema)]
pub struct RfdUpdateBody {
/// Full Asciidoc content to store for this RFD
content: String,
/// Optional Git commit message to send with this update (recommended)
message: Option<String>,
}

#[trace_request]
#[endpoint {
method = POST,
path = "/rfd/{number}",
}]
pub async fn set_rfd_content(
rqctx: RequestContext<ApiContext>,
path: Path<RfdPathParams>,
body: TypedBody<RfdUpdateBody>,
) -> Result<HttpResponseAccepted<()>, HttpError> {
let ctx = rqctx.context();
let auth = ctx.authn_token(&rqctx).await?;
set_rfd_content_op(
ctx,
&ctx.get_caller(auth.as_ref()).await?,
path.into_inner().number,
body.into_inner(),
)
.await
}

async fn set_rfd_content_op(
ctx: &ApiContext,
caller: &ApiCaller,
number: String,
body: RfdUpdateBody,
) -> Result<HttpResponseAccepted<()>, HttpError> {
if let Ok(rfd_number) = number.parse::<i32>() {
ctx.update_rfd_content(
caller,
rfd_number.into(),
&body.content,
body.message.as_deref(),
)
.await?;
Ok(HttpResponseAccepted(()))
} else {
Err(client_error(
StatusCode::BAD_REQUEST,
"Malformed RFD number",
))
}
}

#[derive(Debug, Deserialize, JsonSchema)]
pub struct RfdAttrPathParams {
number: String,
Expand Down Expand Up @@ -162,7 +218,10 @@ async fn get_rfd_attr_op(

#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct RfdAttrValue {
/// Full value to set this attribute to in the existing RFD contents
value: String,
/// Optional Git commit message to send with this update (recommended)
message: Option<String>,
}

/// Set an attribute of a given RFD
Expand All @@ -185,7 +244,7 @@ pub async fn set_rfd_attr(
&ctx.get_caller(auth.as_ref()).await?,
path.number,
path.attr,
body.into_inner().value,
&body.into_inner(),
)
.await
}
Expand All @@ -196,7 +255,7 @@ async fn set_rfd_attr_op(
caller: &ApiCaller,
number: String,
attr: RfdAttrName,
value: String,
body: &RfdAttrValue,
) -> Result<HttpResponseOk<RfdAttr>, HttpError> {
if let Ok(rfd_number) = number.parse::<i32>() {
// Get the latest revision
Expand All @@ -210,10 +269,10 @@ async fn set_rfd_attr_op(

// Update the requested attribute
match &attr {
RfdAttrName::Discussion => content.update_discussion(&value),
RfdAttrName::Labels => content.update_labels(&value),
RfdAttrName::Discussion => content.update_discussion(&body.value),
RfdAttrName::Labels => content.update_labels(&body.value),
RfdAttrName::State => {
let state: RfdState = value.as_str().try_into().map_err(|err| {
let state: RfdState = body.value.as_str().try_into().map_err(|err| {
tracing::info!(?err, "Invalid state was supplied");
HttpError::for_bad_request(None, "Invalid RFD state".to_string())
})?;
Expand All @@ -224,7 +283,7 @@ async fn set_rfd_attr_op(
// Persist the data back to GitHub. Note that we do not store this back to the database.
// We rely on GitHub as the source of truth and revisions are required to tbe linked to
// commits
ctx.update_rfd_content(caller, rfd_number, content.raw())
ctx.update_rfd_content(caller, rfd_number, content.raw(), body.message.as_deref())
.await?;

extract_attr(&attr, &content)
Expand Down Expand Up @@ -414,6 +473,7 @@ async fn search_rfds_op(

#[derive(Debug, Deserialize, JsonSchema)]
pub struct RfdVisibility {
///
pub visibility: Visibility,
}

Expand Down
7 changes: 6 additions & 1 deletion rfd-api/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ use crate::{
device_token::{exchange_device_token, get_device_provider},
},
mappers::{create_mapper, delete_mapper, get_mappers},
rfd::{get_rfd, get_rfd_attr, get_rfds, search_rfds, set_rfd_attr, update_rfd_visibility},
rfd::{
get_rfd, get_rfd_attr, get_rfds, search_rfds, set_rfd_attr, set_rfd_content,
update_rfd_visibility,
},
webhook::github_webhook,
well_known::{jwks_json, openid_configuration},
},
Expand Down Expand Up @@ -88,6 +91,8 @@ pub fn server(
// RFDs
api.register(get_rfds).expect("Failed to register endpoint");
api.register(get_rfd).expect("Failed to register endpoint");
api.register(set_rfd_content)
.expect("Failed to register endpoint");
api.register(get_rfd_attr)
.expect("Failed to register endpoint");
api.register(set_rfd_attr)
Expand Down
Loading

0 comments on commit 6532004

Please sign in to comment.