Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ Refactor media API into multiple modules #477

Merged
merged 3 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions apps/server/src/routers/api/filters/library.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use stump_core::{
db::entity::User,
prisma::{
library::{self, WhereParam},
user,
},
};

use crate::{
filter::{
chain_optional_iter, decode_path_filter, LibraryBaseFilter, LibraryFilter,
LibraryRelationFilter,
},
routers::api::filters::apply_series_base_filters,
};

pub(crate) fn apply_library_base_filters(filters: LibraryBaseFilter) -> Vec<WhereParam> {
chain_optional_iter(
[],
[
(!filters.id.is_empty()).then(|| library::id::in_vec(filters.id)),
(!filters.name.is_empty()).then(|| library::name::in_vec(filters.name)),
(!filters.path.is_empty()).then(|| {
let decoded_paths = decode_path_filter(filters.path);
library::path::in_vec(decoded_paths)
}),
filters.search.map(library::name::contains),
],
)
}

Check warning on line 30 in apps/server/src/routers/api/filters/library.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/library.rs#L17-L30

Added lines #L17 - L30 were not covered by tests

pub(crate) fn apply_library_relation_filters(
filters: LibraryRelationFilter,
) -> Vec<WhereParam> {
chain_optional_iter(
[],
[filters
.series
.map(apply_series_base_filters)
.map(library::series::some)],
)
}

Check warning on line 42 in apps/server/src/routers/api/filters/library.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/library.rs#L32-L42

Added lines #L32 - L42 were not covered by tests

pub(crate) fn library_not_hidden_from_user_filter(user: &User) -> WhereParam {
library::hidden_from_users::none(vec![user::id::equals(user.id.clone())])
}

Check warning on line 46 in apps/server/src/routers/api/filters/library.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/library.rs#L44-L46

Added lines #L44 - L46 were not covered by tests

// FIXME: hidden libraries introduced a bug here, need to fix!

pub(crate) fn apply_library_filters_for_user(
filters: LibraryFilter,
user: &User,
) -> Vec<WhereParam> {
let not_hidden_filter = library_not_hidden_from_user_filter(user);
apply_library_base_filters(filters.base_filter)
.into_iter()
.chain(apply_library_relation_filters(filters.relation_filter))
.chain([not_hidden_filter])
.collect()
}

Check warning on line 60 in apps/server/src/routers/api/filters/library.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/library.rs#L50-L60

Added lines #L50 - L60 were not covered by tests
255 changes: 255 additions & 0 deletions apps/server/src/routers/api/filters/media.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
use prisma_client_rust::{
and,
operator::{self, or},
or,
};
use stump_core::{
db::{entity::User, query::pagination::Pagination},
prisma::{
active_reading_session, finished_reading_session,
media::{self, WhereParam},
media_metadata, series, series_metadata, tag,
},
};

use crate::{
filter::{
chain_optional_iter, decode_path_filter, MediaBaseFilter, MediaFilter,
MediaRelationFilter, ReadStatus,
},
routers::api::filters::{
apply_media_metadata_base_filters, apply_series_filters,
library_not_hidden_from_user_filter,
},
};

pub(crate) fn apply_media_read_status_filter(
user_id: String,
read_status: Vec<ReadStatus>,
) -> Vec<WhereParam> {
chain_optional_iter(
[],
[(!read_status.is_empty()).then(|| {
or(read_status
.into_iter()
.map(|rs| match rs {

Check warning on line 35 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L26-L35

Added lines #L26 - L35 were not covered by tests
ReadStatus::Reading => {
media::active_user_reading_sessions::some(vec![and![
active_reading_session::user_id::equals(user_id.clone()),
]])

Check warning on line 39 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L37-L39

Added lines #L37 - L39 were not covered by tests
},
ReadStatus::Completed => {
media::finished_user_reading_sessions::some(vec![and![
finished_reading_session::user_id::equals(user_id.clone()),
]])

Check warning on line 44 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L42-L44

Added lines #L42 - L44 were not covered by tests
},
ReadStatus::Unread => {
and![
media::active_user_reading_sessions::none(vec![
active_reading_session::user_id::equals(user_id.clone()),
]),
media::finished_user_reading_sessions::none(vec![
finished_reading_session::user_id::equals(
user_id.clone()
),
])
]

Check warning on line 56 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L47-L56

Added lines #L47 - L56 were not covered by tests
},
})
.collect())
})],
)
}

