1
0
mirror of https://github.com/immich-app/immich.git synced 2025-01-25 17:15:28 +02:00

infra(server)!: fix typeorm asset entity relations (#1782)

* fix: add correct relations to asset typeorm entity

* fix: add missing createdAt column to asset entity

* ci: run check to make sure generated API is up-to-date

* ci: cancel workflows that aren't for the latest commit in a branch

* chore: add fvm config for flutter
This commit is contained in:
Zack Pollard 2023-02-19 16:44:53 +00:00 committed by GitHub
parent 000d0a08f4
commit 5ad4e5b614
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
65 changed files with 432 additions and 306 deletions

View File

@ -11,6 +11,10 @@ on:
push: push:
branches: [main] branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
build-sign-android: build-sign-android:
name: Build and sign Android name: Build and sign Android
@ -24,7 +28,7 @@ jobs:
github_ref="${{ github.sha }}" github_ref="${{ github.sha }}"
ref="${input_ref:-$github_ref}" ref="${input_ref:-$github_ref}"
echo "ref=$ref" >> $GITHUB_OUTPUT echo "ref=$ref" >> $GITHUB_OUTPUT
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
ref: ${{ steps.get-ref.outputs.ref }} ref: ${{ steps.get-ref.outputs.ref }}

View File

@ -4,24 +4,28 @@ on:
types: types:
- closed - closed
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
cleanup: cleanup:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Cleanup - name: Cleanup
run: | run: |
gh extension install actions/gh-actions-cache gh extension install actions/gh-actions-cache
REPO=${{ github.repository }} REPO=${{ github.repository }}
BRANCH=${{ github.ref }} BRANCH=${{ github.ref }}
echo "Fetching list of cache keys" echo "Fetching list of cache keys"
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 ) cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 )
## Setting this to not fail the workflow while deleting cache keys. ## Setting this to not fail the workflow while deleting cache keys.
set +e set +e
echo "Deleting caches..." echo "Deleting caches..."
for cacheKey in $cacheKeysForPR for cacheKey in $cacheKeysForPR

View File

@ -20,6 +20,10 @@ on:
schedule: schedule:
- cron: '20 13 * * 1' - cron: '20 13 * * 1'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
analyze: analyze:
name: Analyze name: Analyze
@ -48,11 +52,11 @@ jobs:
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file. # By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file. # Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality # queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
@ -61,7 +65,7 @@ jobs:
# ℹ️ Command-line programs to run using the OS shell. # ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines. # If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: | # - run: |

View File

@ -5,6 +5,10 @@ on:
push: push:
branches: ["main"] branches: ["main"]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
update-sdk-repos: update-sdk-repos:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@ -9,6 +9,10 @@ on:
release: release:
types: [published] types: [published]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
build_and_push: build_and_push:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@ -7,6 +7,10 @@ on:
- cron: "0 23 * * *" - cron: "0 23 * * *"
workflow_dispatch: # Allow for running this manually. workflow_dispatch: # Allow for running this manually.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
j1: j1:
name: github-repo-stats name: github-repo-stats

View File

