summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Reeder <vpzomtrrfrt@gmail.com>2020-12-03 20:32:32 -0700
committerColin Reeder <vpzomtrrfrt@gmail.com>2020-12-03 20:32:32 -0700
commit3419324fd722e1edaae572a396816fd63d6bcf82 (patch)
tree6f57b7cdff5d2ad9a0c2ad9d50d9b4f3f7452f5b
parent3856bd417db790342cce89ecf96de836f9b7d8ac (diff)
Include more fields in community list (#128)
-rw-r--r--openapi/openapi.json53
-rw-r--r--src/main.rs4
-rw-r--r--src/routes/api/communities.rs61
3 files changed, 81 insertions, 37 deletions
diff --git a/openapi/openapi.json b/openapi/openapi.json
index 5168fbc..2d9586b 100644
--- a/openapi/openapi.json
+++ b/openapi/openapi.json
@@ -100,6 +100,26 @@
}
}
},
+ "CommunityInfo": {
+ "allOf": [{"$ref": "#/components/schemas/MinimalCommunityInfo"}],
+ "type": "object",
+ "required": ["description"],
+ "properties": {
+ "description": {"type": "string"},
+ "you_are_moderator": {"type": "boolean"},
+ "your_follow": {
+ "type": "object",
+ "nullable": true,
+ "required": ["accepted"],
+ "properties": {
+ "accepted": {
+ "type": "boolean",
+ "description": "Whether your follow request has been accepted by the community."
+ }
+ }
+ }
+ }
+ },
"SomePostInfo": {
"type": "object",
"required": ["id", "title", "created", "community", "score"],
@@ -445,6 +465,15 @@
"/api/unstable/communities": {
"get": {
"summary": "List communities",
+ "parameters": [
+ {
+ "name": "include_your",
+ "in": "query",
+ "required": false,
+ "schema": {"type": "boolean"},
+ "description": "If true, will include `you_are_moderator` and `your_follow` in list. Requires login."
+ }
+ ],
"responses": {
"200": {
"description": "",
@@ -453,13 +482,14 @@
"schema": {
"type": "array",
"items": {
- "$ref": "#/components/schemas/MinimalCommunityInfo"
+ "$ref": "#/components/schemas/CommunityInfo"
}
}
}
}
}
- }
+ },
+ "security": [{"bearer": []}]
},
"post": {
"summary": "Create a community",
@@ -525,24 +555,7 @@
"content": {
"application/json": {
"schema": {
- "allOf": [{"$ref": "#/components/schemas/MinimalCommunityInfo"}],
- "type": "object",
- "required": ["description"],
- "properties": {
- "description": {"type": "string"},
- "you_are_moderator": {"type": "boolean"},
- "your_follow": {
- "type": "object",
- "nullable": true,
- "required": ["accepted"],
- "properties": {
- "accepted": {
- "type": "boolean",
- "description": "Whether your follow request has been accepted by the community."
- }
- }
- }
- }
+ "$ref": "#/components/schemas/CommunityInfo"
}
}
}
diff --git a/src/main.rs b/src/main.rs
index 18d2959..3a93424 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -87,6 +87,8 @@ impl Into<activitystreams::primitives::OneOrMany<activitystreams::base::AnyBase>
}
}
+pub type ParamSlice<'a> = &'a [&'a (dyn tokio_postgres::types::ToSql + Sync)];
+
#[derive(Serialize, Default)]
pub struct Empty {}
@@ -450,7 +452,7 @@ pub fn get_path_and_query(url: &url::Url) -> Result<String, url::ParseError> {
pub async fn query_stream(
db: &tokio_postgres::Client,
statement: &(impl tokio_postgres::ToStatement + ?Sized),
- params: &[&(dyn tokio_postgres::types::ToSql + Sync)],
+ params: ParamSlice<'_>,
) -> Result<tokio_postgres::RowStream, tokio_postgres::Error> {
let params = params.iter().map(|s| *s as _);
diff --git a/src/routes/api/communities.rs b/src/routes/api/communities.rs
index 29bbcad..aa0d80f 100644
--- a/src/routes/api/communities.rs
+++ b/src/routes/api/communities.rs
@@ -10,7 +10,7 @@ use std::sync::Arc;
#[derive(Serialize)]
struct RespCommunityInfo<'a> {
#[serde(flatten)]
- base: &'a RespMinimalCommunityInfo<'a>,
+ base: RespMinimalCommunityInfo<'a>,
description: &'a str,
@@ -28,30 +28,59 @@ struct RespYourFollowInfo {
async fn route_unstable_communities_list(
_: (),
ctx: Arc<crate::RouteContext>,
- _req: hyper::Request<hyper::Body>,
+ req: hyper::Request<hyper::Body>,
) -> Result<hyper::Response<hyper::Body>, crate::Error> {
- let db = ctx.db_pool.get().await?;
+ let query: MaybeIncludeYour = serde_urlencoded::from_str(req.uri().query().unwrap_or(""))?;
- let rows = db
- .query("SELECT id, local, ap_id, name FROM community", &[])
- .await?;
+ let db = ctx.db_pool.get().await?;
+ let rows = if query.include_your {
+ let user = crate::require_login(&req, &db).await?;
+ db.query(
+ "SELECT id, name, local, ap_id, description, (SELECT accepted FROM community_follow WHERE community=community.id AND follower=$1), EXISTS(SELECT 1 FROM community_moderator WHERE community=community.id AND person=$1) FROM community",
+ &[&user.raw()],
+ ).await?
+ } else {
+ db.query(
+ "SELECT id, name, local, ap_id, description FROM community",
+ &[],
+ )
+ .await?
+ };
let output: Vec<_> = rows
.iter()
.map(|row| {
let id = CommunityLocalID(row.get(0));
- let local = row.get(1);
- let ap_id = row.get(2);
- let name = row.get(3);
+ let name = row.get(1);
+ let local = row.get(2);
+ let ap_id = row.get(3);
+ let description = row.get(4);
let host = crate::get_actor_host_or_unknown(local, ap_id, &ctx.local_hostname);
- RespMinimalCommunityInfo {
- id,
- name,
- local,
- host,
- remote_url: ap_id,
+ RespCommunityInfo {
+ base: RespMinimalCommunityInfo {
+ id,
+ name,
+ local,
+ host,
+ remote_url: ap_id,
+ },
+
+ description,
+ you_are_moderator: if query.include_your {
+ Some(row.get(6))
+ } else {
+ None
+ },
+ your_follow: if query.include_your {
+ Some(match row.get(5) {
+ Some(accepted) => Some(RespYourFollowInfo { accepted }),
+ None => None,
+ })
+ } else {
+ None
+ },
}
})
.collect();
@@ -173,7 +202,7 @@ async fn route_unstable_communities_get(
let community_ap_id: Option<&str> = row.get(2);
let info = RespCommunityInfo {
- base: &RespMinimalCommunityInfo {
+ base: RespMinimalCommunityInfo {
id: community_id,
name: row.get(0),
local: community_local,