Check warning on line 62 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L58-L62

Added lines #L58 - L62 were not covered by tests

pub(crate) fn apply_media_base_filters(filters: MediaBaseFilter) -> Vec<WhereParam> {
chain_optional_iter(
[],
[
(!filters.id.is_empty()).then(|| media::id::in_vec(filters.id)),
(!filters.name.is_empty()).then(|| media::name::in_vec(filters.name)),
(!filters.extension.is_empty())
.then(|| media::extension::in_vec(filters.extension)),
(!filters.path.is_empty()).then(|| {
let decoded_paths = decode_path_filter(filters.path);
media::path::in_vec(decoded_paths)
}),
(!filters.tags.is_empty())
.then(|| media::tags::some(vec![tag::name::in_vec(filters.tags)])),
filters.search.map(|s| {
or![
media::name::contains(s.clone()),
media::metadata::is(vec![or![
media_metadata::title::contains(s.clone()),
media_metadata::summary::contains(s),
]])
]
}),
filters
.metadata
.map(apply_media_metadata_base_filters)
.map(media::metadata::is),
],
)
}

Check warning on line 93 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L64-L93

Added lines #L64 - L93 were not covered by tests

pub(crate) fn apply_media_relation_filters(
filters: MediaRelationFilter,
) -> Vec<WhereParam> {
chain_optional_iter(
[],
[filters
.series
.map(apply_series_filters)
.map(media::series::is)],
)
}

Check warning on line 105 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L95-L105

Added lines #L95 - L105 were not covered by tests

pub(crate) fn apply_media_filters(filters: MediaFilter) -> Vec<WhereParam> {
apply_media_base_filters(filters.base_filter)
.into_iter()
.chain(apply_media_relation_filters(filters.relation_filter))
.collect()
}

Check warning on line 112 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L107-L112

Added lines #L107 - L112 were not covered by tests

pub(crate) fn apply_media_library_not_hidden_for_user_filter(
user: &User,
) -> Vec<WhereParam> {
vec![media::series::is(vec![series::library::is(vec![
library_not_hidden_from_user_filter(user),
])])]
}

Check warning on line 120 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L114-L120

Added lines #L114 - L120 were not covered by tests

pub(crate) fn apply_media_filters_for_user(
filters: MediaFilter,
user: &User,
) -> Vec<WhereParam> {
let user_id = user.id.clone();
let age_restrictions = user
.age_restriction
.as_ref()
.map(|ar| apply_media_age_restriction(ar.age, ar.restrict_on_unset));

let read_status_filters = filters.base_filter.read_status.clone();
let base_filters = operator::and(
apply_media_filters(filters)
.into_iter()
.chain(age_restrictions.map(|ar| vec![ar]).unwrap_or_default())
.chain(apply_media_read_status_filter(user_id, read_status_filters))
.collect::<Vec<WhereParam>>(),
);

// TODO: This is not ideal, I am adding an _additional_ relation filter for
// the library exclusion, when I need to merge any requested filters with this one,
// instead. This was a regression from the exclusion feature I need to tackle
vec![and![
base_filters,
media::series::is(vec![series::library::is(vec![
library_not_hidden_from_user_filter(user),
])])
]]
}

Check warning on line 150 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L122-L150

Added lines #L122 - L150 were not covered by tests

