feat: enhance chatbot Telegram/Discord integrations, add /remove commands and Q&A reply handling

This commit is contained in:
Shanmuga Krishnan S M
2026-08-03 08:28:47 +05:30
parent 8bd0718b72
commit d51d538ee9
20 changed files with 1243 additions and 99 deletions

View File

@@ -43,6 +43,10 @@ public class CollabController {
public CollabRequest createCollabRequest(@RequestBody CollabRequest request) {
if (request.getStatus() == null) request.setStatus("OPEN");
if (request.getApplicationsCount() == null) request.setApplicationsCount(0);
if (request.getCollaboratorsNeeded() == null || request.getCollaboratorsNeeded() < 1) {
request.setCollaboratorsNeeded(1);
}
if (request.getAcceptedCount() == null) request.setAcceptedCount(0);
request.setCreatedAt(LocalDateTime.now());
return collabRequestRepository.save(request);
}
@@ -52,6 +56,10 @@ public class CollabController {
@PathVariable Integer id,
@RequestBody CollabApplication application) {
return collabRequestRepository.findById(id).map(request -> {
if ("CLOSED".equalsIgnoreCase(request.getStatus()) || "CANCELLED".equalsIgnoreCase(request.getStatus())) {
return ResponseEntity.badRequest().<CollabApplication>build();
}
application.setCollabRequest(request);
if (application.getStatus() == null) application.setStatus("PENDING");
application.setCreatedAt(LocalDateTime.now());
@@ -95,9 +103,44 @@ public class CollabController {
@PathVariable Integer applicationId,
@RequestParam String status) {
return collabApplicationRepository.findById(applicationId).map(app -> {
app.setStatus(status.toUpperCase());
String newStatus = status.toUpperCase();
String oldStatus = app.getStatus();
app.setStatus(newStatus);
CollabApplication updated = collabApplicationRepository.save(app);
// Delete request entirely when accepted count meets requested collaborators count
if ("ACCEPTED".equals(newStatus) && !"ACCEPTED".equals(oldStatus)) {
CollabRequest parentReq = app.getCollabRequest();
if (parentReq != null) {
int accepted = (parentReq.getAcceptedCount() == null ? 0 : parentReq.getAcceptedCount()) + 1;
parentReq.setAcceptedCount(accepted);
int needed = parentReq.getCollaboratorsNeeded() == null ? 1 : parentReq.getCollaboratorsNeeded();
if (accepted >= needed) {
collabRequestRepository.delete(parentReq);
} else {
collabRequestRepository.save(parentReq);
}
}
}
return ResponseEntity.ok(updated);
}).orElse(ResponseEntity.notFound().build());
}
@GetMapping("/active/telegram/{chatId}")
public List<CollabRequest> getActiveRequestsByTelegram(@PathVariable Long chatId) {
return collabRequestRepository.findByTelegramChatIdAndStatusOrderByCreatedAtDesc(chatId, "OPEN");
}
@GetMapping("/active/discord/{userId}")
public List<CollabRequest> getActiveRequestsByDiscord(@PathVariable String userId) {
return collabRequestRepository.findByDiscordUserIdAndStatusOrderByCreatedAtDesc(userId, "OPEN");
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteOrCancelCollabRequest(@PathVariable Integer id) {
return collabRequestRepository.findById(id).map(req -> {
collabRequestRepository.delete(req);
return ResponseEntity.noContent().<Void>build();
}).orElse(ResponseEntity.notFound().build());
}
}

View File

@@ -0,0 +1,63 @@
package com.rit.portal.controller;
import com.rit.portal.entity.LeetcodeProfile;
import com.rit.portal.service.LeetcodeService;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/leetcode")
@CrossOrigin(originPatterns = "*")
@RequiredArgsConstructor
public class LeetcodeController {
private final LeetcodeService leetcodeService;
@GetMapping("/leaderboard")
public List<LeetcodeProfile> getLeaderboard() {
return leetcodeService.getAllRankedProfiles();
}
@PostMapping("/register")
public ResponseEntity<?> registerProfile(@RequestBody RegisterRequest request) {
if (request.getLeetcodeUsername() == null || request.getLeetcodeUsername().trim().isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("error", "LeetCode username is required"));
}
if (request.getStudentName() == null || request.getStudentName().trim().isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("error", "Student name is required"));
}
try {
LeetcodeProfile profile = leetcodeService.registerOrUpdateStudent(
request.getStudentName(),
request.getLeetcodeUsername(),
request.getDepartment() != null ? request.getDepartment() : "CSE",
request.getYear() != null ? request.getYear() : "1st Year"
);
return ResponseEntity.ok(profile);
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(Map.of("error", e.getMessage()));
} catch (Exception e) {
return ResponseEntity.internalServerError().body(Map.of("error", "Failed to register profile: " + e.getMessage()));
}
}
@PostMapping("/sync")
public ResponseEntity<?> triggerSpacedSync() {
leetcodeService.syncAllProfilesWithSpacing();
return ResponseEntity.ok(Map.of("message", "24h background sync initiated with 3-second request spacing between users."));
}
@Data
public static class RegisterRequest {
private String studentName;
private String leetcodeUsername;
private String department;
private String year;
}
}