WIP filtering by tags

This commit is contained in:
Mia Pilchová 2025-02-24 16:06:12 +01:00
parent fac4053cf4
commit 9db1d704dd
6 changed files with 115 additions and 11 deletions

View File

@ -1,16 +1,74 @@
use sea_orm::EntityTrait; use std::cmp;
use actix_web::{http::header::CONTENT_TYPE, web::Query};
use sea_orm::{
ColumnTrait, EntityTrait, JoinType, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect,
RelationTrait,
};
use serde::Deserialize;
use crate::{ use crate::{
endpoints::prelude::*, entities::prelude::Cat, models::cat::CatModel, state::AppState, endpoints::prelude::*,
entities::{cat, prelude::Cat, tag},
models::cat::CatModel,
state::AppState,
utils::errors::GenericError, utils::errors::GenericError,
}; };
#[get("/")] #[derive(Deserialize)]
pub async fn handler(state: Data<AppState>) -> Result<impl Responder, GenericError> { struct ListRequest {
let users = Cat::find() page: Option<u64>,
.all(&state.db) cat_tags: Option<Vec<String>>,
camera_tags: Option<Vec<String>>,
content_tags: Option<Vec<String>>,
include_hidden: Option<bool>,
}
const LIMIT: u64 = 20;
#[get("")]
pub async fn handler(
state: Data<AppState>,
data: Query<ListRequest>,
) -> Result<impl Responder, GenericError> {
// SeaORM starts at 0, we start at 1
let page = cmp::max(data.page.unwrap_or(1), 1) - 1;
let mut query = Cat::find().order_by_desc(cat::Column::Date);
let include_hidden = data.include_hidden.unwrap_or(false);
if !include_hidden {
query = query.filter(cat::Column::Hidden.eq(false));
}
if let Some(cat_tags) = &data.cat_tags {
if !cat_tags.is_empty() {
query = query
.join(JoinType::InnerJoin, cat::Relation::CatTag.def())
.filter(tag::Column::Id.is_in(cat_tags))
}
}
if let Some(content_tags) = &data.camera_tags {
if !content_tags.is_empty() {
query = query.filter(cat::Column::CatCameraTag.is_in(content_tags));
}
}
if let Some(content_tags) = &data.content_tags {
if !content_tags.is_empty() {
query = query
.join(JoinType::InnerJoin, cat::Relation::CatContentTags.def())
.filter(tag::Column::Id.is_in(content_tags));
}
}
let cats = query
.paginate(&state.db, LIMIT)
.fetch_page(page)
.await .await
.map_err(|e| GenericError::new(e.to_string().as_str()))?; .map_err(|e| GenericError::new(e.to_string().as_str()))?;
Ok(Json(CatModel::from_many(users))) Ok(Json(CatModel::from_many(cats)))
} }

View File

@ -5,4 +5,5 @@ pub use super::cat_content_tags::Entity as CatContentTags;
pub use super::cat_tag::Entity as CatTag; pub use super::cat_tag::Entity as CatTag;
// pub use super::doctrine_migration_versions::Entity as DoctrineMigrationVersions; // pub use super::doctrine_migration_versions::Entity as DoctrineMigrationVersions;
pub use super::tag::Entity as Tag; pub use super::tag::Entity as Tag;
pub use super::tag::TagType;
pub use super::user::Entity as User; pub use super::user::Entity as User;

View File

@ -1,13 +1,25 @@
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.6 //! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.6
use sea_orm::entity::prelude::*; use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, EnumIter, DeriveActiveEnum, Serialize, Deserialize, Clone, Eq, PartialEq)]
#[sea_orm(rs_type = "String", db_type = "String(StringLen::N(255))")]
pub enum TagType {
#[sea_orm(string_value = "cat_tag")]
Cat,
#[sea_orm(string_value = "camera_tag")]
Camera,
#[sea_orm(string_value = "content_tag")]
Content,
}
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "tag")] #[sea_orm(table_name = "tag")]
pub struct Model { pub struct Model {
#[sea_orm(primary_key)] #[sea_orm(primary_key)]
pub id: i32, pub id: i32,
pub r#type: String, pub r#type: TagType,
pub content: String, pub content: String,
} }

View File

@ -1,18 +1,21 @@
use sea_orm::ModelTrait;
use serde::Serialize; use serde::Serialize;
use crate::utils::strings::create_page_title; use crate::utils::strings::create_page_title;
use super::tag::TagModel;
#[derive(Serialize)] #[derive(Serialize)]
pub struct CatModel { pub struct CatModel {
pub id: i32, pub id: i32,
pub image_url: String, pub image_url: String,
pub thumbnail_url: Option<String>, pub thumbnail_url: Option<String>,
// cat_tags
pub content: Option<String>, pub content: Option<String>,
pub page_title: Option<String>, pub page_title: Option<String>,
pub date: String, pub date: String,
// camera_tag, pub cat_tags: Vec<TagModel>,
// tags pub camera_tag: Option<TagModel>,
pub tags: Vec<TagModel>,
} }
impl From<crate::entities::cat::Model> for CatModel { impl From<crate::entities::cat::Model> for CatModel {
@ -29,6 +32,9 @@ impl From<crate::entities::cat::Model> for CatModel {
.clone() .clone()
.map(|content| create_page_title(&content)), .map(|content| create_page_title(&content)),
date: value.date.and_utc().to_rfc3339(), date: value.date.and_utc().to_rfc3339(),
cat_tags: vec![],
camera_tag: None,
tags: vec![],
} }
} }
} }

View File

@ -1,2 +1,3 @@
pub mod cat; pub mod cat;
pub mod tag;
pub mod user; pub mod user;

26
src/models/tag.rs Normal file
View File

@ -0,0 +1,26 @@
use serde::Serialize;
use crate::entities::tag::TagType;
#[derive(Serialize)]
pub struct TagModel {
pub id: i32,
pub r#type: TagType,
pub content: String,
}
impl From<crate::entities::tag::Model> for TagModel {
fn from(value: crate::entities::tag::Model) -> Self {
Self {
id: value.id,
r#type: value.r#type,
content: value.content,
}
}
}
impl TagModel {
pub fn from_many(values: Vec<crate::entities::tag::Model>) -> Vec<Self> {
values.into_iter().map(Into::into).collect()
}
}