Skip to content

Commit

Permalink
Merge c713479 into 2a08217
Browse files Browse the repository at this point in the history
  • Loading branch information
bukajsytlos committed Jan 7, 2019
2 parents 2a08217 + c713479 commit cf01254
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 12 deletions.
112 changes: 112 additions & 0 deletions src/inttest/java/com/faforever/api/event/EventControllerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package com.faforever.api.event;

import com.faforever.api.AbstractIntegrationTest;
import com.faforever.api.data.DataController;
import com.faforever.api.security.OAuthScope;
import com.google.common.collect.Lists;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.Sql.ExecutionPhase;

import java.util.List;

import static org.hamcrest.Matchers.hasSize;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:sql/prepDefaultUser.sql")
@Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:sql/prepEventsData.sql")
@Sql(executionPhase = ExecutionPhase.AFTER_TEST_METHOD, scripts = "classpath:sql/cleanEventsData.sql")
public class EventControllerTest extends AbstractIntegrationTest {

@Test
public void singleExistingPlayerEventCanBeUpdated() throws Exception {
List<EventUpdateRequest> updatedEvents = Lists.newArrayList(new EventUpdateRequest(1, "15b6c19a-6084-4e82-ada9-6c30e282191f", 10));
mockMvc.perform(
patch("/events/update")
.header(HttpHeaders.CONTENT_TYPE, DataController.JSON_API_MEDIA_TYPE)
.content(objectMapper.writeValueAsString(updatedEvents))
.with(getOAuthToken(OAuthScope._WRITE_EVENTS)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data", hasSize(1)))
.andExpect(jsonPath("$.data[0].attributes.currentCount", Matchers.is(31)))
.andExpect(jsonPath("$.data[0].attributes.eventId", Matchers.is("15b6c19a-6084-4e82-ada9-6c30e282191f")));
}

@Test
public void singleNonExistingPlayerEventCanBeCreated() throws Exception {
List<EventUpdateRequest> updatedEvents = Lists.newArrayList(new EventUpdateRequest(1, "cc791f00-343c-48d4-b5b3-8900b83209c0", 10));
mockMvc.perform(
patch("/events/update")
.header(HttpHeaders.CONTENT_TYPE, DataController.JSON_API_MEDIA_TYPE)
.content(objectMapper.writeValueAsString(updatedEvents))
.with(getOAuthToken(OAuthScope._WRITE_EVENTS)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data", hasSize(1)))
.andExpect(jsonPath("$.data[0].attributes.currentCount", Matchers.is(10)))
.andExpect(jsonPath("$.data[0].attributes.eventId", Matchers.is("cc791f00-343c-48d4-b5b3-8900b83209c0")));
}

@Test
public void multipleExistingPlayerEventsCanBeUpdated() throws Exception {
List<EventUpdateRequest> updatedEvents = Lists.newArrayList(
new EventUpdateRequest(1, "15b6c19a-6084-4e82-ada9-6c30e282191f", 10),
new EventUpdateRequest(1, "225e9b2e-ae09-4ae1-a198-eca8780b0fcd", 10)
);
mockMvc.perform(
patch("/events/update")
.header(HttpHeaders.CONTENT_TYPE, DataController.JSON_API_MEDIA_TYPE)
.content(objectMapper.writeValueAsString(updatedEvents))
.with(getOAuthToken(OAuthScope._WRITE_EVENTS)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data", hasSize(2)))
.andExpect(jsonPath("$.data[*].attributes.currentCount", Matchers.containsInAnyOrder(31, 20)))
.andExpect(jsonPath("$.data[*].attributes.eventId", Matchers.containsInAnyOrder("15b6c19a-6084-4e82-ada9-6c30e282191f", "225e9b2e-ae09-4ae1-a198-eca8780b0fcd")));
}

@Test
public void authWithoutCorrectScopeShouldFail() throws Exception {
List<EventUpdateRequest> updatedEvents = Lists.newArrayList(new EventUpdateRequest(1, "15b6c19a-6084-4e82-ada9-6c30e282191f", 10));
mockMvc.perform(
patch("/events/update")
.header(HttpHeaders.CONTENT_TYPE, DataController.JSON_API_MEDIA_TYPE)
.content(objectMapper.writeValueAsString(updatedEvents)))
.andExpect(status().isForbidden());
}

@Test
public void nonExistingEventShouldFail() throws Exception {
List<EventUpdateRequest> updatedEvents = Lists.newArrayList(new EventUpdateRequest(1, "non-existing-event-id", 10));
mockMvc.perform(
patch("/events/update")
.header(HttpHeaders.CONTENT_TYPE, DataController.JSON_API_MEDIA_TYPE)
.content(objectMapper.writeValueAsString(updatedEvents))
.with(getOAuthToken(OAuthScope._WRITE_EVENTS)))
.andExpect(status().isUnprocessableEntity());
}

@Test
public void nonExistingPlayerShouldFail() throws Exception {
List<EventUpdateRequest> updatedEvents = Lists.newArrayList(new EventUpdateRequest(-1, "15b6c19a-6084-4e82-ada9-6c30e282191f", 10));
mockMvc.perform(
patch("/events/update")
.header(HttpHeaders.CONTENT_TYPE, DataController.JSON_API_MEDIA_TYPE)
.content(objectMapper.writeValueAsString(updatedEvents))
.with(getOAuthToken(OAuthScope._WRITE_EVENTS)))
.andExpect(status().isUnprocessableEntity());
}

@Test
public void negativeCountShouldFail() throws Exception {
List<EventUpdateRequest> updatedEvents = Lists.newArrayList(new EventUpdateRequest(1, "15b6c19a-6084-4e82-ada9-6c30e282191f", -10));
mockMvc.perform(
patch("/events/update")
.header(HttpHeaders.CONTENT_TYPE, DataController.JSON_API_MEDIA_TYPE)
.content(objectMapper.writeValueAsString(updatedEvents))
.with(getOAuthToken(OAuthScope._WRITE_EVENTS)))
.andExpect(status().isUnprocessableEntity());
}
}
4 changes: 4 additions & 0 deletions src/inttest/resources/sql/cleanEventsData.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DELETE
FROM player_events;
DELETE
FROM event_definitions;
14 changes: 14 additions & 0 deletions src/inttest/resources/sql/prepEventsData.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
DELETE
FROM player_events;
DELETE
FROM event_definitions;
INSERT INTO event_definitions (id, name_key, image_url, type)
VALUES ('15b6c19a-6084-4e82-ada9-6c30e282191f', 'event.seraphimWins', null, 'NUMERIC');
INSERT INTO event_definitions (id, name_key, image_url, type)
VALUES ('225e9b2e-ae09-4ae1-a198-eca8780b0fcd', 'event.lostAirUnits', null, 'NUMERIC');
INSERT INTO event_definitions (id, name_key, image_url, type)
VALUES ('cc791f00-343c-48d4-b5b3-8900b83209c0', 'event.secondsPlayed', null, 'TIME');
INSERT INTO player_events (id, player_id, event_id, count, create_time, update_time)
VALUES (1, 1, '15b6c19a-6084-4e82-ada9-6c30e282191f', 21, '2019-01-06 10:48:18', '2019-01-06 10:48:18');
INSERT INTO player_events (id, player_id, event_id, count, create_time, update_time)
VALUES (2, 1, '225e9b2e-ae09-4ae1-a198-eca8780b0fcd', 10, '2019-01-06 13:36:54', '2019-01-06 13:36:54');
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public int getPlayerId() {
}

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "event_id", updatable = false, insertable = false)
@JoinColumn(name = "event_id", updatable = false)
public Event getEvent() {
return event;
}
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/faforever/api/event/EventUpdateRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import lombok.NoArgsConstructor;
import lombok.Setter;

import javax.validation.constraints.Min;

@Getter
@Setter
@NoArgsConstructor
Expand All @@ -13,6 +15,7 @@ class EventUpdateRequest {

private int playerId;
private String eventId;
@Min(0)
private int count;

}
14 changes: 7 additions & 7 deletions src/main/java/com/faforever/api/event/EventsController.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,35 @@
import com.yahoo.elide.jsonapi.models.Resource;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.inject.Inject;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import javax.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping(path = "/events")
@Validated
public class EventsController {

private static final String JSON_API_MEDIA_TYPE = "application/vnd.api+json";
private final EventsService eventsService;
private AtomicInteger nextUpdateId;

@Inject
public EventsController(EventsService eventsService) {
this.eventsService = eventsService;
nextUpdateId = new AtomicInteger();
}

@ApiOperation(value = "Updates the state and progress of one or multiple events.")
@PreAuthorize("#oauth2.hasScope('" + OAuthScope._WRITE_EVENTS + "')")
@RequestMapping(value = "/update", method = RequestMethod.PATCH, produces = JSON_API_MEDIA_TYPE)
public JsonApiDocument update(@RequestBody EventUpdateRequest[] updateRequests) {
return new JsonApiDocument(new Data<>(Arrays.stream(updateRequests)
public JsonApiDocument update(@RequestBody List<@Valid EventUpdateRequest> updateRequests) {
return new JsonApiDocument(new Data<>(updateRequests.stream()
.map(request -> eventsService.increment(request.getPlayerId(), request.getEventId(), request.getCount()))
.map(this::toResource)
.collect(Collectors.toList())));
Expand All @@ -47,7 +47,7 @@ private Resource toResource(UpdatedEventResponse updatedEventResponse) {
.put("eventId", updatedEventResponse.getEventId())
.put("currentCount", updatedEventResponse.getCurrentCount());

return new Resource("updatedEvent", String.valueOf(nextUpdateId.getAndIncrement()),
return new Resource("updatedEvent", String.valueOf(updatedEventResponse.getId()),
attributesBuilder.build(), null, null, null);
}
}
14 changes: 11 additions & 3 deletions src/main/java/com/faforever/api/event/EventsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

import com.faforever.api.data.domain.Event;
import com.faforever.api.data.domain.PlayerEvent;
import com.faforever.api.error.ApiException;
import com.faforever.api.error.Error;
import com.faforever.api.error.ErrorCode;
import com.faforever.api.player.PlayerService;
import com.google.common.base.MoreObjects;
import org.springframework.stereotype.Service;

Expand All @@ -12,17 +16,21 @@
public class EventsService {

private final EventRepository eventRepository;
private final PlayerService playerService;
private final PlayerEventRepository playerEventRepository;

@Inject
public EventsService(EventRepository eventRepository, PlayerEventRepository playerEventRepository) {
public EventsService(EventRepository eventRepository, PlayerService playerService, PlayerEventRepository playerEventRepository) {
this.eventRepository = eventRepository;
this.playerService = playerService;
this.playerEventRepository = playerEventRepository;
}

UpdatedEventResponse increment(int playerId, String eventId, int steps) {
BiFunction<Integer, Integer, Integer> stepsFunction = (currentSteps, newSteps) -> currentSteps + newSteps;
Event event = eventRepository.getOne(eventId);
playerService.getById(playerId);
Event event = eventRepository.findById(eventId)
.orElseThrow(() -> new ApiException(new Error(ErrorCode.ENTITY_NOT_FOUND, eventId)));

PlayerEvent playerEvent = getOrCreatePlayerEvent(playerId, event);

Expand All @@ -32,7 +40,7 @@ UpdatedEventResponse increment(int playerId, String eventId, int steps) {
playerEvent.setCurrentCount(newCurrentCount);
playerEventRepository.save(playerEvent);

return new UpdatedEventResponse(eventId, newCurrentCount);
return new UpdatedEventResponse(playerEvent.getId(), eventId, newCurrentCount);
}

private PlayerEvent getOrCreatePlayerEvent(int playerId, Event event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
@Data
class UpdatedEventResponse {

private final int id;
private final String eventId;
private final Integer currentCount;

Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/faforever/api/player/PlayerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.faforever.api.data.domain.Player;
import com.faforever.api.error.ApiException;
import com.faforever.api.error.Error;
import com.faforever.api.error.ErrorCode;
import com.faforever.api.security.FafUserDetails;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -30,4 +31,9 @@ public Player getPlayer(Authentication authentication) {
}
throw new ApiException(new Error(TOKEN_INVALID));
}

public Player getById(Integer playerId) {
return playerRepository.findById(playerId)
.orElseThrow(() -> new ApiException(new Error(ErrorCode.ENTITY_NOT_FOUND, playerId)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@


@RunWith(MockitoJUnitRunner.class)
public class PlayerEventsControllerTest {
public class PlayerAchievementsControllerTest {

private AchievementsController instance;

Expand Down

0 comments on commit cf01254

Please sign in to comment.