Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 31 additions & 56 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,9 @@
"typescript": "5.9.3",
"typescript-eslint": "^8.20.0",
"vite": "^6.0.7"
},
"overrides": {
"ajv": "^6.14.0",
"minimatch": "^10.2.2"
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
package de.tum.cit.memo.controller;

import de.tum.cit.memo.dto.CreateCompetencyRelationshipRequest;
import de.tum.cit.memo.entity.CompetencyRelationship;
import de.tum.cit.memo.service.CompetencyRelationshipService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
* CRUD endpoints for competency relationships (voting happens via
* SchedulingController).
*/
@RestController
@RequestMapping("/api/competency-relationships")
@RequiredArgsConstructor
Expand All @@ -27,13 +26,6 @@ public class CompetencyRelationshipController {

private final CompetencyRelationshipService relationshipService;

@PostMapping
@Operation(summary = "Create a new competency relationship")
public ResponseEntity<CompetencyRelationship> createRelationship(@Valid @RequestBody CreateCompetencyRelationshipRequest request) {
CompetencyRelationship relationship = relationshipService.createRelationship(request);
return ResponseEntity.status(HttpStatus.CREATED).body(relationship);
}

@GetMapping("/{id}")
@Operation(summary = "Get competency relationship by ID")
public ResponseEntity<CompetencyRelationship> getRelationshipById(@PathVariable String id) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package de.tum.cit.memo.controller;

import de.tum.cit.memo.dto.RelationshipTaskResponse;
import de.tum.cit.memo.dto.VoteRequest;
import de.tum.cit.memo.dto.VoteResponse;
import de.tum.cit.memo.service.SchedulingService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/scheduling")
@RequiredArgsConstructor
@Tag(name = "Scheduling", description = "Endpoints for competency mapping scheduling")
public class SchedulingController {

private final SchedulingService schedulingService;

@GetMapping("/next-relationship")
@Operation(summary = "Get next relationship to vote on", description = "Returns the next competency pair for this user. 204 if no tasks remain.")
public ResponseEntity<RelationshipTaskResponse> getNextRelationship(
@RequestHeader("X-User-Id") String userId) {
return schedulingService.getNextTask(userId)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.noContent().build());
}

@PostMapping("/vote")
@Operation(summary = "Submit a vote on a relationship", description = "Records the user's vote on a competency pair identified by originId + destinationId.")
public ResponseEntity<VoteResponse> submitVote(
@RequestHeader("X-User-Id") String userId,
@Valid @RequestBody VoteRequest request) {
VoteResponse response = schedulingService.submitVote(userId, request);
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package de.tum.cit.memo.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RelationshipTaskResponse {

private String relationshipId;
private CompetencyInfo origin;
private CompetencyInfo destination;
private String pipeline;
private VoteCounts currentVotes;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class CompetencyInfo {
private String id;
private String title;
private String description;
}
}
18 changes: 18 additions & 0 deletions server/src/main/java/de/tum/cit/memo/dto/VoteCounts.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package de.tum.cit.memo.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class VoteCounts {

private int assumes;
private int extendsRelation;
private int matches;
private int unrelated;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package de.tum.cit.memo.dto;

import de.tum.cit.memo.enums.RelationshipType;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
Expand All @@ -12,17 +11,14 @@
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CreateCompetencyRelationshipRequest {
public class VoteRequest {

@NotNull(message = "Relationship type is required")
private RelationshipType relationshipType;

@NotBlank(message = "Origin ID is required")
@NotNull
private String originId;

@NotBlank(message = "Destination ID is required")
@NotNull
private String destinationId;

@NotBlank(message = "User ID is required")
private String userId;
@NotNull
private RelationshipType relationshipType;
}
18 changes: 18 additions & 0 deletions server/src/main/java/de/tum/cit/memo/dto/VoteResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package de.tum.cit.memo.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class VoteResponse {

private String relationshipId;
private boolean success;
private VoteCounts updatedVotes;
private double newEntropy;
}
3 changes: 3 additions & 0 deletions server/src/main/java/de/tum/cit/memo/entity/Competency.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ public class Competency {
@CreationTimestamp
@Column(nullable = false, updatable = false)
private Instant createdAt;

@Column(nullable = false)
private int degree;
}
Loading