Restricted Profiles (#1581)
* Added ReadingList age rating from all series and started on some unit tests for the new flows. * Wrote more unit tests for Reading Lists * Added ability to restrict user accounts to a given age rating via admin edit user modal and invite user. This commit contains all basic code, but no query modifications. * When updating a reading list's title via UI, explicitly check if there is an existing RL with the same title. * Refactored Reading List calculation to work properly in the flows it's invoked from. * Cleaned up an unused method * Promoted Collections no longer show tags where a Series exists within them that is above the user's age rating. * Collection search now respects age restrictions * Series Detail page now checks if the user has explicit access (as a user might bypass with direct url access) * Hooked up age restriction for dashboard activity streams. * Refactored some methods from Series Controller and Library Controller to a new Search Controller to keep things organized * Updated Search to respect age restrictions * Refactored all the Age Restriction queries to extensions * Related Series no longer show up if they are out of the age restriction * Fixed a bad mapping for the update age restriction api * Fixed a UI state change after updating age restriction * Fixed unit test * Added a migration for reading lists * Code cleanup
This commit is contained in:
parent
0ad1638ec0
commit
442af965c6
63 changed files with 4638 additions and 262 deletions
|
|
@ -10,8 +10,16 @@ import { EVENTS, MessageHubService } from './message-hub.service';
|
|||
import { ThemeService } from './theme.service';
|
||||
import { InviteUserResponse } from '../_models/invite-user-response';
|
||||
import { UserUpdateEvent } from '../_models/events/user-update-event';
|
||||
import { DeviceService } from './device.service';
|
||||
import { UpdateEmailResponse } from '../_models/email/update-email-response';
|
||||
import { AgeRating } from '../_models/metadata/age-rating';
|
||||
|
||||
export enum Role {
|
||||
Admin = 'Admin',
|
||||
ChangePassword = 'Change Password',
|
||||
Bookmark = 'Bookmark',
|
||||
Download = 'Download',
|
||||
ChangeRestriction = 'Change Restriction'
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
|
@ -49,19 +57,23 @@ export class AccountService implements OnDestroy {
|
|||
}
|
||||
|
||||
hasAdminRole(user: User) {
|
||||
return user && user.roles.includes('Admin');
|
||||
return user && user.roles.includes(Role.Admin);
|
||||
}
|
||||
|
||||
hasChangePasswordRole(user: User) {
|
||||
return user && user.roles.includes('Change Password');
|
||||
return user && user.roles.includes(Role.ChangePassword);
|
||||
}
|
||||
|
||||
hasChangeAgeRestrictionRole(user: User) {
|
||||
return user && user.roles.includes(Role.ChangeRestriction);
|
||||
}
|
||||
|
||||
hasDownloadRole(user: User) {
|
||||
return user && user.roles.includes('Download');
|
||||
return user && user.roles.includes(Role.Download);
|
||||
}
|
||||
|
||||
hasBookmarkRole(user: User) {
|
||||
return user && user.roles.includes('Bookmark');
|
||||
return user && user.roles.includes(Role.Bookmark);
|
||||
}
|
||||
|
||||
getRoles() {
|
||||
|
|
@ -149,7 +161,7 @@ export class AccountService implements OnDestroy {
|
|||
return this.httpClient.post<string>(this.baseUrl + 'account/resend-confirmation-email?userId=' + userId, {}, {responseType: 'text' as 'json'});
|
||||
}
|
||||
|
||||
inviteUser(model: {email: string, roles: Array<string>, libraries: Array<number>}) {
|
||||
inviteUser(model: {email: string, roles: Array<string>, libraries: Array<number>, ageRestriction: AgeRating}) {
|
||||
return this.httpClient.post<InviteUserResponse>(this.baseUrl + 'account/invite', model);
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +198,7 @@ export class AccountService implements OnDestroy {
|
|||
return this.httpClient.post(this.baseUrl + 'account/reset-password', {username, password, oldPassword}, {responseType: 'json' as 'text'});
|
||||
}
|
||||
|
||||
update(model: {email: string, roles: Array<string>, libraries: Array<number>, userId: number}) {
|
||||
update(model: {email: string, roles: Array<string>, libraries: Array<number>, userId: number, ageRestriction: AgeRating}) {
|
||||
return this.httpClient.post(this.baseUrl + 'account/update', model);
|
||||
}
|
||||
|
||||
|
|
@ -194,6 +206,10 @@ export class AccountService implements OnDestroy {
|
|||
return this.httpClient.post<UpdateEmailResponse>(this.baseUrl + 'account/update/email', {email});
|
||||
}
|
||||
|
||||
updateAgeRestriction(ageRating: AgeRating) {
|
||||
return this.httpClient.post(this.baseUrl + 'account/update/age-restriction', {ageRating});
|
||||
}
|
||||
|
||||
/**
|
||||
* This will get latest preferences for a user and cache them into user store
|
||||
* @returns
|
||||
|
|
|
|||
|
|
@ -113,12 +113,4 @@ export class LibraryService {
|
|||
return this.libraryTypes[libraryId];
|
||||
}));
|
||||
}
|
||||
|
||||
search(term: string) {
|
||||
if (term === '') {
|
||||
return of(new SearchResultGroup());
|
||||
}
|
||||
return this.httpClient.get<SearchResultGroup>(this.baseUrl + 'library/search?queryString=' + encodeURIComponent(term));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
31
UI/Web/src/app/_services/search.service.ts
Normal file
31
UI/Web/src/app/_services/search.service.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { of } from 'rxjs';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { SearchResultGroup } from '../_models/search/search-result-group';
|
||||
import { Series } from '../_models/series';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SearchService {
|
||||
|
||||
baseUrl = environment.apiUrl;
|
||||
|
||||
constructor(private httpClient: HttpClient) { }
|
||||
|
||||
search(term: string) {
|
||||
if (term === '') {
|
||||
return of(new SearchResultGroup());
|
||||
}
|
||||
return this.httpClient.get<SearchResultGroup>(this.baseUrl + 'search/search?queryString=' + encodeURIComponent(term));
|
||||
}
|
||||
|
||||
getSeriesForMangaFile(mangaFileId: number) {
|
||||
return this.httpClient.get<Series | null>(this.baseUrl + 'search/series-for-mangafile?mangaFileId=' + mangaFileId);
|
||||
}
|
||||
|
||||
getSeriesForChapter(chapterId: number) {
|
||||
return this.httpClient.get<Series | null>(this.baseUrl + 'search/series-for-chapter?chapterId=' + chapterId);
|
||||
}
|
||||
}
|
||||
|
|
@ -78,14 +78,6 @@ export class SeriesService {
|
|||
return this.httpClient.get<ChapterMetadata>(this.baseUrl + 'series/chapter-metadata?chapterId=' + chapterId);
|
||||
}
|
||||
|
||||
getSeriesForMangaFile(mangaFileId: number) {
|
||||
return this.httpClient.get<Series | null>(this.baseUrl + 'series/series-for-mangafile?mangaFileId=' + mangaFileId);
|
||||
}
|
||||
|
||||
getSeriesForChapter(chapterId: number) {
|
||||
return this.httpClient.get<Series | null>(this.baseUrl + 'series/series-for-chapter?chapterId=' + chapterId);
|
||||
}
|
||||
|
||||
delete(seriesId: number) {
|
||||
return this.httpClient.delete<boolean>(this.baseUrl + 'series/' + seriesId);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue