diff --git a/heimdall-api/pom.xml b/heimdall-api/pom.xml
index e6d5d587..163976dc 100644
--- a/heimdall-api/pom.xml
+++ b/heimdall-api/pom.xml
@@ -5,7 +5,7 @@
br.com.conductor.heimdall
heimdall
- 2.3.2-SNAPSHOT
+ 2.4.2-SNAPSHOT
heimdall-api
heimdall-api
diff --git a/heimdall-api/src/test/java/br/com/conductor/heimdall/api/resource/AccessTokenResourceTest.java b/heimdall-api/src/test/java/br/com/conductor/heimdall/api/resource/AccessTokenResourceTest.java
index 512522b0..cce99200 100644
--- a/heimdall-api/src/test/java/br/com/conductor/heimdall/api/resource/AccessTokenResourceTest.java
+++ b/heimdall-api/src/test/java/br/com/conductor/heimdall/api/resource/AccessTokenResourceTest.java
@@ -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 {
@@ -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());
}
diff --git a/heimdall-core/pom.xml b/heimdall-core/pom.xml
index 9306cc36..4697cfbb 100644
--- a/heimdall-core/pom.xml
+++ b/heimdall-core/pom.xml
@@ -4,7 +4,7 @@
br.com.conductor.heimdall
heimdall
- 2.3.2-SNAPSHOT
+ 2.4.2-SNAPSHOT
heimdall-core
diff --git a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/dto/AppDTO.java b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/dto/AppDTO.java
index d9a9afed..1ec5ddc6 100644
--- a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/dto/AppDTO.java
+++ b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/dto/AppDTO.java
@@ -56,5 +56,7 @@ public class AppDTO implements Serializable {
private Status status;
+ @NotNull
+ @Size(min = 1)
private List plans;
}
diff --git a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/dto/persist/AccessTokenPersist.java b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/dto/persist/AccessTokenPersist.java
index 729b42b9..619ea5bd 100644
--- a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/dto/persist/AccessTokenPersist.java
+++ b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/dto/persist/AccessTokenPersist.java
@@ -52,6 +52,8 @@ public class AccessTokenPersist implements Serializable {
private LocalDateTime expiredDate;
+ @NotNull
+ @Size(min = 1)
private List plans;
private Status status;
diff --git a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/dto/persist/AppPersist.java b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/dto/persist/AppPersist.java
index 0385e0da..51d78715 100644
--- a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/dto/persist/AppPersist.java
+++ b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/dto/persist/AppPersist.java
@@ -56,6 +56,8 @@ public class AppPersist implements Serializable {
private Status status;
+ @NotNull
+ @Size(min = 1)
private List plans;
private String clientId;
diff --git a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/entity/AccessToken.java b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/entity/AccessToken.java
index 978bd60c..4524632a 100644
--- a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/entity/AccessToken.java
+++ b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/entity/AccessToken.java
@@ -103,6 +103,7 @@ private void initValuesPersist() {
status = (status == null) ? Status.ACTIVE : status;
creationDate = LocalDateTime.now();
+ code = code.trim();
}
}
diff --git a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/entity/App.java b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/entity/App.java
index c84d8624..20c4d237 100644
--- a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/entity/App.java
+++ b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/entity/App.java
@@ -101,6 +101,7 @@ private void initValuesPersist() {
status = (status == null) ? Status.ACTIVE : status;
creationDate = LocalDateTime.now();
+ clientId = clientId.trim();
}
diff --git a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/entity/Plan.java b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/entity/Plan.java
index f930f8dd..8853a7bd 100644
--- a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/entity/Plan.java
+++ b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/entity/Plan.java
@@ -27,6 +27,7 @@
import javax.persistence.*;
+import lombok.ToString;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
@@ -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)
diff --git a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/exception/ExceptionMessage.java b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/exception/ExceptionMessage.java
index bc52c752..264eb68a 100644
--- a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/exception/ExceptionMessage.java
+++ b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/exception/ExceptionMessage.java
@@ -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),
diff --git a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/repository/MiddlewareRepository.java b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/repository/MiddlewareRepository.java
index f9952a93..7c868e98 100644
--- a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/repository/MiddlewareRepository.java
+++ b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/repository/MiddlewareRepository.java
@@ -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;
@@ -95,5 +98,13 @@ public interface MiddlewareRepository extends JpaRepository {
* @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);
}
diff --git a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/repository/PlanRepository.java b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/repository/PlanRepository.java
index 02fcbefc..14aa1534 100644
--- a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/repository/PlanRepository.java
+++ b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/repository/PlanRepository.java
@@ -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.
@@ -33,4 +35,13 @@
*/
public interface PlanRepository extends JpaRepository {
+ /**
+ * 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);
+
}
diff --git a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/service/AppService.java b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/service/AppService.java
index 43f47284..48f7c973 100644
--- a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/service/AppService.java
+++ b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/service/AppService.java
@@ -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;
@@ -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;
@@ -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);
@@ -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 plansIds) {
+ List accessTokenList = accessTokenRepository.findByAppId(appId);
+ if (Objects.nonNull(accessTokenList)) {
+ accessTokenList.forEach(accessToken -> {
+ if (Objects.nonNull(accessToken.getPlans()) && !accessToken.getPlans().isEmpty()) {
+ List 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.
*
diff --git a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/service/InterceptorService.java b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/service/InterceptorService.java
index acc53d40..0bf0b03a 100644
--- a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/service/InterceptorService.java
+++ b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/service/InterceptorService.java
@@ -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())) {
diff --git a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/service/PlanService.java b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/service/PlanService.java
index ae0f6668..596f761b 100644
--- a/heimdall-core/src/main/java/br/com/conductor/heimdall/core/service/PlanService.java
+++ b/heimdall-core/src/main/java/br/com/conductor/heimdall/core/service/PlanService.java
@@ -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;
@@ -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();
diff --git a/heimdall-core/src/test/java/br/com/conductor/heimdall/core/service/AppServiceTest.java b/heimdall-core/src/test/java/br/com/conductor/heimdall/core/service/AppServiceTest.java
index e63bc7e2..d16890c1 100644
--- a/heimdall-core/src/test/java/br/com/conductor/heimdall/core/service/AppServiceTest.java
+++ b/heimdall-core/src/test/java/br/com/conductor/heimdall/core/service/AppServiceTest.java
@@ -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;
@@ -39,6 +44,9 @@
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* @author Dijalma Silva
*/
@@ -56,6 +64,9 @@ public class AppServiceTest {
@Mock
private AMQPCacheService amqpCacheService;
+
+ @Mock
+ private AccessTokenRepository accessTokenRepository;
@Rule
public ExpectedException thrown = ExpectedException.none();
@@ -64,6 +75,8 @@ public class AppServiceTest {
private App app1;
private Developer developer;
private AppPersist appPersist;
+ private AppDTO appDTO;
+ private List referenceIdDTOList = Lists.newArrayList(new ReferenceIdDTO(0L));
@Before
public void initAttributes() {
@@ -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
@@ -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 plans) {
+
+ AccessToken accessToken = new AccessToken();
+ accessToken.setPlans(plans);
+ accessToken.setId(0L);
+ return accessToken;
+ }
}
diff --git a/heimdall-frontend/package.json b/heimdall-frontend/package.json
index 1298541f..2435bffc 100644
--- a/heimdall-frontend/package.json
+++ b/heimdall-frontend/package.json
@@ -15,18 +15,20 @@
"i18next": "11.9.0",
"i18next-browser-languagedetector": "2.2.3",
"less": "2.7.3",
+ "less-loader": "^5.0.0",
"lodash.flow": "3.5.0",
"moment": "2.22.1",
"nprogress": "0.2.0",
"prop-types": "15.6.1",
"rc-animate": "2.4.4",
- "react": "16.3.2",
+ "react": "^16.8.6",
"react-ace": "6.2.0",
"react-addons-css-transition-group": "15.6.2",
"react-addons-update": "15.6.2",
"react-dnd": "2.6.0",
"react-dnd-html5-backend": "2.6.0",
- "react-dom": "16.3.2",
+ "react-dom": "^16.8.6",
+ "react-i18next": "8.3.8",
"react-joyride": "1.11.4",
"react-json-view": "^1.17.1",
"react-particles-js": "2.1.2",
@@ -38,9 +40,8 @@
"recharts": "1.0.0-beta.10",
"redux": "3.7.2",
"redux-logger": "3.0.6",
- "swagger-ui": "3.19.4",
"redux-thunk": "2.3.0",
- "react-i18next": "8.3.8"
+ "swagger-ui": "3.19.4"
},
"scripts": {
"start": "react-app-rewired start",
diff --git a/heimdall-frontend/src/actions/plans/index.js b/heimdall-frontend/src/actions/plans/index.js
index 022bd394..dd752ad7 100644
--- a/heimdall-frontend/src/actions/plans/index.js
+++ b/heimdall-frontend/src/actions/plans/index.js
@@ -78,5 +78,12 @@ export const remove = planId => dispatch => {
dispatch(getAllPlans())
dispatch(sendNotification({ type: 'success', message: i18n.t('plan_removed') }))
})
+ .catch(error => {
+ if (error.response && error.response.status === 400) {
+ dispatch(sendNotification({ type: 'error', message: i18n.t('error'), description: error.response.data.message }))
+ }
+ dispatch(getAllPlans())
+ dispatch(finishLoading())
+ })
}
diff --git a/heimdall-frontend/src/components/access-tokens/AccessTokenForm.js b/heimdall-frontend/src/components/access-tokens/AccessTokenForm.js
index a90a44f9..636e78d7 100644
--- a/heimdall-frontend/src/components/access-tokens/AccessTokenForm.js
+++ b/heimdall-frontend/src/components/access-tokens/AccessTokenForm.js
@@ -52,6 +52,9 @@ class AccessTokenForm extends Component {
checkApp = (rule, value, callback) => {
if (this.props.appSource.some(app => app.id === value)) {
const app = this.props.appSource.filter(app => app.id === value)[0];
+ if (app.plans === undefined || app.plans.length === 0) {
+ callback(i18n.t('app_plans_invalid'))
+ }
this.setState({...this.state, plans: app.plans})
callback();
return
@@ -59,6 +62,14 @@ class AccessTokenForm extends Component {
callback(i18n.t('you_need_select_app'));
}
+ checkToken = (rule, value, callback) => {
+ if (value !== value.trim()) {
+ callback(i18n.t('please_check_token_spacing'))
+ }
+ callback()
+ return
+ }
+
render() {
const {getFieldDecorator} = this.props.form
@@ -79,7 +90,8 @@ class AccessTokenForm extends Component {
getFieldDecorator('code', {
initialValue: accessToken && accessToken.code,
rules: [
- {min: 6, message: i18n.t('min_6_characters_to_token')}
+ {min: 6, message: i18n.t('min_6_characters_to_token')},
+ {validator: this.checkToken}
]
})()
@@ -129,7 +141,10 @@ class AccessTokenForm extends Component {
{
getFieldDecorator('plans', {
- initialValue: accessToken && accessToken.plans.map(plan => plan.id)
+ initialValue: accessToken && accessToken.plans.map(plan => plan.id),
+ rules: [
+ {required: true, message: i18n.t('please_pick_plan')}
+ ]
})(
{plans && plans.map((plan, index) => {
return import('../../containers/Resources'))
+const Middlewares = lazy(() => import('../../containers/Middlewares'))
+const Interceptors = lazy(() => import('../../containers/Interceptors'))
+const Scopes = lazy(() => import('../../containers/Scopes'))
+
const TabPane = Tabs.TabPane;
class SingleApi extends Component {
@@ -63,21 +65,29 @@ class SingleApi extends Component {
{PrivilegeUtils.verifyPrivileges([privileges.PRIVILEGE_READ_RESOURCE]) &&
{i18n.t('resources')}}
key="2">
-
+ }>
+
+
}
{PrivilegeUtils.verifyPrivileges([privileges.PRIVILEGE_READ_INTERCEPTOR]) &&
{i18n.t('interceptors')}}
key="3">
-
+ }>
+
+
}
{PrivilegeUtils.verifyPrivileges([privileges.PRIVILEGE_READ_MIDDLEWARE]) &&
{i18n.t('middlewares')}}
key="4">
-
+ }>
+
+
}
{PrivilegeUtils.verifyPrivileges([privileges.PRIVILEGE_READ_SCOPE]) &&
{i18n.t('scopes')}} key="5">
-
+ }>
+
+
}
diff --git a/heimdall-frontend/src/components/apps/AppForm.js b/heimdall-frontend/src/components/apps/AppForm.js
index 3de01eaa..5e24af71 100644
--- a/heimdall-frontend/src/components/apps/AppForm.js
+++ b/heimdall-frontend/src/components/apps/AppForm.js
@@ -51,6 +51,15 @@ class AppForm extends Component {
callback(i18n.t('you_need_select_developer'));
}
+ checkClientId = (rule, value, callback) => {
+
+ if (value && value !== value.trim()) {
+ callback(i18n.t('please_check_client_id_spacing'))
+ }
+ callback()
+ return
+ }
+
render() {
const {getFieldDecorator} = this.props.form
@@ -108,7 +117,8 @@ class AppForm extends Component {
getFieldDecorator('clientId', {
initialValue: app && app.clientId,
rules: [
- {min: 6, message: i18n.t('min_6_characters_to_client_id')}
+ {min: 6, message: i18n.t('min_6_characters_to_client_id')},
+ {validator: this.checkClientId}
]
})()
@@ -157,7 +167,10 @@ class AppForm extends Component {
{
getFieldDecorator('plans', {
- initialValue: app && app.plans.map(plan => plan.id)
+ initialValue: app && app.plans.map(plan => plan.id),
+ rules: [
+ {required: true, message: i18n.t('please_pick_plan')}
+ ]
})(
{this.props.plans && this.props.plans.content.map((plan, index) => {
return
- { interceptor && interceptor.content && TEMPLATES(this.props.form, JSON.parse(interceptor.content))[type] }
- { (!interceptor || !interceptor.content) && TEMPLATES(this.props.form, undefined )[type] }
+ { interceptor && interceptor.content && TEMPLATES(this.props.form, interceptor.content, type)[type] }
+ { (!interceptor || !interceptor.content) && TEMPLATES(this.props.form, undefined, type )[type] }
diff --git a/heimdall-frontend/src/containers/App.js b/heimdall-frontend/src/containers/App.js
index 03487039..a4bdfa16 100644
--- a/heimdall-frontend/src/containers/App.js
+++ b/heimdall-frontend/src/containers/App.js
@@ -12,7 +12,7 @@ class App extends Component {
return (
-
+
{/* {routes} */}
diff --git a/heimdall-frontend/src/i18n/en.js b/heimdall-frontend/src/i18n/en.js
index efaa43a1..3380a289 100644
--- a/heimdall-frontend/src/i18n/en.js
+++ b/heimdall-frontend/src/i18n/en.js
@@ -160,6 +160,7 @@ export default {
'min_5_characters_to_description': 'Min of 5 Characters to description!',
'min_6_characters_to_client_id': 'Min of 6 Characters to clientId!',
'please_input_email_developer': 'Please, input a email of developer!',
+ 'please_pick_plan': 'Please choose at least one plan',
'please_input_your_name': 'Please, input your name!',
'please_input_valid_email': 'Please, input a valid email!',
'please_input_your_environment_name': 'Please, input your environment name!',
@@ -310,6 +311,9 @@ export default {
'ignored_headers': 'Ignored Headers',
'param_name': 'Param Name',
'param_value': 'Param Value',
- 'add_new_param': 'Add new param'
+ 'add_new_param': 'Add new param',
+ 'app_plans_invalid': 'App\'s plans are invalid!',
+ 'please_check_token_spacing': 'Please check token\'s spacing!',
+ 'please_check_client_id_spacing': 'Please check Client ID\'s spacing!'
}
}
\ No newline at end of file
diff --git a/heimdall-frontend/src/i18n/pt-br.js b/heimdall-frontend/src/i18n/pt-br.js
index 756593c3..a7e58525 100644
--- a/heimdall-frontend/src/i18n/pt-br.js
+++ b/heimdall-frontend/src/i18n/pt-br.js
@@ -160,6 +160,7 @@ export default {
'min_5_characters_to_description': 'A descrição deve ter no mínimo 5 caracteres!',
'min_6_characters_to_client_id': 'O ID do Cliente deve ter no mínimo 6 caracteres!',
'please_input_email_developer': 'Por favor, insira o email de um desenvolvedor!',
+ 'please_pick_plan': 'Por favor, selecione ao menos um Plano!',
'please_input_your_name': 'Por favor, insira seu nome!',
'please_input_valid_email': 'Por favor, insira um email válido!',
'please_input_your_environment_name': 'Por favor, insira o nome do ambiente!',
@@ -310,6 +311,9 @@ export default {
'ignored_headers': 'Cabeçalhos ignorados',
'param_name': 'Nome do parâmetro',
'param_value': 'Valor do parâmetro',
- 'add_new_param': 'Adicionar novo paramêtro'
+ 'add_new_param': 'Adicionar novo paramêtro',
+ 'app_plans_invalid': 'Planos do App são invalidos!',
+ 'please_check_token_spacing': 'Por favor, verificar espaçamentos no Token!',
+ 'please_check_client_id_spacing': 'Por favor, verificar espaçamentos no Client ID!'
}
}
\ No newline at end of file
diff --git a/heimdall-frontend/src/routes/index.js b/heimdall-frontend/src/routes/index.js
index 9e1f6fe2..b58e5d31 100644
--- a/heimdall-frontend/src/routes/index.js
+++ b/heimdall-frontend/src/routes/index.js
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { Suspense, lazy } from 'react'
import { Switch, Redirect } from 'react-router'
// HOCs
import FadeIn from '../components/wrappers/FadeIn'
@@ -14,81 +14,86 @@ import { privileges } from '../constants/privileges-types'
// Route components
// import Home from '../components/Home'
-import Apis from '../components/apis/Index'
-import NewApi from '../components/apis/NewApi'
-import SingleApi from '../components/apis/SingleApi'
-import SingleListApis from '../components/apis/SingleListApis'
-import ApiInterceptors from '../components/apis/ApiInterceptors'
-import SingleResource from '../components/apis/SingleResource'
-
+import Authorization from '../components/policy/Authorization'
import LoginContainer from '../containers/Login'
-import Environments from '../containers/Environments'
+import Loading from "../components/ui/Loading";
-import Authorization from '../components/policy/Authorization'
-import SingleEnvironment from '../containers/SingleEnvironment';
-import Developers from '../containers/Developers';
-import SingleDeveloper from '../containers/SingleDeveloper';
-import Apps from '../containers/Apps';
-import SingleApp from '../containers/SingleApp';
-import Plans from '../containers/Plans';
-import SinglePlan from '../containers/SinglePlan';
-import AccessTokens from '../containers/AccessTokens';
-import SingleAccessToken from '../containers/SingleAccessToken';
-import Users from '../containers/Users';
-import SingleUser from '../containers/SingleUser';
-import Traces from "../containers/Traces";
-import SingleTrace from "../containers/SingleTrace";
-import Roles from "../containers/Roles";
-import SingleRole from "../containers/SingleRole";
-import SingleLdap from "../containers/SingleLdap";
-import Providers from "../containers/Providers";
-import SingleProvider from "../containers/SingleProvider";
-import UsersChangePassword from "../containers/UsersChangePassword";
-import SingleApiSwaggerEditor from "../components/apis/SingleApiSwaggerEditor"
+const Apis = lazy(() => import('../components/apis/Index'))
+const NewApi = lazy(() => import('../components/apis/NewApi'))
+const SingleApi = lazy(() => import('../components/apis/SingleApi'))
+const SingleListApis = lazy(() => import('../components/apis/SingleListApis'))
+const ApiInterceptors = lazy(() => import('../components/apis/ApiInterceptors'))
+const SingleResource = lazy(() => import('../components/apis/SingleResource'))
+const Environments = lazy(() => import('../containers/Environments'))
+const SingleEnvironment = lazy(() => import('../containers/SingleEnvironment'))
+const Developers = lazy(() => import('../containers/Developers'))
+const SingleDeveloper = lazy(() => import('../containers/SingleDeveloper'))
+const Apps = lazy(() => import('../containers/Apps'))
+const SingleApp = lazy(() => import('../containers/SingleApp'))
+const Plans = lazy(() => import('../containers/Plans'))
+const SinglePlan = lazy(() => import('../containers/SinglePlan'))
+const AccessTokens = lazy(() => import('../containers/AccessTokens'))
+const SingleAccessToken = lazy(() => import('../containers/SingleAccessToken'))
+const Users = lazy(() => import('../containers/Users'))
+const SingleUser = lazy(() => import('../containers/SingleUser'))
+const Traces = lazy(() => import('../containers/Traces'))
+const SingleTrace = lazy(() => import('../containers/SingleTrace'))
+const Roles = lazy(() => import('../containers/Roles'))
+const SingleRole = lazy(() => import('../containers/SingleRole'))
+const SingleLdap = lazy(() => import('../containers/SingleLdap'))
+const Providers = lazy(() => import('../containers/Providers'))
+const SingleProvider = lazy(() => import('../containers/SingleProvider'))
+const UsersChangePassword = lazy(() => import('../containers/UsersChangePassword'))
+const SingleApiSwaggerEditor = lazy(() => import('../components/apis/SingleApiSwaggerEditor'))
-const routes = ({ history }) => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* routes not finded or 404 */}
-
+const Loadable = Component => props => (
+ }>
+
+
+)
-
+const routes = ({ history }) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* routes not found or 404 */}
+
+
)
export default routes
diff --git a/heimdall-frontend/src/utils/InterceptorContentUtils.js b/heimdall-frontend/src/utils/InterceptorContentUtils.js
index 003f63a7..cac946af 100644
--- a/heimdall-frontend/src/utils/InterceptorContentUtils.js
+++ b/heimdall-frontend/src/utils/InterceptorContentUtils.js
@@ -58,10 +58,6 @@ const logMaskerContent = content => {
}
const defaultContent = content => {
- if (content) {
- return JSON.stringify(content)
- }
-
return content
}
diff --git a/heimdall-frontend/src/utils/InterceptorUtils.js b/heimdall-frontend/src/utils/InterceptorUtils.js
index 6a95f2f6..59286148 100644
--- a/heimdall-frontend/src/utils/InterceptorUtils.js
+++ b/heimdall-frontend/src/utils/InterceptorUtils.js
@@ -13,23 +13,38 @@ import Identifier from '../components/interceptors/wrappers/Identifier'
import LogMasker from '../components/interceptors/wrappers/LogMasker'
import { InterceptorContent } from './InterceptorContentUtils'
-export const TEMPLATES = (form, content) => ({
- ACCESS_TOKEN: ,
- CLIENT_ID: ,
- MOCK: ,
- RATTING: ,
- BLACKLIST: ,
- WHITELIST: ,
- CACHE: ,
- CACHE_CLEAR: ,
- CORS: ,
- CUSTOM: ,
- LOG_MASKER: ,
- OAUTH: ,
- IDENTIFIER: ,
- MIDDLEWARE: ,
+export const TEMPLATES = (form, content, type) => ({
+ ACCESS_TOKEN: ,
+ CLIENT_ID: ,
+ MOCK: ,
+ RATTING: ,
+ BLACKLIST: ,
+ WHITELIST: ,
+ CACHE: ,
+ CACHE_CLEAR: ,
+ CORS: ,
+ CUSTOM: ,
+ LOG_MASKER: ,
+ OAUTH: ,
+ IDENTIFIER: ,
+ MIDDLEWARE: ,
})
+const parseContentByType = (content, type) => {
+
+ if (!content) {
+ return content
+ }
+
+ switch (type) {
+ case 'MIDDLEWARE':
+ case 'CUSTOM':
+ return content
+ default:
+ return JSON.parse(content)
+ }
+}
+
export const CONTENTS = (content, type) => {
switch (type) {
diff --git a/heimdall-gateway/pom.xml b/heimdall-gateway/pom.xml
index 86d63371..eb905b7a 100644
--- a/heimdall-gateway/pom.xml
+++ b/heimdall-gateway/pom.xml
@@ -5,7 +5,7 @@
br.com.conductor.heimdall
heimdall
- 2.3.2-SNAPSHOT
+ 2.4.2-SNAPSHOT
heimdall-gateway
heimdall-gateway
diff --git a/heimdall-gateway/src/main/java/br/com/conductor/heimdall/gateway/filter/helper/CallImpl.java b/heimdall-gateway/src/main/java/br/com/conductor/heimdall/gateway/filter/helper/CallImpl.java
index f3350171..469c17a3 100644
--- a/heimdall-gateway/src/main/java/br/com/conductor/heimdall/gateway/filter/helper/CallImpl.java
+++ b/heimdall-gateway/src/main/java/br/com/conductor/heimdall/gateway/filter/helper/CallImpl.java
@@ -102,7 +102,7 @@ public String get(String name) {
HttpServletRequest r = context.getRequest();
String value = r.getHeader(name);
- if (value != null) {
+ if (value == null) {
value = context.getZuulRequestHeaders().get(name);
}
diff --git a/heimdall-middleware-spec/pom.xml b/heimdall-middleware-spec/pom.xml
index 43b4bb10..44fd94d5 100644
--- a/heimdall-middleware-spec/pom.xml
+++ b/heimdall-middleware-spec/pom.xml
@@ -4,7 +4,7 @@
br.com.conductor.heimdall
heimdall
- 2.3.2-SNAPSHOT
+ 2.4.2-SNAPSHOT
heimdall-middleware-spec
diff --git a/pom.xml b/pom.xml
index fd5fc6c9..5dcaff97 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,7 +13,7 @@
br.com.conductor.heimdall
heimdall
- 2.3.2-SNAPSHOT
+ 2.4.2-SNAPSHOT
pom
Heimdall
@@ -274,12 +274,12 @@
br.com.conductor.heimdall
heimdall-core
- 2.3.2-SNAPSHOT
+ 2.4.2-SNAPSHOT
br.com.conductor.heimdall
heimdall-middleware-spec
- 2.3.2-SNAPSHOT
+ 2.4.2-SNAPSHOT
org.mongodb