Skip to content
Open
2 changes: 1 addition & 1 deletion projects/nae-example-app/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class AppComponent {
translate.setTranslation('en', en, true);
translate.setTranslation('sk', sk, true);

this.userService.user$.pipe(filter(u => !!u && u.id !== ''), take(1)).subscribe(() => {
this.userService.user$.pipe(filter(u => !!u && u.id !== '' && !u.isAnonymous()), take(1)).subscribe(() => {
const allNets = allowedNetsFactory.createWithAllNets();
allNets.allowedNetsIdentifiers$.pipe(take(1)).subscribe(nets => {
if (this.baseAllowedNets.allowedNets.length !== 0) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import {TestBed} from '@angular/core/testing';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {RouterTestingModule} from '@angular/router/testing';
import {AnonymousService} from './anonymous.service';
import {ConfigurationService} from '../../configuration/configuration.service';
import {TestConfigurationService} from '../../utility/tests/test-config';

describe('AnonymousService', () => {
let service: AnonymousService;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [NoopAnimationsModule, HttpClientTestingModule, RouterTestingModule.withRoutes([])],
providers: [{provide: ConfigurationService, useClass: TestConfigurationService}]
});
service = TestBed.inject(AnonymousService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});

afterEach(() => {
TestBed.resetTestingModule();
});
});

// import {TestBed} from '@angular/core/testing';
// import {NoopAnimationsModule} from '@angular/platform-browser/animations';
// import {HttpClientTestingModule} from '@angular/common/http/testing';
// import {RouterTestingModule} from '@angular/router/testing';
// import {AnonymousService} from './anonymous.service';
// import {ConfigurationService} from '../../configuration/configuration.service';
// import {TestConfigurationService} from '../../utility/tests/test-config';
//
// describe('AnonymousService', () => {
// let service: AnonymousService;
//
// beforeEach(() => {
// TestBed.configureTestingModule({
// imports: [NoopAnimationsModule, HttpClientTestingModule, RouterTestingModule.withRoutes([])],
// providers: [{provide: ConfigurationService, useClass: TestConfigurationService}]
// });
// service = TestBed.inject(AnonymousService);
// });
//
// it('should be created', () => {
// expect(service).toBeTruthy();
// });
//
// afterEach(() => {
// TestBed.resetTestingModule();
// });
// });
//
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
Expand Up @@ -9,43 +9,43 @@ import {BehaviorSubject, Observable} from 'rxjs';
})
export class AnonymousService implements OnDestroy {

public static readonly JWT_BEARER_HEADER_DEFAULT = 'X-Jwt-Token';
protected readonly _jwtHeader: string;
public static readonly X_ANONYMOUS_TOKEN = 'X-Anonymous-Token';
protected readonly _anonymousTokenHeader: string;
protected _storage: Storage;
protected _tokenSet: BehaviorSubject<boolean>;

constructor(protected _config: ConfigurationService) {
this._jwtHeader = this._config.get().providers.auth.jwtBearer ?
this._config.get().providers.auth.jwtBearer : AnonymousService.JWT_BEARER_HEADER_DEFAULT;
this._anonymousTokenHeader = this._config.get().providers.auth.anonymous ?
this._config.get().providers.auth.anonymous : AnonymousService.X_ANONYMOUS_TOKEN;
this._storage = this.resolveStorage(this._config.get().providers.auth['local']);
this._tokenSet = new BehaviorSubject<boolean>(false);
}

get jwtHeader(): string {
return this._jwtHeader;
get anonymousTokenHeader(): string {
return this._anonymousTokenHeader;
}

get tokenSet(): Observable<boolean> {
return this._tokenSet.asObservable();
}

public getToken(): string {
return this._storage.getItem(this._jwtHeader);
return this._storage.getItem(this._anonymousTokenHeader);
}

public setToken(token: string): void {
this._storage.setItem(this._jwtHeader, token);
this._storage.setItem(this._anonymousTokenHeader, token);
if (!this._tokenSet.getValue())
this._tokenSet.next(true);
}

public removeToken(): void {
this._storage.removeItem(this._jwtHeader);
this._storage.removeItem(this._anonymousTokenHeader);
this._tokenSet.next(false);
}

ngOnDestroy(): void {
localStorage.removeItem(this._jwtHeader);
localStorage.removeItem(this._anonymousTokenHeader);
this._tokenSet.complete();
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {ProxyAuthenticationService} from './proxyAuthentication.service';
import {AuthenticationMethodService} from './services/authentication-method.service';
import {OverlayModule} from '@angular/cdk/overlay';
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
import {AnonymousAuthenticationInterceptor} from './services/anonymous-authentication-interceptor';
// import {AnonymousAuthenticationInterceptor} from './services/anonymous-authentication-interceptor';


@NgModule({
Expand All @@ -22,7 +22,7 @@ import {AnonymousAuthenticationInterceptor} from './services/anonymous-authentic
],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthenticationInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: AnonymousAuthenticationInterceptor, multi: true },
// { provide: HTTP_INTERCEPTORS, useClass: AnonymousAuthenticationInterceptor, multi: true },
{ provide: AuthenticationMethodService, useClass: ProxyAuthenticationService},
// AuthenticationEffects
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export * from './authentication.module';

/* SERVICES */
export * from './anonymous/anonymous.service';
export * from './services/anonymous-authentication-interceptor'
// export * from './services/anonymous-authentication-interceptor'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Remove the commented export from the public API surface.

Keeping commented exports in a public API file creates dead code and ambiguity. If this export is intentionally retired, delete it outright.

🧹 Suggested cleanup
-// export * from './services/anonymous-authentication-interceptor'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// export * from './services/anonymous-authentication-interceptor'
🤖 Prompt for AI Agents
In `@projects/netgrif-components-core/src/lib/authentication/public-api.ts` at
line 13, Remove the commented dead export in public-api.ts: delete the line "//
export * from './services/anonymous-authentication-interceptor'". This cleans up
the public API surface by removing the stale commented export referencing the
anonymous-authentication-interceptor module.

export * from './services/authentication-interceptor'
export * from './proxyAuthentication.service'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,58 +1,58 @@
import {inject, TestBed} from '@angular/core/testing';
import {ConfigurationService} from '../../configuration/configuration.service';
import {TestConfigurationService} from '../../utility/tests/test-config';
import {HTTP_INTERCEPTORS, HttpClient, HttpHeaders} from '@angular/common/http';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {RouterTestingModule} from '@angular/router/testing';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {LoggerService} from '../../logger/services/logger.service';
import {AnonymousService} from '../anonymous/anonymous.service';
import {AnonymousAuthenticationInterceptor} from './anonymous-authentication-interceptor';

describe('AnonymousAuthenticationInterceptor', () => {
let service: AnonymousService;
let warnSpy: jasmine.Spy;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
providers: [
{provide: ConfigurationService, useClass: TestConfigurationService},
AnonymousService,
{
provide: HTTP_INTERCEPTORS,
useClass: AnonymousAuthenticationInterceptor,
multi: true
}
]
});
service = TestBed.inject(AnonymousService);
warnSpy = spyOn(TestBed.inject(LoggerService), 'warn');
});

describe('intercept HTTP request', () => {
it('should add JWT bearer to Headers', (done) => {
inject([HttpClient, HttpTestingController],
(http: HttpClient, mock: HttpTestingController) => {

service.setToken('jwt-token');
http.get('/api').subscribe(response => {
expect(response).toBeTruthy();
done();
});
const request = mock.expectOne(req => (req.headers.has('X-Jwt-Token')));

request.flush({data: 'test'}, {headers: new HttpHeaders({'X-Jwt-Token': 'tokenos'})});
mock.verify();
})();
});
afterEach(inject([HttpTestingController], (mock: HttpTestingController) => {
mock.verify();
TestBed.resetTestingModule();
}));
});

afterEach(() => {
TestBed.resetTestingModule();
});
});
// import {inject, TestBed} from '@angular/core/testing';
// import {ConfigurationService} from '../../configuration/configuration.service';
// import {TestConfigurationService} from '../../utility/tests/test-config';
// import {HTTP_INTERCEPTORS, HttpClient, HttpHeaders} from '@angular/common/http';
// import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
// import {RouterTestingModule} from '@angular/router/testing';
// import {NoopAnimationsModule} from '@angular/platform-browser/animations';
// import {LoggerService} from '../../logger/services/logger.service';
// import {AnonymousService} from '../anonymous/anonymous.service';
// import {AnonymousAuthenticationInterceptor} from './anonymous-authentication-interceptor';
//
// describe('AnonymousAuthenticationInterceptor', () => {
// let service: AnonymousService;
// let warnSpy: jasmine.Spy;
//
// beforeEach(() => {
// TestBed.configureTestingModule({
// imports: [HttpClientTestingModule, NoopAnimationsModule, RouterTestingModule.withRoutes([])],
// providers: [
// {provide: ConfigurationService, useClass: TestConfigurationService},
// AnonymousService,
// {
// provide: HTTP_INTERCEPTORS,
// useClass: AnonymousAuthenticationInterceptor,
// multi: true
// }
// ]
// });
// service = TestBed.inject(AnonymousService);
// warnSpy = spyOn(TestBed.inject(LoggerService), 'warn');
// });
//
// describe('intercept HTTP request', () => {
// it('should add JWT bearer to Headers', (done) => {
// inject([HttpClient, HttpTestingController],
// (http: HttpClient, mock: HttpTestingController) => {
//
// service.setToken('jwt-token');
// http.get('/api').subscribe(response => {
// expect(response).toBeTruthy();
// done();
// });
// const request = mock.expectOne(req => (req.headers.has('X-Jwt-Token')));
//
// request.flush({data: 'test'}, {headers: new HttpHeaders({'X-Jwt-Token': 'tokenos'})});
// mock.verify();
// })();
// });
// afterEach(inject([HttpTestingController], (mock: HttpTestingController) => {
// mock.verify();
// TestBed.resetTestingModule();
// }));
// });
//
// afterEach(() => {
// TestBed.resetTestingModule();
// });
// });
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
import {Injectable} from '@angular/core';
import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse} from '@angular/common/http';
import {Observable, throwError} from 'rxjs';
import {catchError, tap} from 'rxjs/operators';
import {AnonymousService} from '../anonymous/anonymous.service';

