Skip to content

Commit

Permalink
Set TypeScript to strict mode and fix issues related to server types (i…
Browse files Browse the repository at this point in the history
…mmich-app#261)

* Fix lint issues and some other TS issues

- set TypeScript in strict mode
- add npm commands to lint / check code
- fix all lint issues
- fix some TS issues
- rename User reponse DTO to make it consistent with the other ones
- override Express/User interface to use UserResponseDto interface
 This is for when the accessing the `user` from a Express Request,
 like in `asset-upload-config`

* Fix the rest of TS issues

- fix all the remaining TypeScript errors
- add missing `@types/mapbox__mapbox-sdk` package

* Move global.d.ts to server `src` folder

* Update AssetReponseDto duration type

This is now of type `string` that defaults to '0:00:00.00000' if not set
which is what the mobile app currently expects

* Set context when logging error in asset.service

Use `ServeFile` as the context for logging an error when
asset.resizePath is not set

* Fix wrong AppController merge conflict resolution

`redirectToWebpage` was removed in main as is no longer used.
  • Loading branch information
jbaez authored Jun 25, 2022
1 parent cca2f7d commit c918f5b
Show file tree
Hide file tree
Showing 64 changed files with 415 additions and 273 deletions.
11 changes: 5 additions & 6 deletions server/apps/immich/src/api-v1/album/album-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { UpdateAlbumDto } from './dto/update-album.dto';
export interface IAlbumRepository {
create(ownerId: string, createAlbumDto: CreateAlbumDto): Promise<AlbumEntity>;
getList(ownerId: string, getAlbumsDto: GetAlbumsDto): Promise<AlbumEntity[]>;
get(albumId: string): Promise<AlbumEntity>;
get(albumId: string): Promise<AlbumEntity | undefined>;
delete(album: AlbumEntity): Promise<void>;
addSharedUsers(album: AlbumEntity, addUsersDto: AddUsersDto): Promise<AlbumEntity>;
removeUser(album: AlbumEntity, userId: string): Promise<void>;
Expand All @@ -39,7 +39,7 @@ export class AlbumRepository implements IAlbumRepository {
) {}

async create(ownerId: string, createAlbumDto: CreateAlbumDto): Promise<AlbumEntity> {
return await getConnection().transaction(async (transactionalEntityManager) => {
return getConnection().transaction(async (transactionalEntityManager) => {
// Create album entity
const newAlbum = new AlbumEntity();
newAlbum.ownerId = ownerId;
Expand Down Expand Up @@ -80,7 +80,6 @@ export class AlbumRepository implements IAlbumRepository {

return album;
});
return;
}

getList(ownerId: string, getAlbumsDto: GetAlbumsDto): Promise<AlbumEntity[]> {
Expand Down Expand Up @@ -155,7 +154,7 @@ export class AlbumRepository implements IAlbumRepository {
return;
}
// TODO: sort in query
const sortedSharedAsset = album.assets.sort(
const sortedSharedAsset = album.assets?.sort(
(a, b) => new Date(a.assetInfo.createdAt).valueOf() - new Date(b.assetInfo.createdAt).valueOf(),
);

Expand All @@ -180,7 +179,7 @@ export class AlbumRepository implements IAlbumRepository {
}

await this.userAlbumRepository.save([...newRecords]);
return this.get(album.id);
return this.get(album.id) as Promise<AlbumEntity>; // There is an album for sure
}

async removeUser(album: AlbumEntity, userId: string): Promise<void> {
Expand Down Expand Up @@ -217,7 +216,7 @@ export class AlbumRepository implements IAlbumRepository {
}

await this.assetAlbumRepository.save([...newRecords]);
return this.get(album.id);
return this.get(album.id) as Promise<AlbumEntity>; // There is an album for sure
}

updateAlbum(album: AlbumEntity, updateAlbumDto: UpdateAlbumDto): Promise<AlbumEntity> {
Expand Down
6 changes: 5 additions & 1 deletion server/apps/immich/src/api-v1/album/album.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe('Album service', () => {
albumEntity.createdAt = 'date';
albumEntity.sharedUsers = [];
albumEntity.assets = [];
albumEntity.albumThumbnailAssetId = null;

return albumEntity;
};
Expand All @@ -36,6 +37,7 @@ describe('Album service', () => {
albumEntity.albumName = 'name';
albumEntity.createdAt = 'date';
albumEntity.assets = [];
albumEntity.albumThumbnailAssetId = null;
albumEntity.sharedUsers = [
{
id: '99',
Expand All @@ -60,6 +62,7 @@ describe('Album service', () => {
albumEntity.albumName = 'name';
albumEntity.createdAt = 'date';
albumEntity.assets = [];
albumEntity.albumThumbnailAssetId = null;
albumEntity.sharedUsers = [
{
id: '99',
Expand Down Expand Up @@ -96,6 +99,7 @@ describe('Album service', () => {
albumEntity.createdAt = 'date';
albumEntity.sharedUsers = [];
albumEntity.assets = [];
albumEntity.albumThumbnailAssetId = null;

return albumEntity;
};
Expand Down Expand Up @@ -151,7 +155,7 @@ describe('Album service', () => {

const expectedResult: AlbumResponseDto = {
albumName: 'name',
albumThumbnailAssetId: undefined,
albumThumbnailAssetId: null,
createdAt: 'date',
id: '0001',
ownerId,
Expand Down
2 changes: 1 addition & 1 deletion server/apps/immich/src/api-v1/album/album.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class AlbumService {

if (validateIsOwner && !isOwner) {
throw new ForbiddenException('Unauthorized Album Access');
} else if (!isOwner && !album.sharedUsers.some((user) => user.sharedUserId == authUser.id)) {
} else if (!isOwner && !album.sharedUsers?.some((user) => user.sharedUserId == authUser.id)) {
throw new ForbiddenException('Unauthorized Album Access');
}
return album;
Expand Down
2 changes: 1 addition & 1 deletion server/apps/immich/src/api-v1/album/dto/add-assets.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { IsNotEmpty } from 'class-validator';

export class AddAssetsDto {
@IsNotEmpty()
assetIds: string[];
assetIds!: string[];
}
2 changes: 1 addition & 1 deletion server/apps/immich/src/api-v1/album/dto/add-users.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { IsNotEmpty } from 'class-validator';

export class AddUsersDto {
@IsNotEmpty()
sharedUserIds: string[];
sharedUserIds!: string[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { IsNotEmpty, IsOptional } from 'class-validator';

export class CreateAlbumDto {
@IsNotEmpty()
albumName: string;
albumName!: string;

@IsOptional()
sharedWithUserIds?: string[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { IsNotEmpty } from 'class-validator';

export class RemoveAssetsDto {
@IsNotEmpty()
assetIds: string[];
assetIds!: string[];
}
4 changes: 2 additions & 2 deletions server/apps/immich/src/api-v1/album/dto/update-album.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { IsNotEmpty } from 'class-validator';

export class UpdateAlbumDto {
@IsNotEmpty()
albumName: string;
albumName!: string;

@IsNotEmpty()
ownerId: string;
ownerId!: string;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AlbumEntity } from '../../../../../../libs/database/src/entities/album.entity';
import { User, mapUser } from '../../user/response-dto/user';
import { UserResponseDto, mapUser } from '../../user/response-dto/user-response.dto';
import { AssetResponseDto, mapAsset } from '../../asset/response-dto/asset-response.dto';

export interface AlbumResponseDto {
Expand All @@ -9,7 +9,7 @@ export interface AlbumResponseDto {
createdAt: string;
albumThumbnailAssetId: string | null;
shared: boolean;
sharedUsers: User[];
sharedUsers: UserResponseDto[];
assets: AssetResponseDto[];
}

Expand Down
21 changes: 12 additions & 9 deletions server/apps/immich/src/api-v1/asset/asset.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
Headers,
Delete,
Logger,
Patch,
HttpCode,
} from '@nestjs/common';
import { JwtAuthGuard } from '../../modules/immich-jwt/guards/jwt-auth.guard';
Expand All @@ -25,9 +24,7 @@ import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator';
import { CreateAssetDto } from './dto/create-asset.dto';
import { ServeFileDto } from './dto/serve-file.dto';
import { AssetEntity } from '@app/database/entities/asset.entity';
import { GetAllAssetQueryDto } from './dto/get-all-asset-query.dto';
import { Response as Res } from 'express';
import { GetNewAssetQueryDto } from './dto/get-new-asset-query.dto';
import { BackgroundTaskService } from '../../modules/background-task/background-task.service';
import { DeleteAssetDto } from './dto/delete-asset.dto';
import { SearchAssetDto } from './dto/search-asset.dto';
Expand Down Expand Up @@ -58,15 +55,18 @@ export class AssetController {
),
)
async uploadFile(
@GetAuthUser() authUser,
@GetAuthUser() authUser: AuthUserDto,
@UploadedFiles() uploadFiles: { assetData: Express.Multer.File[]; thumbnailData?: Express.Multer.File[] },
@Body(ValidationPipe) assetInfo: CreateAssetDto,
) {
): Promise<'ok' | undefined> {
for (const file of uploadFiles.assetData) {
try {
const savedAsset = await this.assetService.createUserAsset(authUser, assetInfo, file.path, file.mimetype);

if (uploadFiles.thumbnailData != null && savedAsset) {
if (!savedAsset) {
return;
}
if (uploadFiles.thumbnailData != null) {
const assetWithThumbnail = await this.assetService.updateThumbnailInfo(
savedAsset,
uploadFiles.thumbnailData[0].path,
Expand Down Expand Up @@ -107,11 +107,11 @@ export class AssetController {

@Get('/file')
async serveFile(
@Headers() headers,
@Headers() headers: Record<string, string>,
@GetAuthUser() authUser: AuthUserDto,
@Response({ passthrough: true }) res: Res,
@Query(ValidationPipe) query: ServeFileDto,
): Promise<StreamableFile> {
): Promise<StreamableFile | undefined> {
return this.assetService.serveFile(authUser, query, res, headers);
}

Expand Down Expand Up @@ -151,7 +151,7 @@ export class AssetController {
}

@Get('/assetById/:assetId')
async getAssetById(@GetAuthUser() authUser: AuthUserDto, @Param('assetId') assetId) {
async getAssetById(@GetAuthUser() authUser: AuthUserDto, @Param('assetId') assetId: string) {
return await this.assetService.getAssetById(authUser, assetId);
}

Expand All @@ -161,6 +161,9 @@ export class AssetController {

for (const id of assetIds.ids) {
const assets = await this.assetService.getAssetById(authUser, id);
if (!assets) {
continue;
}
deleteAssetList.push(assets);
}

Expand Down
Loading

0 comments on commit c918f5b

Please sign in to comment.