Skip to content

Commit

Permalink
Merge pull request #317 from Consdata/IKC-292-survey
Browse files Browse the repository at this point in the history
IKC-292 Survey
  • Loading branch information
pbelke authored Dec 7, 2023
2 parents d06ec33 + fb0e183 commit b498753
Show file tree
Hide file tree
Showing 25 changed files with 739 additions and 28 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ local
/node_modules/
docker-compose.yml
.firebase
kouncil_installation_id.txt
default_*_password.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
package com.consdata.kouncil.config;

import static java.lang.String.format;
import static java.util.stream.Collectors.toMap;
import static org.apache.logging.log4j.util.Strings.isNotBlank;

import com.consdata.kouncil.KouncilRuntimeException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.annotation.PostConstruct;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -11,24 +31,14 @@
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static java.lang.String.format;
import static java.util.stream.Collectors.toMap;
import static org.apache.logging.log4j.util.Strings.isNotBlank;

@Component
@Slf4j
@Data
@ConfigurationProperties(prefix = "kouncil")
public class KouncilConfiguration {

protected static final String SPECIAL_CHARS = "[^a-zA-Z0-9\\s]";
public static final String INSTALLATION_ID_FILE = "kouncil_installation_id.txt";

private static final String HOST_PORT_SEPARATOR = ":";

Expand All @@ -42,6 +52,8 @@ public class KouncilConfiguration {

private Map<String, ClusterConfig> clusterConfig;

private String installationId;

/**
* @return first known broker from given cluster
*/
Expand Down Expand Up @@ -72,6 +84,10 @@ public Optional<BrokerConfig> getBrokerConfigFromCluster(String clusterId, Strin
.findFirst();
}

public String getInstallationId() {
return installationId;
}

/**
* hosts may be specified either in IP or hostname form, this method allows us to compare them regardless of their form
*/
Expand All @@ -93,9 +109,25 @@ public void initialize() {
} else {
initializeSimpleConfig();
}
generateInstallationId();
log.info(toString());
}

private void generateInstallationId() {
Path path = Paths.get(INSTALLATION_ID_FILE);
try {
if (!Files.exists(path)) {
installationId = UUID.randomUUID().toString();
Files.write(path, installationId.getBytes());
} else {
installationId = Files.readString(path);
}
} catch (IOException e) {
throw new KouncilRuntimeException("Failed to read installation id file", e);
}
}


private void initializeSimpleConfig() {
log.info("Using simple Kouncil configuration: bootstrapServers={}, schemaRegistryUrl={}", initialBootstrapServers, schemaRegistryUrl);
clusterConfig = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package com.consdata.kouncil.config.security.inmemory;

import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.ADMIN_CONFIG;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.ADMIN_DEFAULT_PASSWORD;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.ADMIN_DEFAULT_GROUP;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.ADMIN_DEFAULT_PASSWORD;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.ADMIN_USERNAME;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.EDITOR_CONFIG;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.EDITOR_DEFAULT_PASSWORD;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.EDITOR_DEFAULT_GROUP;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.EDITOR_DEFAULT_PASSWORD;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.EDITOR_USERNAME;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.VIEWER_CONFIG;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.VIEWER_DEFAULT_PASSWORD;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.VIEWER_DEFAULT_GROUP;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.VIEWER_DEFAULT_PASSWORD;
import static com.consdata.kouncil.config.security.inmemory.InMemoryConst.VIEWER_USERNAME;

import com.consdata.kouncil.KouncilRuntimeException;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package com.consdata.kouncil.security;

import static com.consdata.kouncil.config.KouncilConfiguration.INSTALLATION_ID_FILE;
import static com.consdata.kouncil.config.security.RoleNames.ADMIN_ROLE;
import static com.consdata.kouncil.config.security.RoleNames.EDITOR_ROLE;
import static com.consdata.kouncil.config.security.RoleNames.VIEWER_ROLE;
import static org.springframework.security.web.context.HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -36,8 +40,6 @@ public class AuthController {
@Value("${kouncil.auth.active-provider}")
private String activeProvider;

private final UserRolesMapping userRolesMapping;

@GetMapping("/api/activeProvider")
public String activeProvider() {
return activeProvider;
Expand Down Expand Up @@ -69,4 +71,10 @@ public Set<String> getUserRoles() {
Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
return authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
}

@RolesAllowed({ADMIN_ROLE, EDITOR_ROLE, VIEWER_ROLE})
@GetMapping("/api/installationId")
public String getInstallationId() throws IOException {
return Files.readString(Path.of(INSTALLATION_ID_FILE));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.consdata.kouncil.survey;

import static com.consdata.kouncil.config.security.RoleNames.ADMIN_ROLE;
import static com.consdata.kouncil.config.security.RoleNames.EDITOR_ROLE;
import static com.consdata.kouncil.config.security.RoleNames.VIEWER_ROLE;

import javax.annotation.security.RolesAllowed;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class SurveyController {

@Value("${kouncil.survey.base-path:}")
private String surveyBasePath;

@RolesAllowed({ADMIN_ROLE, EDITOR_ROLE, VIEWER_ROLE})
@GetMapping("/api/survey/config")
public String getSurveyBasePath() {
return surveyBasePath;
}
}
2 changes: 2 additions & 0 deletions kouncil-backend/src/main/resources/kouncil.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ kouncil:
role-admin: admin_group
role-editor: editor_group
role-viewer: viewer_group
survey:
base-path: "https://kouncil-eximee-survey-n22nwdfueq-lm.a.run.app/kouncil"
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import com.consdata.kouncil.KafkaConnectionService;
import java.util.stream.IntStream;
import org.junit.Ignore;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
Expand All @@ -14,8 +13,12 @@

@SpringBootTest
@DirtiesContext
@EmbeddedKafka(partitions = 4, bootstrapServersProperty =
"spring.kafka.bootstrap-servers", brokerProperties = {"listeners=PLAINTEXT://localhost:59092", "port=59092"}, ports = 59092)
@EmbeddedKafka(
partitions = 4,
bootstrapServersProperty = "spring.kafka.bootstrap-servers",
brokerProperties = {"listeners=PLAINTEXT://localhost:59092", "port=59092"},
ports = 59092
)
class TopicServiceTest {

@Autowired
Expand All @@ -30,22 +33,22 @@ class TopicServiceTest {
private static final String BOOSTRAP_SERVER = "localhost_59092";

@Test
@Ignore
void should_fetch_all_generated_messages() {
IntStream.range(0, 100).forEach(index -> kafkaTemplate.send("embedded-test-topic", String.format("Msg no %s", index)));
kafkaConnectionService.getAdminClient(BOOSTRAP_SERVER);

TopicMessagesDto topicMessages = topicService.getTopicMessages("embedded-test-topic", "all", "1", "100", null, null, null, BOOSTRAP_SERVER);
TopicMessagesDto topicMessages = topicService.getTopicMessages("embedded-test-topic", "all", "1", "100",
null, null, null, BOOSTRAP_SERVER);
assertThat(topicMessages.getMessages()).hasSize(100);
}

@Test
@Ignore
void should_fetch_all_generated_messages_small_amount() {
IntStream.range(0, 2).forEach(index -> kafkaTemplate.send("embedded-test-topic-2", String.format("Msg no %s", index)));
kafkaConnectionService.getAdminClient(BOOSTRAP_SERVER);

TopicMessagesDto topicMessages = topicService.getTopicMessages("embedded-test-topic-2", "all", "1", "10", null, null, null, BOOSTRAP_SERVER);
TopicMessagesDto topicMessages = topicService.getTopicMessages("embedded-test-topic-2", "all", "1", "10",
null, null, null, BOOSTRAP_SERVER);
assertThat(topicMessages.getMessages()).hasSize(2);
}
}
10 changes: 8 additions & 2 deletions kouncil-frontend/apps/kouncil/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ import {DragDropModule} from '@angular/cdk/drag-drop';
import {MatSortModule} from '@angular/material/sort';
import {AccessDeniedComponent} from './access-denied/access-denied.component';
import {PageNotFoundComponent} from './page-not-found/page-not-found.component';
import {SurveyComponent} from './survey/survey.component';
import {
SurveyScaleQuestionComponent
} from './survey/survey-scale-question/survey-scale-question.component';


export function configProviderFactory(provider: ServersService): Promise<boolean> {
Expand Down Expand Up @@ -137,8 +141,7 @@ export function trackServiceFactory(http: HttpClient, rxStompService: RxStompSer
ChangePasswordComponent,
MainLoginComponent,
OAuthRedirectComponent,
AccessDeniedComponent,
PageNotFoundComponent
AccessDeniedComponent
],
imports: [
BrowserModule,
Expand Down Expand Up @@ -173,6 +176,9 @@ export function trackServiceFactory(http: HttpClient, rxStompService: RxStompSer
CommonComponentsModule,
MatSortModule,
DragDropModule,
PageNotFoundComponent,
SurveyComponent,
SurveyScaleQuestionComponent
],
providers: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {User} from '@app/common-login';
import {AuthService} from './auth.service';
import {environment} from '../../environments/environment';
import {KouncilRole} from './kouncil-role';
import {v4 as uuidv4} from 'uuid';

@Injectable({
providedIn: 'root',
Expand Down Expand Up @@ -35,6 +36,7 @@ export class AuthBackendService implements AuthService {
return this.http.post<boolean>('/api/login', user).pipe(map(data => {
this.setAuthenticated(data);
localStorage.setItem(this.IS_LOGGED_IN, data.toString());
this.generateUserId();
return data;
}));
}
Expand Down Expand Up @@ -105,4 +107,16 @@ export class AuthBackendService implements AuthService {
}
return this.userRoles.some(userRole => roles.includes(userRole));
}

private generateUserId() {
if (!localStorage.getItem('userId')) {
localStorage.setItem('userId', uuidv4());
}
}

getInstallationId$(): void {
this.http.get('/api/installationId', {responseType: 'text'}).subscribe((installationId) => {
localStorage.setItem('installationId', installationId);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {Observable, of} from 'rxjs';
import {AuthService} from './auth.service';
import {User} from '@app/common-login';
import {KouncilRole} from './kouncil-role';
import {v4 as uuidv4} from 'uuid';

@Injectable()
export class AuthDemoService implements AuthService {
Expand Down Expand Up @@ -71,4 +72,8 @@ export class AuthDemoService implements AuthService {
canAccess(roles: KouncilRole[]): boolean {
return this.userRoles.some(userRole => roles.includes(userRole));
}

getInstallationId$(): void {
localStorage.setItem('installationId',uuidv4());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export abstract class AuthService {
abstract getUserRoles$(): Observable<void>;

abstract canAccess(roles: KouncilRole[]): boolean;
abstract getInstallationId$(): void;
}

export function authServiceFactory(http: HttpClient): AuthService {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export class LoginComponent implements OnInit {
this.checkFirstTimeLogin($event.username);
} else {
this.fetchUserRoles();
this.fetchInstallationId();
}
}
});
Expand Down Expand Up @@ -92,6 +93,11 @@ export class LoginComponent implements OnInit {
this.service.firstTimeLogin$(username).subscribe(firstTime => {
this.firstTimeLogin = firstTime;
this.fetchUserRoles();
this.fetchInstallationId();
});
}

private fetchInstallationId() {
this.service.getInstallationId$();
}
}
2 changes: 2 additions & 0 deletions kouncil-frontend/apps/kouncil/src/app/main/main.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {environment} from '../../environments/environment';
<app-demo *ngIf="backend === 'DEMO'"></app-demo>
<app-kafka-navbar></app-kafka-navbar>
<app-survey></app-survey>
<div [ngClass]="backend === 'SERVER' ? 'kafka-desktop' : 'kafka-desktop-demo'">
<app-progress-bar></app-progress-bar>
<router-outlet></router-outlet>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {ChangeDetectionStrategy, Component} from '@angular/core';
import {MatIconModule} from '@angular/material/icon';

@Component({
standalone: true,
imports: [MatIconModule],
selector: 'app-access-denied',
template: `
<div class="page-not-found-main">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export interface SurveyAnswer {
sentId: string;
result: SurveyResultValue;
status: SurveyResultStatus;
position: string;
}

export interface SurveyResultValue {
questions?: SurveyQuestionResult[];
}

export interface SurveyQuestionResult {
questionId: number;
value: string;
answer: string;
}

export enum SurveyResultStatus {
FILLED = 'FILLED',
DISCARDED = 'DISCARDED',
PENDING = 'PENDING'
}
Loading

0 comments on commit b498753

Please sign in to comment.