1
0
mirror of https://github.com/immich-app/immich.git synced 2024-12-25 10:43:13 +02:00

chore(server,mobile): remove device info entity (#1527)

* chore(server): remove unused device info code

* chore: generate open api

* remove any DeviceTypeEnum usage from mobile

* chore: coverage

* fix: drop device info table

---------

Co-authored-by: Fynn Petersen-Frey <zody22@gmail.com>
This commit is contained in:
Jason Rasmussen 2023-04-28 16:01:03 -04:00 committed by GitHub
parent 1e97407025
commit e22cdea485
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 34 additions and 606 deletions

View File

@ -1,8 +1,5 @@
import 'package:openapi/api.dart';
class AuthenticationState { class AuthenticationState {
final String deviceId; final String deviceId;
final DeviceTypeEnum deviceType;
final String userId; final String userId;
final String userEmail; final String userEmail;
final bool isAuthenticated; final bool isAuthenticated;
@ -13,7 +10,6 @@ class AuthenticationState {
final String profileImagePath; final String profileImagePath;
AuthenticationState({ AuthenticationState({
required this.deviceId, required this.deviceId,
required this.deviceType,
required this.userId, required this.userId,
required this.userEmail, required this.userEmail,
required this.isAuthenticated, required this.isAuthenticated,
@ -26,7 +22,6 @@ class AuthenticationState {
AuthenticationState copyWith({ AuthenticationState copyWith({
String? deviceId, String? deviceId,
DeviceTypeEnum? deviceType,
String? userId, String? userId,
String? userEmail, String? userEmail,
bool? isAuthenticated, bool? isAuthenticated,
@ -38,7 +33,6 @@ class AuthenticationState {
}) { }) {
return AuthenticationState( return AuthenticationState(
deviceId: deviceId ?? this.deviceId, deviceId: deviceId ?? this.deviceId,
deviceType: deviceType ?? this.deviceType,
userId: userId ?? this.userId, userId: userId ?? this.userId,
userEmail: userEmail ?? this.userEmail, userEmail: userEmail ?? this.userEmail,
isAuthenticated: isAuthenticated ?? this.isAuthenticated, isAuthenticated: isAuthenticated ?? this.isAuthenticated,
@ -52,7 +46,7 @@ class AuthenticationState {
@override @override
String toString() { String toString() {
return 'AuthenticationState(deviceId: $deviceId, deviceType: $deviceType, userId: $userId, userEmail: $userEmail, isAuthenticated: $isAuthenticated, firstName: $firstName, lastName: $lastName, isAdmin: $isAdmin, shouldChangePassword: $shouldChangePassword, profileImagePath: $profileImagePath)'; return 'AuthenticationState(deviceId: $deviceId, userId: $userId, userEmail: $userEmail, isAuthenticated: $isAuthenticated, firstName: $firstName, lastName: $lastName, isAdmin: $isAdmin, shouldChangePassword: $shouldChangePassword, profileImagePath: $profileImagePath)';
} }
@override @override
@ -61,7 +55,6 @@ class AuthenticationState {
return other is AuthenticationState && return other is AuthenticationState &&
other.deviceId == deviceId && other.deviceId == deviceId &&
other.deviceType == deviceType &&
other.userId == userId && other.userId == userId &&
other.userEmail == userEmail && other.userEmail == userEmail &&
other.isAuthenticated == isAuthenticated && other.isAuthenticated == isAuthenticated &&
@ -75,7 +68,6 @@ class AuthenticationState {
@override @override
int get hashCode { int get hashCode {
return deviceId.hashCode ^ return deviceId.hashCode ^
deviceType.hashCode ^
userId.hashCode ^ userId.hashCode ^
userEmail.hashCode ^ userEmail.hashCode ^
isAuthenticated.hashCode ^ isAuthenticated.hashCode ^

View File

@ -3,24 +3,22 @@ import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_udid/flutter_udid.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/shared/models/store.dart'; import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/modules/login/models/authentication_state.model.dart'; import 'package:immich_mobile/modules/login/models/authentication_state.model.dart';
import 'package:immich_mobile/shared/models/user.dart'; import 'package:immich_mobile/shared/models/user.dart';
import 'package:immich_mobile/shared/providers/api.provider.dart'; import 'package:immich_mobile/shared/providers/api.provider.dart';
import 'package:immich_mobile/shared/services/api.service.dart'; import 'package:immich_mobile/shared/services/api.service.dart';
import 'package:immich_mobile/shared/services/device_info.service.dart';
import 'package:immich_mobile/utils/hash.dart'; import 'package:immich_mobile/utils/hash.dart';
import 'package:openapi/api.dart'; import 'package:openapi/api.dart';
class AuthenticationNotifier extends StateNotifier<AuthenticationState> { class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
AuthenticationNotifier( AuthenticationNotifier(
this._deviceInfoService,
this._apiService, this._apiService,
) : super( ) : super(
AuthenticationState( AuthenticationState(
deviceId: "", deviceId: "",
deviceType: DeviceTypeEnum.ANDROID,
userId: "", userId: "",
userEmail: "", userEmail: "",
firstName: '', firstName: '',
@ -32,7 +30,6 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
), ),
); );
final DeviceInfoService _deviceInfoService;
final ApiService _apiService; final ApiService _apiService;
Future<bool> login( Future<bool> login(
@ -146,9 +143,9 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
} }
if (userResponseDto != null) { if (userResponseDto != null) {
var deviceInfo = await _deviceInfoService.getDeviceInfo(); final deviceId = await FlutterUdid.consistentUdid;
Store.put(StoreKey.deviceId, deviceInfo["deviceId"]); Store.put(StoreKey.deviceId, deviceId);
Store.put(StoreKey.deviceIdHash, fastHash(deviceInfo["deviceId"])); Store.put(StoreKey.deviceIdHash, fastHash(deviceId));
Store.put(StoreKey.currentUser, User.fromDto(userResponseDto)); Store.put(StoreKey.currentUser, User.fromDto(userResponseDto));
Store.put(StoreKey.serverUrl, serverUrl); Store.put(StoreKey.serverUrl, serverUrl);
Store.put(StoreKey.accessToken, accessToken); Store.put(StoreKey.accessToken, accessToken);
@ -162,8 +159,7 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
profileImagePath: userResponseDto.profileImagePath, profileImagePath: userResponseDto.profileImagePath,
isAdmin: userResponseDto.isAdmin, isAdmin: userResponseDto.isAdmin,
shouldChangePassword: userResponseDto.shouldChangePassword, shouldChangePassword: userResponseDto.shouldChangePassword,
deviceId: deviceInfo["deviceId"], deviceId: deviceId,
deviceType: deviceInfo["deviceType"],
); );
} }
return true; return true;
@ -173,7 +169,6 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
final authenticationProvider = final authenticationProvider =
StateNotifierProvider<AuthenticationNotifier, AuthenticationState>((ref) { StateNotifierProvider<AuthenticationNotifier, AuthenticationState>((ref) {
return AuthenticationNotifier( return AuthenticationNotifier(
ref.watch(deviceInfoServiceProvider),
ref.watch(apiServiceProvider), ref.watch(apiServiceProvider),
); );
}); });

View File

@ -1,23 +0,0 @@
import 'package:flutter_udid/flutter_udid.dart';
import 'dart:io' show Platform;
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:openapi/api.dart';
final deviceInfoServiceProvider = Provider((_) => DeviceInfoService());
class DeviceInfoService {
Future<Map<String, dynamic>> getDeviceInfo() async {
// Get device info
var deviceId = await FlutterUdid.consistentUdid;
var deviceType = DeviceTypeEnum.ANDROID;
if (Platform.isAndroid) {
deviceType = DeviceTypeEnum.ANDROID;
} else if (Platform.isIOS) {
deviceType = DeviceTypeEnum.IOS;
}
return {"deviceId": deviceId, "deviceType": deviceType};
}
}

View File

@ -41,9 +41,6 @@ doc/CuratedObjectsResponseDto.md
doc/DeleteAssetDto.md doc/DeleteAssetDto.md
doc/DeleteAssetResponseDto.md doc/DeleteAssetResponseDto.md
doc/DeleteAssetStatus.md doc/DeleteAssetStatus.md
doc/DeviceInfoApi.md
doc/DeviceInfoResponseDto.md
doc/DeviceTypeEnum.md
doc/DownloadFilesDto.md doc/DownloadFilesDto.md
doc/EditSharedLinkDto.md doc/EditSharedLinkDto.md
doc/ExifResponseDto.md doc/ExifResponseDto.md
@ -100,7 +97,6 @@ doc/UpdateAlbumDto.md
doc/UpdateAssetDto.md doc/UpdateAssetDto.md
doc/UpdateTagDto.md doc/UpdateTagDto.md
doc/UpdateUserDto.md doc/UpdateUserDto.md
doc/UpsertDeviceInfoDto.md
doc/UsageByUserDto.md doc/UsageByUserDto.md
doc/UserApi.md doc/UserApi.md
doc/UserCountResponseDto.md doc/UserCountResponseDto.md
@ -112,7 +108,6 @@ lib/api/album_api.dart
lib/api/api_key_api.dart lib/api/api_key_api.dart
lib/api/asset_api.dart lib/api/asset_api.dart
lib/api/authentication_api.dart lib/api/authentication_api.dart
lib/api/device_info_api.dart
lib/api/job_api.dart lib/api/job_api.dart
lib/api/o_auth_api.dart lib/api/o_auth_api.dart
lib/api/search_api.dart lib/api/search_api.dart
@ -163,8 +158,6 @@ lib/model/curated_objects_response_dto.dart
lib/model/delete_asset_dto.dart lib/model/delete_asset_dto.dart
lib/model/delete_asset_response_dto.dart lib/model/delete_asset_response_dto.dart
lib/model/delete_asset_status.dart lib/model/delete_asset_status.dart
lib/model/device_info_response_dto.dart
lib/model/device_type_enum.dart
lib/model/download_files_dto.dart lib/model/download_files_dto.dart
lib/model/edit_shared_link_dto.dart lib/model/edit_shared_link_dto.dart
lib/model/exif_response_dto.dart lib/model/exif_response_dto.dart
@ -214,7 +207,6 @@ lib/model/update_album_dto.dart
lib/model/update_asset_dto.dart lib/model/update_asset_dto.dart
lib/model/update_tag_dto.dart lib/model/update_tag_dto.dart
lib/model/update_user_dto.dart lib/model/update_user_dto.dart
lib/model/upsert_device_info_dto.dart
lib/model/usage_by_user_dto.dart lib/model/usage_by_user_dto.dart
lib/model/user_count_response_dto.dart lib/model/user_count_response_dto.dart
lib/model/user_response_dto.dart lib/model/user_response_dto.dart
@ -258,9 +250,6 @@ test/curated_objects_response_dto_test.dart
test/delete_asset_dto_test.dart test/delete_asset_dto_test.dart
test/delete_asset_response_dto_test.dart test/delete_asset_response_dto_test.dart
test/delete_asset_status_test.dart test/delete_asset_status_test.dart
test/device_info_api_test.dart
test/device_info_response_dto_test.dart
test/device_type_enum_test.dart
test/download_files_dto_test.dart test/download_files_dto_test.dart
test/edit_shared_link_dto_test.dart test/edit_shared_link_dto_test.dart
test/exif_response_dto_test.dart test/exif_response_dto_test.dart
@ -317,7 +306,6 @@ test/update_album_dto_test.dart
test/update_asset_dto_test.dart test/update_asset_dto_test.dart
test/update_tag_dto_test.dart test/update_tag_dto_test.dart
test/update_user_dto_test.dart test/update_user_dto_test.dart
test/upsert_device_info_dto_test.dart
test/usage_by_user_dto_test.dart test/usage_by_user_dto_test.dart
test/user_api_test.dart test/user_api_test.dart
test/user_count_response_dto_test.dart test/user_count_response_dto_test.dart

BIN
mobile/openapi/README.md generated

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -10,7 +10,6 @@ import {
AlbumController, AlbumController,
APIKeyController, APIKeyController,
AuthController, AuthController,
DeviceInfoController,
JobController, JobController,
OAuthController, OAuthController,
SearchController, SearchController,
@ -36,7 +35,6 @@ import { AppCronJobs } from './app.cron-jobs';
AlbumController, AlbumController,
APIKeyController, APIKeyController,
AuthController, AuthController,
DeviceInfoController,
JobController, JobController,
OAuthController, OAuthController,
SearchController, SearchController,

View File

@ -1,24 +0,0 @@
import {
AuthUserDto,
DeviceInfoResponseDto as ResponseDto,
DeviceInfoService,
UpsertDeviceInfoDto as UpsertDto,
} from '@app/domain';
import { Body, Controller, Put } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { GetAuthUser } from '../decorators/auth-user.decorator';
import { Authenticated } from '../decorators/authenticated.decorator';
import { UseValidation } from '../decorators/use-validation.decorator';
@ApiTags('Device Info')
@Controller('device-info')
@Authenticated()
@UseValidation()
export class DeviceInfoController {
constructor(private readonly service: DeviceInfoService) {}
@Put()
upsertDeviceInfo(@GetAuthUser() authUser: AuthUserDto, @Body() dto: UpsertDto): Promise<ResponseDto> {
return this.service.upsert(authUser, dto);
}
}

View File

@ -1,7 +1,6 @@
export * from './album.controller'; export * from './album.controller';
export * from './api-key.controller'; export * from './api-key.controller';
export * from './auth.controller'; export * from './auth.controller';
export * from './device-info.controller';
export * from './job.controller'; export * from './job.controller';
export * from './oauth.controller'; export * from './oauth.controller';
export * from './search.controller'; export * from './search.controller';

View File

@ -500,45 +500,6 @@
] ]
} }
}, },
"/device-info": {
"put": {
"operationId": "upsertDeviceInfo",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpsertDeviceInfoDto"
}
}
}
},
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeviceInfoResponseDto"
}
}
}
}
},
"tags": [
"Device Info"
],
"security": [
{
"bearer": []
},
{
"cookie": []
}
]
}
},
"/jobs": { "/jobs": {
"get": { "get": {
"operationId": "getAllJobsStatus", "operationId": "getAllJobsStatus",
@ -4124,63 +4085,6 @@
"redirectUri" "redirectUri"
] ]
}, },
"DeviceTypeEnum": {
"type": "string",
"enum": [
"IOS",
"ANDROID",
"WEB"
]
},
"UpsertDeviceInfoDto": {
"type": "object",
"properties": {
"deviceType": {
"$ref": "#/components/schemas/DeviceTypeEnum"
},
"deviceId": {
"type": "string"
},
"isAutoBackup": {
"type": "boolean"
}
},
"required": [
"deviceType",
"deviceId"
]
},
"DeviceInfoResponseDto": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"deviceType": {
"$ref": "#/components/schemas/DeviceTypeEnum"
},
"userId": {
"type": "string"
},
"deviceId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"isAutoBackup": {
"type": "boolean"
}
},
"required": [
"id",
"deviceType",
"userId",
"deviceId",
"createdAt",
"isAutoBackup"
]
},
"JobCountsDto": { "JobCountsDto": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -1,23 +0,0 @@
import { DeviceInfoEntity } from '@app/infra/entities';
import { IDeviceInfoRepository } from './device-info.repository';
type UpsertKeys = Pick<DeviceInfoEntity, 'deviceId' | 'userId'>;
type UpsertEntity = UpsertKeys & Partial<DeviceInfoEntity>;
export class DeviceInfoCore {
constructor(private repository: IDeviceInfoRepository) {}
async upsert(entity: UpsertEntity) {
const exists = await this.repository.get(entity.userId, entity.deviceId);
if (!exists) {
if (!entity.isAutoBackup) {
entity.isAutoBackup = false;
}
return this.repository.save(entity);
}
exists.isAutoBackup = entity.isAutoBackup ?? exists.isAutoBackup;
exists.deviceType = entity.deviceType ?? exists.deviceType;
return this.repository.save(exists);
}
}

View File

@ -1,8 +0,0 @@
import { DeviceInfoEntity } from '@app/infra/entities';
export const IDeviceInfoRepository = 'IDeviceInfoRepository';
export interface IDeviceInfoRepository {
get(userId: string, deviceId: string): Promise<DeviceInfoEntity | null>;
save(entity: Partial<DeviceInfoEntity>): Promise<DeviceInfoEntity>;
}

View File

@ -1,63 +0,0 @@
import { DeviceInfoEntity, DeviceType } from '@app/infra/entities';
import { authStub, newDeviceInfoRepositoryMock } from '../../test';
import { IDeviceInfoRepository } from './device-info.repository';
import { DeviceInfoService } from './device-info.service';
const deviceId = 'device-123';
const userId = 'user-123';
describe('DeviceInfoService', () => {
let sut: DeviceInfoService;
let repositoryMock: jest.Mocked<IDeviceInfoRepository>;
beforeEach(async () => {
repositoryMock = newDeviceInfoRepositoryMock();
sut = new DeviceInfoService(repositoryMock);
});
it('should be defined', () => {
expect(sut).toBeDefined();
});
describe('upsert', () => {
it('should create a new record', async () => {
const request = { deviceId, userId, deviceType: DeviceType.IOS } as DeviceInfoEntity;
const response = { ...request, id: 1 } as DeviceInfoEntity;
repositoryMock.get.mockResolvedValue(null);
repositoryMock.save.mockResolvedValue(response);
await expect(sut.upsert(authStub.user1, request)).resolves.toEqual(response);
expect(repositoryMock.get).toHaveBeenCalledTimes(1);
expect(repositoryMock.save).toHaveBeenCalledTimes(1);
});
it('should update an existing record', async () => {
const request = { deviceId, userId, deviceType: DeviceType.IOS, isAutoBackup: true } as DeviceInfoEntity;
const response = { ...request, id: 1 } as DeviceInfoEntity;
repositoryMock.get.mockResolvedValue(response);
repositoryMock.save.mockResolvedValue(response);
await expect(sut.upsert(authStub.user1, request)).resolves.toEqual(response);
expect(repositoryMock.get).toHaveBeenCalledTimes(1);
expect(repositoryMock.save).toHaveBeenCalledTimes(1);
});
it('should keep properties that were not updated', async () => {
const request = { deviceId, userId } as DeviceInfoEntity;
const response = { id: 1, isAutoBackup: true, deviceId, userId, deviceType: DeviceType.WEB } as DeviceInfoEntity;
repositoryMock.get.mockResolvedValue(response);
repositoryMock.save.mockResolvedValue(response);
await expect(sut.upsert(authStub.user1, request)).resolves.toEqual(response);
expect(repositoryMock.get).toHaveBeenCalledTimes(1);
expect(repositoryMock.save).toHaveBeenCalledTimes(1);
});
});
});

View File

@ -1,20 +0,0 @@
import { Inject, Injectable } from '@nestjs/common';
import { AuthUserDto } from '../auth';
import { DeviceInfoCore } from './device-info.core';
import { IDeviceInfoRepository } from './device-info.repository';
import { UpsertDeviceInfoDto } from './dto';
import { DeviceInfoResponseDto, mapDeviceInfoResponse } from './response-dto';
@Injectable()
export class DeviceInfoService {
private core: DeviceInfoCore;
constructor(@Inject(IDeviceInfoRepository) repository: IDeviceInfoRepository) {
this.core = new DeviceInfoCore(repository);
}
public async upsert(authUser: AuthUserDto, dto: UpsertDeviceInfoDto): Promise<DeviceInfoResponseDto> {
const deviceInfo = await this.core.upsert({ ...dto, userId: authUser.id });
return mapDeviceInfoResponse(deviceInfo);
}
}

View File

@ -1 +0,0 @@
export * from './upsert-device-info.dto';

View File

@ -1,15 +0,0 @@
import { IsNotEmpty, IsOptional } from 'class-validator';
import { DeviceType } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger';
export class UpsertDeviceInfoDto {
@IsNotEmpty()
deviceId!: string;
@IsNotEmpty()
@ApiProperty({ enumName: 'DeviceTypeEnum', enum: DeviceType })
deviceType!: DeviceType;
@IsOptional()
isAutoBackup?: boolean;
}

View File

@ -1,4 +0,0 @@
export * from './device-info.repository';
export * from './device-info.service';
export * from './dto';
export * from './response-dto';

View File

@ -1,26 +0,0 @@
import { DeviceInfoEntity, DeviceType } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger';
export class DeviceInfoResponseDto {
@ApiProperty({ type: 'integer' })
id!: number;
userId!: string;
deviceId!: string;
@ApiProperty({ enumName: 'DeviceTypeEnum', enum: DeviceType })
deviceType!: DeviceType;
createdAt!: string;
isAutoBackup!: boolean;
}
export function mapDeviceInfoResponse(entity: DeviceInfoEntity): DeviceInfoResponseDto {
return {
id: entity.id,
userId: entity.userId,
deviceId: entity.deviceId,
deviceType: entity.deviceType,
createdAt: entity.createdAt,
isAutoBackup: entity.isAutoBackup,
};
}

View File

@ -1 +0,0 @@
export * from './device-info-response.dto';

View File

@ -3,7 +3,6 @@ import { AlbumService } from './album';
import { APIKeyService } from './api-key'; import { APIKeyService } from './api-key';
import { AssetService } from './asset'; import { AssetService } from './asset';
import { AuthService } from './auth'; import { AuthService } from './auth';
import { DeviceInfoService } from './device-info';
import { JobService } from './job'; import { JobService } from './job';
import { MediaService } from './media'; import { MediaService } from './media';
import { OAuthService } from './oauth'; import { OAuthService } from './oauth';
@ -21,7 +20,6 @@ const providers: Provider[] = [
AssetService, AssetService,
APIKeyService, APIKeyService,
AuthService, AuthService,
DeviceInfoService,
JobService, JobService,
MediaService, MediaService,
OAuthService, OAuthService,

View File

@ -4,7 +4,6 @@ export * from './asset';
export * from './auth'; export * from './auth';
export * from './communication'; export * from './communication';
export * from './crypto'; export * from './crypto';
export * from './device-info';
export * from './domain.config'; export * from './domain.config';
export * from './domain.constant'; export * from './domain.constant';
export * from './domain.module'; export * from './domain.module';

View File

@ -1,8 +0,0 @@
import { IDeviceInfoRepository } from '../src';
export const newDeviceInfoRepositoryMock = (): jest.Mocked<IDeviceInfoRepository> => {
return {
get: jest.fn(),
save: jest.fn(),
};
};

View File

@ -3,7 +3,6 @@ export * from './api-key.repository.mock';
export * from './asset.repository.mock'; export * from './asset.repository.mock';
export * from './communication.repository.mock'; export * from './communication.repository.mock';
export * from './crypto.repository.mock'; export * from './crypto.repository.mock';
export * from './device-info.repository.mock';
export * from './fixtures'; export * from './fixtures';
export * from './job.repository.mock'; export * from './job.repository.mock';
export * from './machine-learning.repository.mock'; export * from './machine-learning.repository.mock';

View File

@ -1,32 +0,0 @@
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, Unique } from 'typeorm';
@Entity('device_info')
@Unique(['userId', 'deviceId'])
export class DeviceInfoEntity {
@PrimaryGeneratedColumn()
id!: number;
@Column()
userId!: string;
@Column()
deviceId!: string;
@Column()
deviceType!: DeviceType;
@Column({ type: 'varchar', nullable: true })
notificationToken!: string | null;
@CreateDateColumn()
createdAt!: string;
@Column({ type: 'bool', default: false })
isAutoBackup!: boolean;
}
export enum DeviceType {
IOS = 'IOS',
ANDROID = 'ANDROID',
WEB = 'WEB',
}

View File

@ -1,7 +1,6 @@
import { AlbumEntity } from './album.entity'; import { AlbumEntity } from './album.entity';
import { APIKeyEntity } from './api-key.entity'; import { APIKeyEntity } from './api-key.entity';
import { AssetEntity } from './asset.entity'; import { AssetEntity } from './asset.entity';
import { DeviceInfoEntity } from './device-info.entity';
import { SharedLinkEntity } from './shared-link.entity'; import { SharedLinkEntity } from './shared-link.entity';
import { SmartInfoEntity } from './smart-info.entity'; import { SmartInfoEntity } from './smart-info.entity';
import { SystemConfigEntity } from './system-config.entity'; import { SystemConfigEntity } from './system-config.entity';
@ -11,7 +10,6 @@ import { UserEntity } from './user.entity';
export * from './album.entity'; export * from './album.entity';
export * from './api-key.entity'; export * from './api-key.entity';
export * from './asset.entity'; export * from './asset.entity';
export * from './device-info.entity';
export * from './exif.entity'; export * from './exif.entity';
export * from './shared-link.entity'; export * from './shared-link.entity';
export * from './smart-info.entity'; export * from './smart-info.entity';
@ -24,7 +22,6 @@ export const databaseEntities = [
AssetEntity, AssetEntity,
AlbumEntity, AlbumEntity,
APIKeyEntity, APIKeyEntity,
DeviceInfoEntity,
UserEntity, UserEntity,
SharedLinkEntity, SharedLinkEntity,
SmartInfoEntity, SmartInfoEntity,

View File

@ -3,7 +3,6 @@ import {
IAssetRepository, IAssetRepository,
ICommunicationRepository, ICommunicationRepository,
ICryptoRepository, ICryptoRepository,
IDeviceInfoRepository,
IGeocodingRepository, IGeocodingRepository,
IJobRepository, IJobRepository,
IKeyRepository, IKeyRepository,
@ -32,7 +31,6 @@ import {
AssetRepository, AssetRepository,
CommunicationRepository, CommunicationRepository,
CryptoRepository, CryptoRepository,
DeviceInfoRepository,
FilesystemProvider, FilesystemProvider,
GeocodingRepository, GeocodingRepository,
JobRepository, JobRepository,
@ -51,7 +49,6 @@ const providers: Provider[] = [
{ provide: IAssetRepository, useClass: AssetRepository }, { provide: IAssetRepository, useClass: AssetRepository },
{ provide: ICommunicationRepository, useClass: CommunicationRepository }, { provide: ICommunicationRepository, useClass: CommunicationRepository },
{ provide: ICryptoRepository, useClass: CryptoRepository }, { provide: ICryptoRepository, useClass: CryptoRepository },
{ provide: IDeviceInfoRepository, useClass: DeviceInfoRepository },
{ provide: IGeocodingRepository, useClass: GeocodingRepository }, { provide: IGeocodingRepository, useClass: GeocodingRepository },
{ provide: IJobRepository, useClass: JobRepository }, { provide: IJobRepository, useClass: JobRepository },
{ provide: IKeyRepository, useClass: APIKeyRepository }, { provide: IKeyRepository, useClass: APIKeyRepository },

View File

@ -0,0 +1,26 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class DropDeviceInfoTable1682710252424 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`drop table device_info`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
create table if not exists device_info
(
id serial
constraint "PK_b1c15a80b0a4e5f4eebadbdd92c"
primary key,
"userId" varchar not null,
"deviceId" varchar not null,
"deviceType" varchar not null,
"notificationToken" varchar,
"createdAt" timestamp default now() not null,
"isAutoBackup" boolean default false not null,
constraint "UQ_ebad78f36b10d15fbea8560e107"
unique ("userId", "deviceId")
);
`);
}
}

View File

@ -1,16 +0,0 @@
import { IDeviceInfoRepository } from '@app/domain';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { DeviceInfoEntity } from '../entities';
export class DeviceInfoRepository implements IDeviceInfoRepository {
constructor(@InjectRepository(DeviceInfoEntity) private repository: Repository<DeviceInfoEntity>) {}
get(userId: string, deviceId: string): Promise<DeviceInfoEntity | null> {
return this.repository.findOne({ where: { userId, deviceId } });
}
save(entity: Partial<DeviceInfoEntity>): Promise<DeviceInfoEntity> {
return this.repository.save(entity);
}
}

View File

@ -3,7 +3,6 @@ export * from './api-key.repository';
export * from './asset.repository'; export * from './asset.repository';
export * from './communication.repository'; export * from './communication.repository';
export * from './crypto.repository'; export * from './crypto.repository';
export * from './device-info.repository';
export * from './filesystem.provider'; export * from './filesystem.provider';
export * from './geocoding.repository'; export * from './geocoding.repository';
export * from './job.repository'; export * from './job.repository';

View File

@ -141,9 +141,9 @@
"coverageThreshold": { "coverageThreshold": {
"./libs/domain/": { "./libs/domain/": {
"branches": 80, "branches": 80,
"functions": 88, "functions": 87,
"lines": 94, "lines": 94,
"statements": 94 "statements": 93
} }
}, },
"setupFilesAfterEnv": [ "setupFilesAfterEnv": [

View File

@ -5,7 +5,6 @@ import {
AuthenticationApi, AuthenticationApi,
Configuration, Configuration,
ConfigurationParameters, ConfigurationParameters,
DeviceInfoApi,
JobApi, JobApi,
OAuthApi, OAuthApi,
SearchApi, SearchApi,
@ -24,7 +23,6 @@ export class ImmichApi {
public assetApi: AssetApi; public assetApi: AssetApi;
public authenticationApi: AuthenticationApi; public authenticationApi: AuthenticationApi;
public oauthApi: OAuthApi; public oauthApi: OAuthApi;
public deviceInfoApi: DeviceInfoApi;
public searchApi: SearchApi; public searchApi: SearchApi;
public serverInfoApi: ServerInfoApi; public serverInfoApi: ServerInfoApi;
public jobApi: JobApi; public jobApi: JobApi;
@ -42,7 +40,6 @@ export class ImmichApi {
this.assetApi = new AssetApi(this.config); this.assetApi = new AssetApi(this.config);
this.authenticationApi = new AuthenticationApi(this.config); this.authenticationApi = new AuthenticationApi(this.config);
this.oauthApi = new OAuthApi(this.config); this.oauthApi = new OAuthApi(this.config);
this.deviceInfoApi = new DeviceInfoApi(this.config);
this.serverInfoApi = new ServerInfoApi(this.config); this.serverInfoApi = new ServerInfoApi(this.config);
this.jobApi = new JobApi(this.config); this.jobApi = new JobApi(this.config);
this.keyApi = new APIKeyApi(this.config); this.keyApi = new APIKeyApi(this.config);

View File

@ -1021,66 +1021,6 @@ export const DeleteAssetStatus = {
export type DeleteAssetStatus = typeof DeleteAssetStatus[keyof typeof DeleteAssetStatus]; export type DeleteAssetStatus = typeof DeleteAssetStatus[keyof typeof DeleteAssetStatus];
/**
*
* @export
* @interface DeviceInfoResponseDto
*/
export interface DeviceInfoResponseDto {
/**
*
* @type {number}
* @memberof DeviceInfoResponseDto
*/
'id': number;
/**
*
* @type {DeviceTypeEnum}
* @memberof DeviceInfoResponseDto
*/
'deviceType': DeviceTypeEnum;
/**
*
* @type {string}
* @memberof DeviceInfoResponseDto
*/
'userId': string;
/**
*
* @type {string}
* @memberof DeviceInfoResponseDto
*/
'deviceId': string;
/**
*
* @type {string}
* @memberof DeviceInfoResponseDto
*/
'createdAt': string;
/**
*
* @type {boolean}
* @memberof DeviceInfoResponseDto
*/
'isAutoBackup': boolean;
}
/**
*
* @export
* @enum {string}
*/
export const DeviceTypeEnum = {
Ios: 'IOS',
Android: 'ANDROID',
Web: 'WEB'
} as const;
export type DeviceTypeEnum = typeof DeviceTypeEnum[keyof typeof DeviceTypeEnum];
/** /**
* *
* @export * @export
@ -2465,33 +2405,6 @@ export interface UpdateUserDto {
*/ */
'shouldChangePassword'?: boolean; 'shouldChangePassword'?: boolean;
} }
/**
*
* @export
* @interface UpsertDeviceInfoDto
*/
export interface UpsertDeviceInfoDto {
/**
*
* @type {DeviceTypeEnum}
* @memberof UpsertDeviceInfoDto
*/
'deviceType': DeviceTypeEnum;
/**
*
* @type {string}
* @memberof UpsertDeviceInfoDto
*/
'deviceId': string;
/**
*
* @type {boolean}
* @memberof UpsertDeviceInfoDto
*/
'isAutoBackup'?: boolean;
}
/** /**
* *
* @export * @export
@ -6406,115 +6319,6 @@ export class AuthenticationApi extends BaseAPI {
} }
/**
* DeviceInfoApi - axios parameter creator
* @export
*/
export const DeviceInfoApiAxiosParamCreator = function (configuration?: Configuration) {
return {
/**
*
* @param {UpsertDeviceInfoDto} upsertDeviceInfoDto
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
upsertDeviceInfo: async (upsertDeviceInfoDto: UpsertDeviceInfoDto, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'upsertDeviceInfoDto' is not null or undefined
assertParamExists('upsertDeviceInfo', 'upsertDeviceInfoDto', upsertDeviceInfoDto)
const localVarPath = `/device-info`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication cookie required
// authentication bearer required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
localVarHeaderParameter['Content-Type'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(upsertDeviceInfoDto, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
}
};
/**
* DeviceInfoApi - functional programming interface
* @export
*/
export const DeviceInfoApiFp = function(configuration?: Configuration) {
const localVarAxiosParamCreator = DeviceInfoApiAxiosParamCreator(configuration)
return {
/**
*
* @param {UpsertDeviceInfoDto} upsertDeviceInfoDto
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async upsertDeviceInfo(upsertDeviceInfoDto: UpsertDeviceInfoDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<DeviceInfoResponseDto>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.upsertDeviceInfo(upsertDeviceInfoDto, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
}
};
/**
* DeviceInfoApi - factory interface
* @export
*/
export const DeviceInfoApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
const localVarFp = DeviceInfoApiFp(configuration)
return {
/**
*
* @param {UpsertDeviceInfoDto} upsertDeviceInfoDto
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
upsertDeviceInfo(upsertDeviceInfoDto: UpsertDeviceInfoDto, options?: any): AxiosPromise<DeviceInfoResponseDto> {
return localVarFp.upsertDeviceInfo(upsertDeviceInfoDto, options).then((request) => request(axios, basePath));
},
};
};
/**
* DeviceInfoApi - object-oriented interface
* @export
* @class DeviceInfoApi
* @extends {BaseAPI}
*/
export class DeviceInfoApi extends BaseAPI {
/**
*
* @param {UpsertDeviceInfoDto} upsertDeviceInfoDto
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof DeviceInfoApi
*/
public upsertDeviceInfo(upsertDeviceInfoDto: UpsertDeviceInfoDto, options?: AxiosRequestConfig) {
return DeviceInfoApiFp(this.configuration).upsertDeviceInfo(upsertDeviceInfoDto, options).then((request) => request(this.axios, this.basePath));
}
}
/** /**
* JobApi - axios parameter creator * JobApi - axios parameter creator
* @export * @export