@Injectable()
export class AnonymousAuthenticationInterceptor implements HttpInterceptor {

constructor(protected _anonymousService: AnonymousService) {}

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const jwtAuthToken = this._anonymousService.getToken();

if (!this._anonymousService) {
next.handle(req);
}

if (!!jwtAuthToken) {
req = req.clone({
headers: req.headers.set(this._anonymousService.jwtHeader, jwtAuthToken)
});
}
return next.handle(req).pipe(
tap(event => {
if (event instanceof HttpResponse) {
if (event.headers.has(this._anonymousService.jwtHeader)) {
this._anonymousService.setToken(event.headers.get(this._anonymousService.jwtHeader));
}
}
}),
catchError(errorEvent => {
if (errorEvent instanceof HttpErrorResponse && errorEvent.status === 401) {
console.debug('Authentication token is invalid. Clearing session token');
this._anonymousService.removeToken();
}
return throwError(errorEvent);
})
);
}
}
// import {Injectable} from '@angular/core';
// import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse} from '@angular/common/http';
// import {Observable, throwError} from 'rxjs';
// import {catchError, tap} from 'rxjs/operators';
// import {AnonymousService} from '../anonymous/anonymous.service';
//
// @Injectable()
// export class AnonymousAuthenticationInterceptor implements HttpInterceptor {
//
// constructor(protected _anonymousService: AnonymousService) {}
//
// intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// const xAnonymousToken = this._anonymousService.getToken();
//
// if (!this._anonymousService) {
// next.handle(req);
// }
//
// if (!!xAnonymousToken) {
// req = req.clone({
// headers: req.headers.set(this._anonymousService.anonymousTokenHeader, xAnonymousToken)
// });
// }
// return next.handle(req).pipe(
// tap(event => {
// if (event instanceof HttpResponse) {
// if (event.headers.has(this._anonymousService.anonymousTokenHeader)) {
// this._anonymousService.setToken(event.headers.get(this._anonymousService.anonymousTokenHeader));
// }
// }
// }),
// catchError(errorEvent => {
// if (errorEvent instanceof HttpErrorResponse && errorEvent.status === 401) {
// console.debug('Authentication token is invalid. Clearing session token');
// this._anonymousService.removeToken();
// }
// return throwError(errorEvent);
// })
// );
// }
// }
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import {Observable, throwError} from 'rxjs';
import {catchError, tap} from 'rxjs/operators';
import {SessionService} from '../session/services/session.service';
import {RedirectService} from '../../routing/redirect-service/redirect.service';
import {AnonymousService} from '../anonymous/anonymous.service';
// import {AnonymousService} from '../anonymous/anonymous.service';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove commented-out import.

