diff --git a/SOCIAL_MEDIA_CREDENTIALS_API_FRONTEND.md b/SOCIAL_MEDIA_CREDENTIALS_API_FRONTEND.md new file mode 100644 index 0000000..21acbf1 --- /dev/null +++ b/SOCIAL_MEDIA_CREDENTIALS_API_FRONTEND.md @@ -0,0 +1,396 @@ +# Social Media Credentials API - Frontend Guide + +## Обзор изменений + +API для управления credentials социальных сетей был обновлен для поддержки разных форматов данных в зависимости от платформы. Поле `credentials` теперь может принимать как простую строку (токен), так и JSON объект для платформ, требующих несколько параметров. + +## Базовый URL + +``` +http://your-server:port/api/social-media/credentials +``` + +## Аутентификация + +Все endpoints требуют JWT токен в заголовке `Authorization`: + +``` +Authorization: Bearer +``` + +## Изменения в API + +### Поле `credentials` теперь поддерживает разные типы + +**До изменений:** + +- `credentials` был только `String` (токен) + +**После изменений:** + +- `credentials` может быть `String` (для простых токенов) или `Object` (для сложных структур) + +### Поддерживаемые форматы + +#### 1. Простой токен (String) - для Facebook, LinkedIn + +```json +{ + "platform": "facebook", + "credentials": "EAABwzLix..." +} +``` + +#### 2. JSON объект (Object) - для Telegram и других платформ с несколькими параметрами + +```json +{ + "platform": "telegram", + "credentials": { + "botToken": "123456789:ABCdefGHIjklMNOpqrsTUVwxyz", + "chatId": "-1001234567890" + } +} +``` + +## Endpoints + +### 1. Сохранение/обновление credentials + +**Endpoint:** `POST /api/social-media/credentials` + +**Headers:** + +``` +Authorization: Bearer +Content-Type: application/json +``` + +**Request Body для простого токена (Facebook/LinkedIn):** + +```json +{ + "platform": "facebook", + "credentials": "EAABwzLix..." +} +``` + +**Request Body для JSON объекта (Telegram):** + +```json +{ + "platform": "telegram", + "credentials": { + "botToken": "123456789:ABCdefGHIjklMNOpqrsTUVwxyz", + "chatId": "-1001234567890" + } +} +``` + +**Response 200 OK:** + +```json +{ + "success": true, + "message": "Credentials успешно сохранены для платформы telegram", + "data": { + "platform": "telegram", + "hasCredentials": true, + "createdAt": "2024-01-15T10:30:00", + "updatedAt": "2024-01-15T10:30:00" + } +} +``` + +**Примеры использования (JavaScript):** + +```javascript +// Сохранение простого токена (Facebook/LinkedIn) +const saveFacebookCredentials = async (accessToken) => { + const response = await fetch('/api/social-media/credentials', { + method: 'POST', + headers: { + Authorization: `Bearer ${jwtToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + platform: 'facebook', + credentials: accessToken, // Простая строка + }), + }); + + const data = await response.json(); + return data; +}; + +// Сохранение JSON объекта (Telegram) +const saveTelegramCredentials = async (botToken, chatId) => { + const response = await fetch('/api/social-media/credentials', { + method: 'POST', + headers: { + Authorization: `Bearer ${jwtToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + platform: 'telegram', + credentials: { + // JSON объект + botToken: botToken, + chatId: chatId, + }, + }), + }); + + const data = await response.json(); + return data; +}; + +// Использование +await saveFacebookCredentials('EAABwzLix...'); +await saveTelegramCredentials('123456789:ABC...', '-1001234567890'); +``` + +### 2. Получение информации о credentials + +**Endpoint:** `GET /api/social-media/credentials/{platform}` + +**Headers:** + +``` +Authorization: Bearer +``` + +**Path Parameters:** + +- `platform` (string) - Название платформы + +**Response 200 OK:** + +```json +{ + "success": true, + "message": "Операция выполнена успешно", + "data": { + "platform": "telegram", + "hasCredentials": true + } +} +``` + +### 3. Получение списка всех credentials + +**Endpoint:** `GET /api/social-media/credentials` + +**Headers:** + +``` +Authorization: Bearer +``` + +**Response 200 OK:** + +```json +{ + "success": true, + "message": "Операция выполнена успешно", + "data": [ + { + "platform": "facebook", + "hasCredentials": true, + "createdAt": "2024-01-15T10:30:00", + "updatedAt": "2024-01-15T10:30:00" + }, + { + "platform": "telegram", + "hasCredentials": true, + "createdAt": "2024-01-15T11:00:00", + "updatedAt": "2024-01-15T11:00:00" + } + ] +} +``` + +### 4. Удаление credentials + +**Endpoint:** `DELETE /api/social-media/credentials/{platform}` + +**Headers:** + +``` +Authorization: Bearer +``` + +**Path Parameters:** + +- `platform` (string) - Название платформы + +**Response 200 OK:** + +```json +{ + "success": true, + "message": "Credentials для платформы telegram успешно удалены", + "data": null +} +``` + +## Форматы credentials по платформам + +### Facebook + +```json +{ + "platform": "facebook", + "credentials": "EAABwzLix..." // Access Token +} +``` + +### LinkedIn + +```json +{ + "platform": "linkedin", + "credentials": "AQV..." // Access Token +} +``` + +### Telegram + +```json +{ + "platform": "telegram", + "credentials": { + "botToken": "123456789:ABCdefGHIjklMNOpqrsTUVwxyz", + "chatId": "-1001234567890" + } +} +``` + +**Примечание для Telegram:** + +- `botToken` - токен бота, полученный от @BotFather +- `chatId` - ID чата/канала (может быть отрицательным для групп и каналов) +- Формат: `-1001234567890` для супергрупп и каналов + +## Обработка ошибок + +### 400 Bad Request - Ошибка валидации + +```json +{ + "success": false, + "message": "Ошибка валидации", + "error": { + "code": "VALIDATION_ERROR", + "message": "Platform is required", + "details": { + "platform": "Platform is required" + } + } +} +``` + +### 401 Unauthorized + +```json +{ + "success": false, + "message": "Не авторизован", + "error": { + "code": "UNAUTHORIZED", + "message": "Требуется аутентификация. Пожалуйста, предоставьте валидный JWT токен." + } +} +``` + +### 500 Internal Server Error + +```json +{ + "success": false, + "message": "Внутренняя ошибка сервера", + "error": { + "code": "INTERNAL_SERVER_ERROR", + "message": "Произошла ошибка при сохранении credentials" + } +} +``` + +## Миграция с старого API + +Если вы использовали старый API, где `credentials` был только строкой, изменения минимальны: + +**Старый код:** + +```javascript +body: JSON.stringify({ + platform: 'facebook', + credentials: 'EAABwzLix...', +}); +``` + +**Новый код (без изменений для простых токенов):** + +```javascript +// Работает как раньше +body: JSON.stringify({ + platform: 'facebook', + credentials: 'EAABwzLix...', // String по-прежнему поддерживается +}); +``` + +**Для Telegram (новый формат):** + +```javascript +body: JSON.stringify({ + platform: 'telegram', + credentials: { + // Теперь можно передавать объект + botToken: '...', + chatId: '...', + }, +}); +``` + +## Важные замечания + +1. **Обратная совместимость**: API полностью обратно совместим. Старый формат (String) продолжает работать. + +2. **Автоматическая конвертация**: Если вы передаете объект, он автоматически сериализуется в JSON строку перед сохранением. + +3. **Безопасность**: Все credentials автоматически шифруются перед сохранением в базе данных. + +4. **Валидация**: Поле `credentials` обязательно (`@NotNull`), но может быть как строкой, так и объектом. + +## Примеры для TypeScript + +```typescript +interface SimpleCredentials { + platform: string; + credentials: string; // Для Facebook, LinkedIn +} + +interface TelegramCredentials { + platform: 'telegram'; + credentials: { + botToken: string; + chatId: string; + }; +} + +type CredentialsRequest = SimpleCredentials | TelegramCredentials; + +// Использование +const saveCredentials = async (request: CredentialsRequest) => { + const response = await fetch('/api/social-media/credentials', { + method: 'POST', + headers: { + Authorization: `Bearer ${jwtToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(request), + }); + + return response.json(); +}; +``` diff --git a/src/main/java/kz/konturai/parser/controller/SocialMediaCredentialsController.java b/src/main/java/kz/konturai/parser/controller/SocialMediaCredentialsController.java index d8d464c..b5a8198 100644 --- a/src/main/java/kz/konturai/parser/controller/SocialMediaCredentialsController.java +++ b/src/main/java/kz/konturai/parser/controller/SocialMediaCredentialsController.java @@ -1,9 +1,12 @@ package kz.konturai.parser.controller; +import com.fasterxml.jackson.databind.ObjectMapper; import kz.konturai.parser.dto.*; import kz.konturai.parser.model.SocialMediaCredentials; import kz.konturai.parser.service.JwtService; import kz.konturai.parser.service.SocialMediaCredentialsService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; @@ -19,193 +22,219 @@ import java.util.stream.Collectors; @RequestMapping("/api/social-media/credentials") public class SocialMediaCredentialsController { - private final SocialMediaCredentialsService credentialsService; - private final JwtService jwtService; + private static final Logger logger = LoggerFactory.getLogger(SocialMediaCredentialsController.class); - public SocialMediaCredentialsController( - SocialMediaCredentialsService credentialsService, - JwtService jwtService) { - this.credentialsService = credentialsService; - this.jwtService = jwtService; - } + private final SocialMediaCredentialsService credentialsService; + private final JwtService jwtService; + private final ObjectMapper objectMapper; - private String extractUserIdFromHeader(String authHeader) { - if (authHeader == null || authHeader.isEmpty()) { - return null; - } - return jwtService.extractUserIdFromHeader(authHeader); - } - - private ResponseEntity unauthorizedResponse() { - ErrorResponse error = new ErrorResponse( - "UNAUTHORIZED", - "Требуется аутентификация. Пожалуйста, предоставьте валидный JWT токен."); - return ResponseEntity.status(HttpStatus.UNAUTHORIZED) - .body(ApiResponse.error("Не авторизован", error)); - } - - /** - * Сохранение или обновление credentials для платформы - * POST /api/social-media/credentials - */ - @PostMapping - public ResponseEntity saveCredentials( - @RequestHeader(value = "Authorization", required = false) String authHeader, - @Valid @RequestBody SocialMediaCredentialsRequest request) { - - String userId = extractUserIdFromHeader(authHeader); - if (userId == null) { - return unauthorizedResponse(); + public SocialMediaCredentialsController( + SocialMediaCredentialsService credentialsService, + JwtService jwtService) { + this.credentialsService = credentialsService; + this.jwtService = jwtService; + this.objectMapper = new ObjectMapper(); } - try { - SocialMediaCredentials credentials = credentialsService.saveCredentials( - userId, - request.getPlatform(), - request.getCredentials() - ); - - SocialMediaCredentialsResponse response = new SocialMediaCredentialsResponse( - credentials.getPlatform(), - true, - credentials.getCreatedAt(), - credentials.getUpdatedAt() - ); - - return ResponseEntity.ok(ApiResponse.success( - "Credentials успешно сохранены для платформы " + request.getPlatform(), - response)); - - } catch (IllegalArgumentException e) { - ErrorResponse error = new ErrorResponse("VALIDATION_ERROR", e.getMessage()); - return ResponseEntity.badRequest() - .body(ApiResponse.error("Ошибка валидации", error)); - } catch (Exception e) { - ErrorResponse error = new ErrorResponse( - "INTERNAL_SERVER_ERROR", - "Произошла ошибка при сохранении credentials"); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .body(ApiResponse.error("Внутренняя ошибка сервера", error)); - } - } - - /** - * Получение информации о credentials для платформы - * GET /api/social-media/credentials/{platform} - */ - @GetMapping("/{platform}") - public ResponseEntity getCredentials( - @RequestHeader(value = "Authorization", required = false) String authHeader, - @PathVariable String platform) { - - String userId = extractUserIdFromHeader(authHeader); - if (userId == null) { - return unauthorizedResponse(); + private String extractUserIdFromHeader(String authHeader) { + if (authHeader == null || authHeader.isEmpty()) { + return null; + } + return jwtService.extractUserIdFromHeader(authHeader); } - boolean hasCredentials = credentialsService.hasCredentials(userId, platform); - SocialMediaCredentialsResponse response = new SocialMediaCredentialsResponse( - platform, - hasCredentials - ); - - return ResponseEntity.ok(ApiResponse.success(response)); - } - - /** - * Получение списка всех платформ с credentials - * GET /api/social-media/credentials - */ - @GetMapping - public ResponseEntity getAllCredentials( - @RequestHeader(value = "Authorization", required = false) String authHeader) { - - String userId = extractUserIdFromHeader(authHeader); - if (userId == null) { - return unauthorizedResponse(); - } - - List credentialsList = credentialsService.getUserCredentials(userId); - List responseList = credentialsList.stream() - .map(cred -> new SocialMediaCredentialsResponse( - cred.getPlatform(), - true, - cred.getCreatedAt(), - cred.getUpdatedAt() - )) - .collect(Collectors.toList()); - - return ResponseEntity.ok(ApiResponse.success(responseList)); - } - - /** - * Удаление credentials для платформы - * DELETE /api/social-media/credentials/{platform} - */ - @DeleteMapping("/{platform}") - public ResponseEntity deleteCredentials( - @RequestHeader(value = "Authorization", required = false) String authHeader, - @PathVariable String platform) { - - String userId = extractUserIdFromHeader(authHeader); - if (userId == null) { - return unauthorizedResponse(); - } - - try { - if (!credentialsService.hasCredentials(userId, platform)) { + private ResponseEntity unauthorizedResponse() { ErrorResponse error = new ErrorResponse( - "NOT_FOUND", - "Credentials для платформы " + platform + " не найдены"); - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ApiResponse.error("Credentials не найдены", error)); - } - - credentialsService.deleteCredentials(userId, platform); - - return ResponseEntity.ok(ApiResponse.success( - "Credentials для платформы " + platform + " успешно удалены", - null)); - - } catch (IllegalArgumentException e) { - ErrorResponse error = new ErrorResponse("VALIDATION_ERROR", e.getMessage()); - return ResponseEntity.badRequest() - .body(ApiResponse.error("Ошибка валидации", error)); - } catch (Exception e) { - ErrorResponse error = new ErrorResponse( - "INTERNAL_SERVER_ERROR", - "Произошла ошибка при удалении credentials"); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .body(ApiResponse.error("Внутренняя ошибка сервера", error)); + "UNAUTHORIZED", + "Требуется аутентификация. Пожалуйста, предоставьте валидный JWT токен."); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body(ApiResponse.error("Не авторизован", error)); } - } - @ExceptionHandler(MethodArgumentNotValidException.class) - public ResponseEntity> handleValidationException( - MethodArgumentNotValidException ex) { + /** + * Сохранение или обновление credentials для платформы + * POST /api/social-media/credentials + */ + @PostMapping + public ResponseEntity saveCredentials( + @RequestHeader(value = "Authorization", required = false) String authHeader, + @Valid @RequestBody SocialMediaCredentialsRequest request) { - Map details = new HashMap<>(); - ex.getBindingResult().getFieldErrors().forEach(error -> { - details.put(error.getField(), error.getDefaultMessage()); - }); + String userId = extractUserIdFromHeader(authHeader); + if (userId == null) { + return unauthorizedResponse(); + } - ErrorResponse errorResponse = new ErrorResponse( - "VALIDATION_ERROR", - "Ошибка валидации входных данных", - details); + try { + // Конвертируем credentials в строку: если это String - используем как есть, + // если Object - сериализуем в JSON + String credentialsString = convertCredentialsToString(request.getCredentials()); - return ResponseEntity.badRequest() - .body(ApiResponse.error("Ошибка валидации", errorResponse)); - } + SocialMediaCredentials credentials = credentialsService.saveCredentials( + userId, + request.getPlatform(), + credentialsString); - @ExceptionHandler(Exception.class) - public ResponseEntity> handleGenericException(Exception e) { - ErrorResponse errorResponse = new ErrorResponse( - "INTERNAL_SERVER_ERROR", - "Произошла внутренняя ошибка сервера. Попробуйте позже."); + SocialMediaCredentialsResponse response = new SocialMediaCredentialsResponse( + credentials.getPlatform(), + true, + credentials.getCreatedAt(), + credentials.getUpdatedAt()); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .body(ApiResponse.error("Внутренняя ошибка сервера", errorResponse)); - } + return ResponseEntity.ok(ApiResponse.success( + "Credentials успешно сохранены для платформы " + request.getPlatform(), + response)); + + } catch (IllegalArgumentException e) { + ErrorResponse error = new ErrorResponse("VALIDATION_ERROR", e.getMessage()); + return ResponseEntity.badRequest() + .body(ApiResponse.error("Ошибка валидации", error)); + } catch (Exception e) { + ErrorResponse error = new ErrorResponse( + "INTERNAL_SERVER_ERROR", + "Произошла ошибка при сохранении credentials"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ApiResponse.error("Внутренняя ошибка сервера", error)); + } + } + + /** + * Получение информации о credentials для платформы + * GET /api/social-media/credentials/{platform} + */ + @GetMapping("/{platform}") + public ResponseEntity getCredentials( + @RequestHeader(value = "Authorization", required = false) String authHeader, + @PathVariable String platform) { + + String userId = extractUserIdFromHeader(authHeader); + if (userId == null) { + return unauthorizedResponse(); + } + + boolean hasCredentials = credentialsService.hasCredentials(userId, platform); + SocialMediaCredentialsResponse response = new SocialMediaCredentialsResponse( + platform, + hasCredentials); + + return ResponseEntity.ok(ApiResponse.success(response)); + } + + /** + * Получение списка всех платформ с credentials + * GET /api/social-media/credentials + */ + @GetMapping + public ResponseEntity getAllCredentials( + @RequestHeader(value = "Authorization", required = false) String authHeader) { + + String userId = extractUserIdFromHeader(authHeader); + if (userId == null) { + return unauthorizedResponse(); + } + + List credentialsList = credentialsService.getUserCredentials(userId); + List responseList = credentialsList.stream() + .map(cred -> new SocialMediaCredentialsResponse( + cred.getPlatform(), + true, + cred.getCreatedAt(), + cred.getUpdatedAt())) + .collect(Collectors.toList()); + + return ResponseEntity.ok(ApiResponse.success(responseList)); + } + + /** + * Удаление credentials для платформы + * DELETE /api/social-media/credentials/{platform} + */ + @DeleteMapping("/{platform}") + public ResponseEntity deleteCredentials( + @RequestHeader(value = "Authorization", required = false) String authHeader, + @PathVariable String platform) { + + String userId = extractUserIdFromHeader(authHeader); + if (userId == null) { + return unauthorizedResponse(); + } + + try { + if (!credentialsService.hasCredentials(userId, platform)) { + ErrorResponse error = new ErrorResponse( + "NOT_FOUND", + "Credentials для платформы " + platform + " не найдены"); + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(ApiResponse.error("Credentials не найдены", error)); + } + + credentialsService.deleteCredentials(userId, platform); + + return ResponseEntity.ok(ApiResponse.success( + "Credentials для платформы " + platform + " успешно удалены", + null)); + + } catch (IllegalArgumentException e) { + ErrorResponse error = new ErrorResponse("VALIDATION_ERROR", e.getMessage()); + return ResponseEntity.badRequest() + .body(ApiResponse.error("Ошибка валидации", error)); + } catch (Exception e) { + ErrorResponse error = new ErrorResponse( + "INTERNAL_SERVER_ERROR", + "Произошла ошибка при удалении credentials"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ApiResponse.error("Внутренняя ошибка сервера", error)); + } + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity> handleValidationException( + MethodArgumentNotValidException ex) { + + Map details = new HashMap<>(); + ex.getBindingResult().getFieldErrors().forEach(error -> { + details.put(error.getField(), error.getDefaultMessage()); + }); + + ErrorResponse errorResponse = new ErrorResponse( + "VALIDATION_ERROR", + "Ошибка валидации входных данных", + details); + + return ResponseEntity.badRequest() + .body(ApiResponse.error("Ошибка валидации", errorResponse)); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity> handleGenericException(Exception e) { + ErrorResponse errorResponse = new ErrorResponse( + "INTERNAL_SERVER_ERROR", + "Произошла внутренняя ошибка сервера. Попробуйте позже."); + + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ApiResponse.error("Внутренняя ошибка сервера", errorResponse)); + } + + /** + * Конвертирует credentials (Object или String) в строку для сохранения + * Если это String - возвращает как есть + * Если это Object - сериализует в JSON строку + */ + private String convertCredentialsToString(Object credentials) { + if (credentials == null) { + throw new IllegalArgumentException("Credentials cannot be null"); + } + + if (credentials instanceof String) { + return (String) credentials; + } + + try { + // Сериализуем объект в JSON строку + return objectMapper.writeValueAsString(credentials); + } catch (Exception e) { + logger.error("Failed to serialize credentials to JSON", e); + throw new IllegalArgumentException("Failed to serialize credentials: " + e.getMessage(), e); + } + } } - diff --git a/src/main/java/kz/konturai/parser/dto/SocialMediaCredentialsRequest.java b/src/main/java/kz/konturai/parser/dto/SocialMediaCredentialsRequest.java index 2b1ffd1..11ce8bb 100644 --- a/src/main/java/kz/konturai/parser/dto/SocialMediaCredentialsRequest.java +++ b/src/main/java/kz/konturai/parser/dto/SocialMediaCredentialsRequest.java @@ -1,19 +1,22 @@ package kz.konturai.parser.dto; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; public class SocialMediaCredentialsRequest { @NotBlank(message = "Platform is required") private String platform; - @NotBlank(message = "Credentials are required") - private String credentials; + @NotNull(message = "Credentials are required") + @JsonProperty("credentials") + private Object credentials; // Может быть String (токен) или Object (JSON объект для Telegram и др.) public SocialMediaCredentialsRequest() { } - public SocialMediaCredentialsRequest(String platform, String credentials) { + public SocialMediaCredentialsRequest(String platform, Object credentials) { this.platform = platform; this.credentials = credentials; } @@ -26,12 +29,11 @@ public class SocialMediaCredentialsRequest { this.platform = platform; } - public String getCredentials() { + public Object getCredentials() { return credentials; } - public void setCredentials(String credentials) { + public void setCredentials(Object credentials) { this.credentials = credentials; } } - diff --git a/src/main/java/kz/konturai/parser/model/SocialMediaCredentials.java b/src/main/java/kz/konturai/parser/model/SocialMediaCredentials.java index 4fe33ac..33f6f09 100644 --- a/src/main/java/kz/konturai/parser/model/SocialMediaCredentials.java +++ b/src/main/java/kz/konturai/parser/model/SocialMediaCredentials.java @@ -19,7 +19,7 @@ public class SocialMediaCredentials { private String platform; // "facebook", "instagram", etc. @Field("encrypted_credentials") - private String encryptedCredentials; + private Object encryptedCredentials; @Field("created_at") private LocalDateTime createdAt; @@ -32,7 +32,7 @@ public class SocialMediaCredentials { this.updatedAt = LocalDateTime.now(); } - public SocialMediaCredentials(String userId, String platform, String encryptedCredentials) { + public SocialMediaCredentials(String userId, String platform, Object encryptedCredentials) { this(); this.userId = userId; this.platform = platform; @@ -63,11 +63,11 @@ public class SocialMediaCredentials { this.platform = platform; } - public String getEncryptedCredentials() { + public Object getEncryptedCredentials() { return encryptedCredentials; } - public void setEncryptedCredentials(String encryptedCredentials) { + public void setEncryptedCredentials(Object encryptedCredentials) { this.encryptedCredentials = encryptedCredentials; this.updatedAt = LocalDateTime.now(); } @@ -88,4 +88,3 @@ public class SocialMediaCredentials { this.updatedAt = updatedAt; } } - diff --git a/src/main/java/kz/konturai/parser/service/SocialMediaCredentialsService.java b/src/main/java/kz/konturai/parser/service/SocialMediaCredentialsService.java index 3915075..52601ee 100644 --- a/src/main/java/kz/konturai/parser/service/SocialMediaCredentialsService.java +++ b/src/main/java/kz/konturai/parser/service/SocialMediaCredentialsService.java @@ -27,9 +27,11 @@ public class SocialMediaCredentialsService { /** * Сохраняет или обновляет credentials пользователя для платформы * - * @param userId ID пользователя - * @param platform Платформа (facebook, instagram, etc.) - * @param credentials Открытые credentials (будут зашифрованы) + * @param userId ID пользователя + * @param platform Платформа (facebook, instagram, telegram, etc.) + * @param credentials Открытые credentials (могут быть String для токена или + * JSON строка для объектов, например для Telegram: + * {"botToken": "...", "chatId": "..."}) * @return Сохраненные credentials */ public SocialMediaCredentials saveCredentials(String userId, String platform, String credentials) { @@ -39,7 +41,7 @@ public class SocialMediaCredentialsService { // Проверяем существующие credentials Optional existing = repository.findByUserIdAndPlatform(userId, platform); - + SocialMediaCredentials credentialsEntity; if (existing.isPresent()) { credentialsEntity = existing.get(); @@ -61,7 +63,7 @@ public class SocialMediaCredentialsService { /** * Получает и расшифровывает credentials пользователя для платформы * - * @param userId ID пользователя + * @param userId ID пользователя * @param platform Платформа * @return Расшифрованные credentials или null если не найдены */ @@ -80,7 +82,22 @@ public class SocialMediaCredentialsService { try { SocialMediaCredentials credentialsEntity = optCredentials.get(); - return encryptionService.decrypt(credentialsEntity.getEncryptedCredentials()); + Object encryptedCreds = credentialsEntity.getEncryptedCredentials(); + + // Если это String (старый формат или зашифрованная строка), расшифровываем + if (encryptedCreds instanceof String) { + return encryptionService.decrypt((String) encryptedCreds); + } + + // Если это Object (например, Map из MongoDB), сериализуем в JSON, затем + // расшифровываем + // Но обычно зашифрованные данные хранятся как String + if (encryptedCreds != null) { + String encryptedString = encryptedCreds.toString(); + return encryptionService.decrypt(encryptedString); + } + + return null; } catch (Exception e) { logger.error("Failed to decrypt credentials for user {} and platform {}", userId, platform, e); throw new RuntimeException("Failed to decrypt credentials", e); @@ -90,7 +107,7 @@ public class SocialMediaCredentialsService { /** * Проверяет наличие credentials для пользователя и платформы * - * @param userId ID пользователя + * @param userId ID пользователя * @param platform Платформа * @return true если credentials существуют */ @@ -105,7 +122,7 @@ public class SocialMediaCredentialsService { /** * Удаляет credentials пользователя для платформы * - * @param userId ID пользователя + * @param userId ID пользователя * @param platform Платформа */ public void deleteCredentials(String userId, String platform) { @@ -147,4 +164,3 @@ public class SocialMediaCredentialsService { return repository.findByUserId(userId); } } -