From 13066b8c0a1833e5bb8b6f9174ffebf6eaa83d13 Mon Sep 17 00:00:00 2001 From: "aditya.chandel" <> Date: Mon, 17 Feb 2025 09:25:04 -0700 Subject: [PATCH] Lots of permission related stuffs --- .../booklore/mapper/BookLoreUserMapper.java | 4 +-- .../booklore/model/dto/BookLoreUser.java | 3 ++ .../booklore/model/dto/UserCreateRequest.java | 4 +++ .../model/dto/request/UserUpdateRequest.java | 3 ++ .../model/entity/BookLoreUserEntity.java | 9 ++++++ .../booklore/model/entity/LibraryEntity.java | 3 ++ .../booklore/repository/BookRepository.java | 10 ++++-- .../repository/LibraryRepository.java | 5 +++ .../booklore/service/BooksService.java | 25 +++++++++++++-- .../booklore/service/LibraryService.java | 16 +++++++++- .../booklore/service/UserService.java | 26 ++++++++++++---- .../V1__Create_Library_and_Book_Tables.sql | 12 ++++++- .../src/app/book/service/library.service.ts | 6 ++++ .../settings/admin/admin.component.html | 15 +++++++++ .../settings/admin/admin.component.ts | 31 ++++++++++++++++--- .../create-user-dialog.component.ts | 5 ++- booklore-ui/src/app/user.service.ts | 2 ++ 17 files changed, 158 insertions(+), 21 deletions(-) diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/mapper/BookLoreUserMapper.java b/booklore-api/src/main/java/com/adityachandel/booklore/mapper/BookLoreUserMapper.java index 0cbdd553b..5dad70f31 100644 --- a/booklore-api/src/main/java/com/adityachandel/booklore/mapper/BookLoreUserMapper.java +++ b/booklore-api/src/main/java/com/adityachandel/booklore/mapper/BookLoreUserMapper.java @@ -10,6 +10,7 @@ import org.mapstruct.Mapping; public interface BookLoreUserMapper { @Mapping(source = "permissions", target = "permissions") + @Mapping(source = "libraries", target = "assignedLibraries") BookLoreUser toDto(BookLoreUserEntity entity); default BookLoreUser.UserPermissions mapPermissions(UserPermissionsEntity permissions) { @@ -22,7 +23,6 @@ public interface BookLoreUserMapper { dto.setCanDownload(permissions.isPermissionDownload()); dto.setCanManipulateLibrary(permissions.isPermissionManipulateLibrary()); dto.setCanEditMetadata(permissions.isPermissionEditMetadata()); - dto.setCanEditMetadata(permissions.isPermissionEditMetadata()); return dto; } -} +} \ No newline at end of file diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/BookLoreUser.java b/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/BookLoreUser.java index 130beea11..9b41e979e 100644 --- a/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/BookLoreUser.java +++ b/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/BookLoreUser.java @@ -2,12 +2,15 @@ package com.adityachandel.booklore.model.dto; import lombok.Data; +import java.util.List; + @Data public class BookLoreUser { private Long id; private String username; private String name; private String email; + private List assignedLibraries; private UserPermissions permissions; @Data diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/UserCreateRequest.java b/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/UserCreateRequest.java index c58426f0c..598820a0c 100644 --- a/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/UserCreateRequest.java +++ b/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/UserCreateRequest.java @@ -2,6 +2,8 @@ package com.adityachandel.booklore.model.dto; import lombok.Data; +import java.util.Set; + @Data public class UserCreateRequest { private String username; @@ -13,4 +15,6 @@ public class UserCreateRequest { private boolean permissionDownload; private boolean permissionEditMetadata; private boolean permissionManipulateLibrary; + + private Set selectedLibraries; } \ No newline at end of file diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/request/UserUpdateRequest.java b/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/request/UserUpdateRequest.java index d9f969a78..71536a8c2 100644 --- a/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/request/UserUpdateRequest.java +++ b/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/request/UserUpdateRequest.java @@ -2,11 +2,14 @@ package com.adityachandel.booklore.model.dto.request; import lombok.Data; +import java.util.List; + @Data public class UserUpdateRequest { private String name; private String email; private Permissions permissions; + private List assignedLibraries; @Data public static class Permissions { diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/model/entity/BookLoreUserEntity.java b/booklore-api/src/main/java/com/adityachandel/booklore/model/entity/BookLoreUserEntity.java index dba8713fe..2f2a30b2d 100644 --- a/booklore-api/src/main/java/com/adityachandel/booklore/model/entity/BookLoreUserEntity.java +++ b/booklore-api/src/main/java/com/adityachandel/booklore/model/entity/BookLoreUserEntity.java @@ -5,6 +5,7 @@ import lombok.*; import java.time.LocalDateTime; import java.util.HashSet; +import java.util.List; import java.util.Set; @Getter @@ -44,6 +45,14 @@ public class BookLoreUserEntity { @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) private Set shelves = new HashSet<>(); + @ManyToMany + @JoinTable( + name = "user_library_mapping", + joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "library_id") + ) + private List libraries; + @PrePersist public void prePersist() { LocalDateTime now = LocalDateTime.now(); diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/model/entity/LibraryEntity.java b/booklore-api/src/main/java/com/adityachandel/booklore/model/entity/LibraryEntity.java index 329b5ddc4..a479ef373 100644 --- a/booklore-api/src/main/java/com/adityachandel/booklore/model/entity/LibraryEntity.java +++ b/booklore-api/src/main/java/com/adityachandel/booklore/model/entity/LibraryEntity.java @@ -31,6 +31,9 @@ public class LibraryEntity { @OneToMany(mappedBy = "library", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) private List libraryPaths; + @ManyToMany(mappedBy = "libraries") + private List users; + private boolean watch; private String icon; diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/repository/BookRepository.java b/booklore-api/src/main/java/com/adityachandel/booklore/repository/BookRepository.java index 871e1006d..698a730f6 100644 --- a/booklore-api/src/main/java/com/adityachandel/booklore/repository/BookRepository.java +++ b/booklore-api/src/main/java/com/adityachandel/booklore/repository/BookRepository.java @@ -1,6 +1,7 @@ package com.adityachandel.booklore.repository; import com.adityachandel.booklore.model.entity.BookEntity; +import com.adityachandel.booklore.model.entity.LibraryEntity; import com.adityachandel.booklore.model.entity.LibraryPathEntity; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -14,6 +15,7 @@ import org.springframework.stereotype.Repository; import java.util.Collection; import java.util.List; import java.util.Optional; +import java.util.Set; @Repository public interface BookRepository extends JpaRepository, JpaSpecificationExecutor { @@ -29,14 +31,16 @@ public interface BookRepository extends JpaRepository, JpaSpec Optional findBookByFileNameAndLibraryId(String fileName, long libraryId); - @Query("SELECT b FROM BookEntity b JOIN b.metadata bm WHERE LOWER(bm.title) LIKE LOWER(CONCAT('%', :title, '%'))") - List findByTitleContainingIgnoreCase(@Param("title") String title); - @Query("SELECT b FROM BookEntity b JOIN b.shelves s WHERE s.id = :shelfId") List findByShelfId(@Param("shelfId") Long shelfId); @Modifying @Query("DELETE FROM BookEntity b WHERE b.id IN (:ids)") void deleteByIdIn(Collection ids); + + @Query("SELECT b FROM BookEntity b WHERE b.library IN (SELECT l FROM LibraryEntity l WHERE l IN :userLibraries)") + List findBooksByUserLibraries(@Param("userLibraries") List userLibraries); + + List findByLibraryIdIn(Set userLibraryIds); } diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/repository/LibraryRepository.java b/booklore-api/src/main/java/com/adityachandel/booklore/repository/LibraryRepository.java index 152cf584e..00a9482a1 100644 --- a/booklore-api/src/main/java/com/adityachandel/booklore/repository/LibraryRepository.java +++ b/booklore-api/src/main/java/com/adityachandel/booklore/repository/LibraryRepository.java @@ -3,9 +3,14 @@ package com.adityachandel.booklore.repository; import com.adityachandel.booklore.model.entity.LibraryEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface LibraryRepository extends JpaRepository, JpaSpecificationExecutor { + List findByIdIn(List ids); } diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/service/BooksService.java b/booklore-api/src/main/java/com/adityachandel/booklore/service/BooksService.java index 7bf1d56d3..84d8dd67b 100644 --- a/booklore-api/src/main/java/com/adityachandel/booklore/service/BooksService.java +++ b/booklore-api/src/main/java/com/adityachandel/booklore/service/BooksService.java @@ -97,8 +97,29 @@ public class BooksService { } public List getBooks(boolean withDescription) { - return bookRepository.findAll().stream() - .map(bookEntity -> bookMapper.toBookWithDescription(bookEntity, withDescription)) + BookLoreUser user = authenticationService.getAuthenticatedUser(); + BookLoreUserEntity userEntity = userRepository.findById(user.getId()).orElseThrow(() -> new UsernameNotFoundException("User not found")); + + List books; + if (userEntity.getPermissions().isPermissionAdmin()) { + books = bookRepository.findAll(); + } else { + Set userLibraryIds = userEntity.getLibraries().stream() + .map(LibraryEntity::getId) + .collect(Collectors.toSet()); + books = bookRepository.findByLibraryIdIn(userLibraryIds); + } + + return books.stream() + .map(bookEntity -> { + UserBookProgressEntity userProgress = userBookProgressRepository.findByUserIdAndBookId(user.getId(), bookEntity.getId()) + .orElse(new UserBookProgressEntity()); + Book book = bookMapper.toBookWithDescription(bookEntity, withDescription); + book.setLastReadTime(userProgress.getLastReadTime()); + book.setPdfProgress(userProgress.getPdfProgress()); + book.setEpubProgress(userProgress.getEpubProgress()); + return book; + }) .collect(Collectors.toList()); } diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/service/LibraryService.java b/booklore-api/src/main/java/com/adityachandel/booklore/service/LibraryService.java index 6810e0dfa..414c4c557 100644 --- a/booklore-api/src/main/java/com/adityachandel/booklore/service/LibraryService.java +++ b/booklore-api/src/main/java/com/adityachandel/booklore/service/LibraryService.java @@ -4,16 +4,19 @@ import com.adityachandel.booklore.exception.ApiError; import com.adityachandel.booklore.mapper.BookMapper; import com.adityachandel.booklore.mapper.LibraryMapper; import com.adityachandel.booklore.model.dto.Book; +import com.adityachandel.booklore.model.dto.BookLoreUser; import com.adityachandel.booklore.model.dto.Library; import com.adityachandel.booklore.model.dto.LibraryPath; import com.adityachandel.booklore.model.dto.request.CreateLibraryRequest; import com.adityachandel.booklore.model.entity.BookEntity; +import com.adityachandel.booklore.model.entity.BookLoreUserEntity; import com.adityachandel.booklore.model.entity.LibraryEntity; import com.adityachandel.booklore.model.entity.LibraryPathEntity; import com.adityachandel.booklore.model.websocket.Topic; import com.adityachandel.booklore.repository.BookRepository; import com.adityachandel.booklore.repository.LibraryPathRepository; import com.adityachandel.booklore.repository.LibraryRepository; +import com.adityachandel.booklore.repository.UserRepository; import com.adityachandel.booklore.service.fileprocessor.FileProcessingUtils; import com.adityachandel.booklore.service.monitoring.MonitoringService; import jakarta.annotation.PostConstruct; @@ -21,6 +24,7 @@ import jakarta.transaction.Transactional; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import java.io.IOException; @@ -45,6 +49,8 @@ public class LibraryService { private final NotificationService notificationService; private final FileProcessingUtils fileProcessingUtils; private final MonitoringService monitoringService; + private final AuthenticationService authenticationService; + private final UserRepository userRepository; @Transactional @PostConstruct @@ -188,7 +194,15 @@ public class LibraryService { } public List getLibraries() { - List libraries = libraryRepository.findAll(); + BookLoreUser user = authenticationService.getAuthenticatedUser(); + BookLoreUserEntity userEntity = userRepository.findById(user.getId()).orElseThrow(() -> new UsernameNotFoundException("User not found")); + List libraries; + if (userEntity.getPermissions().isPermissionAdmin()) { + libraries = libraryRepository.findAll(); + } else { + List libraryIds = userEntity.getLibraries().stream().map(LibraryEntity::getId).toList(); + libraries = libraryRepository.findByIdIn(libraryIds); + } return libraries.stream().map(libraryMapper::toLibrary).toList(); } diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/service/UserService.java b/booklore-api/src/main/java/com/adityachandel/booklore/service/UserService.java index 5a6cfcc3e..c0c5a6c73 100644 --- a/booklore-api/src/main/java/com/adityachandel/booklore/service/UserService.java +++ b/booklore-api/src/main/java/com/adityachandel/booklore/service/UserService.java @@ -8,8 +8,11 @@ import com.adityachandel.booklore.model.dto.UserCreateRequest; import com.adityachandel.booklore.model.dto.request.UserLoginRequest; import com.adityachandel.booklore.model.dto.request.UserUpdateRequest; import com.adityachandel.booklore.model.entity.BookLoreUserEntity; +import com.adityachandel.booklore.model.entity.LibraryEntity; import com.adityachandel.booklore.model.entity.UserPermissionsEntity; +import com.adityachandel.booklore.repository.LibraryRepository; import com.adityachandel.booklore.repository.UserRepository; +import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -18,10 +21,7 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; @Service @@ -31,8 +31,10 @@ public class UserService { private final UserRepository userRepository; private final BookLoreUserMapper bookLoreUserMapper; private final PasswordEncoder passwordEncoder; + private final LibraryRepository libraryRepository; private final JwtUtils jwtUtils; + @Transactional public ResponseEntity> registerUser(UserCreateRequest request) { Optional existingUser = userRepository.findByUsername(request.getUsername()); if (existingUser.isPresent()) { @@ -50,10 +52,14 @@ public class UserService { permissions.setPermissionUpload(request.isPermissionUpload()); permissions.setPermissionDownload(request.isPermissionDownload()); permissions.setPermissionEditMetadata(request.isPermissionEditMetadata()); - permissions.setPermissionEditMetadata(request.isPermissionManipulateLibrary()); - + permissions.setPermissionManipulateLibrary(request.isPermissionManipulateLibrary()); bookLoreUserEntity.setPermissions(permissions); + if (request.getSelectedLibraries() != null && !request.getSelectedLibraries().isEmpty()) { + List libraries = libraryRepository.findAllById(request.getSelectedLibraries()); + bookLoreUserEntity.setLibraries(new ArrayList<>(libraries)); + } + userRepository.save(bookLoreUserEntity); String token = jwtUtils.generateToken(bookLoreUserEntity); @@ -84,11 +90,19 @@ public class UserService { public BookLoreUser updateUser(Long id, UserUpdateRequest updateRequest) { BookLoreUserEntity user = userRepository.findById(id).orElseThrow(() -> ApiError.USER_NOT_FOUND.createException(id)); + user.setName(updateRequest.getName()); user.setEmail(updateRequest.getEmail()); user.getPermissions().setPermissionUpload(updateRequest.getPermissions().isCanUpload()); user.getPermissions().setPermissionDownload(updateRequest.getPermissions().isCanDownload()); user.getPermissions().setPermissionEditMetadata(updateRequest.getPermissions().isCanEditMetadata()); + + List libraryIds = updateRequest.getAssignedLibraries(); + if (libraryIds != null) { + List updatedLibraries = libraryRepository.findAllById(libraryIds); + user.setLibraries(updatedLibraries); + } + userRepository.save(user); return bookLoreUserMapper.toDto(user); } diff --git a/booklore-api/src/main/resources/db/migration/V1__Create_Library_and_Book_Tables.sql b/booklore-api/src/main/resources/db/migration/V1__Create_Library_and_Book_Tables.sql index 9fa9d9755..9e3774c78 100644 --- a/booklore-api/src/main/resources/db/migration/V1__Create_Library_and_Book_Tables.sql +++ b/booklore-api/src/main/resources/db/migration/V1__Create_Library_and_Book_Tables.sql @@ -206,4 +206,14 @@ CREATE TABLE IF NOT EXISTS user_book_progress ); CREATE INDEX IF NOT EXISTS idx_user_book_progress_user ON user_book_progress (user_id); -CREATE INDEX IF NOT EXISTS idx_user_book_progress_book ON user_book_progress (book_id); \ No newline at end of file +CREATE INDEX IF NOT EXISTS idx_user_book_progress_book ON user_book_progress (book_id); + + +CREATE TABLE IF NOT EXISTS user_library_mapping +( + user_id BIGINT NOT NULL, + library_id BIGINT NOT NULL, + PRIMARY KEY (user_id, library_id), + CONSTRAINT fk_user_library_mapping_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE, + CONSTRAINT fk_user_library_mapping_library FOREIGN KEY (library_id) REFERENCES library (id) ON DELETE CASCADE +); \ No newline at end of file diff --git a/booklore-ui/src/app/book/service/library.service.ts b/booklore-ui/src/app/book/service/library.service.ts index d08e786a1..fa274218f 100644 --- a/booklore-ui/src/app/book/service/library.service.ts +++ b/booklore-ui/src/app/book/service/library.service.ts @@ -7,6 +7,8 @@ import {BookService} from './book.service'; import {SortOption} from '../model/sort.model'; import {LibraryState} from '../model/state/library-state.model'; import {API_CONFIG} from '../../config/api-config'; +import {FetchMetadataRequest} from '../../metadata/model/request/fetch-metadata-request.model'; +import {BookMetadata} from '../model/book.model'; @Injectable({ providedIn: 'root', @@ -138,4 +140,8 @@ export class LibraryService { getLibrariesFromState(): Library[] { return this.libraryStateSubject.value.libraries || []; } + + getAllLibrariesFromAPI(): Observable { + return this.http.get (`${this.url}`); + } } diff --git a/booklore-ui/src/app/core/component/settings/admin/admin.component.html b/booklore-ui/src/app/core/component/settings/admin/admin.component.html index ae3b712bf..3431b05d3 100644 --- a/booklore-ui/src/app/core/component/settings/admin/admin.component.html +++ b/booklore-ui/src/app/core/component/settings/admin/admin.component.html @@ -7,6 +7,7 @@ Username Full Name Email + Assigned Libraries Can Upload Can Download Can Edit Metadata @@ -26,6 +27,20 @@ {{ user.email }} + + + + + {{ user.libraryNames }} + + diff --git a/booklore-ui/src/app/core/component/settings/admin/admin.component.ts b/booklore-ui/src/app/core/component/settings/admin/admin.component.ts index e970b5d2c..4477a4464 100644 --- a/booklore-ui/src/app/core/component/settings/admin/admin.component.ts +++ b/booklore-ui/src/app/core/component/settings/admin/admin.component.ts @@ -8,23 +8,37 @@ import {NgIf, NgStyle} from '@angular/common'; import {User, UserService} from '../../../../user.service'; import {MessageService} from 'primeng/api'; import {Checkbox} from 'primeng/checkbox'; +import {MultiSelect} from 'primeng/multiselect'; +import {Library} from '../../../../book/model/library.model'; +import {LibraryService} from '../../../../book/service/library.service'; @Component({ selector: 'app-admin', - imports: [FormsModule, Button, TableModule, NgIf, Checkbox, NgStyle], + imports: [FormsModule, Button, TableModule, NgIf, Checkbox, NgStyle, MultiSelect], templateUrl: './admin.component.html', - styleUrl: './admin.component.scss', + styleUrls: ['./admin.component.scss'], }) export class AdminComponent implements OnInit { ref: DynamicDialogRef | undefined; private dialogService = inject(DialogService); private userService = inject(UserService); + private libraryService = inject(LibraryService); private messageService = inject(MessageService); - users: any[] = []; + users: User[] = []; + editingLibraryIds: number[] = []; + allLibraries: Library[] = []; ngOnInit() { this.loadUsers(); + this.libraryService.getAllLibrariesFromAPI().subscribe({ + next: (libraries) => { + this.allLibraries = libraries; + }, + error: () => { + this.messageService.add({severity: 'error', summary: 'Error', detail: 'Failed to load libraries'}); + } + }); } loadUsers() { @@ -33,6 +47,8 @@ export class AdminComponent implements OnInit { this.users = data.map(user => ({ ...user, isEditing: false, + selectedLibraryIds: user.assignedLibraries?.map(lib => lib.id) || [], + libraryNames: user.assignedLibraries?.map(lib => lib.name).join(', ') || '' })); }, error: () => { @@ -57,19 +73,24 @@ export class AdminComponent implements OnInit { toggleEdit(user: any) { user.isEditing = !user.isEditing; - if (!user.isEditing) { - this.loadUsers(); + if (user.isEditing) { + this.editingLibraryIds = [...user.selectedLibraryIds]; + } else { + user.libraryNames = user.assignedLibraries?.map((lib: Library) => lib.name).join(', ') || ''; } } saveUser(user: any) { + user.selectedLibraryIds = [...this.editingLibraryIds]; this.userService.updateUser(user.id, { name: user.name, email: user.email, permissions: user.permissions, + assignedLibraries: user.selectedLibraryIds }).subscribe({ next: () => { user.isEditing = false; + this.loadUsers(); this.messageService.add({severity: 'success', summary: 'Success', detail: 'User updated successfully'}); }, error: () => { diff --git a/booklore-ui/src/app/core/component/settings/admin/create-user-dialog/create-user-dialog.component.ts b/booklore-ui/src/app/core/component/settings/admin/create-user-dialog/create-user-dialog.component.ts index e8a8c755f..5d392c8ed 100644 --- a/booklore-ui/src/app/core/component/settings/admin/create-user-dialog/create-user-dialog.component.ts +++ b/booklore-ui/src/app/core/component/settings/admin/create-user-dialog/create-user-dialog.component.ts @@ -61,7 +61,10 @@ export class CreateUserDialogComponent implements OnInit { return; } - const userData = this.userForm.value; + const userData = { + ...this.userForm.value, + selectedLibraries: this.userForm.value.selectedLibraries.map((lib: Library) => lib.id) + }; this.userService.createUser(userData).subscribe({ next: response => { diff --git a/booklore-ui/src/app/user.service.ts b/booklore-ui/src/app/user.service.ts index 6b384afd8..1787796c5 100644 --- a/booklore-ui/src/app/user.service.ts +++ b/booklore-ui/src/app/user.service.ts @@ -4,12 +4,14 @@ import {BehaviorSubject, Observable} from 'rxjs'; import {API_CONFIG} from './config/api-config'; import {jwtDecode} from 'jwt-decode'; import {RxStompService} from './shared/websocket/rx-stomp.service'; +import {Library} from './book/model/library.model'; export interface User { id: number; username: string; name: string; email: string; + assignedLibraries: Library[]; permissions: { admin: boolean; canUpload: boolean;