refactor(server): asset stats (#3253)

* refactor(server): asset stats

* chore: open api
This commit is contained in:
Jason Rasmussen 2023-07-14 09:30:17 -04:00 committed by GitHub
parent 05e1a6d949
commit f952bc0b64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 601 additions and 844 deletions

View File

@ -486,43 +486,6 @@ export interface AssetCountByTimeBucketResponseDto {
*/
'buckets': Array<AssetCountByTimeBucket>;
}
/**
*
* @export
* @interface AssetCountByUserIdResponseDto
*/
export interface AssetCountByUserIdResponseDto {
/**
*
* @type {number}
* @memberof AssetCountByUserIdResponseDto
*/
'audio': number;
/**
*
* @type {number}
* @memberof AssetCountByUserIdResponseDto
*/
'photos': number;
/**
*
* @type {number}
* @memberof AssetCountByUserIdResponseDto
*/
'videos': number;
/**
*
* @type {number}
* @memberof AssetCountByUserIdResponseDto
*/
'other': number;
/**
*
* @type {number}
* @memberof AssetCountByUserIdResponseDto
*/
'total': number;
}
/**
*
* @export
@ -724,6 +687,31 @@ export interface AssetResponseDto {
}
/**
*
* @export
* @interface AssetStatsResponseDto
*/
export interface AssetStatsResponseDto {
/**
*
* @type {number}
* @memberof AssetStatsResponseDto
*/
'images': number;
/**
*
* @type {number}
* @memberof AssetStatsResponseDto
*/
'videos': number;
/**
*
* @type {number}
* @memberof AssetStatsResponseDto
*/
'total': number;
}
/**
*
* @export
@ -4892,44 +4880,6 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getArchivedAssetCountByUserId: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/asset/stat/archive`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication cookie required
// authentication api_key required
await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration)
// authentication bearer required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
@ -5079,8 +5029,8 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getAssetCountByUserId: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/asset/count-by-user-id`;
getAssetSearchTerms: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/asset/search-terms`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
@ -5114,11 +5064,13 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
},
/**
*
* @param {boolean} [isArchived]
* @param {boolean} [isFavorite]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getAssetSearchTerms: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/asset/search-terms`;
getAssetStats: async (isArchived?: boolean, isFavorite?: boolean, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/asset/statistics`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
@ -5139,6 +5091,14 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
if (isArchived !== undefined) {
localVarQueryParameter['isArchived'] = isArchived;
}
if (isFavorite !== undefined) {
localVarQueryParameter['isFavorite'] = isFavorite;
}
setSearchParams(localVarUrlObj, localVarQueryParameter);
@ -5887,15 +5847,6 @@ export const AssetApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.getAllAssets(userId, isFavorite, isArchived, withoutThumbs, skip, ifNoneMatch, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getArchivedAssetCountByUserId(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetCountByUserIdResponseDto>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getArchivedAssetCountByUserId(options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
* Get a single asset\'s information
* @param {string} id
@ -5932,17 +5883,19 @@ export const AssetApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getAssetCountByUserId(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetCountByUserIdResponseDto>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetCountByUserId(options);
async getAssetSearchTerms(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetSearchTerms(options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {boolean} [isArchived]
* @param {boolean} [isFavorite]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getAssetSearchTerms(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetSearchTerms(options);
async getAssetStats(isArchived?: boolean, isFavorite?: boolean, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetStatsResponseDto>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetStats(isArchived, isFavorite, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
@ -6160,14 +6113,6 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
getAllAssets(requestParameters: AssetApiGetAllAssetsRequest = {}, options?: AxiosRequestConfig): AxiosPromise<Array<AssetResponseDto>> {
return localVarFp.getAllAssets(requestParameters.userId, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.withoutThumbs, requestParameters.skip, requestParameters.ifNoneMatch, options).then((request) => request(axios, basePath));
},
/**
*
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getArchivedAssetCountByUserId(options?: AxiosRequestConfig): AxiosPromise<AssetCountByUserIdResponseDto> {
return localVarFp.getArchivedAssetCountByUserId(options).then((request) => request(axios, basePath));
},
/**
* Get a single asset\'s information
* @param {AssetApiGetAssetByIdRequest} requestParameters Request parameters.
@ -6200,16 +6145,17 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getAssetCountByUserId(options?: AxiosRequestConfig): AxiosPromise<AssetCountByUserIdResponseDto> {
return localVarFp.getAssetCountByUserId(options).then((request) => request(axios, basePath));
getAssetSearchTerms(options?: AxiosRequestConfig): AxiosPromise<Array<string>> {
return localVarFp.getAssetSearchTerms(options).then((request) => request(axios, basePath));
},
/**
*
* @param {AssetApiGetAssetStatsRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getAssetSearchTerms(options?: AxiosRequestConfig): AxiosPromise<Array<string>> {
return localVarFp.getAssetSearchTerms(options).then((request) => request(axios, basePath));
getAssetStats(requestParameters: AssetApiGetAssetStatsRequest = {}, options?: AxiosRequestConfig): AxiosPromise<AssetStatsResponseDto> {
return localVarFp.getAssetStats(requestParameters.isArchived, requestParameters.isFavorite, options).then((request) => request(axios, basePath));
},
/**
*
@ -6523,6 +6469,27 @@ export interface AssetApiGetAssetCountByTimeBucketRequest {
readonly getAssetCountByTimeBucketDto: GetAssetCountByTimeBucketDto
}
/**
* Request parameters for getAssetStats operation in AssetApi.
* @export
* @interface AssetApiGetAssetStatsRequest
*/
export interface AssetApiGetAssetStatsRequest {
/**
*
* @type {boolean}
* @memberof AssetApiGetAssetStats
*/
readonly isArchived?: boolean
/**
*
* @type {boolean}
* @memberof AssetApiGetAssetStats
*/
readonly isFavorite?: boolean
}
/**
* Request parameters for getAssetThumbnail operation in AssetApi.
* @export
@ -6915,16 +6882,6 @@ export class AssetApi extends BaseAPI {
return AssetApiFp(this.configuration).getAllAssets(requestParameters.userId, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.withoutThumbs, requestParameters.skip, requestParameters.ifNoneMatch, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof AssetApi
*/
public getArchivedAssetCountByUserId(options?: AxiosRequestConfig) {
return AssetApiFp(this.configuration).getArchivedAssetCountByUserId(options).then((request) => request(this.axios, this.basePath));
}
/**
* Get a single asset\'s information
* @param {AssetApiGetAssetByIdRequest} requestParameters Request parameters.
@ -6964,18 +6921,19 @@ export class AssetApi extends BaseAPI {
* @throws {RequiredError}
* @memberof AssetApi
*/
public getAssetCountByUserId(options?: AxiosRequestConfig) {
return AssetApiFp(this.configuration).getAssetCountByUserId(options).then((request) => request(this.axios, this.basePath));
public getAssetSearchTerms(options?: AxiosRequestConfig) {
return AssetApiFp(this.configuration).getAssetSearchTerms(options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {AssetApiGetAssetStatsRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof AssetApi
*/
public getAssetSearchTerms(options?: AxiosRequestConfig) {
return AssetApiFp(this.configuration).getAssetSearchTerms(options).then((request) => request(this.axios, this.basePath));
public getAssetStats(requestParameters: AssetApiGetAssetStatsRequest = {}, options?: AxiosRequestConfig) {
return AssetApiFp(this.configuration).getAssetStats(requestParameters.isArchived, requestParameters.isFavorite, options).then((request) => request(this.axios, this.basePath));
}
/**

View File

@ -23,11 +23,11 @@ doc/AssetBulkUploadCheckResponseDto.md
doc/AssetBulkUploadCheckResult.md
doc/AssetCountByTimeBucket.md
doc/AssetCountByTimeBucketResponseDto.md
doc/AssetCountByUserIdResponseDto.md
doc/AssetFileUploadResponseDto.md
doc/AssetIdsDto.md
doc/AssetIdsResponseDto.md
doc/AssetResponseDto.md
doc/AssetStatsResponseDto.md
doc/AssetTypeEnum.md
doc/AudioCodec.md
doc/AuthDeviceResponseDto.md
@ -163,11 +163,11 @@ lib/model/asset_bulk_upload_check_response_dto.dart
lib/model/asset_bulk_upload_check_result.dart
lib/model/asset_count_by_time_bucket.dart
lib/model/asset_count_by_time_bucket_response_dto.dart
lib/model/asset_count_by_user_id_response_dto.dart
lib/model/asset_file_upload_response_dto.dart
lib/model/asset_ids_dto.dart
lib/model/asset_ids_response_dto.dart
lib/model/asset_response_dto.dart
lib/model/asset_stats_response_dto.dart
lib/model/asset_type_enum.dart
lib/model/audio_codec.dart
lib/model/auth_device_response_dto.dart
@ -272,11 +272,11 @@ test/asset_bulk_upload_check_response_dto_test.dart
test/asset_bulk_upload_check_result_test.dart
test/asset_count_by_time_bucket_response_dto_test.dart
test/asset_count_by_time_bucket_test.dart
test/asset_count_by_user_id_response_dto_test.dart
test/asset_file_upload_response_dto_test.dart
test/asset_ids_dto_test.dart
test/asset_ids_response_dto_test.dart
test/asset_response_dto_test.dart
test/asset_stats_response_dto_test.dart
test/asset_type_enum_test.dart
test/audio_codec_test.dart
test/auth_device_response_dto_test.dart

View File

@ -94,12 +94,11 @@ Class | Method | HTTP request | Description
*AssetApi* | [**downloadArchive**](doc//AssetApi.md#downloadarchive) | **POST** /asset/download |
*AssetApi* | [**downloadFile**](doc//AssetApi.md#downloadfile) | **POST** /asset/download/{id} |
*AssetApi* | [**getAllAssets**](doc//AssetApi.md#getallassets) | **GET** /asset |
*AssetApi* | [**getArchivedAssetCountByUserId**](doc//AssetApi.md#getarchivedassetcountbyuserid) | **GET** /asset/stat/archive |
*AssetApi* | [**getAssetById**](doc//AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} |
*AssetApi* | [**getAssetByTimeBucket**](doc//AssetApi.md#getassetbytimebucket) | **POST** /asset/time-bucket |
*AssetApi* | [**getAssetCountByTimeBucket**](doc//AssetApi.md#getassetcountbytimebucket) | **POST** /asset/count-by-time-bucket |
*AssetApi* | [**getAssetCountByUserId**](doc//AssetApi.md#getassetcountbyuserid) | **GET** /asset/count-by-user-id |
*AssetApi* | [**getAssetSearchTerms**](doc//AssetApi.md#getassetsearchterms) | **GET** /asset/search-terms |
*AssetApi* | [**getAssetStats**](doc//AssetApi.md#getassetstats) | **GET** /asset/statistics |
*AssetApi* | [**getAssetThumbnail**](doc//AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{id} |
*AssetApi* | [**getCuratedLocations**](doc//AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |
*AssetApi* | [**getCuratedObjects**](doc//AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |
@ -194,11 +193,11 @@ Class | Method | HTTP request | Description
- [AssetBulkUploadCheckResult](doc//AssetBulkUploadCheckResult.md)
- [AssetCountByTimeBucket](doc//AssetCountByTimeBucket.md)
- [AssetCountByTimeBucketResponseDto](doc//AssetCountByTimeBucketResponseDto.md)
- [AssetCountByUserIdResponseDto](doc//AssetCountByUserIdResponseDto.md)
- [AssetFileUploadResponseDto](doc//AssetFileUploadResponseDto.md)
- [AssetIdsDto](doc//AssetIdsDto.md)
- [AssetIdsResponseDto](doc//AssetIdsResponseDto.md)
- [AssetResponseDto](doc//AssetResponseDto.md)
- [AssetStatsResponseDto](doc//AssetStatsResponseDto.md)
- [AssetTypeEnum](doc//AssetTypeEnum.md)
- [AudioCodec](doc//AudioCodec.md)
- [AuthDeviceResponseDto](doc//AuthDeviceResponseDto.md)

View File

@ -16,12 +16,11 @@ Method | HTTP request | Description
[**downloadArchive**](AssetApi.md#downloadarchive) | **POST** /asset/download |
[**downloadFile**](AssetApi.md#downloadfile) | **POST** /asset/download/{id} |
[**getAllAssets**](AssetApi.md#getallassets) | **GET** /asset |
[**getArchivedAssetCountByUserId**](AssetApi.md#getarchivedassetcountbyuserid) | **GET** /asset/stat/archive |
[**getAssetById**](AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} |
[**getAssetByTimeBucket**](AssetApi.md#getassetbytimebucket) | **POST** /asset/time-bucket |
[**getAssetCountByTimeBucket**](AssetApi.md#getassetcountbytimebucket) | **POST** /asset/count-by-time-bucket |
[**getAssetCountByUserId**](AssetApi.md#getassetcountbyuserid) | **GET** /asset/count-by-user-id |
[**getAssetSearchTerms**](AssetApi.md#getassetsearchterms) | **GET** /asset/search-terms |
[**getAssetStats**](AssetApi.md#getassetstats) | **GET** /asset/statistics |
[**getAssetThumbnail**](AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{id} |
[**getCuratedLocations**](AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |
[**getCuratedObjects**](AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |
@ -445,57 +444,6 @@ 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)
# **getArchivedAssetCountByUserId**
> AssetCountByUserIdResponseDto getArchivedAssetCountByUserId()
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure API key authorization: cookie
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
// TODO Configure API key authorization: api_key
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKeyPrefix = 'Bearer';
// TODO Configure HTTP Bearer authorization: bearer
// Case 1. Use String Token
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
// Case 2. Use Function which generate token.
// String yourTokenGeneratorFunction() { ... }
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = AssetApi();
try {
final result = api_instance.getArchivedAssetCountByUserId();
print(result);
} catch (e) {
print('Exception when calling AssetApi->getArchivedAssetCountByUserId: $e\n');
}
```
### Parameters
This endpoint does not need any parameter.
### Return type
[**AssetCountByUserIdResponseDto**](AssetCountByUserIdResponseDto.md)
### Authorization
[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[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)
# **getAssetById**
> AssetResponseDto getAssetById(id, key)
@ -665,57 +613,6 @@ 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)
# **getAssetCountByUserId**
> AssetCountByUserIdResponseDto getAssetCountByUserId()
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure API key authorization: cookie
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
// TODO Configure API key authorization: api_key
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKeyPrefix = 'Bearer';
// TODO Configure HTTP Bearer authorization: bearer
// Case 1. Use String Token
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
// Case 2. Use Function which generate token.
// String yourTokenGeneratorFunction() { ... }
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = AssetApi();
try {
final result = api_instance.getAssetCountByUserId();
print(result);
} catch (e) {
print('Exception when calling AssetApi->getAssetCountByUserId: $e\n');
}
```
### Parameters
This endpoint does not need any parameter.
### Return type
[**AssetCountByUserIdResponseDto**](AssetCountByUserIdResponseDto.md)
### Authorization
[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[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)
# **getAssetSearchTerms**
> List<String> getAssetSearchTerms()
@ -767,6 +664,63 @@ This endpoint does not need any parameter.
[[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)
# **getAssetStats**
> AssetStatsResponseDto getAssetStats(isArchived, isFavorite)
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure API key authorization: cookie
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
// TODO Configure API key authorization: api_key
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKeyPrefix = 'Bearer';
// TODO Configure HTTP Bearer authorization: bearer
// Case 1. Use String Token
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
// Case 2. Use Function which generate token.
// String yourTokenGeneratorFunction() { ... }
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = AssetApi();
final isArchived = true; // bool |
final isFavorite = true; // bool |
try {
final result = api_instance.getAssetStats(isArchived, isFavorite);
print(result);
} catch (e) {
print('Exception when calling AssetApi->getAssetStats: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**isArchived** | **bool**| | [optional]
**isFavorite** | **bool**| | [optional]
### Return type
[**AssetStatsResponseDto**](AssetStatsResponseDto.md)
### Authorization
[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[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)
# **getAssetThumbnail**
> MultipartFile getAssetThumbnail(id, format, key)

View File

@ -1,4 +1,4 @@
# openapi.model.AssetCountByUserIdResponseDto
# openapi.model.AssetStatsResponseDto
## Load the model package
```dart
@ -8,11 +8,9 @@ import 'package:openapi/api.dart';
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**audio** | **int** | | [default to 0]
**photos** | **int** | | [default to 0]
**videos** | **int** | | [default to 0]
**other** | **int** | | [default to 0]
**total** | **int** | | [default to 0]
**images** | **int** | |
**videos** | **int** | |
**total** | **int** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -60,11 +60,11 @@ part 'model/asset_bulk_upload_check_response_dto.dart';
part 'model/asset_bulk_upload_check_result.dart';
part 'model/asset_count_by_time_bucket.dart';
part 'model/asset_count_by_time_bucket_response_dto.dart';
part 'model/asset_count_by_user_id_response_dto.dart';
part 'model/asset_file_upload_response_dto.dart';
part 'model/asset_ids_dto.dart';
part 'model/asset_ids_response_dto.dart';
part 'model/asset_response_dto.dart';
part 'model/asset_stats_response_dto.dart';
part 'model/asset_type_enum.dart';
part 'model/audio_codec.dart';
part 'model/auth_device_response_dto.dart';

View File

@ -440,47 +440,6 @@ class AssetApi {
return null;
}
/// Performs an HTTP 'GET /asset/stat/archive' operation and returns the [Response].
Future<Response> getArchivedAssetCountByUserIdWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/asset/stat/archive';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
Future<AssetCountByUserIdResponseDto?> getArchivedAssetCountByUserId() async {
final response = await getArchivedAssetCountByUserIdWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AssetCountByUserIdResponseDto',) as AssetCountByUserIdResponseDto;
}
return null;
}
/// Get a single asset's information
///
/// Note: This method returns the HTTP [Response].
@ -639,47 +598,6 @@ class AssetApi {
return null;
}
/// Performs an HTTP 'GET /asset/count-by-user-id' operation and returns the [Response].
Future<Response> getAssetCountByUserIdWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/asset/count-by-user-id';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
Future<AssetCountByUserIdResponseDto?> getAssetCountByUserId() async {
final response = await getAssetCountByUserIdWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AssetCountByUserIdResponseDto',) as AssetCountByUserIdResponseDto;
}
return null;
}
/// Performs an HTTP 'GET /asset/search-terms' operation and returns the [Response].
Future<Response> getAssetSearchTermsWithHttpInfo() async {
// ignore: prefer_const_declarations
@ -724,6 +642,64 @@ class AssetApi {
return null;
}
/// Performs an HTTP 'GET /asset/statistics' operation and returns the [Response].
/// Parameters:
///
/// * [bool] isArchived:
///
/// * [bool] isFavorite:
Future<Response> getAssetStatsWithHttpInfo({ bool? isArchived, bool? isFavorite, }) async {
// ignore: prefer_const_declarations
final path = r'/asset/statistics';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (isArchived != null) {
queryParams.addAll(_queryParams('', 'isArchived', isArchived));
}
if (isFavorite != null) {
queryParams.addAll(_queryParams('', 'isFavorite', isFavorite));
}
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [bool] isArchived:
///
/// * [bool] isFavorite:
Future<AssetStatsResponseDto?> getAssetStats({ bool? isArchived, bool? isFavorite, }) async {
final response = await getAssetStatsWithHttpInfo( isArchived: isArchived, isFavorite: isFavorite, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AssetStatsResponseDto',) as AssetStatsResponseDto;
}
return null;
}
/// Performs an HTTP 'GET /asset/thumbnail/{id}' operation and returns the [Response].
/// Parameters:
///

View File

@ -215,8 +215,6 @@ class ApiClient {
return AssetCountByTimeBucket.fromJson(value);
case 'AssetCountByTimeBucketResponseDto':
return AssetCountByTimeBucketResponseDto.fromJson(value);
case 'AssetCountByUserIdResponseDto':
return AssetCountByUserIdResponseDto.fromJson(value);
case 'AssetFileUploadResponseDto':
return AssetFileUploadResponseDto.fromJson(value);
case 'AssetIdsDto':
@ -225,6 +223,8 @@ class ApiClient {
return AssetIdsResponseDto.fromJson(value);
case 'AssetResponseDto':
return AssetResponseDto.fromJson(value);
case 'AssetStatsResponseDto':
return AssetStatsResponseDto.fromJson(value);
case 'AssetTypeEnum':
return AssetTypeEnumTypeTransformer().decode(value);
case 'AudioCodec':

View File

@ -1,130 +0,0 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class AssetCountByUserIdResponseDto {
/// Returns a new [AssetCountByUserIdResponseDto] instance.
AssetCountByUserIdResponseDto({
this.audio = 0,
this.photos = 0,
this.videos = 0,
this.other = 0,
this.total = 0,
});
int audio;
int photos;
int videos;
int other;
int total;
@override
bool operator ==(Object other) => identical(this, other) || other is AssetCountByUserIdResponseDto &&
other.audio == audio &&
other.photos == photos &&
other.videos == videos &&
other.other == other &&
other.total == total;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(audio.hashCode) +
(photos.hashCode) +
(videos.hashCode) +
(other.hashCode) +
(total.hashCode);
@override
String toString() => 'AssetCountByUserIdResponseDto[audio=$audio, photos=$photos, videos=$videos, other=$other, total=$total]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'audio'] = this.audio;
json[r'photos'] = this.photos;
json[r'videos'] = this.videos;
json[r'other'] = this.other;
json[r'total'] = this.total;
return json;
}
/// Returns a new [AssetCountByUserIdResponseDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static AssetCountByUserIdResponseDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return AssetCountByUserIdResponseDto(
audio: mapValueOfType<int>(json, r'audio')!,
photos: mapValueOfType<int>(json, r'photos')!,
videos: mapValueOfType<int>(json, r'videos')!,
other: mapValueOfType<int>(json, r'other')!,
total: mapValueOfType<int>(json, r'total')!,
);
}
return null;
}
static List<AssetCountByUserIdResponseDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetCountByUserIdResponseDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = AssetCountByUserIdResponseDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, AssetCountByUserIdResponseDto> mapFromJson(dynamic json) {
final map = <String, AssetCountByUserIdResponseDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = AssetCountByUserIdResponseDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of AssetCountByUserIdResponseDto-objects as value to a dart map
static Map<String, List<AssetCountByUserIdResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<AssetCountByUserIdResponseDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = AssetCountByUserIdResponseDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'audio',
'photos',
'videos',
'other',
'total',
};
}

View File

@ -0,0 +1,114 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class AssetStatsResponseDto {
/// Returns a new [AssetStatsResponseDto] instance.
AssetStatsResponseDto({
required this.images,
required this.videos,
required this.total,
});
int images;
int videos;
int total;
@override
bool operator ==(Object other) => identical(this, other) || other is AssetStatsResponseDto &&
other.images == images &&
other.videos == videos &&
other.total == total;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(images.hashCode) +
(videos.hashCode) +
(total.hashCode);
@override
String toString() => 'AssetStatsResponseDto[images=$images, videos=$videos, total=$total]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'images'] = this.images;
json[r'videos'] = this.videos;
json[r'total'] = this.total;
return json;
}
/// Returns a new [AssetStatsResponseDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static AssetStatsResponseDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return AssetStatsResponseDto(
images: mapValueOfType<int>(json, r'images')!,
videos: mapValueOfType<int>(json, r'videos')!,
total: mapValueOfType<int>(json, r'total')!,
);
}
return null;
}
static List<AssetStatsResponseDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetStatsResponseDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = AssetStatsResponseDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, AssetStatsResponseDto> mapFromJson(dynamic json) {
final map = <String, AssetStatsResponseDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = AssetStatsResponseDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of AssetStatsResponseDto-objects as value to a dart map
static Map<String, List<AssetStatsResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<AssetStatsResponseDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = AssetStatsResponseDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'images',
'videos',
'total',
};
}

View File

@ -60,11 +60,6 @@ void main() {
// TODO
});
//Future<AssetCountByUserIdResponseDto> getArchivedAssetCountByUserId() async
test('test getArchivedAssetCountByUserId', () async {
// TODO
});
// Get a single asset's information
//
//Future<AssetResponseDto> getAssetById(String id, { String key }) async
@ -82,13 +77,13 @@ void main() {
// TODO
});
//Future<AssetCountByUserIdResponseDto> getAssetCountByUserId() async
test('test getAssetCountByUserId', () async {
//Future<List<String>> getAssetSearchTerms() async
test('test getAssetSearchTerms', () async {
// TODO
});
//Future<List<String>> getAssetSearchTerms() async
test('test getAssetSearchTerms', () async {
//Future<AssetStatsResponseDto> getAssetStats({ bool isArchived, bool isFavorite }) async
test('test getAssetStats', () async {
// TODO
});

View File

@ -11,32 +11,22 @@
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for AssetCountByUserIdResponseDto
// tests for AssetStatsResponseDto
void main() {
// final instance = AssetCountByUserIdResponseDto();
// final instance = AssetStatsResponseDto();
group('test AssetCountByUserIdResponseDto', () {
// int audio (default value: 0)
test('to test the property `audio`', () async {
group('test AssetStatsResponseDto', () {
// int images
test('to test the property `images`', () async {
// TODO
});
// int photos (default value: 0)
test('to test the property `photos`', () async {
// TODO
});
// int videos (default value: 0)
// int videos
test('to test the property `videos`', () async {
// TODO
});
// int other (default value: 0)
test('to test the property `other`', () async {
// TODO
});
// int total (default value: 0)
// int total
test('to test the property `total`', () async {
// TODO
});

View File

@ -984,38 +984,6 @@
]
}
},
"/asset/count-by-user-id": {
"get": {
"operationId": "getAssetCountByUserId",
"parameters": [],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AssetCountByUserIdResponseDto"
}
}
}
}
},
"tags": [
"Asset"
],
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
]
}
},
"/asset/curated-locations": {
"get": {
"operationId": "getCuratedLocations",
@ -1608,17 +1576,34 @@
]
}
},
"/asset/stat/archive": {
"/asset/statistics": {
"get": {
"operationId": "getArchivedAssetCountByUserId",
"parameters": [],
"operationId": "getAssetStats",
"parameters": [
{
"name": "isArchived",
"required": false,
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "isFavorite",
"required": false,
"in": "query",
"schema": {
"type": "boolean"
}
}
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AssetCountByUserIdResponseDto"
"$ref": "#/components/schemas/AssetStatsResponseDto"
}
}
}
@ -4786,38 +4771,6 @@
"buckets"
]
},
"AssetCountByUserIdResponseDto": {
"type": "object",
"properties": {
"audio": {
"type": "integer",
"default": 0
},
"photos": {
"type": "integer",
"default": 0
},
"videos": {
"type": "integer",
"default": 0
},
"other": {
"type": "integer",
"default": 0
},
"total": {
"type": "integer",
"default": 0
}
},
"required": [
"audio",
"photos",
"videos",
"other",
"total"
]
},
"AssetFileUploadResponseDto": {
"type": "object",
"properties": {
@ -4970,6 +4923,25 @@
"checksum"
]
},
"AssetStatsResponseDto": {
"type": "object",
"properties": {
"images": {
"type": "integer"
},
"videos": {
"type": "integer"
},
"total": {
"type": "integer"
}
},
"required": [
"images",
"videos",
"total"
]
},
"AssetTypeEnum": {
"type": "string",
"enum": [

View File

@ -1,6 +1,13 @@
import { AssetEntity, AssetType } from '@app/infra/entities';
import { Paginated, PaginationOptions } from '../domain.util';
export type AssetStats = Record<AssetType, number>;
export interface AssetStatsOptions {
isFavorite?: boolean;
isArchived?: boolean;
}
export interface AssetSearchOptions {
isVisible?: boolean;
type?: AssetType;
@ -55,4 +62,5 @@ export interface IAssetRepository {
save(asset: Partial<AssetEntity>): Promise<AssetEntity>;
findLivePhotoMatch(options: LivePhotoSearchOptions): Promise<AssetEntity | null>;
getMapMarkers(ownerId: string, options?: MapMarkerSearchOptions): Promise<MapMarker[]>;
getStatistics(ownerId: string, options: AssetStatsOptions): Promise<AssetStats>;
}

View File

@ -1,3 +1,4 @@
import { AssetType } from '@app/infra/entities';
import { BadRequestException } from '@nestjs/common';
import {
assetEntityStub,
@ -10,9 +11,9 @@ import {
import { when } from 'jest-when';
import { Readable } from 'stream';
import { IStorageRepository } from '../storage';
import { IAssetRepository } from './asset.repository';
import { AssetStats, IAssetRepository } from './asset.repository';
import { AssetService } from './asset.service';
import { DownloadResponseDto } from './index';
import { AssetStatsResponseDto, DownloadResponseDto } from './dto';
import { mapAsset } from './response-dto';
const downloadResponse: DownloadResponseDto = {
@ -25,6 +26,19 @@ const downloadResponse: DownloadResponseDto = {
],
};
const stats: AssetStats = {
[AssetType.IMAGE]: 10,
[AssetType.VIDEO]: 23,
[AssetType.AUDIO]: 0,
[AssetType.OTHER]: 0,
};
const statResponse: AssetStatsResponseDto = {
images: 10,
videos: 23,
total: 33,
};
describe(AssetService.name, () => {
let sut: AssetService;
let accessMock: IAccessRepositoryMock;
@ -287,4 +301,30 @@ describe(AssetService.name, () => {
});
});
});
describe('getStatistics', () => {
it('should get the statistics for a user, excluding archived assets', async () => {
assetMock.getStatistics.mockResolvedValue(stats);
await expect(sut.getStatistics(authStub.admin, { isArchived: false })).resolves.toEqual(statResponse);
expect(assetMock.getStatistics).toHaveBeenCalledWith(authStub.admin.id, { isArchived: false });
});
it('should get the statistics for a user for archived assets', async () => {
assetMock.getStatistics.mockResolvedValue(stats);
await expect(sut.getStatistics(authStub.admin, { isArchived: true })).resolves.toEqual(statResponse);
expect(assetMock.getStatistics).toHaveBeenCalledWith(authStub.admin.id, { isArchived: true });
});
it('should get the statistics for a user for favorite assets', async () => {
assetMock.getStatistics.mockResolvedValue(stats);
await expect(sut.getStatistics(authStub.admin, { isFavorite: true })).resolves.toEqual(statResponse);
expect(assetMock.getStatistics).toHaveBeenCalledWith(authStub.admin.id, { isFavorite: true });
});
it('should get the statistics for a user for all assets', async () => {
assetMock.getStatistics.mockResolvedValue(stats);
await expect(sut.getStatistics(authStub.admin, {})).resolves.toEqual(statResponse);
expect(assetMock.getStatistics).toHaveBeenCalledWith(authStub.admin.id, {});
});
});
});

View File

@ -9,6 +9,7 @@ import { HumanReadableSize, usePagination } from '../domain.util';
import { ImmichReadStream, IStorageRepository } from '../storage';
import { IAssetRepository } from './asset.repository';
import { AssetIdsDto, DownloadArchiveInfo, DownloadDto, DownloadResponseDto, MemoryLaneDto } from './dto';
import { AssetStatsDto, mapStats } from './dto/asset-statistics.dto';
import { MapMarkerDto } from './dto/map-marker.dto';
import { mapAsset, MapMarkerResponseDto } from './response-dto';
import { MemoryLaneResponseDto } from './response-dto/memory-lane-response.dto';
@ -155,4 +156,9 @@ export class AssetService {
throw new BadRequestException('assetIds, albumId, or userId is required');
}
async getStatistics(authUser: AuthUserDto, dto: AssetStatsDto) {
const stats = await this.assetRepository.getStatistics(authUser.id, dto);
return mapStats(stats);
}
}

View File

@ -0,0 +1,37 @@
import { AssetType } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import { IsBoolean, IsOptional } from 'class-validator';
import { toBoolean } from '../../domain.util';
import { AssetStats } from '../asset.repository';
export class AssetStatsDto {
@IsBoolean()
@Transform(toBoolean)
@IsOptional()
isArchived?: boolean;
@IsBoolean()
@Transform(toBoolean)
@IsOptional()
isFavorite?: boolean;
}
export class AssetStatsResponseDto {
@ApiProperty({ type: 'integer' })
images!: number;
@ApiProperty({ type: 'integer' })
videos!: number;
@ApiProperty({ type: 'integer' })
total!: number;
}
export const mapStats = (stats: AssetStats): AssetStatsResponseDto => {
return {
images: stats[AssetType.IMAGE],
videos: stats[AssetType.VIDEO],
total: Object.values(stats).reduce((total, value) => total + value, 0),
};
};

View File

@ -1,4 +1,5 @@
export * from './asset-ids.dto';
export * from './asset-statistics.dto';
export * from './download.dto';
export * from './map-marker.dto';
export * from './memory-lane.dto';

View File

@ -1,4 +1,4 @@
import { AssetEntity, AssetType, ExifEntity } from '@app/infra/entities';
import { AssetEntity, ExifEntity } from '@app/infra/entities';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { IsNull, Not } from 'typeorm';
@ -11,7 +11,6 @@ import { GetAssetCountByTimeBucketDto, TimeGroupEnum } from './dto/get-asset-cou
import { SearchPropertiesDto } from './dto/search-properties.dto';
import { UpdateAssetDto } from './dto/update-asset.dto';
import { AssetCountByTimeBucket } from './response-dto/asset-count-by-time-group-response.dto';
import { AssetCountByUserIdResponseDto } from './response-dto/asset-count-by-user-id-response.dto';
import { CuratedLocationsResponseDto } from './response-dto/curated-locations-response.dto';
import { CuratedObjectsResponseDto } from './response-dto/curated-objects-response.dto';
@ -38,8 +37,6 @@ export interface IAssetRepository {
getDetectedObjectsByUserId(userId: string): Promise<CuratedObjectsResponseDto[]>;
getSearchPropertiesByUserId(userId: string): Promise<SearchPropertiesDto[]>;
getAssetCountByTimeBucket(userId: string, dto: GetAssetCountByTimeBucketDto): Promise<AssetCountByTimeBucket[]>;
getAssetCountByUserId(userId: string): Promise<AssetCountByUserIdResponseDto>;
getArchivedAssetCountByUserId(userId: string): Promise<AssetCountByUserIdResponseDto>;
getAssetByTimeBucket(userId: string, getAssetByTimeBucketDto: GetAssetByTimeBucketDto): Promise<AssetEntity[]>;
getAssetsByChecksums(userId: string, checksums: Buffer[]): Promise<AssetCheck[]>;
getExistingAssets(userId: string, checkDuplicateAssetDto: CheckExistingAssetsDto): Promise<string[]>;
@ -55,35 +52,6 @@ export class AssetRepository implements IAssetRepository {
@InjectRepository(ExifEntity) private exifRepository: Repository<ExifEntity>,
) {}
async getAssetCountByUserId(ownerId: string): Promise<AssetCountByUserIdResponseDto> {
// Get asset count by AssetType
const items = await this.assetRepository
.createQueryBuilder('asset')
.select(`COUNT(asset.id)`, 'count')
.addSelect(`asset.type`, 'type')
.where('"ownerId" = :ownerId', { ownerId: ownerId })
.andWhere('asset.isVisible = true')
.groupBy('asset.type')
.getRawMany();
return this.getAssetCount(items);
}
async getArchivedAssetCountByUserId(ownerId: string): Promise<AssetCountByUserIdResponseDto> {
// Get archived asset count by AssetType
const items = await this.assetRepository
.createQueryBuilder('asset')
.select(`COUNT(asset.id)`, 'count')
.addSelect(`asset.type`, 'type')
.where('"ownerId" = :ownerId', { ownerId: ownerId })
.andWhere('asset.isVisible = true')
.andWhere('asset.isArchived = true')
.groupBy('asset.type')
.getRawMany();
return this.getAssetCount(items);
}
async getAssetByTimeBucket(userId: string, dto: GetAssetByTimeBucketDto): Promise<AssetEntity[]> {
// Get asset entity from a list of time buckets
let builder = this.assetRepository
@ -337,29 +305,6 @@ export class AssetRepository implements IAssetRepository {
return assets.map((asset) => asset.deviceAssetId);
}
private getAssetCount(items: any): AssetCountByUserIdResponseDto {
const assetCountByUserId = new AssetCountByUserIdResponseDto();
// asset type to dto property mapping
const map: Record<AssetType, keyof AssetCountByUserIdResponseDto> = {
[AssetType.AUDIO]: 'audio',
[AssetType.IMAGE]: 'photos',
[AssetType.VIDEO]: 'videos',
[AssetType.OTHER]: 'other',
};
for (const item of items) {
const count = Number(item.count) || 0;
const assetType = item.type as AssetType;
const type = map[assetType];
assetCountByUserId[type] = count;
assetCountByUserId.total += count;
}
return assetCountByUserId;
}
getByOriginalPath(originalPath: string): Promise<AssetOwnerCheck | null> {
return this.assetRepository.findOne({
select: {

View File

@ -38,7 +38,6 @@ import { ServeFileDto } from './dto/serve-file.dto';
import { UpdateAssetDto } from './dto/update-asset.dto';
import { AssetBulkUploadCheckResponseDto } from './response-dto/asset-check-response.dto';
import { AssetCountByTimeBucketResponseDto } from './response-dto/asset-count-by-time-group-response.dto';
import { AssetCountByUserIdResponseDto } from './response-dto/asset-count-by-user-id-response.dto';
import { AssetFileUploadResponseDto } from './response-dto/asset-file-upload-response.dto';
import { CheckDuplicateAssetResponseDto } from './response-dto/check-duplicate-asset-response.dto';
import { CheckExistingAssetsResponseDto } from './response-dto/check-existing-assets-response.dto';
@ -173,15 +172,6 @@ export class AssetController {
return this.assetService.getAssetCountByTimeBucket(authUser, dto);
}
@Get('/count-by-user-id')
getAssetCountByUserId(@AuthUser() authUser: AuthUserDto): Promise<AssetCountByUserIdResponseDto> {
return this.assetService.getAssetCountByUserId(authUser);
}
@Get('/stat/archive')
getArchivedAssetCountByUserId(@AuthUser() authUser: AuthUserDto): Promise<AssetCountByUserIdResponseDto> {
return this.assetService.getArchivedAssetCountByUserId(authUser);
}
/**
* Get all AssetEntity belong to the user
*/

View File

@ -26,7 +26,6 @@ import { CreateAssetDto } from './dto/create-asset.dto';
import { TimeGroupEnum } from './dto/get-asset-count-by-time-bucket.dto';
import { AssetRejectReason, AssetUploadAction } from './response-dto/asset-check-response.dto';
import { AssetCountByTimeBucket } from './response-dto/asset-count-by-time-group-response.dto';
import { AssetCountByUserIdResponseDto } from './response-dto/asset-count-by-user-id-response.dto';
const _getCreateAssetDto = (): CreateAssetDto => {
const createAssetDto = new CreateAssetDto();
@ -103,24 +102,6 @@ const _getAssetCountByTimeBucket = (): AssetCountByTimeBucket[] => {
return [result1, result2];
};
const _getAssetCountByUserId = (): AssetCountByUserIdResponseDto => {
const result = new AssetCountByUserIdResponseDto();
result.videos = 2;
result.photos = 2;
return result;
};
const _getArchivedAssetsCountByUserId = (): AssetCountByUserIdResponseDto => {
const result = new AssetCountByUserIdResponseDto();
result.videos = 1;
result.photos = 2;
return result;
};
const uploadFile = {
nullAuth: {
authUser: null,
@ -197,8 +178,6 @@ describe('AssetService', () => {
getSearchPropertiesByUserId: jest.fn(),
getAssetByTimeBucket: jest.fn(),
getAssetsByChecksums: jest.fn(),
getAssetCountByUserId: jest.fn(),
getArchivedAssetCountByUserId: jest.fn(),
getExistingAssets: jest.fn(),
getByOriginalPath: jest.fn(),
};
@ -467,20 +446,6 @@ describe('AssetService', () => {
expect(result.buckets.length).toEqual(2);
});
it('get asset count by user id', async () => {
const assetCount = _getAssetCountByUserId();
assetRepositoryMock.getAssetCountByUserId.mockResolvedValue(assetCount);
await expect(sut.getAssetCountByUserId(authStub.user1)).resolves.toEqual(assetCount);
});
it('get archived asset count by user id', async () => {
const assetCount = _getArchivedAssetsCountByUserId();
assetRepositoryMock.getArchivedAssetCountByUserId.mockResolvedValue(assetCount);
await expect(sut.getArchivedAssetCountByUserId(authStub.user1)).resolves.toEqual(assetCount);
});
describe('deleteAll', () => {
it('should return failed status when an asset is missing', async () => {
assetRepositoryMock.get.mockResolvedValue(null);

View File

@ -58,7 +58,6 @@ import {
AssetCountByTimeBucketResponseDto,
mapAssetCountByTimeBucket,
} from './response-dto/asset-count-by-time-group-response.dto';
import { AssetCountByUserIdResponseDto } from './response-dto/asset-count-by-user-id-response.dto';
import { AssetFileUploadResponseDto } from './response-dto/asset-file-upload-response.dto';
import { CheckDuplicateAssetResponseDto } from './response-dto/check-duplicate-asset-response.dto';
import { CheckExistingAssetsResponseDto } from './response-dto/check-existing-assets-response.dto';
@ -536,14 +535,6 @@ export class AssetService {
return mapAssetCountByTimeBucket(result);
}
getAssetCountByUserId(authUser: AuthUserDto): Promise<AssetCountByUserIdResponseDto> {
return this._assetRepository.getAssetCountByUserId(authUser.id);
}
getArchivedAssetCountByUserId(authUser: AuthUserDto): Promise<AssetCountByUserIdResponseDto> {
return this._assetRepository.getArchivedAssetCountByUserId(authUser.id);
}
getExifPermission(authUser: AuthUserDto) {
return !authUser.isPublicUser || authUser.isShowExif;
}

View File

@ -1,18 +0,0 @@
import { ApiProperty } from '@nestjs/swagger';
export class AssetCountByUserIdResponseDto {
@ApiProperty({ type: 'integer' })
audio = 0;
@ApiProperty({ type: 'integer' })
photos = 0;
@ApiProperty({ type: 'integer' })
videos = 0;
@ApiProperty({ type: 'integer' })
other = 0;
@ApiProperty({ type: 'integer' })
total = 0;
}

View File

@ -1,6 +1,8 @@
import {
AssetIdsDto,
AssetService,
AssetStatsDto,
AssetStatsResponseDto,
AuthUserDto,
DownloadDto,
DownloadResponseDto,
@ -53,4 +55,9 @@ export class AssetController {
downloadFile(@AuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto) {
return this.service.downloadFile(authUser, id).then(asStreamableFile);
}
@Get('statistics')
getAssetStats(@AuthUser() authUser: AuthUserDto, @Query() dto: AssetStatsDto): Promise<AssetStatsResponseDto> {
return this.service.getStatistics(authUser, dto);
}
}

View File

@ -1,5 +1,7 @@
import {
AssetSearchOptions,
AssetStats,
AssetStatsOptions,
IAssetRepository,
LivePhotoSearchOptions,
MapMarker,
@ -321,4 +323,38 @@ export class AssetRepository implements IAssetRepository {
lon: asset.exifInfo!.longitude!,
}));
}
async getStatistics(ownerId: string, options: AssetStatsOptions): Promise<AssetStats> {
let builder = await this.repository
.createQueryBuilder('asset')
.select(`COUNT(asset.id)`, 'count')
.addSelect(`asset.type`, 'type')
.where('"ownerId" = :ownerId', { ownerId })
.andWhere('asset.isVisible = true')
.groupBy('asset.type');
const { isArchived, isFavorite } = options;
if (isArchived !== undefined) {
builder = builder.andWhere(`asset.isArchived = :isArchived`, { isArchived });
}
if (isFavorite !== undefined) {
builder = builder.andWhere(`asset.isFavorite = :isFavorite`, { isFavorite });
}
const items = await builder.getRawMany();
const result: AssetStats = {
[AssetType.AUDIO]: 0,
[AssetType.IMAGE]: 0,
[AssetType.VIDEO]: 0,
[AssetType.OTHER]: 0,
};
for (const item of items) {
result[item.type as AssetType] = Number(item.count) || 0;
}
return result;
}
}

View File

@ -18,5 +18,6 @@ export const newAssetRepositoryMock = (): jest.Mocked<IAssetRepository> => {
save: jest.fn(),
findLivePhotoMatch: jest.fn(),
getMapMarkers: jest.fn(),
getStatistics: jest.fn(),
};
};

View File

@ -486,43 +486,6 @@ export interface AssetCountByTimeBucketResponseDto {
*/
'buckets': Array<AssetCountByTimeBucket>;
}
/**
*
* @export
* @interface AssetCountByUserIdResponseDto
*/
export interface AssetCountByUserIdResponseDto {
/**
*
* @type {number}
* @memberof AssetCountByUserIdResponseDto
*/
'audio': number;
/**
*
* @type {number}
* @memberof AssetCountByUserIdResponseDto
*/
'photos': number;
/**
*
* @type {number}
* @memberof AssetCountByUserIdResponseDto
*/
'videos': number;
/**
*
* @type {number}
* @memberof AssetCountByUserIdResponseDto
*/
'other': number;
/**
*
* @type {number}
* @memberof AssetCountByUserIdResponseDto
*/
'total': number;
}
/**
*
* @export
@ -724,6 +687,31 @@ export interface AssetResponseDto {
}
/**
*
* @export
* @interface AssetStatsResponseDto
*/
export interface AssetStatsResponseDto {
/**
*
* @type {number}
* @memberof AssetStatsResponseDto
*/
'images': number;
/**
*
* @type {number}
* @memberof AssetStatsResponseDto
*/
'videos': number;
/**
*
* @type {number}
* @memberof AssetStatsResponseDto
*/
'total': number;
}
/**
*
* @export
@ -4901,44 +4889,6 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getArchivedAssetCountByUserId: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/asset/stat/archive`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication cookie required
// authentication api_key required
await setApiKeyToObject(localVarHeaderParameter, "x-api-key", configuration)
// authentication bearer required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
@ -5088,8 +5038,8 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getAssetCountByUserId: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/asset/count-by-user-id`;
getAssetSearchTerms: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/asset/search-terms`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
@ -5123,11 +5073,13 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
},
/**
*
* @param {boolean} [isArchived]
* @param {boolean} [isFavorite]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getAssetSearchTerms: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/asset/search-terms`;
getAssetStats: async (isArchived?: boolean, isFavorite?: boolean, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/asset/statistics`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
@ -5148,6 +5100,14 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
if (isArchived !== undefined) {
localVarQueryParameter['isArchived'] = isArchived;
}
if (isFavorite !== undefined) {
localVarQueryParameter['isFavorite'] = isFavorite;
}
setSearchParams(localVarUrlObj, localVarQueryParameter);
@ -5896,15 +5856,6 @@ export const AssetApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.getAllAssets(userId, isFavorite, isArchived, withoutThumbs, skip, ifNoneMatch, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getArchivedAssetCountByUserId(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetCountByUserIdResponseDto>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getArchivedAssetCountByUserId(options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
* Get a single asset\'s information
* @param {string} id
@ -5941,17 +5892,19 @@ export const AssetApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getAssetCountByUserId(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetCountByUserIdResponseDto>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetCountByUserId(options);
async getAssetSearchTerms(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetSearchTerms(options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {boolean} [isArchived]
* @param {boolean} [isFavorite]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async getAssetSearchTerms(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<string>>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetSearchTerms(options);
async getAssetStats(isArchived?: boolean, isFavorite?: boolean, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetStatsResponseDto>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getAssetStats(isArchived, isFavorite, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
@ -6177,14 +6130,6 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
getAllAssets(userId?: string, isFavorite?: boolean, isArchived?: boolean, withoutThumbs?: boolean, skip?: number, ifNoneMatch?: string, options?: any): AxiosPromise<Array<AssetResponseDto>> {
return localVarFp.getAllAssets(userId, isFavorite, isArchived, withoutThumbs, skip, ifNoneMatch, options).then((request) => request(axios, basePath));
},
/**
*
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getArchivedAssetCountByUserId(options?: any): AxiosPromise<AssetCountByUserIdResponseDto> {
return localVarFp.getArchivedAssetCountByUserId(options).then((request) => request(axios, basePath));
},
/**
* Get a single asset\'s information
* @param {string} id
@ -6218,16 +6163,18 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getAssetCountByUserId(options?: any): AxiosPromise<AssetCountByUserIdResponseDto> {
return localVarFp.getAssetCountByUserId(options).then((request) => request(axios, basePath));
getAssetSearchTerms(options?: any): AxiosPromise<Array<string>> {
return localVarFp.getAssetSearchTerms(options).then((request) => request(axios, basePath));
},
/**
*
* @param {boolean} [isArchived]
* @param {boolean} [isFavorite]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
getAssetSearchTerms(options?: any): AxiosPromise<Array<string>> {
return localVarFp.getAssetSearchTerms(options).then((request) => request(axios, basePath));
getAssetStats(isArchived?: boolean, isFavorite?: boolean, options?: any): AxiosPromise<AssetStatsResponseDto> {
return localVarFp.getAssetStats(isArchived, isFavorite, options).then((request) => request(axios, basePath));
},
/**
*
@ -6565,6 +6512,27 @@ export interface AssetApiGetAssetCountByTimeBucketRequest {
readonly getAssetCountByTimeBucketDto: GetAssetCountByTimeBucketDto
}
/**
* Request parameters for getAssetStats operation in AssetApi.
* @export
* @interface AssetApiGetAssetStatsRequest
*/
export interface AssetApiGetAssetStatsRequest {
/**
*
* @type {boolean}
* @memberof AssetApiGetAssetStats
*/
readonly isArchived?: boolean
/**
*
* @type {boolean}
* @memberof AssetApiGetAssetStats
*/
readonly isFavorite?: boolean
}
/**
* Request parameters for getAssetThumbnail operation in AssetApi.
* @export
@ -6957,16 +6925,6 @@ export class AssetApi extends BaseAPI {
return AssetApiFp(this.configuration).getAllAssets(requestParameters.userId, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.withoutThumbs, requestParameters.skip, requestParameters.ifNoneMatch, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof AssetApi
*/
public getArchivedAssetCountByUserId(options?: AxiosRequestConfig) {
return AssetApiFp(this.configuration).getArchivedAssetCountByUserId(options).then((request) => request(this.axios, this.basePath));
}
/**
* Get a single asset\'s information
* @param {AssetApiGetAssetByIdRequest} requestParameters Request parameters.
@ -7006,18 +6964,19 @@ export class AssetApi extends BaseAPI {
* @throws {RequiredError}
* @memberof AssetApi
*/
public getAssetCountByUserId(options?: AxiosRequestConfig) {
return AssetApiFp(this.configuration).getAssetCountByUserId(options).then((request) => request(this.axios, this.basePath));
public getAssetSearchTerms(options?: AxiosRequestConfig) {
return AssetApiFp(this.configuration).getAssetSearchTerms(options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {AssetApiGetAssetStatsRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof AssetApi
*/
public getAssetSearchTerms(options?: AxiosRequestConfig) {
return AssetApiFp(this.configuration).getAssetSearchTerms(options).then((request) => request(this.axios, this.basePath));
public getAssetStats(requestParameters: AssetApiGetAssetStatsRequest = {}, options?: AxiosRequestConfig) {
return AssetApiFp(this.configuration).getAssetStats(requestParameters.isArchived, requestParameters.isFavorite, options).then((request) => request(this.axios, this.basePath));
}
/**

View File

@ -1,6 +1,6 @@
<script lang="ts">
import { page } from '$app/stores';
import { api } from '@api';
import { AssetApiGetAssetStatsRequest, api } from '@api';
import AccountMultipleOutline from 'svelte-material-icons/AccountMultipleOutline.svelte';
import AccountMultiple from 'svelte-material-icons/AccountMultiple.svelte';
import ImageAlbum from 'svelte-material-icons/ImageAlbum.svelte';
@ -18,31 +18,9 @@
import { locale } from '$lib/stores/preferences.store';
import SideBarSection from './side-bar-section.svelte';
const getAssetCount = async () => {
const { data: allAssetCount } = await api.assetApi.getAssetCountByUserId();
const { data: archivedCount } = await api.assetApi.getArchivedAssetCountByUserId();
return {
videos: allAssetCount.videos - archivedCount.videos,
photos: allAssetCount.photos - archivedCount.photos,
};
};
const getFavoriteCount = async () => {
try {
const { data: assets } = await api.assetApi.getAllAssets({
isFavorite: true,
withoutThumbs: true,
});
return {
favorites: assets.length,
};
} catch {
return {
favorites: 0,
};
}
const getStats = async (dto: AssetApiGetAssetStatsRequest) => {
const { data: stats } = await api.assetApi.getAssetStats(dto);
return stats;
};
const getAlbumCount = async () => {
@ -54,22 +32,6 @@
}
};
const getArchivedAssetsCount = async () => {
try {
const { data: assetCount } = await api.assetApi.getArchivedAssetCountByUserId();
return {
videos: assetCount.videos,
photos: assetCount.photos,
};
} catch {
return {
videos: 0,
photos: 0,
};
}
};
const isFavoritesSelected = $page.route.id === '/(user)/favorites';
const isPhotosSelected = $page.route.id === '/(user)/photos';
const isSharingSelected = $page.route.id === '/(user)/sharing';
@ -83,12 +45,12 @@
isSelected={isPhotosSelected}
>
<svelte:fragment slot="moreInformation">
{#await getAssetCount()}
{#await getStats({ isArchived: false })}
<LoadingSpinner />
{:then data}
<div>
<p>{data.videos.toLocaleString($locale)} Videos</p>
<p>{data.photos.toLocaleString($locale)} Photos</p>
<p>{data.images.toLocaleString($locale)} Photos</p>
</div>
{/await}
</svelte:fragment>
@ -129,11 +91,12 @@
isSelected={isFavoritesSelected}
>
<svelte:fragment slot="moreInformation">
{#await getFavoriteCount()}
{#await getStats({ isFavorite: true })}
<LoadingSpinner />
{:then data}
<div>
<p>{data.favorites} Favorites</p>
<p>{data.videos.toLocaleString($locale)} Videos</p>
<p>{data.images.toLocaleString($locale)} Photos</p>
</div>
{/await}
</svelte:fragment>
@ -155,12 +118,12 @@
<a data-sveltekit-preload-data="hover" href={AppRoute.ARCHIVE} draggable="false">
<SideBarButton title="Archive" logo={ArchiveArrowDownOutline} isSelected={$page.route.id === '/(user)/archive'}>
<svelte:fragment slot="moreInformation">
{#await getArchivedAssetsCount()}
{#await getStats({ isArchived: true })}
<LoadingSpinner />
{:then data}
<div>
<p>{data.videos.toLocaleString($locale)} Videos</p>
<p>{data.photos.toLocaleString($locale)} Photos</p>
<p>{data.images.toLocaleString($locale)} Photos</p>
</div>
{/await}
</svelte:fragment>

View File

@ -10,22 +10,22 @@
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
import AssetSelectContextMenu from '$lib/components/photos-page/asset-select-context-menu.svelte';
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import { assetInteractionStore, isMultiSelectStoreState, selectedAssets } from '$lib/stores/asset-interaction.store';
import { assetStore } from '$lib/stores/assets.store';
import { openFileUploadDialog } from '$lib/utils/file-uploader';
import { api } from '@api';
import { onDestroy, onMount } from 'svelte';
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
import Plus from 'svelte-material-icons/Plus.svelte';
import type { PageData } from './$types';
import { api } from '@api';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import { openFileUploadDialog } from '$lib/utils/file-uploader';
export let data: PageData;
let assetCount = 1;
onMount(async () => {
const { data: allAssetCount } = await api.assetApi.getAssetCountByUserId();
assetCount = allAssetCount.total;
const { data: stats } = await api.assetApi.getAssetStats();
assetCount = stats.total;
});
onDestroy(() => {