Skip to content

Commit 1e4aac1

Browse files
committed
feat : add "problem of the day" endpoint
1 parent bdf2855 commit 1e4aac1

File tree

8 files changed

+92
-1
lines changed

8 files changed

+92
-1
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,12 @@ All endpoints are relative to the base path `/api/v1`.
8484
**Base Path**: `/api/v1/questions`
8585

8686
| Method | Endpoint | Description |
87-
|--------|----------|-------------|
87+
|--------|--------|-------------|
8888
| GET | `/` | Get a paginated list of all questions from the local database. Supports `?page=`, `&size=`, and `&sort=`. |
89+
| GET | `/potd` | Get the current LeetCode Problem of the Day (POTD). |
8990
| POST | `/search` | A powerful search endpoint. See request body details below. |
9091

92+
9193
#### POST /search Request Body
9294

9395
This endpoint allows for complex filtering and sorting of questions stored in the API's database.

src/main/java/com/rajat_singh/leetcode_api/client/LeetCodeClient.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,4 +272,16 @@ public UserLeetCodeCalendarResponse fetchUserLeetCodeCalendar(String username, i
272272
return restTemplate.postForObject(leetcodeApiUrl,entity,UserLeetCodeCalendarResponse.class);
273273
}
274274

275+
@RateLimiter(name = "leetcode-api")
276+
public DailyCodingChallengeResponse fetchDailyCodingChallengeQuestions() {
277+
HttpHeaders headers = new HttpHeaders();
278+
setHeader(headers);
279+
280+
Map<String,Object> requestBody = new HashMap<>();
281+
requestBody.put("query", FETCH_POTD);
282+
283+
HttpEntity<Map<String ,Object>> entity = new HttpEntity<>(requestBody, headers);
284+
return restTemplate.postForObject(leetcodeApiUrl,entity,DailyCodingChallengeResponse.class);
285+
}
286+
275287
}

src/main/java/com/rajat_singh/leetcode_api/controller/LeetCodeQuestionsController.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,17 @@ public ResponseEntity<Page<QuestionResponseDTO>> getAllQuestions(Pageable pageab
5454
return ResponseEntity.ok(dtoPage);
5555
}
5656

57+
@GetMapping("/potd")
58+
public ResponseEntity<QuestionResponseDTO> getPotd() {
59+
Logger.info("Fetching POTD from database");
60+
QuestionEntity potd = questionsRepository.findByIsProblemOfTheDayTrue();
61+
if (potd == null) {
62+
Logger.warn("No problem of the day found");
63+
return ResponseEntity.notFound().build();
64+
}
65+
QuestionResponseDTO dto = questionMapper.entityToResponseDTO(potd);
66+
return ResponseEntity.ok(dto);
67+
}
68+
5769

5870
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.rajat_singh.leetcode_api.dto;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class DailyCodingChallengeResponse {
7+
public DataNode data;
8+
9+
@Data
10+
public static class DataNode {
11+
public ActiveDailyCodingChallengeQuestion activeDailyCodingChallengeQuestion;
12+
}
13+
14+
@Data
15+
public static class ActiveDailyCodingChallengeQuestion {
16+
private String date;
17+
private String link;
18+
private Question question;
19+
}
20+
21+
@Data
22+
public static class Question {
23+
private String title;
24+
private String titleSlug;
25+
}
26+
27+
}

src/main/java/com/rajat_singh/leetcode_api/entity/QuestionEntity.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ public class QuestionEntity {
2626
)
2727
private List<TopicTag> topicTags = new ArrayList<>();
2828
String problemUrl;
29+
Boolean isProblemOfTheDay;
2930
}

src/main/java/com/rajat_singh/leetcode_api/graphql/GraphQlQueries.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,5 +286,17 @@ query userProfileCalendar($username: String!, $year: Int) {
286286
}
287287
""";
288288

289+
public static final String FETCH_POTD = """
290+
query questionOfToday {
291+
activeDailyCodingChallengeQuestion {
292+
date
293+
link
294+
question {
295+
titleSlug
296+
}
297+
}
298+
}
299+
""";
300+
289301

290302
}

src/main/java/com/rajat_singh/leetcode_api/repository/QuestionsRepository.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
public interface QuestionsRepository extends JpaRepository<QuestionEntity,Integer>, JpaSpecificationExecutor<QuestionEntity> {
1111

1212
QuestionEntity findByTitleSlug(String title);
13+
QuestionEntity findByIsProblemOfTheDayTrue();
1314

1415
}

src/main/java/com/rajat_singh/leetcode_api/scheduler/LeetCodeSyncScheduler.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.rajat_singh.leetcode_api.scheduler;
22

33
import com.rajat_singh.leetcode_api.client.LeetCodeClient;
4+
import com.rajat_singh.leetcode_api.dto.DailyCodingChallengeResponse;
45
import com.rajat_singh.leetcode_api.dto.QuestionListResponse;
56
import com.rajat_singh.leetcode_api.entity.QuestionEntity;
67
import com.rajat_singh.leetcode_api.entity.TopicTag;
78
import com.rajat_singh.leetcode_api.mappers.QuestionMapper;
89
import com.rajat_singh.leetcode_api.repository.QuestionsRepository;
10+
import jakarta.annotation.PostConstruct;
911
import org.springframework.beans.factory.annotation.Autowired;
1012
import org.springframework.scheduling.annotation.Async;
1113
import org.springframework.scheduling.annotation.Scheduled;
@@ -88,4 +90,26 @@ public void syncAcRateData() {
8890
Long endTime = System.currentTimeMillis();
8991
Logger.info("LeetCode [AC Rate] sync completed in {} seconds.", (endTime - startTime) / 1000);
9092
}
93+
94+
@Scheduled(cron = "0 31 5 * * ?", zone = "Asia/Kolkata") // Runs every day at 5:31 AM (IST) for POTD sync
95+
@Async
96+
public void syncPOTD() {
97+
Logger.info("Starting LeetCode [POTD] sync... at {}", DateFormat.getDateInstance().format(System.currentTimeMillis()));
98+
Long startTime = System.currentTimeMillis();
99+
DailyCodingChallengeResponse response = leetCodeApiClient.fetchDailyCodingChallengeQuestions();
100+
101+
QuestionEntity existingQuestion = questionRepository.findByTitleSlug(response.getData().getActiveDailyCodingChallengeQuestion().getQuestion().getTitleSlug());
102+
if(Objects.nonNull(existingQuestion)){
103+
existingQuestion.setIsProblemOfTheDay(true);
104+
questionRepository.save(existingQuestion);
105+
}
106+
107+
Long endTime = System.currentTimeMillis();
108+
Logger.info("LeetCode [POTD] sync completed in {} seconds.", (endTime - startTime) / 1000);
109+
}
110+
111+
@PostConstruct
112+
public void initialSync() {
113+
syncPOTD();
114+
}
91115
}

0 commit comments

Comments
 (0)