pub(crate) fn apply_media_pagination<'a>(
query: media::FindMany<'a>,
pagination: &Pagination,
) -> media::FindMany<'a> {
match pagination {
Pagination::Page(page_query) => {
let (skip, take) = page_query.get_skip_take();
query.skip(skip).take(take)

Check warning on line 159 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L152-L159

Added lines #L152 - L159 were not covered by tests
},
Pagination::Cursor(cursor_params) => {
let mut cursor_query = query;
if let Some(cursor) = cursor_params.cursor.as_deref() {
cursor_query = cursor_query
.cursor(media::id::equals(cursor.to_string()))
.skip(1);
}
if let Some(limit) = cursor_params.limit {
cursor_query = cursor_query.take(limit);
}
cursor_query

Check warning on line 171 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L161-L171

Added lines #L161 - L171 were not covered by tests
},
_ => query,

Check warning on line 173 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L173

Added line #L173 was not covered by tests
}
}

Check warning on line 175 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L175

Added line #L175 was not covered by tests

/// Generates a single where condition for a media progress query to enforce media which
/// is currently in progress
pub(crate) fn apply_in_progress_filter_for_user(
user_id: String,
) -> active_reading_session::WhereParam {
and![
active_reading_session::user_id::equals(user_id),
or![
active_reading_session::page::gt(0),
active_reading_session::epubcfi::not(None),
]
]
}

Check warning on line 189 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L179-L189

Added lines #L179 - L189 were not covered by tests

/// Generates a condition to enforce age restrictions on media and their corresponding
/// series.
pub(crate) fn apply_media_age_restriction(
min_age: i32,
restrict_on_unset: bool,
) -> WhereParam {
if restrict_on_unset {
or![
// If the media has no age rating, then we can defer to the series age rating.
and![
media::metadata::is(vec![media_metadata::age_rating::equals(None)]),
media::series::is(vec![series::metadata::is(vec![
series_metadata::age_rating::not(None),
series_metadata::age_rating::lte(min_age),
])])
],
// If the media has an age rating, it must be under the user age restriction
media::metadata::is(vec![
media_metadata::age_rating::not(None),
media_metadata::age_rating::lte(min_age),
]),
]

Check warning on line 212 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L193-L212

Added lines #L193 - L212 were not covered by tests
} else {
or![
// If there is no media metadata at all, or it exists with no age rating, then we
// should try to defer to the series age rating
and![
or![
media::metadata::is_null(),
media::metadata::is(vec![media_metadata::age_rating::equals(None)])
],
media::series::is(vec![or![
// If the series has no metadata, then we can allow the media
series::metadata::is_null(),
// Or if the series has an age rating and it is under the user age restriction
series::metadata::is(vec![
series_metadata::age_rating::not(None),
series_metadata::age_rating::lte(min_age),
]),
// Or if the series has no age rating, then we can allow the media
series::metadata::is(vec![series_metadata::age_rating::equals(None)])
]])
],
// If the media has an age rating, it must be under the user age restriction
media::metadata::is(vec![
media_metadata::age_rating::not(None),
media_metadata::age_rating::lte(min_age),
]),
]

Check warning on line 239 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L214-L239

Added lines #L214 - L239 were not covered by tests
}
}

Check warning on line 241 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L241

Added line #L241 was not covered by tests

pub fn apply_media_restrictions_for_user(user: &User) -> Vec<WhereParam> {
let age_restrictions = user
.age_restriction
.as_ref()
.map(|ar| apply_media_age_restriction(ar.age, ar.restrict_on_unset));

chain_optional_iter(
[media::series::is(vec![series::library::is(vec![
library_not_hidden_from_user_filter(user),
])])],
[age_restrictions],
)
}

Check warning on line 255 in apps/server/src/routers/api/filters/media.rs

View check run for this annotation

Codecov / codecov/patch

apps/server/src/routers/api/filters/media.rs#L243-L255

Added lines #L243 - L255 were not covered by tests
Loading
Loading