Add API method for retrieving tag timeline
This commit is contained in:
parent
a4dd06d6e9
commit
da918d2296
4 changed files with 130 additions and 4 deletions
|
@ -132,6 +132,7 @@ POST /api/v1/statuses/{status_id}/unfavourite
|
|||
POST /api/v1/statuses/{status_id}/reblog
|
||||
POST /api/v1/statuses/{status_id}/unreblog
|
||||
GET /api/v1/timelines/home
|
||||
GET /api/v1/timelines/tag/{hashtag}
|
||||
```
|
||||
|
||||
Additional methods:
|
||||
|
|
|
@ -18,7 +18,7 @@ paths:
|
|||
description: Post does not belong to user
|
||||
404:
|
||||
description: Post not found
|
||||
/api/v1/{status_id}/make_permanent:
|
||||
/api/v1/statuses/{status_id}/make_permanent:
|
||||
post:
|
||||
summary: Save post to IPFS
|
||||
parameters:
|
||||
|
@ -38,7 +38,7 @@ paths:
|
|||
description: IPFS integration is not enabled
|
||||
422:
|
||||
description: Post already saved to IPFS
|
||||
/api/v1/{status_id}/signature:
|
||||
/api/v1/statuses/{status_id}/signature:
|
||||
get:
|
||||
summary: Sign post data with instance key
|
||||
parameters:
|
||||
|
@ -69,7 +69,7 @@ paths:
|
|||
description: Ethereum integration is not enabled
|
||||
422:
|
||||
description: Post is not saved to IPFS
|
||||
/api/v1/{status_id}/token_minted:
|
||||
/api/v1/statuses/{status_id}/token_minted:
|
||||
post:
|
||||
summary: Register transaction that mints a token
|
||||
parameters:
|
||||
|
@ -95,6 +95,40 @@ paths:
|
|||
description: Post not found
|
||||
422:
|
||||
description: Transaction already registered
|
||||
/api/v1/timelines/tag/{hashtag}:
|
||||
get:
|
||||
summary: View public posts containing the given hashtag
|
||||
parameters:
|
||||
- name: hashtag
|
||||
in: path
|
||||
description: Hashtag name
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: max_id
|
||||
in: query
|
||||
description: Return results older than this ID.
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
- name: limit
|
||||
in: query
|
||||
description: Maximum number of results to return.
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
default: 20
|
||||
responses:
|
||||
200:
|
||||
description: Successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
description: Post list
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Status'
|
||||
|
||||
components:
|
||||
parameters:
|
||||
|
@ -113,6 +147,14 @@ components:
|
|||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
content:
|
||||
description: HTML-encoded status content.
|
||||
type: string
|
||||
tags:
|
||||
description: Hashtags used within the status content.
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Tag'
|
||||
ipfs_cid:
|
||||
type: string
|
||||
nullable: true
|
||||
|
@ -121,3 +163,11 @@ components:
|
|||
type: string
|
||||
nullable: true
|
||||
example: '0x5fe80cdea7f...'
|
||||
Tag:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: 'The value of the hashtag after the # sign.'
|
||||
type: string
|
||||
url:
|
||||
description: A link to the hashtag on the instance.
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::models::posts::helpers::{
|
|||
get_actions_for_posts,
|
||||
get_reposted_posts,
|
||||
};
|
||||
use crate::models::posts::queries::get_home_timeline;
|
||||
use crate::models::posts::queries::{get_home_timeline, get_posts_by_tag};
|
||||
use super::types::TimelineQueryParams;
|
||||
|
||||
#[get("/home")]
|
||||
|
@ -42,7 +42,42 @@ async fn home_timeline(
|
|||
Ok(HttpResponse::Ok().json(statuses))
|
||||
}
|
||||
|
||||
#[get("/tag/{hashtag}")]
|
||||
async fn hashtag_timeline(
|
||||
auth: Option<BearerAuth>,
|
||||
config: web::Data<Config>,
|
||||
db_pool: web::Data<Pool>,
|
||||
web::Path(hashtag): web::Path<String>,
|
||||
query_params: web::Query<TimelineQueryParams>,
|
||||
) -> Result<HttpResponse, HttpError> {
|
||||
let db_client = &**get_database_client(&db_pool).await?;
|
||||
let maybe_current_user = match auth {
|
||||
Some(auth) => Some(get_current_user(db_client, auth.token()).await?),
|
||||
None => None,
|
||||
};
|
||||
let mut posts = get_posts_by_tag(
|
||||
db_client,
|
||||
&hashtag,
|
||||
query_params.max_id,
|
||||
query_params.limit,
|
||||
).await?;
|
||||
get_reposted_posts(db_client, posts.iter_mut().collect()).await?;
|
||||
if let Some(user) = maybe_current_user {
|
||||
get_actions_for_posts(
|
||||
db_client,
|
||||
&user.id,
|
||||
posts.iter_mut().collect(),
|
||||
).await?;
|
||||
};
|
||||
let statuses: Vec<Status> = posts
|
||||
.into_iter()
|
||||
.map(|post| Status::from_post(post, &config.instance_url()))
|
||||
.collect();
|
||||
Ok(HttpResponse::Ok().json(statuses))
|
||||
}
|
||||
|
||||
pub fn timeline_api_scope() -> Scope {
|
||||
web::scope("/api/v1/timelines")
|
||||
.service(home_timeline)
|
||||
.service(hashtag_timeline)
|
||||
}
|
||||
|
|
|
@ -329,6 +329,46 @@ pub async fn get_posts_by_author(
|
|||
Ok(posts)
|
||||
}
|
||||
|
||||
pub async fn get_posts_by_tag(
|
||||
db_client: &impl GenericClient,
|
||||
tag_name: &str,
|
||||
max_post_id: Option<Uuid>,
|
||||
limit: i64,
|
||||
) -> Result<Vec<Post>, DatabaseError> {
|
||||
let statement = format!(
|
||||
"
|
||||
SELECT
|
||||
post, actor_profile,
|
||||
{related_attachments},
|
||||
{related_mentions},
|
||||
{related_tags}
|
||||
FROM post
|
||||
JOIN actor_profile ON post.author_id = actor_profile.id
|
||||
WHERE
|
||||
post.visibility = {visibility_public}
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM post_tag JOIN tag ON post_tag.tag_id = tag.id
|
||||
WHERE post_tag.post_id = post.id AND tag.tag_name = $1
|
||||
)
|
||||
AND ($2::uuid IS NULL OR post.id < $2)
|
||||
ORDER BY post.id DESC
|
||||
LIMIT $3
|
||||
",
|
||||
related_attachments=RELATED_ATTACHMENTS,
|
||||
related_mentions=RELATED_MENTIONS,
|
||||
related_tags=RELATED_TAGS,
|
||||
visibility_public=i16::from(&Visibility::Public),
|
||||
);
|
||||
let rows = db_client.query(
|
||||
statement.as_str(),
|
||||
&[&tag_name.to_lowercase(), &max_post_id, &limit],
|
||||
).await?;
|
||||
let posts: Vec<Post> = rows.iter()
|
||||
.map(Post::try_from)
|
||||
.collect::<Result<_, _>>()?;
|
||||
Ok(posts)
|
||||
}
|
||||
|
||||
pub async fn get_post_by_id(
|
||||
db_client: &impl GenericClient,
|
||||
post_id: &Uuid,
|
||||
|
|
Loading…
Reference in a new issue