Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
28ac846
Fixing issues when saving apps and adding validation when saving acce…
Mar 26, 2019
547b821
Fixing tests
Mar 26, 2019
0c51fc0
Additional validation to clientId
Mar 29, 2019
3c8ff22
Changing from == to ===
Mar 29, 2019
6e18849
Correção do erro ao validar CPF
Mar 29, 2019
10a1329
Removing access-token to plan association when deleting one plan from an
Mar 29, 2019
afe0168
Merge branch 'hotfix' into fix-tokens
MAAARKIN May 5, 2019
5745b85
Merge remote-tracking branch 'origin/master' into fix-tokens
May 7, 2019
7438f4d
Merging from master
May 7, 2019
73d72d0
Merge branch 'fix-tokens' of https://github.com/pedrohff/heimdall int…
May 7, 2019
15f547c
Merge pull request #247 from pedrohff/fix-tokens
MAAARKIN May 8, 2019
f42bb94
Merge pull request #277 from getheimdall/release
MAAARKIN May 10, 2019
e17f28f
Creating a new SNAPSHOT
May 10, 2019
d3f2d57
Merge remote-tracking branch 'getheimdall/master' into hotfix
MAAARKIN May 13, 2019
1fc5964
Fixed header.get() method. It should only try to get the header from …
marceloaguiarr May 15, 2019
55b7257
Resolved problem to create new middleware or custom interceptors, and…
dijalmass May 16, 2019
68640b0
Merge pull request #280 from dijalmasilva/problem-middleware
MAAARKIN May 16, 2019
8ab0f7a
Merge pull request #279 from marceloaguiarr/header-get-hotfix
MAAARKIN May 16, 2019
c89ab7d
Merge remote-tracking branch 'getheimdall/hotfix' into fix-middleware-fk
MAAARKIN May 16, 2019
4d1e9f0
Fixed bug when trying to delete a plan associated to an App
May 16, 2019
f6cbd5a
Merge pull request #281 from cassioesp/hotfix-delete-plan-attached
MAAARKIN May 17, 2019
1ed81b9
*Detach middleware from interceptor;
MAAARKIN May 17, 2019
1af1bc2
*removing duplicated key
MAAARKIN May 17, 2019
652f004
Merge pull request #282 from MAAARKIN/fix-middleware-fk
MAAARKIN May 17, 2019
1bcc9ab
Merge pull request #283 from getheimdall/hotfix
MAAARKIN May 17, 2019
d675f54
Ajuste automatico de versao para hotfix
May 17, 2019
296c6c4
Added React.Lazy in routes and tabs from Api Component
dijalmass May 30, 2019
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
2 changes: 1 addition & 1 deletion heimdall-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>br.com.conductor.heimdall</groupId>
<artifactId>heimdall</artifactId>
<version>2.3.2-SNAPSHOT</version>
<version>2.4.2-SNAPSHOT</version>
</parent>
<artifactId>heimdall-api</artifactId>
<name>heimdall-api</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,37 @@ public void setupTest() {

@Test
@WithMockUser(username="tester", authorities={"CREATE_ACCESSTOKEN"})
public void testSavingAccessTokenWithoutRequiredField() throws Exception {
public void testSavingAccessTokenWithoutApp() throws Exception {

mockMvc.perform(MockMvcRequestBuilders.post(ConstantsPath.PATH_ACCESS_TOKENS, 10L)
.content("{\"code\":\"!!@!##1212\"}")
.contentType(MediaType.APPLICATION_JSON))
.content("{\"code\":\"!!@!##1212\", \"plans\": [{\"id\": 5}]}")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.status().is4xxClientError())
.andExpect(MockMvcResultMatchers.content().json("{\"status\":400,\"exception\":\"MethodArgumentNotValidException\",\"erros\":[{\"defaultMessage\":\"may not be null\",\"field\":\"app\",\"code\":\"NotNull\"}]}"));
}

@Test
@WithMockUser(username="tester", authorities={"CREATE_ACCESSTOKEN"})
public void testSavingAccessTokenWithEmptyPlans() throws Exception {

mockMvc.perform(MockMvcRequestBuilders.post(ConstantsPath.PATH_ACCESS_TOKENS, 10L)
.content("{\"code\":\"!!@!##1212\", \"app\":{\"id\":10}, \"plans\": [] }")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.status().is4xxClientError())
.andExpect(MockMvcResultMatchers.content().json("{\"status\":400,\"exception\":\"MethodArgumentNotValidException\",\"erros\":[{\"defaultMessage\":\"size must be between 1 and 2147483647\",\"field\":\"plans\",\"code\":\"Size\"}]}"));
}

@Test
@WithMockUser(username="tester", authorities={"CREATE_ACCESSTOKEN"})
public void testSavingAccessTokenWithoutPlans() throws Exception {

mockMvc.perform(MockMvcRequestBuilders.post(ConstantsPath.PATH_ACCESS_TOKENS, 10L)
.content("{\"code\":\"!!@!##1212\", \"app\":{\"id\":10}}")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.status().is4xxClientError())
.andExpect(MockMvcResultMatchers.content().json("{\"status\":400,\"exception\":\"MethodArgumentNotValidException\",\"erros\":[{\"defaultMessage\":\"may not be null\",\"field\":\"plans\",\"code\":\"NotNull\"}]}"));
}

@Test
@WithMockUser(username="tester", authorities={"CREATE_ACCESSTOKEN"})
public void testSavingAccessTokenWithoutDefaultValues() throws Exception {
Expand All @@ -93,7 +115,7 @@ public void testSavingAccessTokenWithoutDefaultValues() throws Exception {
Mockito.when(service.save(Mockito.any(AccessTokenPersist.class))).thenReturn(recoverAt);

mockMvc.perform(MockMvcRequestBuilders.post(ConstantsPath.PATH_ACCESS_TOKENS, 10L)
.content("{\"code\":\"!!@!##1212\",\"app\":{\"id\":10}}")
.content("{\"code\":\"!!@!##1212\",\"app\":{\"id\":10}, \"plans\": [{\"id\": 5}]}")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.status().isCreated());
}
Expand Down
2 changes: 1 addition & 1 deletion heimdall-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>br.com.conductor.heimdall</groupId>
<artifactId>heimdall</artifactId>
<version>2.3.2-SNAPSHOT</version>
<version>2.4.2-SNAPSHOT</version>
</parent>

<artifactId>heimdall-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,7 @@ public class AppDTO implements Serializable {

private Status status;

@NotNull
@Size(min = 1)
private List<ReferenceIdDTO> plans;
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public class AccessTokenPersist implements Serializable {

private LocalDateTime expiredDate;

@NotNull
@Size(min = 1)
private List<ReferenceIdDTO> plans;

private Status status;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ public class AppPersist implements Serializable {

private Status status;

@NotNull
@Size(min = 1)
private List<ReferenceIdDTO> plans;

private String clientId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ private void initValuesPersist() {
status = (status == null) ? Status.ACTIVE : status;

creationDate = LocalDateTime.now();
code = code.trim();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ private void initValuesPersist() {
status = (status == null) ? Status.ACTIVE : status;

creationDate = LocalDateTime.now();
clientId = clientId.trim();
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import javax.persistence.*;

import lombok.ToString;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

Expand Down Expand Up @@ -67,6 +68,7 @@ public class Plan implements Serializable {
@ManyToOne
@JoinColumn(name = "API_ID", nullable = false)
@JsonIgnoreProperties({ "environments" })
@ToString.Exclude
private Api api;

@Column(name = "CREATION_DATE", nullable = false, updatable=false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ public enum ExceptionMessage {

ENVIRONMENT_ATTACHED_TO_API(BAD_REQUEST.value(), "Environment attached to Api", BadRequestException.class),

PLAN_ATTACHED_TO_APPS(BAD_REQUEST.value(), "Plan attached to App", BadRequestException.class),

ENVIRONMENT_INBOUND_DNS_PATTERN(BAD_REQUEST.value(), "Environment inbound URL has to follow the pattern http[s]://host.domain[:port] or www.host.domain[:port]", BadRequestException.class),

PROVIDER_NOT_FOUND(BAD_REQUEST.value(), "Provider not found", BadRequestException.class),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import br.com.conductor.heimdall.core.entity.Middleware;
import br.com.conductor.heimdall.core.enums.Status;
Expand Down Expand Up @@ -95,5 +98,13 @@ public interface MiddlewareRepository extends JpaRepository<Middleware, Long> {
* @return The Middleware found
*/
Middleware findTop1ByApiIdOrderByVersionDesc(Long apiId);

/**
*
* @param id interceptor id
*/
@Modifying
@Query(value = "DELETE FROM MIDDLEWARES_INTERCEPTORS WHERE INTERCEPTOR_ID = :ID", nativeQuery = true)
void detachFromInterceptor(@Param("ID") Long id);

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import org.springframework.data.jpa.repository.JpaRepository;

import br.com.conductor.heimdall.core.entity.Plan;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

/**
* Plan Repository.
Expand All @@ -33,4 +35,13 @@
*/
public interface PlanRepository extends JpaRepository<Plan, Long> {

/**
* Check if a plan has apps attached
*
* @param id
* @return
*/
@Query(value = "select count(0) from apps_plans where plan_id = :id", nativeQuery = true)
Integer findAppsWithPlan(@Param("id") Long id);

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,17 @@
*/

import static br.com.conductor.heimdall.core.exception.ExceptionMessage.*;
import static br.com.twsoftware.alfred.object.Objeto.isBlank;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import br.com.conductor.heimdall.core.dto.ReferenceIdDTO;
import br.com.conductor.heimdall.core.dto.persist.AppPersist;
import br.com.conductor.heimdall.core.entity.AccessToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
Expand All @@ -37,9 +41,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;

//import br.com.conductor.heimdall.core.converter.AppMap;
import br.com.conductor.heimdall.core.converter.GenericConverter;
import br.com.conductor.heimdall.core.dto.AppDTO;
import br.com.conductor.heimdall.core.dto.PageDTO;
Expand Down Expand Up @@ -184,7 +186,9 @@ public App save(AppPersist appDTO) {
public App update(Long id, AppDTO appDTO) {

App app = appRepository.findOne(id);
HeimdallException.checkThrow(app == null, GLOBAL_RESOURCE_NOT_FOUND);
HeimdallException.checkThrow(isBlank(app), GLOBAL_RESOURCE_NOT_FOUND);

updateTokensPlansByApp(id, appDTO.getPlans().stream().map(ReferenceIdDTO::getId).collect(Collectors.toList()));

app.setAccessTokens(accessTokenRepository.findByAppId(app.getId()));
app = GenericConverter.mapper(appDTO, app);
Expand All @@ -195,6 +199,26 @@ public App update(Long id, AppDTO appDTO) {
return app;
}

/**
* Updates app's access tokens.
* This is used for removing the access token to plan association, only if an app removes one of it's plans.
*
* @param appId The ID of the {@link App}
* @param plansIds List of {@link Plan}'s IDs
*/
private void updateTokensPlansByApp(Long appId, List<Long> plansIds) {
List<AccessToken> accessTokenList = accessTokenRepository.findByAppId(appId);
if (Objects.nonNull(accessTokenList)) {
accessTokenList.forEach(accessToken -> {
if (Objects.nonNull(accessToken.getPlans()) && !accessToken.getPlans().isEmpty()) {
List<Plan> planList = accessToken.getPlans().stream().filter(plan -> plansIds.contains(plan.getId())).collect(Collectors.toList());
accessToken.setPlans(planList);
accessTokenRepository.save(accessToken);
}
});
}
}

/**
* Deletes a {@link App} by its ID.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ public void delete(Long id) {

String api = interceptor.getOperation().getResource().getApi().getId().toString();
pathName = String.join("/", zuulFilterRoot, MIDDLEWARE_API_ROOT, api, fileName);
middlewareRepository.detachFromInterceptor(id);
}

if (TypeInterceptor.CORS.equals(interceptor.getType())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import static br.com.conductor.heimdall.core.exception.ExceptionMessage.DEFAULT_PLAN_ALREADY_EXIST_TO_THIS_API;
import static br.com.conductor.heimdall.core.exception.ExceptionMessage.GLOBAL_RESOURCE_NOT_FOUND;
import static br.com.conductor.heimdall.core.exception.ExceptionMessage.PLAN_ATTACHED_TO_APPS;

import java.util.List;

Expand Down Expand Up @@ -173,6 +174,9 @@ public void delete(Long id) {
Plan plan = planRepository.findOne(id);
HeimdallException.checkThrow(plan == null, GLOBAL_RESOURCE_NOT_FOUND);

Integer totalAppsAttached = planRepository.findAppsWithPlan(id);
HeimdallException.checkThrow(totalAppsAttached > 0, PLAN_ATTACHED_TO_APPS);

planRepository.delete(plan);

amqpCacheService.dispatchClean();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,19 @@
* ==========================LICENSE_END===================================
*/

import br.com.conductor.heimdall.core.dto.AppDTO;
import br.com.conductor.heimdall.core.dto.ReferenceIdDTO;
import br.com.conductor.heimdall.core.dto.persist.AppPersist;
import br.com.conductor.heimdall.core.entity.AccessToken;
import br.com.conductor.heimdall.core.entity.App;
import br.com.conductor.heimdall.core.entity.Developer;
import br.com.conductor.heimdall.core.entity.Plan;
import br.com.conductor.heimdall.core.exception.BadRequestException;
import br.com.conductor.heimdall.core.repository.AccessTokenRepository;
import br.com.conductor.heimdall.core.repository.AppRepository;
import br.com.conductor.heimdall.core.repository.DeveloperRepository;
import br.com.conductor.heimdall.core.service.amqp.AMQPCacheService;
import com.google.common.collect.Lists;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
Expand All @@ -39,6 +44,9 @@
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.ArrayList;
import java.util.List;

/**
* @author <a href="https://dijalmasilva.github.io" target="_blank">Dijalma Silva</a>
*/
Expand All @@ -56,6 +64,9 @@ public class AppServiceTest {

@Mock
private AMQPCacheService amqpCacheService;

@Mock
private AccessTokenRepository accessTokenRepository;

@Rule
public ExpectedException thrown = ExpectedException.none();
Expand All @@ -64,6 +75,8 @@ public class AppServiceTest {
private App app1;
private Developer developer;
private AppPersist appPersist;
private AppDTO appDTO;
private List<ReferenceIdDTO> referenceIdDTOList = Lists.newArrayList(new ReferenceIdDTO(0L));

@Before
public void initAttributes() {
Expand All @@ -84,6 +97,10 @@ public void initAttributes() {
appPersist.setName("App test");
appPersist.setDescription("App test description");
appPersist.setDeveloper(new ReferenceIdDTO(1L));

appDTO = new AppDTO();
appDTO.setName("App name");
appDTO.setDeveloper(new ReferenceIdDTO(1l));
}

@Test
Expand Down Expand Up @@ -129,4 +146,58 @@ public void testSaveWithCodeIsAlready() {

this.appService.save(appPersist);
}

@Test
public void testUpdateHavingPlans() {
Mockito.when(appRepository.findOne(Mockito.anyLong())).thenReturn(app);
Mockito.when(appRepository.save(Mockito.any(App.class))).thenReturn(app);
Mockito.when(accessTokenRepository.findByAppId(Mockito.anyLong())).thenReturn(Lists.newArrayList(getAccessToken(Lists.newArrayList(getPlan()))));

appDTO.setPlans(referenceIdDTOList);

this.appService.update(0L, appDTO);
Mockito.verify(accessTokenRepository, Mockito.times(2)).findByAppId(Mockito.anyLong());
Mockito.verify(accessTokenRepository, Mockito.times(1)).save(Mockito.any(AccessToken.class));
}


@Test
public void testUpdateHavingNoAccessToken() {
Mockito.when(appRepository.findOne(Mockito.anyLong())).thenReturn(app);
Mockito.when(appRepository.save(Mockito.any(App.class))).thenReturn(app);
Mockito.when(accessTokenRepository.findByAppId(Mockito.anyLong())).thenReturn(null);

appDTO.setPlans(referenceIdDTOList);

this.appService.update(0L, appDTO);
Mockito.verify(accessTokenRepository, Mockito.times(0)).save(Mockito.any(AccessToken.class));
}

@Test
public void testUpdateHavingEmptyAccessToken() {
Mockito.when(appRepository.findOne(Mockito.anyLong())).thenReturn(app);
Mockito.when(appRepository.save(Mockito.any(App.class))).thenReturn(app);
Mockito.when(accessTokenRepository.findByAppId(Mockito.anyLong())).thenReturn(new ArrayList<>());

appDTO.setPlans(referenceIdDTOList);

this.appService.update(0L, appDTO);
Mockito.verify(accessTokenRepository, Mockito.times(0)).save(Mockito.any(AccessToken.class));
}


private Plan getPlan() {

Plan plan = new Plan();
plan.setId(1l);
return plan;
}

private AccessToken getAccessToken(List<Plan> plans) {

AccessToken accessToken = new AccessToken();
accessToken.setPlans(plans);
accessToken.setId(0L);
return accessToken;
}
}
Loading