Merge branch 'develop/3.4' into refactoring_tests_alarm_customer
refactoring: alarm resolving the conflict
This commit is contained in:
		
						commit
						eceec2af0c
					
				@ -19,6 +19,8 @@ server:
 | 
			
		||||
  address: "${HTTP_BIND_ADDRESS:0.0.0.0}"
 | 
			
		||||
  # Server bind port
 | 
			
		||||
  port: "${HTTP_BIND_PORT:8080}"
 | 
			
		||||
  # Server forward headers strategy
 | 
			
		||||
  forward_headers_strategy: "${HTTP_FORWARD_HEADERS_STRATEGY:NONE}"
 | 
			
		||||
  # Server SSL configuration
 | 
			
		||||
  ssl:
 | 
			
		||||
    # Enable/disable SSL support
 | 
			
		||||
 | 
			
		||||
@ -32,8 +32,6 @@ import org.thingsboard.server.common.msg.TbMsg;
 | 
			
		||||
import org.thingsboard.server.dao.audit.AuditLogService;
 | 
			
		||||
import org.thingsboard.server.dao.model.ModelConstants;
 | 
			
		||||
 | 
			
		||||
import java.io.PrintWriter;
 | 
			
		||||
import java.io.StringWriter;
 | 
			
		||||
import java.util.Locale;
 | 
			
		||||
 | 
			
		||||
import static org.mockito.Mockito.never;
 | 
			
		||||
