11package com .stackscout .controller ;
22
3- import com .stackscout .dto .ErrorResponse ;
4- import com .stackscout .model .Library ;
3+ import com .stackscout .dto .CreateLibraryRequest ;
4+ import com .stackscout .dto .LibraryDto ;
5+ import com .stackscout .dto .UpdateLibraryRequest ;
6+ import com .stackscout .service .LibraryService ;
7+ import io .swagger .v3 .oas .annotations .Operation ;
8+ import io .swagger .v3 .oas .annotations .tags .Tag ;
9+ import jakarta .validation .Valid ;
10+ import lombok .RequiredArgsConstructor ;
11+ import org .springframework .data .domain .Page ;
12+ import org .springframework .data .domain .PageRequest ;
13+ import org .springframework .data .domain .Pageable ;
14+ import org .springframework .data .domain .Sort ;
515import org .springframework .http .HttpStatus ;
616import org .springframework .http .ResponseEntity ;
717import org .springframework .web .bind .annotation .*;
818
9- import java .time .LocalDateTime ;
10- import java .util .ArrayList ;
1119import java .util .HashMap ;
1220import java .util .List ;
1321import java .util .Map ;
1422
23+ /**
24+ * REST контроллер для управления библиотеками
25+ */
1526@ RestController
1627@ RequestMapping ("/api/v1/libraries" )
1728@ CrossOrigin (origins = "*" )
29+ @ RequiredArgsConstructor
30+ @ Tag (name = "Libraries" , description = "API для управления библиотеками" )
1831public class LibraryController {
1932
20- private final List <Library > libraries = new ArrayList <>();
21- private Long nextId = 1L ;
22-
23- public LibraryController () {
24- libraries .add (new Library (
25- nextId ++, "requests" , "2.31.0" , "pypi" ,
26- "Apache-2.0" , 95 , "2023-05-22" ,
27- "https://github.com/psf/requests" ,
28- "HTTP библиотека для Python"
29- ));
30-
31- libraries .add (new Library (
32- nextId ++, "django" , "5.0.0" , "pypi" ,
33- "BSD-3-Clause" , 98 , "2023-12-04" ,
34- "https://github.com/django/django" ,
35- "Веб-фреймворк для Python"
36- ));
37-
38- libraries .add (new Library (
39- nextId ++, "react" , "18.2.0" , "npm" ,
40- "MIT" , 99 , "2023-06-14" ,
41- "https://github.com/facebook/react" ,
42- "JavaScript библиотека для UI"
43- ));
44- }
33+ private final LibraryService libraryService ;
4534
35+ @ Operation (summary = "Получить все библиотеки" , description = "Возвращает список всех библиотек с пагинацией" )
4636 @ GetMapping
4737 public ResponseEntity <Map <String , Object >> getAllLibraries (
4838 @ RequestParam (defaultValue = "0" ) int page ,
49- @ RequestParam (defaultValue = "10" ) int size
39+ @ RequestParam (defaultValue = "10" ) int size ,
40+ @ RequestParam (defaultValue = "id" ) String sortBy ,
41+ @ RequestParam (defaultValue = "ASC" ) String sortDirection
5042 ) {
51- int start = Math .min (page * size , libraries .size ());
52- int end = Math .min (start + size , libraries .size ());
53- List <Library > paginatedLibraries = libraries .subList (start , end );
43+ Sort .Direction direction = Sort .Direction .fromString (sortDirection );
44+ Pageable pageable = PageRequest .of (page , size , Sort .by (direction , sortBy ));
45+
46+ Page <LibraryDto > librariesPage = libraryService .getAllLibraries (pageable );
5447
5548 Map <String , Object > response = new HashMap <>();
56- response .put ("libraries" , paginatedLibraries );
57- response .put ("totalElements" , libraries . size ());
58- response .put ("currentPage" , page );
59- response .put ("pageSize" , size );
60- response .put ("totalPages" , ( int ) Math . ceil (( double ) libraries . size () / size ));
49+ response .put ("libraries" , librariesPage . getContent () );
50+ response .put ("totalElements" , librariesPage . getTotalElements ());
51+ response .put ("currentPage" , librariesPage . getNumber () );
52+ response .put ("pageSize" , librariesPage . getSize () );
53+ response .put ("totalPages" , librariesPage . getTotalPages ( ));
6154
6255 return ResponseEntity .ok (response );
6356 }
6457
58+ @ Operation (summary = "Получить библиотеку по ID" , description = "Возвращает детали конкретной библиотеки" )
6559 @ GetMapping ("/{id}" )
66- public ResponseEntity <Library > getLibraryById (@ PathVariable Long id ) {
67- return libraries .stream ()
68- .filter (lib -> lib .getId ().equals (id ))
69- .findFirst ()
70- .map (ResponseEntity ::ok )
71- .orElse (ResponseEntity .notFound ().build ());
60+ public ResponseEntity <LibraryDto > getLibraryById (@ PathVariable Long id ) {
61+ LibraryDto library = libraryService .getLibraryById (id );
62+ return ResponseEntity .ok (library );
7263 }
7364
65+ @ Operation (summary = "Поиск библиотек" , description = "Поиск библиотек по названию и/или источнику" )
7466 @ GetMapping ("/search" )
75- public ResponseEntity <List < Library >> searchLibraries (
67+ public ResponseEntity <Map < String , Object >> searchLibraries (
7668 @ RequestParam (required = false ) String query ,
77- @ RequestParam (required = false ) String source
69+ @ RequestParam (required = false ) String source ,
70+ @ RequestParam (defaultValue = "0" ) int page ,
71+ @ RequestParam (defaultValue = "10" ) int size
7872 ) {
79- List <Library > result = libraries .stream ()
80- .filter (lib -> {
81- boolean matchQuery = query == null ||
82- lib .getName ().toLowerCase ().contains (query .toLowerCase ());
83- boolean matchSource = source == null ||
84- lib .getSource ().equalsIgnoreCase (source );
85- return matchQuery && matchSource ;
86- })
87- .toList ();
88- return ResponseEntity .ok (result );
73+ Pageable pageable = PageRequest .of (page , size );
74+ Page <LibraryDto > result ;
75+
76+ if (query != null && !query .trim ().isEmpty () && source != null && !source .trim ().isEmpty ()) {
77+ result = libraryService .searchLibrariesBySource (query , source , pageable );
78+ } else if (query != null && !query .trim ().isEmpty ()) {
79+ result = libraryService .searchLibraries (query , pageable );
80+ } else if (source != null && !source .trim ().isEmpty ()) {
81+ result = libraryService .getLibrariesBySource (source , pageable );
82+ } else {
83+ result = libraryService .getAllLibraries (pageable );
84+ }
85+
86+ Map <String , Object > response = new HashMap <>();
87+ response .put ("libraries" , result .getContent ());
88+ response .put ("totalElements" , result .getTotalElements ());
89+ response .put ("currentPage" , result .getNumber ());
90+ response .put ("totalPages" , result .getTotalPages ());
91+
92+ return ResponseEntity .ok (response );
8993 }
9094
95+ @ Operation (summary = "Создать новую библиотеку" , description = "Добавляет новую библиотеку в систему" )
9196 @ PostMapping
92- public ResponseEntity <?> createLibrary (@ RequestBody Library library ) {
93- try {
94- if (library .getName () == null || library .getName ().trim ().isEmpty ()) {
95- return ResponseEntity .badRequest ()
96- .body (new ErrorResponse ("Имя библиотеки обязательно" , LocalDateTime .now ()));
97- }
98-
99- library .setId (nextId ++);
100- libraries .add (library );
101-
102- Map <String , Object > response = new HashMap <>();
103- response .put ("message" , "Библиотека успешно создана" );
104- response .put ("library" , library );
105-
106- return ResponseEntity .status (HttpStatus .CREATED ).body (response );
107- } catch (Exception e ) {
108- return ResponseEntity .status (HttpStatus .INTERNAL_SERVER_ERROR )
109- .body (new ErrorResponse ("Ошибка при создании библиотеки: " + e .getMessage (), LocalDateTime .now ()));
110- }
97+ public ResponseEntity <Map <String , Object >> createLibrary (@ Valid @ RequestBody CreateLibraryRequest request ) {
98+ LibraryDto createdLibrary = libraryService .createLibrary (request );
99+
100+ Map <String , Object > response = new HashMap <>();
101+ response .put ("message" , "Библиотека успешно создана" );
102+ response .put ("library" , createdLibrary );
103+
104+ return ResponseEntity .status (HttpStatus .CREATED ).body (response );
111105 }
112106
107+ @ Operation (summary = "Обновить библиотеку" , description = "Обновляет существующую библиотеку" )
113108 @ PutMapping ("/{id}" )
114- public ResponseEntity <?> updateLibrary (@ PathVariable Long id , @ RequestBody Library updatedLibrary ) {
115- return libraries .stream ()
116- .filter (lib -> lib .getId ().equals (id ))
117- .findFirst ()
118- .<ResponseEntity <?>>map (library -> {
119- if (updatedLibrary .getName () != null ) library .setName (updatedLibrary .getName ());
120- if (updatedLibrary .getVersion () != null ) library .setVersion (updatedLibrary .getVersion ());
121- if (updatedLibrary .getSource () != null ) library .setSource (updatedLibrary .getSource ());
122- if (updatedLibrary .getLicense () != null ) library .setLicense (updatedLibrary .getLicense ());
123- if (updatedLibrary .getHealthScore () != null ) library .setHealthScore (updatedLibrary .getHealthScore ());
124- if (updatedLibrary .getLastRelease () != null ) library .setLastRelease (updatedLibrary .getLastRelease ());
125- if (updatedLibrary .getRepository () != null ) library .setRepository (updatedLibrary .getRepository ());
126- if (updatedLibrary .getDescription () != null ) library .setDescription (updatedLibrary .getDescription ());
127-
128- Map <String , Object > response = new HashMap <>();
129- response .put ("message" , "Библиотека успешно обновлена" );
130- response .put ("library" , library );
131- return ResponseEntity .ok (response );
132- })
133- .orElseGet (() -> ResponseEntity .status (HttpStatus .NOT_FOUND )
134- .body (new ErrorResponse ("Библиотека с ID " + id + " не найдена" , LocalDateTime .now ())));
109+ public ResponseEntity <Map <String , Object >> updateLibrary (
110+ @ PathVariable Long id ,
111+ @ Valid @ RequestBody UpdateLibraryRequest request ) {
112+
113+ LibraryDto updatedLibrary = libraryService .updateLibrary (id , request );
114+
115+ Map <String , Object > response = new HashMap <>();
116+ response .put ("message" , "Библиотека успешно обновлена" );
117+ response .put ("library" , updatedLibrary );
118+
119+ return ResponseEntity .ok (response );
135120 }
136121
122+ @ Operation (summary = "Удалить библиотеку" , description = "Удаляет библиотеку из системы" )
137123 @ DeleteMapping ("/{id}" )
138- public ResponseEntity <?> deleteLibrary (@ PathVariable Long id ) {
139- boolean removed = libraries .removeIf (lib -> lib .getId ().equals (id ));
140- if (removed ) {
141- Map <String , String > response = new HashMap <>();
142- response .put ("message" , "Библиотека успешно удалена" );
143- response .put ("id" , id .toString ());
144- return ResponseEntity .ok (response );
145- } else {
146- return ResponseEntity .status (HttpStatus .NOT_FOUND )
147- .body (new ErrorResponse ("Библиотека с ID " + id + " не найдена" , LocalDateTime .now ()));
148- }
124+ public ResponseEntity <Map <String , String >> deleteLibrary (@ PathVariable Long id ) {
125+ libraryService .deleteLibrary (id );
126+
127+ Map <String , String > response = new HashMap <>();
128+ response .put ("message" , "Библиотека успешно удалена" );
129+ response .put ("id" , id .toString ());
130+
131+ return ResponseEntity .ok (response );
149132 }
150133
134+ @ Operation (summary = "Получить здоровые библиотеки" , description = "Возвращает библиотеки с оценкой здоровья выше заданного порога" )
135+ @ GetMapping ("/healthy" )
136+ public ResponseEntity <List <LibraryDto >> getHealthyLibraries (
137+ @ RequestParam (defaultValue = "80" ) Integer minScore ) {
138+ List <LibraryDto > healthyLibraries = libraryService .getHealthyLibraries (minScore );
139+ return ResponseEntity .ok (healthyLibraries );
140+ }
141+
142+ @ Operation (summary = "Статистика библиотек" , description = "Возвращает общую статистику по библиотекам" )
151143 @ GetMapping ("/stats" )
152144 public ResponseEntity <Map <String , Object >> getStats () {
145+ Page <LibraryDto > allLibraries = libraryService .getAllLibraries (Pageable .unpaged ());
146+ List <LibraryDto > libraries = allLibraries .getContent ();
147+
153148 Map <String , Object > stats = new HashMap <>();
154149 stats .put ("totalLibraries" , libraries .size ());
155150 stats .put ("sources" , Map .of (
@@ -159,10 +154,12 @@ public ResponseEntity<Map<String, Object>> getStats() {
159154 ));
160155 stats .put ("averageHealthScore" ,
161156 libraries .stream ()
162- .mapToInt (l -> l .getHealthScore () != null ? l .getHealthScore () : 0 )
157+ .filter (l -> l .getHealthScore () != null )
158+ .mapToInt (LibraryDto ::getHealthScore )
163159 .average ()
164160 .orElse (0.0 )
165161 );
162+
166163 return ResponseEntity .ok (stats );
167164 }
168165}
0 commit comments