Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
406 changes: 0 additions & 406 deletions sticker-award/docs/api.json

This file was deleted.

436 changes: 397 additions & 39 deletions sticker-award/docs/api.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@

import com.datadoghq.stickerlandia.stickeraward.beans.AssignStickerCommand;
import com.datadoghq.stickerlandia.stickeraward.beans.StickerAssignmentResponse;
import com.datadoghq.stickerlandia.stickeraward.beans.StickerAssignmentResponseApiResponse;
import com.datadoghq.stickerlandia.stickeraward.beans.StickerDTO;
import com.datadoghq.stickerlandia.stickeraward.beans.StickerRemovalResponse;
import com.datadoghq.stickerlandia.stickeraward.beans.StickerRemovalResponseApiResponse;
import com.datadoghq.stickerlandia.stickeraward.beans.UserStickersResponse;
import com.datadoghq.stickerlandia.stickeraward.beans.UserStickersResponseApiResponse;
import com.datadoghq.stickerlandia.stickeraward.entity.Sticker;
import com.datadoghq.stickerlandia.stickeraward.entity.StickerAssignment;
import com.datadoghq.stickerlandia.stickeraward.messaging.StickerEventPublisher;
Expand Down Expand Up @@ -45,7 +42,7 @@ public class StickerAwardResource {
@GET
@Produces("application/json")
@Transactional
public Response getUserStickers(@PathParam("userId") String userId) {
public UserStickersResponse getUserStickers(@PathParam("userId") String userId) {
List<StickerAssignment> assignments = StickerAssignment.findActiveByUserId(userId);

List<StickerDTO> stickerDTOs = assignments.stream()
Expand All @@ -65,12 +62,7 @@ public Response getUserStickers(@PathParam("userId") String userId) {
response.setUserId(userId);
response.setStickers(stickerDTOs);

UserStickersResponseApiResponse apiResponse = new UserStickersResponseApiResponse();
apiResponse.setSuccess(true);
apiResponse.setMessage("Successfully retrieved user stickers");
apiResponse.setData(response);

return Response.ok(apiResponse).build();
return response;
}

@Operation(description = "Assign a new sticker to a user (access controlled based on caller identity)")
Expand All @@ -86,23 +78,13 @@ public Response assignStickerToUser(@PathParam("userId") String userId,
Sticker sticker = Sticker.findById(stickerId);

if (sticker == null) {
StickerAssignmentResponseApiResponse apiResponse = new StickerAssignmentResponseApiResponse();
apiResponse.setSuccess(false);
apiResponse.setMessage("Sticker not found: " + stickerId);
return Response.status(Response.Status.BAD_REQUEST)
.entity(apiResponse)
.build();
return Response.status(Response.Status.BAD_REQUEST).build();
}

// Check if sticker is already assigned to the user and not removed
StickerAssignment existingAssignment = StickerAssignment.findActiveByUserAndSticker(userId, stickerId);
if (existingAssignment != null) {
StickerAssignmentResponseApiResponse apiResponse = new StickerAssignmentResponseApiResponse();
apiResponse.setSuccess(false);
apiResponse.setMessage("User already has this sticker assigned");
return Response.status(Response.Status.CONFLICT)
.entity(apiResponse)
.build();
return Response.status(Response.Status.CONFLICT).build();
}

// Create new assignment
Expand All @@ -125,13 +107,8 @@ public Response assignStickerToUser(@PathParam("userId") String userId,
response.setStickerId(stickerId);
response.setAssignedAt(Date.from(assignment.getAssignedAt()));

StickerAssignmentResponseApiResponse apiResponse = new StickerAssignmentResponseApiResponse();
apiResponse.setSuccess(true);
apiResponse.setMessage("Sticker assigned successfully");
apiResponse.setData(response);

return Response.status(Response.Status.CREATED)
.entity(apiResponse)
.entity(response)
.build();
}

Expand All @@ -146,12 +123,7 @@ public Response removeStickerFromUser(@PathParam("userId") String userId,
StickerAssignment assignment = StickerAssignment.findActiveByUserAndSticker(userId, stickerId);

if (assignment == null) {
StickerRemovalResponseApiResponse apiResponse = new StickerRemovalResponseApiResponse();
apiResponse.setSuccess(false);
apiResponse.setMessage("Active sticker assignment not found for user");
return Response.status(Response.Status.NOT_FOUND)
.entity(apiResponse)
.build();
return Response.status(Response.Status.NOT_FOUND).build();
}

// Mark as removed
Expand All @@ -174,11 +146,6 @@ public Response removeStickerFromUser(@PathParam("userId") String userId,
response.setStickerId(stickerId);
response.setRemovedAt(Date.from(assignment.getRemovedAt()));

StickerRemovalResponseApiResponse apiResponse = new StickerRemovalResponseApiResponse();
apiResponse.setSuccess(true);
apiResponse.setMessage("Sticker removed successfully");
apiResponse.setData(response);

return Response.ok(apiResponse).build();
return Response.ok(response).build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public class Sticker extends PanacheEntityBase {
@Column(name = "image_url")
private String imageUrl;

@Column(name = "sticker_quantity_remaining", nullable = false)
private Integer stickerQuantityRemaining;

@Column(name = "created_at", nullable = false)
private Instant createdAt;

Expand All @@ -36,11 +39,12 @@ public Sticker() {
}

// Constructor with fields
public Sticker(String stickerId, String name, String description, String imageUrl) {
public Sticker(String stickerId, String name, String description, String imageUrl, Integer stickerQuantityRemaining) {
this.stickerId = stickerId;
this.name = name;
this.description = description;
this.imageUrl = imageUrl;
this.stickerQuantityRemaining = stickerQuantityRemaining;
this.createdAt = Instant.now();
}

Expand Down Expand Up @@ -93,6 +97,29 @@ public void setUpdatedAt(Instant updatedAt) {
this.updatedAt = updatedAt;
}

public Integer getStickerQuantityRemaining() {
return stickerQuantityRemaining;
}

public void setStickerQuantityRemaining(Integer stickerQuantityRemaining) {
this.stickerQuantityRemaining = stickerQuantityRemaining;
}

// Helper methods for quantity management
public boolean isAvailable() {
return stickerQuantityRemaining == null || stickerQuantityRemaining == -1 || stickerQuantityRemaining > 0;
}

public boolean hasUnlimitedQuantity() {
return stickerQuantityRemaining == null || stickerQuantityRemaining == -1;
}

public void decrementQuantity() {
if (stickerQuantityRemaining != null && stickerQuantityRemaining > 0) {
stickerQuantityRemaining--;
}
}

// Helper methods for finding stickers
public static Sticker findById(String id) {
return find("stickerId", id).firstResult();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ CREATE TABLE stickers (
name VARCHAR(100) NOT NULL,
description VARCHAR(500),
image_url VARCHAR(255),
sticker_quantity_remaining INTEGER NOT NULL DEFAULT -1,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP
);
Expand All @@ -27,12 +28,18 @@ CREATE INDEX idx_sticker_assignments_user_id ON sticker_assignments(user_id);
CREATE INDEX idx_sticker_assignments_active ON sticker_assignments(user_id, removed_at)
WHERE removed_at IS NULL;

-- Add comment to explain the quantity field
COMMENT ON COLUMN stickers.sticker_quantity_remaining IS 'Quantity remaining (-1 for infinite)';

-- Initial seed data
INSERT INTO stickers (sticker_id, name, description, image_url, created_at)
INSERT INTO stickers (sticker_id, name, description, image_url, sticker_quantity_remaining, created_at)
VALUES
('sticker-001', 'Debugging Hero', 'Awarded for exceptional debugging skills', 'https://stickerlandia.example.com/images/debugging-hero.png', CURRENT_TIMESTAMP),
('sticker-002', 'Code Review Champion', 'Awarded for thorough code reviews', 'https://stickerlandia.example.com/images/code-review-champion.png', CURRENT_TIMESTAMP),
('sticker-003', 'Performance Optimizer', 'Awarded for significant performance improvements', 'https://stickerlandia.example.com/images/performance-optimizer.png', CURRENT_TIMESTAMP);
('sticker-001', 'Debugging Hero', 'Awarded for exceptional debugging skills', 'https://stickerlandia.example.com/images/debugging-hero.png', 100, CURRENT_TIMESTAMP),
('sticker-002', 'Code Review Champion', 'Awarded for thorough code reviews', 'https://stickerlandia.example.com/images/code-review-champion.png', 100, CURRENT_TIMESTAMP),
('sticker-003', 'Performance Optimizer', 'Awarded for significant performance improvements', 'https://stickerlandia.example.com/images/performance-optimizer.png', -1, CURRENT_TIMESTAMP),
('sticker-004', 'Early Bird', 'Awarded for being first to complete tasks', 'https://stickerlandia.example.com/images/early-bird.png', 50, CURRENT_TIMESTAMP),
('sticker-005', 'Team Player', 'Awarded for excellent collaboration', 'https://stickerlandia.example.com/images/team-player.png', -1, CURRENT_TIMESTAMP),
('sticker-006', 'Innovation Award', 'Awarded for creative solutions', 'https://stickerlandia.example.com/images/innovation-award.png', 25, CURRENT_TIMESTAMP);

-- Sample assignment
INSERT INTO sticker_assignments (user_id, sticker_id, assigned_at, reason)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class StickerAwardResourceKafkaIT {
@Order(1)
public void testCreateSticker() {
// Create a test sticker in the database
Sticker sticker = new Sticker(TEST_STICKER_ID, "Test Sticker", "A test sticker", "https://example.com/sticker.png");
Sticker sticker = new Sticker(TEST_STICKER_ID, "Test Sticker", "A test sticker", "https://example.com/sticker.png", 100);
sticker.persist();
}

Expand All @@ -55,9 +55,8 @@ public void testAssignStickerToUser() {
.post("/api/award/v1/users/" + TEST_USER_ID + "/stickers")
.then()
.statusCode(Status.CREATED.getStatusCode())
.body("success", is(true))
.body("data.userId", is(TEST_USER_ID))
.body("data.stickerId", is(TEST_STICKER_ID));
.body("userId", is(TEST_USER_ID))
.body("stickerId", is(TEST_STICKER_ID));
}

@Test
Expand All @@ -69,10 +68,9 @@ public void testGetUserStickers() {
.get("/api/award/v1/users/" + TEST_USER_ID + "/stickers")
.then()
.statusCode(Status.OK.getStatusCode())
.body("success", is(true))
.body("data.userId", is(TEST_USER_ID))
.body("data.stickers.size()", is(1))
.body("data.stickers[0].stickerId", is(TEST_STICKER_ID));
.body("userId", is(TEST_USER_ID))
.body("stickers.size()", is(1))
.body("stickers[0].stickerId", is(TEST_STICKER_ID));
}

@Test
Expand All @@ -84,18 +82,16 @@ public void testRemoveStickerFromUser() {
.delete("/api/award/v1/users/" + TEST_USER_ID + "/stickers/" + TEST_STICKER_ID)
.then()
.statusCode(Status.OK.getStatusCode())
.body("success", is(true))
.body("data.userId", is(TEST_USER_ID))
.body("data.stickerId", is(TEST_STICKER_ID));
.body("userId", is(TEST_USER_ID))
.body("stickerId", is(TEST_STICKER_ID));

// Verify the user no longer has the sticker
given()
.when()
.get("/api/award/v1/users/" + TEST_USER_ID + "/stickers")
.then()
.statusCode(Status.OK.getStatusCode())
.body("success", is(true))
.body("data.userId", is(TEST_USER_ID))
.body("data.stickers.size()", is(0));
.body("userId", is(TEST_USER_ID))
.body("stickers.size()", is(0));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@ void setupTestData() {
// Make sure our test stickers exist
Sticker sticker1 = Sticker.findById(EXISTING_STICKER_ID);
if (sticker1 == null) {
sticker1 = new Sticker(EXISTING_STICKER_ID, "Test Sticker", "For testing", "http://example.com/test.png");
sticker1 = new Sticker(EXISTING_STICKER_ID, "Test Sticker", "For testing", "http://example.com/test.png", 100);
sticker1.persist();
}

// Create sticker-002 and sticker-003 for other tests
Sticker sticker2 = Sticker.findById("sticker-002");
if (sticker2 == null) {
sticker2 = new Sticker("sticker-002", "Test Sticker 2", "For testing", "http://example.com/test2.png");
sticker2 = new Sticker("sticker-002", "Test Sticker 2", "For testing", "http://example.com/test2.png", 100);
sticker2.persist();
}

Sticker sticker3 = Sticker.findById("sticker-003");
if (sticker3 == null) {
sticker3 = new Sticker("sticker-003", "Test Sticker 3", "For testing", "http://example.com/test3.png");
sticker3 = new Sticker("sticker-003", "Test Sticker 3", "For testing", "http://example.com/test3.png", 100);
sticker3.persist();
}

Expand All @@ -65,11 +65,9 @@ void testGetUserStickers() {
.then()
.statusCode(200)
.contentType(ContentType.JSON)
.body("success", is(true))
.body("data", notNullValue())
.body("data.userId", is(TEST_USER_ID))
.body("data.stickers.size()", is(1))
.body("data.stickers[0].stickerId", is(EXISTING_STICKER_ID));
.body("userId", is(TEST_USER_ID))
.body("stickers.size()", is(1))
.body("stickers[0].stickerId", is(EXISTING_STICKER_ID));
}

@Test
Expand All @@ -80,10 +78,8 @@ void testGetUserStickersForUserWithNoStickers() {
.then()
.statusCode(200)
.contentType(ContentType.JSON)
.body("success", is(true))
.body("data", notNullValue())
.body("data.userId", is(unknownUserId))
.body("data.stickers.size()", is(0));
.body("userId", is(unknownUserId))
.body("stickers.size()", is(0));
}

@Test
Expand All @@ -104,20 +100,18 @@ void testAssignStickerToUser() {
.then()
.statusCode(201)
.contentType(ContentType.JSON)
.body("success", is(true))
.body("data", notNullValue())
.body("data.userId", is(userId))
.body("data.stickerId", is(stickerId))
.body("data.assignedAt", notNullValue());
.body("userId", is(userId))
.body("stickerId", is(stickerId))
.body("assignedAt", notNullValue());

// Verify the sticker is now assigned by getting user stickers
given()
.when().get("/api/award/v1/users/{userId}/stickers", userId)
.then()
.statusCode(200)
.contentType(ContentType.JSON)
.body("data.stickers.size()", is(1))
.body("data.stickers[0].stickerId", is(stickerId));
.body("stickers.size()", is(1))
.body("stickers[0].stickerId", is(stickerId));
}

@Test
Expand All @@ -135,10 +129,7 @@ void testAssignNonExistingStickerReturns400() {
.body(command)
.when().post("/api/award/v1/users/{userId}/stickers", userId)
.then()
.statusCode(400)
.contentType(ContentType.JSON)
.body("success", is(false))
.body("message", notNullValue());
.statusCode(400);
}

@Test
Expand Down Expand Up @@ -166,10 +157,7 @@ void testAssignAlreadyAssignedStickerReturns409() {
.body(command)
.when().post("/api/award/v1/users/{userId}/stickers", userId)
.then()
.statusCode(409)
.contentType(ContentType.JSON)
.body("success", is(false))
.body("message", notNullValue());
.statusCode(409);
}

@Test
Expand Down Expand Up @@ -197,19 +185,17 @@ void testRemoveStickerAssignment() {
.then()
.statusCode(200)
.contentType(ContentType.JSON)
.body("success", is(true))
.body("data", notNullValue())
.body("data.userId", is(userId))
.body("data.stickerId", is(stickerId))
.body("data.removedAt", notNullValue());
.body("userId", is(userId))
.body("stickerId", is(stickerId))
.body("removedAt", notNullValue());

// Verify the sticker is no longer assigned
given()
.when().get("/api/award/v1/users/{userId}/stickers", userId)
.then()
.statusCode(200)
.contentType(ContentType.JSON)
.body("data.stickers.size()", is(0));
.body("stickers.size()", is(0));
}

@Test
Expand All @@ -220,9 +206,6 @@ void testRemoveNonExistingStickerAssignmentReturns404() {
given()
.when().delete("/api/award/v1/users/{userId}/stickers/{stickerId}", userId, stickerId)
.then()
.statusCode(404)
.contentType(ContentType.JSON)
.body("success", is(false))
.body("message", notNullValue());
.statusCode(404);
}
}
Loading
Loading