mirror of
https://github.com/Arcadia-Solutions/arcadia.git
synced 2025-12-21 09:19:33 -06:00
feat: search series search bar and small changes/additions
This commit is contained in:
@@ -9,11 +9,11 @@ use utoipa::{
|
||||
Modify, OpenApi,
|
||||
};
|
||||
|
||||
use crate::handlers::search::search_title_group_tags_lite::SearchTitleGroupTagsLiteQuery;
|
||||
use crate::handlers::{
|
||||
search::search_torrent_requests::SearchTorrentRequestsQuery,
|
||||
user_applications::get_user_applications::GetUserApplicationsQuery,
|
||||
use crate::handlers::search::{
|
||||
search_title_group_tags_lite::SearchTitleGroupTagsLiteQuery,
|
||||
search_torrent_requests::SearchTorrentRequestsQuery,
|
||||
};
|
||||
use crate::handlers::user_applications::get_user_applications::GetUserApplicationsQuery;
|
||||
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
@@ -52,6 +52,8 @@ use crate::handlers::{
|
||||
crate::handlers::master_groups::create_master_group::exec,
|
||||
crate::handlers::series::create_series::exec,
|
||||
crate::handlers::series::get_series::exec,
|
||||
crate::handlers::series::edit_series::exec,
|
||||
crate::handlers::series::add_title_group::exec,
|
||||
crate::handlers::subscriptions::create_subscription_forum_thread_posts::exec,
|
||||
crate::handlers::subscriptions::remove_subscription_forum_thread_posts::exec,
|
||||
crate::handlers::subscriptions::create_subscription_title_group_torrents::exec,
|
||||
@@ -76,6 +78,7 @@ use crate::handlers::{
|
||||
crate::handlers::search::search_collages::exec,
|
||||
crate::handlers::search::search_collages_lite::exec,
|
||||
crate::handlers::search::search_series::exec,
|
||||
crate::handlers::search::search_series_lite::exec,
|
||||
crate::handlers::search::search_forum::exec,
|
||||
crate::handlers::torrent_requests::create_torrent_request::exec,
|
||||
crate::handlers::torrent_requests::get_torrent_request::exec,
|
||||
|
||||
@@ -3,6 +3,7 @@ pub mod search_collages;
|
||||
pub mod search_collages_lite;
|
||||
pub mod search_forum;
|
||||
pub mod search_series;
|
||||
pub mod search_series_lite;
|
||||
pub mod search_title_group_info_lite;
|
||||
pub mod search_title_group_tags;
|
||||
pub mod search_title_group_tags_lite;
|
||||
@@ -33,5 +34,6 @@ pub fn config<R: RedisPoolInterface + 'static>(cfg: &mut ServiceConfig) {
|
||||
cfg.service(resource("/collages").route(get().to(self::search_collages::exec::<R>)));
|
||||
cfg.service(resource("/collages/lite").route(get().to(self::search_collages_lite::exec::<R>)));
|
||||
cfg.service(resource("/series").route(get().to(self::search_series::exec::<R>)));
|
||||
cfg.service(resource("/series/lite").route(get().to(self::search_series_lite::exec::<R>)));
|
||||
cfg.service(resource("/forum").route(get().to(self::search_forum::exec::<R>)));
|
||||
}
|
||||
|
||||
34
backend/api/src/handlers/search/search_series_lite.rs
Normal file
34
backend/api/src/handlers/search/search_series_lite.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
use crate::Arcadia;
|
||||
use actix_web::{
|
||||
web::{Data, Query},
|
||||
HttpResponse,
|
||||
};
|
||||
use arcadia_common::error::Result;
|
||||
use arcadia_storage::{models::series::SeriesLite, redis::RedisPoolInterface};
|
||||
use serde::Deserialize;
|
||||
use utoipa::{IntoParams, ToSchema};
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema, IntoParams)]
|
||||
pub struct SearchSeriesLiteQuery {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
operation_id = "Search series lite",
|
||||
tag = "Search",
|
||||
path = "/api/search/series/lite",
|
||||
params (SearchSeriesLiteQuery),
|
||||
description = "Case insensitive",
|
||||
responses(
|
||||
(status = 200, description = "Successfully got the series (lite)", body=Vec<SeriesLite>),
|
||||
)
|
||||
)]
|
||||
pub async fn exec<R: RedisPoolInterface + 'static>(
|
||||
query: Query<SearchSeriesLiteQuery>,
|
||||
arc: Data<Arcadia<R>>,
|
||||
) -> Result<HttpResponse> {
|
||||
let series = arc.pool.search_series_lite(&query.name, 7).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(series))
|
||||
}
|
||||
38
backend/api/src/handlers/series/add_title_group.rs
Normal file
38
backend/api/src/handlers/series/add_title_group.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use crate::Arcadia;
|
||||
use actix_web::{
|
||||
web::{Data, Json},
|
||||
HttpResponse,
|
||||
};
|
||||
use arcadia_common::error::Result;
|
||||
use arcadia_storage::{models::title_group::TitleGroup, redis::RedisPoolInterface};
|
||||
use serde::Deserialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct AddTitleGroupToSeriesRequest {
|
||||
pub series_id: i64,
|
||||
pub title_group_id: i32,
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
operation_id = "Add title group to series",
|
||||
tag = "Series",
|
||||
path = "/api/series/title-group",
|
||||
security(
|
||||
("http" = ["Bearer"])
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Successfully attached the title group to the series", body=TitleGroup),
|
||||
)
|
||||
)]
|
||||
pub async fn exec<R: RedisPoolInterface + 'static>(
|
||||
form: Json<AddTitleGroupToSeriesRequest>,
|
||||
arc: Data<Arcadia<R>>,
|
||||
) -> Result<HttpResponse> {
|
||||
arc.pool
|
||||
.assign_title_group_to_series(form.title_group_id, form.series_id)
|
||||
.await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(serde_json::json!({"result": "success"})))
|
||||
}
|
||||
41
backend/api/src/handlers/series/edit_series.rs
Normal file
41
backend/api/src/handlers/series/edit_series.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use crate::{middlewares::auth_middleware::Authdata, Arcadia};
|
||||
use actix_web::{
|
||||
web::{Data, Json},
|
||||
HttpResponse,
|
||||
};
|
||||
use arcadia_common::error::{Error, Result};
|
||||
use arcadia_storage::{
|
||||
models::{
|
||||
series::{EditedSeries, Series},
|
||||
user::UserClass,
|
||||
},
|
||||
redis::RedisPoolInterface,
|
||||
};
|
||||
|
||||
#[utoipa::path(
|
||||
put,
|
||||
operation_id = "Edit series",
|
||||
tag = "Series",
|
||||
path = "/api/series",
|
||||
security(
|
||||
("http" = ["Bearer"])
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Successfully edited the series", body=Series),
|
||||
)
|
||||
)]
|
||||
pub async fn exec<R: RedisPoolInterface + 'static>(
|
||||
form: Json<EditedSeries>,
|
||||
arc: Data<Arcadia<R>>,
|
||||
user: Authdata,
|
||||
) -> Result<HttpResponse> {
|
||||
let series = arc.pool.find_series(&form.id).await?;
|
||||
|
||||
if user.class != UserClass::Staff && series.created_by_id != user.sub {
|
||||
return Err(Error::InsufficientPrivileges);
|
||||
}
|
||||
|
||||
let updated_series = arc.pool.update_series(&form).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(updated_series))
|
||||
}
|
||||
@@ -1,13 +1,17 @@
|
||||
pub mod add_title_group;
|
||||
pub mod create_series;
|
||||
pub mod edit_series;
|
||||
pub mod get_series;
|
||||
|
||||
use actix_web::web::{get, post, resource, ServiceConfig};
|
||||
use actix_web::web::{get, post, put, resource, ServiceConfig};
|
||||
use arcadia_storage::redis::RedisPoolInterface;
|
||||
|
||||
pub fn config<R: RedisPoolInterface + 'static>(cfg: &mut ServiceConfig) {
|
||||
cfg.service(
|
||||
resource("")
|
||||
.route(post().to(self::create_series::exec::<R>))
|
||||
.route(get().to(self::get_series::exec::<R>)),
|
||||
.route(get().to(self::get_series::exec::<R>))
|
||||
.route(put().to(self::edit_series::exec::<R>)),
|
||||
);
|
||||
cfg.service(resource("/title-group").route(post().to(self::add_title_group::exec::<R>)));
|
||||
}
|
||||
|
||||
15
backend/api/tests/fixtures/with_test_series.sql
vendored
Normal file
15
backend/api/tests/fixtures/with_test_series.sql
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
INSERT INTO
|
||||
series (id, name, description, tags, covers, banners, created_by_id, created_at, updated_at)
|
||||
VALUES
|
||||
(
|
||||
1,
|
||||
'Test Series',
|
||||
'A series used for testing',
|
||||
'{test,series}',
|
||||
'{https://example.com/cover.jpg}',
|
||||
'{https://example.com/banner.jpg}',
|
||||
1,
|
||||
NOW(),
|
||||
NOW()
|
||||
);
|
||||
|
||||
88
backend/api/tests/test_series.rs
Normal file
88
backend/api/tests/test_series.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
pub mod common;
|
||||
pub mod mocks;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::{
|
||||
http::StatusCode,
|
||||
test::{self, call_service},
|
||||
};
|
||||
use arcadia_storage::{
|
||||
connection_pool::ConnectionPool,
|
||||
models::{
|
||||
series::{EditedSeries, Series},
|
||||
title_group::TitleGroupAndAssociatedData,
|
||||
},
|
||||
};
|
||||
use mocks::mock_redis::MockRedisPool;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::common::{
|
||||
auth_header, call_and_read_body_json_with_status, create_test_app_and_login, TestUser,
|
||||
};
|
||||
|
||||
#[sqlx::test(
|
||||
fixtures("with_test_user2", "with_test_series"),
|
||||
migrations = "../storage/migrations"
|
||||
)]
|
||||
async fn test_edit_series(pool: PgPool) {
|
||||
let pool = Arc::new(ConnectionPool::with_pg_pool(pool));
|
||||
let (service, user) =
|
||||
create_test_app_and_login(pool, MockRedisPool::default(), 100, 100, TestUser::Staff).await;
|
||||
|
||||
let payload = EditedSeries {
|
||||
id: 1,
|
||||
name: "Updated Series".to_string(),
|
||||
description: "Updated description".to_string(),
|
||||
covers: vec!["https://example.com/updated-cover.jpg".to_string()],
|
||||
banners: vec!["https://example.com/updated-banner.jpg".to_string()],
|
||||
tags: vec!["updated".to_string()],
|
||||
};
|
||||
|
||||
let req = test::TestRequest::put()
|
||||
.uri("/api/series")
|
||||
.insert_header(auth_header(&user.token))
|
||||
.set_json(&payload)
|
||||
.to_request();
|
||||
|
||||
let series: Series = call_and_read_body_json_with_status(&service, req, StatusCode::OK).await;
|
||||
|
||||
assert_eq!(series.name, payload.name);
|
||||
assert_eq!(series.description, payload.description);
|
||||
assert_eq!(series.covers, payload.covers);
|
||||
assert_eq!(series.banners, Some(payload.banners));
|
||||
assert_eq!(series.tags, payload.tags);
|
||||
}
|
||||
|
||||
#[sqlx::test(
|
||||
fixtures("with_test_user", "with_test_series", "with_test_title_group"),
|
||||
migrations = "../storage/migrations"
|
||||
)]
|
||||
async fn test_add_title_group_to_series(pool: PgPool) {
|
||||
let pool = Arc::new(ConnectionPool::with_pg_pool(pool));
|
||||
let (service, user) =
|
||||
create_test_app_and_login(pool, MockRedisPool::default(), 100, 100, TestUser::Standard)
|
||||
.await;
|
||||
|
||||
let req = test::TestRequest::post()
|
||||
.uri("/api/series/title-group")
|
||||
.insert_header(auth_header(&user.token))
|
||||
.set_json(serde_json::json!({
|
||||
"series_id": 1,
|
||||
"title_group_id": 1
|
||||
}))
|
||||
.to_request();
|
||||
|
||||
let _ = call_service(&service, req).await;
|
||||
|
||||
let req = test::TestRequest::get()
|
||||
.uri("/api/title-groups?id=1")
|
||||
.insert_header(auth_header(&user.token))
|
||||
.to_request();
|
||||
|
||||
let title_group: TitleGroupAndAssociatedData =
|
||||
call_and_read_body_json_with_status(&service, req, StatusCode::OK).await;
|
||||
|
||||
assert_eq!(title_group.title_group.id, 1);
|
||||
assert_eq!(title_group.title_group.series_id, Some(1));
|
||||
}
|
||||
@@ -108,6 +108,9 @@ pub enum Error {
|
||||
#[error("could not create series")]
|
||||
CouldNotCreateSeries(#[source] sqlx::Error),
|
||||
|
||||
#[error("could not update series")]
|
||||
CouldNotUpdateSeries(#[source] sqlx::Error),
|
||||
|
||||
#[error("could not create api key")]
|
||||
CouldNotCreateAPIKey(#[source] sqlx::Error),
|
||||
|
||||
|
||||
75
backend/storage/.sqlx/query-61a6c11b6da252a26f963509c57cb726d29394f0e77d9d3e65f46b0284c96d78.json
generated
Normal file
75
backend/storage/.sqlx/query-61a6c11b6da252a26f963509c57cb726d29394f0e77d9d3e65f46b0284c96d78.json
generated
Normal file
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE series\n SET\n name = $2,\n description = $3,\n covers = $4,\n banners = $5,\n tags = $6,\n updated_at = NOW()\n WHERE id = $1\n RETURNING *\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "name",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "description",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "tags",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "covers",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "banners",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "created_by_id",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "created_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "updated_at",
|
||||
"type_info": "Timestamptz"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Varchar",
|
||||
"Text",
|
||||
"TextArray",
|
||||
"TextArray",
|
||||
"TextArray"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "61a6c11b6da252a26f963509c57cb726d29394f0e77d9d3e65f46b0284c96d78"
|
||||
}
|
||||
29
backend/storage/.sqlx/query-a47fbecaf179e762203deb5497de7d15ad7caaf68a0269a57b37dafba36121c3.json
generated
Normal file
29
backend/storage/.sqlx/query-a47fbecaf179e762203deb5497de7d15ad7caaf68a0269a57b37dafba36121c3.json
generated
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n s.id,\n s.name\n FROM series s\n WHERE (s.name ILIKE '%' || $1 || '%')\n LIMIT $2\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "name",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "a47fbecaf179e762203deb5497de7d15ad7caaf68a0269a57b37dafba36121c3"
|
||||
}
|
||||
15
backend/storage/.sqlx/query-b70d718632b169f7a13e6c2a34e8aebe703b7b3b3e1d033807228c1f0d3e73de.json
generated
Normal file
15
backend/storage/.sqlx/query-b70d718632b169f7a13e6c2a34e8aebe703b7b3b3e1d033807228c1f0d3e73de.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE title_groups\n SET series_id = $2, updated_at = NOW()\n WHERE id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "b70d718632b169f7a13e6c2a34e8aebe703b7b3b3e1d033807228c1f0d3e73de"
|
||||
}
|
||||
@@ -29,6 +29,16 @@ pub struct UserCreatedSeries {
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct EditedSeries {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub covers: Vec<String>,
|
||||
pub banners: Vec<String>,
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, ToSchema)]
|
||||
pub struct SeriesAndTitleGroupHierarchyLite {
|
||||
pub series: Series,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use crate::{
|
||||
connection_pool::ConnectionPool,
|
||||
models::series::{
|
||||
SearchSeriesQuery, Series, SeriesSearchResponse, SeriesSearchResult, UserCreatedSeries,
|
||||
EditedSeries, SearchSeriesQuery, Series, SeriesLite, SeriesSearchResponse,
|
||||
SeriesSearchResult, UserCreatedSeries,
|
||||
},
|
||||
};
|
||||
use arcadia_common::error::{Error, Result};
|
||||
@@ -99,4 +100,57 @@ impl ConnectionPool {
|
||||
total_items,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn search_series_lite(
|
||||
&self,
|
||||
name: &str,
|
||||
results_amount: u8,
|
||||
) -> Result<Vec<SeriesLite>> {
|
||||
let results = sqlx::query_as!(
|
||||
SeriesLite,
|
||||
r#"
|
||||
SELECT
|
||||
s.id,
|
||||
s.name
|
||||
FROM series s
|
||||
WHERE (s.name ILIKE '%' || $1 || '%')
|
||||
LIMIT $2
|
||||
"#,
|
||||
name,
|
||||
results_amount as i64
|
||||
)
|
||||
.fetch_all(self.borrow())
|
||||
.await?;
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
pub async fn update_series(&self, edited_series: &EditedSeries) -> Result<Series> {
|
||||
let series = sqlx::query_as!(
|
||||
Series,
|
||||
r#"
|
||||
UPDATE series
|
||||
SET
|
||||
name = $2,
|
||||
description = $3,
|
||||
covers = $4,
|
||||
banners = $5,
|
||||
tags = $6,
|
||||
updated_at = NOW()
|
||||
WHERE id = $1
|
||||
RETURNING *
|
||||
"#,
|
||||
edited_series.id,
|
||||
edited_series.name,
|
||||
edited_series.description,
|
||||
&edited_series.covers,
|
||||
&edited_series.banners,
|
||||
&edited_series.tags
|
||||
)
|
||||
.fetch_one(self.borrow())
|
||||
.await
|
||||
.map_err(Error::CouldNotUpdateSeries)?;
|
||||
|
||||
Ok(series)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,6 +488,27 @@ impl ConnectionPool {
|
||||
Ok(updated_title_group)
|
||||
}
|
||||
|
||||
pub async fn assign_title_group_to_series(
|
||||
&self,
|
||||
title_group_id: i32,
|
||||
series_id: i64,
|
||||
) -> Result<()> {
|
||||
let _ = sqlx::query!(
|
||||
r#"
|
||||
UPDATE title_groups
|
||||
SET series_id = $2, updated_at = NOW()
|
||||
WHERE id = $1
|
||||
"#,
|
||||
title_group_id,
|
||||
series_id
|
||||
)
|
||||
.fetch_one(self.borrow())
|
||||
.await
|
||||
.map_err(|e| Error::ErrorWhileUpdatingTitleGroup(e.to_string()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn does_title_group_with_link_exist(
|
||||
&self,
|
||||
external_link: &str,
|
||||
|
||||
@@ -23,5 +23,5 @@ Arcadia's frontend is a [SPA](https://developer.mozilla.org/en-US/docs/Glossary/
|
||||
If you make changes to structs that are listed in the swagger or the api routes, you must regenerate the typescript interfaces with this command (from the frontend directory, while the backend is running):
|
||||
|
||||
```bash
|
||||
npx openapi-generator-cli generate -g typescript-axios -i http://127.0.0.1:8080/swagger-json/openapi.json -o ./src/services/api-schema -t .openapi-generator/templates --config .openapi-generator/openapi-generator.config.json --global-property=models,apiDocs=false,modelDocs=false,skipFormModel=false
|
||||
npx openapi-generator-cli generate -g typescript-axios -i http://127.0.0.1:8080/swagger-json/openapi.json -o ./src/services/api-schema -t .openapi-generator/templates --config .openapi-generator/openapi-generator.config.json --global-property=apiDocs=false,modelDocs=false,skipFormModel=false
|
||||
```
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
}
|
||||
"
|
||||
/>
|
||||
<ArtistSearchBar :placeholder="t('artist.artist', 2)" @artistSelected="artistSelected" :clearInputOnSelect="true" v-model="searchForm.artists" />
|
||||
<InputText type="text" :placeholder="t('series.series')" v-model="searchForm.series" size="small" />
|
||||
<ArtistSearchBar :placeholder="t('artist.artist', 2)" :clickableSeriesLink="true" :clearInputOnSelect="true" v-model="searchForm.artists" />
|
||||
<SeriesSearchBar :placeholder="t('series.series')" :clickableSeriesLink="true" :clearInputOnSelect="true" v-model="searchForm.series" />
|
||||
<InputText type="text" :placeholder="t('forum.forum', 2)" v-model="searchForm.forums" size="small" />
|
||||
<InputText type="text" :placeholder="t('user.user', 2)" v-model="searchForm.users" size="small" />
|
||||
</div>
|
||||
@@ -22,10 +22,10 @@
|
||||
<script setup lang="ts">
|
||||
import InputText from 'primevue/inputtext'
|
||||
import ArtistSearchBar from './artist/ArtistSearchBar.vue'
|
||||
import SeriesSearchBar from './series/SeriesSearchBar.vue'
|
||||
import { ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { ArtistLite } from '@/services/api-schema'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
@@ -38,10 +38,6 @@ const searchForm = ref({
|
||||
forums: '',
|
||||
users: '',
|
||||
})
|
||||
|
||||
const artistSelected = (artist: ArtistLite) => {
|
||||
router.push(`/artist/${artist.id}`)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
@input="onInput"
|
||||
>
|
||||
<template #option="slotProps">
|
||||
<div>{{ slotProps.option.name }}</div>
|
||||
<RouterLink v-if="clickableSeriesLink" :to="`/artist/${slotProps.option.id}`" style="width: 100%">
|
||||
{{ slotProps.option.name }}
|
||||
</RouterLink>
|
||||
<div v-else>{{ slotProps.option.name }}</div>
|
||||
</template>
|
||||
</AutoComplete>
|
||||
</template>
|
||||
@@ -24,6 +27,7 @@ const props = defineProps<{
|
||||
placeholder: string
|
||||
clearInputOnSelect: boolean
|
||||
modelValue: string
|
||||
clickableSeriesLink?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
||||
73
frontend/src/components/series/SeriesSearchBar.vue
Normal file
73
frontend/src/components/series/SeriesSearchBar.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<AutoComplete
|
||||
v-model="name"
|
||||
:suggestions="foundSeries"
|
||||
@complete="search"
|
||||
size="small"
|
||||
:placeholder
|
||||
optionLabel="name"
|
||||
@option-select="seriesSelected"
|
||||
@input="onInput"
|
||||
>
|
||||
<template #option="slotProps">
|
||||
<RouterLink v-if="clickableSeriesLink" :to="`/series/${slotProps.option.id}`" style="width: 100%">
|
||||
{{ slotProps.option.name }}
|
||||
</RouterLink>
|
||||
<div v-else>{{ slotProps.option.name }}</div>
|
||||
</template>
|
||||
</AutoComplete>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { AutoComplete, type AutoCompleteOptionSelectEvent } from 'primevue'
|
||||
import { searchSeriesLite, type SeriesLite } from '@/services/api-schema'
|
||||
import type { RouterLink } from 'vue-router'
|
||||
|
||||
const props = defineProps<{
|
||||
placeholder: string
|
||||
clearInputOnSelect: boolean
|
||||
modelValue: string
|
||||
clickableSeriesLink: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [string]
|
||||
seriesSelected: [SeriesLite]
|
||||
}>()
|
||||
|
||||
const name = ref('')
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
name.value = newValue
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
const foundSeries = ref<SeriesLite[]>()
|
||||
|
||||
const seriesSelected = (event: AutoCompleteOptionSelectEvent) => {
|
||||
if (props.clearInputOnSelect) {
|
||||
name.value = ''
|
||||
}
|
||||
const selectedSeriesName = (event.value as SeriesLite).name
|
||||
emit('seriesSelected', event.value)
|
||||
emit('update:modelValue', selectedSeriesName)
|
||||
}
|
||||
|
||||
const onInput = () => {
|
||||
emit('update:modelValue', name.value)
|
||||
}
|
||||
|
||||
const search = () => {
|
||||
if (name.value !== '') {
|
||||
searchSeriesLite(name.value).then((series) => {
|
||||
foundSeries.value = series
|
||||
})
|
||||
} else {
|
||||
foundSeries.value = []
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -23,6 +23,10 @@ import type { RequestArgs } from './base';
|
||||
// @ts-ignore
|
||||
import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError, operationServerMap } from './base';
|
||||
|
||||
export interface AddTitleGroupToSeriesRequest {
|
||||
'series_id': number;
|
||||
'title_group_id': number;
|
||||
}
|
||||
export interface AffiliatedArtistHierarchy {
|
||||
'artist': Artist;
|
||||
'artist_id': number;
|
||||
@@ -332,6 +336,14 @@ export interface EditedCssSheet {
|
||||
'old_name': string;
|
||||
'preview_image_url': string;
|
||||
}
|
||||
export interface EditedSeries {
|
||||
'banners': Array<string>;
|
||||
'covers': Array<string>;
|
||||
'description': string;
|
||||
'id': number;
|
||||
'name': string;
|
||||
'tags': Array<string>;
|
||||
}
|
||||
export interface EditedTitleGroup {
|
||||
'category'?: TitleGroupCategory | null;
|
||||
'content_type': ContentType;
|
||||
@@ -1516,6 +1528,7 @@ export interface TorrentSearch {
|
||||
'order_by_direction': OrderByDirection;
|
||||
'page': number;
|
||||
'page_size': number;
|
||||
'series_id'?: number | null;
|
||||
'title_group_include_empty_groups': boolean;
|
||||
'title_group_name'?: string | null;
|
||||
'torrent_created_by_id'?: number | null;
|
||||
@@ -5231,6 +5244,42 @@ export const SearchApiAxiosParamCreator = function (configuration?: Configuratio
|
||||
|
||||
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Case insensitive
|
||||
* @param {string} name
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
searchSeriesLite: async (name: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'name' is not null or undefined
|
||||
assertParamExists('searchSeriesLite', 'name', name)
|
||||
const localVarPath = `/api/search/series/lite`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
if (name !== undefined) {
|
||||
localVarQueryParameter['name'] = name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
@@ -5398,10 +5447,11 @@ export const SearchApiAxiosParamCreator = function (configuration?: Configuratio
|
||||
* @param {number | null} [torrentSnatchedById]
|
||||
* @param {number | null} [artistId]
|
||||
* @param {number | null} [collageId]
|
||||
* @param {number | null} [seriesId]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
searchTorrents: async (titleGroupIncludeEmptyGroups: boolean, page: number, pageSize: number, orderByColumn: TorrentSearchOrderByColumn, orderByDirection: OrderByDirection, titleGroupName?: string | null, torrentReported?: boolean | null, torrentStaffChecked?: boolean | null, torrentCreatedById?: number | null, torrentSnatchedById?: number | null, artistId?: number | null, collageId?: number | null, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
searchTorrents: async (titleGroupIncludeEmptyGroups: boolean, page: number, pageSize: number, orderByColumn: TorrentSearchOrderByColumn, orderByDirection: OrderByDirection, titleGroupName?: string | null, torrentReported?: boolean | null, torrentStaffChecked?: boolean | null, torrentCreatedById?: number | null, torrentSnatchedById?: number | null, artistId?: number | null, collageId?: number | null, seriesId?: number | null, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'titleGroupIncludeEmptyGroups' is not null or undefined
|
||||
assertParamExists('searchTorrents', 'titleGroupIncludeEmptyGroups', titleGroupIncludeEmptyGroups)
|
||||
// verify required parameter 'page' is not null or undefined
|
||||
@@ -5456,6 +5506,10 @@ export const SearchApiAxiosParamCreator = function (configuration?: Configuratio
|
||||
localVarQueryParameter['collage_id'] = collageId;
|
||||
}
|
||||
|
||||
if (seriesId !== undefined) {
|
||||
localVarQueryParameter['series_id'] = seriesId;
|
||||
}
|
||||
|
||||
if (page !== undefined) {
|
||||
localVarQueryParameter['page'] = page;
|
||||
}
|
||||
@@ -5561,6 +5615,18 @@ export const SearchApiFp = function(configuration?: Configuration) {
|
||||
const localVarOperationServerBasePath = operationServerMap['SearchApi.searchSeries']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
* Case insensitive
|
||||
* @param {string} name
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async searchSeriesLite(name: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<SeriesLite>>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.searchSeriesLite(name, options);
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||
const localVarOperationServerBasePath = operationServerMap['SearchApi.searchSeriesLite']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {string} name
|
||||
@@ -5617,11 +5683,12 @@ export const SearchApiFp = function(configuration?: Configuration) {
|
||||
* @param {number | null} [torrentSnatchedById]
|
||||
* @param {number | null} [artistId]
|
||||
* @param {number | null} [collageId]
|
||||
* @param {number | null} [seriesId]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async searchTorrents(titleGroupIncludeEmptyGroups: boolean, page: number, pageSize: number, orderByColumn: TorrentSearchOrderByColumn, orderByDirection: OrderByDirection, titleGroupName?: string | null, torrentReported?: boolean | null, torrentStaffChecked?: boolean | null, torrentCreatedById?: number | null, torrentSnatchedById?: number | null, artistId?: number | null, collageId?: number | null, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<PaginatedResultsTitleGroupHierarchyLite>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.searchTorrents(titleGroupIncludeEmptyGroups, page, pageSize, orderByColumn, orderByDirection, titleGroupName, torrentReported, torrentStaffChecked, torrentCreatedById, torrentSnatchedById, artistId, collageId, options);
|
||||
async searchTorrents(titleGroupIncludeEmptyGroups: boolean, page: number, pageSize: number, orderByColumn: TorrentSearchOrderByColumn, orderByDirection: OrderByDirection, titleGroupName?: string | null, torrentReported?: boolean | null, torrentStaffChecked?: boolean | null, torrentCreatedById?: number | null, torrentSnatchedById?: number | null, artistId?: number | null, collageId?: number | null, seriesId?: number | null, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<PaginatedResultsTitleGroupHierarchyLite>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.searchTorrents(titleGroupIncludeEmptyGroups, page, pageSize, orderByColumn, orderByDirection, titleGroupName, torrentReported, torrentStaffChecked, torrentCreatedById, torrentSnatchedById, artistId, collageId, seriesId, options);
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||
const localVarOperationServerBasePath = operationServerMap['SearchApi.searchTorrents']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
@@ -5689,6 +5756,15 @@ export const SearchApiFactory = function (configuration?: Configuration, basePat
|
||||
searchSeries(page: number, pageSize: number, name?: string | null, tags?: Array<string> | null, options?: RawAxiosRequestConfig): AxiosPromise<SeriesSearchResponse> {
|
||||
return localVarFp.searchSeries(page, pageSize, name, tags, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* Case insensitive
|
||||
* @param {string} name
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
searchSeriesLite(name: string, options?: RawAxiosRequestConfig): AxiosPromise<Array<SeriesLite>> {
|
||||
return localVarFp.searchSeriesLite(name, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {string} name
|
||||
@@ -5736,11 +5812,12 @@ export const SearchApiFactory = function (configuration?: Configuration, basePat
|
||||
* @param {number | null} [torrentSnatchedById]
|
||||
* @param {number | null} [artistId]
|
||||
* @param {number | null} [collageId]
|
||||
* @param {number | null} [seriesId]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
searchTorrents(titleGroupIncludeEmptyGroups: boolean, page: number, pageSize: number, orderByColumn: TorrentSearchOrderByColumn, orderByDirection: OrderByDirection, titleGroupName?: string | null, torrentReported?: boolean | null, torrentStaffChecked?: boolean | null, torrentCreatedById?: number | null, torrentSnatchedById?: number | null, artistId?: number | null, collageId?: number | null, options?: RawAxiosRequestConfig): AxiosPromise<PaginatedResultsTitleGroupHierarchyLite> {
|
||||
return localVarFp.searchTorrents(titleGroupIncludeEmptyGroups, page, pageSize, orderByColumn, orderByDirection, titleGroupName, torrentReported, torrentStaffChecked, torrentCreatedById, torrentSnatchedById, artistId, collageId, options).then((request) => request(axios, basePath));
|
||||
searchTorrents(titleGroupIncludeEmptyGroups: boolean, page: number, pageSize: number, orderByColumn: TorrentSearchOrderByColumn, orderByDirection: OrderByDirection, titleGroupName?: string | null, torrentReported?: boolean | null, torrentStaffChecked?: boolean | null, torrentCreatedById?: number | null, torrentSnatchedById?: number | null, artistId?: number | null, collageId?: number | null, seriesId?: number | null, options?: RawAxiosRequestConfig): AxiosPromise<PaginatedResultsTitleGroupHierarchyLite> {
|
||||
return localVarFp.searchTorrents(titleGroupIncludeEmptyGroups, page, pageSize, orderByColumn, orderByDirection, titleGroupName, torrentReported, torrentStaffChecked, torrentCreatedById, torrentSnatchedById, artistId, collageId, seriesId, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -5808,6 +5885,16 @@ export class SearchApi extends BaseAPI {
|
||||
return SearchApiFp(this.configuration).searchSeries(page, pageSize, name, tags, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive
|
||||
* @param {string} name
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
public searchSeriesLite(name: string, options?: RawAxiosRequestConfig) {
|
||||
return SearchApiFp(this.configuration).searchSeriesLite(name, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} name
|
||||
@@ -5858,11 +5945,12 @@ export class SearchApi extends BaseAPI {
|
||||
* @param {number | null} [torrentSnatchedById]
|
||||
* @param {number | null} [artistId]
|
||||
* @param {number | null} [collageId]
|
||||
* @param {number | null} [seriesId]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
public searchTorrents(titleGroupIncludeEmptyGroups: boolean, page: number, pageSize: number, orderByColumn: TorrentSearchOrderByColumn, orderByDirection: OrderByDirection, titleGroupName?: string | null, torrentReported?: boolean | null, torrentStaffChecked?: boolean | null, torrentCreatedById?: number | null, torrentSnatchedById?: number | null, artistId?: number | null, collageId?: number | null, options?: RawAxiosRequestConfig) {
|
||||
return SearchApiFp(this.configuration).searchTorrents(titleGroupIncludeEmptyGroups, page, pageSize, orderByColumn, orderByDirection, titleGroupName, torrentReported, torrentStaffChecked, torrentCreatedById, torrentSnatchedById, artistId, collageId, options).then((request) => request(this.axios, this.basePath));
|
||||
public searchTorrents(titleGroupIncludeEmptyGroups: boolean, page: number, pageSize: number, orderByColumn: TorrentSearchOrderByColumn, orderByDirection: OrderByDirection, titleGroupName?: string | null, torrentReported?: boolean | null, torrentStaffChecked?: boolean | null, torrentCreatedById?: number | null, torrentSnatchedById?: number | null, artistId?: number | null, collageId?: number | null, seriesId?: number | null, options?: RawAxiosRequestConfig) {
|
||||
return SearchApiFp(this.configuration).searchTorrents(titleGroupIncludeEmptyGroups, page, pageSize, orderByColumn, orderByDirection, titleGroupName, torrentReported, torrentStaffChecked, torrentCreatedById, torrentSnatchedById, artistId, collageId, seriesId, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5938,6 +6026,12 @@ export const searchSeries = async (requestParameters: SearchSeriesRequest, optio
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
export const searchSeriesLite = async (name: string, options?: RawAxiosRequestConfig): Promise<Array<SeriesLite>> => {
|
||||
const response = await searchApi.searchSeriesLite(name, options);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export interface SearchTitleGroupInfoRequest {
|
||||
/** */
|
||||
'name': string;
|
||||
@@ -6008,11 +6102,13 @@ export interface SearchTorrentsRequest {
|
||||
'artist_id'?: number | null;
|
||||
/** */
|
||||
'collage_id'?: number | null;
|
||||
/** */
|
||||
'series_id'?: number | null;
|
||||
}
|
||||
|
||||
|
||||
export const searchTorrents = async (requestParameters: SearchTorrentsRequest, options?: RawAxiosRequestConfig): Promise<PaginatedResultsTitleGroupHierarchyLite> => {
|
||||
const response = await searchApi.searchTorrents(requestParameters['title_group_include_empty_groups']!, requestParameters['page']!, requestParameters['page_size']!, requestParameters['order_by_column']!, requestParameters['order_by_direction']!, requestParameters['title_group_name']!, requestParameters['torrent_reported']!, requestParameters['torrent_staff_checked']!, requestParameters['torrent_created_by_id']!, requestParameters['torrent_snatched_by_id']!, requestParameters['artist_id']!, requestParameters['collage_id']!, options);
|
||||
const response = await searchApi.searchTorrents(requestParameters['title_group_include_empty_groups']!, requestParameters['page']!, requestParameters['page_size']!, requestParameters['order_by_column']!, requestParameters['order_by_direction']!, requestParameters['title_group_name']!, requestParameters['torrent_reported']!, requestParameters['torrent_staff_checked']!, requestParameters['torrent_created_by_id']!, requestParameters['torrent_snatched_by_id']!, requestParameters['artist_id']!, requestParameters['collage_id']!, requestParameters['series_id']!, options);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
@@ -6022,6 +6118,45 @@ export const searchTorrents = async (requestParameters: SearchTorrentsRequest, o
|
||||
*/
|
||||
export const SeriesApiAxiosParamCreator = function (configuration?: Configuration) {
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @param {AddTitleGroupToSeriesRequest} addTitleGroupToSeriesRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
addTitleGroupToSeries: async (addTitleGroupToSeriesRequest: AddTitleGroupToSeriesRequest, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'addTitleGroupToSeriesRequest' is not null or undefined
|
||||
assertParamExists('addTitleGroupToSeries', 'addTitleGroupToSeriesRequest', addTitleGroupToSeriesRequest)
|
||||
const localVarPath = `/api/series/title-group`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication http required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(addTitleGroupToSeriesRequest, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {UserCreatedSeries} userCreatedSeries
|
||||
@@ -6061,6 +6196,45 @@ export const SeriesApiAxiosParamCreator = function (configuration?: Configuratio
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {EditedSeries} editedSeries
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
editSeries: async (editedSeries: EditedSeries, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'editedSeries' is not null or undefined
|
||||
assertParamExists('editSeries', 'editedSeries', editedSeries)
|
||||
const localVarPath = `/api/series`;
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication http required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
|
||||
|
||||
localVarHeaderParameter['Content-Type'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(editedSeries, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {number} id
|
||||
@@ -6106,6 +6280,18 @@ export const SeriesApiAxiosParamCreator = function (configuration?: Configuratio
|
||||
export const SeriesApiFp = function(configuration?: Configuration) {
|
||||
const localVarAxiosParamCreator = SeriesApiAxiosParamCreator(configuration)
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @param {AddTitleGroupToSeriesRequest} addTitleGroupToSeriesRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async addTitleGroupToSeries(addTitleGroupToSeriesRequest: AddTitleGroupToSeriesRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<TitleGroup>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.addTitleGroupToSeries(addTitleGroupToSeriesRequest, options);
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||
const localVarOperationServerBasePath = operationServerMap['SeriesApi.addTitleGroupToSeries']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {UserCreatedSeries} userCreatedSeries
|
||||
@@ -6118,6 +6304,18 @@ export const SeriesApiFp = function(configuration?: Configuration) {
|
||||
const localVarOperationServerBasePath = operationServerMap['SeriesApi.createSeries']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {EditedSeries} editedSeries
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async editSeries(editedSeries: EditedSeries, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Series>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.editSeries(editedSeries, options);
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||
const localVarOperationServerBasePath = operationServerMap['SeriesApi.editSeries']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {number} id
|
||||
@@ -6139,6 +6337,15 @@ export const SeriesApiFp = function(configuration?: Configuration) {
|
||||
export const SeriesApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
|
||||
const localVarFp = SeriesApiFp(configuration)
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @param {AddTitleGroupToSeriesRequest} addTitleGroupToSeriesRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
addTitleGroupToSeries(addTitleGroupToSeriesRequest: AddTitleGroupToSeriesRequest, options?: RawAxiosRequestConfig): AxiosPromise<TitleGroup> {
|
||||
return localVarFp.addTitleGroupToSeries(addTitleGroupToSeriesRequest, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {UserCreatedSeries} userCreatedSeries
|
||||
@@ -6148,6 +6355,15 @@ export const SeriesApiFactory = function (configuration?: Configuration, basePat
|
||||
createSeries(userCreatedSeries: UserCreatedSeries, options?: RawAxiosRequestConfig): AxiosPromise<Series> {
|
||||
return localVarFp.createSeries(userCreatedSeries, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {EditedSeries} editedSeries
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
editSeries(editedSeries: EditedSeries, options?: RawAxiosRequestConfig): AxiosPromise<Series> {
|
||||
return localVarFp.editSeries(editedSeries, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param {number} id
|
||||
@@ -6164,6 +6380,16 @@ export const SeriesApiFactory = function (configuration?: Configuration, basePat
|
||||
* SeriesApi - object-oriented interface
|
||||
*/
|
||||
export class SeriesApi extends BaseAPI {
|
||||
/**
|
||||
*
|
||||
* @param {AddTitleGroupToSeriesRequest} addTitleGroupToSeriesRequest
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
public addTitleGroupToSeries(addTitleGroupToSeriesRequest: AddTitleGroupToSeriesRequest, options?: RawAxiosRequestConfig) {
|
||||
return SeriesApiFp(this.configuration).addTitleGroupToSeries(addTitleGroupToSeriesRequest, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {UserCreatedSeries} userCreatedSeries
|
||||
@@ -6174,6 +6400,16 @@ export class SeriesApi extends BaseAPI {
|
||||
return SeriesApiFp(this.configuration).createSeries(userCreatedSeries, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {EditedSeries} editedSeries
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
public editSeries(editedSeries: EditedSeries, options?: RawAxiosRequestConfig) {
|
||||
return SeriesApiFp(this.configuration).editSeries(editedSeries, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} id
|
||||
@@ -6190,12 +6426,24 @@ export const seriesApi = new SeriesApi(undefined, undefined, globalAxios);
|
||||
|
||||
|
||||
|
||||
export const addTitleGroupToSeries = async (addTitleGroupToSeriesRequest: AddTitleGroupToSeriesRequest, options?: RawAxiosRequestConfig): Promise<TitleGroup> => {
|
||||
const response = await seriesApi.addTitleGroupToSeries(addTitleGroupToSeriesRequest, options);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
export const createSeries = async (userCreatedSeries: UserCreatedSeries, options?: RawAxiosRequestConfig): Promise<Series> => {
|
||||
const response = await seriesApi.createSeries(userCreatedSeries, options);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
export const editSeries = async (editedSeries: EditedSeries, options?: RawAxiosRequestConfig): Promise<Series> => {
|
||||
const response = await seriesApi.editSeries(editedSeries, options);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
|
||||
export const getSeries = async (id: number, options?: RawAxiosRequestConfig): Promise<SeriesAndTitleGroupHierarchyLite> => {
|
||||
const response = await seriesApi.getSeries(id, options);
|
||||
return response.data;
|
||||
|
||||
@@ -115,7 +115,7 @@ export class Configuration {
|
||||
* @return True if the given MIME is JSON, false otherwise.
|
||||
*/
|
||||
public isJsonMime(mime: string): boolean {
|
||||
const jsonMime: RegExp = new RegExp('^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i');
|
||||
const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i');
|
||||
return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,4 +15,3 @@
|
||||
|
||||
export * from "./api";
|
||||
export * from "./configuration";
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import SeriesSlimHeader from '@/components/series/SeriesSlimHeader.vue'
|
||||
import ContentContainer from '@/components/ContentContainer.vue'
|
||||
@@ -32,7 +32,7 @@ const title_groups = ref<TitleGroupHierarchyLite[]>([])
|
||||
const title_group_preview_mode = ref<'table' | 'cover-only'>('table') // TODO: make a select button to switch from cover-only to table
|
||||
const siteName = import.meta.env.VITE_SITE_NAME
|
||||
|
||||
onMounted(async () => {
|
||||
const fetchSeries = async () => {
|
||||
const id = Number(route.params.id)
|
||||
// TODO: either toast an error message + redirect or show an error component
|
||||
if (!Number.isNaN(id)) {
|
||||
@@ -42,7 +42,13 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
document.title = `${series.value?.name} - ${siteName}`
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
fetchSeries()
|
||||
})
|
||||
|
||||
watch(() => route.params.id, fetchSeries, { immediate: true })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user