httpd: Add `api::test::patch` request method
Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
This commit is contained in:
parent
5c491284dd
commit
a57b33c785
|
|
@ -11,7 +11,7 @@ The issue is now listed under our project.
|
|||
|
||||
```
|
||||
$ rad issue list
|
||||
de81d97d7fe07a80bfb339200c6af862d4526b6a "flux capacitor underpowered"
|
||||
5bce692884916d8d5f0c05824ce9ff44c04a82a8 "flux capacitor underpowered"
|
||||
```
|
||||
|
||||
Great! Now we've documented the issue for ourselves and others.
|
||||
|
|
@ -22,20 +22,20 @@ others to work on. This is to ensure work is not duplicated.
|
|||
Let's assign ourselves to this one.
|
||||
|
||||
```
|
||||
$ rad assign de81d97d7fe07a80bfb339200c6af862d4526b6a z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||
$ rad assign 5bce692884916d8d5f0c05824ce9ff44c04a82a8 z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||
```
|
||||
|
||||
It will now show in the list of issues assigned to us.
|
||||
|
||||
```
|
||||
$ rad issue list --assigned
|
||||
de81d97d7fe07a80bfb339200c6af862d4526b6a "flux capacitor underpowered" z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||
5bce692884916d8d5f0c05824ce9ff44c04a82a8 "flux capacitor underpowered" z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||
```
|
||||
|
||||
Note: this can always be undone with the `unassign` subcommand.
|
||||
|
||||
```
|
||||
$ rad unassign de81d97d7fe07a80bfb339200c6af862d4526b6a z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||
$ rad unassign 5bce692884916d8d5f0c05824ce9ff44c04a82a8 z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||
```
|
||||
|
||||
Great, now we have communicated to the world about our car's defect.
|
||||
|
|
@ -44,8 +44,8 @@ But wait! We've found an important detail about the car's power requirements.
|
|||
It will help whoever works on a fix.
|
||||
|
||||
```
|
||||
$ rad comment de81d97d7fe07a80bfb339200c6af862d4526b6a --message 'The flux capacitor needs 1.21 Gigawatts'
|
||||
$ rad comment 5bce692884916d8d5f0c05824ce9ff44c04a82a8 --message 'The flux capacitor needs 1.21 Gigawatts'
|
||||
z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/6
|
||||
$ rad comment de81d97d7fe07a80bfb339200c6af862d4526b6a --reply-to z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/6 --message 'More power!'
|
||||
$ rad comment 5bce692884916d8d5f0c05824ce9ff44c04a82a8 --reply-to z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/6 --message 'More power!'
|
||||
z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/7
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
use radicle::crypto::PublicKey;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::{serde::timestamp, OffsetDateTime};
|
||||
use time::serde::timestamp;
|
||||
use time::{Duration, OffsetDateTime};
|
||||
|
||||
pub const UNAUTHORIZED_SESSIONS_EXPIRATION: Duration = Duration::seconds(60);
|
||||
pub const AUTHORIZED_SESSIONS_EXPIRATION: Duration = Duration::weeks(1);
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use serde_json::{json, Value};
|
|||
use radicle::cob::issue::{Issue, IssueId};
|
||||
use radicle::cob::patch::{Patch, PatchId};
|
||||
use radicle::cob::thread::{self, CommentId};
|
||||
use radicle::cob::Timestamp;
|
||||
use radicle::cob::{OpId, Timestamp};
|
||||
use radicle::identity::PublicKey;
|
||||
use radicle_surf::blob::Blob;
|
||||
use radicle_surf::tree::Tree;
|
||||
|
|
@ -129,6 +129,7 @@ struct Author {
|
|||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct Comment {
|
||||
id: OpId,
|
||||
author: Author,
|
||||
body: String,
|
||||
reactions: [String; 0],
|
||||
|
|
@ -143,8 +144,9 @@ impl<'a> FromIterator<(&'a CommentId, &'a thread::Comment)> for Comments {
|
|||
fn from_iter<I: IntoIterator<Item = (&'a CommentId, &'a thread::Comment)>>(iter: I) -> Self {
|
||||
let mut comments = Vec::new();
|
||||
|
||||
for (_, comment) in iter {
|
||||
for (id, comment) in iter {
|
||||
comments.push(Comment {
|
||||
id: id.to_owned(),
|
||||
author: Author {
|
||||
id: comment.author(),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use axum::body::Body;
|
|||
use axum::http::{Method, Request};
|
||||
use axum::Router;
|
||||
use serde_json::Value;
|
||||
use time::OffsetDateTime;
|
||||
use tower::ServiceExt;
|
||||
|
||||
use radicle::cob::issue::Issues;
|
||||
|
|
@ -17,7 +18,7 @@ use radicle_cli::commands::rad_init;
|
|||
use radicle_crypto::ssh::keystore::MemorySigner;
|
||||
use radicle_crypto::Signer;
|
||||
|
||||
use crate::api::Context;
|
||||
use crate::api::{auth, Context};
|
||||
|
||||
pub const HEAD: &str = "1e978d19f251cd9821d9d9a76d1bd436bf0690d5";
|
||||
pub const HEAD_1: &str = "f604ce9fd5b7cc77b7609beda45ea8760bee78f7";
|
||||
|
|
@ -135,40 +136,89 @@ pub fn seed(dir: &Path) -> Context {
|
|||
}
|
||||
}
|
||||
|
||||
/// Adds an authorized session to the Context::sessions HashMap.
|
||||
pub async fn create_session(ctx: Context) {
|
||||
let issued_at = OffsetDateTime::now_utc();
|
||||
let mut sessions = ctx.sessions.write().await;
|
||||
sessions.insert(
|
||||
String::from("u9MGAkkfkMOv0uDDB2WeUHBT7HbsO2Dy"),
|
||||
auth::Session {
|
||||
status: auth::AuthState::Authorized,
|
||||
public_key: ctx.profile.public_key,
|
||||
issued_at,
|
||||
expires_at: issued_at
|
||||
.checked_add(auth::AUTHORIZED_SESSIONS_EXPIRATION)
|
||||
.unwrap(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub async fn get(app: &Router, path: impl ToString) -> Response {
|
||||
Response(
|
||||
app.clone()
|
||||
.oneshot(request(path, Method::GET, None))
|
||||
.oneshot(request(path, Method::GET, None, None))
|
||||
.await
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn post(app: &Router, path: impl ToString, body: Option<Body>) -> Response {
|
||||
pub async fn post(
|
||||
app: &Router,
|
||||
path: impl ToString,
|
||||
body: Option<Body>,
|
||||
auth: Option<String>,
|
||||
) -> Response {
|
||||
Response(
|
||||
app.clone()
|
||||
.oneshot(request(path, Method::POST, body))
|
||||
.oneshot(request(path, Method::POST, body, auth))
|
||||
.await
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn put(app: &Router, path: impl ToString, body: Option<Body>) -> Response {
|
||||
pub async fn patch(
|
||||
app: &Router,
|
||||
path: impl ToString,
|
||||
body: Option<Body>,
|
||||
auth: Option<String>,
|
||||
) -> Response {
|
||||
Response(
|
||||
app.clone()
|
||||
.oneshot(request(path, Method::PUT, body))
|
||||
.oneshot(request(path, Method::PATCH, body, auth))
|
||||
.await
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
fn request(path: impl ToString, method: Method, body: Option<Body>) -> Request<Body> {
|
||||
Request::builder()
|
||||
pub async fn put(
|
||||
app: &Router,
|
||||
path: impl ToString,
|
||||
body: Option<Body>,
|
||||
auth: Option<String>,
|
||||
) -> Response {
|
||||
Response(
|
||||
app.clone()
|
||||
.oneshot(request(path, Method::PUT, body, auth))
|
||||
.await
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
fn request(
|
||||
path: impl ToString,
|
||||
method: Method,
|
||||
body: Option<Body>,
|
||||
auth: Option<String>,
|
||||
) -> Request<Body> {
|
||||
let mut request = Request::builder()
|
||||
.method(method)
|
||||
.uri(path.to_string())
|
||||
.header("Content-Type", "application/json")
|
||||
.body(body.unwrap_or_else(Body::empty))
|
||||
.unwrap()
|
||||
.header("Content-Type", "application/json");
|
||||
if let Some(token) = auth {
|
||||
request = request.header("Authorization", format!("Bearer {token}"));
|
||||
}
|
||||
|
||||
request.body(body.unwrap_or_else(Body::empty)).unwrap()
|
||||
}
|
||||
|
||||
pub struct Response(axum::response::Response);
|
||||
|
|
|
|||
|
|
@ -542,10 +542,11 @@ async fn patch_handler(
|
|||
|
||||
#[cfg(test)]
|
||||
mod routes {
|
||||
use axum::body::Body;
|
||||
use axum::http::StatusCode;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::api::test::{self, get, HEAD, HEAD_1};
|
||||
use crate::api::test::{self, get, patch, post, HEAD, HEAD_1};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_projects_root() {
|
||||
|
|
@ -995,7 +996,7 @@ mod routes {
|
|||
response.json().await,
|
||||
json!([
|
||||
{
|
||||
"id": "458bbd9f6d47eed3d60cd905141687ad1f99251e",
|
||||
"id": "90c8f0bab59d9efe35e234acf3abce4168bba6b4",
|
||||
"author": {
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi"
|
||||
},
|
||||
|
|
@ -1006,6 +1007,7 @@ mod routes {
|
|||
"assignees": [],
|
||||
"discussion": [
|
||||
{
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/1",
|
||||
"author": {
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi"
|
||||
},
|
||||
|
|
@ -1021,6 +1023,205 @@ mod routes {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_projects_issues_create() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let ctx = test::seed(tmp.path());
|
||||
let app = super::router(ctx.to_owned());
|
||||
test::create_session(ctx).await;
|
||||
let body = serde_json::to_vec(&json!({
|
||||
"title": "Issue #2",
|
||||
"description": "Change 'hello world' to 'hello everyone'",
|
||||
"tags": ["bug"],
|
||||
}))
|
||||
.unwrap();
|
||||
let response = post(
|
||||
&app,
|
||||
"/projects/rad:z4FucBZHZMCsxTyQE1dfE2YR59Qbp/issues",
|
||||
Some(Body::from(body)),
|
||||
Some("u9MGAkkfkMOv0uDDB2WeUHBT7HbsO2Dy".to_string()),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(response.status(), StatusCode::CREATED);
|
||||
assert_eq!(response.json().await, json!({ "success": true }));
|
||||
|
||||
let issue_id = "bd2bde30b52db0fc2dae35f4e97ff9fdcc93dead";
|
||||
let response = get(
|
||||
&app,
|
||||
format!("/projects/rad:z4FucBZHZMCsxTyQE1dfE2YR59Qbp/issues/{issue_id}"),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
response.json().await,
|
||||
json!({
|
||||
"id": issue_id,
|
||||
"author": {
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi",
|
||||
},
|
||||
"assignees": [],
|
||||
"title": "Issue #2",
|
||||
"state": {
|
||||
"status": "open",
|
||||
},
|
||||
"discussion": [{
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/1",
|
||||
"author": {
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi",
|
||||
},
|
||||
"body": "Change 'hello world' to 'hello everyone'",
|
||||
"reactions": [],
|
||||
"timestamp": 1673001014,
|
||||
"replyTo": null,
|
||||
}],
|
||||
"tags": [
|
||||
"bug",
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_projects_issues_comment() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let ctx = test::seed(tmp.path());
|
||||
let app = super::router(ctx.to_owned());
|
||||
test::create_session(ctx).await;
|
||||
let body = serde_json::to_vec(&json!({
|
||||
"type": "thread",
|
||||
"action": {
|
||||
"type": "comment",
|
||||
"body": "This is first-level comment",
|
||||
}
|
||||
}))
|
||||
.unwrap();
|
||||
let response = patch(
|
||||
&app,
|
||||
"/projects/rad:z4FucBZHZMCsxTyQE1dfE2YR59Qbp/issues/90c8f0bab59d9efe35e234acf3abce4168bba6b4",
|
||||
Some(Body::from(body)),
|
||||
Some("u9MGAkkfkMOv0uDDB2WeUHBT7HbsO2Dy".to_string()),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
assert_eq!(response.json().await, json!({ "success": true }));
|
||||
|
||||
let response = get(
|
||||
&app,
|
||||
"/projects/rad:z4FucBZHZMCsxTyQE1dfE2YR59Qbp/issues/90c8f0bab59d9efe35e234acf3abce4168bba6b4",
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
response.json().await,
|
||||
json!({
|
||||
"id": "90c8f0bab59d9efe35e234acf3abce4168bba6b4",
|
||||
"author": {
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi",
|
||||
},
|
||||
"assignees": [],
|
||||
"title": "Issue #1",
|
||||
"state": {
|
||||
"status": "open",
|
||||
},
|
||||
"discussion": [
|
||||
{
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/1",
|
||||
"author": {
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi",
|
||||
},
|
||||
"body": "Change 'hello world' to 'hello everyone'",
|
||||
"reactions": [],
|
||||
"timestamp": 1673001014,
|
||||
"replyTo": null,
|
||||
},
|
||||
{
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/4",
|
||||
"author": {
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi",
|
||||
},
|
||||
"body": "This is first-level comment",
|
||||
"reactions": [],
|
||||
"timestamp": 1673001014,
|
||||
"replyTo": null,
|
||||
},
|
||||
],
|
||||
"tags": [],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_projects_issues_reply() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let ctx = test::seed(tmp.path());
|
||||
let app = super::router(ctx.to_owned());
|
||||
test::create_session(ctx).await;
|
||||
let body = serde_json::to_vec(&json!({
|
||||
"type":"thread",
|
||||
"action": {
|
||||
"type": "comment",
|
||||
"body": "This is a reply to the first comment",
|
||||
"replyTo": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/1",
|
||||
}}))
|
||||
.unwrap();
|
||||
let response = patch(
|
||||
&app,
|
||||
"/projects/rad:z4FucBZHZMCsxTyQE1dfE2YR59Qbp/issues/90c8f0bab59d9efe35e234acf3abce4168bba6b4",
|
||||
Some(Body::from(body)),
|
||||
Some("u9MGAkkfkMOv0uDDB2WeUHBT7HbsO2Dy".to_string()),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
assert_eq!(response.json().await, json!({ "success": true }));
|
||||
|
||||
let response = get(
|
||||
&app,
|
||||
"/projects/rad:z4FucBZHZMCsxTyQE1dfE2YR59Qbp/issues/90c8f0bab59d9efe35e234acf3abce4168bba6b4",
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
response.json().await,
|
||||
json!({
|
||||
"id": "90c8f0bab59d9efe35e234acf3abce4168bba6b4",
|
||||
"author": {
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi",
|
||||
},
|
||||
"assignees": [],
|
||||
"title": "Issue #1",
|
||||
"state": {
|
||||
"status": "open",
|
||||
},
|
||||
"discussion": [
|
||||
{
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/1",
|
||||
"author": {
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi",
|
||||
},
|
||||
"body": "Change 'hello world' to 'hello everyone'",
|
||||
"reactions": [],
|
||||
"timestamp": 1673001014,
|
||||
"replyTo": null,
|
||||
},
|
||||
{
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/4",
|
||||
"author": {
|
||||
"id": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi",
|
||||
},
|
||||
"body": "This is a reply to the first comment",
|
||||
"reactions": [],
|
||||
"timestamp": 1673001014,
|
||||
"replyTo": "z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/1",
|
||||
},
|
||||
],
|
||||
"tags": [],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_projects_patches() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
|
|
|
|||
|
|
@ -8,17 +8,14 @@ use axum_auth::AuthBearer;
|
|||
use hyper::StatusCode;
|
||||
use radicle::crypto::{PublicKey, Signature};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::{Duration, OffsetDateTime};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
use crate::api::auth::{AuthState, Session};
|
||||
use crate::api::auth::{self, AuthState, Session};
|
||||
use crate::api::axum_extra::Path;
|
||||
use crate::api::error::Error;
|
||||
use crate::api::json;
|
||||
use crate::api::Context;
|
||||
|
||||
pub const UNAUTHORIZED_SESSIONS_EXPIRATION: Duration = Duration::seconds(60);
|
||||
pub const AUTHORIZED_SESSIONS_EXPIRATION: Duration = Duration::weeks(1);
|
||||
|
||||
pub fn router(ctx: Context) -> Router {
|
||||
Router::new()
|
||||
.route("/sessions", post(session_create_handler))
|
||||
|
|
@ -50,7 +47,7 @@ async fn session_create_handler(State(ctx): State<Context>) -> impl IntoResponse
|
|||
public_key: *signer.public_key(),
|
||||
issued_at: OffsetDateTime::now_utc(),
|
||||
expires_at: OffsetDateTime::now_utc()
|
||||
.checked_add(UNAUTHORIZED_SESSIONS_EXPIRATION)
|
||||
.checked_add(auth::UNAUTHORIZED_SESSIONS_EXPIRATION)
|
||||
.unwrap(),
|
||||
};
|
||||
let mut sessions = ctx.sessions.write().await;
|
||||
|
|
@ -97,7 +94,7 @@ async fn session_signin_handler(
|
|||
.map_err(Error::from)?;
|
||||
session.status = AuthState::Authorized;
|
||||
session.expires_at = OffsetDateTime::now_utc()
|
||||
.checked_add(AUTHORIZED_SESSIONS_EXPIRATION)
|
||||
.checked_add(auth::AUTHORIZED_SESSIONS_EXPIRATION)
|
||||
.unwrap();
|
||||
|
||||
return Ok::<_, Error>(Json(json!({ "success": true })));
|
||||
|
|
@ -140,16 +137,20 @@ mod routes {
|
|||
let app = super::router(ctx.to_owned());
|
||||
|
||||
// Create session.
|
||||
let response = post(&app, "/sessions", None).await;
|
||||
assert_eq!(response.status(), StatusCode::CREATED);
|
||||
let response = post(&app, "/sessions", None, None).await;
|
||||
let status = response.status();
|
||||
let json = response.json().await;
|
||||
let session_info: SessionInfo = serde_json::from_value(json).unwrap();
|
||||
|
||||
assert_eq!(status, StatusCode::CREATED);
|
||||
|
||||
// Check that an unauthorized session has been created.
|
||||
let response = get(&app, format!("/sessions/{}", session_info.session_id)).await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let status = response.status();
|
||||
let json = response.json().await;
|
||||
let body: Session = serde_json::from_value(json).unwrap();
|
||||
|
||||
assert_eq!(status, StatusCode::OK);
|
||||
assert_eq!(body.status, AuthState::Unauthorized);
|
||||
|
||||
// Create request body
|
||||
|
|
@ -165,15 +166,19 @@ mod routes {
|
|||
&app,
|
||||
format!("/sessions/{}", session_info.session_id),
|
||||
Some(Body::from(body)),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
|
||||
// Check that session has been authorized.
|
||||
let response = get(&app, format!("/sessions/{}", session_info.session_id)).await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let status = response.status();
|
||||
let json = response.json().await;
|
||||
let body: Session = serde_json::from_value(json).unwrap();
|
||||
|
||||
assert_eq!(status, StatusCode::OK);
|
||||
assert_eq!(body.status, AuthState::Authorized);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ impl PartialOrd for Comment {
|
|||
#[serde(tag = "type", rename_all = "camelCase")]
|
||||
pub enum Action {
|
||||
/// Comment on a thread.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Comment {
|
||||
/// Comment body.
|
||||
body: String,
|
||||
|
|
|
|||
Loading…
Reference in New Issue