|
| 1 | +package com.igot.cb.service.impl; |
| 2 | + |
| 3 | +import com.igot.cb.cassandra.CassandraOperation; |
| 4 | +import com.igot.cb.model.ApiResponse; |
| 5 | +import com.igot.cb.service.ContentInfoServiceImpl; |
| 6 | +import com.igot.cb.service.LearningPathwayRetireService; |
| 7 | +import com.igot.cb.util.AccessTokenValidator; |
| 8 | +import com.igot.cb.util.Constants; |
| 9 | +import lombok.extern.slf4j.Slf4j; |
| 10 | +import org.apache.commons.collections4.MapUtils; |
| 11 | +import org.springframework.http.HttpStatus; |
| 12 | +import org.springframework.stereotype.Service; |
| 13 | +import org.springframework.util.CollectionUtils; |
| 14 | +import org.apache.commons.lang3.StringUtils; |
| 15 | + |
| 16 | +import java.util.*; |
| 17 | + |
| 18 | +@Service |
| 19 | +@Slf4j |
| 20 | +public class LearningPathwayRetireServiceImpl implements LearningPathwayRetireService { |
| 21 | + |
| 22 | + private final AccessTokenValidator accessTokenValidator; |
| 23 | + private final CassandraOperation cassandraOperation; |
| 24 | + private final ContentInfoServiceImpl contentService; |
| 25 | + |
| 26 | + public LearningPathwayRetireServiceImpl(AccessTokenValidator accessTokenValidator, |
| 27 | + CassandraOperation cassandraOperation, |
| 28 | + ContentInfoServiceImpl contentService) { |
| 29 | + this.accessTokenValidator = accessTokenValidator; |
| 30 | + this.cassandraOperation = cassandraOperation; |
| 31 | + this.contentService = contentService; |
| 32 | + } |
| 33 | + |
| 34 | + @Override |
| 35 | + public ApiResponse retireLearningPathway(String userToken, String contentId) { |
| 36 | + ApiResponse response = new ApiResponse(); |
| 37 | + |
| 38 | + try { |
| 39 | + log.info("LearningPathwayRetireServiceImpl::retireLearningPathway: starting validation for contentId: {}", contentId); |
| 40 | + String userId = accessTokenValidator.fetchUserIdFromAccessToken(userToken, response); |
| 41 | + |
| 42 | + if (StringUtils.isBlank(userId)) { |
| 43 | + response.getParams().setStatus(Constants.FAILED); |
| 44 | + response.getParams().setErr(Constants.USER_ID_DOESNT_EXIST); |
| 45 | + response.setResponseCode(HttpStatus.BAD_REQUEST); |
| 46 | + return response; |
| 47 | + } |
| 48 | + |
| 49 | + // Validate user has SPV_PUBLISHER role |
| 50 | + if (!hasSPVPublisherRole(userId)) { |
| 51 | + log.info("User {} does not have SPV_PUBLISHER role", userId); |
| 52 | + return commonApiResponse(response, "User does not have SPV_PUBLISHER role", HttpStatus.FORBIDDEN); |
| 53 | + } |
| 54 | + |
| 55 | + Map<String, Object> content = contentService.readContent(contentId, Arrays.asList(Constants.BATCHES, Constants.CREATED_BY, Constants.STATUS, Constants.COURSE_CATEGORY)); |
| 56 | + |
| 57 | + if (MapUtils.isEmpty(content)) { |
| 58 | + return commonApiResponse(response, "Content not found", HttpStatus.NOT_FOUND); |
| 59 | + } |
| 60 | + |
| 61 | + String createdBy = (String) content.get(Constants.CREATED_BY); |
| 62 | + if(StringUtils.isNotBlank(createdBy) && !userId.equals(createdBy)){ |
| 63 | + return commonApiResponse(response, "Content is not created by user", HttpStatus.BAD_REQUEST); |
| 64 | + } |
| 65 | + |
| 66 | + if(!Constants.LEARNING_PATHWAY.equals(content.get(Constants.COURSE_CATEGORY))){ |
| 67 | + return commonApiResponse(response, "Content is not learning pathway", HttpStatus.BAD_REQUEST); |
| 68 | + } |
| 69 | + |
| 70 | + List<Map<String, Object>> batches = (List<Map<String, Object>>) content.get(Constants.BATCHES); |
| 71 | + |
| 72 | + if (CollectionUtils.isEmpty(batches)) { |
| 73 | + log.info("No batches found for content {}, proceeding with retirement", contentId); |
| 74 | + return proceedWithRetirement(contentId, response); |
| 75 | + } |
| 76 | + |
| 77 | + // Check for active enrollments |
| 78 | + if (hasActiveEnrollments(batches)) { |
| 79 | + log.info("Active enrollments found for content {}, cannot retire", contentId); |
| 80 | + return commonApiResponse(response, "Active enrollments available. Cannot retire the content.", |
| 81 | + HttpStatus.BAD_REQUEST); |
| 82 | + } |
| 83 | + |
| 84 | + log.info("No active enrollments found for content {}, proceeding with retirement", contentId); |
| 85 | + return proceedWithRetirement(contentId, response); |
| 86 | + |
| 87 | + } catch (Exception e) { |
| 88 | + log.error("Error while retiring content with validation for contentId: {}", contentId, e); |
| 89 | + return commonApiResponse(response, "Failed to retire content: " + e.getMessage(), |
| 90 | + HttpStatus.INTERNAL_SERVER_ERROR); |
| 91 | + } |
| 92 | + } |
| 93 | + |
| 94 | + /** |
| 95 | + * Check if there are active enrollments for the content |
| 96 | + * @param batches - List of batches associated with content |
| 97 | + * @return true if active enrollments exist, false otherwise |
| 98 | + */ |
| 99 | + private boolean hasActiveEnrollments(List<Map<String, Object>> batches) { |
| 100 | + |
| 101 | + for (Map<String, Object> batch : batches) { |
| 102 | + String batchId = (String) batch.get(Constants.BATCH_ID); |
| 103 | + |
| 104 | + if (StringUtils.isBlank(batchId)) { |
| 105 | + continue; |
| 106 | + } |
| 107 | + log.debug("Checking enrollments for batchId: {}", batchId); |
| 108 | + Map<String, Object> properties = new HashMap<>(); |
| 109 | + properties.put(Constants.BATCH_ID, batchId); |
| 110 | + List<Map<String, Object>> enrollments = cassandraOperation.getRecordsByProperties( |
| 111 | + Constants.KEYSPACE_SUNBIRD_COURSE, |
| 112 | + Constants.ENROLLMENT_BATCH_LOOKUP, |
| 113 | + properties, |
| 114 | + Arrays.asList(Constants.USER_ID, Constants.ACTIVE), |
| 115 | + null |
| 116 | + ); |
| 117 | + |
| 118 | + if (!CollectionUtils.isEmpty(enrollments)) { |
| 119 | + return true; |
| 120 | + } |
| 121 | + } |
| 122 | + return false; |
| 123 | + } |
| 124 | + |
| 125 | + /** |
| 126 | + * Proceed with content retirement |
| 127 | + * @param contentId - Content ID to retire |
| 128 | + * @param response - ApiResponse object to populate |
| 129 | + * @return ApiResponse with retirement status |
| 130 | + */ |
| 131 | + private ApiResponse proceedWithRetirement(String contentId, ApiResponse response) { |
| 132 | + try { |
| 133 | + Map<String, Object> contentRetireStatusMap = contentService.retireContent(contentId); |
| 134 | + if (MapUtils.isNotEmpty(contentRetireStatusMap)) { |
| 135 | + log.info("Content retired successfully: {}", contentId); |
| 136 | + return commonApiResponse(response, "Content retired successfully", HttpStatus.OK); |
| 137 | + } else { |
| 138 | + log.info("Retirement API returned empty response for {}", contentId); |
| 139 | + return commonApiResponse(response, "Retirement API returned empty response", |
| 140 | + HttpStatus.INTERNAL_SERVER_ERROR); |
| 141 | + } |
| 142 | + } catch (Exception ex) { |
| 143 | + log.error("Failed to retire content {}", contentId, ex); |
| 144 | + return commonApiResponse(response, "Failed to retire content: " + ex.getMessage(), |
| 145 | + HttpStatus.INTERNAL_SERVER_ERROR); |
| 146 | + } |
| 147 | + } |
| 148 | + |
| 149 | + /** |
| 150 | + * Check if user has SPV_PUBLISHER role |
| 151 | + * @param userId - User ID to validate |
| 152 | + * @return true if user has SPV_PUBLISHER role, false otherwise |
| 153 | + */ |
| 154 | + private boolean hasSPVPublisherRole(String userId) { |
| 155 | + try { |
| 156 | + log.debug("Checking if user {} has SPV_PUBLISHER role", userId); |
| 157 | + |
| 158 | + Map<String, Object> properties = new HashMap<>(); |
| 159 | + properties.put(Constants.USER_ID, userId); |
| 160 | + properties.put(Constants.ROLE, Constants.SPV_PUBLISHER); |
| 161 | + |
| 162 | + List<Map<String, Object>> userRoles = cassandraOperation.getRecordsByProperties( |
| 163 | + Constants.KEYSPACE_SUNBIRD, |
| 164 | + Constants.TABLE_USER_ROLES, |
| 165 | + properties, |
| 166 | + null, |
| 167 | + null |
| 168 | + ); |
| 169 | + |
| 170 | + boolean hasRole = !CollectionUtils.isEmpty(userRoles); |
| 171 | + log.info("User {} has SPV_PUBLISHER role: {}", userId, hasRole); |
| 172 | + return hasRole; |
| 173 | + |
| 174 | + } catch (Exception e) { |
| 175 | + log.error("Error checking role for user {}", userId, e); |
| 176 | + return false; |
| 177 | + } |
| 178 | + } |
| 179 | + |
| 180 | + /** |
| 181 | + * Build response with custom data |
| 182 | + * @param response - ApiResponse object to populate |
| 183 | + * @param message - Message to set |
| 184 | + * @param statusCode - HTTP status code |
| 185 | + * @return ApiResponse with provided details |
| 186 | + */ |
| 187 | + private ApiResponse commonApiResponse(ApiResponse response, String message, HttpStatus statusCode) { |
| 188 | + response.put(Constants.MESSAGE, message); |
| 189 | + response.setResponseCode(statusCode); |
| 190 | + return response; |
| 191 | + } |
| 192 | +} |
0 commit comments