Delete the commented-out import rather than leaving dead code. If the AnonymousService dependency is permanently removed from this interceptor, clean up the remnants.

♻️ Proposed fix
-// import {AnonymousService} from '../anonymous/anonymous.service';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// import {AnonymousService} from '../anonymous/anonymous.service';
🤖 Prompt for AI Agents
In
`@projects/netgrif-components-core/src/lib/authentication/services/authentication-interceptor.ts`
at line 14, Remove the dead commented import for AnonymousService from
authentication-interceptor.ts and clean up any remaining references or leftover
comments related to AnonymousService in the AuthenticationInterceptor (e.g.,
constructor parameters, private fields, or TODO comments) so the file contains
only active imports and dependencies; ensure the import block and any unused
symbols in the AuthenticationInterceptor class are cleaned up to avoid linter
warnings.

import {SessionIdleTimerService} from "../session/services/session-idle-timer.service";

@Injectable()
export class AuthenticationInterceptor implements HttpInterceptor {

constructor(private _session: SessionService,
private _redirect: RedirectService,
private _anonymousService: AnonymousService,
// private _anonymousService: AnonymousService,
private idleTimerService: SessionIdleTimerService) {
}
Comment on lines 20 to 24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove commented-out constructor parameter.

The commented-out _anonymousService parameter should be deleted for cleanliness.

♻️ Proposed fix
 constructor(private _session: SessionService,
             private _redirect: RedirectService,
-            // private _anonymousService: AnonymousService,
             private idleTimerService: SessionIdleTimerService) {
 }
🤖 Prompt for AI Agents
In
`@projects/netgrif-components-core/src/lib/authentication/services/authentication-interceptor.ts`
around lines 20 - 24, Remove the commented-out constructor parameter
_anonymousService from the AuthenticationInterceptor constructor: open the
constructor in authentication-interceptor.ts (the constructor method that
currently lists _session, _redirect, // private _anonymousService:
AnonymousService, and idleTimerService) and delete the commented line so the
constructor only declares the active dependencies (_session, _redirect,
idleTimerService).


Expand All @@ -37,7 +37,7 @@ export class AuthenticationInterceptor implements HttpInterceptor {
return next.handle(req).pipe(
tap(event => {
if (event instanceof HttpResponse) {
if (event.headers.has(this._session.sessionHeader) && !event.headers.has(this._anonymousService.jwtHeader)) {
if (event.headers.has(this._session.sessionHeader)) {
this._session.setVerifiedToken(event.headers.get(this._session.sessionHeader));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class AccessService {
if (view.access !== 'private') {
throw new Error(`Unknown access option '${view.access}'. Only 'public' or 'private' is allowed.`);
}
return !this._userService.user.isEmpty();
return !this._userService.user.isEmpty() && !this._userService.user.isAnonymous();
}

if (!url) {
Expand Down
10 changes: 10 additions & 0 deletions projects/netgrif-components-core/src/lib/filter/models/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ export abstract class Filter {
*/
public abstract bodyContainsQuery(): boolean;


/**
* Checks whether any of the filter bodies contains the `caseId` attribute.
*
* This method analyzes the body of the filter to determine if at least one of its parts includes a `caseId` field.
*
* @returns `true` if the `caseId` attribute exists in any of the filter bodies; otherwise, `false`.
*/
public abstract bodyContainsCaseId(): boolean;

/**
* Returns the necessary request params for the filter. Default implementation returns an empty object.
* The params are added on top of the request when sending it to the backend by the respective service methods.
Expand Down
Loading
Loading