diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..25e28f0
Binary files /dev/null and b/.DS_Store differ
diff --git a/EbfEmployees/pom.xml b/EbfEmployees/pom.xml
index 3e27f09..2167219 100644
--- a/EbfEmployees/pom.xml
+++ b/EbfEmployees/pom.xml
@@ -34,10 +34,10 @@
org.springframework.boot
spring-boot-starter-web
-
- org.flywaydb
- flyway-core
-
+
+
+
+
com.h2database
h2
@@ -106,7 +106,7 @@
3
true
- -Xmx1024m -XX:MaxPermSize=256m
+ -Xmx1024m
diff --git a/EbfEmployees/src/main/java/com/itekako/EbfEmployees/EbfEmployeesApplication.java b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/EbfEmployeesApplication.java
index 0d8fc1a..d1b5e47 100644
--- a/EbfEmployees/src/main/java/com/itekako/EbfEmployees/EbfEmployeesApplication.java
+++ b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/EbfEmployeesApplication.java
@@ -1,7 +1,9 @@
package com.itekako.EbfEmployees;
import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.transaction.annotation.EnableTransactionManagement;
diff --git a/EbfEmployees/src/main/java/com/itekako/EbfEmployees/auth/DatabaseFilter.java b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/auth/DatabaseFilter.java
new file mode 100644
index 0000000..69f285f
--- /dev/null
+++ b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/auth/DatabaseFilter.java
@@ -0,0 +1,27 @@
+package com.itekako.EbfEmployees.auth;
+
+import org.springframework.core.annotation.Order;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Order(10000)
+public class DatabaseFilter extends OncePerRequestFilter {
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+ String database = request.getHeader("Selected-Database");
+ if(database == null){
+ filterChain.doFilter (request,response);
+ return;
+ }
+ TenantAuthentificationToken authentication = (TenantAuthentificationToken) SecurityContextHolder.getContext().getAuthentication();
+ authentication.setDatabase(database);
+ filterChain.doFilter (request,response);
+ }
+}
diff --git a/EbfEmployees/src/main/java/com/itekako/EbfEmployees/auth/JwtFilter.java b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/auth/JwtFilter.java
index b8f7f7f..f3b5a12 100644
--- a/EbfEmployees/src/main/java/com/itekako/EbfEmployees/auth/JwtFilter.java
+++ b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/auth/JwtFilter.java
@@ -63,7 +63,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
roles.add(new SimpleGrantedAuthority("ROLE_" + role.asString()));
}
SecurityContextHolder.getContext().setAuthentication(
- new UsernamePasswordAuthenticationToken(subject,null, roles));
+ new TenantAuthentificationToken(subject, roles));
super.doFilterInternal(request, response, chain);
}
}
diff --git a/EbfEmployees/src/main/java/com/itekako/EbfEmployees/auth/TenantAuthentificationToken.java b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/auth/TenantAuthentificationToken.java
new file mode 100644
index 0000000..041afbe
--- /dev/null
+++ b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/auth/TenantAuthentificationToken.java
@@ -0,0 +1,27 @@
+package com.itekako.EbfEmployees.auth;
+
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+
+import java.util.Collection;
+
+public class TenantAuthentificationToken extends UsernamePasswordAuthenticationToken {
+
+ private final String userId;
+ private String database;
+
+ public TenantAuthentificationToken(String userId,Collection extends GrantedAuthority> authorities) {
+ super(userId,null,authorities);
+ this.userId = userId;
+ }
+
+
+ public String getDatabase(){
+ return database;
+ }
+
+ public void setDatabase(String database){
+ this.database = database;
+ }
+}
diff --git a/EbfEmployees/src/main/java/com/itekako/EbfEmployees/configurations/SessionConfiguration.java b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/configurations/SessionConfiguration.java
new file mode 100644
index 0000000..d168f5a
--- /dev/null
+++ b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/configurations/SessionConfiguration.java
@@ -0,0 +1,11 @@
+package com.itekako.EbfEmployees.configurations;
+
+import org.hibernate.SessionFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SessionConfiguration {
+
+
+}
diff --git a/EbfEmployees/src/main/java/com/itekako/EbfEmployees/configurations/WebSecurityConfiguration.java b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/configurations/WebSecurityConfiguration.java
index 69a75de..e129ae4 100644
--- a/EbfEmployees/src/main/java/com/itekako/EbfEmployees/configurations/WebSecurityConfiguration.java
+++ b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/configurations/WebSecurityConfiguration.java
@@ -1,5 +1,6 @@
package com.itekako.EbfEmployees.configurations;
+import com.itekako.EbfEmployees.auth.DatabaseFilter;
import com.itekako.EbfEmployees.auth.JwtFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
@@ -23,9 +24,9 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/swagger-ui.html", "/api-docs/**", "/webjars/**", "/swagger-ui/**", "/v3/api-docs/**").permitAll() //allow swagger
- .antMatchers("/api/**").hasRole("admin").anyRequest().authenticated()
+ .antMatchers("/api/**").authenticated()
.and().csrf().disable().cors()
- .and().addFilter(new JwtFilter(authenticationManager(), authConfiguration));
+ .and().addFilter(new JwtFilter(authenticationManager(), authConfiguration)).addFilterAfter(new DatabaseFilter(),JwtFilter.class);
}
@Bean
diff --git a/EbfEmployees/src/main/java/com/itekako/EbfEmployees/controllers/CompanyController.java b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/controllers/CompanyController.java
index 1ed81e8..37c789d 100644
--- a/EbfEmployees/src/main/java/com/itekako/EbfEmployees/controllers/CompanyController.java
+++ b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/controllers/CompanyController.java
@@ -83,4 +83,5 @@ public ResponseEntity generateEmployees(@PathVariable Long id) throws ResourceNo
employeeService.generateEmployees(id);
return ResponseEntity.noContent().build();
}
+
}
diff --git a/EbfEmployees/src/main/java/com/itekako/EbfEmployees/database/CurrentTenantIdentifierResolverImpl.java b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/database/CurrentTenantIdentifierResolverImpl.java
new file mode 100644
index 0000000..96d1145
--- /dev/null
+++ b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/database/CurrentTenantIdentifierResolverImpl.java
@@ -0,0 +1,37 @@
+package com.itekako.EbfEmployees.database;
+
+import com.itekako.EbfEmployees.auth.TenantAuthentificationToken;
+import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.ScopedProxyMode;
+import org.springframework.security.authentication.AnonymousAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
+public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {
+
+
+ @Override
+ public String resolveCurrentTenantIdentifier() {
+ SecurityContext context = SecurityContextHolder.getContext();
+ if(context.getAuthentication() == null)return "admin";
+ Authentication authentication = context.getAuthentication();
+ if(authentication instanceof AnonymousAuthenticationToken){
+ return "admin";
+ }
+ return ((TenantAuthentificationToken) authentication).getDatabase();
+ }
+
+ @Override
+ public boolean validateExistingCurrentSessions() {
+ return true;
+ }
+}
diff --git a/EbfEmployees/src/main/java/com/itekako/EbfEmployees/database/MapMultiTenantConnectionProvider.java b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/database/MapMultiTenantConnectionProvider.java
new file mode 100644
index 0000000..9633242
--- /dev/null
+++ b/EbfEmployees/src/main/java/com/itekako/EbfEmployees/database/MapMultiTenantConnectionProvider.java
@@ -0,0 +1,46 @@
+package com.itekako.EbfEmployees.database;
+
+import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
+import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider;
+import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+@Component
+public class MapMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider {
+
+ private Map connectionProviderMap
+ = new HashMap<>();
+
+ public MapMultiTenantConnectionProvider() throws IOException {
+ initConnectionProviderForTenant("user");
+ initConnectionProviderForTenant("admin");
+ }
+
+ @Override
+ protected ConnectionProvider getAnyConnectionProvider() {
+ return connectionProviderMap.values()
+ .iterator()
+ .next();
+ }
+
+ @Override
+ protected ConnectionProvider selectConnectionProvider(String s) {
+ return connectionProviderMap.get(s);
+ }
+
+ private void initConnectionProviderForTenant(String tenantId)
+ throws IOException {
+ Properties properties = new Properties();
+ properties.load(getClass().getResourceAsStream(
+ String.format("/hibernate-database-%s.properties", tenantId)));
+ DriverManagerConnectionProviderImpl connectionProvider
+ = new DriverManagerConnectionProviderImpl();
+ connectionProvider.configure(properties);
+ this.connectionProviderMap.put(tenantId, connectionProvider);
+ }
+}
diff --git a/EbfEmployees/src/main/resources/application.properties b/EbfEmployees/src/main/resources/application.properties
index c77274b..32ffd8f 100644
--- a/EbfEmployees/src/main/resources/application.properties
+++ b/EbfEmployees/src/main/resources/application.properties
@@ -1,14 +1,7 @@
logging.level.root=debug
-spring.datasource.initialization-mode=always
-spring.datasource.platform=postgres
-spring.datasource.url=jdbc:postgresql://localhost:5432/ebf_employees
-spring.datasource.username=ebf_db_user
-spring.datasource.password=ebf_db_password
-
-flyway.user=ebf_db_user
-flyway.password=ebf_db_password
-flyway.schemas=public
-flyway.url=jdbc:postgresql://localhost:5432/ebf_employees
+spring.jpa.properties.hibernate.multiTenancy=DATABASE
+spring.jpa.properties.hibernate.tenant_identifier_resolver=com.itekako.EbfEmployees.database.CurrentTenantIdentifierResolverImpl
+spring.jpa.properties.hibernate.multi_tenant_connection_provider=com.itekako.EbfEmployees.database.MapMultiTenantConnectionProvider
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
log4j.logger.org.springframework.transaction=INFO
diff --git a/EbfEmployees/src/main/resources/hibernate-database-admin.properties b/EbfEmployees/src/main/resources/hibernate-database-admin.properties
new file mode 100644
index 0000000..37f9801
--- /dev/null
+++ b/EbfEmployees/src/main/resources/hibernate-database-admin.properties
@@ -0,0 +1,4 @@
+hibernate.connection.driver_class=org.postgresql.Driver
+hibernate.connection.url=jdbc:postgresql://localhost:5432/ebf_employees2
+hibernate.connection.username=ebf_db_user2
+hibernate.connection.password=ebf_db_password2
\ No newline at end of file
diff --git a/EbfEmployees/src/main/resources/hibernate-database-user.properties b/EbfEmployees/src/main/resources/hibernate-database-user.properties
new file mode 100644
index 0000000..508f5b1
--- /dev/null
+++ b/EbfEmployees/src/main/resources/hibernate-database-user.properties
@@ -0,0 +1,4 @@
+hibernate.connection.driver_class=org.postgresql.Driver
+hibernate.connection.url=jdbc:postgresql://localhost:54322/ebf_employees1
+hibernate.connection.username=ebf_db_user1
+hibernate.connection.password=ebf_db_password1
\ No newline at end of file
diff --git a/EbfEmployees/src/test/resources/application.properties b/EbfEmployees/src/test/resources/application.properties
deleted file mode 100644
index ff6fab7..0000000
--- a/EbfEmployees/src/test/resources/application.properties
+++ /dev/null
@@ -1,12 +0,0 @@
-logging.level.root=info
-spring.datasource.initialization-mode=always
-spring.datasource.platform=h2
-spring.datasource.driver-class-name=org.h2.Driver
-spring.datasource.url=jdbc:h2:mem:ebf_db;DB_CLOSE_DELAY=-1
-spring.datasource.username=sa
-spring.datasource.password=sa
-
-spring.flyway.enabled=false
-spring.mvc.pathmatch.matching-strategy=ant_path_matcher
-jwtauth.lifeTime = 7200000
-jwtauth.secret = ebfSecret
\ No newline at end of file
diff --git a/EbfEmployeesFront/package-lock.json b/EbfEmployeesFront/package-lock.json
index 0ddca16..2a4ec1b 100644
--- a/EbfEmployeesFront/package-lock.json
+++ b/EbfEmployeesFront/package-lock.json
@@ -18,6 +18,7 @@
"@angular/platform-browser-dynamic": "~13.1.0",
"@angular/router": "~13.1.0",
"rxjs": "~7.4.0",
+ "sass": "^1.49.9",
"tslib": "^2.3.0",
"zone.js": "~0.11.4"
},
@@ -210,6 +211,22 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
+ "node_modules/@angular-devkit/build-angular/node_modules/sass": {
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.44.0.tgz",
+ "integrity": "sha512-0hLREbHFXGQqls/K8X+koeP+ogFRPF4ZqetVB19b7Cst9Er8cOR0rc6RU7MaI4W1JmUShd1BPgPoeqmmgMMYFw==",
+ "dev": true,
+ "dependencies": {
+ "chokidar": ">=3.0.0 <4.0.0",
+ "immutable": "^4.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=8.9.0"
+ }
+ },
"node_modules/@angular-devkit/build-webpack": {
"version": "0.1301.2",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1301.2.tgz",
@@ -2928,7 +2945,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
- "dev": true,
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
@@ -3239,7 +3255,6 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -3325,7 +3340,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
"dependencies": {
"fill-range": "^7.0.1"
},
@@ -3507,7 +3521,6 @@
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
- "dev": true,
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -5407,7 +5420,6 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -5571,7 +5583,6 @@
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
@@ -5684,7 +5695,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
"dependencies": {
"is-glob": "^4.0.1"
},
@@ -6060,8 +6070,7 @@
"node_modules/immutable": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz",
- "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==",
- "dev": true
+ "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw=="
},
"node_modules/import-fresh": {
"version": "3.3.0",
@@ -6279,7 +6288,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
"dependencies": {
"binary-extensions": "^2.0.0"
},
@@ -6333,7 +6341,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -6351,7 +6358,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
"dependencies": {
"is-extglob": "^2.1.1"
},
@@ -6378,7 +6384,6 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
"engines": {
"node": ">=0.12.0"
}
@@ -7756,7 +7761,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -8377,7 +8381,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
- "dev": true,
"engines": {
"node": ">=8.6"
},
@@ -10236,7 +10239,6 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
"dependencies": {
"picomatch": "^2.2.1"
},
@@ -10580,19 +10582,19 @@
"dev": true
},
"node_modules/sass": {
- "version": "1.44.0",
- "resolved": "https://registry.npmjs.org/sass/-/sass-1.44.0.tgz",
- "integrity": "sha512-0hLREbHFXGQqls/K8X+koeP+ogFRPF4ZqetVB19b7Cst9Er8cOR0rc6RU7MaI4W1JmUShd1BPgPoeqmmgMMYFw==",
- "dev": true,
+ "version": "1.49.9",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.9.tgz",
+ "integrity": "sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==",
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0",
- "immutable": "^4.0.0"
+ "immutable": "^4.0.0",
+ "source-map-js": ">=0.6.2 <2.0.0"
},
"bin": {
"sass": "sass.js"
},
"engines": {
- "node": ">=8.9.0"
+ "node": ">=12.0.0"
}
},
"node_modules/sass-loader": {
@@ -11017,7 +11019,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz",
"integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -11532,7 +11533,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
"dependencies": {
"is-number": "^7.0.0"
},
@@ -12403,6 +12403,16 @@
"dev": true
}
}
+ },
+ "sass": {
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.44.0.tgz",
+ "integrity": "sha512-0hLREbHFXGQqls/K8X+koeP+ogFRPF4ZqetVB19b7Cst9Er8cOR0rc6RU7MaI4W1JmUShd1BPgPoeqmmgMMYFw==",
+ "dev": true,
+ "requires": {
+ "chokidar": ">=3.0.0 <4.0.0",
+ "immutable": "^4.0.0"
+ }
}
}
},
@@ -14386,7 +14396,6 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
- "dev": true,
"requires": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
@@ -14616,8 +14625,7 @@
"binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
},
"bl": {
"version": "4.1.0",
@@ -14699,7 +14707,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
"requires": {
"fill-range": "^7.0.1"
}
@@ -14832,7 +14839,6 @@
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
- "dev": true,
"requires": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -16246,7 +16252,6 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
@@ -16370,7 +16375,6 @@
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
"optional": true
},
"function-bind": {
@@ -16449,7 +16453,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
"requires": {
"is-glob": "^4.0.1"
}
@@ -16742,8 +16745,7 @@
"immutable": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz",
- "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==",
- "dev": true
+ "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw=="
},
"import-fresh": {
"version": "3.3.0",
@@ -16914,7 +16916,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
"requires": {
"binary-extensions": "^2.0.0"
}
@@ -16946,8 +16947,7 @@
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
- "dev": true
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
},
"is-fullwidth-code-point": {
"version": "3.0.0",
@@ -16959,7 +16959,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
"requires": {
"is-extglob": "^2.1.1"
}
@@ -16979,8 +16978,7 @@
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
},
"is-path-cwd": {
"version": "2.2.0",
@@ -18007,8 +18005,7 @@
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
},
"normalize-range": {
"version": "0.1.2",
@@ -18479,8 +18476,7 @@
"picomatch": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
- "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
- "dev": true
+ "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw=="
},
"pify": {
"version": "2.3.0",
@@ -19877,7 +19873,6 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
"requires": {
"picomatch": "^2.2.1"
}
@@ -20133,13 +20128,13 @@
"dev": true
},
"sass": {
- "version": "1.44.0",
- "resolved": "https://registry.npmjs.org/sass/-/sass-1.44.0.tgz",
- "integrity": "sha512-0hLREbHFXGQqls/K8X+koeP+ogFRPF4ZqetVB19b7Cst9Er8cOR0rc6RU7MaI4W1JmUShd1BPgPoeqmmgMMYFw==",
- "dev": true,
+ "version": "1.49.9",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.9.tgz",
+ "integrity": "sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==",
"requires": {
"chokidar": ">=3.0.0 <4.0.0",
- "immutable": "^4.0.0"
+ "immutable": "^4.0.0",
+ "source-map-js": ">=0.6.2 <2.0.0"
}
},
"sass-loader": {
@@ -20475,8 +20470,7 @@
"source-map-js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz",
- "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==",
- "dev": true
+ "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA=="
},
"source-map-loader": {
"version": "3.0.0",
@@ -20851,7 +20845,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
"requires": {
"is-number": "^7.0.0"
}
diff --git a/EbfEmployeesFront/package.json b/EbfEmployeesFront/package.json
index de2f52b..78228a7 100644
--- a/EbfEmployeesFront/package.json
+++ b/EbfEmployeesFront/package.json
@@ -20,6 +20,7 @@
"@angular/platform-browser-dynamic": "~13.1.0",
"@angular/router": "~13.1.0",
"rxjs": "~7.4.0",
+ "sass": "^1.49.9",
"tslib": "^2.3.0",
"zone.js": "~0.11.4"
},
diff --git a/EbfEmployeesFront/src/app/app.component.html b/EbfEmployeesFront/src/app/app.component.html
index 29dbb20..277bd67 100644
--- a/EbfEmployeesFront/src/app/app.component.html
+++ b/EbfEmployeesFront/src/app/app.component.html
@@ -1,4 +1,6 @@
diff --git a/EbfEmployeesFront/src/app/app.component.ts b/EbfEmployeesFront/src/app/app.component.ts
index d2fce75..bd6faa0 100644
--- a/EbfEmployeesFront/src/app/app.component.ts
+++ b/EbfEmployeesFront/src/app/app.component.ts
@@ -1,4 +1,5 @@
import { Component } from '@angular/core';
+import { DatabaseSelectionService } from './services/database-selection.service';
@Component({
selector: 'app-root',
@@ -7,4 +8,11 @@ import { Component } from '@angular/core';
})
export class AppComponent {
title = 'EbfEmployeesFront';
+
+ constructor(private databaseSelectionService: DatabaseSelectionService){}
+
+ public selectDatabase(database: string): void {
+ this.databaseSelectionService.setDatabase(database)
+ }
}
+
diff --git a/EbfEmployeesFront/src/app/app.module.ts b/EbfEmployeesFront/src/app/app.module.ts
index 74ca723..422ca5c 100644
--- a/EbfEmployeesFront/src/app/app.module.ts
+++ b/EbfEmployeesFront/src/app/app.module.ts
@@ -31,6 +31,7 @@ import { CreateCompanyDialogComponent } from './components/dialogs/create-compan
import { CreateEmployeeDialogComponent } from './components/dialogs/create-employee-dialog/create-employee-dialog.component';
import { EmployeeDetailsComponent } from './components/employee-details/employee-details.component'
import { MatPaginatorModule } from '@angular/material/paginator';
+import { MatSortModule } from '@angular/material/sort';
@NgModule({
declarations: [
@@ -65,7 +66,8 @@ import { MatPaginatorModule } from '@angular/material/paginator';
MatSnackBarModule,
MatTableModule,
MatIconModule,
- MatPaginatorModule
+ MatPaginatorModule,
+ MatSortModule
],
providers: [{ provide: HTTP_INTERCEPTORS, useClass: HttpInterceptorService, multi: true }],
bootstrap: [AppComponent],
diff --git a/EbfEmployeesFront/src/app/services/database-selection.service.ts b/EbfEmployeesFront/src/app/services/database-selection.service.ts
new file mode 100644
index 0000000..04e9ee5
--- /dev/null
+++ b/EbfEmployeesFront/src/app/services/database-selection.service.ts
@@ -0,0 +1,12 @@
+import { Injectable } from "@angular/core";
+
+@Injectable({ providedIn: 'root' })
+export class DatabaseSelectionService {
+ public setDatabase(database: string): void {
+ sessionStorage.setItem('database', database)
+ }
+
+ public getDatabase(): string | null {
+ return sessionStorage.getItem('database');
+ }
+}
\ No newline at end of file
diff --git a/EbfEmployeesFront/src/app/services/http-interceptor.service.ts b/EbfEmployeesFront/src/app/services/http-interceptor.service.ts
index da53a7f..c9040d7 100644
--- a/EbfEmployeesFront/src/app/services/http-interceptor.service.ts
+++ b/EbfEmployeesFront/src/app/services/http-interceptor.service.ts
@@ -1,16 +1,17 @@
import { AccessTokenModel } from './../models/access-token.model';
import { LoginDialogComponent } from './../components/login-dialog/login-dialog.component';
-import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http";
+import { HttpEvent, HttpHandler, HttpHeaders, HttpInterceptor, HttpRequest } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
import { catchError, filter, Observable, switchMap, take, throwError } from "rxjs";
import { StorageService } from "./storage.service";
import { MatSnackBar } from '@angular/material/snack-bar';
+import { DatabaseSelectionService } from './database-selection.service';
@Injectable({ providedIn: 'root' })
export class HttpInterceptorService implements HttpInterceptor {
- constructor(private storageService: StorageService, private matDialog: MatDialog, private snackBar: MatSnackBar) { }
+ constructor(private storageService: StorageService, private matDialog: MatDialog, private snackBar: MatSnackBar, private databaseSelectionService: DatabaseSelectionService) { }
intercept(req: HttpRequest, next: HttpHandler): Observable> {
return next.handle(this.cloneRequestWithAccessToken(req)).pipe(catchError(e => {
@@ -36,13 +37,17 @@ export class HttpInterceptorService implements HttpInterceptor {
cloneRequestWithAccessToken(request: HttpRequest): HttpRequest {
if (this.storageService.getAccessToken() != null) {
-
+ let httph = new HttpHeaders({'Authorization': `Bearer ${this.storageService.getAccessToken()}`});
+ if(this.databaseSelectionService.getDatabase() != null){
+ let database = this.databaseSelectionService.getDatabase() as string;
+ httph = new HttpHeaders({'Authorization': `Bearer ${this.storageService.getAccessToken()}`,
+ 'Selected-Database': database});
+ }
+
return request.clone(
{
withCredentials: true,
- setHeaders: {
- Authorization: `Bearer ${this.storageService.getAccessToken()}`
- }
+ headers: httph
}
)
} else {
diff --git a/db-test.yml b/db-test.yml
new file mode 100644
index 0000000..8e91199
--- /dev/null
+++ b/db-test.yml
@@ -0,0 +1,25 @@
+version: '2'
+
+services:
+
+ db1:
+ image: 'postgres:13.1-alpine'
+ container_name: db1
+ environment:
+ - POSTGRES_DB=ebf_employees1
+ - POSTGRES_USER=ebf_db_user1
+ - POSTGRES_PASSWORD=ebf_db_password1
+ - APP_DB_NAME=ebf_employees1
+ ports:
+ - "54322:5432"
+
+ db2:
+ image: 'postgres:13.1-alpine'
+ container_name: db2
+ environment:
+ - POSTGRES_DB=ebf_employees2
+ - POSTGRES_USER=ebf_db_user2
+ - POSTGRES_PASSWORD=ebf_db_password2
+ - APP_DB_NAME=ebf_employees2
+ ports:
+ - "5432:5432"