@ -49,40 +47,47 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
 | 
			
		||||
    @SpyBean
 | 
			
		||||
    protected AuditLogService auditLogService;
 | 
			
		||||
 | 
			
		||||
    protected void testNotifyEntityOne(HasName entity, EntityId entityId, EntityId originatorId,
 | 
			
		||||
                                       TenantId tenantId, CustomerId customerId, UserId userId, String userName,
 | 
			
		||||
                                       ActionType actionType, Object... additionalInfo) {
 | 
			
		||||
        testSendNotificationMsgToEdgeServiceOne(entityId, tenantId, actionType);
 | 
			
		||||
        testLogEntityActionOne(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo);
 | 
			
		||||
        testPushMsgToRuleEngineOne(originatorId, tenantId);
 | 
			
		||||
    protected void testNotifyEntityAllOneTime(HasName entity, EntityId entityId, EntityId originatorId,
 | 
			
		||||
                                              TenantId tenantId, CustomerId customerId, UserId userId, String userName,
 | 
			
		||||
                                              ActionType actionType, Object... additionalInfo) {
 | 
			
		||||
        testSendNotificationMsgToEdgeServiceOneTime(entityId, tenantId, actionType);
 | 
			
		||||
        testLogEntityActionOneTime(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo);
 | 
			
		||||
        testPushMsgToRuleEngineOneTime(originatorId, tenantId);
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void testNotifyEntityDeleteOneMsgToEdgeServiceNever(HasName entity, EntityId entityId, EntityId originatorId,
 | 
			
		||||
                                                                  TenantId tenantId, CustomerId customerId, UserId userId, String userName,
 | 
			
		||||
                                                                  ActionType actionType, Object... additionalInfo) {
 | 
			
		||||
    protected void testNotifyEntityDeleteOneTimeMsgToEdgeServiceNever(HasName entity, EntityId entityId, EntityId originatorId,
 | 
			
		||||
                                                                      TenantId tenantId, CustomerId customerId, UserId userId, String userName,
 | 
			
		||||
                                                                      ActionType actionType, Object... additionalInfo) {
 | 
			
		||||
        testNotificationMsgToEdgeServiceNever(entityId);
 | 
			
		||||
        testLogEntityActionOne(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo);
 | 
			
		||||
        testPushMsgToRuleEngineOne(entityId, tenantId);
 | 
			
		||||
        testBroadcastEntityStateChangeEventOne(entityId, tenantId);
 | 
			
		||||
        testLogEntityActionOneTime(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo);
 | 
			
		||||
        testPushMsgToRuleEngineOneTime(entityId, tenantId);
 | 
			
		||||
        testBroadcastEntityStateChangeEventOneTime(entityId, tenantId);
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void testNotifyEntityOneMsgToEdgeServiceNever(HasName entity, EntityId entityId, EntityId originatorId,
 | 
			
		||||
                                                            TenantId tenantId, CustomerId customerId, UserId userId, String userName,
 | 
			
		||||
                                                            ActionType actionType, Object... additionalInfo) {
 | 
			
		||||
        testNotificationMsgToEdgeServiceNever(entityId);
 | 
			
		||||
        testLogEntityActionOne(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo);
 | 
			
		||||
        testPushMsgToRuleEngineOne(originatorId, tenantId);
 | 
			
		||||
    protected void testNotifyEntityNeverMsgToEdgeServiceOneTime(HasName entity, EntityId entityId, TenantId tenantId, ActionType actionType) {
 | 
			
		||||
        testSendNotificationMsgToEdgeServiceOneTime(entityId, tenantId, actionType);
 | 
			
		||||
        testLogEntityActionNever(entityId, entity);
 | 
			
		||||
        testPushMsgToRuleEngineNever(entityId);
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void testNotifyEntityBroadcastEntityStateChangeEventOneMsgToEdgeServiceNever(HasName entity, EntityId entityId, EntityId originatorId,
 | 
			
		||||
                                                                                           TenantId tenantId, CustomerId customerId, UserId userId, String userName,
 | 
			
		||||
                                                                                           ActionType actionType, Object... additionalInfo) {
 | 
			
		||||
    protected void testNotifyEntityOneTimeMsgToEdgeServiceNever(HasName entity, EntityId entityId, EntityId originatorId,
 | 
			
		||||
                                                                TenantId tenantId, CustomerId customerId, UserId userId, String userName,
 | 
			
		||||
                                                                ActionType actionType, Object... additionalInfo) {
 | 
			
		||||
        testNotificationMsgToEdgeServiceNever(entityId);
 | 
			
		||||
        testLogEntityActionOne(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo);
 | 
			
		||||
        testPushMsgToRuleEngineOne(originatorId, tenantId);
 | 
			
		||||
        testBroadcastEntityStateChangeEventOne(entityId, tenantId);
 | 
			
		||||
        testLogEntityActionOneTime(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo);
 | 
			
		||||
        testPushMsgToRuleEngineOneTime(originatorId, tenantId);
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(HasName entity, EntityId entityId, EntityId originatorId,
 | 
			
		||||
                                                                                               TenantId tenantId, CustomerId customerId, UserId userId, String userName,
 | 
			
		||||
                                                                                               ActionType actionType, Object... additionalInfo) {
 | 
			
		||||
        testNotificationMsgToEdgeServiceNever(entityId);
 | 
			
		||||
        testLogEntityActionOneTime(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo);
 | 
			
		||||
        testPushMsgToRuleEngineOneTime(originatorId, tenantId);
 | 
			
		||||
        testBroadcastEntityStateChangeEventOneTime(entityId, tenantId);
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -107,8 +112,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
 | 
			
		||||
                    Mockito.argThat(argument ->
 | 
			
		||||
                        argument.getMessage().equals(exp.getMessage())));
 | 
			
		||||
        }
 | 
			
		||||
        Mockito.verify(tbClusterService, never()).pushMsgToRuleEngine(Mockito.any(), Mockito.any(entity_NULL_UUID.getClass()),
 | 
			
		||||
                Mockito.any(), Mockito.any());
 | 
			
		||||
        testPushMsgToRuleEngineNever(entity_NULL_UUID);
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -116,26 +120,27 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
 | 
			
		||||
        testNotificationMsgToEdgeServiceNever(entityId);
 | 
			
		||||
        testLogEntityActionNever(entityId, entity);
 | 
			
		||||
        testPushMsgToRuleEngineNever(entityId);
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void testNotificationMsgToEdgeServiceNever(EntityId entityId) {
 | 
			
		||||
    private void testNotificationMsgToEdgeServiceNever(EntityId entityId) {
 | 
			
		||||
        Mockito.verify(tbClusterService, never()).sendNotificationMsgToEdgeService(Mockito.any(),
 | 
			
		||||
                Mockito.any(), Mockito.any(entityId.getClass()), Mockito.any(), Mockito.any(), Mockito.any());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void testLogEntityActionNever(EntityId entityId, HasName entity) {
 | 
			
		||||
    private void testLogEntityActionNever(EntityId entityId, HasName entity) {
 | 
			
		||||
        Mockito.verify(auditLogService, never()).logEntityAction(Mockito.any(), Mockito.any(),
 | 
			
		||||
                Mockito.any(), Mockito.any(), Mockito.any(entityId.getClass()), Mockito.any(entity.getClass()),
 | 
			
		||||
                Mockito.any(), Mockito.any());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void testPushMsgToRuleEngineNever(EntityId entityId) {
 | 
			
		||||
    private void testPushMsgToRuleEngineNever(EntityId entityId) {
 | 
			
		||||
        Mockito.verify(tbClusterService, never()).pushMsgToRuleEngine(Mockito.any(),
 | 
			
		||||
                Mockito.any(entityId.getClass()), Mockito.any(), Mockito.any());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void testLogEntityActionOne(HasName entity, EntityId originatorId, TenantId tenantId, CustomerId customerId,
 | 
			
		||||
                                        UserId userId, String userName, ActionType actionType, Object... additionalInfo) {
 | 
			
		||||
    private void testLogEntityActionOneTime(HasName entity, EntityId originatorId, TenantId tenantId, CustomerId customerId,
 | 
			
		||||
                                            UserId userId, String userName, ActionType actionType, Object... additionalInfo) {
 | 
			
		||||
        if (additionalInfo.length == 0) {
 | 
			
		||||
            Mockito.verify(auditLogService, times(1)).logEntityAction(Mockito.eq(tenantId), Mockito.eq(customerId),
 | 
			
		||||
                    Mockito.eq(userId), Mockito.eq(userName), Mockito.eq(originatorId),
 | 
			
		||||
@ -148,18 +153,18 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void testPushMsgToRuleEngineOne(EntityId originatorId, TenantId tenantId) {
 | 
			
		||||
    private void testPushMsgToRuleEngineOneTime(EntityId originatorId, TenantId tenantId) {
 | 
			
		||||
        Mockito.verify(tbClusterService, times(1)).pushMsgToRuleEngine(Mockito.eq(tenantId),
 | 
			
		||||
                Mockito.eq(originatorId), Mockito.any(TbMsg.class), Mockito.isNull());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void testSendNotificationMsgToEdgeServiceOne(EntityId entityId, TenantId tenantId, ActionType actionType) {
 | 
			
		||||
    private void testSendNotificationMsgToEdgeServiceOneTime(EntityId entityId, TenantId tenantId, ActionType actionType) {
 | 
			
		||||
        Mockito.verify(tbClusterService, times(1)).sendNotificationMsgToEdgeService(Mockito.eq(tenantId),
 | 
			
		||||
                Mockito.isNull(), Mockito.eq(entityId), Mockito.isNull(), Mockito.isNull(),
 | 
			
		||||
                Mockito.eq(edgeTypeByActionType(actionType)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void testBroadcastEntityStateChangeEventOne(EntityId entityId, TenantId tenantId) {
 | 
			
		||||
    private void testBroadcastEntityStateChangeEventOneTime(EntityId entityId, TenantId tenantId) {
 | 
			
		||||
        Mockito.verify(tbClusterService, times(1)).broadcastEntityStateChangeEvent(Mockito.eq(tenantId),
 | 
			
		||||
                Mockito.any(entityId.getClass()), Mockito.any(ComponentLifecycleEvent.class));
 | 
			
		||||
    }
 | 
			
		||||
@ -174,10 +179,4 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String getFailureStack(Exception e) {
 | 
			
		||||
        StringWriter sw = new StringWriter();
 | 
			
		||||
        e.printStackTrace(new PrintWriter(sw));
 | 
			
		||||
        return sw.toString();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -107,6 +107,7 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
 | 
			
		||||
    protected ObjectMapper mapper = new ObjectMapper();
 | 
			
		||||
 | 
			
		||||
    protected static final String TEST_TENANT_NAME = "TEST TENANT";
 | 
			
		||||
    protected static final String TEST_DIFFERENT_TENANT_NAME = "TEST DIFFERENT TENANT";
 | 
			
		||||
 | 
			
		||||
    protected static final String SYS_ADMIN_EMAIL = "sysadmin@thingsboard.org";
 | 
			
		||||
    private static final String SYS_ADMIN_PASSWORD = "sysadmin";
 | 
			
		||||
@ -114,9 +115,15 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
 | 
			
		||||
    protected static final String TENANT_ADMIN_EMAIL = "testtenant@thingsboard.org";
 | 
			
		||||
    protected static final String TENANT_ADMIN_PASSWORD = "tenant";
 | 
			
		||||
 | 
			
		||||
    protected static final String DIFFERENT_TENANT_ADMIN_EMAIL = "testdifftenant@thingsboard.org";
 | 
			
		||||
    private static final String DIFFERENT_TENANT_ADMIN_PASSWORD = "difftenant";
 | 
			
		||||
 | 
			
		||||
    protected static final String CUSTOMER_USER_EMAIL = "testcustomer@thingsboard.org";
 | 
			
		||||
    private static final String CUSTOMER_USER_PASSWORD = "customer";
 | 
			
		||||
 | 
			
		||||
    protected static final String DIFFERENT_CUSTOMER_USER_EMAIL = "testdifferentcustomer@thingsboard.org";
 | 
			
		||||
    private static final String DIFFERENT_CUSTOMER_USER_PASSWORD = "diffcustomer";
 | 
			
		||||
 | 
			
		||||
    /** See {@link org.springframework.test.web.servlet.DefaultMvcResult#getAsyncResult(long)}
 | 
			
		||||
     *  and {@link org.springframework.mock.web.MockAsyncContext#getTimeout()}
 | 
			
		||||
     */
 | 
			
		||||
@ -134,6 +141,8 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
 | 
			
		||||
    protected UserId tenantAdminUserId;
 | 
			
		||||
    protected CustomerId tenantAdminCustomerId;
 | 
			
		||||
    protected CustomerId customerId;
 | 
			
		||||
    protected TenantId differentTenantId;
 | 
			
		||||
    protected CustomerId differentCustomerId;
 | 
			
		||||
    protected UserId customerUserId;
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("rawtypes")
 | 
			
		||||
@ -272,36 +281,52 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
 | 
			
		||||
    private Customer savedDifferentCustomer;
 | 
			
		||||
 | 
			
		||||
    protected void loginDifferentTenant() throws Exception {
 | 
			
		||||
        loginSysAdmin();
 | 
			
		||||
        if (savedDifferentTenant != null) {
 | 
			
		||||
            deleteDifferentTenant();
 | 
			
		||||
            login(savedDifferentTenant.getEmail(), TENANT_ADMIN_PASSWORD);
 | 
			
		||||
        } else {
 | 
			
		||||
            loginSysAdmin();
 | 
			
		||||
 | 
			
		||||
            Tenant tenant = new Tenant();
 | 
			
		||||
            tenant.setTitle(TEST_DIFFERENT_TENANT_NAME);
 | 
			
		||||
            savedDifferentTenant = doPost("/api/tenant", tenant, Tenant.class);
 | 
			
		||||
            differentTenantId = savedDifferentTenant.getId();
 | 
			
		||||
            Assert.assertNotNull(savedDifferentTenant);
 | 
			
		||||
            User differentTenantAdmin = new User();
 | 
			
		||||
            differentTenantAdmin.setAuthority(Authority.TENANT_ADMIN);
 | 
			
		||||
            differentTenantAdmin.setTenantId(savedDifferentTenant.getId());
 | 
			
		||||
            differentTenantAdmin.setEmail(DIFFERENT_TENANT_ADMIN_EMAIL);
 | 
			
		||||
 | 
			
		||||
            createUserAndLogin(differentTenantAdmin, DIFFERENT_TENANT_ADMIN_PASSWORD);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Tenant tenant = new Tenant();
 | 
			
		||||
        tenant.setTitle("Different tenant");
 | 
			
		||||
        savedDifferentTenant = doPost("/api/tenant", tenant, Tenant.class);
 | 
			
		||||
        Assert.assertNotNull(savedDifferentTenant);
 | 
			
		||||
        User differentTenantAdmin = new User();
 | 
			
		||||
        differentTenantAdmin.setAuthority(Authority.TENANT_ADMIN);
 | 
			
		||||
        differentTenantAdmin.setTenantId(savedDifferentTenant.getId());
 | 
			
		||||
        differentTenantAdmin.setEmail("different_tenant@thingsboard.org");
 | 
			
		||||
 | 
			
		||||
        createUserAndLogin(differentTenantAdmin, "testPassword");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void loginDifferentCustomer() throws Exception {
 | 
			
		||||
        if (savedDifferentCustomer != null) {
 | 
			
		||||
            login(savedDifferentCustomer.getEmail(), CUSTOMER_USER_PASSWORD);
 | 
			
		||||
        } else {
 | 
			
		||||
            createDifferentCustomer();
 | 
			
		||||
 | 
			
		||||
            loginTenantAdmin();
 | 
			
		||||
            User differentCustomerUser = new User();
 | 
			
		||||
            differentCustomerUser.setAuthority(Authority.CUSTOMER_USER);
 | 
			
		||||
            differentCustomerUser.setTenantId(tenantId);
 | 
			
		||||
            differentCustomerUser.setCustomerId(savedDifferentCustomer.getId());
 | 
			
		||||
            differentCustomerUser.setEmail(DIFFERENT_CUSTOMER_USER_EMAIL);
 | 
			
		||||
 | 
			
		||||
            createUserAndLogin(differentCustomerUser, DIFFERENT_CUSTOMER_USER_PASSWORD);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void createDifferentCustomer() throws Exception {
 | 
			
		||||
        loginTenantAdmin();
 | 
			
		||||
 | 
			
		||||
        Customer customer = new Customer();
 | 
			
		||||
        customer.setTitle("Different customer");
 | 
			
		||||
        savedDifferentCustomer = doPost("/api/customer", customer, Customer.class);
 | 
			
		||||
        Assert.assertNotNull(savedDifferentCustomer);
 | 
			
		||||
        User differentCustomerUser = new User();
 | 
			
		||||
        differentCustomerUser.setAuthority(Authority.CUSTOMER_USER);
 | 
			
		||||
        differentCustomerUser.setTenantId(tenantId);
 | 
			
		||||
        differentCustomerUser.setCustomerId(savedDifferentCustomer.getId());
 | 
			
		||||
        differentCustomerUser.setEmail("different_customer@thingsboard.org");
 | 
			
		||||
        differentCustomerId = savedDifferentCustomer.getId();
 | 
			
		||||
 | 
			
		||||
        createUserAndLogin(differentCustomerUser, "testPassword");
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void deleteDifferentTenant() throws Exception {
 | 
			
		||||
 | 
			
		||||
@ -15,17 +15,26 @@
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.server.controller;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.core.type.TypeReference;
 | 
			
		||||
import com.fasterxml.jackson.databind.JsonNode;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.junit.After;
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.mockito.Mockito;
 | 
			
		||||
import org.thingsboard.common.util.JacksonUtil;
 | 
			
		||||
import org.thingsboard.server.common.data.Device;
 | 
			
		||||
import org.thingsboard.server.common.data.EntityType;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.Alarm;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.AlarmInfo;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.AlarmStatus;
 | 
			
		||||
import org.thingsboard.server.common.data.audit.ActionType;
 | 
			
		||||
import org.thingsboard.server.common.data.page.PageData;
 | 
			
		||||
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 | 
			
		||||
 | 
			
		||||
@ -65,9 +74,8 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityOne(alarm, alarm.getId(), alarm.getOriginator(),
 | 
			
		||||
        testNotifyEntityAllOneTime(alarm, alarm.getId(), alarm.getOriginator(),
 | 
			
		||||
                tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.ADDED);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
@ -78,15 +86,13 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityOne(alarm, alarm.getId(), alarm.getOriginator(),
 | 
			
		||||
        testNotifyEntityAllOneTime(alarm, alarm.getId(), alarm.getOriginator(),
 | 
			
		||||
                tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ADDED);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testUpdateAlarmViaCustomer() throws Exception {
 | 
			
		||||
        loginCustomerUser();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
@ -96,15 +102,13 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
        Assert.assertNotNull(updatedAlarm);
 | 
			
		||||
        Assert.assertEquals(AlarmSeverity.MAJOR, updatedAlarm.getSeverity());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityOne(alarm, alarm.getId(), alarm.getOriginator(),
 | 
			
		||||
        testNotifyEntityAllOneTime(updatedAlarm, updatedAlarm.getId(), updatedAlarm.getOriginator(),
 | 
			
		||||
                tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.UPDATED);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testUpdateAlarmViaTenant() throws Exception {
 | 
			
		||||
        loginTenantAdmin();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
@ -114,15 +118,13 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
        Assert.assertNotNull(updatedAlarm);
 | 
			
		||||
        Assert.assertEquals(AlarmSeverity.MAJOR, updatedAlarm.getSeverity());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityOne(updatedAlarm, updatedAlarm.getId(), updatedAlarm.getOriginator(),
 | 
			
		||||
        testNotifyEntityAllOneTime(updatedAlarm, updatedAlarm.getId(), updatedAlarm.getOriginator(),
 | 
			
		||||
                tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.UPDATED);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testUpdateAlarmViaDifferentTenant() throws Exception {
 | 
			
		||||
        loginTenantAdmin();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        alarm.setSeverity(AlarmSeverity.MAJOR);
 | 
			
		||||
@ -133,13 +135,11 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
        doPost("/api/alarm", alarm).andExpect(status().isForbidden());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityNever(alarm.getId(), alarm);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testUpdateAlarmViaDifferentCustomer() throws Exception {
 | 
			
		||||
        loginCustomerUser();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        loginDifferentCustomer();
 | 
			
		||||
@ -150,43 +150,37 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
        doPost("/api/alarm", alarm).andExpect(status().isForbidden());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityNever(alarm.getId(), alarm);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteAlarmViaCustomer() throws Exception {
 | 
			
		||||
        loginCustomerUser();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
 | 
			
		||||
        doDelete("/api/alarm/" + alarm.getId()).andExpect(status().isOk());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityOneMsgToEdgeServiceNever(alarm, alarm.getId(), alarm.getOriginator(),
 | 
			
		||||
        testNotifyEntityOneTimeMsgToEdgeServiceNever(alarm, alarm.getId(), alarm.getOriginator(),
 | 
			
		||||
                tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.DELETED);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteAlarmViaTenant() throws Exception {
 | 
			
		||||
        loginTenantAdmin();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
 | 
			
		||||
        doDelete("/api/alarm/" + alarm.getId()).andExpect(status().isOk());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityOneMsgToEdgeServiceNever(alarm, alarm.getId(), alarm.getOriginator(),
 | 
			
		||||
        testNotifyEntityOneTimeMsgToEdgeServiceNever(alarm, alarm.getId(), alarm.getOriginator(),
 | 
			
		||||
                tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.DELETED);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteAlarmViaDifferentTenant() throws Exception {
 | 
			
		||||
        loginTenantAdmin();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        loginDifferentTenant();
 | 
			
		||||
@ -196,14 +190,11 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
        doDelete("/api/alarm/" + alarm.getId()).andExpect(status().isForbidden());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityNever(alarm.getId(), alarm);
 | 
			
		||||
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteAlarmViaAnotherCustomer() throws Exception {
 | 
			
		||||
    public void testDeleteAlarmViaDifferentCustomer() throws Exception {
 | 
			
		||||
        loginCustomerUser();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        loginDifferentCustomer();
 | 
			
		||||
@ -213,14 +204,11 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
        doDelete("/api/alarm/" + alarm.getId()).andExpect(status().isForbidden());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityNever(alarm.getId(), alarm);
 | 
			
		||||
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testClearAlarmViaCustomer() throws Exception {
 | 
			
		||||
        loginCustomerUser();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
@ -231,15 +219,13 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
        Assert.assertNotNull(foundAlarm);
 | 
			
		||||
        Assert.assertEquals(AlarmStatus.CLEARED_UNACK, foundAlarm.getStatus());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityOne(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(),
 | 
			
		||||
        testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(),
 | 
			
		||||
                tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.ALARM_CLEAR);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testClearAlarmViaTenant() throws Exception {
 | 
			
		||||
        loginTenantAdmin();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
@ -249,15 +235,13 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
        Assert.assertNotNull(foundAlarm);
 | 
			
		||||
        Assert.assertEquals(AlarmStatus.CLEARED_UNACK, foundAlarm.getStatus());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityOne(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(),
 | 
			
		||||
        testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(),
 | 
			
		||||
                tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_CLEAR);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testAcknowledgeAlarmViaCustomer() throws Exception {
 | 
			
		||||
        loginCustomerUser();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
@ -268,15 +252,13 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
        Assert.assertNotNull(foundAlarm);
 | 
			
		||||
        Assert.assertEquals(AlarmStatus.ACTIVE_ACK, foundAlarm.getStatus());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityOne(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(),
 | 
			
		||||
        testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(),
 | 
			
		||||
                tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.ALARM_ACK);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testClearAlarmViaDifferentCustomer() throws Exception {
 | 
			
		||||
        loginCustomerUser();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        loginDifferentCustomer();
 | 
			
		||||
@ -286,13 +268,11 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
        doPost("/api/alarm/" + alarm.getId() + "/clear").andExpect(status().isForbidden());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityNever(alarm.getId(), alarm);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testClearAlarmViaDifferentTenant() throws Exception {
 | 
			
		||||
        loginTenantAdmin();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        loginDifferentTenant();
 | 
			
		||||
@ -302,13 +282,11 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
        doPost("/api/alarm/" + alarm.getId() + "/clear").andExpect(status().isForbidden());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityNever(alarm.getId(), alarm);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testAcknowledgeAlarmViaDifferentCustomer() throws Exception {
 | 
			
		||||
        loginCustomerUser();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        loginDifferentCustomer();
 | 
			
		||||
@ -318,13 +296,11 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
        doPost("/api/alarm/" + alarm.getId() + "/ack").andExpect(status().isForbidden());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityNever(alarm.getId(), alarm);
 | 
			
		||||
        logout();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testAcknowledgeAlarmViaDifferentTenant() throws Exception {
 | 
			
		||||
        loginTenantAdmin();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = createAlarm(TEST_ALARM_TYPE);
 | 
			
		||||
 | 
			
		||||
        loginDifferentTenant();
 | 
			
		||||
@ -332,9 +308,99 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
 | 
			
		||||
        doPost("/api/alarm/" + alarm.getId() + "/ack").andExpect(status().isForbidden());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFindAlarmsViaCustomerUser() throws Exception {
 | 
			
		||||
        loginCustomerUser();
 | 
			
		||||
 | 
			
		||||
        List<Alarm> createdAlarms = new LinkedList<>();
 | 
			
		||||
 | 
			
		||||
        final int size = 10;
 | 
			
		||||
        for (int i = 0; i < size; i++) {
 | 
			
		||||
            createdAlarms.add(
 | 
			
		||||
                    createAlarm(TEST_ALARM_TYPE + i)
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var response = doGetTyped(
 | 
			
		||||
                "/api/alarm/" + EntityType.DEVICE + "/"
 | 
			
		||||
                        + customerDevice.getUuidId() + "?page=0&pageSize=" + size,
 | 
			
		||||
                new TypeReference<PageData<AlarmInfo>>() {}
 | 
			
		||||
        );
 | 
			
		||||
        var foundAlarmInfos = response.getData();
 | 
			
		||||
        Assert.assertNotNull("Found pageData is null", foundAlarmInfos);
 | 
			
		||||
        Assert.assertNotEquals(
 | 
			
		||||
                "Expected alarms are not found!",
 | 
			
		||||
                0, foundAlarmInfos.size()
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        boolean allMatch = createdAlarms.stream()
 | 
			
		||||
                .allMatch(alarm -> foundAlarmInfos.stream()
 | 
			
		||||
                        .map(Alarm::getType)
 | 
			
		||||
                        .anyMatch(type -> alarm.getType().equals(type))
 | 
			
		||||
                );
 | 
			
		||||
        Assert.assertTrue("Created alarm doesn't match any found!", allMatch);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFindAlarmsViaDifferentCustomerUser() throws Exception {
 | 
			
		||||
        loginCustomerUser();
 | 
			
		||||
 | 
			
		||||
        final int size = 10;
 | 
			
		||||
        for (int i = 0; i < size; i++) {
 | 
			
		||||
            createAlarm(TEST_ALARM_TYPE + i);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        loginDifferentCustomer();
 | 
			
		||||
        doGet("/api/alarm/" + EntityType.DEVICE + "/"
 | 
			
		||||
                + customerDevice.getUuidId() + "?page=0&pageSize=" + size)
 | 
			
		||||
                .andExpect(status().isForbidden());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFindAlarmsViaPublicCustomer() throws Exception {
 | 
			
		||||
        loginTenantAdmin();
 | 
			
		||||
 | 
			
		||||
        Device device = new Device();
 | 
			
		||||
        device.setName("Test Public Device");
 | 
			
		||||
        device.setLabel("Label");
 | 
			
		||||
        device.setCustomerId(customerId);
 | 
			
		||||
        device = doPost("/api/device", device, Device.class);
 | 
			
		||||
        device = doPost("/api/customer/public/device/" + device.getUuidId(), Device.class);
 | 
			
		||||
 | 
			
		||||
        String publicId = device.getCustomerId().toString();
 | 
			
		||||
 | 
			
		||||
        Alarm alarm = Alarm.builder()
 | 
			
		||||
                .originator(device.getId())
 | 
			
		||||
                .status(AlarmStatus.ACTIVE_UNACK)
 | 
			
		||||
                .severity(AlarmSeverity.CRITICAL)
 | 
			
		||||
                .type("Test")
 | 
			
		||||
                .build();
 | 
			
		||||
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
 | 
			
		||||
        alarm = doPost("/api/alarm", alarm, Alarm.class);
 | 
			
		||||
        Assert.assertNotNull("Saved alarm is null!", alarm);
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityNeverMsgToEdgeServiceOneTime(alarm, alarm.getId(), tenantId, ActionType.ADDED);
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityNever(alarm.getId(), alarm);
 | 
			
		||||
        logout();
 | 
			
		||||
 | 
			
		||||
        JsonNode publicLoginRequest = JacksonUtil.toJsonNode("{\"publicId\": \"" + publicId + "\"}");
 | 
			
		||||
        JsonNode tokens = doPost("/api/auth/login/public", publicLoginRequest, JsonNode.class);
 | 
			
		||||
        this.token = tokens.get("token").asText();
 | 
			
		||||
 | 
			
		||||
        PageData<AlarmInfo> pageData = doGetTyped(
 | 
			
		||||
                "/api/alarm/DEVICE/" + device.getUuidId() + "?page=0&pageSize=1", new TypeReference<PageData<AlarmInfo>>() {}
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        Assert.assertNotNull("Found pageData is null", pageData);
 | 
			
		||||
        Assert.assertNotEquals("Expected alarms are not found!", 0, pageData.getTotalElements());
 | 
			
		||||
 | 
			
		||||
        AlarmInfo alarmInfo = pageData.getData().get(0);
 | 
			
		||||
        boolean equals = alarm.getId().equals(alarmInfo.getId()) && alarm.getType().equals(alarmInfo.getType());
 | 
			
		||||
        Assert.assertTrue("Created alarm doesn't match the found one!", equals);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Alarm createAlarm(String type) throws Exception {
 | 
			
		||||
@ -346,8 +412,10 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
 | 
			
		||||
                .severity(AlarmSeverity.CRITICAL)
 | 
			
		||||
                .type(type)
 | 
			
		||||
                .build();
 | 
			
		||||
 | 
			
		||||
        alarm = doPost("/api/alarm", alarm, Alarm.class);
 | 
			
		||||
        Assert.assertNotNull(alarm);
 | 
			
		||||
 | 
			
		||||
        return alarm;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -94,7 +94,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
 | 
			
		||||
 | 
			
		||||
        Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityOneMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(), savedCustomer.getId(),
 | 
			
		||||
        testNotifyEntityOneTimeMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(), savedCustomer.getId(),
 | 
			
		||||
                savedCustomer.getTenantId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
 | 
			
		||||
                ActionType.ADDED);
 | 
			
		||||
 | 
			
		||||
@ -103,14 +103,11 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
 | 
			
		||||
        Assert.assertTrue(savedCustomer.getCreatedTime() > 0);
 | 
			
		||||
        Assert.assertEquals(customer.getTitle(), savedCustomer.getTitle());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        savedCustomer.setTitle("My new customer");
 | 
			
		||||
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
 | 
			
		||||
        doPost("/api/customer", savedCustomer, Customer.class);
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityOne(savedCustomer, savedCustomer.getId(), savedCustomer.getId(), savedCustomer.getTenantId(),
 | 
			
		||||
        testNotifyEntityAllOneTime(savedCustomer, savedCustomer.getId(), savedCustomer.getId(), savedCustomer.getTenantId(),
 | 
			
		||||
                savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
 | 
			
		||||
                ActionType.UPDATED);
 | 
			
		||||
 | 
			
		||||
@ -119,10 +116,6 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
 | 
			
		||||
 | 
			
		||||
        doDelete("/api/customer/" + savedCustomer.getId().getId().toString())
 | 
			
		||||
                .andExpect(status().isOk());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityBroadcastEntityStateChangeEventOneMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(),
 | 
			
		||||
                savedCustomer.getId(), savedCustomer.getTenantId(), savedCustomer.getId(), tenantAdmin.getId(),
 | 
			
		||||
                tenantAdmin.getEmail(), ActionType.DELETED, savedCustomer.getId().getId().toString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
@ -199,14 +192,12 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
 | 
			
		||||
        deleteDifferentTenant();
 | 
			
		||||
        login(tenantAdmin.getName(), "testPassword1");
 | 
			
		||||
 | 
			
		||||
        Mockito.reset(tbClusterService, auditLogService);
 | 
			
		||||
 | 
			
		||||
        doDelete("/api/customer/" + savedCustomer.getId().getId().toString())
 | 
			
		||||
                .andExpect(status().isOk());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityDeleteOneMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(), savedCustomer.getId(),
 | 
			
		||||
                savedCustomer.getTenantId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
 | 
			
		||||
                ActionType.DELETED, savedCustomer.getId().getId().toString());
 | 
			
		||||
        testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(),
 | 
			
		||||
                savedCustomer.getId(), savedCustomer.getTenantId(), savedCustomer.getId(), tenantAdmin.getId(),
 | 
			
		||||
                tenantAdmin.getEmail(), ActionType.DELETED, savedCustomer.getId().getId().toString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
@ -223,10 +214,6 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
 | 
			
		||||
 | 
			
		||||
        doDelete("/api/customer/" + savedCustomer.getId().getId().toString())
 | 
			
		||||
                .andExpect(status().isOk());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityBroadcastEntityStateChangeEventOneMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(),
 | 
			
		||||
                savedCustomer.getId(), savedCustomer.getTenantId(), savedCustomer.getId(), tenantAdmin.getId(),
 | 
			
		||||
                tenantAdmin.getEmail(), ActionType.DELETED, savedCustomer.getId().getId().toString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
@ -240,7 +227,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
 | 
			
		||||
        doDelete("/api/customer/" + savedCustomer.getId().getId().toString())
 | 
			
		||||
                .andExpect(status().isOk());
 | 
			
		||||
 | 
			
		||||
        testNotifyEntityBroadcastEntityStateChangeEventOneMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(),
 | 
			
		||||
        testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(),
 | 
			
		||||
                savedCustomer.getId(), savedCustomer.getTenantId(), savedCustomer.getId(), tenantAdmin.getId(),
 | 
			
		||||
                tenantAdmin.getEmail(), ActionType.DELETED, savedCustomer.getId().getId().toString());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -12,20 +12,19 @@
 | 
			
		||||
    "start-prod": "NODE_ENV=production nodemon server.js"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@azure/service-bus": "^1.1.9",
 | 
			
		||||
    "@google-cloud/pubsub": "^2.5.0",
 | 
			
		||||
    "amqplib": "^0.6.0",
 | 
			
		||||
    "aws-sdk": "^2.741.0",
 | 
			
		||||
    "azure-sb": "^0.11.1",
 | 
			
		||||
    "config": "^3.3.1",
 | 
			
		||||
    "express": "^4.17.1",
 | 
			
		||||
    "js-yaml": "^3.14.0",
 | 
			
		||||
    "kafkajs": "^1.15.0",
 | 
			
		||||
    "long": "^4.0.0",
 | 
			
		||||
    "@azure/service-bus": "^7.5.1",
 | 
			
		||||
    "@google-cloud/pubsub": "^3.0.1",
 | 
			
		||||
    "amqplib": "^0.10.0",
 | 
			
		||||
    "aws-sdk": "^2.1152.0",
 | 
			
		||||
    "config": "^3.3.7",
 | 
			
		||||
    "express": "^4.18.1",
 | 
			
		||||
    "js-yaml": "^4.1.0",
 | 
			
		||||
    "kafkajs": "^2.0.2",
 | 
			
		||||
    "long": "^5.2.0",
 | 
			
		||||
    "uuid-parse": "^1.1.0",
 | 
			
		||||
    "uuid-random": "^1.3.2",
 | 
			
		||||
    "winston": "^3.3.3",
 | 
			
		||||
    "winston-daily-rotate-file": "^4.5.0"
 | 
			
		||||
    "winston": "^3.7.2",
 | 
			
		||||
    "winston-daily-rotate-file": "^4.7.1"
 | 
			
		||||
  },
 | 
			
		||||
  "nyc": {
 | 
			
		||||
    "exclude": [
 | 
			
		||||
@ -36,13 +35,19 @@
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "fs-extra": "^10.0.0",
 | 
			
		||||
    "nodemon": "^2.0.12",
 | 
			
		||||
    "pkg": "^5.3.1"
 | 
			
		||||
    "fs-extra": "^10.1.0",
 | 
			
		||||
    "nodemon": "^2.0.16",
 | 
			
		||||
    "pkg": "^5.7.0"
 | 
			
		||||
  },
 | 
			
		||||
  "pkg": {
 | 
			
		||||
    "assets": [
 | 
			
		||||
      "node_modules/config/**/*.*"
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  "resolutions": {
 | 
			
		||||
    "ansi-regex": "^5.0.1",
 | 
			
		||||
    "color-string": "^1.5.5",
 | 
			
		||||
    "minimist": "^1.2.6",
 | 
			
		||||
    "node-fetch": "^2.6.7"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -71,8 +71,8 @@
 | 
			
		||||
                            <goal>install-node-and-yarn</goal>
 | 
			
		||||
                        </goals>
 | 
			
		||||
                        <configuration>
 | 
			
		||||
                            <nodeVersion>v12.16.1</nodeVersion>
 | 
			
		||||
                            <yarnVersion>v1.22.4</yarnVersion>
 | 
			
		||||
                            <nodeVersion>v16.13.1</nodeVersion>
 | 
			
		||||
                            <yarnVersion>v1.22.17</yarnVersion>
 | 
			
		||||
                        </configuration>
 | 
			
		||||
                    </execution>
 | 
			
		||||
                    <execution>
 | 
			
		||||
 | 
			
		||||
@ -18,8 +18,7 @@
 | 
			
		||||
const config = require('config'),
 | 
			
		||||
    JsInvokeMessageProcessor = require('../api/jsInvokeMessageProcessor'),
 | 
			
		||||
    logger = require('../config/logger')._logger('serviceBusTemplate');
 | 
			
		||||
const {ServiceBusClient, ReceiveMode} = require("@azure/service-bus");
 | 
			
		||||
const azure = require('azure-sb');
 | 
			
		||||
const {ServiceBusClient, ServiceBusAdministrationClient} = require("@azure/service-bus");
 | 
			
		||||
 | 
			
		||||
const requestTopic = config.get('request_topic');
 | 
			
		||||
const namespaceName = config.get('service_bus.namespace_name');
 | 
			
		||||
@ -28,7 +27,6 @@ const sasKey = config.get('service_bus.sas_key');
 | 
			
		||||
const queueProperties = config.get('service_bus.queue_properties');
 | 
			
		||||
 | 
			
		||||
let sbClient;
 | 
			
		||||
let receiverClient;
 | 
			
		||||
let receiver;
 | 
			
		||||
let serviceBusService;
 | 
			
		||||
 | 
			
		||||
@ -61,11 +59,10 @@ function ServiceBusProducer() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function CustomSender(topic) {
 | 
			
		||||
    this.queueClient = sbClient.createQueueClient(topic);
 | 
			
		||||
    this.sender = this.queueClient.createSender();
 | 
			
		||||
    this.sender = sbClient.createSender(topic);
 | 
			
		||||
 | 
			
		||||
    this.send = async (message) => {
 | 
			
		||||
        return this.sender.send(message);
 | 
			
		||||
        return this.sender.sendMessages(message);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -74,8 +71,8 @@ function CustomSender(topic) {
 | 
			
		||||
        logger.info('Starting ThingsBoard JavaScript Executor Microservice...');
 | 
			
		||||
 | 
			
		||||
        const connectionString = `Endpoint=sb://${namespaceName}.servicebus.windows.net/;SharedAccessKeyName=${sasKeyName};SharedAccessKey=${sasKey}`;
 | 
			
		||||
        sbClient = ServiceBusClient.createFromConnectionString(connectionString);
 | 
			
		||||
        serviceBusService = azure.createServiceBusService(connectionString);
 | 
			
		||||
        sbClient = new ServiceBusClient(connectionString)
 | 
			
		||||
        serviceBusService = new ServiceBusAdministrationClient(connectionString);
 | 
			
		||||
 | 
			
		||||
        parseQueueProperties();
 | 
			
		||||
 | 
			
		||||
@ -84,9 +81,9 @@ function CustomSender(topic) {
 | 
			
		||||
                if (err) {
 | 
			
		||||
                    reject(err);
 | 
			
		||||
                } else {
 | 
			
		||||
                    data.forEach(queue => {
 | 
			
		||||
                        queues.push(queue.QueueName);
 | 
			
		||||
                    });
 | 
			
		||||
                    for (const queue of data) {
 | 
			
		||||
                        queues.push(queue.name);
 | 
			
		||||
                    }
 | 
			
		||||
                    resolve();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
@ -97,8 +94,7 @@ function CustomSender(topic) {
 | 
			
		||||
            queues.push(requestTopic);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        receiverClient = sbClient.createQueueClient(requestTopic);
 | 
			
		||||
        receiver = receiverClient.createReceiver(ReceiveMode.peekLock);
 | 
			
		||||
        receiver = sbClient.createReceiver(requestTopic, {receiveMode: 'peekLock'});
 | 
			
		||||
 | 
			
		||||
        const messageProcessor = new JsInvokeMessageProcessor(new ServiceBusProducer());
 | 
			
		||||
 | 
			
		||||
@ -111,18 +107,18 @@ function CustomSender(topic) {
 | 
			
		||||
        const errorHandler = (error) => {
 | 
			
		||||
            logger.error('Failed to receive message from queue.', error);
 | 
			
		||||
        };
 | 
			
		||||
        receiver.registerMessageHandler(messageHandler, errorHandler);
 | 
			
		||||
        receiver.subscribe({processMessage: messageHandler, processError: errorHandler})
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        logger.error('Failed to start ThingsBoard JavaScript Executor Microservice: %s', e.message);
 | 
			
		||||
        logger.error(e.stack);
 | 
			
		||||
        exit(-1);
 | 
			
		||||
        await exit(-1);
 | 
			
		||||
    }
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
async function createQueueIfNotExist(topic) {
 | 
			
		||||
    return new Promise((resolve, reject) => {
 | 
			
		||||
        serviceBusService.createQueueIfNotExists(topic, queueOptions, (err) => {
 | 
			
		||||
            if (err) {
 | 
			
		||||
        serviceBusService.createQueue(topic, queueOptions, (err) => {
 | 
			
		||||
            if (err && err.code !== "MessageEntityAlreadyExistsError") {
 | 
			
		||||
                reject(err);
 | 
			
		||||
            } else {
 | 
			
		||||
                resolve();
 | 
			
		||||
@ -139,10 +135,10 @@ function parseQueueProperties() {
 | 
			
		||||
        properties[p.substring(0, delimiterPosition)] = p.substring(delimiterPosition + 1);
 | 
			
		||||
    });
 | 
			
		||||
    queueOptions = {
 | 
			
		||||
        DuplicateDetection: 'false',
 | 
			
		||||
        MaxSizeInMegabytes: properties['maxSizeInMb'],
 | 
			
		||||
        DefaultMessageTimeToLive: `PT${properties['messageTimeToLiveInSec']}S`,
 | 
			
		||||
        LockDuration: `PT${properties['lockDurationInSec']}S`
 | 
			
		||||
        requiresDuplicateDetection: false,
 | 
			
		||||
        maxSizeInMegabytes: properties['maxSizeInMb'],
 | 
			
		||||
        defaultMessageTimeToLive: `PT${properties['messageTimeToLiveInSec']}S`,
 | 
			
		||||
        lockDuration: `PT${properties['lockDurationInSec']}S`
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -161,24 +157,11 @@ async function exit(status) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (receiverClient) {
 | 
			
		||||
        try {
 | 
			
		||||
            await receiverClient.close();
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    senderMap.forEach((k, v) => {
 | 
			
		||||
        try {
 | 
			
		||||
            v.sender.close();
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        try {
 | 
			
		||||
            v.queueClient.close();
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@ -191,4 +174,4 @@ async function exit(status) {
 | 
			
		||||
    }
 | 
			
		||||
    logger.info('Azure Service Bus resources stopped.')
 | 
			
		||||
    process.exit(status);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -13,14 +13,14 @@
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "compression": "^1.7.4",
 | 
			
		||||
    "config": "^3.3.1",
 | 
			
		||||
    "config": "^3.3.7",
 | 
			
		||||
    "connect-history-api-fallback": "^1.6.0",
 | 
			
		||||
    "express": "^4.17.1",
 | 
			
		||||
    "express": "^4.18.1",
 | 
			
		||||
    "http": "0.0.0",
 | 
			
		||||
    "http-proxy": "^1.18.1",
 | 
			
		||||
    "js-yaml": "^3.14.0",
 | 
			
		||||
    "winston": "^3.3.3",
 | 
			
		||||
    "winston-daily-rotate-file": "^4.5.0"
 | 
			
		||||
    "js-yaml": "^4.1.0",
 | 
			
		||||
    "winston": "^3.7.2",
 | 
			
		||||
    "winston-daily-rotate-file": "^4.7.1"
 | 
			
		||||
  },
 | 
			
		||||
  "nyc": {
 | 
			
		||||
    "exclude": [
 | 
			
		||||
@ -31,13 +31,18 @@
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "fs-extra": "^10.0.0",
 | 
			
		||||
    "nodemon": "^2.0.12",
 | 
			
		||||
    "pkg": "^5.3.1"
 | 
			
		||||
    "fs-extra": "^10.1.0",
 | 
			
		||||
    "nodemon": "^2.0.16",
 | 
			
		||||
    "pkg": "^5.7.0"
 | 
			
		||||
  },
 | 
			
		||||
  "pkg": {
 | 
			
		||||
    "assets": [
 | 
			
		||||
      "node_modules/config/**/*.*"
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  "resolutions": {
 | 
			
		||||
    "color-string": "^1.5.5",
 | 
			
		||||
    "follow-redirects": "^1.14.8",
 | 
			
		||||
    "minimist": "^1.2.6"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -80,8 +80,8 @@
 | 
			
		||||
                            <goal>install-node-and-yarn</goal>
 | 
			
		||||
                        </goals>
 | 
			
		||||
                        <configuration>
 | 
			
		||||
                            <nodeVersion>v12.16.1</nodeVersion>
 | 
			
		||||
                            <yarnVersion>v1.22.4</yarnVersion>
 | 
			
		||||
                            <nodeVersion>v16.13.1</nodeVersion>
 | 
			
		||||
                            <yarnVersion>v1.22.17</yarnVersion>
 | 
			
		||||
                        </configuration>
 | 
			
		||||
                    </execution>
 | 
			
		||||
                    <execution>
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -62,6 +62,7 @@
 | 
			
		||||
    "leaflet-providers": "^1.13.0",
 | 
			
		||||
    "leaflet.gridlayer.googlemutant": "^0.13.4",
 | 
			
		||||
    "leaflet.markercluster": "^1.5.3",
 | 
			
		||||
    "libphonenumber-js": "^1.10.4",
 | 
			
		||||
    "messageformat": "^2.3.0",
 | 
			
		||||
    "moment": "^2.29.1",
 | 
			
		||||
    "moment-timezone": "^0.5.34",
 | 
			
		||||
 | 
			
		||||
@ -30,17 +30,11 @@
 | 
			
		||||
  <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
 | 
			
		||||
  <div mat-dialog-content tb-toast toastTarget="sendTestSmsDialogContent">
 | 
			
		||||
    <fieldset [disabled]="(isLoading$ | async)">
 | 
			
		||||
      <mat-form-field class="mat-block">
 | 
			
		||||
        <mat-label translate>admin.number-to</mat-label>
 | 
			
		||||
        <input type="tel" required [pattern]="phoneNumberPattern" matInput formControlName="numberTo">
 | 
			
		||||
        <mat-error *ngIf="sendTestSmsFormGroup.get('numberTo').hasError('required')">
 | 
			
		||||
          {{ 'admin.number-to-required' | translate }}
 | 
			
		||||
        </mat-error>
 | 
			
		||||
        <mat-error *ngIf="sendTestSmsFormGroup.get('numberTo').hasError('pattern')">
 | 
			
		||||
          {{ 'admin.phone-number-pattern' | translate }}
 | 
			
		||||
        </mat-error>
 | 
			
		||||
        <mat-hint innerHTML="{{ 'admin.phone-number-hint' | translate }}"></mat-hint>
 | 
			
		||||
      </mat-form-field>
 | 
			
		||||
      <tb-phone-input required
 | 
			
		||||
                      formControlName="numberTo"
 | 
			
		||||
                      [enableFlagsSelect]="false"
 | 
			
		||||
                      [label]="'admin.number-to'">
 | 
			
		||||
      </tb-phone-input>
 | 
			
		||||
      <mat-form-field class="mat-block">
 | 
			
		||||
        <mat-label translate>admin.sms-message</mat-label>
 | 
			
		||||
        <textarea required matInput rows="3" [maxLength]="1600" formControlName="message"></textarea>
 | 
			
		||||
 | 
			
		||||
@ -36,21 +36,12 @@
 | 
			
		||||
      <ng-template matStepLabel>{{ 'security.2fa.dialog.sms-step-label' | translate }}</ng-template>
 | 
			
		||||
      <form [formGroup]="smsConfigForm" (ngSubmit)="nextStep()">
 | 
			
		||||
        <p class="mat-body step-description input" translate>security.2fa.dialog.sms-step-description</p>
 | 
			
		||||
        <div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="8px">
 | 
			
		||||
          <mat-form-field  fxFlex class="mat-block input-container" floatLabel="always" hideRequiredMarker>
 | 
			
		||||
            <mat-label></mat-label>
 | 
			
		||||
            <input type="tel" required
 | 
			
		||||
                   [pattern]="phoneNumberPattern"
 | 
			
		||||
                   matInput formControlName="phone"
 | 
			
		||||
                   placeholder="{{ 'security.2fa.dialog.sms-step-label' | translate }}">
 | 
			
		||||
            <mat-error *ngIf="smsConfigForm.get('phone').hasError('required')">
 | 
			
		||||
              {{ 'admin.number-to-required' | translate }}
 | 
			
		||||
            </mat-error>
 | 
			
		||||
            <mat-error *ngIf="smsConfigForm.get('phone').hasError('pattern')">
 | 
			
		||||
              {{ 'admin.phone-number-pattern' | translate }}
 | 
			
		||||
            </mat-error>
 | 
			
		||||
            <mat-hint innerHTML="{{ 'admin.phone-number-hint' | translate }}"></mat-hint>
 | 
			
		||||
          </mat-form-field>
 | 
			
		||||
        <div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="15px">
 | 
			
		||||
          <tb-phone-input fxFlex
 | 
			
		||||
                          formControlName="phone"
 | 
			
		||||
                          [floatLabel]="'never'"
 | 
			
		||||
                          [placeholder]="'security.2fa.dialog.sms-step-label'">
 | 
			
		||||
          </tb-phone-input>
 | 
			
		||||
          <button mat-raised-button
 | 
			
		||||
                  type="submit"
 | 
			
		||||
                  color="primary"
 | 
			
		||||
 | 
			
		||||
@ -55,13 +55,11 @@
 | 
			
		||||
    <mat-label translate>contact.address2</mat-label>
 | 
			
		||||
    <input matInput formControlName="address2">
 | 
			
		||||
  </mat-form-field>
 | 
			
		||||
  <mat-form-field class="mat-block">
 | 
			
		||||
    <mat-label translate>contact.phone</mat-label>
 | 
			
		||||
    <input matInput formControlName="phone">
 | 
			
		||||
    <mat-error *ngIf="parentForm.get('phone').hasError('maxlength')">
 | 
			
		||||
      {{ 'contact.phone-max-length' | translate }}
 | 
			
		||||
    </mat-error>
 | 
			
		||||
  </mat-form-field>
 | 
			
		||||
  <tb-phone-input [required]="false"
 | 
			
		||||
                  [label]="'contact.phone'"
 | 
			
		||||
                  [enableFlagsSelect]="false"
 | 
			
		||||
                  formControlName="phone">
 | 
			
		||||
  </tb-phone-input>
 | 
			
		||||
  <mat-form-field class="mat-block">
 | 
			
		||||
    <mat-label translate>contact.email</mat-label>
 | 
			
		||||
    <input matInput formControlName="email">
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										50
									
								
								ui-ngx/src/app/shared/components/phone-input.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								ui-ngx/src/app/shared/components/phone-input.component.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
			
		||||
<!--
 | 
			
		||||
 | 
			
		||||
    Copyright © 2016-2022 The Thingsboard Authors
 | 
			
		||||
 | 
			
		||||
    Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
    you may not use this file except in compliance with the License.
 | 
			
		||||
    You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
    Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
    distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
    See the License for the specific language governing permissions and
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<form [formGroup]="phoneFormGroup">
 | 
			
		||||
  <div class="phone-input-container">
 | 
			
		||||
    <div class="flags-select-container" *ngIf="enableFlagsSelect">
 | 
			
		||||
      <span class="flag-container">{{ flagIcon }}</span>
 | 
			
		||||
      <mat-select class="country-select" formControlName="country">
 | 
			
		||||
        <mat-option *ngFor="let country of allCountries" [value]="country.iso2">
 | 
			
		||||
          <span style="font-size: 20px;">{{country.flag}}</span>
 | 
			
		||||
          <span>{{' ' + country.name + ' +' + country.dialCode }}</span>
 | 
			
		||||
        </mat-option>
 | 
			
		||||
      </mat-select>
 | 
			
		||||
    </div>
 | 
			
		||||
    <mat-form-field class="phone-input" [appearance]="appearance" [floatLabel]="floatLabel">
 | 
			
		||||
      <mat-label>{{ label | translate }}</mat-label>
 | 
			
		||||
      <input
 | 
			
		||||
        formControlName="phoneNumber"
 | 
			
		||||
        type="tel"
 | 
			
		||||
        matInput
 | 
			
		||||
        placeholder="{{ placeholder | translate }}"
 | 
			
		||||
        [pattern]="phoneNumberPattern"
 | 
			
		||||
        (focus)="focus()"
 | 
			
		||||
        autocomplete="off"
 | 
			
		||||
        [required]="required">
 | 
			
		||||
      <mat-hint innerHTML="{{ 'phone-input.phone-input-hint' | translate: {phoneNumber: phonePlaceholder} }}"></mat-hint>
 | 
			
		||||
      <mat-error *ngIf="phoneFormGroup.get('phoneNumber').hasError('required')">
 | 
			
		||||
        {{ 'phone-input.phone-input-required' | translate }}
 | 
			
		||||
      </mat-error>
 | 
			
		||||
      <mat-error *ngIf="phoneFormGroup.get('phoneNumber').hasError('invalidPhoneNumber')">
 | 
			
		||||
        {{ 'phone-input.phone-input-validation' | translate }}
 | 
			
		||||
      </mat-error>
 | 
			
		||||
    </mat-form-field>
 | 
			
		||||
  </div>
 | 
			
		||||
</form>
 | 
			
		||||
							
								
								
									
										55
									
								
								ui-ngx/src/app/shared/components/phone-input.component.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								ui-ngx/src/app/shared/components/phone-input.component.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2022 The Thingsboard Authors
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
:host ::ng-deep {
 | 
			
		||||
 | 
			
		||||
  .phone-input-container {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
 | 
			
		||||
    .phone-input {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .flags-select-container {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    width: 50px;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    margin-right: 5px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .flag-container {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    font-size: 20px;
 | 
			
		||||
    top: 50%;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    transform: translate(0, -50%);
 | 
			
		||||
  }
 | 
			
		||||
  .country-select {
 | 
			
		||||
    width: 45px;
 | 
			
		||||
    height: 30px;
 | 
			
		||||
 | 
			
		||||
    .mat-select-trigger {
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .mat-select-value {
 | 
			
		||||
      visibility: hidden;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										222
									
								
								ui-ngx/src/app/shared/components/phone-input.component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								ui-ngx/src/app/shared/components/phone-input.component.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,222 @@
 | 
			
		||||
///
 | 
			
		||||
/// Copyright © 2016-2022 The Thingsboard Authors
 | 
			
		||||
///
 | 
			
		||||
/// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
/// you may not use this file except in compliance with the License.
 | 
			
		||||
/// You may obtain a copy of the License at
 | 
			
		||||
///
 | 
			
		||||
///     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
///
 | 
			
		||||
/// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
/// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
/// See the License for the specific language governing permissions and
 | 
			
		||||
/// limitations under the License.
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
import { Component, forwardRef, Input, OnInit } from '@angular/core';
 | 
			
		||||
import {
 | 
			
		||||
  ControlValueAccessor,
 | 
			
		||||
  FormBuilder,
 | 
			
		||||
  FormControl,
 | 
			
		||||
  FormGroup,
 | 
			
		||||
  NG_VALIDATORS,
 | 
			
		||||
  NG_VALUE_ACCESSOR,
 | 
			
		||||
  ValidationErrors,
 | 
			
		||||
  Validator,
 | 
			
		||||
  ValidatorFn,
 | 
			
		||||
  Validators
 | 
			
		||||
} from '@angular/forms';
 | 
			
		||||
import { TranslateService } from '@ngx-translate/core';
 | 
			
		||||
import { Country, CountryData } from '@shared/models/country.models';
 | 
			
		||||
import examples from 'libphonenumber-js/examples.mobile.json';
 | 
			
		||||
import { CountryCode, getExampleNumber, parsePhoneNumberFromString } from 'libphonenumber-js';
 | 
			
		||||
import { phoneNumberPattern } from '@shared/models/settings.models';
 | 
			
		||||
import { Subscription } from 'rxjs';
 | 
			
		||||
import { FloatLabelType, MatFormFieldAppearance } from '@angular/material/form-field/form-field';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-phone-input',
 | 
			
		||||
  templateUrl: './phone-input.component.html',
 | 
			
		||||
  styleUrls: ['./phone-input.component.scss'],
 | 
			
		||||
  providers: [
 | 
			
		||||
    CountryData,
 | 
			
		||||
    {
 | 
			
		||||
      provide: NG_VALUE_ACCESSOR,
 | 
			
		||||
      useExisting: forwardRef(() => PhoneInputComponent),
 | 
			
		||||
      multi: true
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      provide: NG_VALIDATORS,
 | 
			
		||||
      useExisting: forwardRef(() => PhoneInputComponent),
 | 
			
		||||
      multi: true
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class PhoneInputComponent implements OnInit, ControlValueAccessor, Validator {
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  disabled: boolean;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  defaultCountry: CountryCode = 'US';
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  enableFlagsSelect = true;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  required = true;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  floatLabel: FloatLabelType = 'auto';
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  appearance: MatFormFieldAppearance = 'legacy';
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  placeholder;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  label = 'phone-input.phone-input-label';
 | 
			
		||||
 | 
			
		||||
  allCountries: Array<Country> = this.countryCodeData.allCountries;
 | 
			
		||||
  phonePlaceholder: string;
 | 
			
		||||
  flagIcon: string;
 | 
			
		||||
  phoneFormGroup: FormGroup;
 | 
			
		||||
  phoneNumberPattern = phoneNumberPattern;
 | 
			
		||||
 | 
			
		||||
  private baseCode = 127397;
 | 
			
		||||
  private countryCallingCode: string;
 | 
			
		||||
  private modelValue: string;
 | 
			
		||||
  private valueChange$: Subscription = null;
 | 
			
		||||
  private propagateChange = (v: any) => { };
 | 
			
		||||
 | 
			
		||||
  constructor(private translate: TranslateService,
 | 
			
		||||
              private fb: FormBuilder,
 | 
			
		||||
              private countryCodeData: CountryData) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    const validators: ValidatorFn[] = [Validators.pattern(phoneNumberPattern), this.validatePhoneNumber()];
 | 
			
		||||
    if (this.required) {
 | 
			
		||||
      validators.push(Validators.required);
 | 
			
		||||
    }
 | 
			
		||||
    this.phoneFormGroup = this.fb.group({
 | 
			
		||||
      country: [this.defaultCountry, []],
 | 
			
		||||
      phoneNumber: [null, validators]
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.valueChange$ = this.phoneFormGroup.get('phoneNumber').valueChanges.subscribe(value => {
 | 
			
		||||
      this.updateModel();
 | 
			
		||||
      if (value) {
 | 
			
		||||
        const parsedPhoneNumber = parsePhoneNumberFromString(value);
 | 
			
		||||
        const country = this.phoneFormGroup.get('country').value;
 | 
			
		||||
        if (parsedPhoneNumber?.country && parsedPhoneNumber?.country !== country) {
 | 
			
		||||
          this.phoneFormGroup.get('country').patchValue(parsedPhoneNumber.country, {emitEvent: true});
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.phoneFormGroup.get('country').valueChanges.subscribe(value => {
 | 
			
		||||
      if (value) {
 | 
			
		||||
        const code = this.countryCallingCode;
 | 
			
		||||
        this.getFlagAndPhoneNumberData(value);
 | 
			
		||||
        let phoneNumber = this.phoneFormGroup.get('phoneNumber').value;
 | 
			
		||||
        if (phoneNumber) {
 | 
			
		||||
          if (code !== this.countryCallingCode && phoneNumber.includes(code)) {
 | 
			
		||||
            phoneNumber = phoneNumber.replace(code, this.countryCallingCode);
 | 
			
		||||
            this.phoneFormGroup.get('phoneNumber').patchValue(phoneNumber);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy() {
 | 
			
		||||
    if (this.valueChange$) {
 | 
			
		||||
      this.valueChange$.unsubscribe();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  focus() {
 | 
			
		||||
    const phoneNumber = this.phoneFormGroup.get('phoneNumber');
 | 
			
		||||
    this.phoneFormGroup.markAsPristine();
 | 
			
		||||
    this.phoneFormGroup.markAsUntouched();
 | 
			
		||||
    if (!phoneNumber.value) {
 | 
			
		||||
      phoneNumber.patchValue(this.countryCallingCode);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getFlagAndPhoneNumberData(country) {
 | 
			
		||||
    if (this.enableFlagsSelect) {
 | 
			
		||||
      this.flagIcon = this.getFlagIcon(country);
 | 
			
		||||
    }
 | 
			
		||||
    this.getPhoneNumberData(country);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getPhoneNumberData(country): void {
 | 
			
		||||
    const phoneData = getExampleNumber(country, examples);
 | 
			
		||||
    this.phonePlaceholder = phoneData.number;
 | 
			
		||||
    this.countryCallingCode = '+' + phoneData.countryCallingCode;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getFlagIcon(countryCode) {
 | 
			
		||||
    return String.fromCodePoint(...countryCode.split('').map(country => this.baseCode + country.charCodeAt(0)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  validatePhoneNumber(): ValidatorFn {
 | 
			
		||||
    return (c: FormControl) => {
 | 
			
		||||
      const phoneNumber = c.value;
 | 
			
		||||
      if (phoneNumber) {
 | 
			
		||||
        const parsedPhoneNumber = parsePhoneNumberFromString(phoneNumber);
 | 
			
		||||
        if (!parsedPhoneNumber?.isValid() || !parsedPhoneNumber?.isPossible()) {
 | 
			
		||||
          return {
 | 
			
		||||
            invalidPhoneNumber: {
 | 
			
		||||
              valid: false
 | 
			
		||||
            }
 | 
			
		||||
          };
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return null;
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  validate(): ValidationErrors | null {
 | 
			
		||||
    return this.phoneFormGroup.get('phoneNumber').valid ? null : {
 | 
			
		||||
      phoneFormGroup: false
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  registerOnChange(fn: any): void {
 | 
			
		||||
    this.propagateChange = fn;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  registerOnTouched(fn: any): void {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setDisabledState(isDisabled: boolean): void {
 | 
			
		||||
    this.disabled = isDisabled;
 | 
			
		||||
    if (isDisabled) {
 | 
			
		||||
      this.phoneFormGroup.disable({emitEvent: false});
 | 
			
		||||
    } else {
 | 
			
		||||
      this.phoneFormGroup.enable({emitEvent: false});
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  writeValue(phoneNumber): void {
 | 
			
		||||
    this.modelValue = phoneNumber;
 | 
			
		||||
    const country = phoneNumber ? parsePhoneNumberFromString(phoneNumber)?.country : this.defaultCountry;
 | 
			
		||||
    this.getFlagAndPhoneNumberData(country);
 | 
			
		||||
    this.phoneFormGroup.patchValue({phoneNumber, country}, {emitEvent: !phoneNumber});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private updateModel() {
 | 
			
		||||
    const phoneNumber = this.phoneFormGroup.get('phoneNumber');
 | 
			
		||||
    if (phoneNumber.valid && phoneNumber.value) {
 | 
			
		||||
      this.modelValue = phoneNumber.value;
 | 
			
		||||
      this.propagateChange(this.modelValue);
 | 
			
		||||
    } else {
 | 
			
		||||
      this.propagateChange(null);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										520
									
								
								ui-ngx/src/app/shared/models/country.models.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										520
									
								
								ui-ngx/src/app/shared/models/country.models.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,520 @@
 | 
			
		||||
///
 | 
			
		||||
/// Copyright © 2016-2022 The Thingsboard Authors
 | 
			
		||||
///
 | 
			
		||||
/// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
/// you may not use this file except in compliance with the License.
 | 
			
		||||
/// You may obtain a copy of the License at
 | 
			
		||||
///
 | 
			
		||||
///     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
///
 | 
			
		||||
/// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
/// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
/// See the License for the specific language governing permissions and
 | 
			
		||||
/// limitations under the License.
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
export interface Country {
 | 
			
		||||
  name: string;
 | 
			
		||||
  iso2: string;
 | 
			
		||||
  dialCode: string;
 | 
			
		||||
  areaCodes?: string[];
 | 
			
		||||
  flag: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum CountryISO {
 | 
			
		||||
  Afghanistan = 'AF',
 | 
			
		||||
  Albania = 'AL',
 | 
			
		||||
  Algeria = 'DZ',
 | 
			
		||||
  AmericanSamoa = 'AS',
 | 
			
		||||
  Andorra = 'AD',
 | 
			
		||||
  Angola = 'AO',
 | 
			
		||||
  Anguilla = 'AI',
 | 
			
		||||
  AntiguaAndBarbuda = 'AG',
 | 
			
		||||
  Argentina = 'AR',
 | 
			
		||||
  Armenia = 'AM',
 | 
			
		||||
  Aruba = 'AW',
 | 
			
		||||
  Australia = 'AU',
 | 
			
		||||
  Austria = 'AT',
 | 
			
		||||
  Azerbaijan = 'AZ',
 | 
			
		||||
  Bahamas = 'BS',
 | 
			
		||||
  Bahrain = 'BH',
 | 
			
		||||
  Bangladesh = 'BD',
 | 
			
		||||
  Barbados = 'BB',
 | 
			
		||||
  Belarus = 'BY',
 | 
			
		||||
  Belgium = 'BE',
 | 
			
		||||
  Belize = 'BZ',
 | 
			
		||||
  Benin = 'BJ',
 | 
			
		||||
  Bermuda = 'BM',
 | 
			
		||||
  Bhutan = 'BT',
 | 
			
		||||
  Bolivia = 'BO',
 | 
			
		||||
  BosniaAndHerzegovina = 'BA',
 | 
			
		||||
  Botswana = 'BW',
 | 
			
		||||
  Brazil = 'BR',
 | 
			
		||||
  BritishIndianOceanTerritory = 'IO',
 | 
			
		||||
  BritishVirginIslands = 'VG',
 | 
			
		||||
  Brunei = 'BN',
 | 
			
		||||
  Bulgaria = 'BG',
 | 
			
		||||
  BurkinaFaso = 'BF',
 | 
			
		||||
  Burundi = 'BI',
 | 
			
		||||
  Cambodia = 'KH',
 | 
			
		||||
  Cameroon = 'CM',
 | 
			
		||||
  Canada = 'CA',
 | 
			
		||||
  CapeVerde = 'CV',
 | 
			
		||||
  CaribbeanNetherlands = 'BQ',
 | 
			
		||||
  CaymanIslands = 'KY',
 | 
			
		||||
  CentralAfricanRepublic = 'CF',
 | 
			
		||||
  Chad = 'TD',
 | 
			
		||||
  Chile = 'CL',
 | 
			
		||||
  China = 'CN',
 | 
			
		||||
  ChristmasIsland = 'CX',
 | 
			
		||||
  Cocos = 'CC',
 | 
			
		||||
  Colombia = 'CC',
 | 
			
		||||
  Comoros = 'KM',
 | 
			
		||||
  CongoDRCJamhuriYaKidemokrasiaYaKongo = 'CD',
 | 
			
		||||
  CongoRepublicCongoBrazzaville = 'CG',
 | 
			
		||||
  CookIslands = 'CK',
 | 
			
		||||
  CostaRica = 'CR',
 | 
			
		||||
  CôteDIvoire = 'CI',
 | 
			
		||||
  Croatia = 'HR',
 | 
			
		||||
  Cuba = 'CU',
 | 
			
		||||
  Curaçao = 'CW',
 | 
			
		||||
  Cyprus = 'CY',
 | 
			
		||||
  CzechRepublic = 'CZ',
 | 
			
		||||
  Denmark = 'DK',
 | 
			
		||||
  Djibouti = 'DJ',
 | 
			
		||||
  Dominica = 'DM',
 | 
			
		||||
  DominicanRepublic = 'DO',
 | 
			
		||||
  Ecuador = 'EC',
 | 
			
		||||
  Egypt = 'EG',
 | 
			
		||||
  ElSalvador = 'SV',
 | 
			
		||||
  EquatorialGuinea = 'GQ',
 | 
			
		||||
  Eritrea = 'ER',
 | 
			
		||||
  Estonia = 'EE',
 | 
			
		||||
  Ethiopia = 'ET',
 | 
			
		||||
  FalklandIslands = 'FK',
 | 
			
		||||
  FaroeIslands = 'FO',
 | 
			
		||||
  Fiji = 'FJ',
 | 
			
		||||
  Finland = 'FI',
 | 
			
		||||
  France = 'FR',
 | 
			
		||||
  FrenchGuiana = 'GF',
 | 
			
		||||
  FrenchPolynesia = 'PF',
 | 
			
		||||
  Gabon = 'GA',
 | 
			
		||||
  Gambia = 'GM',
 | 
			
		||||
  Georgia = 'GE',
 | 
			
		||||
  Germany = 'DE',
 | 
			
		||||
  Ghana = 'GH',
 | 
			
		||||
  Gibraltar = 'GI',
 | 
			
		||||
  Greece = 'GR',
 | 
			
		||||
  Greenland = 'GL',
 | 
			
		||||
  Grenada = 'GD',
 | 
			
		||||
  Guadeloupe = 'GP',
 | 
			
		||||
  Guam = 'GU',
 | 
			
		||||
  Guatemala = 'GT',
 | 
			
		||||
  Guernsey = 'GG',
 | 
			
		||||
  Guinea = 'GN',
 | 
			
		||||
  GuineaBissau = 'GW',
 | 
			
		||||
  Guyana = 'GY',
 | 
			
		||||
  Haiti = 'HT',
 | 
			
		||||
  Honduras = 'HN',
 | 
			
		||||
  HongKong = 'HK',
 | 
			
		||||
  Hungary = 'HU',
 | 
			
		||||
  Iceland = 'IS',
 | 
			
		||||
  India = 'IN',
 | 
			
		||||
  Indonesia = 'ID',
 | 
			
		||||
  Iran = 'IR',
 | 
			
		||||
  Iraq = 'IQ',
 | 
			
		||||
  Ireland = 'IE',
 | 
			
		||||
  IsleOfMan = 'IM',
 | 
			
		||||
  Israel = 'IL',
 | 
			
		||||
  Italy = 'IT',
 | 
			
		||||
  Jamaica = 'JM',
 | 
			
		||||
  Japan = 'JP',
 | 
			
		||||
  Jersey = 'JE',
 | 
			
		||||
  Jordan = 'JO',
 | 
			
		||||
  Kazakhstan = 'KZ',
 | 
			
		||||
  Kenya = 'KE',
 | 
			
		||||
  Kiribati = 'KI',
 | 
			
		||||
  Kosovo = 'XK',
 | 
			
		||||
  Kuwait = 'KW',
 | 
			
		||||
  Kyrgyzstan = 'KG',
 | 
			
		||||
  Laos = 'LA',
 | 
			
		||||
  Latvia = 'LV',
 | 
			
		||||
  Lebanon = 'LB',
 | 
			
		||||
  Lesotho = 'LS',
 | 
			
		||||
  Liberia = 'LR',
 | 
			
		||||
  Libya = 'LY',
 | 
			
		||||
  Liechtenstein = 'LI',
 | 
			
		||||
  Lithuania = 'LT',
 | 
			
		||||
  Luxembourg = 'LU',
 | 
			
		||||
  Macau = 'MO',
 | 
			
		||||
  Macedonia = 'MK',
 | 
			
		||||
  Madagascar = 'MG',
 | 
			
		||||
  Malawi = 'MW',
 | 
			
		||||
  Malaysia = 'MY',
 | 
			
		||||
  Maldives = 'MV',
 | 
			
		||||
  Mali = 'ML',
 | 
			
		||||
  Malta = 'MT',
 | 
			
		||||
  MarshallIslands = 'MH',
 | 
			
		||||
  Martinique = 'MQ',
 | 
			
		||||
  Mauritania = 'MR',
 | 
			
		||||
  Mauritius = 'MU',
 | 
			
		||||
  Mayotte = 'YT',
 | 
			
		||||
  Mexico = 'MX',
 | 
			
		||||
  Micronesia = 'FM',
 | 
			
		||||
  Moldova = 'MD',
 | 
			
		||||
  Monaco = 'MC',
 | 
			
		||||
  Mongolia = 'MN',
 | 
			
		||||
  Montenegro = 'ME',
 | 
			
		||||
  Montserrat = 'MS',
 | 
			
		||||
  Morocco = 'MA',
 | 
			
		||||
  Mozambique = 'MZ',
 | 
			
		||||
  Myanmar = 'MM',
 | 
			
		||||
  Namibia = 'NA',
 | 
			
		||||
  Nauru = 'NR',
 | 
			
		||||
  Nepal = 'NP',
 | 
			
		||||
  Netherlands = 'NL',
 | 
			
		||||
  NewCaledonia = 'NC',
 | 
			
		||||
  NewZealand = 'NZ',
 | 
			
		||||
  Nicaragua = 'NI',
 | 
			
		||||
  Niger = 'NE',
 | 
			
		||||
  Nigeria = 'NG',
 | 
			
		||||
  Niue = 'NU',
 | 
			
		||||
  NorfolkIsland = 'NF',
 | 
			
		||||
  NorthKorea = 'KP',
 | 
			
		||||
  NorthernMarianaIslands = 'MP',
 | 
			
		||||
  Norway = 'NO',
 | 
			
		||||
  Oman = 'OM',
 | 
			
		||||
  Pakistan = 'PK',
 | 
			
		||||
  Palau = 'PW',
 | 
			
		||||
  Palestine = 'PS',
 | 
			
		||||
  Panama = 'PA',
 | 
			
		||||
  PapuaNewGuinea = 'PG',
 | 
			
		||||
  Paraguay = 'PY',
 | 
			
		||||
  Peru = 'PE',
 | 
			
		||||
  Philippines = 'PH',
 | 
			
		||||
  Poland = 'PL',
 | 
			
		||||
  Portugal = 'PT',
 | 
			
		||||
  PuertoRico = 'PR',
 | 
			
		||||
  Qatar = 'QA',
 | 
			
		||||
  Réunion = 'RE',
 | 
			
		||||
  Romania = 'RO',
 | 
			
		||||
  Russia = 'RU',
 | 
			
		||||
  Rwanda = 'RW',
 | 
			
		||||
  SaintBarthélemy = 'BL',
 | 
			
		||||
  SaintHelena = 'SH',
 | 
			
		||||
  SaintKittsAndNevis = 'KN',
 | 
			
		||||
  SaintLucia = 'LC',
 | 
			
		||||
  SaintMartin = 'MF',
 | 
			
		||||
  SaintPierreAndMiquelon = 'PM',
 | 
			
		||||
  SaintVincentAndTheGrenadines = 'VC',
 | 
			
		||||
  Samoa = 'WS',
 | 
			
		||||
  SanMarino = 'SM',
 | 
			
		||||
  SãoToméAndPríncipe = 'ST',
 | 
			
		||||
  SaudiArabia = 'SA',
 | 
			
		||||
  Senegal = 'SN',
 | 
			
		||||
  Serbia = 'RS',
 | 
			
		||||
  Seychelles = 'SC',
 | 
			
		||||
  SierraLeone = 'SL',
 | 
			
		||||
  Singapore = 'SG',
 | 
			
		||||
  SintMaarten = 'SX',
 | 
			
		||||
  Slovakia = 'SK',
 | 
			
		||||
  Slovenia = 'SI',
 | 
			
		||||
  SolomonIslands = 'SB',
 | 
			
		||||
  Somalia = 'SO',
 | 
			
		||||
  SouthAfrica = 'ZA',
 | 
			
		||||
  SouthKorea = 'KR',
 | 
			
		||||
  SouthSudan = 'SS',
 | 
			
		||||
  Spain = 'ES',
 | 
			
		||||
  SriLanka = 'LK',
 | 
			
		||||
  Sudan = 'SD',
 | 
			
		||||
  Suriname = 'SR',
 | 
			
		||||
  SvalbardAndJanMayen = 'SJ',
 | 
			
		||||
  Swaziland = 'SZ',
 | 
			
		||||
  Sweden = 'SE',
 | 
			
		||||
  Switzerland = 'CH',
 | 
			
		||||
  Syria = 'SY',
 | 
			
		||||
  Taiwan = 'TW',
 | 
			
		||||
  Tajikistan = 'TJ',
 | 
			
		||||
  Tanzania = 'TZ',
 | 
			
		||||
  Thailand = 'TH',
 | 
			
		||||
  TimorLeste = 'TL',
 | 
			
		||||
  Togo = 'TG',
 | 
			
		||||
  Tokelau = 'TK',
 | 
			
		||||
  Tonga = 'TO',
 | 
			
		||||
  TrinidadAndTobago = 'TT',
 | 
			
		||||
  Tunisia = 'TN',
 | 
			
		||||
  Turkey = 'TR',
 | 
			
		||||
  Turkmenistan = 'TM',
 | 
			
		||||
  TurksAndCaicosIslands = 'TC',
 | 
			
		||||
  Tuvalu = 'TV',
 | 
			
		||||
  USVirginIslands = 'VI',
 | 
			
		||||
  Uganda = 'UG',
 | 
			
		||||
  Ukraine = 'UA',
 | 
			
		||||
  UnitedArabEmirates = 'AE',
 | 
			
		||||
  UnitedKingdom = 'GB',
 | 
			
		||||
  UnitedStates = 'US',
 | 
			
		||||
  Uruguay = 'UY',
 | 
			
		||||
  Uzbekistan = 'UZ',
 | 
			
		||||
  Vanuatu = 'VU',
 | 
			
		||||
  VaticanCity = 'VA',
 | 
			
		||||
  Venezuela = 'VE',
 | 
			
		||||
  Vietnam = 'VN',
 | 
			
		||||
  WallisAndFutuna = 'WF',
 | 
			
		||||
  WesternSahara = 'EH',
 | 
			
		||||
  Yemen = 'YE',
 | 
			
		||||
  Zambia = 'ZM',
 | 
			
		||||
  Zimbabwe = 'ZW',
 | 
			
		||||
  ÅlandIslands = 'AX',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class CountryData {
 | 
			
		||||
  public allCountries: Array<Country> = [
 | 
			
		||||
    {name: 'Afghanistan', iso2: CountryISO.Afghanistan, dialCode: '93', flag: '🇦🇫'},
 | 
			
		||||
    {name: 'Albania', iso2: CountryISO.Albania, dialCode: '355', flag: '🇦🇱'},
 | 
			
		||||
    {name: 'Algeria', iso2: CountryISO.Algeria, dialCode: '213', flag: '🇩🇿'},
 | 
			
		||||
    {name: 'American Samoa', iso2: CountryISO.AmericanSamoa, dialCode: '1', flag: '🇦🇸'},
 | 
			
		||||
    {name: 'Andorra', iso2: CountryISO.Andorra, dialCode: '376', flag: '🇦🇩'},
 | 
			
		||||
    {name: 'Angola', iso2: CountryISO.Angola, dialCode: '244', flag: '🇦🇴'},
 | 
			
		||||
    {name: 'Anguilla', iso2: CountryISO.Anguilla, dialCode: '1', flag: '🇦🇮'},
 | 
			
		||||
    {name: 'Antigua and Barbuda', iso2: CountryISO.AntiguaAndBarbuda, dialCode: '1', flag: '🇦🇬'},
 | 
			
		||||
    {name: 'Argentina', iso2: CountryISO.Argentina, dialCode: '54', flag: '🇦🇷'},
 | 
			
		||||
    {name: 'Armenia', iso2: CountryISO.Armenia, dialCode: '374', flag: '🇦🇲'},
 | 
			
		||||
    {name: 'Aruba', iso2: CountryISO.Aruba, dialCode: '297', flag: '🇦🇼'},
 | 
			
		||||
    {name: 'Australia', iso2: CountryISO.Australia, dialCode: '61', flag: '🇦🇺'},
 | 
			
		||||
    {name: 'Austria', iso2: CountryISO.Austria, dialCode: '43', flag: '🇦🇹'},
 | 
			
		||||
    {name: 'Azerbaijan', iso2: CountryISO.Azerbaijan, dialCode: '994', flag: '🇦🇿'},
 | 
			
		||||
    {name: 'Bahamas', iso2: CountryISO.Bahamas, dialCode: '1', flag: '🇧🇸'},
 | 
			
		||||
    {name: 'Bahrain', iso2: CountryISO.Bahrain, dialCode: '973', flag: '🇧🇭'},
 | 
			
		||||
    {name: 'Bangladesh', iso2: CountryISO.Bangladesh, dialCode: '880', flag: '🇧🇩'},
 | 
			
		||||
    {name: 'Barbados', iso2: CountryISO.Barbados, dialCode: '1', flag: '🇧🇧'},
 | 
			
		||||
    {name: 'Belarus', iso2: CountryISO.Belarus, dialCode: '375', flag: '🇧🇾'},
 | 
			
		||||
    {name: 'Belgium', iso2: CountryISO.Belgium, dialCode: '32', flag: '🇧🇪'},
 | 
			
		||||
    {name: 'Belize', iso2: CountryISO.Belize, dialCode: '501', flag: '🇧🇿'},
 | 
			
		||||
    {name: 'Benin', iso2: CountryISO.Benin, dialCode: '229', flag: '🇧🇯'},
 | 
			
		||||
    {name: 'Bermuda', iso2: CountryISO.Bermuda, dialCode: '1', flag: '🇧🇲'},
 | 
			
		||||
    {name: 'Bhutan', iso2: CountryISO.Bhutan, dialCode: '975', flag: '🇧🇹'},
 | 
			
		||||
    {name: 'Bolivia', iso2: CountryISO.Bolivia, dialCode: '591', flag: '🇧🇴'},
 | 
			
		||||
    {name: 'Bosnia and Herzegovina', iso2: CountryISO.BosniaAndHerzegovina, dialCode: '387', flag: '🇧🇦'},
 | 
			
		||||
    {name: 'Botswana', iso2: CountryISO.Botswana, dialCode: '267', flag: '🇧🇼'},
 | 
			
		||||
    {name: 'Brazil', iso2: CountryISO.Brazil, dialCode: '55', flag: '🇧🇷'},
 | 
			
		||||
    {name: 'British Indian Ocean Territory', iso2: CountryISO.BritishIndianOceanTerritory, dialCode: '246', flag: '🇮🇴'},
 | 
			
		||||
    {name: 'British Virgin Islands', iso2: CountryISO.BritishVirginIslands, dialCode: '1', flag: '🇻🇬'},
 | 
			
		||||
    {name: 'Brunei', iso2: CountryISO.Brunei, dialCode: '673', flag: '🇧🇳'},
 | 
			
		||||
    {name: 'Bulgaria', iso2: CountryISO.Bulgaria, dialCode: '359', flag: '🇧🇬'},
 | 
			
		||||
    {name: 'Burkina Faso', iso2: CountryISO.BurkinaFaso, dialCode: '226', flag: '🇧🇫'},
 | 
			
		||||
    {name: 'Burundi', iso2: CountryISO.Burundi, dialCode: '257', flag: '🇧🇮'},
 | 
			
		||||
    {name: 'Cambodia', iso2: CountryISO.Cambodia, dialCode: '855', flag: '🇰🇭'},
 | 
			
		||||
    {name: 'Cameroon', iso2: CountryISO.Cameroon, dialCode: '237', flag: '🇨🇲'},
 | 
			
		||||
    {name: 'Canada', iso2: CountryISO.Canada, dialCode: '1', flag: '🇨🇦'},
 | 
			
		||||
    {name: 'Cape Verde', iso2: CountryISO.CapeVerde, dialCode: '238', flag: '🇨🇻'},
 | 
			
		||||
    {name: 'Caribbean Netherlands', iso2: CountryISO.CaribbeanNetherlands, dialCode: '599', flag: '🇧🇶'},
 | 
			
		||||
    {name: 'Cayman Islands', iso2: CountryISO.CaymanIslands, dialCode: '1', flag: '🇰🇾'},
 | 
			
		||||
    {name: 'Central African Republic', iso2: CountryISO.CentralAfricanRepublic, dialCode: '236', flag: '🇨🇫'},
 | 
			
		||||
    {name: 'Chad', iso2: CountryISO.Chad, dialCode: '235', flag: '🇹🇩'},
 | 
			
		||||
    {name: 'Chile', iso2: CountryISO.Chile, dialCode: '56', flag: '🇨🇱'},
 | 
			
		||||
    {name: 'China', iso2: CountryISO.China, dialCode: '86', flag: '🇨🇳'},
 | 
			
		||||
    {name: 'Christmas Island', iso2: CountryISO.ChristmasIsland, dialCode: '61', flag: '🇨🇽'},
 | 
			
		||||
    {name: 'Cocos Islands', iso2: CountryISO.Cocos, dialCode: '61', flag: '🇨🇨'},
 | 
			
		||||
    {name: 'Colombia', iso2: CountryISO.Colombia, dialCode: '57', flag: '🇨🇨'},
 | 
			
		||||
    {name: 'Comoros', iso2: CountryISO.Comoros, dialCode: '269', flag: '🇰🇲'},
 | 
			
		||||
    {name: 'Congo-Kinshasa', iso2: CountryISO.CongoDRCJamhuriYaKidemokrasiaYaKongo, dialCode: '243', flag: '🇨🇩'},
 | 
			
		||||
    {name: 'Congo-Brazzaville', iso2: CountryISO.CongoRepublicCongoBrazzaville, dialCode: '242', flag: '🇨🇬'},
 | 
			
		||||
    {name: 'Cook Islands', iso2: CountryISO.CookIslands, dialCode: '682', flag: '🇨🇰'},
 | 
			
		||||
    {name: 'Costa Rica', iso2: CountryISO.CostaRica, dialCode: '506', flag: '🇨🇷'},
 | 
			
		||||
    {name: 'Côte d’Ivoire', iso2: CountryISO.CôteDIvoire, dialCode: '225', flag: '🇨🇮'},
 | 
			
		||||
    {name: 'Croatia', iso2: CountryISO.Croatia, dialCode: '385', flag: '🇭🇷'},
 | 
			
		||||
    {name: 'Cuba', iso2: CountryISO.Cuba, dialCode: '53', flag: '🇨🇺'},
 | 
			
		||||
    {name: 'Curaçao', iso2: CountryISO.Curaçao, dialCode: '599', flag: '🇨🇼'},
 | 
			
		||||
    {name: 'Cyprus', iso2: CountryISO.Cyprus, dialCode: '357', flag: '🇨🇾'},
 | 
			
		||||
    {name: 'Czech Republic', iso2: CountryISO.CzechRepublic, dialCode: '420', flag: '🇨🇿'},
 | 
			
		||||
    {name: 'Denmark', iso2: CountryISO.Denmark, dialCode: '45', flag: '🇩🇰'},
 | 
			
		||||
    {name: 'Djibouti', iso2: CountryISO.Djibouti, dialCode: '253', flag: '🇩🇯'},
 | 
			
		||||
    {name: 'Dominica', iso2: CountryISO.Dominica, dialCode: '1767', flag: '🇩🇲'},
 | 
			
		||||
    {name: 'Dominican Republic', iso2: CountryISO.DominicanRepublic, dialCode: '1', flag: '🇩🇴'},
 | 
			
		||||
    {name: 'Ecuador', iso2: CountryISO.Ecuador, dialCode: '593', flag: '🇪🇨'},
 | 
			
		||||
    {name: 'Egypt', iso2: CountryISO.Egypt, dialCode: '20', flag: '🇪🇬'},
 | 
			
		||||
    {name: 'El Salvador', iso2: CountryISO.ElSalvador, dialCode: '503', flag: '🇸🇻'},
 | 
			
		||||
    {name: 'Equatorial Guinea', iso2: CountryISO.EquatorialGuinea, dialCode: '240', flag: '🇬🇶'},
 | 
			
		||||
    {name: 'Eritrea', iso2: CountryISO.Eritrea, dialCode: '291', flag: '🇪🇷'},
 | 
			
		||||
    {name: 'Estonia', iso2: CountryISO.Estonia, dialCode: '372', flag: '🇪🇪'},
 | 
			
		||||
    {name: 'Ethiopia', iso2: CountryISO.Ethiopia, dialCode: '251', flag: '🇪🇹'},
 | 
			
		||||
    {name: 'Falkland Islands', iso2: CountryISO.FalklandIslands, dialCode: '500', flag: '🇫🇰'},
 | 
			
		||||
    {name: 'Faroe Islands', iso2: CountryISO.FaroeIslands, dialCode: '298', flag: '🇫🇴'},
 | 
			
		||||
    {name: 'Fiji', iso2: CountryISO.Fiji, dialCode: '679', flag: '🇫🇯'},
 | 
			
		||||
    {name: 'Finland', iso2: CountryISO.Finland, dialCode: '358', flag: '🇫🇮'},
 | 
			
		||||
    {name: 'France', iso2: CountryISO.France, dialCode: '33', flag: '🇫🇷'},
 | 
			
		||||
    {name: 'French Guiana', iso2: CountryISO.FrenchGuiana, dialCode: '594', flag: '🇬🇫'},
 | 
			
		||||
    {name: 'French Polynesia', iso2: CountryISO.FrenchPolynesia, dialCode: '689', flag: '🇵🇫'},
 | 
			
		||||
    {name: 'Gabon', iso2: CountryISO.Gabon, dialCode: '241', flag: '🇬🇦'},
 | 
			
		||||
    {name: 'Gambia', iso2: CountryISO.Gambia, dialCode: '220', flag: '🇬🇲'},
 | 
			
		||||
    {name: 'Georgia', iso2: CountryISO.Georgia, dialCode: '995', flag: '🇬🇪'},
 | 
			
		||||
    {name: 'Germany', iso2: CountryISO.Germany, dialCode: '49', flag: '🇩🇪'},
 | 
			
		||||
    {name: 'Ghana', iso2: CountryISO.Ghana, dialCode: '233', flag: '🇬🇭'},
 | 
			
		||||
    {name: 'Gibraltar', iso2: CountryISO.Gibraltar, dialCode: '350', flag: '🇬🇮'},
 | 
			
		||||
    {name: 'Greece', iso2: CountryISO.Greece, dialCode: '30', flag: '🇬🇷'},
 | 
			
		||||
    {name: 'Greenland', iso2: CountryISO.Greenland, dialCode: '299', flag: '🇬🇱'},
 | 
			
		||||
    {name: 'Grenada', iso2: CountryISO.Grenada, dialCode: '1473', flag: '🇬🇩'},
 | 
			
		||||
    {name: 'Guadeloupe', iso2: CountryISO.Guadeloupe, dialCode: '590', flag: '🇬🇵'},
 | 
			
		||||
    {name: 'Guam', iso2: CountryISO.Guam, dialCode: '1', flag: '🇬🇺'},
 | 
			
		||||
    {name: 'Guatemala', iso2: CountryISO.Guatemala, dialCode: '502', flag: '🇬🇹'},
 | 
			
		||||
    {name: 'Guernsey', iso2: CountryISO.Guernsey, dialCode: '44', flag: '🇬🇬'},
 | 
			
		||||
    {name: 'Guinea', iso2: CountryISO.Guinea, dialCode: '224', flag: '🇬🇳'},
 | 
			
		||||
    {name: 'Guinea-Bissau', iso2: CountryISO.GuineaBissau, dialCode: '245', flag: '🇬🇼'},
 | 
			
		||||
    {name: 'Guyana', iso2: CountryISO.Guyana, dialCode: '592', flag: '🇬🇾'},
 | 
			
		||||
    {name: 'Haiti', iso2: CountryISO.Haiti, dialCode: '509', flag: '🇭🇹'},
 | 
			
		||||
    {name: 'Honduras', iso2: CountryISO.Honduras, dialCode: '504', flag: '🇭🇳'},
 | 
			
		||||
    {name: 'Hong Kong', iso2: CountryISO.HongKong, dialCode: '852', flag: '🇭🇰'},
 | 
			
		||||
    {name: 'Hungary', iso2: CountryISO.Hungary, dialCode: '36', flag: '🇭🇺'},
 | 
			
		||||
    {name: 'Iceland', iso2: CountryISO.Iceland, dialCode: '354', flag: '🇮🇸'},
 | 
			
		||||
    {name: 'India', iso2: CountryISO.India, dialCode: '91', flag: '🇮🇳'},
 | 
			
		||||
    {name: 'Indonesia', iso2: CountryISO.Indonesia, dialCode: '62', flag: '🇮🇩'},
 | 
			
		||||
    {name: 'Iran', iso2: CountryISO.Iran, dialCode: '98', flag: '🇮🇷'},
 | 
			
		||||
    {name: 'Iraq', iso2: CountryISO.Iraq, dialCode: '964', flag: '🇮🇶'},
 | 
			
		||||
    {name: 'Ireland', iso2: CountryISO.Ireland, dialCode: '353', flag: '🇮🇪'},
 | 
			
		||||
    {name: 'Isle of Man', iso2: CountryISO.IsleOfMan, dialCode: '44', flag: '🇮🇲'},
 | 
			
		||||
    {name: 'Israel', iso2: CountryISO.Israel, dialCode: '972', flag: '🇮🇱'},
 | 
			
		||||
    {name: 'Italy', iso2: CountryISO.Italy, dialCode: '39', flag: '🇮🇹'},
 | 
			
		||||
    {name: 'Jamaica', iso2: CountryISO.Jamaica, dialCode: '1', flag: '🇯🇲'},
 | 
			
		||||
    {name: 'Japan', iso2: CountryISO.Japan, dialCode: '81', flag: '🇯🇵'},
 | 
			
		||||
    {name: 'Jersey', iso2: CountryISO.Jersey, dialCode: '44', flag: '🇯🇪'},
 | 
			
		||||
    {name: 'Jordan', iso2: CountryISO.Jordan, dialCode: '962', flag: '🇯🇴'},
 | 
			
		||||
    {name: 'Kazakhstan', iso2: CountryISO.Kazakhstan, dialCode: '7', flag: '🇰🇿'},
 | 
			
		||||
    {name: 'Kenya', iso2: CountryISO.Kenya, dialCode: '254', flag: '🇰🇪'},
 | 
			
		||||
    {name: 'Kiribati', iso2: CountryISO.Kiribati, dialCode: '686', flag: '🇰🇮'},
 | 
			
		||||
    {name: 'Kosovo', iso2: CountryISO.Kosovo, dialCode: '383', flag: '🇽🇰'},
 | 
			
		||||
    {name: 'Kuwait', iso2: CountryISO.Kuwait, dialCode: '965', flag: '🇰🇼'},
 | 
			
		||||
    {name: 'Kyrgyzstan', iso2: CountryISO.Kyrgyzstan, dialCode: '996', flag: '🇰🇬'},
 | 
			
		||||
    {name: 'Laos', iso2: CountryISO.Laos, dialCode: '856', flag: '🇱🇦'},
 | 
			
		||||
    {name: 'Latvia', iso2: CountryISO.Latvia, dialCode: '371', flag: '🇱🇻'},
 | 
			
		||||
    {name: 'Lebanon', iso2: CountryISO.Lebanon, dialCode: '961', flag: '🇱🇧'},
 | 
			
		||||
    {name: 'Lesotho', iso2: CountryISO.Lesotho, dialCode: '266', flag: '🇱🇸'},
 | 
			
		||||
    {name: 'Liberia', iso2: CountryISO.Liberia, dialCode: '231', flag: '🇱🇷'},
 | 
			
		||||
    {name: 'Libya', iso2: CountryISO.Libya, dialCode: '218', flag: '🇱🇾'},
 | 
			
		||||
    {name: 'Liechtenstein', iso2: CountryISO.Liechtenstein, dialCode: '423', flag: '🇱🇮'},
 | 
			
		||||
    {name: 'Lithuania', iso2: CountryISO.Lithuania, dialCode: '370', flag: '🇱🇹'},
 | 
			
		||||
    {name: 'Luxembourg', iso2: CountryISO.Luxembourg, dialCode: '352', flag: '🇱🇺'},
 | 
			
		||||
    {name: 'Macau', iso2: CountryISO.Macau, dialCode: '853', flag: '🇲🇴'},
 | 
			
		||||
    {name: 'Macedonia', iso2: CountryISO.Macedonia, dialCode: '389', flag: '🇲🇰'},
 | 
			
		||||
    {name: 'Madagascar', iso2: CountryISO.Madagascar, dialCode: '261', flag: '🇲🇬'},
 | 
			
		||||
    {name: 'Malawi', iso2: CountryISO.Malawi, dialCode: '265', flag: '🇲🇼'},
 | 
			
		||||
    {name: 'Malaysia', iso2: CountryISO.Malaysia, dialCode: '60', flag: '🇲🇾'},
 | 
			
		||||
    {name: 'Maldives', iso2: CountryISO.Maldives, dialCode: '960', flag: '🇲🇻'},
 | 
			
		||||
    {name: 'Mali', iso2: CountryISO.Mali, dialCode: '223', flag: '🇲🇱'},
 | 
			
		||||
    {name: 'Malta', iso2: CountryISO.Malta, dialCode: '356', flag: '🇲🇹'},
 | 
			
		||||
    {name: 'Marshall Islands', iso2: CountryISO.MarshallIslands, dialCode: '692', flag: '🇲🇭'},
 | 
			
		||||
    {name: 'Martinique', iso2: CountryISO.Martinique, dialCode: '596', flag: '🇲🇶'},
 | 
			
		||||
    {name: 'Mauritania', iso2: CountryISO.Mauritania, dialCode: '222', flag: '🇲🇷'},
 | 
			
		||||
    {name: 'Mauritius', iso2: CountryISO.Mauritius, dialCode: '230', flag: '🇲🇺'},
 | 
			
		||||
    {name: 'Mayotte', iso2: CountryISO.Mayotte, dialCode: '262', flag: '🇾🇹'},
 | 
			
		||||
    {name: 'Mexico', iso2: CountryISO.Mexico, dialCode: '52', flag: '🇲🇽'},
 | 
			
		||||
    {name: 'Micronesia', iso2: CountryISO.Micronesia, dialCode: '691', flag: '🇫🇲'},
 | 
			
		||||
    {name: 'Moldova', iso2: CountryISO.Moldova, dialCode: '373', flag: '🇲🇩'},
 | 
			
		||||
    {name: 'Monaco', iso2: CountryISO.Monaco, dialCode: '377', flag: '🇲🇨'},
 | 
			
		||||
    {name: 'Mongolia', iso2: CountryISO.Mongolia, dialCode: '976', flag: '🇲🇳'},
 | 
			
		||||
    {name: 'Montenegro', iso2: CountryISO.Montenegro, dialCode: '382', flag: '🇲🇪'},
 | 
			
		||||
    {name: 'Montserrat', iso2: CountryISO.Montserrat, dialCode: '1', flag: '🇲🇸'},
 | 
			
		||||
    {name: 'Morocco', iso2: CountryISO.Morocco, dialCode: '212', flag: '🇲🇦'},
 | 
			
		||||
    {name: 'Mozambique', iso2: CountryISO.Mozambique, dialCode: '258', flag: '🇲🇿'},
 | 
			
		||||
    {name: 'Myanmar', iso2: CountryISO.Myanmar, dialCode: '95', flag: '🇲🇲'},
 | 
			
		||||
    {name: 'Namibia', iso2: CountryISO.Namibia, dialCode: '264', flag: '🇳🇦'},
 | 
			
		||||
    {name: 'Nauru', iso2: CountryISO.Nauru, dialCode: '674', flag: '🇳🇷'},
 | 
			
		||||
    {name: 'Nepal', iso2: CountryISO.Nepal, dialCode: '977', flag: '🇳🇵'},
 | 
			
		||||
    {name: 'Netherlands', iso2: CountryISO.Netherlands, dialCode: '31', flag: '🇳🇱'},
 | 
			
		||||
    {name: 'New Caledonia', iso2: CountryISO.NewCaledonia, dialCode: '687', flag: '🇳🇨'},
 | 
			
		||||
    {name: 'New Zealand', iso2: CountryISO.NewZealand, dialCode: '64', flag: '🇳🇿'},
 | 
			
		||||
    {name: 'Nicaragua', iso2: CountryISO.Nicaragua, dialCode: '505', flag: '🇳🇮'},
 | 
			
		||||
    {name: 'Niger', iso2: CountryISO.Niger, dialCode: '227', flag: '🇳🇪'},
 | 
			
		||||
    {name: 'Nigeria', iso2: CountryISO.Nigeria, dialCode: '234', flag: '🇳🇬'},
 | 
			
		||||
    {name: 'Niue', iso2: CountryISO.Niue, dialCode: '683', flag: '🇳🇺'},
 | 
			
		||||
    {name: 'Norfolk Island', iso2: CountryISO.NorfolkIsland, dialCode: '672', flag: '🇳🇫'},
 | 
			
		||||
    {name: 'North Korea', iso2: CountryISO.NorthKorea, dialCode: '850', flag: '🇰🇵'},
 | 
			
		||||
    {name: 'Northern Mariana Islands', iso2: CountryISO.NorthernMarianaIslands, dialCode: '1670', flag: '🇲🇵'},
 | 
			
		||||
    {name: 'Norway', iso2: CountryISO.Norway, dialCode: '47', flag: '🇳🇴'},
 | 
			
		||||
    {name: 'Oman', iso2: CountryISO.Oman, dialCode: '968', flag: '🇴🇲'},
 | 
			
		||||
    {name: 'Pakistan', iso2: CountryISO.Pakistan, dialCode: '92', flag: '🇵🇰'},
 | 
			
		||||
    {name: 'Palau', iso2: CountryISO.Palau, dialCode: '680', flag: '🇵🇼'},
 | 
			
		||||
    {name: 'Palestine', iso2: CountryISO.Palestine, dialCode: '970', flag: '🇵🇸'},
 | 
			
		||||
    {name: 'Panama', iso2: CountryISO.Panama, dialCode: '507', flag: '🇵🇦'},
 | 
			
		||||
    {name: 'Papua New Guinea', iso2: CountryISO.PapuaNewGuinea, dialCode: '675', flag: '🇵🇬'},
 | 
			
		||||
    {name: 'Paraguay', iso2: CountryISO.Paraguay, dialCode: '595', flag: '🇵🇾'},
 | 
			
		||||
    {name: 'Peru', iso2: CountryISO.Peru, dialCode: '51', flag: '🇵🇪'},
 | 
			
		||||
    {name: 'Philippines', iso2: CountryISO.Philippines, dialCode: '63', flag: '🇵🇭'},
 | 
			
		||||
    {name: 'Poland', iso2: CountryISO.Poland, dialCode: '48', flag: '🇵🇱'},
 | 
			
		||||
    {name: 'Portugal', iso2: CountryISO.Portugal, dialCode: '351', flag: '🇵🇹'},
 | 
			
		||||
    {name: 'Puerto Rico', iso2: CountryISO.PuertoRico, dialCode: '1', flag: '🇵🇷'},
 | 
			
		||||
    {name: 'Qatar', iso2: CountryISO.Qatar, dialCode: '974', flag: '🇶🇦'},
 | 
			
		||||
    {name: 'Réunion', iso2: CountryISO.Réunion, dialCode: '262', flag: '🇷🇪'},
 | 
			
		||||
    {name: 'Romania', iso2: CountryISO.Romania, dialCode: '40', flag: '🇷🇴'},
 | 
			
		||||
    {name: 'Russia', iso2: CountryISO.Russia, dialCode: '7', flag: '🇷🇺'},
 | 
			
		||||
    {name: 'Rwanda', iso2: CountryISO.Rwanda, dialCode: '250', flag: '🇷🇼'},
 | 
			
		||||
    {name: 'Saint Barthélemy', iso2: CountryISO.SaintBarthélemy, dialCode: '590', flag: '🇧🇱'},
 | 
			
		||||
    {name: 'Saint Helena', iso2: CountryISO.SaintHelena, dialCode: '290', flag: '🇸🇭'},
 | 
			
		||||
    {name: 'Saint Kitts and Nevis', iso2: CountryISO.SaintKittsAndNevis, dialCode: '1869', flag: '🇰🇳'},
 | 
			
		||||
    {name: 'Saint Lucia', iso2: CountryISO.SaintLucia, dialCode: '1', flag: '🇱🇨'},
 | 
			
		||||
    {name: 'Saint Martin', iso2: CountryISO.SaintMartin, dialCode: '590', flag: '🇲🇫'},
 | 
			
		||||
    {name: 'Saint Pierre and Miquelon', iso2: CountryISO.SaintPierreAndMiquelon, dialCode: '508', flag: '🇵🇲'},
 | 
			
		||||
    {name: 'Saint Vincent and the Grenadines', iso2: CountryISO.SaintVincentAndTheGrenadines, dialCode: '1', flag: '🇻🇨'},
 | 
			
		||||
    {name: 'Samoa', iso2: CountryISO.Samoa, dialCode: '685', flag: '🇼🇸'},
 | 
			
		||||
    {name: 'San Marino', iso2: CountryISO.SanMarino, dialCode: '378', flag: '🇸🇲'},
 | 
			
		||||
    {name: 'São Tomé and Príncipe', iso2: CountryISO.SãoToméAndPríncipe, dialCode: '239', flag: '🇸🇹'},
 | 
			
		||||
    {name: 'Saudi Arabia', iso2: CountryISO.SaudiArabia, dialCode: '966', flag: '🇸🇦'},
 | 
			
		||||
    {name: 'Senegal', iso2: CountryISO.Senegal, dialCode: '221', flag: '🇸🇳'},
 | 
			
		||||
    {name: 'Serbia', iso2: CountryISO.Serbia, dialCode: '381', flag: '🇷🇸'},
 | 
			
		||||
    {name: 'Seychelles', iso2: CountryISO.Seychelles, dialCode: '248', flag: '🇸🇨'},
 | 
			
		||||
    {name: 'Sierra Leone', iso2: CountryISO.SierraLeone, dialCode: '232', flag: '🇸🇱'},
 | 
			
		||||
    {name: 'Singapore', iso2: CountryISO.Singapore, dialCode: '65', flag: '🇸🇬'},
 | 
			
		||||
    {name: 'Sint Maarten', iso2: CountryISO.SintMaarten, dialCode: '1', flag: '🇸🇽'},
 | 
			
		||||
    {name: 'Slovakia', iso2: CountryISO.Slovakia, dialCode: '421', flag: '🇸🇰'},
 | 
			
		||||
    {name: 'Slovenia', iso2: CountryISO.Slovenia, dialCode: '386', flag: '🇸🇮'},
 | 
			
		||||
    {name: 'Solomon Islands', iso2: CountryISO.SolomonIslands, dialCode: '677', flag: '🇸🇧'},
 | 
			
		||||
    {name: 'Somalia', iso2: CountryISO.Somalia, dialCode: '252', flag: '🇸🇴'},
 | 
			
		||||
    {name: 'South Africa', iso2: CountryISO.SouthAfrica, dialCode: '27', flag: '🇿🇦'},
 | 
			
		||||
    {name: 'South Korea', iso2: CountryISO.SouthKorea, dialCode: '82', flag: '🇰🇷'},
 | 
			
		||||
    {name: 'South Sudan', iso2: CountryISO.SouthSudan, dialCode: '211', flag: '🇸🇸'},
 | 
			
		||||
    {name: 'Spain', iso2: CountryISO.Spain, dialCode: '34', flag: '🇪🇸'},
 | 
			
		||||
    {name: 'Sri Lanka', iso2: CountryISO.SriLanka, dialCode: '94', flag: '🇱🇰'},
 | 
			
		||||
    {name: 'Sudan', iso2: CountryISO.Sudan, dialCode: '249', flag: '🇸🇩'},
 | 
			
		||||
    {name: 'Suriname: ', iso2: CountryISO.Suriname, dialCode: '597', flag: '🇸🇷'},
 | 
			
		||||
    {name: 'Svalbard and Jan Mayen', iso2: CountryISO.SvalbardAndJanMayen, dialCode: '47', flag: '🇸🇯'},
 | 
			
		||||
    {name: 'Swaziland', iso2: CountryISO.Swaziland, dialCode: '268', flag: '🇸🇿'},
 | 
			
		||||
    {name: 'Sweden', iso2: CountryISO.Sweden, dialCode: '46', flag: '🇸🇪'},
 | 
			
		||||
    {name: 'Switzerland', iso2: CountryISO.Switzerland, dialCode: '41', flag: '🇨🇭'},
 | 
			
		||||
    {name: 'Syria', iso2: CountryISO.Syria, dialCode: '963', flag: '🇸🇾'},
 | 
			
		||||
    {name: 'Taiwan', iso2: CountryISO.Taiwan, dialCode: '886', flag: '🇹🇼'},
 | 
			
		||||
    {name: 'Tajikistan', iso2: CountryISO.Tajikistan, dialCode: '992', flag: '🇹🇯'},
 | 
			
		||||
    {name: 'Tanzania', iso2: CountryISO.Tanzania, dialCode: '255', flag: '🇹🇿'},
 | 
			
		||||
    {name: 'Thailand', iso2: CountryISO.Thailand, dialCode: '66', flag: '🇹🇭'},
 | 
			
		||||
    {name: 'Timor-Leste', iso2: CountryISO.TimorLeste, dialCode: '670', flag: '🇹🇱'},
 | 
			
		||||
    {name: 'Togo', iso2: CountryISO.Togo, dialCode: '228', flag: '🇹🇬'},
 | 
			
		||||
    {name: 'Tokelau', iso2: CountryISO.Tokelau, dialCode: '690', flag: '🇹🇰'},
 | 
			
		||||
    {name: 'Tonga', iso2: CountryISO.Tonga, dialCode: '676', flag: '🇹🇴'},
 | 
			
		||||
    {name: 'Trinidad and Tobago', iso2: CountryISO.TrinidadAndTobago, dialCode: '1', flag: '🇹🇹'},
 | 
			
		||||
    {name: 'Tunisia', iso2: CountryISO.Tunisia, dialCode: '216', flag: '🇹🇳'},
 | 
			
		||||
    {name: 'Turkey', iso2: CountryISO.Turkey, dialCode: '90', flag: '🇹🇷'},
 | 
			
		||||
    {name: 'Turkmenistan', iso2: CountryISO.Turkmenistan, dialCode: '993', flag: '🇹🇲'},
 | 
			
		||||
    {name: 'Turks and Caicos Islands', iso2: CountryISO.TurksAndCaicosIslands, dialCode: '1649', flag: '🇹🇨'},
 | 
			
		||||
    {name: 'Tuvalu', iso2: CountryISO.Tuvalu, dialCode: '688', flag: '🇹🇻'},
 | 
			
		||||
    {name: 'U.S. Virgin Islands', iso2: CountryISO.USVirginIslands, dialCode: '1', flag: '🇻🇮'},
 | 
			
		||||
    {name: 'Uganda', iso2: CountryISO.Uganda, dialCode: '256', flag: '🇺🇬'},
 | 
			
		||||
    {name: 'Ukraine', iso2: CountryISO.Ukraine, dialCode: '380', flag: '🇺🇦'},
 | 
			
		||||
    {name: 'United Arab Emirates', iso2: CountryISO.UnitedArabEmirates, dialCode: '971', flag: '🇦🇪'},
 | 
			
		||||
    {name: 'United Kingdom', iso2: CountryISO.UnitedKingdom, dialCode: '44', flag: '🇬🇧'},
 | 
			
		||||
    {name: 'United States', iso2: CountryISO.UnitedStates, dialCode: '1', flag: '🇺🇸'},
 | 
			
		||||
    {name: 'Uruguay', iso2: CountryISO.Uruguay, dialCode: '598', flag: '🇺🇾'},
 | 
			
		||||
    {name: 'Uzbekistan', iso2: CountryISO.Uzbekistan, dialCode: '998', flag: '🇺🇿'},
 | 
			
		||||
    {name: 'Vanuatu', iso2: CountryISO.Vanuatu, dialCode: '678', flag: '🇻🇺'},
 | 
			
		||||
    {name: 'Vatican City', iso2: CountryISO.VaticanCity, dialCode: '39', flag: '🇻🇦'},
 | 
			
		||||
    {name: 'Venezuela', iso2: CountryISO.Venezuela, dialCode: '58', flag: '🇻🇪'},
 | 
			
		||||
    {name: 'Vietnam', iso2: CountryISO.Vietnam, dialCode: '84', flag: '🇻🇳'},
 | 
			
		||||
    {name: 'Wallis and Futuna', iso2: CountryISO.WallisAndFutuna, dialCode: '681', flag: '🇼🇫'},
 | 
			
		||||
    {name: 'Western Sahara', iso2: CountryISO.WesternSahara, dialCode: '212', flag: '🇪🇭'},
 | 
			
		||||
    {name: 'Yemen', iso2: CountryISO.Yemen, dialCode: '967', flag: '🇾🇪'},
 | 
			
		||||
    {name: 'Zambia', iso2: CountryISO.Zambia, dialCode: '260', flag: '🇿🇲'},
 | 
			
		||||
    {name: 'Zimbabwe', iso2: CountryISO.Zimbabwe, dialCode: '263', flag: '🇿🇼'},
 | 
			
		||||
    {name: 'Åland Islands', iso2: CountryISO.ÅlandIslands, dialCode: '358', flag: '🇦🇽'}
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
@ -163,6 +163,7 @@ import { HtmlComponent } from '@shared/components/html.component';
 | 
			
		||||
import { SafePipe } from '@shared/pipe/safe.pipe';
 | 
			
		||||
import { DragDropModule } from '@angular/cdk/drag-drop';
 | 
			
		||||
import { MultipleImageInputComponent } from '@shared/components/multiple-image-input.component';
 | 
			
		||||
import { PhoneInputComponent } from '@shared/components/phone-input.component';
 | 
			
		||||
 | 
			
		||||
export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) {
 | 
			
		||||
  return markedOptionsService;
 | 
			
		||||
@ -284,7 +285,8 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
 | 
			
		||||
    WidgetsBundleSearchComponent,
 | 
			
		||||
    CopyButtonComponent,
 | 
			
		||||
    TogglePasswordComponent,
 | 
			
		||||
    ProtobufContentComponent
 | 
			
		||||
    ProtobufContentComponent,
 | 
			
		||||
    PhoneInputComponent
 | 
			
		||||
  ],
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
@ -484,7 +486,8 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
 | 
			
		||||
    WidgetsBundleSearchComponent,
 | 
			
		||||
    CopyButtonComponent,
 | 
			
		||||
    TogglePasswordComponent,
 | 
			
		||||
    ProtobufContentComponent
 | 
			
		||||
    ProtobufContentComponent,
 | 
			
		||||
    PhoneInputComponent
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class SharedModule { }
 | 
			
		||||
 | 
			
		||||
@ -4449,6 +4449,13 @@
 | 
			
		||||
        "material-icons": "Material icons",
 | 
			
		||||
        "show-all": "Show all icons"
 | 
			
		||||
    },
 | 
			
		||||
    "phone-input": {
 | 
			
		||||
        "phone-input-label": "Phone number",
 | 
			
		||||
        "phone-input-required": "Phone number is required",
 | 
			
		||||
        "phone-input-validation": "Phone number is invalid or not possible",
 | 
			
		||||
        "phone-input-pattern": "Invalid phone number. Should be in E.164 format, ex. {{phoneNumber}}",
 | 
			
		||||
        "phone-input-hint": "Phone Number in E.164 format, ex. {{phoneNumber}}"
 | 
			
		||||
    },
 | 
			
		||||
    "custom": {
 | 
			
		||||
        "widget-action": {
 | 
			
		||||
            "action-cell-button": "Action cell button",
 | 
			
		||||
 | 
			
		||||
@ -6027,6 +6027,11 @@ less@4.1.1:
 | 
			
		||||
    needle "^2.5.2"
 | 
			
		||||
    source-map "~0.6.0"
 | 
			
		||||
 | 
			
		||||
libphonenumber-js@^1.10.4:
 | 
			
		||||
  version "1.10.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.4.tgz#90397f0ed620262570a32244c9fbc389cc417ce4"
 | 
			
		||||
  integrity sha512-9QWxEk4GW5RDnFzt8UtyRENfFpAN8u7Sbf9wf32tcXY9tdtnz1dKHIBwW2Wnfx8ypXJb9zUnTpK9aQJ/B8AlnA==
 | 
			
		||||
 | 
			
		||||
license-webpack-plugin@2.3.20:
 | 
			
		||||
  version "2.3.20"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.3.20.tgz#f51fb674ca31519dbedbe1c7aabc036e5a7f2858"
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user