package com.openisle.service; import com.fasterxml.jackson.databind.JsonNode; import com.openisle.model.Role; import com.openisle.model.User; import com.openisle.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.Collections; import java.util.Optional; @Service @RequiredArgsConstructor public class GithubAuthService { private final UserRepository userRepository; private final RestTemplate restTemplate = new RestTemplate(); @Value("${github.client-id:}") private String clientId; @Value("${github.client-secret:}") private String clientSecret; public Optional authenticate(String code, String reason, com.openisle.model.RegisterMode mode, String redirectUri) { try { String tokenUrl = "https://github.com/login/oauth/access_token"; HttpHeaders headers = new HttpHeaders(); headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); HttpEntity request = new HttpEntity<>( "client_id=" + clientId + "&client_secret=" + clientSecret + "&code=" + code + (redirectUri != null ? "&redirect_uri=" + redirectUri : ""), headers); ResponseEntity tokenRes = restTemplate.postForEntity(tokenUrl, request, JsonNode.class); if (!tokenRes.getStatusCode().is2xxSuccessful() || tokenRes.getBody() == null || !tokenRes.getBody().has("access_token")) { return Optional.empty(); } String accessToken = tokenRes.getBody().get("access_token").asText(); HttpHeaders authHeaders = new HttpHeaders(); authHeaders.setBearerAuth(accessToken); HttpEntity entity = new HttpEntity<>(authHeaders); ResponseEntity userRes = restTemplate.exchange( "https://api.github.com/user", HttpMethod.GET, entity, JsonNode.class); if (!userRes.getStatusCode().is2xxSuccessful() || userRes.getBody() == null) { return Optional.empty(); } JsonNode userNode = userRes.getBody(); String username = userNode.hasNonNull("login") ? userNode.get("login").asText() : null; String email = null; if (userNode.hasNonNull("email")) { email = userNode.get("email").asText(); } if (email == null || email.isEmpty()) { ResponseEntity emailsRes = restTemplate.exchange( "https://api.github.com/user/emails", HttpMethod.GET, entity, JsonNode.class); if (emailsRes.getStatusCode().is2xxSuccessful() && emailsRes.getBody() != null && emailsRes.getBody().isArray()) { for (JsonNode n : emailsRes.getBody()) { if (n.has("primary") && n.get("primary").asBoolean()) { email = n.get("email").asText(); break; } } } } if (email == null) { email = username + "@users.noreply.github.com"; } return Optional.of(processUser(email, username, reason, mode)); } catch (Exception e) { return Optional.empty(); } } private User processUser(String email, String username, String reason, com.openisle.model.RegisterMode mode) { Optional existing = userRepository.findByEmail(email); if (existing.isPresent()) { User user = existing.get(); if (!user.isVerified()) { user.setVerified(true); user.setVerificationCode(null); userRepository.save(user); } if (!user.isApproved() && reason != null && !reason.isEmpty()) { user.setRegisterReason(reason); userRepository.save(user); } return user; } String baseUsername = username != null ? username : email.split("@")[0]; String finalUsername = baseUsername; int suffix = 1; while (userRepository.findByUsername(finalUsername).isPresent()) { finalUsername = baseUsername + suffix++; } User user = new User(); user.setUsername(finalUsername); user.setEmail(email); user.setPassword(""); user.setRole(Role.USER); user.setVerified(true); user.setRegisterReason(reason); user.setApproved(mode == com.openisle.model.RegisterMode.DIRECT); user.setAvatar("https://github.com/" + finalUsername + ".png"); return userRepository.save(user); } }