Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/app/shared/services/api/base.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { HttpService } from '@shared/services/http/http.service';
import { SimpleVO, ResponseMessageType } from '@root/app/models';
import { compact } from 'lodash';
import { Injectable } from '@angular/core';
import { HttpV2Service } from '../http-v2/http-v2.service';

export interface CSRFResponse {
Expand Down Expand Up @@ -75,6 +76,7 @@ export class BaseResponse {
}
}

@Injectable()
export class BaseRepo {
constructor(
public http: HttpService,
Expand Down
171 changes: 132 additions & 39 deletions src/app/shared/services/api/folder.repo.spec.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,132 @@
// This suite doesn't actually have any tests, but for some reason the setup
// was causing the test bed to get contaminated.
// For this reason, I comment it out! There are other tests
// fully commented out, and we will be cleaning them up

// import { TestBed } from '@angular/core/testing';
// import {
// HttpTestingController,
// provideHttpClientTesting,
// } from '@angular/common/http/testing';

// import { HttpService } from '@shared/services/http/http.service';
// import { FolderRepo } from '@shared/services/api/folder.repo';
// import {
// provideHttpClient,
// withInterceptorsFromDi,
// } from '@angular/common/http';

// describe('FolderRepo', () => {
// let repo: FolderRepo;
// let httpMock: HttpTestingController;

// beforeEach(() => {
// TestBed.configureTestingModule({
// imports: [],
// providers: [
// HttpService,
// provideHttpClient(withInterceptorsFromDi()),
// provideHttpClientTesting(),
// ],
// });

// httpMock = TestBed.inject(HttpTestingController);
// });

// afterEach(() => {
// httpMock.verify();
// });
// });
import { TestBed } from '@angular/core/testing';
import { FolderVO } from '@models/index';
import { of } from 'rxjs';
import { HttpV2Service } from '../http-v2/http-v2.service';
import { HttpService } from '../http/http.service';
import { FolderRepo } from './folder.repo';

const emptyResponse = { items: [] };
const fakeFolderResponse = {
items: [
{
id: 42,
name: 'Auth Folder',
},
],
};
const fakeChildrenResponse = {
items: [
{
id: 300,
name: 'Auth Child',
thumbnailUrls: { 200: 'test' },
paths: { names: 'test' },
location: { stelaLocation: { id: 13 } },
},
],
};

describe('Folder repo', () => {
let folderRepo: FolderRepo;
let httpSpy: jasmine.SpyObj<HttpService>;
let httpV2Spy: jasmine.SpyObj<HttpV2Service>;

beforeEach(() => {
httpSpy = jasmine.createSpyObj('HttpService', [
'sendRequest',
'sendRequestPromise',
]);
httpV2Spy = jasmine.createSpyObj('HttpV2Service', ['get']);

TestBed.configureTestingModule({
providers: [
FolderRepo,
{ provide: HttpService, useValue: httpSpy },
{ provide: HttpV2Service, useValue: httpV2Spy },
],
});

folderRepo = TestBed.inject(FolderRepo);
});

it('should get folder with children using the auth token', async () => {
const mockFolderVO = { folderId: 42 } as FolderVO;

httpV2Spy.get.and.returnValues(
of([fakeFolderResponse]),
of([fakeChildrenResponse]),
);

const result = await folderRepo.getWithChildren([mockFolderVO]);

expect(httpV2Spy.get).toHaveBeenCalledWith('v2/folder', {
folderIds: [42],
});

expect(httpV2Spy.get).toHaveBeenCalledWith('v2/folder/42/children', {
pageSize: 99999999,
});

expect(result.isSuccessful).toBeTrue();
expect(result.Results[0].data[0].FolderVO).toBeDefined();
});

it('should get folder with children using the share token', async () => {
const mockFolderVO = { folderId: 42 } as FolderVO;

httpV2Spy.get.and.returnValues(
of([fakeFolderResponse]),
of([fakeChildrenResponse]),
);

const result = await folderRepo.getWithChildren(
[mockFolderVO],
'share-token-123',
);

expect(httpV2Spy.get).toHaveBeenCalledWith(
'v2/folder',
{ folderIds: [42] },
null,
{ authToken: false, shareToken: 'share-token-123' },
);

expect(httpV2Spy.get).toHaveBeenCalledWith(
'v2/folder/42/children',
jasmine.anything(),
null,
{ authToken: false, shareToken: 'share-token-123' },
);

expect(result.Results[0].data[0].FolderVO).toBeDefined();
});

it('should get folder with children using fallback to auth token', async () => {
const mockFolderVO = { folderId: 42 } as FolderVO;

httpV2Spy.get.and.returnValues(
of([emptyResponse]),
of([fakeFolderResponse]),
of([emptyResponse]),
of([fakeChildrenResponse]),
);

const result = await folderRepo.getWithChildren(
[mockFolderVO],
'bad-share-token',
);

expect(httpV2Spy.get).toHaveBeenCalledWith(
'v2/folder',
{ folderIds: [42] },
null,
{ authToken: false, shareToken: 'bad-share-token' },
);

expect(httpV2Spy.get).toHaveBeenCalledWith('v2/folder', {
folderIds: [42],
});

expect(result.Results[0].data[0].FolderVO).toBeDefined();
});
});
104 changes: 67 additions & 37 deletions src/app/shared/services/api/folder.repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,17 +115,17 @@ const convertStelaFolderToFolderVO = (stelaFolder: StelaFolder): FolderVO => {
imageRatio: stelaFolder.imageRatio,
type: stelaFolder.type,
thumbStatus: stelaFolder.status,
thumbURL200: stelaFolder.thumbnailUrls['200'],
thumbURL500: stelaFolder.thumbnailUrls['500'],
thumbURL1000: stelaFolder.thumbnailUrls['1000'],
thumbURL2000: stelaFolder.thumbnailUrls['2000'],
thumbURL200: stelaFolder.thumbnailUrls?.['200'],
thumbURL500: stelaFolder.thumbnailUrls?.['500'],
thumbURL1000: stelaFolder.thumbnailUrls?.['1000'],
thumbURL2000: stelaFolder.thumbnailUrls?.['2000'],
thumbDT: stelaFolder.displayTimestamp,
thumbnail256: stelaFolder.thumbnailUrls['256'],
thumbnail256CloudPath: stelaFolder.thumbnailUrls['256'],
thumbnail256: stelaFolder.thumbnailUrls?.['256'],
thumbnail256CloudPath: stelaFolder.thumbnailUrls?.['256'],
status: stelaFolder.status,
publicDT: stelaFolder.publicAt,
parentFolderId: stelaFolder.parentFolder?.id,
pathAsText: stelaFolder.paths.names,
pathAsText: stelaFolder.paths?.names,
ParentFolderVOs: [new FolderVO({ folderId: stelaFolder.parentFolder?.id })],
ChildFolderVOs: childFolderVOs,
RecordVOs: childRecordVOs,
Expand Down Expand Up @@ -176,23 +176,37 @@ export class FolderRepo extends BaseRepo {
const queryData = {
folderIds: [folderVO.folderId],
};
let options = {};
let folderResponse: PagedStelaResponse<StelaFolder>;
if (shareToken) {
options = {
authToken: false,
shareToken,
};
folderResponse = (
await firstValueFrom(
this.httpV2.get<PagedStelaResponse<StelaFolder>>(
`v2/folder`,
queryData,
null,
{
authToken: false,
shareToken,
},
),
)
)[0];
}
// we do not want to reveal the existence or non-existence of
// matching items, unless the request is authenticated by auth token
// a request authenticated by a share token will not get a 404 or 401,
// it just responds with a 200 and an empty array and if we get an empty array,
// we try as a fallback and see if maybe we can get the files as an authenticated user
if (!folderResponse?.items?.[0]) {
folderResponse = (
await firstValueFrom(
this.httpV2.get<PagedStelaResponse<StelaFolder>>(
`v2/folder`,
queryData,
),
)
)[0];
}
const folderResponse = (
await firstValueFrom(
this.httpV2.get<PagedStelaResponse<StelaFolder>>(
`v2/folder`,
queryData,
null,
options,
),
)
)[0];
return folderResponse.items[0];
}

Expand All @@ -203,23 +217,39 @@ export class FolderRepo extends BaseRepo {
const queryData = {
pageSize: 99999999, // We want all results in one request
};
let options = {};

let childrenResponse: PagedStelaResponse<StelaFolderChild>;
if (shareToken) {
options = {
authToken: false,
shareToken,
};
childrenResponse = (
await firstValueFrom(
this.httpV2.get<PagedStelaResponse<StelaFolderChild>>(
`v2/folder/${folderVO.folderId}/children`,
queryData,
null,
{
authToken: false,
shareToken,
},
),
)
)[0];
}
const childrenResponse = (
await firstValueFrom(
this.httpV2.get<PagedStelaResponse<StelaFolderChild>>(
`v2/folder/${folderVO.folderId}/children`,
queryData,
null,
options,
),
)
)[0];
// we do not want to reveal the existence or non-existence of
// matching items, unless the request is authenticated by auth token
// a request authenticated by a share token will not get a 404 or 401,
// it just responds with a 200 and an empty array and if we get an empty array,
// we try as a fallback and see if maybe we can get the files as an authenticated user
if (!childrenResponse?.items) {
childrenResponse = (
await firstValueFrom(
this.httpV2.get<PagedStelaResponse<StelaFolderChild>>(
`v2/folder/${folderVO.folderId}/children`,
queryData,
),
)
)[0];
}

return childrenResponse.items;
}

Expand Down
31 changes: 29 additions & 2 deletions src/app/shared/services/api/record.repo.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { TestBed } from '@angular/core/testing';
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import {
HttpTestingController,
provideHttpClientTesting,
} from '@angular/common/http/testing';
import { environment } from '@root/environments/environment';
import { HttpService } from '@shared/services/http/http.service';
import { RecordRepo } from '@shared/services/api/record.repo';
import { RecordRepo, RecordResponse } from '@shared/services/api/record.repo';
import { RecordVO } from '@root/app/models';
import {
provideHttpClient,
Expand Down Expand Up @@ -39,6 +39,33 @@ describe('RecordRepo', () => {
httpMock.verify();
});

// in order to test that the request is made with the auth token,
// with the share token and that the fallback works, the test suite
// should be refactored to mock the http and httpV2 services

// isolating the record.repo service functionality from other
// dependencies would make the tests more reliable
it('should use a V2 request to get records by id', fakeAsync(() => {
const fakeRecordVO = {
recordId: 5,
} as unknown as RecordVO;

const recordPromise = repo.get([fakeRecordVO]);

tick();

const req = httpMock.expectOne(
`${environment.apiUrl}/v2/record?recordIds[]=5`,
);

expect(req.request.method).toBe('GET');
expect(req.request.headers.get('Request-Version')).toBe('2');
req.flush([fakeRecordVO]);
recordPromise.then((recordResponse: RecordResponse) => {
expect(recordResponse).toBeDefined();
});
}));

it('should use a V2 request for registerRecord', (done) => {
const testRecord = new RecordVO({
displayName: 'test',
Expand Down
Loading