@ -17,13 +17,17 @@ on:
required: false required: false
type: boolean type: boolean
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
bump_version: bump_version:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
ref: ${{ steps.push-tag.outputs.commit_long_sha }} ref: ${{ steps.push-tag.outputs.commit_long_sha }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -42,7 +46,7 @@ jobs:
message: "Version ${{ env.IMMICH_VERSION }}" message: "Version ${{ env.IMMICH_VERSION }}"
tag: ${{ env.IMMICH_VERSION }} tag: ${{ env.IMMICH_VERSION }}
push: true push: true
build_mobile: build_mobile:
uses: ./.github/workflows/build-mobile.yml uses: ./.github/workflows/build-mobile.yml
needs: bump_version needs: bump_version
@ -59,7 +63,7 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
token: ${{ secrets.ORG_RELEASE_TOKEN }} token: ${{ secrets.ORG_RELEASE_TOKEN }}
- name: Download APK - name: Download APK
uses: actions/download-artifact@v3 uses: actions/download-artifact@v3
with: with:

View File

@ -5,6 +5,10 @@ on:
push: push:
branches: [main] branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
mobile-dart-analyze: mobile-dart-analyze:
name: Run Dart Code Analysis name: Run Dart Code Analysis

View File

@ -5,6 +5,10 @@ on:
push: push:
branches: [main] branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
e2e-tests: e2e-tests:
name: Run end-to-end test suites name: Run end-to-end test suites
@ -54,6 +58,27 @@ jobs:
working-directory: ./mobile working-directory: ./mobile
run: flutter test run: flutter test
generated-api-up-to-date:
name: Check generated files are up-to-date
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run API generation
run: cd server && npm ci && npm run api:generate
- name: Find file changes
uses: tj-actions/verify-changed-files@v13.1
id: verify-changed-files
with:
files: |
mobile/openapi
web/src/api/open-api
- name: Verify files have not changed
if: steps.verify-changed-files.outputs.files_changed == 'true'
run: |
echo "ERROR: Generated files not up to date!"
echo "Changed files: ${{ steps.verify-changed-files.outputs.changed_files }}"
exit 1
mobile-integration-tests: mobile-integration-tests:
name: Run mobile end-to-end integration tests name: Run mobile end-to-end integration tests
runs-on: macos-latest runs-on: macos-latest

View File

@ -0,0 +1,4 @@
{
"flutterSdkVersion": "3.7.0",
"flavors": {}
}

3
mobile/.gitignore vendored
View File

@ -32,6 +32,7 @@
.pub-cache/ .pub-cache/
.pub/ .pub/
/build/ /build/
.fvm/flutter_sdk
# Web related # Web related
lib/generated_plugin_registrant.dart lib/generated_plugin_registrant.dart
@ -48,4 +49,4 @@ app.*.map.json
/android/app/release /android/app/release
# Fastlane # Fastlane
ios/fastlane/report.xml ios/fastlane/report.xml

View File

@ -120,8 +120,8 @@ class AlbumViewerPage extends HookConsumerWidget {
} }
Widget buildAlbumDateRange(Album album) { Widget buildAlbumDateRange(Album album) {
final DateTime startDate = album.assets.first.createdAt; final DateTime startDate = album.assets.first.fileCreatedAt;
final DateTime endDate = album.assets.last.createdAt; //Need default. final DateTime endDate = album.assets.last.fileCreatedAt; //Need default.
final String startDateText = final String startDateText =
DateFormat(startDate.year == endDate.year ? 'LLL d' : 'LLL d, y') DateFormat(startDate.year == endDate.year ? 'LLL d' : 'LLL d, y')
.format(startDate); .format(startDate);

View File

@ -146,7 +146,7 @@ class ExifBottomSheet extends HookConsumerWidget {
buildDate() { buildDate() {
return Text( return Text(
DateFormat('date_format'.tr()).format( DateFormat('date_format'.tr()).format(
assetDetail.createdAt.toLocal(), assetDetail.fileCreatedAt.toLocal(),
), ),
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,

View File

@ -2,26 +2,26 @@ import 'dart:convert';
class CurrentUploadAsset { class CurrentUploadAsset {
final String id; final String id;
final DateTime createdAt; final DateTime fileCreatedAt;
final String fileName; final String fileName;
final String fileType; final String fileType;
CurrentUploadAsset({ CurrentUploadAsset({
required this.id, required this.id,
required this.createdAt, required this.fileCreatedAt,
required this.fileName, required this.fileName,
required this.fileType, required this.fileType,
}); });
CurrentUploadAsset copyWith({ CurrentUploadAsset copyWith({
String? id, String? id,
DateTime? createdAt, DateTime? fileCreatedAt,
String? fileName, String? fileName,
String? fileType, String? fileType,
}) { }) {
return CurrentUploadAsset( return CurrentUploadAsset(
id: id ?? this.id, id: id ?? this.id,
createdAt: createdAt ?? this.createdAt, fileCreatedAt: fileCreatedAt ?? this.fileCreatedAt,
fileName: fileName ?? this.fileName, fileName: fileName ?? this.fileName,
fileType: fileType ?? this.fileType, fileType: fileType ?? this.fileType,
); );
@ -31,7 +31,7 @@ class CurrentUploadAsset {
final result = <String, dynamic>{}; final result = <String, dynamic>{};
result.addAll({'id': id}); result.addAll({'id': id});
result.addAll({'createdAt': createdAt.millisecondsSinceEpoch}); result.addAll({'fileCreatedAt': fileCreatedAt.millisecondsSinceEpoch});
result.addAll({'fileName': fileName}); result.addAll({'fileName': fileName});
result.addAll({'fileType': fileType}); result.addAll({'fileType': fileType});
@ -41,7 +41,7 @@ class CurrentUploadAsset {
factory CurrentUploadAsset.fromMap(Map<String, dynamic> map) { factory CurrentUploadAsset.fromMap(Map<String, dynamic> map) {
return CurrentUploadAsset( return CurrentUploadAsset(
id: map['id'] ?? '', id: map['id'] ?? '',
createdAt: DateTime.fromMillisecondsSinceEpoch(map['createdAt']), fileCreatedAt: DateTime.fromMillisecondsSinceEpoch(map['fileCreatedAt']),
fileName: map['fileName'] ?? '', fileName: map['fileName'] ?? '',
fileType: map['fileType'] ?? '', fileType: map['fileType'] ?? '',
); );
@ -54,7 +54,7 @@ class CurrentUploadAsset {
@override @override
String toString() { String toString() {
return 'CurrentUploadAsset(id: $id, createdAt: $createdAt, fileName: $fileName, fileType: $fileType)'; return 'CurrentUploadAsset(id: $id, fileCreatedAt: $fileCreatedAt, fileName: $fileName, fileType: $fileType)';
} }
@override @override
@ -63,7 +63,7 @@ class CurrentUploadAsset {
return other is CurrentUploadAsset && return other is CurrentUploadAsset &&
other.id == id && other.id == id &&
other.createdAt == createdAt && other.fileCreatedAt == fileCreatedAt &&
other.fileName == fileName && other.fileName == fileName &&
other.fileType == fileType; other.fileType == fileType;
} }
@ -71,7 +71,7 @@ class CurrentUploadAsset {
@override @override
int get hashCode { int get hashCode {
return id.hashCode ^ return id.hashCode ^
createdAt.hashCode ^ fileCreatedAt.hashCode ^
fileName.hashCode ^ fileName.hashCode ^
fileType.hashCode; fileType.hashCode;
} }

View File

@ -2,7 +2,7 @@ import 'package:photo_manager/photo_manager.dart';
class ErrorUploadAsset { class ErrorUploadAsset {
final String id; final String id;
final DateTime createdAt; final DateTime fileCreatedAt;
final String fileName; final String fileName;
final String fileType; final String fileType;
final AssetEntity asset; final AssetEntity asset;
@ -10,7 +10,7 @@ class ErrorUploadAsset {
const ErrorUploadAsset({ const ErrorUploadAsset({
required this.id, required this.id,
required this.createdAt, required this.fileCreatedAt,
required this.fileName, required this.fileName,
required this.fileType, required this.fileType,
required this.asset, required this.asset,
@ -19,7 +19,7 @@ class ErrorUploadAsset {
ErrorUploadAsset copyWith({ ErrorUploadAsset copyWith({
String? id, String? id,
DateTime? createdAt, DateTime? fileCreatedAt,
String? fileName, String? fileName,
String? fileType, String? fileType,
AssetEntity? asset, AssetEntity? asset,
@ -27,7 +27,7 @@ class ErrorUploadAsset {
}) { }) {
return ErrorUploadAsset( return ErrorUploadAsset(
id: id ?? this.id, id: id ?? this.id,
createdAt: createdAt ?? this.createdAt, fileCreatedAt: fileCreatedAt ?? this.fileCreatedAt,
fileName: fileName ?? this.fileName, fileName: fileName ?? this.fileName,
fileType: fileType ?? this.fileType, fileType: fileType ?? this.fileType,
asset: asset ?? this.asset, asset: asset ?? this.asset,
@ -37,7 +37,7 @@ class ErrorUploadAsset {
@override @override
String toString() { String toString() {
return 'ErrorUploadAsset(id: $id, createdAt: $createdAt, fileName: $fileName, fileType: $fileType, asset: $asset, errorMessage: $errorMessage)'; return 'ErrorUploadAsset(id: $id, fileCreatedAt: $fileCreatedAt, fileName: $fileName, fileType: $fileType, asset: $asset, errorMessage: $errorMessage)';
} }
@override @override
@ -46,7 +46,7 @@ class ErrorUploadAsset {
return other is ErrorUploadAsset && return other is ErrorUploadAsset &&
other.id == id && other.id == id &&
other.createdAt == createdAt && other.fileCreatedAt == fileCreatedAt &&
other.fileName == fileName && other.fileName == fileName &&
other.fileType == fileType && other.fileType == fileType &&
other.asset == asset && other.asset == asset &&
@ -56,7 +56,7 @@ class ErrorUploadAsset {
@override @override
int get hashCode { int get hashCode {
return id.hashCode ^ return id.hashCode ^
createdAt.hashCode ^ fileCreatedAt.hashCode ^
fileName.hashCode ^ fileName.hashCode ^
fileType.hashCode ^ fileType.hashCode ^
asset.hashCode ^ asset.hashCode ^

View File

@ -55,7 +55,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
selectedAlbumsBackupAssetsIds: const {}, selectedAlbumsBackupAssetsIds: const {},
currentUploadAsset: CurrentUploadAsset( currentUploadAsset: CurrentUploadAsset(
id: '...', id: '...',
createdAt: DateTime.parse('2020-10-04'), fileCreatedAt: DateTime.parse('2020-10-04'),
fileName: '...', fileName: '...',
fileType: '...', fileType: '...',
), ),

View File

@ -260,8 +260,8 @@ class BackupService {
req.fields['deviceAssetId'] = entity.id; req.fields['deviceAssetId'] = entity.id;
req.fields['deviceId'] = deviceId; req.fields['deviceId'] = deviceId;
req.fields['assetType'] = _getAssetType(entity.type); req.fields['assetType'] = _getAssetType(entity.type);
req.fields['createdAt'] = entity.createDateTime.toIso8601String(); req.fields['fileCreatedAt'] = entity.createDateTime.toIso8601String();
req.fields['modifiedAt'] = entity.modifiedDateTime.toIso8601String(); req.fields['fileModifiedAt'] = entity.modifiedDateTime.toIso8601String();
req.fields['isFavorite'] = entity.isFavorite.toString(); req.fields['isFavorite'] = entity.isFavorite.toString();
req.fields['fileExtension'] = fileExtension; req.fields['fileExtension'] = fileExtension;
req.fields['duration'] = entity.videoDuration.toString(); req.fields['duration'] = entity.videoDuration.toString();
@ -278,7 +278,7 @@ class BackupService {
setCurrentUploadAssetCb( setCurrentUploadAssetCb(
CurrentUploadAsset( CurrentUploadAsset(
id: entity.id, id: entity.id,
createdAt: entity.createDateTime.year == 1970 fileCreatedAt: entity.createDateTime.year == 1970
? entity.modifiedDateTime ? entity.modifiedDateTime
: entity.createDateTime, : entity.createDateTime,
fileName: originalFileName, fileName: originalFileName,
@ -308,7 +308,7 @@ class BackupService {
ErrorUploadAsset( ErrorUploadAsset(
asset: entity, asset: entity,
id: entity.id, id: entity.id,
createdAt: entity.createDateTime, fileCreatedAt: entity.createDateTime,
fileName: originalFileName, fileName: originalFileName,
fileType: _getAssetType(entity.type), fileType: _getAssetType(entity.type),
errorMessage: error['error'], errorMessage: error['error'],

View File

@ -20,7 +20,7 @@ class CurrentUploadingAssetInfoBox extends HookConsumerWidget {
String getAssetCreationDate() { String getAssetCreationDate() {
return DateFormat.yMMMMd('en_US').format( return DateFormat.yMMMMd('en_US').format(
DateTime.parse( DateTime.parse(
asset.createdAt.toString(), asset.fileCreatedAt.toString(),
).toLocal(), ).toLocal(),
); );
} }

View File

@ -89,7 +89,7 @@ class FailedBackupStatusPage extends HookConsumerWidget {
Text( Text(
DateFormat.yMMMMd('en_US').format( DateFormat.yMMMMd('en_US').format(
DateTime.parse( DateTime.parse(
errorAsset.createdAt.toString(), errorAsset.fileCreatedAt.toString(),
).toLocal(), ).toLocal(),
), ),
style: TextStyle( style: TextStyle(

View File

@ -82,14 +82,14 @@ class RenderList {
if (groupBy == GroupAssetsBy.day) { if (groupBy == GroupAssetsBy.day) {
return assets.groupListsBy( return assets.groupListsBy(
(element) { (element) {
final date = element.createdAt.toLocal(); final date = element.fileCreatedAt.toLocal();
return DateTime(date.year, date.month, date.day); return DateTime(date.year, date.month, date.day);
}, },
); );
} else if (groupBy == GroupAssetsBy.month) { } else if (groupBy == GroupAssetsBy.month) {
return assets.groupListsBy( return assets.groupListsBy(
(element) { (element) {
final date = element.createdAt.toLocal(); final date = element.fileCreatedAt.toLocal();
return DateTime(date.year, date.month); return DateTime(date.year, date.month);
}, },
); );

View File

@ -10,8 +10,8 @@ import 'package:path/path.dart' as p;
class Asset { class Asset {
Asset.remote(AssetResponseDto remote) Asset.remote(AssetResponseDto remote)
: remoteId = remote.id, : remoteId = remote.id,
createdAt = DateTime.parse(remote.createdAt), fileCreatedAt = DateTime.parse(remote.fileCreatedAt),
modifiedAt = DateTime.parse(remote.modifiedAt), fileModifiedAt = DateTime.parse(remote.fileModifiedAt),
durationInSeconds = remote.duration.toDuration().inSeconds, durationInSeconds = remote.duration.toDuration().inSeconds,
fileName = p.basename(remote.originalPath), fileName = p.basename(remote.originalPath),
height = remote.exifInfo?.exifImageHeight?.toInt(), height = remote.exifInfo?.exifImageHeight?.toInt(),
@ -37,11 +37,11 @@ class Asset {
deviceAssetId = local.id, deviceAssetId = local.id,
deviceId = Hive.box(userInfoBox).get(deviceIdKey), deviceId = Hive.box(userInfoBox).get(deviceIdKey),
ownerId = owner, ownerId = owner,
modifiedAt = local.modifiedDateTime.toUtc(), fileModifiedAt = local.modifiedDateTime.toUtc(),
isFavorite = local.isFavorite, isFavorite = local.isFavorite,
createdAt = local.createDateTime.toUtc() { fileCreatedAt = local.createDateTime.toUtc() {
if (createdAt.year == 1970) { if (fileCreatedAt.year == 1970) {
createdAt = modifiedAt; fileCreatedAt = fileModifiedAt;
} }
} }
@ -51,8 +51,8 @@ class Asset {
required this.deviceAssetId, required this.deviceAssetId,
required this.deviceId, required this.deviceId,
required this.ownerId, required this.ownerId,
required this.createdAt, required this.fileCreatedAt,
required this.modifiedAt, required this.fileModifiedAt,
this.latitude, this.latitude,
this.longitude, this.longitude,
required this.durationInSeconds, required this.durationInSeconds,
@ -74,10 +74,10 @@ class Asset {
width: width!, width: width!,
height: height!, height: height!,
duration: durationInSeconds, duration: durationInSeconds,
createDateSecond: createdAt.millisecondsSinceEpoch ~/ 1000, createDateSecond: fileCreatedAt.millisecondsSinceEpoch ~/ 1000,
latitude: latitude, latitude: latitude,
longitude: longitude, longitude: longitude,
modifiedDateSecond: modifiedAt.millisecondsSinceEpoch ~/ 1000, modifiedDateSecond: fileModifiedAt.millisecondsSinceEpoch ~/ 1000,
title: fileName, title: fileName,
); );
} }
@ -94,9 +94,9 @@ class Asset {
String ownerId; String ownerId;
DateTime createdAt; DateTime fileCreatedAt;
DateTime modifiedAt; DateTime fileModifiedAt;
double? latitude; double? latitude;
@ -146,8 +146,8 @@ class Asset {
json["deviceAssetId"] = deviceAssetId; json["deviceAssetId"] = deviceAssetId;
json["deviceId"] = deviceId; json["deviceId"] = deviceId;
json["ownerId"] = ownerId; json["ownerId"] = ownerId;
json["createdAt"] = createdAt.millisecondsSinceEpoch; json["fileCreatedAt"] = fileCreatedAt.millisecondsSinceEpoch;
json["modifiedAt"] = modifiedAt.millisecondsSinceEpoch; json["fileModifiedAt"] = fileModifiedAt.millisecondsSinceEpoch;
json["latitude"] = latitude; json["latitude"] = latitude;
json["longitude"] = longitude; json["longitude"] = longitude;
json["durationInSeconds"] = durationInSeconds; json["durationInSeconds"] = durationInSeconds;
@ -171,10 +171,10 @@ class Asset {
deviceAssetId: json["deviceAssetId"], deviceAssetId: json["deviceAssetId"],
deviceId: json["deviceId"], deviceId: json["deviceId"],
ownerId: json["ownerId"], ownerId: json["ownerId"],
createdAt: fileCreatedAt:
DateTime.fromMillisecondsSinceEpoch(json["createdAt"], isUtc: true), DateTime.fromMillisecondsSinceEpoch(json["fileCreatedAt"], isUtc: true),
modifiedAt: DateTime.fromMillisecondsSinceEpoch( fileModifiedAt: DateTime.fromMillisecondsSinceEpoch(
json["modifiedAt"], json["fileModifiedAt"],
isUtc: true, isUtc: true,
), ),
latitude: json["latitude"], latitude: json["latitude"],

View File

@ -302,11 +302,11 @@ final assetGroupByMonthYearProvider = StateProvider((ref) {
ref.watch(assetProvider).allAssets.where((e) => e.isRemote).toList(); ref.watch(assetProvider).allAssets.where((e) => e.isRemote).toList();
assets.sortByCompare<DateTime>( assets.sortByCompare<DateTime>(
(e) => e.createdAt, (e) => e.fileCreatedAt,
(a, b) => b.compareTo(a), (a, b) => b.compareTo(a),
); );
return assets.groupListsBy( return assets.groupListsBy(
(element) => DateFormat('MMMM, y').format(element.createdAt.toLocal()), (element) => DateFormat('MMMM, y').format(element.fileCreatedAt.toLocal()),
); );
}); });

View File

@ -3,7 +3,7 @@ Immich API
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: 1.47.2 - API version: 1.47.3
- Build package: org.openapitools.codegen.languages.DartClientCodegen - Build package: org.openapitools.codegen.languages.DartClientCodegen
## Requirements ## Requirements

View File

@ -71,7 +71,7 @@ No authorization required
import 'package:openapi/api.dart'; import 'package:openapi/api.dart';
final api_instance = APIKeyApi(); final api_instance = APIKeyApi();
final id = 8.14; // num | final id = id_example; // String |
try { try {
api_instance.deleteKey(id); api_instance.deleteKey(id);
@ -84,7 +84,7 @@ try {
Name | Type | Description | Notes Name | Type | Description | Notes
------------- | ------------- | ------------- | ------------- ------------- | ------------- | ------------- | -------------
**id** | **num**| | **id** | **String**| |
### Return type ### Return type
@ -113,7 +113,7 @@ No authorization required
import 'package:openapi/api.dart'; import 'package:openapi/api.dart';
final api_instance = APIKeyApi(); final api_instance = APIKeyApi();
final id = 8.14; // num | final id = id_example; // String |
try { try {
final result = api_instance.getKey(id); final result = api_instance.getKey(id);
@ -127,7 +127,7 @@ try {
Name | Type | Description | Notes Name | Type | Description | Notes
------------- | ------------- | ------------- | ------------- ------------- | ------------- | ------------- | -------------
**id** | **num**| | **id** | **String**| |
### Return type ### Return type
@ -195,7 +195,7 @@ No authorization required
import 'package:openapi/api.dart'; import 'package:openapi/api.dart';
final api_instance = APIKeyApi(); final api_instance = APIKeyApi();
final id = 8.14; // num | final id = id_example; // String |
final aPIKeyUpdateDto = APIKeyUpdateDto(); // APIKeyUpdateDto | final aPIKeyUpdateDto = APIKeyUpdateDto(); // APIKeyUpdateDto |
try { try {
@ -210,7 +210,7 @@ try {
Name | Type | Description | Notes Name | Type | Description | Notes
------------- | ------------- | ------------- | ------------- ------------- | ------------- | ------------- | -------------
**id** | **num**| | **id** | **String**| |
**aPIKeyUpdateDto** | [**APIKeyUpdateDto**](APIKeyUpdateDto.md)| | **aPIKeyUpdateDto** | [**APIKeyUpdateDto**](APIKeyUpdateDto.md)| |
### Return type ### Return type

View File

@ -8,7 +8,7 @@ import 'package:openapi/api.dart';
## Properties ## Properties
Name | Type | Description | Notes Name | Type | Description | Notes
------------ | ------------- | ------------- | ------------- ------------ | ------------- | ------------- | -------------
**id** | **int** | | **id** | **String** | |
**name** | **String** | | **name** | **String** | |
**createdAt** | **String** | | **createdAt** | **String** | |
**updatedAt** | **String** | | **updatedAt** | **String** | |

View File

@ -1109,7 +1109,7 @@ Name | Type | Description | Notes
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **uploadFile** # **uploadFile**
> AssetFileUploadResponseDto uploadFile(assetType, assetData, deviceAssetId, deviceId, createdAt, modifiedAt, isFavorite, fileExtension, livePhotoData, isVisible, duration) > AssetFileUploadResponseDto uploadFile(assetType, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, fileExtension, livePhotoData, isVisible, duration)
@ -1130,8 +1130,8 @@ final assetType = ; // AssetTypeEnum |
final assetData = BINARY_DATA_HERE; // MultipartFile | final assetData = BINARY_DATA_HERE; // MultipartFile |
final deviceAssetId = deviceAssetId_example; // String | final deviceAssetId = deviceAssetId_example; // String |
final deviceId = deviceId_example; // String | final deviceId = deviceId_example; // String |
final createdAt = createdAt_example; // String | final fileCreatedAt = fileCreatedAt_example; // String |
final modifiedAt = modifiedAt_example; // String | final fileModifiedAt = fileModifiedAt_example; // String |
final isFavorite = true; // bool | final isFavorite = true; // bool |
final fileExtension = fileExtension_example; // String | final fileExtension = fileExtension_example; // String |
final livePhotoData = BINARY_DATA_HERE; // MultipartFile | final livePhotoData = BINARY_DATA_HERE; // MultipartFile |
@ -1139,7 +1139,7 @@ final isVisible = true; // bool |
final duration = duration_example; // String | final duration = duration_example; // String |
try { try {
final result = api_instance.uploadFile(assetType, assetData, deviceAssetId, deviceId, createdAt, modifiedAt, isFavorite, fileExtension, livePhotoData, isVisible, duration); final result = api_instance.uploadFile(assetType, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, fileExtension, livePhotoData, isVisible, duration);
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling AssetApi->uploadFile: $e\n'); print('Exception when calling AssetApi->uploadFile: $e\n');
@ -1154,8 +1154,8 @@ Name | Type | Description | Notes
**assetData** | **MultipartFile**| | **assetData** | **MultipartFile**| |
**deviceAssetId** | **String**| | **deviceAssetId** | **String**| |
**deviceId** | **String**| | **deviceId** | **String**| |
**createdAt** | **String**| | **fileCreatedAt** | **String**| |
**modifiedAt** | **String**| | **fileModifiedAt** | **String**| |
**isFavorite** | **bool**| | **isFavorite** | **bool**| |
**fileExtension** | **String**| | **fileExtension** | **String**| |
**livePhotoData** | **MultipartFile**| | [optional] **livePhotoData** | **MultipartFile**| | [optional]

View File

@ -15,8 +15,8 @@ Name | Type | Description | Notes
**deviceId** | **String** | | **deviceId** | **String** | |
**originalPath** | **String** | | **originalPath** | **String** | |
**resizePath** | **String** | | **resizePath** | **String** | |
**createdAt** | **String** | | **fileCreatedAt** | **String** | |
**modifiedAt** | **String** | | **fileModifiedAt** | **String** | |
**updatedAt** | **String** | | **updatedAt** | **String** | |
**isFavorite** | **bool** | | **isFavorite** | **bool** | |
**mimeType** | **String** | | **mimeType** | **String** | |

View File

@ -74,11 +74,11 @@ class APIKeyApi {
/// ///
/// Parameters: /// Parameters:
/// ///
/// * [num] id (required): /// * [String] id (required):
Future<Response> deleteKeyWithHttpInfo(num id,) async { Future<Response> deleteKeyWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/api-key/{id}' final path = r'/api-key/{id}'
.replaceAll('{id}', id.toString()); .replaceAll('{id}', id);
// ignore: prefer_final_locals // ignore: prefer_final_locals
Object? postBody; Object? postBody;
@ -105,8 +105,8 @@ class APIKeyApi {
/// ///
/// Parameters: /// Parameters:
/// ///
/// * [num] id (required): /// * [String] id (required):
Future<void> deleteKey(num id,) async { Future<void> deleteKey(String id,) async {
final response = await deleteKeyWithHttpInfo(id,); final response = await deleteKeyWithHttpInfo(id,);
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
@ -119,11 +119,11 @@ class APIKeyApi {
/// ///
/// Parameters: /// Parameters:
/// ///
/// * [num] id (required): /// * [String] id (required):
Future<Response> getKeyWithHttpInfo(num id,) async { Future<Response> getKeyWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/api-key/{id}' final path = r'/api-key/{id}'
.replaceAll('{id}', id.toString()); .replaceAll('{id}', id);
// ignore: prefer_final_locals // ignore: prefer_final_locals
Object? postBody; Object? postBody;
@ -150,8 +150,8 @@ class APIKeyApi {
/// ///
/// Parameters: /// Parameters:
/// ///
/// * [num] id (required): /// * [String] id (required):
Future<APIKeyResponseDto?> getKey(num id,) async { Future<APIKeyResponseDto?> getKey(String id,) async {
final response = await getKeyWithHttpInfo(id,); final response = await getKeyWithHttpInfo(id,);
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
@ -219,13 +219,13 @@ class APIKeyApi {
/// ///
/// Parameters: /// Parameters:
/// ///
/// * [num] id (required): /// * [String] id (required):
/// ///
/// * [APIKeyUpdateDto] aPIKeyUpdateDto (required): /// * [APIKeyUpdateDto] aPIKeyUpdateDto (required):
Future<Response> updateKeyWithHttpInfo(num id, APIKeyUpdateDto aPIKeyUpdateDto,) async { Future<Response> updateKeyWithHttpInfo(String id, APIKeyUpdateDto aPIKeyUpdateDto,) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/api-key/{id}' final path = r'/api-key/{id}'
.replaceAll('{id}', id.toString()); .replaceAll('{id}', id);
// ignore: prefer_final_locals // ignore: prefer_final_locals
Object? postBody = aPIKeyUpdateDto; Object? postBody = aPIKeyUpdateDto;
@ -252,10 +252,10 @@ class APIKeyApi {
/// ///
/// Parameters: /// Parameters:
/// ///
/// * [num] id (required): /// * [String] id (required):
/// ///
/// * [APIKeyUpdateDto] aPIKeyUpdateDto (required): /// * [APIKeyUpdateDto] aPIKeyUpdateDto (required):
Future<APIKeyResponseDto?> updateKey(num id, APIKeyUpdateDto aPIKeyUpdateDto,) async { Future<APIKeyResponseDto?> updateKey(String id, APIKeyUpdateDto aPIKeyUpdateDto,) async {
final response = await updateKeyWithHttpInfo(id, aPIKeyUpdateDto,); final response = await updateKeyWithHttpInfo(id, aPIKeyUpdateDto,);
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));

View File

@ -1224,9 +1224,9 @@ class AssetApi {
/// ///
/// * [String] deviceId (required): /// * [String] deviceId (required):
/// ///
/// * [String] createdAt (required): /// * [String] fileCreatedAt (required):
/// ///
/// * [String] modifiedAt (required): /// * [String] fileModifiedAt (required):
/// ///
/// * [bool] isFavorite (required): /// * [bool] isFavorite (required):
/// ///
@ -1237,7 +1237,7 @@ class AssetApi {
/// * [bool] isVisible: /// * [bool] isVisible:
/// ///
/// * [String] duration: /// * [String] duration:
Future<Response> uploadFileWithHttpInfo(AssetTypeEnum assetType, MultipartFile assetData, String deviceAssetId, String deviceId, String createdAt, String modifiedAt, bool isFavorite, String fileExtension, { MultipartFile? livePhotoData, bool? isVisible, String? duration, }) async { Future<Response> uploadFileWithHttpInfo(AssetTypeEnum assetType, MultipartFile assetData, String deviceAssetId, String deviceId, String fileCreatedAt, String fileModifiedAt, bool isFavorite, String fileExtension, { MultipartFile? livePhotoData, bool? isVisible, String? duration, }) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/asset/upload'; final path = r'/asset/upload';
@ -1274,13 +1274,13 @@ class AssetApi {
hasFields = true; hasFields = true;
mp.fields[r'deviceId'] = parameterToString(deviceId); mp.fields[r'deviceId'] = parameterToString(deviceId);
} }
if (createdAt != null) { if (fileCreatedAt != null) {
hasFields = true; hasFields = true;
mp.fields[r'createdAt'] = parameterToString(createdAt); mp.fields[r'fileCreatedAt'] = parameterToString(fileCreatedAt);
} }
if (modifiedAt != null) { if (fileModifiedAt != null) {
hasFields = true; hasFields = true;
mp.fields[r'modifiedAt'] = parameterToString(modifiedAt); mp.fields[r'fileModifiedAt'] = parameterToString(fileModifiedAt);
} }
if (isFavorite != null) { if (isFavorite != null) {
hasFields = true; hasFields = true;
@ -1325,9 +1325,9 @@ class AssetApi {
/// ///
/// * [String] deviceId (required): /// * [String] deviceId (required):
/// ///
/// * [String] createdAt (required): /// * [String] fileCreatedAt (required):
/// ///
/// * [String] modifiedAt (required): /// * [String] fileModifiedAt (required):
/// ///
/// * [bool] isFavorite (required): /// * [bool] isFavorite (required):
/// ///
@ -1338,8 +1338,8 @@ class AssetApi {
/// * [bool] isVisible: /// * [bool] isVisible:
/// ///
/// * [String] duration: /// * [String] duration:
Future<AssetFileUploadResponseDto?> uploadFile(AssetTypeEnum assetType, MultipartFile assetData, String deviceAssetId, String deviceId, String createdAt, String modifiedAt, bool isFavorite, String fileExtension, { MultipartFile? livePhotoData, bool? isVisible, String? duration, }) async { Future<AssetFileUploadResponseDto?> uploadFile(AssetTypeEnum assetType, MultipartFile assetData, String deviceAssetId, String deviceId, String fileCreatedAt, String fileModifiedAt, bool isFavorite, String fileExtension, { MultipartFile? livePhotoData, bool? isVisible, String? duration, }) async {
final response = await uploadFileWithHttpInfo(assetType, assetData, deviceAssetId, deviceId, createdAt, modifiedAt, isFavorite, fileExtension, livePhotoData: livePhotoData, isVisible: isVisible, duration: duration, ); final response = await uploadFileWithHttpInfo(assetType, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, fileExtension, livePhotoData: livePhotoData, isVisible: isVisible, duration: duration, );
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }

View File

@ -19,7 +19,7 @@ class APIKeyResponseDto {
required this.updatedAt, required this.updatedAt,
}); });
int id; String id;
String name; String name;
@ -73,7 +73,7 @@ class APIKeyResponseDto {
}()); }());
return APIKeyResponseDto( return APIKeyResponseDto(
id: mapValueOfType<int>(json, r'id')!, id: mapValueOfType<String>(json, r'id')!,
name: mapValueOfType<String>(json, r'name')!, name: mapValueOfType<String>(json, r'name')!,
createdAt: mapValueOfType<String>(json, r'createdAt')!, createdAt: mapValueOfType<String>(json, r'createdAt')!,
updatedAt: mapValueOfType<String>(json, r'updatedAt')!, updatedAt: mapValueOfType<String>(json, r'updatedAt')!,

View File

@ -20,8 +20,8 @@ class AssetResponseDto {
required this.deviceId, required this.deviceId,
required this.originalPath, required this.originalPath,
required this.resizePath, required this.resizePath,
required this.createdAt, required this.fileCreatedAt,
required this.modifiedAt, required this.fileModifiedAt,
required this.updatedAt, required this.updatedAt,
required this.isFavorite, required this.isFavorite,
required this.mimeType, required this.mimeType,
@ -48,9 +48,9 @@ class AssetResponseDto {
String? resizePath; String? resizePath;
String createdAt; String fileCreatedAt;
String modifiedAt; String fileModifiedAt;
String updatedAt; String updatedAt;
@ -93,8 +93,8 @@ class AssetResponseDto {
other.deviceId == deviceId && other.deviceId == deviceId &&
other.originalPath == originalPath && other.originalPath == originalPath &&
other.resizePath == resizePath && other.resizePath == resizePath &&
other.createdAt == createdAt && other.fileCreatedAt == fileCreatedAt &&
other.modifiedAt == modifiedAt && other.fileModifiedAt == fileModifiedAt &&
other.updatedAt == updatedAt && other.updatedAt == updatedAt &&
other.isFavorite == isFavorite && other.isFavorite == isFavorite &&
other.mimeType == mimeType && other.mimeType == mimeType &&
@ -116,8 +116,8 @@ class AssetResponseDto {
(deviceId.hashCode) + (deviceId.hashCode) +
(originalPath.hashCode) + (originalPath.hashCode) +
(resizePath == null ? 0 : resizePath!.hashCode) + (resizePath == null ? 0 : resizePath!.hashCode) +
(createdAt.hashCode) + (fileCreatedAt.hashCode) +
(modifiedAt.hashCode) + (fileModifiedAt.hashCode) +
(updatedAt.hashCode) + (updatedAt.hashCode) +
(isFavorite.hashCode) + (isFavorite.hashCode) +
(mimeType == null ? 0 : mimeType!.hashCode) + (mimeType == null ? 0 : mimeType!.hashCode) +
@ -130,7 +130,7 @@ class AssetResponseDto {
(tags.hashCode); (tags.hashCode);
@override @override
String toString() => 'AssetResponseDto[type=$type, id=$id, deviceAssetId=$deviceAssetId, ownerId=$ownerId, deviceId=$deviceId, originalPath=$originalPath, resizePath=$resizePath, createdAt=$createdAt, modifiedAt=$modifiedAt, updatedAt=$updatedAt, isFavorite=$isFavorite, mimeType=$mimeType, duration=$duration, webpPath=$webpPath, encodedVideoPath=$encodedVideoPath, exifInfo=$exifInfo, smartInfo=$smartInfo, livePhotoVideoId=$livePhotoVideoId, tags=$tags]'; String toString() => 'AssetResponseDto[type=$type, id=$id, deviceAssetId=$deviceAssetId, ownerId=$ownerId, deviceId=$deviceId, originalPath=$originalPath, resizePath=$resizePath, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, updatedAt=$updatedAt, isFavorite=$isFavorite, mimeType=$mimeType, duration=$duration, webpPath=$webpPath, encodedVideoPath=$encodedVideoPath, exifInfo=$exifInfo, smartInfo=$smartInfo, livePhotoVideoId=$livePhotoVideoId, tags=$tags]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
@ -145,8 +145,8 @@ class AssetResponseDto {
} else { } else {
// json[r'resizePath'] = null; // json[r'resizePath'] = null;
} }
json[r'createdAt'] = this.createdAt; json[r'fileCreatedAt'] = this.fileCreatedAt;
json[r'modifiedAt'] = this.modifiedAt; json[r'fileModifiedAt'] = this.fileModifiedAt;
json[r'updatedAt'] = this.updatedAt; json[r'updatedAt'] = this.updatedAt;
json[r'isFavorite'] = this.isFavorite; json[r'isFavorite'] = this.isFavorite;
if (this.mimeType != null) { if (this.mimeType != null) {
@ -210,8 +210,8 @@ class AssetResponseDto {
deviceId: mapValueOfType<String>(json, r'deviceId')!, deviceId: mapValueOfType<String>(json, r'deviceId')!,
originalPath: mapValueOfType<String>(json, r'originalPath')!, originalPath: mapValueOfType<String>(json, r'originalPath')!,
resizePath: mapValueOfType<String>(json, r'resizePath'), resizePath: mapValueOfType<String>(json, r'resizePath'),
createdAt: mapValueOfType<String>(json, r'createdAt')!, fileCreatedAt: mapValueOfType<String>(json, r'fileCreatedAt')!,
modifiedAt: mapValueOfType<String>(json, r'modifiedAt')!, fileModifiedAt: mapValueOfType<String>(json, r'fileModifiedAt')!,
updatedAt: mapValueOfType<String>(json, r'updatedAt')!, updatedAt: mapValueOfType<String>(json, r'updatedAt')!,
isFavorite: mapValueOfType<bool>(json, r'isFavorite')!, isFavorite: mapValueOfType<bool>(json, r'isFavorite')!,
mimeType: mapValueOfType<String>(json, r'mimeType'), mimeType: mapValueOfType<String>(json, r'mimeType'),
@ -278,8 +278,8 @@ class AssetResponseDto {
'deviceId', 'deviceId',
'originalPath', 'originalPath',
'resizePath', 'resizePath',
'createdAt', 'fileCreatedAt',
'modifiedAt', 'fileModifiedAt',
'updatedAt', 'updatedAt',
'isFavorite', 'isFavorite',
'mimeType', 'mimeType',

View File

@ -26,14 +26,14 @@ void main() {
// //
// //
//Future deleteKey(num id) async //Future deleteKey(String id) async
test('test deleteKey', () async { test('test deleteKey', () async {
// TODO // TODO
}); });
// //
// //
//Future<APIKeyResponseDto> getKey(num id) async //Future<APIKeyResponseDto> getKey(String id) async
test('test getKey', () async { test('test getKey', () async {
// TODO // TODO
}); });
@ -47,7 +47,7 @@ void main() {
// //
// //
//Future<APIKeyResponseDto> updateKey(num id, APIKeyUpdateDto aPIKeyUpdateDto) async //Future<APIKeyResponseDto> updateKey(String id, APIKeyUpdateDto aPIKeyUpdateDto) async
test('test updateKey', () async { test('test updateKey', () async {
// TODO // TODO
}); });

View File

@ -16,7 +16,7 @@ void main() {
// final instance = APIKeyResponseDto(); // final instance = APIKeyResponseDto();
group('test APIKeyResponseDto', () { group('test APIKeyResponseDto', () {
// int id // String id
test('to test the property `id`', () async { test('to test the property `id`', () async {
// TODO // TODO
}); });

View File

@ -173,7 +173,7 @@ void main() {
// //
// //
//Future<AssetFileUploadResponseDto> uploadFile(AssetTypeEnum assetType, MultipartFile assetData, String deviceAssetId, String deviceId, String createdAt, String modifiedAt, bool isFavorite, String fileExtension, { MultipartFile livePhotoData, bool isVisible, String duration }) async //Future<AssetFileUploadResponseDto> uploadFile(AssetTypeEnum assetType, MultipartFile assetData, String deviceAssetId, String deviceId, String fileCreatedAt, String fileModifiedAt, bool isFavorite, String fileExtension, { MultipartFile livePhotoData, bool isVisible, String duration }) async
test('test uploadFile', () async { test('test uploadFile', () async {
// TODO // TODO
}); });

View File

@ -51,13 +51,13 @@ void main() {
// TODO // TODO
}); });
// String createdAt // String fileCreatedAt
test('to test the property `createdAt`', () async { test('to test the property `fileCreatedAt`', () async {
// TODO // TODO
}); });
// String modifiedAt // String fileModifiedAt
test('to test the property `modifiedAt`', () async { test('to test the property `fileModifiedAt`', () async {
// TODO // TODO
}); });

View File

@ -1513,5 +1513,5 @@ packages:
source: hosted source: hosted
version: "3.1.1" version: "3.1.1"
sdks: sdks:
dart: ">=2.19.0 <3.0.0" dart: ">=2.19.0 <4.0.0"
flutter: ">=3.3.0" flutter: ">=3.3.0"

View File

@ -16,8 +16,8 @@ void main() {
deviceAssetId: '$i', deviceAssetId: '$i',
deviceId: '', deviceId: '',
ownerId: '', ownerId: '',
createdAt: date, fileCreatedAt: date,
modifiedAt: date, fileModifiedAt: date,
durationInSeconds: 0, durationInSeconds: 0,
fileName: '', fileName: '',
isFavorite: false, isFavorite: false,
@ -29,25 +29,25 @@ void main() {
assets.addAll( assets.addAll(
testAssets.sublist(0, 5).map((e) { testAssets.sublist(0, 5).map((e) {
e.createdAt = DateTime(2022, 1, 5); e.fileCreatedAt = DateTime(2022, 1, 5);
return e; return e;
}).toList(), }).toList(),
); );
assets.addAll( assets.addAll(
testAssets.sublist(5, 10).map((e) { testAssets.sublist(5, 10).map((e) {
e.createdAt = DateTime(2022, 1, 10); e.fileCreatedAt = DateTime(2022, 1, 10);
return e; return e;
}).toList(), }).toList(),
); );
assets.addAll( assets.addAll(
testAssets.sublist(10, 15).map((e) { testAssets.sublist(10, 15).map((e) {
e.createdAt = DateTime(2022, 2, 17); e.fileCreatedAt = DateTime(2022, 2, 17);
return e; return e;
}).toList(), }).toList(),
); );
assets.addAll( assets.addAll(
testAssets.sublist(15, 30).map((e) { testAssets.sublist(15, 30).map((e) {
e.createdAt = DateTime(2022, 10, 15); e.fileCreatedAt = DateTime(2022, 10, 15);
return e; return e;
}).toList(), }).toList(),
); );

View File

@ -79,7 +79,7 @@ export class AlbumRepository implements IAlbumRepository {
const queryProperties: FindManyOptions<AlbumEntity> = { const queryProperties: FindManyOptions<AlbumEntity> = {
relations: { sharedUsers: true, assets: true, sharedLinks: true, owner: true }, relations: { sharedUsers: true, assets: true, sharedLinks: true, owner: true },
order: { assets: { createdAt: 'ASC' }, createdAt: 'ASC' }, order: { assets: { fileCreatedAt: 'ASC' }, createdAt: 'ASC' },
}; };
let albumsQuery: Promise<AlbumEntity[]>; let albumsQuery: Promise<AlbumEntity[]>;
@ -123,7 +123,7 @@ export class AlbumRepository implements IAlbumRepository {
const albums = await this.albumRepository.find({ const albums = await this.albumRepository.find({
where: { ownerId: userId, assets: { id: assetId } }, where: { ownerId: userId, assets: { id: assetId } },
relations: { owner: true, assets: true, sharedUsers: true }, relations: { owner: true, assets: true, sharedUsers: true },
order: { assets: { createdAt: 'ASC' } }, order: { assets: { fileCreatedAt: 'ASC' } },
}); });
return albums; return albums;
@ -142,7 +142,7 @@ export class AlbumRepository implements IAlbumRepository {
}, },
order: { order: {
assets: { assets: {
createdAt: 'ASC', fileCreatedAt: 'ASC',
}, },
}, },
}); });

View File

@ -19,7 +19,9 @@ import { AssetSearchDto } from './dto/asset-search.dto';
export interface IAssetRepository { export interface IAssetRepository {
get(id: string): Promise<AssetEntity | null>; get(id: string): Promise<AssetEntity | null>;
create(asset: Omit<AssetEntity, 'id'>): Promise<AssetEntity>; create(
asset: Omit<AssetEntity, 'id' | 'createdAt' | 'updatedAt' | 'ownerId' | 'livePhotoVideoId'>,
): Promise<AssetEntity>;
remove(asset: AssetEntity): Promise<void>; remove(asset: AssetEntity): Promise<void>;
update(userId: string, asset: AssetEntity, dto: UpdateAssetDto): Promise<AssetEntity>; update(userId: string, asset: AssetEntity, dto: UpdateAssetDto): Promise<AssetEntity>;
@ -112,13 +114,13 @@ export class AssetRepository implements IAssetRepository {
.getMany(); .getMany();
} }
async getAssetCountByUserId(userId: string): Promise<AssetCountByUserIdResponseDto> { async getAssetCountByUserId(ownerId: string): Promise<AssetCountByUserIdResponseDto> {
// Get asset count by AssetType // Get asset count by AssetType
const items = await this.assetRepository const items = await this.assetRepository
.createQueryBuilder('asset') .createQueryBuilder('asset')
.select(`COUNT(asset.id)`, 'count') .select(`COUNT(asset.id)`, 'count')
.addSelect(`asset.type`, 'type') .addSelect(`asset.type`, 'type')
.where('"userId" = :userId', { userId: userId }) .where('"ownerId" = :ownerId', { ownerId: ownerId })
.andWhere('asset.isVisible = true') .andWhere('asset.isVisible = true')
.groupBy('asset.type') .groupBy('asset.type')
.getRawMany(); .getRawMany();
@ -149,7 +151,7 @@ export class AssetRepository implements IAssetRepository {
// Get asset entity from a list of time buckets // Get asset entity from a list of time buckets
return await this.assetRepository return await this.assetRepository
.createQueryBuilder('asset') .createQueryBuilder('asset')
.where('asset.userId = :userId', { userId: userId }) .where('asset.ownerId = :userId', { userId: userId })
.andWhere(`date_trunc('month', "createdAt") IN (:...buckets)`, { .andWhere(`date_trunc('month', "createdAt") IN (:...buckets)`, {
buckets: [...getAssetByTimeBucketDto.timeBucket], buckets: [...getAssetByTimeBucketDto.timeBucket],
}) })
@ -167,7 +169,7 @@ export class AssetRepository implements IAssetRepository {
.createQueryBuilder('asset') .createQueryBuilder('asset')
.select(`COUNT(asset.id)::int`, 'count') .select(`COUNT(asset.id)::int`, 'count')
.addSelect(`date_trunc('month', "createdAt")`, 'timeBucket') .addSelect(`date_trunc('month', "createdAt")`, 'timeBucket')
.where('"userId" = :userId', { userId: userId }) .where('"ownerId" = :userId', { userId: userId })
.andWhere('asset.resizePath is not NULL') .andWhere('asset.resizePath is not NULL')
.andWhere('asset.isVisible = true') .andWhere('asset.isVisible = true')
.groupBy(`date_trunc('month', "createdAt")`) .groupBy(`date_trunc('month', "createdAt")`)
@ -178,7 +180,7 @@ export class AssetRepository implements IAssetRepository {
.createQueryBuilder('asset') .createQueryBuilder('asset')
.select(`COUNT(asset.id)::int`, 'count') .select(`COUNT(asset.id)::int`, 'count')
.addSelect(`date_trunc('day', "createdAt")`, 'timeBucket') .addSelect(`date_trunc('day', "createdAt")`, 'timeBucket')
.where('"userId" = :userId', { userId: userId }) .where('"ownerId" = :userId', { userId: userId })
.andWhere('asset.resizePath is not NULL') .andWhere('asset.resizePath is not NULL')
.andWhere('asset.isVisible = true') .andWhere('asset.isVisible = true')
.groupBy(`date_trunc('day', "createdAt")`) .groupBy(`date_trunc('day', "createdAt")`)
@ -192,7 +194,7 @@ export class AssetRepository implements IAssetRepository {
async getSearchPropertiesByUserId(userId: string): Promise<SearchPropertiesDto[]> { async getSearchPropertiesByUserId(userId: string): Promise<SearchPropertiesDto[]> {
return await this.assetRepository return await this.assetRepository
.createQueryBuilder('asset') .createQueryBuilder('asset')
.where('asset.userId = :userId', { userId: userId }) .where('asset.ownerId = :userId', { userId: userId })
.andWhere('asset.isVisible = true') .andWhere('asset.isVisible = true')
.leftJoin('asset.exifInfo', 'ei') .leftJoin('asset.exifInfo', 'ei')
.leftJoin('asset.smartInfo', 'si') .leftJoin('asset.smartInfo', 'si')
@ -216,7 +218,7 @@ export class AssetRepository implements IAssetRepository {
SELECT DISTINCT ON (unnest(si.objects)) a.id, unnest(si.objects) as "object", a."resizePath", a."deviceAssetId", a."deviceId" SELECT DISTINCT ON (unnest(si.objects)) a.id, unnest(si.objects) as "object", a."resizePath", a."deviceAssetId", a."deviceId"
FROM assets a FROM assets a
LEFT JOIN smart_info si ON a.id = si."assetId" LEFT JOIN smart_info si ON a.id = si."assetId"
WHERE a."userId" = $1 WHERE a."ownerId" = $1
AND a."isVisible" = true AND a."isVisible" = true
AND si.objects IS NOT NULL AND si.objects IS NOT NULL
`, `,
@ -230,7 +232,7 @@ export class AssetRepository implements IAssetRepository {
SELECT DISTINCT ON (e.city) a.id, e.city, a."resizePath", a."deviceAssetId", a."deviceId" SELECT DISTINCT ON (e.city) a.id, e.city, a."resizePath", a."deviceAssetId", a."deviceId"
FROM assets a FROM assets a
LEFT JOIN exif e ON a.id = e."assetId" LEFT JOIN exif e ON a.id = e."assetId"
WHERE a."userId" = $1 WHERE a."ownerId" = $1
AND a."isVisible" = true AND a."isVisible" = true
AND e.city IS NOT NULL AND e.city IS NOT NULL
AND a.type = 'IMAGE'; AND a.type = 'IMAGE';
@ -255,12 +257,12 @@ export class AssetRepository implements IAssetRepository {
/** /**
* Get all assets belong to the user on the database * Get all assets belong to the user on the database
* @param userId * @param ownerId
*/ */
async getAllByUserId(userId: string, dto: AssetSearchDto): Promise<AssetEntity[]> { async getAllByUserId(ownerId: string, dto: AssetSearchDto): Promise<AssetEntity[]> {
return this.assetRepository.find({ return this.assetRepository.find({
where: { where: {
userId, ownerId,
resizePath: Not(IsNull()), resizePath: Not(IsNull()),
isVisible: true, isVisible: true,
isFavorite: dto.isFavorite, isFavorite: dto.isFavorite,
@ -271,7 +273,7 @@ export class AssetRepository implements IAssetRepository {
}, },
skip: dto.skip || 0, skip: dto.skip || 0,
order: { order: {
createdAt: 'DESC', fileCreatedAt: 'DESC',
}, },
}); });
} }
@ -280,7 +282,9 @@ export class AssetRepository implements IAssetRepository {
return this.assetRepository.findOne({ where: { id } }); return this.assetRepository.findOne({ where: { id } });
} }
async create(asset: Omit<AssetEntity, 'id'>): Promise<AssetEntity> { async create(
asset: Omit<AssetEntity, 'id' | 'createdAt' | 'updatedAt' | 'ownerId' | 'livePhotoVideoId'>,
): Promise<AssetEntity> {
return this.assetRepository.save(asset); return this.assetRepository.save(asset);
} }
@ -304,16 +308,16 @@ export class AssetRepository implements IAssetRepository {
/** /**
* Get assets by device's Id on the database * Get assets by device's Id on the database
* @param userId * @param ownerId
* @param deviceId * @param deviceId
* *
* @returns Promise<string[]> - Array of assetIds belong to the device * @returns Promise<string[]> - Array of assetIds belong to the device
*/ */
async getAllByDeviceId(userId: string, deviceId: string): Promise<string[]> { async getAllByDeviceId(ownerId: string, deviceId: string): Promise<string[]> {
const rows = await this.assetRepository.find({ const rows = await this.assetRepository.find({
where: { where: {
userId: userId, ownerId,
deviceId: deviceId, deviceId,
isVisible: true, isVisible: true,
}, },
select: ['deviceAssetId'], select: ['deviceAssetId'],
@ -326,14 +330,14 @@ export class AssetRepository implements IAssetRepository {
/** /**
* Get asset by checksum on the database * Get asset by checksum on the database
* @param userId * @param ownerId
* @param checksum * @param checksum
* *
*/ */
getAssetByChecksum(userId: string, checksum: Buffer): Promise<AssetEntity> { getAssetByChecksum(ownerId: string, checksum: Buffer): Promise<AssetEntity> {
return this.assetRepository.findOneOrFail({ return this.assetRepository.findOneOrFail({
where: { where: {
userId, ownerId,
checksum, checksum,
}, },
relations: ['exifInfo'], relations: ['exifInfo'],
@ -341,7 +345,7 @@ export class AssetRepository implements IAssetRepository {
} }
async getExistingAssets( async getExistingAssets(
userId: string, ownerId: string,
checkDuplicateAssetDto: CheckExistingAssetsDto, checkDuplicateAssetDto: CheckExistingAssetsDto,
): Promise<CheckExistingAssetsResponseDto> { ): Promise<CheckExistingAssetsResponseDto> {
const existingAssets = await this.assetRepository.find({ const existingAssets = await this.assetRepository.find({
@ -349,17 +353,17 @@ export class AssetRepository implements IAssetRepository {
where: { where: {
deviceAssetId: In(checkDuplicateAssetDto.deviceAssetIds), deviceAssetId: In(checkDuplicateAssetDto.deviceAssetIds),
deviceId: checkDuplicateAssetDto.deviceId, deviceId: checkDuplicateAssetDto.deviceId,
userId, ownerId,
}, },
}); });
return new CheckExistingAssetsResponseDto(existingAssets.map((a) => a.deviceAssetId)); return new CheckExistingAssetsResponseDto(existingAssets.map((a) => a.deviceAssetId));
} }
async countByIdAndUser(assetId: string, userId: string): Promise<number> { async countByIdAndUser(assetId: string, ownerId: string): Promise<number> {
return await this.assetRepository.count({ return await this.assetRepository.count({
where: { where: {
id: assetId, id: assetId,
userId, ownerId,
}, },
}); });
} }

View File

@ -1,6 +1,5 @@
import { timeUtils } from '@app/common';
import { AuthUserDto, IJobRepository, JobName } from '@app/domain'; import { AuthUserDto, IJobRepository, JobName } from '@app/domain';
import { AssetEntity } from '@app/infra/db/entities'; import { AssetEntity, UserEntity } from '@app/infra/db/entities';
import { StorageService } from '@app/storage'; import { StorageService } from '@app/storage';
import { IAssetRepository } from './asset-repository'; import { IAssetRepository } from './asset-repository';
import { CreateAssetDto, UploadFile } from './dto/create-asset.dto'; import { CreateAssetDto, UploadFile } from './dto/create-asset.dto';
@ -19,24 +18,23 @@ export class AssetCore {
livePhotoAssetId?: string, livePhotoAssetId?: string,
): Promise<AssetEntity> { ): Promise<AssetEntity> {
let asset = await this.repository.create({ let asset = await this.repository.create({
userId: authUser.id, owner: { id: authUser.id } as UserEntity,
mimeType: file.mimeType, mimeType: file.mimeType,
checksum: file.checksum || null, checksum: file.checksum || null,
originalPath: file.originalPath, originalPath: file.originalPath,
createdAt: timeUtils.checkValidTimestamp(dto.createdAt) ? dto.createdAt : new Date().toISOString(),
modifiedAt: timeUtils.checkValidTimestamp(dto.modifiedAt) ? dto.modifiedAt : new Date().toISOString(),
updatedAt: new Date().toISOString(),
deviceAssetId: dto.deviceAssetId, deviceAssetId: dto.deviceAssetId,
deviceId: dto.deviceId, deviceId: dto.deviceId,
fileCreatedAt: dto.fileCreatedAt,
fileModifiedAt: dto.fileModifiedAt,
type: dto.assetType, type: dto.assetType,
isFavorite: dto.isFavorite, isFavorite: dto.isFavorite,
duration: dto.duration || null, duration: dto.duration || null,
isVisible: dto.isVisible ?? true, isVisible: dto.isVisible ?? true,
livePhotoVideoId: livePhotoAssetId || null, livePhotoVideo: livePhotoAssetId != null ? ({ id: livePhotoAssetId } as AssetEntity) : null,
resizePath: null, resizePath: null,
webpPath: null, webpPath: null,
encodedVideoPath: null, encodedVideoPath: null,

View File

@ -27,8 +27,8 @@ const _getCreateAssetDto = (): CreateAssetDto => {
createAssetDto.deviceAssetId = 'deviceAssetId'; createAssetDto.deviceAssetId = 'deviceAssetId';
createAssetDto.deviceId = 'deviceId'; createAssetDto.deviceId = 'deviceId';
createAssetDto.assetType = AssetType.OTHER; createAssetDto.assetType = AssetType.OTHER;
createAssetDto.createdAt = '2022-06-19T23:41:36.910Z'; createAssetDto.fileCreatedAt = '2022-06-19T23:41:36.910Z';
createAssetDto.modifiedAt = '2022-06-19T23:41:36.910Z'; createAssetDto.fileModifiedAt = '2022-06-19T23:41:36.910Z';
createAssetDto.isFavorite = false; createAssetDto.isFavorite = false;
createAssetDto.duration = '0:00:00.000000'; createAssetDto.duration = '0:00:00.000000';
@ -39,14 +39,15 @@ const _getAsset_1 = () => {
const asset_1 = new AssetEntity(); const asset_1 = new AssetEntity();
asset_1.id = 'id_1'; asset_1.id = 'id_1';
asset_1.userId = 'user_id_1'; asset_1.ownerId = 'user_id_1';
asset_1.deviceAssetId = 'device_asset_id_1'; asset_1.deviceAssetId = 'device_asset_id_1';
asset_1.deviceId = 'device_id_1'; asset_1.deviceId = 'device_id_1';
asset_1.type = AssetType.VIDEO; asset_1.type = AssetType.VIDEO;
asset_1.originalPath = 'fake_path/asset_1.jpeg'; asset_1.originalPath = 'fake_path/asset_1.jpeg';
asset_1.resizePath = ''; asset_1.resizePath = '';
asset_1.createdAt = '2022-06-19T23:41:36.910Z'; asset_1.fileModifiedAt = '2022-06-19T23:41:36.910Z';
asset_1.modifiedAt = '2022-06-19T23:41:36.910Z'; asset_1.fileCreatedAt = '2022-06-19T23:41:36.910Z';
asset_1.updatedAt = '2022-06-19T23:41:36.910Z';
asset_1.isFavorite = false; asset_1.isFavorite = false;
asset_1.mimeType = 'image/jpeg'; asset_1.mimeType = 'image/jpeg';
asset_1.webpPath = ''; asset_1.webpPath = '';
@ -59,14 +60,15 @@ const _getAsset_2 = () => {
const asset_2 = new AssetEntity(); const asset_2 = new AssetEntity();
asset_2.id = 'id_2'; asset_2.id = 'id_2';
asset_2.userId = 'user_id_1'; asset_2.ownerId = 'user_id_1';
asset_2.deviceAssetId = 'device_asset_id_2'; asset_2.deviceAssetId = 'device_asset_id_2';
asset_2.deviceId = 'device_id_1'; asset_2.deviceId = 'device_id_1';
asset_2.type = AssetType.VIDEO; asset_2.type = AssetType.VIDEO;
asset_2.originalPath = 'fake_path/asset_2.jpeg'; asset_2.originalPath = 'fake_path/asset_2.jpeg';
asset_2.resizePath = ''; asset_2.resizePath = '';
asset_2.createdAt = '2022-06-19T23:41:36.910Z'; asset_2.fileModifiedAt = '2022-06-19T23:41:36.910Z';
asset_2.modifiedAt = '2022-06-19T23:41:36.910Z'; asset_2.fileCreatedAt = '2022-06-19T23:41:36.910Z';
asset_2.updatedAt = '2022-06-19T23:41:36.910Z';
asset_2.isFavorite = false; asset_2.isFavorite = false;
asset_2.mimeType = 'image/jpeg'; asset_2.mimeType = 'image/jpeg';
asset_2.webpPath = ''; asset_2.webpPath = '';
@ -292,7 +294,7 @@ describe('AssetService', () => {
const asset = { const asset = {
id: 'live-photo-asset', id: 'live-photo-asset',
originalPath: file.originalPath, originalPath: file.originalPath,
userId: authStub.user1.id, ownerId: authStub.user1.id,
type: AssetType.IMAGE, type: AssetType.IMAGE,
isVisible: true, isVisible: true,
} as AssetEntity; } as AssetEntity;
@ -307,7 +309,7 @@ describe('AssetService', () => {
const livePhotoAsset = { const livePhotoAsset = {
id: 'live-photo-motion', id: 'live-photo-motion',
originalPath: livePhotoFile.originalPath, originalPath: livePhotoFile.originalPath,
userId: authStub.user1.id, ownerId: authStub.user1.id,
type: AssetType.VIDEO, type: AssetType.VIDEO,
isVisible: false, isVisible: false,
} as AssetEntity; } as AssetEntity;

View File

@ -518,7 +518,7 @@ export class AssetService {
where: { where: {
deviceAssetId: checkDuplicateAssetDto.deviceAssetId, deviceAssetId: checkDuplicateAssetDto.deviceAssetId,
deviceId: checkDuplicateAssetDto.deviceId, deviceId: checkDuplicateAssetDto.deviceId,
userId: authUser.id, ownerId: authUser.id,
}, },
}); });

View File

@ -16,10 +16,10 @@ export class CreateAssetDto {
assetType!: AssetType; assetType!: AssetType;
@IsNotEmpty() @IsNotEmpty()
createdAt!: string; fileCreatedAt!: string;
@IsNotEmpty() @IsNotEmpty()
modifiedAt!: string; fileModifiedAt!: string;
@IsNotEmpty() @IsNotEmpty()
isFavorite!: boolean; isFavorite!: boolean;

View File

@ -159,8 +159,8 @@ export class MetadataExtractionProcessor {
return exifDate.toDate(); return exifDate.toDate();
}; };
const createdAt = exifToDate(exifData?.DateTimeOriginal ?? exifData?.CreateDate ?? asset.createdAt); const fileCreatedAt = exifToDate(exifData?.DateTimeOriginal ?? exifData?.CreateDate ?? asset.fileCreatedAt);
const modifyDate = exifToDate(exifData?.ModifyDate ?? asset.modifiedAt); const fileModifiedAt = exifToDate(exifData?.ModifyDate ?? asset.fileModifiedAt);
const fileStats = fs.statSync(asset.originalPath); const fileStats = fs.statSync(asset.originalPath);
const fileSizeInBytes = fileStats.size; const fileSizeInBytes = fileStats.size;
@ -174,8 +174,8 @@ export class MetadataExtractionProcessor {
newExif.exifImageWidth = exifData?.ExifImageWidth || exifData?.ImageWidth || null; newExif.exifImageWidth = exifData?.ExifImageWidth || exifData?.ImageWidth || null;
newExif.exposureTime = exifData?.ExposureTime || null; newExif.exposureTime = exifData?.ExposureTime || null;
newExif.orientation = exifData?.Orientation?.toString() || null; newExif.orientation = exifData?.Orientation?.toString() || null;
newExif.dateTimeOriginal = createdAt; newExif.dateTimeOriginal = fileCreatedAt;
newExif.modifyDate = modifyDate; newExif.modifyDate = fileModifiedAt;
newExif.lensModel = exifData?.LensModel || null; newExif.lensModel = exifData?.LensModel || null;
newExif.fNumber = exifData?.FNumber || null; newExif.fNumber = exifData?.FNumber || null;
newExif.focalLength = exifData?.FocalLength ? parseFloat(exifData.FocalLength) : null; newExif.focalLength = exifData?.FocalLength ? parseFloat(exifData.FocalLength) : null;
@ -186,7 +186,7 @@ export class MetadataExtractionProcessor {
await this.assetRepository.save({ await this.assetRepository.save({
id: asset.id, id: asset.id,
createdAt: createdAt?.toISOString(), fileCreatedAt: fileCreatedAt?.toISOString(),
}); });
if (newExif.livePhotoCID && !asset.livePhotoVideoId) { if (newExif.livePhotoCID && !asset.livePhotoVideoId) {
@ -273,7 +273,7 @@ export class MetadataExtractionProcessor {
}), }),
); );
let durationString = asset.duration; let durationString = asset.duration;
let createdAt = asset.createdAt; let fileCreatedAt = asset.fileCreatedAt;
if (data.format.duration) { if (data.format.duration) {
durationString = this.extractDuration(data.format.duration); durationString = this.extractDuration(data.format.duration);
@ -282,14 +282,10 @@ export class MetadataExtractionProcessor {
const videoTags = data.format.tags; const videoTags = data.format.tags;
if (videoTags) { if (videoTags) {
if (videoTags['com.apple.quicktime.creationdate']) { if (videoTags['com.apple.quicktime.creationdate']) {
createdAt = String(videoTags['com.apple.quicktime.creationdate']); fileCreatedAt = String(videoTags['com.apple.quicktime.creationdate']);
} else if (videoTags['creation_time']) { } else if (videoTags['creation_time']) {
createdAt = String(videoTags['creation_time']); fileCreatedAt = String(videoTags['creation_time']);
} else {
createdAt = asset.createdAt;
} }
} else {
createdAt = asset.createdAt;
} }
const exifData = await exiftool.read<ImmichTags>(asset.originalPath).catch((e) => { const exifData = await exiftool.read<ImmichTags>(asset.originalPath).catch((e) => {
@ -302,7 +298,7 @@ export class MetadataExtractionProcessor {
newExif.description = ''; newExif.description = '';
newExif.imageName = path.parse(fileName).name || null; newExif.imageName = path.parse(fileName).name || null;
newExif.fileSizeInByte = data.format.size || null; newExif.fileSizeInByte = data.format.size || null;
newExif.dateTimeOriginal = createdAt ? new Date(createdAt) : null; newExif.dateTimeOriginal = fileCreatedAt ? new Date(fileCreatedAt) : null;
newExif.modifyDate = null; newExif.modifyDate = null;
newExif.latitude = null; newExif.latitude = null;
newExif.longitude = null; newExif.longitude = null;
@ -382,8 +378,9 @@ export class MetadataExtractionProcessor {
} }
await this.exifRepository.upsert(newExif, { conflictPaths: ['assetId'] }); await this.exifRepository.upsert(newExif, { conflictPaths: ['assetId'] });
await this.assetRepository.update({ id: asset.id }, { duration: durationString, createdAt: createdAt }); await this.assetRepository.update({ id: asset.id }, { duration: durationString, fileCreatedAt });
} catch (err) { } catch (err) {
``;
// do nothing // do nothing
console.log('Error in video metadata extraction', err); console.log('Error in video metadata extraction', err);
} }

View File

@ -40,7 +40,7 @@ export class ThumbnailGeneratorProcessor {
const { asset } = job.data; const { asset } = job.data;
const sanitizedDeviceId = sanitize(String(asset.deviceId)); const sanitizedDeviceId = sanitize(String(asset.deviceId));
const resizePath = join(basePath, asset.userId, 'thumb', sanitizedDeviceId); const resizePath = join(basePath, asset.ownerId, 'thumb', sanitizedDeviceId);
if (!existsSync(resizePath)) { if (!existsSync(resizePath)) {
mkdirSync(resizePath, { recursive: true }); mkdirSync(resizePath, { recursive: true });
@ -75,7 +75,7 @@ export class ThumbnailGeneratorProcessor {
await this.machineLearningQueue.add(JobName.IMAGE_TAGGING, { asset }); await this.machineLearningQueue.add(JobName.IMAGE_TAGGING, { asset });
await this.machineLearningQueue.add(JobName.OBJECT_DETECTION, { asset }); await this.machineLearningQueue.add(JobName.OBJECT_DETECTION, { asset });
this.wsCommunicationGateway.server.to(asset.userId).emit('on_upload_success', JSON.stringify(mapAsset(asset))); this.wsCommunicationGateway.server.to(asset.ownerId).emit('on_upload_success', JSON.stringify(mapAsset(asset)));
} }
if (asset.type == AssetType.VIDEO) { if (asset.type == AssetType.VIDEO) {
@ -106,7 +106,7 @@ export class ThumbnailGeneratorProcessor {
await this.machineLearningQueue.add(JobName.IMAGE_TAGGING, { asset }); await this.machineLearningQueue.add(JobName.IMAGE_TAGGING, { asset });
await this.machineLearningQueue.add(JobName.OBJECT_DETECTION, { asset }); await this.machineLearningQueue.add(JobName.OBJECT_DETECTION, { asset });
this.wsCommunicationGateway.server.to(asset.userId).emit('on_upload_success', JSON.stringify(mapAsset(asset))); this.wsCommunicationGateway.server.to(asset.ownerId).emit('on_upload_success', JSON.stringify(mapAsset(asset)));
} }
} }

View File

@ -61,7 +61,7 @@ export class UserDeletionProcessor {
await this.albumRepository.remove(albums); await this.albumRepository.remove(albums);
await this.apiKeyRepository.delete({ userId: user.id }); await this.apiKeyRepository.delete({ userId: user.id });
await this.assetRepository.delete({ userId: user.id }); await this.assetRepository.delete({ ownerId: user.id });
await this.userRepository.remove(user); await this.userRepository.remove(user);
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to remove user`); this.logger.error(`Failed to remove user`);

View File

@ -22,7 +22,7 @@ export class VideoTranscodeProcessor {
async videoConversion(job: Job<IVideoConversionProcessor>) { async videoConversion(job: Job<IVideoConversionProcessor>) {
const { asset } = job.data; const { asset } = job.data;
const basePath = APP_UPLOAD_LOCATION; const basePath = APP_UPLOAD_LOCATION;
const encodedVideoPath = `${basePath}/${asset.userId}/encoded-video`; const encodedVideoPath = `${basePath}/${asset.ownerId}/encoded-video`;
if (!existsSync(encodedVideoPath)) { if (!existsSync(encodedVideoPath)) {
mkdirSync(encodedVideoPath, { recursive: true }); mkdirSync(encodedVideoPath, { recursive: true });

View File

@ -3324,10 +3324,10 @@
"type": "string", "type": "string",
"nullable": true "nullable": true
}, },
"createdAt": { "fileCreatedAt": {
"type": "string" "type": "string"
}, },
"modifiedAt": { "fileModifiedAt": {
"type": "string" "type": "string"
}, },
"updatedAt": { "updatedAt": {
@ -3376,8 +3376,8 @@
"deviceId", "deviceId",
"originalPath", "originalPath",
"resizePath", "resizePath",
"createdAt", "fileCreatedAt",
"modifiedAt", "fileModifiedAt",
"updatedAt", "updatedAt",
"isFavorite", "isFavorite",
"mimeType", "mimeType",
@ -3817,10 +3817,10 @@
"deviceId": { "deviceId": {
"type": "string" "type": "string"
}, },
"createdAt": { "fileCreatedAt": {
"type": "string" "type": "string"
}, },
"modifiedAt": { "fileModifiedAt": {
"type": "string" "type": "string"
}, },
"isFavorite": { "isFavorite": {
@ -3841,8 +3841,8 @@
"assetData", "assetData",
"deviceAssetId", "deviceAssetId",
"deviceId", "deviceId",
"createdAt", "fileCreatedAt",
"modifiedAt", "fileModifiedAt",
"isFavorite", "isFavorite",
"fileExtension" "fileExtension"
] ]

View File

@ -14,8 +14,8 @@ export class AssetResponseDto {
type!: AssetType; type!: AssetType;
originalPath!: string; originalPath!: string;
resizePath!: string | null; resizePath!: string | null;
createdAt!: string; fileCreatedAt!: string;
modifiedAt!: string; fileModifiedAt!: string;
updatedAt!: string; updatedAt!: string;
isFavorite!: boolean; isFavorite!: boolean;
mimeType!: string | null; mimeType!: string | null;
@ -32,13 +32,13 @@ export function mapAsset(entity: AssetEntity): AssetResponseDto {
return { return {
id: entity.id, id: entity.id,
deviceAssetId: entity.deviceAssetId, deviceAssetId: entity.deviceAssetId,
ownerId: entity.userId, ownerId: entity.ownerId,
deviceId: entity.deviceId, deviceId: entity.deviceId,
type: entity.type, type: entity.type,
originalPath: entity.originalPath, originalPath: entity.originalPath,
resizePath: entity.resizePath, resizePath: entity.resizePath,
createdAt: entity.createdAt, fileCreatedAt: entity.fileCreatedAt,
modifiedAt: entity.modifiedAt, fileModifiedAt: entity.fileModifiedAt,
updatedAt: entity.updatedAt, updatedAt: entity.updatedAt,
isFavorite: entity.isFavorite, isFavorite: entity.isFavorite,
mimeType: entity.mimeType, mimeType: entity.mimeType,
@ -56,13 +56,13 @@ export function mapAssetWithoutExif(entity: AssetEntity): AssetResponseDto {
return { return {
id: entity.id, id: entity.id,
deviceAssetId: entity.deviceAssetId, deviceAssetId: entity.deviceAssetId,
ownerId: entity.userId, ownerId: entity.ownerId,
deviceId: entity.deviceId, deviceId: entity.deviceId,
type: entity.type, type: entity.type,
originalPath: entity.originalPath, originalPath: entity.originalPath,
resizePath: entity.resizePath, resizePath: entity.resizePath,
createdAt: entity.createdAt, fileCreatedAt: entity.fileCreatedAt,
modifiedAt: entity.modifiedAt, fileModifiedAt: entity.fileModifiedAt,
updatedAt: entity.updatedAt, updatedAt: entity.updatedAt,
isFavorite: entity.isFavorite, isFavorite: entity.isFavorite,
mimeType: entity.mimeType, mimeType: entity.mimeType,

View File

@ -95,20 +95,23 @@ export const assetEntityStub = {
image: Object.freeze<AssetEntity>({ image: Object.freeze<AssetEntity>({
id: 'asset-id', id: 'asset-id',
deviceAssetId: 'device-asset-id', deviceAssetId: 'device-asset-id',
modifiedAt: today.toISOString(), fileModifiedAt: today.toISOString(),
createdAt: today.toISOString(), fileCreatedAt: today.toISOString(),
userId: 'user-id', owner: userEntityStub.user1,
ownerId: 'user-id',
deviceId: 'device-id', deviceId: 'device-id',
originalPath: '/original/path', originalPath: '/original/path',
resizePath: null, resizePath: null,
type: AssetType.IMAGE, type: AssetType.IMAGE,
webpPath: null, webpPath: null,
encodedVideoPath: null, encodedVideoPath: null,
createdAt: today.toISOString(),
updatedAt: today.toISOString(), updatedAt: today.toISOString(),
mimeType: null, mimeType: null,
isFavorite: true, isFavorite: true,
duration: null, duration: null,
isVisible: true, isVisible: true,
livePhotoVideo: null,
livePhotoVideoId: null, livePhotoVideoId: null,
tags: [], tags: [],
sharedLinks: [], sharedLinks: [],
@ -146,8 +149,8 @@ const assetResponse: AssetResponseDto = {
type: AssetType.VIDEO, type: AssetType.VIDEO,
originalPath: 'fake_path/jpeg', originalPath: 'fake_path/jpeg',
resizePath: '', resizePath: '',
createdAt: today.toISOString(), fileModifiedAt: today.toISOString(),
modifiedAt: today.toISOString(), fileCreatedAt: today.toISOString(),
updatedAt: today.toISOString(), updatedAt: today.toISOString(),
isFavorite: false, isFavorite: false,
mimeType: 'image/jpeg', mimeType: 'image/jpeg',
@ -374,14 +377,16 @@ export const sharedLinkStub = {
assets: [ assets: [
{ {
id: 'id_1', id: 'id_1',
userId: 'user_id_1', owner: userEntityStub.user1,
ownerId: 'user_id_1',
deviceAssetId: 'device_asset_id_1', deviceAssetId: 'device_asset_id_1',
deviceId: 'device_id_1', deviceId: 'device_id_1',
type: AssetType.VIDEO, type: AssetType.VIDEO,
originalPath: 'fake_path/jpeg', originalPath: 'fake_path/jpeg',
resizePath: '', resizePath: '',
fileModifiedAt: today.toISOString(),
fileCreatedAt: today.toISOString(),
createdAt: today.toISOString(), createdAt: today.toISOString(),
modifiedAt: today.toISOString(),
updatedAt: today.toISOString(), updatedAt: today.toISOString(),
isFavorite: false, isFavorite: false,
mimeType: 'image/jpeg', mimeType: 'image/jpeg',
@ -396,6 +401,7 @@ export const sharedLinkStub = {
encodedVideoPath: '', encodedVideoPath: '',
duration: null, duration: null,
isVisible: true, isVisible: true,
livePhotoVideo: null,
livePhotoVideoId: null, livePhotoVideoId: null,
exifInfo: { exifInfo: {
livePhotoCID: null, livePhotoCID: null,

View File

@ -1,9 +1,12 @@
import { import {
Column, Column,
CreateDateColumn,
Entity, Entity,
Index, Index,
JoinColumn,
JoinTable, JoinTable,
ManyToMany, ManyToMany,
ManyToOne,
OneToOne, OneToOne,
PrimaryGeneratedColumn, PrimaryGeneratedColumn,
Unique, Unique,
@ -13,9 +16,10 @@ import { ExifEntity } from './exif.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 { TagEntity } from './tag.entity'; import { TagEntity } from './tag.entity';
import { UserEntity } from './user.entity';
@Entity('assets') @Entity('assets')
@Unique('UQ_userid_checksum', ['userId', 'checksum']) @Unique('UQ_userid_checksum', ['owner', 'checksum'])
export class AssetEntity { export class AssetEntity {
@PrimaryGeneratedColumn('uuid') @PrimaryGeneratedColumn('uuid')
id!: string; id!: string;
@ -23,8 +27,11 @@ export class AssetEntity {
@Column() @Column()
deviceAssetId!: string; deviceAssetId!: string;
@ManyToOne(() => UserEntity, { eager: true, onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: false })
owner!: UserEntity;
@Column() @Column()
userId!: string; ownerId!: string;
@Column() @Column()
deviceId!: string; deviceId!: string;
@ -44,15 +51,18 @@ export class AssetEntity {
@Column({ type: 'varchar', nullable: true, default: '' }) @Column({ type: 'varchar', nullable: true, default: '' })
encodedVideoPath!: string | null; encodedVideoPath!: string | null;
@Column({ type: 'timestamptz' }) @CreateDateColumn({ type: 'timestamptz' })
createdAt!: string; createdAt!: string;
@Column({ type: 'timestamptz' })
modifiedAt!: string;
@UpdateDateColumn({ type: 'timestamptz' }) @UpdateDateColumn({ type: 'timestamptz' })
updatedAt!: string; updatedAt!: string;
@Column({ type: 'timestamptz' })
fileCreatedAt!: string;
@Column({ type: 'timestamptz' })
fileModifiedAt!: string;
@Column({ type: 'boolean', default: false }) @Column({ type: 'boolean', default: false })
isFavorite!: boolean; isFavorite!: boolean;
@ -69,7 +79,11 @@ export class AssetEntity {
@Column({ type: 'boolean', default: true }) @Column({ type: 'boolean', default: true })
isVisible!: boolean; isVisible!: boolean;
@Column({ type: 'uuid', nullable: true }) @OneToOne(() => AssetEntity, { nullable: true, onUpdate: 'CASCADE', onDelete: 'SET NULL' })
@JoinColumn()
livePhotoVideo!: AssetEntity | null;
@Column({ nullable: true })
livePhotoVideoId!: string | null; livePhotoVideoId!: string | null;
@OneToOne(() => ExifEntity, (exifEntity) => exifEntity.asset) @OneToOne(() => ExifEntity, (exifEntity) => exifEntity.asset)
@ -78,12 +92,11 @@ export class AssetEntity {
@OneToOne(() => SmartInfoEntity, (smartInfoEntity) => smartInfoEntity.asset) @OneToOne(() => SmartInfoEntity, (smartInfoEntity) => smartInfoEntity.asset)
smartInfo?: SmartInfoEntity; smartInfo?: SmartInfoEntity;
// https://github.com/typeorm/typeorm/blob/master/docs/many-to-many-relations.md @ManyToMany(() => TagEntity, (tag) => tag.assets, { cascade: true, eager: true })
@ManyToMany(() => TagEntity, (tag) => tag.assets, { cascade: true })
@JoinTable({ name: 'tag_asset' }) @JoinTable({ name: 'tag_asset' })
tags!: TagEntity[]; tags!: TagEntity[];
@ManyToMany(() => SharedLinkEntity, (link) => link.assets, { cascade: true }) @ManyToMany(() => SharedLinkEntity, (link) => link.assets, { cascade: true, eager: true })
@JoinTable({ name: 'shared_link__asset' }) @JoinTable({ name: 'shared_link__asset' })
sharedLinks!: SharedLinkEntity[]; sharedLinks!: SharedLinkEntity[];
} }

View File

@ -0,0 +1,30 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class FixAssetRelations1676680127415 implements MigrationInterface {
name = 'FixAssetRelations1676680127415'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "modifiedAt" TO "fileModifiedAt"`);
await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "createdAt" TO "fileCreatedAt"`);
await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "userId" TO "ownerId"`);
await queryRunner.query(`ALTER TABLE assets ALTER COLUMN "ownerId" TYPE uuid USING "ownerId"::uuid;`);
await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "UQ_16294b83fa8c0149719a1f631ef" UNIQUE ("livePhotoVideoId")`);
await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "FK_2c5ac0d6fb58b238fd2068de67d" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`);
await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "FK_16294b83fa8c0149719a1f631ef" FOREIGN KEY ("livePhotoVideoId") REFERENCES "assets"("id") ON DELETE SET NULL ON UPDATE CASCADE`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "FK_16294b83fa8c0149719a1f631ef"`);
await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "FK_2c5ac0d6fb58b238fd2068de67d"`);
await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "UQ_16294b83fa8c0149719a1f631ef"`);
await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "fileCreatedAt" TO "createdAt"`);
await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "fileModifiedAt" TO "modifiedAt"`);
await queryRunner.query(`ALTER TABLE "assets" RENAME COLUMN "ownerId" TO "userId"`);
await queryRunner.query(`ALTER TABLE assets ALTER COLUMN "userId" TYPE varchar`);
}
}

View File

@ -0,0 +1,14 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class AssetCreatedAtField1676721296440 implements MigrationInterface {
name = 'AssetCreatedAtField1676721296440'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "assets" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "assets" DROP COLUMN "createdAt"`);
}
}

View File

@ -31,11 +31,11 @@ export class SharedLinkRepository implements ISharedLinkRepository {
order: { order: {
createdAt: 'DESC', createdAt: 'DESC',
assets: { assets: {
createdAt: 'ASC', fileCreatedAt: 'ASC',
}, },
album: { album: {
assets: { assets: {
createdAt: 'ASC', fileCreatedAt: 'ASC',
}, },
}, },
}, },

View File

@ -50,7 +50,7 @@ export class StorageService {
const source = asset.originalPath; const source = asset.originalPath;
const ext = path.extname(source).split('.').pop() as string; const ext = path.extname(source).split('.').pop() as string;
const sanitized = sanitize(path.basename(filename, `.${ext}`)); const sanitized = sanitize(path.basename(filename, `.${ext}`));
const rootPath = path.join(APP_UPLOAD_LOCATION, asset.userId); const rootPath = path.join(APP_UPLOAD_LOCATION, asset.ownerId);
const storagePath = this.render(this.storageTemplate, asset, sanitized, ext); const storagePath = this.render(this.storageTemplate, asset, sanitized, ext);
const fullPath = path.normalize(path.join(rootPath, storagePath)); const fullPath = path.normalize(path.join(rootPath, storagePath));
let destination = `${fullPath}.${ext}`; let destination = `${fullPath}.${ext}`;
@ -132,7 +132,7 @@ export class StorageService {
this.render( this.render(
template, template,
{ {
createdAt: new Date().toISOString(), fileCreatedAt: new Date().toISOString(),
originalPath: '/upload/test/IMG_123.jpg', originalPath: '/upload/test/IMG_123.jpg',
type: AssetType.IMAGE, type: AssetType.IMAGE,
} as AssetEntity, } as AssetEntity,
@ -161,7 +161,7 @@ export class StorageService {
const fileType = asset.type == AssetType.IMAGE ? 'IMG' : 'VID'; const fileType = asset.type == AssetType.IMAGE ? 'IMG' : 'VID';
const fileTypeFull = asset.type == AssetType.IMAGE ? 'IMAGE' : 'VIDEO'; const fileTypeFull = asset.type == AssetType.IMAGE ? 'IMAGE' : 'VIDEO';
const dt = luxon.DateTime.fromISO(new Date(asset.createdAt).toISOString()); const dt = luxon.DateTime.fromISO(new Date(asset.fileCreatedAt).toISOString());
const dateTokens = [ const dateTokens = [
...supportedYearTokens, ...supportedYearTokens,

View File

@ -6,7 +6,7 @@
"packages": { "packages": {
"": { "": {
"name": "immich", "name": "immich",
"version": "1.46.1", "version": "1.47.3",
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"@nestjs/bull": "^0.6.2", "@nestjs/bull": "^0.6.2",

View File

@ -4,7 +4,7 @@
* Immich * Immich
* Immich API * Immich API
* *
* The version of the OpenAPI document: 1.47.2 * The version of the OpenAPI document: 1.47.3
* *
* *
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
@ -61,10 +61,10 @@ export interface APIKeyCreateResponseDto {
export interface APIKeyResponseDto { export interface APIKeyResponseDto {
/** /**
* *
* @type {number} * @type {string}
* @memberof APIKeyResponseDto * @memberof APIKeyResponseDto
*/ */
'id': number; 'id': string;
/** /**
* *
* @type {string} * @type {string}
@ -467,13 +467,13 @@ export interface AssetResponseDto {
* @type {string} * @type {string}
* @memberof AssetResponseDto * @memberof AssetResponseDto
*/ */
'createdAt': string; 'fileCreatedAt': string;
/** /**
* *
* @type {string} * @type {string}
* @memberof AssetResponseDto * @memberof AssetResponseDto
*/ */
'modifiedAt': string; 'fileModifiedAt': string;
/** /**
* *
* @type {string} * @type {string}
@ -2356,11 +2356,11 @@ export const APIKeyApiAxiosParamCreator = function (configuration?: Configuratio
}, },
/** /**
* *
* @param {number} id * @param {string} id
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
deleteKey: async (id: number, options: AxiosRequestConfig = {}): Promise<RequestArgs> => { deleteKey: async (id: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined // verify required parameter 'id' is not null or undefined
assertParamExists('deleteKey', 'id', id) assertParamExists('deleteKey', 'id', id)
const localVarPath = `/api-key/{id}` const localVarPath = `/api-key/{id}`
@ -2389,11 +2389,11 @@ export const APIKeyApiAxiosParamCreator = function (configuration?: Configuratio
}, },
/** /**
* *
* @param {number} id * @param {string} id
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
getKey: async (id: number, options: AxiosRequestConfig = {}): Promise<RequestArgs> => { getKey: async (id: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined // verify required parameter 'id' is not null or undefined
assertParamExists('getKey', 'id', id) assertParamExists('getKey', 'id', id)
const localVarPath = `/api-key/{id}` const localVarPath = `/api-key/{id}`
@ -2451,12 +2451,12 @@ export const APIKeyApiAxiosParamCreator = function (configuration?: Configuratio
}, },
/** /**
* *
* @param {number} id * @param {string} id
* @param {APIKeyUpdateDto} aPIKeyUpdateDto * @param {APIKeyUpdateDto} aPIKeyUpdateDto
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
updateKey: async (id: number, aPIKeyUpdateDto: APIKeyUpdateDto, options: AxiosRequestConfig = {}): Promise<RequestArgs> => { updateKey: async (id: string, aPIKeyUpdateDto: APIKeyUpdateDto, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined // verify required parameter 'id' is not null or undefined
assertParamExists('updateKey', 'id', id) assertParamExists('updateKey', 'id', id)
// verify required parameter 'aPIKeyUpdateDto' is not null or undefined // verify required parameter 'aPIKeyUpdateDto' is not null or undefined
@ -2510,21 +2510,21 @@ export const APIKeyApiFp = function(configuration?: Configuration) {
}, },
/** /**
* *
* @param {number} id * @param {string} id
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async deleteKey(id: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> { async deleteKey(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.deleteKey(id, options); const localVarAxiosArgs = await localVarAxiosParamCreator.deleteKey(id, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
}, },
/** /**
* *
* @param {number} id * @param {string} id
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async getKey(id: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<APIKeyResponseDto>> { async getKey(id: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<APIKeyResponseDto>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getKey(id, options); const localVarAxiosArgs = await localVarAxiosParamCreator.getKey(id, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
}, },
@ -2539,12 +2539,12 @@ export const APIKeyApiFp = function(configuration?: Configuration) {
}, },
/** /**
* *
* @param {number} id * @param {string} id
* @param {APIKeyUpdateDto} aPIKeyUpdateDto * @param {APIKeyUpdateDto} aPIKeyUpdateDto
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async updateKey(id: number, aPIKeyUpdateDto: APIKeyUpdateDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<APIKeyResponseDto>> { async updateKey(id: string, aPIKeyUpdateDto: APIKeyUpdateDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<APIKeyResponseDto>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.updateKey(id, aPIKeyUpdateDto, options); const localVarAxiosArgs = await localVarAxiosParamCreator.updateKey(id, aPIKeyUpdateDto, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
}, },
@ -2569,20 +2569,20 @@ export const APIKeyApiFactory = function (configuration?: Configuration, basePat
}, },
/** /**
* *
* @param {number} id * @param {string} id
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
deleteKey(id: number, options?: any): AxiosPromise<void> { deleteKey(id: string, options?: any): AxiosPromise<void> {
return localVarFp.deleteKey(id, options).then((request) => request(axios, basePath)); return localVarFp.deleteKey(id, options).then((request) => request(axios, basePath));
}, },
/** /**
* *
* @param {number} id * @param {string} id
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
getKey(id: number, options?: any): AxiosPromise<APIKeyResponseDto> { getKey(id: string, options?: any): AxiosPromise<APIKeyResponseDto> {
return localVarFp.getKey(id, options).then((request) => request(axios, basePath)); return localVarFp.getKey(id, options).then((request) => request(axios, basePath));
}, },
/** /**
@ -2595,12 +2595,12 @@ export const APIKeyApiFactory = function (configuration?: Configuration, basePat
}, },
/** /**
* *
* @param {number} id * @param {string} id
* @param {APIKeyUpdateDto} aPIKeyUpdateDto * @param {APIKeyUpdateDto} aPIKeyUpdateDto
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
updateKey(id: number, aPIKeyUpdateDto: APIKeyUpdateDto, options?: any): AxiosPromise<APIKeyResponseDto> { updateKey(id: string, aPIKeyUpdateDto: APIKeyUpdateDto, options?: any): AxiosPromise<APIKeyResponseDto> {
return localVarFp.updateKey(id, aPIKeyUpdateDto, options).then((request) => request(axios, basePath)); return localVarFp.updateKey(id, aPIKeyUpdateDto, options).then((request) => request(axios, basePath));
}, },
}; };
@ -2626,23 +2626,23 @@ export class APIKeyApi extends BaseAPI {
/** /**
* *
* @param {number} id * @param {string} id
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
* @memberof APIKeyApi * @memberof APIKeyApi
*/ */
public deleteKey(id: number, options?: AxiosRequestConfig) { public deleteKey(id: string, options?: AxiosRequestConfig) {
return APIKeyApiFp(this.configuration).deleteKey(id, options).then((request) => request(this.axios, this.basePath)); return APIKeyApiFp(this.configuration).deleteKey(id, options).then((request) => request(this.axios, this.basePath));
} }
/** /**
* *
* @param {number} id * @param {string} id
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
* @memberof APIKeyApi * @memberof APIKeyApi
*/ */
public getKey(id: number, options?: AxiosRequestConfig) { public getKey(id: string, options?: AxiosRequestConfig) {
return APIKeyApiFp(this.configuration).getKey(id, options).then((request) => request(this.axios, this.basePath)); return APIKeyApiFp(this.configuration).getKey(id, options).then((request) => request(this.axios, this.basePath));
} }
@ -2658,13 +2658,13 @@ export class APIKeyApi extends BaseAPI {
/** /**
* *
* @param {number} id * @param {string} id
* @param {APIKeyUpdateDto} aPIKeyUpdateDto * @param {APIKeyUpdateDto} aPIKeyUpdateDto
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
* @memberof APIKeyApi * @memberof APIKeyApi
*/ */
public updateKey(id: number, aPIKeyUpdateDto: APIKeyUpdateDto, options?: AxiosRequestConfig) { public updateKey(id: string, aPIKeyUpdateDto: APIKeyUpdateDto, options?: AxiosRequestConfig) {
return APIKeyApiFp(this.configuration).updateKey(id, aPIKeyUpdateDto, options).then((request) => request(this.axios, this.basePath)); return APIKeyApiFp(this.configuration).updateKey(id, aPIKeyUpdateDto, options).then((request) => request(this.axios, this.basePath));
} }
} }
@ -4432,8 +4432,8 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
* @param {any} assetData * @param {any} assetData
* @param {string} deviceAssetId * @param {string} deviceAssetId
* @param {string} deviceId * @param {string} deviceId
* @param {string} createdAt * @param {string} fileCreatedAt
* @param {string} modifiedAt * @param {string} fileModifiedAt
* @param {boolean} isFavorite * @param {boolean} isFavorite
* @param {string} fileExtension * @param {string} fileExtension
* @param {any} [livePhotoData] * @param {any} [livePhotoData]
@ -4442,7 +4442,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
uploadFile: async (assetType: AssetTypeEnum, assetData: any, deviceAssetId: string, deviceId: string, createdAt: string, modifiedAt: string, isFavorite: boolean, fileExtension: string, livePhotoData?: any, isVisible?: boolean, duration?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => { uploadFile: async (assetType: AssetTypeEnum, assetData: any, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, fileExtension: string, livePhotoData?: any, isVisible?: boolean, duration?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'assetType' is not null or undefined // verify required parameter 'assetType' is not null or undefined
assertParamExists('uploadFile', 'assetType', assetType) assertParamExists('uploadFile', 'assetType', assetType)
// verify required parameter 'assetData' is not null or undefined // verify required parameter 'assetData' is not null or undefined
@ -4451,10 +4451,10 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
assertParamExists('uploadFile', 'deviceAssetId', deviceAssetId) assertParamExists('uploadFile', 'deviceAssetId', deviceAssetId)
// verify required parameter 'deviceId' is not null or undefined // verify required parameter 'deviceId' is not null or undefined
assertParamExists('uploadFile', 'deviceId', deviceId) assertParamExists('uploadFile', 'deviceId', deviceId)
// verify required parameter 'createdAt' is not null or undefined // verify required parameter 'fileCreatedAt' is not null or undefined
assertParamExists('uploadFile', 'createdAt', createdAt) assertParamExists('uploadFile', 'fileCreatedAt', fileCreatedAt)
// verify required parameter 'modifiedAt' is not null or undefined // verify required parameter 'fileModifiedAt' is not null or undefined
assertParamExists('uploadFile', 'modifiedAt', modifiedAt) assertParamExists('uploadFile', 'fileModifiedAt', fileModifiedAt)
// verify required parameter 'isFavorite' is not null or undefined // verify required parameter 'isFavorite' is not null or undefined
assertParamExists('uploadFile', 'isFavorite', isFavorite) assertParamExists('uploadFile', 'isFavorite', isFavorite)
// verify required parameter 'fileExtension' is not null or undefined // verify required parameter 'fileExtension' is not null or undefined
@ -4497,12 +4497,12 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
localVarFormParams.append('deviceId', deviceId as any); localVarFormParams.append('deviceId', deviceId as any);
} }
if (createdAt !== undefined) { if (fileCreatedAt !== undefined) {
localVarFormParams.append('createdAt', createdAt as any); localVarFormParams.append('fileCreatedAt', fileCreatedAt as any);
} }
if (modifiedAt !== undefined) { if (fileModifiedAt !== undefined) {
localVarFormParams.append('modifiedAt', modifiedAt as any); localVarFormParams.append('fileModifiedAt', fileModifiedAt as any);
} }
if (isFavorite !== undefined) { if (isFavorite !== undefined) {
@ -4772,8 +4772,8 @@ export const AssetApiFp = function(configuration?: Configuration) {
* @param {any} assetData * @param {any} assetData
* @param {string} deviceAssetId * @param {string} deviceAssetId
* @param {string} deviceId * @param {string} deviceId
* @param {string} createdAt * @param {string} fileCreatedAt
* @param {string} modifiedAt * @param {string} fileModifiedAt
* @param {boolean} isFavorite * @param {boolean} isFavorite
* @param {string} fileExtension * @param {string} fileExtension
* @param {any} [livePhotoData] * @param {any} [livePhotoData]
@ -4782,8 +4782,8 @@ export const AssetApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async uploadFile(assetType: AssetTypeEnum, assetData: any, deviceAssetId: string, deviceId: string, createdAt: string, modifiedAt: string, isFavorite: boolean, fileExtension: string, livePhotoData?: any, isVisible?: boolean, duration?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetFileUploadResponseDto>> { async uploadFile(assetType: AssetTypeEnum, assetData: any, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, fileExtension: string, livePhotoData?: any, isVisible?: boolean, duration?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetFileUploadResponseDto>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.uploadFile(assetType, assetData, deviceAssetId, deviceId, createdAt, modifiedAt, isFavorite, fileExtension, livePhotoData, isVisible, duration, options); const localVarAxiosArgs = await localVarAxiosParamCreator.uploadFile(assetType, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, fileExtension, livePhotoData, isVisible, duration, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
}, },
} }
@ -5002,8 +5002,8 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
* @param {any} assetData * @param {any} assetData
* @param {string} deviceAssetId * @param {string} deviceAssetId
* @param {string} deviceId * @param {string} deviceId
* @param {string} createdAt * @param {string} fileCreatedAt
* @param {string} modifiedAt * @param {string} fileModifiedAt
* @param {boolean} isFavorite * @param {boolean} isFavorite
* @param {string} fileExtension * @param {string} fileExtension
* @param {any} [livePhotoData] * @param {any} [livePhotoData]
@ -5012,8 +5012,8 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
uploadFile(assetType: AssetTypeEnum, assetData: any, deviceAssetId: string, deviceId: string, createdAt: string, modifiedAt: string, isFavorite: boolean, fileExtension: string, livePhotoData?: any, isVisible?: boolean, duration?: string, options?: any): AxiosPromise<AssetFileUploadResponseDto> { uploadFile(assetType: AssetTypeEnum, assetData: any, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, fileExtension: string, livePhotoData?: any, isVisible?: boolean, duration?: string, options?: any): AxiosPromise<AssetFileUploadResponseDto> {
return localVarFp.uploadFile(assetType, assetData, deviceAssetId, deviceId, createdAt, modifiedAt, isFavorite, fileExtension, livePhotoData, isVisible, duration, options).then((request) => request(axios, basePath)); return localVarFp.uploadFile(assetType, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, fileExtension, livePhotoData, isVisible, duration, options).then((request) => request(axios, basePath));
}, },
}; };
}; };
@ -5275,8 +5275,8 @@ export class AssetApi extends BaseAPI {
* @param {any} assetData * @param {any} assetData
* @param {string} deviceAssetId * @param {string} deviceAssetId
* @param {string} deviceId * @param {string} deviceId
* @param {string} createdAt * @param {string} fileCreatedAt
* @param {string} modifiedAt * @param {string} fileModifiedAt
* @param {boolean} isFavorite * @param {boolean} isFavorite
* @param {string} fileExtension * @param {string} fileExtension
* @param {any} [livePhotoData] * @param {any} [livePhotoData]
@ -5286,8 +5286,8 @@ export class AssetApi extends BaseAPI {
* @throws {RequiredError} * @throws {RequiredError}
* @memberof AssetApi * @memberof AssetApi
*/ */
public uploadFile(assetType: AssetTypeEnum, assetData: any, deviceAssetId: string, deviceId: string, createdAt: string, modifiedAt: string, isFavorite: boolean, fileExtension: string, livePhotoData?: any, isVisible?: boolean, duration?: string, options?: AxiosRequestConfig) { public uploadFile(assetType: AssetTypeEnum, assetData: any, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, fileExtension: string, livePhotoData?: any, isVisible?: boolean, duration?: string, options?: AxiosRequestConfig) {
return AssetApiFp(this.configuration).uploadFile(assetType, assetData, deviceAssetId, deviceId, createdAt, modifiedAt, isFavorite, fileExtension, livePhotoData, isVisible, duration, options).then((request) => request(this.axios, this.basePath)); return AssetApiFp(this.configuration).uploadFile(assetType, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, fileExtension, livePhotoData, isVisible, duration, options).then((request) => request(this.axios, this.basePath));
} }
} }

View File

@ -4,7 +4,7 @@
* Immich * Immich
* Immich API * Immich API
* *
* The version of the OpenAPI document: 1.47.2 * The version of the OpenAPI document: 1.47.3
* *
* *
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@ -4,7 +4,7 @@
* Immich * Immich
* Immich API * Immich API
* *
* The version of the OpenAPI document: 1.47.2 * The version of the OpenAPI document: 1.47.3
* *
* *
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@ -4,7 +4,7 @@
* Immich * Immich
* Immich API * Immich API
* *
* The version of the OpenAPI document: 1.47.2 * The version of the OpenAPI document: 1.47.3
* *
* *
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@ -4,7 +4,7 @@
* Immich * Immich
* Immich API * Immich API
* *
* The version of the OpenAPI document: 1.47.2 * The version of the OpenAPI document: 1.47.3
* *
* *
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@ -96,8 +96,8 @@
}; };
const getDateRange = () => { const getDateRange = () => {
const startDate = new Date(album.assets[0].createdAt); const startDate = new Date(album.assets[0].fileCreatedAt);
const endDate = new Date(album.assets[album.assetCount - 1].createdAt); const endDate = new Date(album.assets[album.assetCount - 1].fileCreatedAt);
const startDateString = startDate.toLocaleDateString(locale, albumDateFormat); const startDateString = startDate.toLocaleDateString(locale, albumDateFormat);
const endDateString = endDate.toLocaleDateString(locale, albumDateFormat); const endDateString = endDate.toLocaleDateString(locale, albumDateFormat);

View File

@ -31,7 +31,7 @@
let hoveredDateGroup = ''; let hoveredDateGroup = '';
$: assetsGroupByDate = lodash $: assetsGroupByDate = lodash
.chain(assets) .chain(assets)
.groupBy((a) => new Date(a.createdAt).toLocaleDateString(locale, groupDateFormat)) .groupBy((a) => new Date(a.fileCreatedAt).toLocaleDateString(locale, groupDateFormat))
.sortBy((group) => assets.indexOf(group[0])) .sortBy((group) => assets.indexOf(group[0]))
.value(); .value();
@ -114,7 +114,7 @@
bind:clientHeight={actualBucketHeight} bind:clientHeight={actualBucketHeight}
> >
{#each assetsGroupByDate as assetsInDateGroup, groupIndex (assetsInDateGroup[0].id)} {#each assetsGroupByDate as assetsInDateGroup, groupIndex (assetsInDateGroup[0].id)}
{@const dateGroupTitle = new Date(assetsInDateGroup[0].createdAt).toLocaleDateString( {@const dateGroupTitle = new Date(assetsInDateGroup[0].fileCreatedAt).toLocaleDateString(
locale, locale,
groupDateFormat groupDateFormat
)} )}

View File

@ -65,7 +65,7 @@ function createAssetInteractionStore() {
const navigateAsset = async (direction: 'next' | 'previous') => { const navigateAsset = async (direction: 'next' | 'previous') => {
// Flatten and sort the asset by date if there are new assets // Flatten and sort the asset by date if there are new assets
if (assetSortedByDate.length === 0 || savedAssetLength !== _assetGridState.assets.length) { if (assetSortedByDate.length === 0 || savedAssetLength !== _assetGridState.assets.length) {
assetSortedByDate = sortBy(_assetGridState.assets, (a) => a.createdAt); assetSortedByDate = sortBy(_assetGridState.assets, (a) => a.fileCreatedAt);
savedAssetLength = _assetGridState.assets.length; savedAssetLength = _assetGridState.assets.length;
} }

View File

@ -69,7 +69,7 @@ async function fileUploader(
const assetType = mimeType.split('/')[0].toUpperCase(); const assetType = mimeType.split('/')[0].toUpperCase();
const fileExtension = getFilenameExtension(asset.name); const fileExtension = getFilenameExtension(asset.name);
const formData = new FormData(); const formData = new FormData();
const createdAt = new Date(asset.lastModified).toISOString(); const fileCreatedAt = new Date(asset.lastModified).toISOString();
const deviceAssetId = 'web' + '-' + asset.name + '-' + asset.lastModified; const deviceAssetId = 'web' + '-' + asset.name + '-' + asset.lastModified;
try { try {
@ -83,10 +83,10 @@ async function fileUploader(
formData.append('assetType', assetType); formData.append('assetType', assetType);
// Get Asset Created Date // Get Asset Created Date
formData.append('createdAt', createdAt); formData.append('fileCreatedAt', fileCreatedAt);
// Get Asset Modified At // Get Asset Modified At
formData.append('modifiedAt', new Date(asset.lastModified).toISOString()); formData.append('fileModifiedAt', new Date(asset.lastModified).toISOString());
// Set Asset is Favorite to false // Set Asset is Favorite to false
formData.append('isFavorite', 'false'); formData.append('isFavorite', 'false');