TSK-177 Add authentication and login page for taskana spring rest example
This commit is contained in:
parent
66bdaab7cf
commit
99b882f867
29
rest/pom.xml
29
rest/pom.xml
|
@ -1,19 +1,20 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>pro.taskana</groupId>
|
||||
<artifactId>taskana-rest-parent</artifactId>
|
||||
<version>0.1.4-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>pro.taskana</groupId>
|
||||
<artifactId>taskana-rest-parent</artifactId>
|
||||
<version>0.1.4-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<description>This pom is parent to all taskana rest modules and serves the common build.</description>
|
||||
<description>This pom is parent to all taskana rest modules and serves the common build.</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>taskana-rest-spring</module>
|
||||
<module>taskana-rest-spring-example</module>
|
||||
</modules>
|
||||
<modules>
|
||||
<module>taskana-rest-spring</module>
|
||||
<module>../web</module>
|
||||
<module>taskana-rest-spring-example</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
|
@ -52,7 +52,16 @@
|
|||
<artifactId>h2</artifactId>
|
||||
<version>1.4.197</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
Since taskana-web packs its content in /static, we do not have to unpack it again.
|
||||
However, when any local change has to be done to that folder you have to copy
|
||||
target/classes/static manually from taskana-web.
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>pro.taskana</groupId>
|
||||
<artifactId>taskana-web</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- Tests -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
@ -60,7 +69,6 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
@ -69,4 +77,5 @@
|
|||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package pro.taskana.rest.controllers;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@Controller
|
||||
public class ViewController {
|
||||
@RequestMapping({ "/administration*/**", "/workplace*/**", "/monitor*/**" })
|
||||
public String index() {
|
||||
return "forward:/index.html";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package pro.taskana.rest.models;
|
||||
|
||||
public class User {
|
||||
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -10,13 +10,14 @@ import javax.security.auth.callback.PasswordCallback;
|
|||
import javax.security.auth.login.LoginException;
|
||||
import javax.security.auth.spi.LoginModule;
|
||||
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import pro.taskana.security.GroupPrincipal;
|
||||
import pro.taskana.security.UserPrincipal;
|
||||
|
||||
/**
|
||||
* TODO.
|
||||
*/
|
||||
public class SampleLoginModule implements LoginModule {
|
||||
public class SampleLoginModule extends UsernamePasswordAuthenticationFilter implements LoginModule {
|
||||
|
||||
private NameCallback nameCallback;
|
||||
|
||||
|
@ -24,6 +25,7 @@ public class SampleLoginModule implements LoginModule {
|
|||
|
||||
private Subject subject;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean abort() throws LoginException {
|
||||
return true;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package pro.taskana.rest.security;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -11,13 +12,16 @@ import org.springframework.security.authentication.jaas.JaasAuthenticationProvid
|
|||
import org.springframework.security.authentication.jaas.JaasNameCallbackHandler;
|
||||
import org.springframework.security.authentication.jaas.JaasPasswordCallbackHandler;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
|
@ -28,26 +32,43 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
|
|||
@EnableWebSecurity
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Value("${devMode}")
|
||||
private boolean devMode;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
|
||||
http.csrf()
|
||||
.disable()
|
||||
.authenticationProvider(jaasAuthProvider())
|
||||
.authorizeRequests()
|
||||
.antMatchers(HttpMethod.GET, "/**")
|
||||
.authenticated()
|
||||
.and()
|
||||
.httpBasic()
|
||||
.and()
|
||||
.addFilter(new JaasApiIntegrationFilter());
|
||||
.disable()
|
||||
.authenticationProvider(jaasAuthProvider())
|
||||
.authorizeRequests()
|
||||
.antMatchers(HttpMethod.GET, "/**")
|
||||
.authenticated()
|
||||
.and()
|
||||
.httpBasic()
|
||||
.and()
|
||||
.addFilter(new JaasApiIntegrationFilter());
|
||||
|
||||
if (devMode) {
|
||||
return;
|
||||
}
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.permitAll()
|
||||
.and()
|
||||
.logout()
|
||||
.permitAll();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JaasAuthenticationProvider jaasAuthProvider() {
|
||||
JaasAuthenticationProvider authenticationProvider = new JaasAuthenticationProvider();
|
||||
authenticationProvider.setAuthorityGranters(new AuthorityGranter[] {new SampleRoleGranter()});
|
||||
authenticationProvider.setCallbackHandlers(new JaasAuthenticationCallbackHandler[] {
|
||||
new JaasNameCallbackHandler(), new JaasPasswordCallbackHandler()});
|
||||
authenticationProvider.setAuthorityGranters(new AuthorityGranter[]{new SampleRoleGranter()});
|
||||
authenticationProvider.setCallbackHandlers(new JaasAuthenticationCallbackHandler[]{
|
||||
new JaasNameCallbackHandler(), new JaasPasswordCallbackHandler()});
|
||||
authenticationProvider.setLoginContextName("taskana");
|
||||
authenticationProvider.setLoginConfig(new ClassPathResource("pss_jaas.config"));
|
||||
return authenticationProvider;
|
||||
|
@ -72,6 +93,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
config.addAllowedOrigin("*");
|
||||
config.addAllowedHeader("*");
|
||||
config.addAllowedMethod("*");
|
||||
config.addAllowedMethod("POST");
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
|
||||
bean.setOrder(0);
|
||||
|
|
|
@ -4,3 +4,4 @@ datasource.url=jdbc:h2:mem:taskana;IGNORECASE=TRUE;LOCK_MODE=0;INIT=CREATE SCHEM
|
|||
datasource.driverClassName=org.h2.Driver
|
||||
datasource.username=sa
|
||||
datasource.password=sa
|
||||
devMode=false
|
|
@ -0,0 +1,27 @@
|
|||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Custom Login Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<form name="f" th:action="@{/login}" method="post">
|
||||
<fieldset>
|
||||
<legend>Please Login</legend>
|
||||
<div th:if="${param.error}" class="alert alert-error">
|
||||
Invalid username and password.
|
||||
</div>
|
||||
<div th:if="${param.logout}" class="alert alert-success">
|
||||
You have been logged out.
|
||||
</div>
|
||||
<label for="username">Username</label>
|
||||
<input type="text" id="username" name="username"/>
|
||||
<label for="password">Password</label>
|
||||
<input type="password" id="password" name="password"/>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn">Log in</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -39,7 +39,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
import pro.taskana.rest.resource.ClassificationSummaryResource;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"devMode=true"})
|
||||
@Import(RestConfiguration.class)
|
||||
public class ClassificationControllerIntTest {
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
import pro.taskana.rest.resource.TaskSummaryResource;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"devMode=true"})
|
||||
@Import(RestConfiguration.class)
|
||||
public class TaskControllerIntTest {
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ import pro.taskana.TaskanaRole;
|
|||
import pro.taskana.rest.resource.TaskanaUserInfoResource;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"devMode=true"})
|
||||
@Import(RestConfiguration.class)
|
||||
public class TaskanaEngineControllerIntTest {
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ import pro.taskana.rest.resource.DistributionTargetResource;
|
|||
import pro.taskana.rest.resource.WorkbasketSummaryResource;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"devMode=true"})
|
||||
@Import(RestConfiguration.class)
|
||||
public class WorkbasketControllerIntTest {
|
||||
|
||||
|
|
|
@ -1221,7 +1221,17 @@
|
|||
"boom": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
|
||||
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8="
|
||||
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
|
||||
"requires": {
|
||||
"hoek": "2.16.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"hoek": {
|
||||
"version": "2.16.3",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
|
||||
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
|
||||
}
|
||||
}
|
||||
},
|
||||
"bootstrap": {
|
||||
"version": "3.3.7",
|
||||
|
@ -5168,7 +5178,15 @@
|
|||
"requires": {
|
||||
"boom": "2.10.1",
|
||||
"cryptiles": "2.0.5",
|
||||
"hoek": "2.16.3",
|
||||
"sntp": "1.0.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"hoek": {
|
||||
"version": "2.16.3",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
|
||||
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
|
||||
}
|
||||
}
|
||||
},
|
||||
"he": {
|
||||
|
@ -10004,7 +10022,17 @@
|
|||
"sntp": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
|
||||
"integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg="
|
||||
"integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
|
||||
"requires": {
|
||||
"hoek": "2.16.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"hoek": {
|
||||
"version": "2.16.3",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
|
||||
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
|
||||
}
|
||||
}
|
||||
},
|
||||
"socket.io": {
|
||||
"version": "2.0.4",
|
||||
|
|
|
@ -41,7 +41,7 @@ const routes: Routes = [
|
|||
{
|
||||
path: 'classifications',
|
||||
component: MasterAndDetailComponent,
|
||||
canActivate: [DomainGuard],
|
||||
canActivate: [DomainGuard],
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
|
|
|
@ -3,7 +3,6 @@ import { CommonModule } from '@angular/common';
|
|||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { Ng2AutoCompleteModule } from 'ng2-auto-complete';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { AlertModule } from 'ngx-bootstrap';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
|
@ -45,11 +44,10 @@ const MODULES = [
|
|||
CommonModule,
|
||||
FormsModule,
|
||||
Ng2AutoCompleteModule,
|
||||
HttpClientModule,
|
||||
AngularSvgIconModule,
|
||||
AlertModule,
|
||||
SharedModule,
|
||||
AdministrationRoutingModule,
|
||||
AdministrationRoutingModule
|
||||
];
|
||||
|
||||
const DECLARATIONS = [
|
||||
|
|
|
@ -4,23 +4,19 @@ import { Injectable } from '@angular/core';
|
|||
import { environment } from 'environments/environment';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { ReplaySubject } from 'rxjs/ReplaySubject';
|
||||
|
||||
@Injectable()
|
||||
export class ClassificationCategoriesService {
|
||||
|
||||
private url = environment.taskanaRestUrl + '/v1/classification-categories';
|
||||
httpOptions = {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
|
||||
})
|
||||
};
|
||||
private dataObs$ = new ReplaySubject<Array<string>>(1);
|
||||
|
||||
constructor(private httpClient: HttpClient) { }
|
||||
constructor(
|
||||
private httpClient: HttpClient) { }
|
||||
|
||||
getCategories(forceRefresh = false): Observable<Array<string>> {
|
||||
if (!this.dataObs$.observers.length || forceRefresh) {
|
||||
this.httpClient.get<Array<string>>(this.url, this.httpOptions).subscribe(
|
||||
this.httpClient.get<Array<string>>(this.url).subscribe(
|
||||
data => this.dataObs$.next(data),
|
||||
error => {
|
||||
this.dataObs$.error(error);
|
||||
|
|
|
@ -11,21 +11,16 @@ import { TaskanaDate } from 'app/shared/util/taskana.date';
|
|||
export class ClassificationDefinitionService {
|
||||
|
||||
url = environment.taskanaRestUrl + '/v1/classificationdefinitions';
|
||||
|
||||
httpOptions = {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
|
||||
})
|
||||
};
|
||||
|
||||
constructor(private httpClient: HttpClient, private alertService: AlertService) {
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private alertService: AlertService
|
||||
) {
|
||||
}
|
||||
|
||||
// GET
|
||||
exportClassifications(domain: string) {
|
||||
domain = (domain === '' ? '' : '?domain=' + domain);
|
||||
this.httpClient.get<ClassificationDefinition[]>(this.url + domain, this.httpOptions)
|
||||
this.httpClient.get<ClassificationDefinition[]>(this.url + domain)
|
||||
.subscribe(
|
||||
response => saveAs(new Blob([JSON.stringify(response)], { type: 'text/plain;charset=utf-8' }),
|
||||
'Classifications_' + TaskanaDate.getDate() + '.json')
|
||||
|
@ -36,7 +31,7 @@ export class ClassificationDefinitionService {
|
|||
// TODO handle error
|
||||
importClassifications(classifications: any) {
|
||||
this.httpClient.post(this.url + '/import',
|
||||
JSON.parse(classifications), this.httpOptions).subscribe(
|
||||
JSON.parse(classifications)).subscribe(
|
||||
classificationsUpdated => this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'Import was successful')),
|
||||
error => this.alertService.triggerAlert(new AlertModel(AlertType.DANGER, 'Import was not successful'))
|
||||
);
|
||||
|
|
|
@ -9,22 +9,17 @@ import { ReplaySubject } from 'rxjs/ReplaySubject';
|
|||
@Injectable()
|
||||
export class ClassificationTypesService {
|
||||
private url = environment.taskanaRestUrl + '/v1/classification-types';
|
||||
httpOptions = {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
|
||||
})
|
||||
};
|
||||
private classificationTypeSelectedValue = 'TASK';
|
||||
private classificationTypeSelected = new BehaviorSubject<string>(this.classificationTypeSelectedValue);
|
||||
private dataObs$ = new ReplaySubject<Array<string>>(1);
|
||||
|
||||
constructor(private httpClient: HttpClient) { }
|
||||
constructor(private httpClient: HttpClient
|
||||
) { }
|
||||
|
||||
getClassificationTypes(forceRefresh = false): Observable<Array<string>> {
|
||||
|
||||
if (!this.dataObs$.observers.length || forceRefresh) {
|
||||
this.httpClient.get<Array<string>>(this.url, this.httpOptions).subscribe(
|
||||
this.httpClient.get<Array<string>>(this.url).subscribe(
|
||||
data => this.dataObs$.next(data),
|
||||
error => {
|
||||
this.dataObs$.error(error);
|
||||
|
|
|
@ -22,13 +22,6 @@ export class ClassificationsService {
|
|||
private classificationSelected = new Subject<string>();
|
||||
private classificationSaved = new Subject<number>();
|
||||
|
||||
httpOptions = {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
|
||||
})
|
||||
};
|
||||
|
||||
private classificationTypes: Array<string>;
|
||||
|
||||
constructor(
|
||||
|
@ -42,8 +35,7 @@ export class ClassificationsService {
|
|||
return this.domainService.getSelectedDomain().mergeMap(domain => {
|
||||
const classificationTypes = this.classificationTypeService.getSelectedClassificationType();
|
||||
return this.getClassificationObservable(this.httpClient.get<ClassificationResource>(
|
||||
`${environment.taskanaRestUrl}/v1/classifications/?domain=${domain}`,
|
||||
this.httpOptions));
|
||||
`${environment.taskanaRestUrl}/v1/classifications/?domain=${domain}`));
|
||||
|
||||
}).do(() => {
|
||||
this.domainService.domainChangedComplete();
|
||||
|
@ -52,7 +44,7 @@ export class ClassificationsService {
|
|||
|
||||
// GET
|
||||
getClassification(id: string): Observable<ClassificationDefinition> {
|
||||
return this.httpClient.get<ClassificationDefinition>(`${environment.taskanaRestUrl}/v1/classifications/${id}`, this.httpOptions)
|
||||
return this.httpClient.get<ClassificationDefinition>(`${environment.taskanaRestUrl}/v1/classifications/${id}`)
|
||||
.do((classification: ClassificationDefinition) => {
|
||||
if (classification) {
|
||||
this.classificationTypeService.selectClassificationType(classification.type);
|
||||
|
@ -63,18 +55,17 @@ export class ClassificationsService {
|
|||
|
||||
// POST
|
||||
postClassification(classification: Classification): Observable<Classification> {
|
||||
return this.httpClient.post<Classification>(`${environment.taskanaRestUrl}/v1/classifications`, classification,
|
||||
this.httpOptions);
|
||||
return this.httpClient.post<Classification>(`${environment.taskanaRestUrl}/v1/classifications`, classification);
|
||||
}
|
||||
|
||||
// PUT
|
||||
putClassification(url: string, classification: Classification): Observable<Classification> {
|
||||
return this.httpClient.put<Classification>(url, classification, this.httpOptions);
|
||||
return this.httpClient.put<Classification>(url, classification);
|
||||
}
|
||||
|
||||
// DELETE
|
||||
deleteClassification(url: string): Observable<string> {
|
||||
return this.httpClient.delete<string>(url, this.httpOptions);
|
||||
return this.httpClient.delete<string>(url);
|
||||
}
|
||||
|
||||
// #region "Service extras"
|
||||
|
|
|
@ -1,37 +1,29 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
import {HttpClient, HttpHeaders} from '@angular/common/http';
|
||||
import {environment} from 'app/../environments/environment';
|
||||
import {saveAs} from 'file-saver/FileSaver';
|
||||
import {AlertService} from 'app/services/alert/alert.service';
|
||||
import {WorkbasketDefinition} from 'app/models/workbasket-definition';
|
||||
import {AlertModel, AlertType} from 'app/models/alert';
|
||||
import {TaskanaDate} from 'app/shared/util/taskana.date';
|
||||
import {ErrorModel} from 'app/models/modal-error';
|
||||
import {ErrorModalService} from 'app/services/errorModal/error-modal.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { environment } from 'app/../environments/environment';
|
||||
import { saveAs } from 'file-saver/FileSaver';
|
||||
import { AlertService } from 'app/services/alert/alert.service';
|
||||
import { WorkbasketDefinition } from 'app/models/workbasket-definition';
|
||||
import { AlertModel, AlertType } from 'app/models/alert';
|
||||
import { TaskanaDate } from 'app/shared/util/taskana.date';
|
||||
import { ErrorModel } from 'app/models/modal-error';
|
||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class WorkbasketDefinitionService {
|
||||
url: string = environment.taskanaRestUrl + '/v1/workbasketdefinitions';
|
||||
|
||||
httpOptions = {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
constructor(private httpClient: HttpClient, private alertService: AlertService,
|
||||
private errorModalService: ErrorModalService) {
|
||||
}
|
||||
private errorModalService: ErrorModalService) {
|
||||
}
|
||||
|
||||
// GET
|
||||
exportWorkbaskets(domain: string) {
|
||||
domain = (domain === '' ? '' : '?domain=' + domain);
|
||||
this.httpClient.get<WorkbasketDefinition[]>(this.url + domain, this.httpOptions).subscribe(
|
||||
this.httpClient.get<WorkbasketDefinition[]>(this.url + domain).subscribe(
|
||||
response => {
|
||||
saveAs(new Blob([JSON.stringify(response)], {type: 'text/plain;charset=utf-8'}),
|
||||
saveAs(new Blob([JSON.stringify(response)], { type: 'text/plain;charset=utf-8' }),
|
||||
'Workbaskets_' + TaskanaDate.getDate() + '.json');
|
||||
}
|
||||
);
|
||||
|
@ -40,10 +32,10 @@ export class WorkbasketDefinitionService {
|
|||
// POST
|
||||
importWorkbasketDefinitions(workbasketDefinitions: any) {
|
||||
this.httpClient.post(environment.taskanaRestUrl + '/v1/workbasketdefinitions/import',
|
||||
JSON.parse(workbasketDefinitions), this.httpOptions).subscribe(
|
||||
workbasketsUpdated => this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'Import was successful')),
|
||||
error => this.errorModalService.triggerError(new ErrorModel(
|
||||
`There was an error importing workbaskets`, error.message))
|
||||
);
|
||||
JSON.parse(workbasketDefinitions)).subscribe(
|
||||
workbasketsUpdated => this.alertService.triggerAlert(new AlertModel(AlertType.SUCCESS, 'Import was successful')),
|
||||
error => this.errorModalService.triggerError(new ErrorModel(
|
||||
`There was an error importing workbaskets`, error.message))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
import { environment } from 'app/../environments/environment';
|
||||
|
@ -43,12 +43,6 @@ export class WorkbasketService {
|
|||
// Domain
|
||||
readonly DOMAIN = 'domain';
|
||||
|
||||
httpOptions = {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
|
||||
})
|
||||
};
|
||||
|
||||
page = 1;
|
||||
pageSize = 9;
|
||||
|
@ -86,7 +80,7 @@ export class WorkbasketService {
|
|||
`${environment.taskanaRestUrl}/v1/workbaskets/${this.getWorkbasketSummaryQueryParameters(
|
||||
sortBy, order, name,
|
||||
nameLike, descLike, owner, ownerLike, type, key, keyLike, requiredPermission,
|
||||
!allPages ? this.page : undefined, !allPages ? this.pageSize : undefined, domain)}`, this.httpOptions)
|
||||
!allPages ? this.page : undefined, !allPages ? this.pageSize : undefined, domain)}`)
|
||||
.do(workbaskets => {
|
||||
return workbaskets;
|
||||
});
|
||||
|
@ -96,51 +90,50 @@ export class WorkbasketService {
|
|||
}
|
||||
// GET
|
||||
getWorkBasket(id: string): Observable<Workbasket> {
|
||||
return this.httpClient.get<Workbasket>(`${environment.taskanaRestUrl}/v1/workbaskets/${id}`, this.httpOptions);
|
||||
return this.httpClient.get<Workbasket>(`${environment.taskanaRestUrl}/v1/workbaskets/${id}`);
|
||||
}
|
||||
// POST
|
||||
createWorkbasket(workbasket: Workbasket): Observable<Workbasket> {
|
||||
return this.httpClient
|
||||
.post<Workbasket>(`${environment.taskanaRestUrl}/v1/workbaskets`, workbasket, this.httpOptions);
|
||||
.post<Workbasket>(`${environment.taskanaRestUrl}/v1/workbaskets`, workbasket);
|
||||
|
||||
}
|
||||
// PUT
|
||||
updateWorkbasket(url: string, workbasket: Workbasket): Observable<Workbasket> {
|
||||
return this.httpClient
|
||||
.put<Workbasket>(url, workbasket, this.httpOptions)
|
||||
.put<Workbasket>(url, workbasket)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
// DELETE
|
||||
deleteWorkbasket(url: string) {
|
||||
return this.httpClient.delete(url, this.httpOptions);
|
||||
return this.httpClient.delete(url);
|
||||
}
|
||||
// GET
|
||||
getWorkBasketAccessItems(url: string): Observable<WorkbasketAccessItemsResource> {
|
||||
return this.httpClient.get<WorkbasketAccessItemsResource>(url, this.httpOptions);
|
||||
return this.httpClient.get<WorkbasketAccessItemsResource>(url);
|
||||
}
|
||||
// POST
|
||||
createWorkBasketAccessItem(url: string, workbasketAccessItem: WorkbasketAccessItems): Observable<WorkbasketAccessItems> {
|
||||
return this.httpClient.post<WorkbasketAccessItems>(url, workbasketAccessItem, this.httpOptions);
|
||||
return this.httpClient.post<WorkbasketAccessItems>(url, workbasketAccessItem);
|
||||
}
|
||||
// PUT
|
||||
updateWorkBasketAccessItem(url: string, workbasketAccessItem: Array<WorkbasketAccessItems>): Observable<string> {
|
||||
return this.httpClient.put<string>(url,
|
||||
workbasketAccessItem,
|
||||
this.httpOptions);
|
||||
workbasketAccessItem);
|
||||
}
|
||||
// GET
|
||||
getWorkBasketsDistributionTargets(url: string): Observable<WorkbasketDistributionTargetsResource> {
|
||||
return this.httpClient.get<WorkbasketDistributionTargetsResource>(url, this.httpOptions);
|
||||
return this.httpClient.get<WorkbasketDistributionTargetsResource>(url);
|
||||
}
|
||||
|
||||
// PUT
|
||||
updateWorkBasketsDistributionTargets(url: string, distributionTargetsIds: Array<string>):
|
||||
Observable<WorkbasketDistributionTargetsResource> {
|
||||
return this.httpClient.put<WorkbasketDistributionTargetsResource>(url, distributionTargetsIds, this.httpOptions);
|
||||
return this.httpClient.put<WorkbasketDistributionTargetsResource>(url, distributionTargetsIds);
|
||||
}
|
||||
// DELETE
|
||||
removeDistributionTarget(url: string) {
|
||||
return this.httpClient.delete<string>(url, this.httpOptions);
|
||||
return this.httpClient.delete<string>(url);
|
||||
}
|
||||
|
||||
|
||||
|
@ -214,5 +207,6 @@ export class WorkbasketService {
|
|||
return Observable.throw(errMsg);
|
||||
}
|
||||
|
||||
|
||||
// #endregion
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="container-scrollable">
|
||||
<taskana-spinner [isRunning]="requestInProgress" ></taskana-spinner>
|
||||
<taskana-no-access *ngIf="!requestInProgress && (!hasPermission && !workbasket || !workbasket && selectedId)"></taskana-no-access>
|
||||
<taskana-no-access *ngIf="!requestInProgress && (!workbasket || !workbasket && selectedId)"></taskana-no-access>
|
||||
<div id="workbasket-details" *ngIf="workbasket && !requestInProgress">
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li *ngIf="showDetail" class="visible-xs visible-sm hidden">
|
||||
|
|
|
@ -20,7 +20,6 @@ import { LinksWorkbasketSummary } from 'app/models/links-workbasket-summary';
|
|||
|
||||
import { WorkbasketService } from 'app/administration/services/workbasket/workbasket.service';
|
||||
import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-detail.service';
|
||||
import { PermissionService } from 'app/services/permission/permission.service';
|
||||
import { AlertService } from 'app/services/alert/alert.service';
|
||||
import { SavingWorkbasketService } from 'app/administration/services/saving-workbaskets/saving-workbaskets.service';
|
||||
|
||||
|
@ -79,7 +78,7 @@ describe('WorkbasketDetailsComponent', () => {
|
|||
declarations: [WorkbasketDetailsComponent, NoAccessComponent, WorkbasketInformationComponent, SpinnerComponent,
|
||||
IconTypeComponent, MapValuesPipe, RemoveNoneTypePipe, AlertComponent, GeneralMessageModalComponent, AccessItemsComponent,
|
||||
DistributionTargetsComponent, FilterComponent, DualListComponent, DummyDetailComponent, SelectWorkBasketPipe],
|
||||
providers: [WorkbasketService, MasterAndDetailService, PermissionService, ErrorModalService, RequestInProgressService,
|
||||
providers: [WorkbasketService, MasterAndDetailService, ErrorModalService, RequestInProgressService,
|
||||
AlertService, SavingWorkbasketService, {
|
||||
provide: DomainService,
|
||||
useClass: DomainServiceMock
|
||||
|
@ -92,7 +91,6 @@ describe('WorkbasketDetailsComponent', () => {
|
|||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(WorkbasketDetailsComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.hasPermission = false;
|
||||
debugElement = fixture.debugElement.nativeElement;
|
||||
router = TestBed.get(Router)
|
||||
fixture.detectChanges();
|
||||
|
@ -129,16 +127,10 @@ describe('WorkbasketDetailsComponent', () => {
|
|||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should has created taskana-no-access if workbasket is not defined and hasPermission is false', () => {
|
||||
expect(component.workbasket).toBeUndefined();
|
||||
component.hasPermission = false;
|
||||
fixture.detectChanges();
|
||||
expect(debugElement.querySelector('taskana-no-access')).toBeTruthy();
|
||||
});
|
||||
|
||||
|
||||
it('should has created taskana-workbasket-details if workbasket is defined and taskana-no-access should dissapear', () => {
|
||||
expect(component.workbasket).toBeUndefined();
|
||||
component.hasPermission = false;
|
||||
fixture.detectChanges();
|
||||
expect(debugElement.querySelector('taskana-no-access')).toBeTruthy();
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import { ACTION } from 'app/models/action';
|
|||
|
||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||
import { WorkbasketService } from 'app/administration/services/workbasket/workbasket.service'
|
||||
import { PermissionService } from 'app/services/permission/permission.service';
|
||||
import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-detail.service'
|
||||
import { DomainService } from 'app/services/domain/domain.service';
|
||||
|
||||
|
@ -28,7 +27,6 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
|
|||
workbasketCopy: Workbasket;
|
||||
selectedId: string = undefined;
|
||||
showDetail = false;
|
||||
hasPermission = true;
|
||||
requestInProgress = false;
|
||||
action: string;
|
||||
|
||||
|
@ -43,7 +41,6 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
|
|||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private masterAndDetailService: MasterAndDetailService,
|
||||
private permissionService: PermissionService,
|
||||
private domainService: DomainService) { }
|
||||
|
||||
|
||||
|
@ -80,14 +77,6 @@ export class WorkbasketDetailsComponent implements OnInit, OnDestroy {
|
|||
this.masterAndDetailSubscription = this.masterAndDetailService.getShowDetail().subscribe(showDetail => {
|
||||
this.showDetail = showDetail;
|
||||
});
|
||||
|
||||
this.permissionSubscription = this.permissionService.hasPermission().subscribe(permission => {
|
||||
this.hasPermission = permission;
|
||||
if (!this.hasPermission) {
|
||||
this.requestInProgress = false;
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
backClicked(): void {
|
||||
|
|
|
@ -2,13 +2,17 @@ import { NgModule } from '@angular/core';
|
|||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { BusinessAdminGuard } from 'app/guards/business-admin-guard';
|
||||
import { MonitorGuard } from 'app/guards/monitor-guard';
|
||||
|
||||
const appRoutes: Routes = [
|
||||
{
|
||||
canActivate: [BusinessAdminGuard],
|
||||
path: 'administration',
|
||||
loadChildren: './administration/administration.module#AdministrationModule',
|
||||
},
|
||||
{
|
||||
canActivate: [MonitorGuard],
|
||||
path: 'monitor',
|
||||
loadChildren: './monitor/monitor.module#MonitorModule',
|
||||
},
|
||||
|
|
|
@ -19,8 +19,6 @@ import { SharedModule } from 'app/shared/shared.module';
|
|||
* Services
|
||||
*/
|
||||
|
||||
import { HttpClientInterceptor } from 'app/services/httpClientInterceptor/http-client-interceptor.service';
|
||||
import { PermissionService } from 'app/services/permission/permission.service';
|
||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||
import { OrientationService } from 'app/services/orientation/orientation.service';
|
||||
|
@ -32,19 +30,22 @@ import { MasterAndDetailService } from 'app/services/masterAndDetail/master-and-
|
|||
import { TreeService } from 'app/services/tree/tree.service';
|
||||
import { TitlesService } from 'app/services/titles/titles.service';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
|
||||
import { WindowRefService } from 'app/services/window/window.service';
|
||||
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
|
||||
|
||||
/**
|
||||
* Components
|
||||
*/
|
||||
import { AppComponent } from './app.component';
|
||||
import { NavBarComponent } from 'app/components/nav-bar/nav-bar.component';
|
||||
|
||||
import { UserInformationComponent } from 'app/components/user-information/user-information.component';
|
||||
|
||||
/**
|
||||
* Guards
|
||||
*/
|
||||
import { DomainGuard } from './guards/domain-guard';
|
||||
import { BusinessAdminGuard } from './guards/business-admin-guard';
|
||||
import { MonitorGuard } from './guards/monitor-guard';
|
||||
import { APP_BASE_HREF } from '@angular/common';
|
||||
|
||||
|
||||
|
@ -64,29 +65,31 @@ const MODULES = [
|
|||
|
||||
const DECLARATIONS = [
|
||||
AppComponent,
|
||||
NavBarComponent
|
||||
NavBarComponent,
|
||||
UserInformationComponent
|
||||
];
|
||||
|
||||
export function startupServiceFactory(startupService: StartupService): Function {
|
||||
return () => startupService.load();
|
||||
export function startupServiceFactory(startupService: StartupService): () => Promise<any> {
|
||||
return (): Promise<any> => {
|
||||
return startupService.load();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: DECLARATIONS,
|
||||
imports: MODULES,
|
||||
providers: [
|
||||
WindowRefService,
|
||||
{ provide: APP_BASE_HREF, useValue: '/' },
|
||||
DomainService,
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: HttpClientInterceptor,
|
||||
multi: true
|
||||
},
|
||||
ErrorModalService,
|
||||
RequestInProgressService,
|
||||
OrientationService,
|
||||
SelectedRouteService,
|
||||
DomainGuard,
|
||||
BusinessAdminGuard,
|
||||
MonitorGuard,
|
||||
StartupService,
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
|
@ -95,11 +98,11 @@ export function startupServiceFactory(startupService: StartupService): Function
|
|||
multi: true
|
||||
},
|
||||
AlertService,
|
||||
PermissionService,
|
||||
MasterAndDetailService,
|
||||
TreeService,
|
||||
TitlesService,
|
||||
CustomFieldsService
|
||||
CustomFieldsService,
|
||||
TaskanaEngineService
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="pull-left col-sm-3 col-md-4">
|
||||
<button type="button" *ngIf="!showNavbar" class="btn btn-default navbar-toggle show pull-left" (click)="toogleNavBar();"
|
||||
aria-expanded="true" aria-controls="navbar">
|
||||
<span class="glyphicon glyphicon-arrow-right white"></span>
|
||||
<span class="glyphicon glyphicon glyphicon-th-list white"></span>
|
||||
</button>
|
||||
<span> </span>
|
||||
</div>
|
||||
|
@ -13,7 +13,7 @@
|
|||
<h2 class="navbar-brand no-margin"> {{title}}</h2>
|
||||
</ul>
|
||||
</div>
|
||||
<div *ngIf="selectedRoute.indexOf('workbaskets') !== -1 || selectedRoute.indexOf('classifications') !== -1"class="pull-right domain-form">
|
||||
<div *ngIf="selectedRoute.indexOf('workbaskets') !== -1 || selectedRoute.indexOf('classifications') !== -1" class="pull-right domain-form">
|
||||
<div class="dropdown clearfix btn-group">
|
||||
<label class="control-label hidden-xs">Working on </label>
|
||||
<button type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
|
@ -36,23 +36,25 @@
|
|||
<ul class="nav">
|
||||
<svg-icon class="logo white visible-xs" src="./assets/icons/logo.svg"></svg-icon>
|
||||
<h2 class="navbar-brand no-margin logo visible-xs"> {{title}}</h2>
|
||||
<button type="button" *ngIf="showNavbar" class="btn btn-default navbar-toggle show pull-right" (click)="toogleNavBar();"
|
||||
aria-expanded="true" aria-controls="navbar">
|
||||
<span class="glyphicon glyphicon-arrow-left white"></span>
|
||||
<button type="button" class="btn btn-default logout navbar-toggle show pull-right" data-toggle="tooltip" title="logout" (click)="logout()" aria-expanded="true"
|
||||
aria-controls="logout">
|
||||
<span class="glyphicon glyphicon-share white"></span>
|
||||
</button>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="nav-content">
|
||||
<div class="row menu">
|
||||
<taskana-user-information></taskana-user-information>
|
||||
<div *ngIf="administrationAccess" class="row menu">
|
||||
<span (click)="toogleNavBar()" routerLink="administration/workbaskets" aria-controls="administration" routerLinkActive="active">Administration</span>
|
||||
<div class="row submenu" [ngClass]="{'selected': selectedRoute.indexOf('workbaskets') !== -1 }">
|
||||
<span (click)="toogleNavBar()" class="col-xs-6" routerLink="administration/workbaskets" aria-controls="Workbaskets" routerLinkActive="active">Workbaskets</span>
|
||||
</div>
|
||||
<div class="row submenu" [ngClass]="{'selected': selectedRoute.indexOf('classifications') !== -1}">
|
||||
<span (click)="toogleNavBar()" class="col-xs-6" routerLink="administration/classifications" aria-controls="Classifications" routerLinkActive="active">Classifications</span>
|
||||
<span (click)="toogleNavBar()" class="col-xs-6" routerLink="administration/classifications" aria-controls="Classifications"
|
||||
routerLinkActive="active">Classifications</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row menu" [ngClass]="{'selected': selectedRoute.indexOf('monitor') !== -1}">
|
||||
<div *ngIf="monitorAccess" class="row menu" [ngClass]="{'selected': selectedRoute.indexOf('monitor') !== -1}">
|
||||
<span (click)="toogleNavBar()" routerLink="{{monitorUrl}}" aria-controls="Monitor" routerLinkActive="active">Monitor</span>
|
||||
</div>
|
||||
<div class="row menu" [ngClass]="{'selected': selectedRoute.indexOf('workplace') !== -1 || selectedRoute === ''}">
|
||||
|
|
|
@ -10,6 +10,10 @@ $selected-border-color: #22a39f;
|
|||
|
||||
.navbar-toggle{
|
||||
margin-right: 0px;
|
||||
|
||||
}
|
||||
button.navbar-toggle:hover > span{
|
||||
color:$selected-border-color;
|
||||
}
|
||||
ul.nav > p {
|
||||
white-space: nowrap;
|
||||
|
@ -29,7 +33,6 @@ svg-icon.logo {
|
|||
padding: 6px 5px 5px 5px;
|
||||
}
|
||||
|
||||
|
||||
h2.navbar-brand{
|
||||
vertical-align: middle;
|
||||
text-decoration: none;
|
||||
|
@ -67,8 +70,7 @@ h2.navbar-brand{
|
|||
|
||||
|
||||
.nav-content{
|
||||
margin-top: 25px;
|
||||
margin-left: 8px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -3,16 +3,28 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
import { NavBarComponent } from './nav-bar.component';
|
||||
import { UserInformationComponent } from 'app/components/user-information/user-information.component';
|
||||
|
||||
import { SelectedRouteService } from 'app/services/selected-route/selected-route';
|
||||
import { DomainService } from 'app/services/domain/domain.service';
|
||||
import { DomainServiceMock } from 'app/services/domain/domain.service.mock';
|
||||
import { BusinessAdminGuard } from 'app/guards/business-admin-guard';
|
||||
import { MonitorGuard } from 'app/guards/monitor-guard';
|
||||
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
|
||||
import { WindowRefService } from 'app/services/window/window.service';
|
||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||
|
||||
import { UserInfoModel } from 'app/models/user-info';
|
||||
|
||||
describe('NavBarComponent', () => {
|
||||
let component: NavBarComponent;
|
||||
let fixture: ComponentFixture<NavBarComponent>;
|
||||
let debugElement, navBar;
|
||||
let debugElement, navBar, taskanaEngineService;
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'classifications', component: NavBarComponent }
|
||||
|
@ -20,16 +32,23 @@ describe('NavBarComponent', () => {
|
|||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [NavBarComponent],
|
||||
declarations: [NavBarComponent, UserInformationComponent],
|
||||
imports: [
|
||||
AngularSvgIconModule,
|
||||
HttpClientModule,
|
||||
RouterTestingModule.withRoutes(routes),
|
||||
SharedModule
|
||||
],
|
||||
providers: [SelectedRouteService, {
|
||||
provide: DomainService,
|
||||
useClass: DomainServiceMock
|
||||
}]
|
||||
},
|
||||
BusinessAdminGuard,
|
||||
MonitorGuard,
|
||||
TaskanaEngineService,
|
||||
WindowRefService,
|
||||
ErrorModalService,
|
||||
RequestInProgressService]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
@ -39,6 +58,8 @@ describe('NavBarComponent', () => {
|
|||
component = fixture.componentInstance;
|
||||
debugElement = fixture.debugElement.nativeElement;
|
||||
navBar = fixture.debugElement.componentInstance;
|
||||
taskanaEngineService = TestBed.get(TaskanaEngineService);
|
||||
spyOn(taskanaEngineService, 'getUserInformation').and.returnValue(Observable.of(new UserInfoModel));
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
|
|
|
@ -4,7 +4,9 @@ import { SelectedRouteService } from 'app/services/selected-route/selected-route
|
|||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { trigger, state, style, transition, keyframes, animate } from '@angular/animations';
|
||||
import { DomainService } from 'app/services/domain/domain.service';
|
||||
|
||||
import { BusinessAdminGuard } from 'app/guards/business-admin-guard';
|
||||
import { MonitorGuard } from 'app/guards/monitor-guard';
|
||||
import { WindowRefService } from 'app/services/window/window.service';
|
||||
@Component({
|
||||
selector: 'taskana-nav-bar',
|
||||
templateUrl: './nav-bar.component.html',
|
||||
|
@ -38,11 +40,17 @@ export class NavBarComponent implements OnInit, OnDestroy {
|
|||
monitorUrl = './monitor';
|
||||
workplaceUrl = './workplace';
|
||||
|
||||
administrationAccess = false;
|
||||
monitorAccess = false;
|
||||
|
||||
selectedRouteSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private selectedRouteService: SelectedRouteService,
|
||||
private domainService: DomainService) { }
|
||||
private domainService: DomainService,
|
||||
private businessAdminGuard: BusinessAdminGuard,
|
||||
private monitorGuard: MonitorGuard,
|
||||
private window: WindowRefService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.selectedRouteSubscription = this.selectedRouteService.getSelectedRoute().subscribe((value: string) => {
|
||||
|
@ -56,6 +64,13 @@ export class NavBarComponent implements OnInit, OnDestroy {
|
|||
this.domainService.getSelectedDomain().subscribe(domain => {
|
||||
this.selectedDomain = domain;
|
||||
});
|
||||
|
||||
this.businessAdminGuard.canActivate().subscribe(hasAccess => {
|
||||
this.administrationAccess = hasAccess
|
||||
});
|
||||
this.monitorGuard.canActivate().subscribe(hasAccess => {
|
||||
this.monitorAccess = hasAccess
|
||||
});
|
||||
}
|
||||
|
||||
switchDomain(domain) {
|
||||
|
@ -65,6 +80,12 @@ export class NavBarComponent implements OnInit, OnDestroy {
|
|||
toogleNavBar() {
|
||||
this.showNavbar = !this.showNavbar;
|
||||
}
|
||||
|
||||
|
||||
logout() {
|
||||
this.window.nativeWindow.location.href = environment.taskanaRestUrl + '/login?logout';
|
||||
}
|
||||
|
||||
private setTitle(value: string = 'workbaskets') {
|
||||
if (value.indexOf('workbaskets') === 0 || value.indexOf('classifications') === 0) {
|
||||
this.title = this.titleAdministration;
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<div class="row">
|
||||
<div class="icon">
|
||||
<div class="icon-wrap col-xs-offset-5">
|
||||
<svg-icon class="blue big" src="./assets/icons/user.svg"></svg-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-info white">
|
||||
<span>Logged as: {{userInformation.userId}}</span>
|
||||
<button type="button" class="btn btn-default white pull-right transparent" (click)="toogleRoles();" aria-expanded="true" aria-controls="roles">
|
||||
<span>Roles</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="white pull-right roles col-xs-12" [@toggle]="showRoles" *ngIf="showRoles">
|
||||
<span><i>{{roles}}</i></span>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,68 @@
|
|||
.big {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
margin-top:85px;
|
||||
> span {
|
||||
margin: 0 15px 0 15px;
|
||||
font-size: 20px;
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.icon, {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
& > .icon-wrap {
|
||||
border-radius: 50%;
|
||||
border: solid 3px #22a39f;
|
||||
width: 74px;
|
||||
height: 74px;
|
||||
overflow: hidden;
|
||||
background-color: #175263;
|
||||
position: absolute;
|
||||
-webkit-box-shadow: 0px 3px 3px #416b6a;
|
||||
-moz-box-shadow: 0px 3px 3px #416b6a;
|
||||
box-shadow: 0px 3px 3px #416b6a;
|
||||
|
||||
&> svg-icon {
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
margin:2px
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon:before { content: '';
|
||||
position: absolute;
|
||||
border-bottom: solid 3px #22a39f;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
transform: translateY(-33%);
|
||||
-webkit-box-shadow: 0px 3px 3px #416b6a;
|
||||
-moz-box-shadow: 0px 3px 3px #416b6a;
|
||||
box-shadow: 0px 3px 3px #416b6a;
|
||||
}
|
||||
|
||||
button.transparent, {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
&:hover{
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color:#22a39f
|
||||
}
|
||||
&:focus{
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
outline: none;
|
||||
color:white
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpModule } from '@angular/http';
|
||||
|
||||
import { UserInformationComponent } from './user-information.component';
|
||||
|
||||
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
|
||||
import { UserInfoModel } from 'app/models/user-info';
|
||||
|
||||
describe('UserInformationComponent', () => {
|
||||
let component: UserInformationComponent;
|
||||
let fixture: ComponentFixture<UserInformationComponent>;
|
||||
let taskanaEngineService;
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AngularSvgIconModule,
|
||||
HttpClientModule, HttpModule],
|
||||
declarations: [UserInformationComponent],
|
||||
providers: [TaskanaEngineService]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(UserInformationComponent);
|
||||
component = fixture.componentInstance;
|
||||
taskanaEngineService = TestBed.get(TaskanaEngineService);
|
||||
spyOn(taskanaEngineService, 'getUserInformation').and.returnValue(Observable.of(new UserInfoModel));
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,40 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
|
||||
import { UserInfoModel } from 'app/models/user-info';
|
||||
import { trigger, transition, animate, keyframes, style } from '@angular/animations';
|
||||
|
||||
@Component({
|
||||
selector: 'taskana-user-information',
|
||||
templateUrl: './user-information.component.html',
|
||||
styleUrls: ['./user-information.component.scss'],
|
||||
animations: [
|
||||
trigger('toggle', [
|
||||
transition('void => *', animate('300ms ease-in', keyframes([
|
||||
style({ opacity: 0, height: '0px' }),
|
||||
style({ opacity: 1, height: '10px' }),
|
||||
style({ opacity: 1, height: '*' })]))),
|
||||
transition('* => void', animate('300ms ease-out', keyframes([
|
||||
style({ opacity: 1, height: '*' }),
|
||||
style({ opacity: 0, height: '10px' }),
|
||||
style({ opacity: 0, height: '0px' })])))
|
||||
]
|
||||
)],
|
||||
})
|
||||
export class UserInformationComponent implements OnInit {
|
||||
|
||||
userInformation: UserInfoModel;
|
||||
roles = '';
|
||||
showRoles = false;
|
||||
constructor(private taskanaEngineService: TaskanaEngineService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.taskanaEngineService.getUserInformation().subscribe(userInfo => {
|
||||
this.userInformation = userInfo;
|
||||
this.roles = '[' + userInfo.roles.join(',') + ']';
|
||||
})
|
||||
}
|
||||
|
||||
toogleRoles() {
|
||||
this.showRoles = !this.showRoles;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { CanActivate, Router } from '@angular/router';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DomainService } from 'app/services/domain/domain.service';
|
||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||
import { ErrorModel } from 'app/models/modal-error';
|
||||
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
|
||||
|
||||
@Injectable()
|
||||
export class AdminGuard implements CanActivate {
|
||||
constructor(private taskanaEngineService: TaskanaEngineService, public router: Router) { }
|
||||
|
||||
canActivate() {
|
||||
return this.taskanaEngineService.getUserInformation().map(userInfo => {
|
||||
if (userInfo.roles.length === 0) {
|
||||
return this.navigateToWorplace();
|
||||
}
|
||||
const adminRole = userInfo.roles.find(role => {
|
||||
if (role === 'ADMIN') {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (adminRole) {
|
||||
return true;
|
||||
}
|
||||
return this.navigateToWorplace();
|
||||
}).catch(() => {
|
||||
return Observable.of(this.navigateToWorplace())
|
||||
});
|
||||
}
|
||||
|
||||
navigateToWorplace(): boolean {
|
||||
this.router.navigate(['workplace']);
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { CanActivate, Router } from '@angular/router';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DomainService } from 'app/services/domain/domain.service';
|
||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||
import { ErrorModel } from 'app/models/modal-error';
|
||||
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
|
||||
|
||||
@Injectable()
|
||||
export class BusinessAdminGuard implements CanActivate {
|
||||
constructor(private taskanaEngineService: TaskanaEngineService, public router: Router) { }
|
||||
|
||||
canActivate() {
|
||||
return this.taskanaEngineService.getUserInformation().map(userInfo => {
|
||||
if (userInfo.roles.length === 0) {
|
||||
return this.navigateToWorplace();
|
||||
}
|
||||
const adminRole = userInfo.roles.find(role => {
|
||||
if (role === 'BUSINESS_ADMIN' || role === 'ADMIN' ) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (adminRole) {
|
||||
return true;
|
||||
}
|
||||
return this.navigateToWorplace();
|
||||
}).catch(() => {
|
||||
|
||||
return Observable.of(this.navigateToWorplace())
|
||||
});
|
||||
}
|
||||
|
||||
navigateToWorplace(): boolean {
|
||||
this.router.navigate(['workplace']);
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { CanActivate, Router } from '@angular/router';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DomainService } from 'app/services/domain/domain.service';
|
||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||
import { ErrorModel } from 'app/models/modal-error';
|
||||
import { TaskanaEngineService } from 'app/services/taskana-engine/taskana-engine.service';
|
||||
|
||||
@Injectable()
|
||||
export class MonitorGuard implements CanActivate {
|
||||
constructor(private taskanaEngineService: TaskanaEngineService, public router: Router) { }
|
||||
|
||||
canActivate() {
|
||||
return this.taskanaEngineService.getUserInformation().map(userInfo => {
|
||||
if (userInfo.roles.length === 0) {
|
||||
return this.navigateToWorplace();
|
||||
}
|
||||
const adminRole = userInfo.roles.find(role => {
|
||||
if (role === 'MONITOR' || role === 'ADMIN' ) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (adminRole) {
|
||||
return true;
|
||||
}
|
||||
return this.navigateToWorplace();
|
||||
}).catch(() => {
|
||||
|
||||
return Observable.of(this.navigateToWorplace())
|
||||
});
|
||||
}
|
||||
|
||||
navigateToWorplace(): boolean {
|
||||
this.router.navigate(['workplace']);
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
export class UserInfoModel {
|
||||
constructor(
|
||||
public userId: string = undefined,
|
||||
public groupIds: Array<string> = [],
|
||||
public roles: Array<string> = []) { };
|
||||
|
||||
}
|
|
@ -7,29 +7,22 @@ import { WorkbasketCounter } from 'app/monitor/models/workbasket-counter';
|
|||
|
||||
@Injectable()
|
||||
export class RestConnectorService {
|
||||
httpOptions = {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/hal+json',
|
||||
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
|
||||
})
|
||||
};
|
||||
|
||||
constructor(private httpClient: HttpClient) {
|
||||
}
|
||||
|
||||
getTaskStatistics(): Observable<State[]> {
|
||||
return this.httpClient.get<Array<State>>(environment.taskanaRestUrl + '/v1/monitor/countByState?states=READY,CLAIMED,COMPLETED',
|
||||
this.httpOptions)
|
||||
return this.httpClient.get<Array<State>>(environment.taskanaRestUrl + '/v1/monitor/countByState?states=READY,CLAIMED,COMPLETED')
|
||||
}
|
||||
|
||||
|
||||
getWorkbasketStatistics(): Observable<WorkbasketCounter> {
|
||||
return this.httpClient.get<WorkbasketCounter>(environment.taskanaRestUrl
|
||||
+ '/v1/monitor/taskcountByWorkbasketDaysAndState?daysInPast=5&states=READY,CLAIMED,COMPLETED',
|
||||
this.httpOptions)
|
||||
+ '/v1/monitor/taskcountByWorkbasketDaysAndState?daysInPast=5&states=READY,CLAIMED,COMPLETED')
|
||||
}
|
||||
|
||||
getTaskStatusReport(): Observable<Object> {
|
||||
return this.httpClient.get(environment.taskanaRestUrl + '/v1/monitor/taskStatusReport', this.httpOptions)
|
||||
return this.httpClient.get(environment.taskanaRestUrl + '/v1/monitor/taskStatusReport')
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,12 +13,6 @@ export class DomainService {
|
|||
|
||||
url = environment.taskanaRestUrl + '/v1/domains';
|
||||
|
||||
httpOptions = {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
|
||||
})
|
||||
};
|
||||
private domainSelectedValue;
|
||||
private domainSelected = new BehaviorSubject<string>('');
|
||||
private domainSwitched = new Subject<string>();
|
||||
|
@ -33,7 +27,7 @@ export class DomainService {
|
|||
// GET
|
||||
getDomains(forceRefresh = false): Observable<string[]> {
|
||||
if (!this.dataObs$.observers.length || forceRefresh) {
|
||||
this.httpClient.get<string[]>(this.url, this.httpOptions).subscribe(
|
||||
this.httpClient.get<string[]>(this.url).subscribe(
|
||||
domains => {
|
||||
this.dataObs$.next(domains);
|
||||
if (!this.domainSelectedValue && domains && domains.length > 0) {
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { PermissionService } from './permission.service';
|
||||
|
||||
describe('PermissionService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [PermissionService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([PermissionService], (service: PermissionService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
|
@ -1,18 +0,0 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
|
||||
@Injectable()
|
||||
export class PermissionService {
|
||||
|
||||
private permission = new BehaviorSubject<boolean>(true);
|
||||
|
||||
|
||||
setPermission(permission: boolean) {
|
||||
this.permission.next(permission);
|
||||
}
|
||||
|
||||
hasPermission(): Observable<boolean> {
|
||||
return this.permission.asObservable();
|
||||
}
|
||||
}
|
|
@ -2,20 +2,23 @@ import { Observable } from 'rxjs/Observable';
|
|||
import { HttpClient } from '@angular/common/http';
|
||||
import { CanActivate } from '@angular/router';
|
||||
import { environment } from 'app/../environments/environment';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, Inject } from '@angular/core';
|
||||
import { TitlesService } from 'app/services/titles/titles.service';
|
||||
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
|
||||
|
||||
@Injectable()
|
||||
export class StartupService {
|
||||
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private titlesService: TitlesService,
|
||||
private customFieldsService: CustomFieldsService) { }
|
||||
|
||||
load(): Promise<any> {
|
||||
return this.loadEnvironment();
|
||||
}
|
||||
|
||||
|
||||
private loadEnvironment() {
|
||||
return this.httpClient.get<any>('environments/data-sources/environment-information.json').map(jsonFile => {
|
||||
if (jsonFile) {
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { environment } from 'environments/environment';
|
||||
import { UserInfoModel } from 'app/models/user-info';
|
||||
import { ReplaySubject } from 'rxjs/ReplaySubject';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class TaskanaEngineService {
|
||||
|
||||
private dataObs$ = new ReplaySubject<UserInfoModel>(1);
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient
|
||||
) { }
|
||||
|
||||
// GET
|
||||
getUserInformation(forceRefresh = false): Observable<UserInfoModel> {
|
||||
if (!this.dataObs$.observers.length || forceRefresh) {
|
||||
this.httpClient.get<UserInfoModel>(`${environment.taskanaRestUrl}/v1/current-user-info`).subscribe(
|
||||
data => this.dataObs$.next(data),
|
||||
error => {
|
||||
this.dataObs$.error(error);
|
||||
this.dataObs$ = new ReplaySubject(1);
|
||||
}
|
||||
);
|
||||
}
|
||||
return this.dataObs$;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
// This interface is optional, showing how you can add strong typings for custom globals.
|
||||
// Just use "Window" as the type if you don't have custom global stuff
|
||||
export interface IWindowService extends Window {
|
||||
__custom_global_stuff: string;
|
||||
}
|
||||
|
||||
function getWindow (): any {
|
||||
return window;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class WindowRefService {
|
||||
get nativeWindow (): IWindowService {
|
||||
return getWindow();
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ import { HttpClientModule } from '@angular/common/http';
|
|||
import { HttpModule } from '@angular/http';
|
||||
|
||||
import { HttpClientInterceptor } from './http-client-interceptor.service';
|
||||
import { PermissionService } from 'app/services/permission/permission.service';
|
||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||
|
||||
|
@ -11,7 +10,7 @@ describe('HttpExtensionService', () => {
|
|||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [HttpClientModule, HttpModule],
|
||||
providers: [HttpClientInterceptor, PermissionService, ErrorModalService, RequestInProgressService]
|
||||
providers: [HttpClientInterceptor, ErrorModalService, RequestInProgressService]
|
||||
});
|
||||
});
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse } from '@angular/common/http';
|
||||
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/operator/catch';
|
||||
import 'rxjs/add/observable/throw';
|
||||
|
@ -7,28 +7,31 @@ import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
|||
|
||||
import { ErrorModel } from 'app/models/modal-error';
|
||||
|
||||
import { PermissionService } from 'app/services/permission/permission.service';
|
||||
import { ErrorModalService } from 'app/services/errorModal/error-modal.service';
|
||||
import { RequestInProgressService } from 'app/services/requestInProgress/request-in-progress.service';
|
||||
import { environment } from 'environments/environment';
|
||||
|
||||
@Injectable()
|
||||
export class HttpClientInterceptor implements HttpInterceptor {
|
||||
|
||||
constructor(
|
||||
private permissionService: PermissionService,
|
||||
private errorModalService: ErrorModalService,
|
||||
private requestInProgressService: RequestInProgressService) {
|
||||
|
||||
}
|
||||
|
||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
req = req.clone({ headers: req.headers.set('Content-Type', 'application/hal+json') });
|
||||
if (!environment.production) {
|
||||
req = req.clone({ headers: req.headers.set('Authorization', 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x') });
|
||||
}
|
||||
return next.handle(req).do(event => {
|
||||
this.permissionService.setPermission(true);
|
||||
|
||||
}, err => {
|
||||
this.requestInProgressService.setRequestInProgress(false);
|
||||
if (err instanceof HttpErrorResponse && (err.status === 401 || err.status === 403)) {
|
||||
this.permissionService.setPermission(false)
|
||||
this.errorModalService.triggerError(
|
||||
new ErrorModel('You have no access to this resource ', err));
|
||||
} else if (err instanceof HttpErrorResponse && (err.status === 404) && err.url.indexOf('environment-information.json')) {
|
||||
// ignore this error message
|
||||
} else {
|
|
@ -1,7 +1,7 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { AlertModule } from 'ngx-bootstrap';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
@ -22,6 +22,7 @@ import { SelectWorkBasketPipe } from './pipes/selectedWorkbasket/seleted-workbas
|
|||
import { SpreadNumberPipe } from './pipes/spreadNumber/spread-number';
|
||||
import { OrderBy } from './pipes/orderBy/orderBy';
|
||||
import { MapToIterable } from './pipes/mapToIterable/mapToIterable';
|
||||
import { HttpClientInterceptor } from './services/httpClientInterceptor/http-client-interceptor.service';
|
||||
|
||||
|
||||
const MODULES = [
|
||||
|
@ -51,7 +52,14 @@ const DECLARATIONS = [
|
|||
@NgModule({
|
||||
declarations: DECLARATIONS,
|
||||
imports: MODULES,
|
||||
exports: DECLARATIONS
|
||||
exports: DECLARATIONS,
|
||||
providers: [
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: HttpClientInterceptor,
|
||||
multi: true
|
||||
}
|
||||
]
|
||||
})
|
||||
export class SharedModule {
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpHeaders } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
import { environment } from 'environments/environment';
|
||||
|
||||
@Injectable()
|
||||
export class CustomHttpClientInterceptor implements HttpInterceptor {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
if (!environment.production) {
|
||||
req = req.clone({ headers: req.headers.set('Authorization', 'Basic YWRtaW46YWRtaW4=') });
|
||||
}
|
||||
return next.handle(req);
|
||||
}
|
||||
}
|
|
@ -8,35 +8,27 @@ import { environment } from 'app/../environments/environment';
|
|||
export class TaskService {
|
||||
url = environment.taskanaRestUrl + '/v1/tasks';
|
||||
|
||||
httpOptions = {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/hal+json',
|
||||
'Authorization': 'Basic YWRtaW46YWRtaW4=',
|
||||
'user': 'user_1_1'
|
||||
})
|
||||
};
|
||||
|
||||
constructor(private httpClient: HttpClient) {
|
||||
}
|
||||
|
||||
findTaskWithWorkbaskets(basketKey: string): Observable<Task[]> {
|
||||
return this.httpClient.get<Task[]>(this.url + '?workbasketId=' + basketKey, this.httpOptions);
|
||||
return this.httpClient.get<Task[]>(this.url + '?workbasketId=' + basketKey);
|
||||
}
|
||||
|
||||
getTask(id: string): Observable<Task> {
|
||||
return this.httpClient.get<Task>(this.url + '/' + id, this.httpOptions);
|
||||
return this.httpClient.get<Task>(this.url + '/' + id);
|
||||
}
|
||||
|
||||
completeTask(id: string): Observable<Task> {
|
||||
return this.httpClient.post<Task>(this.url + '/' + id + '/complete', '', this.httpOptions);
|
||||
return this.httpClient.post<Task>(this.url + '/' + id + '/complete', '');
|
||||
}
|
||||
|
||||
claimTask(id: string): Observable<Task> {
|
||||
return this.httpClient.post<Task>(this.url + '/' + id + '/claim', 'test', this.httpOptions);
|
||||
return this.httpClient.post<Task>(this.url + '/' + id + '/claim', 'test');
|
||||
}
|
||||
|
||||
transferTask(taskId: string, workbasketKey: string): Observable<Task> {
|
||||
return this.httpClient.post<Task>(this.url + '/' + taskId
|
||||
+ '/transfer/' + workbasketKey, '', this.httpOptions);
|
||||
+ '/transfer/' + workbasketKey, '');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,17 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import {Workbasket} from 'app/models/workbasket';
|
||||
import {environment} from 'app/../environments/environment';
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
import {HttpClient, HttpHeaders} from '@angular/common/http';
|
||||
import { Workbasket } from 'app/models/workbasket';
|
||||
import { environment } from 'app/../environments/environment';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
|
||||
@Injectable()
|
||||
export class WorkbasketService {
|
||||
url = environment.taskanaRestUrl + '/v1/workbaskets';
|
||||
|
||||
httpOptions = {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/hal+json',
|
||||
'Authorization': 'Basic VEVBTUxFQURfMTpURUFNTEVBRF8x'
|
||||
})
|
||||
};
|
||||
|
||||
constructor(private httpClient: HttpClient) {
|
||||
}
|
||||
|
||||
getAllWorkBaskets(): Observable<Workbasket[]> {
|
||||
return this.httpClient.get<Workbasket[]>(this.url + '?required-permission=OPEN', this.httpOptions);
|
||||
return this.httpClient.get<Workbasket[]>(this.url + '?required-permission=OPEN');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,11 @@ import { CommonModule } from '@angular/common';
|
|||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { Ng2AutoCompleteModule } from 'ng2-auto-complete';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { WorkplaceRoutingModule } from './workplace-routing.module';
|
||||
import { AlertModule } from 'ngx-bootstrap';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
|
||||
import { WorkplaceComponent } from './workplace.component';
|
||||
import { SelectorComponent } from './workbasket-selector/workbasket-selector.component';
|
||||
|
@ -19,6 +20,8 @@ import { OrderTasksByPipe } from './util/orderTasksBy.pipe';
|
|||
import { DataService } from './services/data.service';
|
||||
import { TaskService } from './services/task.service';
|
||||
import { WorkbasketService } from './services/workbasket.service';
|
||||
import { CustomHttpClientInterceptor } from './services/custom-http-interceptor/custom-http-interceptor.service';
|
||||
|
||||
|
||||
const MODULES = [
|
||||
CommonModule,
|
||||
|
@ -27,7 +30,8 @@ const MODULES = [
|
|||
HttpClientModule,
|
||||
AngularSvgIconModule,
|
||||
WorkplaceRoutingModule,
|
||||
AlertModule
|
||||
AlertModule,
|
||||
SharedModule
|
||||
];
|
||||
|
||||
const DECLARATIONS = [
|
||||
|
@ -46,7 +50,12 @@ const DECLARATIONS = [
|
|||
providers: [
|
||||
DataService,
|
||||
TaskService,
|
||||
WorkbasketService
|
||||
WorkbasketService,
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: CustomHttpClientInterceptor,
|
||||
multi: true
|
||||
},
|
||||
]
|
||||
})
|
||||
export class WorkplaceModule {
|
||||
|
|
|
@ -3,4 +3,5 @@ $blue: #2e9eca;
|
|||
$green: #246972;
|
||||
$grey: grey;
|
||||
$brown: #f0ad4e;
|
||||
$invalid: #a94442;
|
||||
$invalid: #a94442;
|
||||
$aquamarine: #22a39f;
|
||||
|
|
|
@ -77,6 +77,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.blue-green{
|
||||
color: $blue-green;
|
||||
& svg {
|
||||
fill: $blue-green;
|
||||
}
|
||||
}
|
||||
|
||||
.green {
|
||||
color: $green;
|
||||
& svg {
|
||||
|
@ -112,6 +119,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.aquamarine {
|
||||
color: $aquamarine;
|
||||
& svg {
|
||||
fill: $aquamarine;
|
||||
}
|
||||
}
|
||||
|
||||
svg-icon.fa-fw > svg {
|
||||
text-align: center;
|
||||
width: 1.25em;
|
||||
|
@ -282,4 +296,5 @@ li.list-group-item:hover, {
|
|||
color: #555;
|
||||
text-decoration: none;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue