mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-10-29 17:40:28 +00:00
feat(server,web): Delete and restore user from the admin portal (#935)
* delete and restore user from admin UI * addressed review comments and fix e2e test * added cron job to delete user, and some formatting changes * addressed review comments * adding missing queue registration
This commit is contained in:
@@ -108,11 +108,13 @@ Class | Method | HTTP request | Description
|
||||
*ServerInfoApi* | [**pingServer**](doc//ServerInfoApi.md#pingserver) | **GET** /server-info/ping |
|
||||
*UserApi* | [**createProfileImage**](doc//UserApi.md#createprofileimage) | **POST** /user/profile-image |
|
||||
*UserApi* | [**createUser**](doc//UserApi.md#createuser) | **POST** /user |
|
||||
*UserApi* | [**deleteUser**](doc//UserApi.md#deleteuser) | **DELETE** /user/{userId} |
|
||||
*UserApi* | [**getAllUsers**](doc//UserApi.md#getallusers) | **GET** /user |
|
||||
*UserApi* | [**getMyUserInfo**](doc//UserApi.md#getmyuserinfo) | **GET** /user/me |
|
||||
*UserApi* | [**getProfileImage**](doc//UserApi.md#getprofileimage) | **GET** /user/profile-image/{userId} |
|
||||
*UserApi* | [**getUserById**](doc//UserApi.md#getuserbyid) | **GET** /user/info/{userId} |
|
||||
*UserApi* | [**getUserCount**](doc//UserApi.md#getusercount) | **GET** /user/count |
|
||||
*UserApi* | [**restoreUser**](doc//UserApi.md#restoreuser) | **POST** /user/{userId}/restore |
|
||||
*UserApi* | [**updateUser**](doc//UserApi.md#updateuser) | **PUT** /user |
|
||||
|
||||
|
||||
|
||||
@@ -11,11 +11,13 @@ Method | HTTP request | Description
|
||||
------------- | ------------- | -------------
|
||||
[**createProfileImage**](UserApi.md#createprofileimage) | **POST** /user/profile-image |
|
||||
[**createUser**](UserApi.md#createuser) | **POST** /user |
|
||||
[**deleteUser**](UserApi.md#deleteuser) | **DELETE** /user/{userId} |
|
||||
[**getAllUsers**](UserApi.md#getallusers) | **GET** /user |
|
||||
[**getMyUserInfo**](UserApi.md#getmyuserinfo) | **GET** /user/me |
|
||||
[**getProfileImage**](UserApi.md#getprofileimage) | **GET** /user/profile-image/{userId} |
|
||||
[**getUserById**](UserApi.md#getuserbyid) | **GET** /user/info/{userId} |
|
||||
[**getUserCount**](UserApi.md#getusercount) | **GET** /user/count |
|
||||
[**restoreUser**](UserApi.md#restoreuser) | **POST** /user/{userId}/restore |
|
||||
[**updateUser**](UserApi.md#updateuser) | **PUT** /user |
|
||||
|
||||
|
||||
@@ -113,6 +115,53 @@ 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)
|
||||
|
||||
# **deleteUser**
|
||||
> UserResponseDto deleteUser(userId)
|
||||
|
||||
|
||||
|
||||
### Example
|
||||
```dart
|
||||
import 'package:openapi/api.dart';
|
||||
// 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 = UserApi();
|
||||
final userId = userId_example; // String |
|
||||
|
||||
try {
|
||||
final result = api_instance.deleteUser(userId);
|
||||
print(result);
|
||||
} catch (e) {
|
||||
print('Exception when calling UserApi->deleteUser: $e\n');
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**userId** | **String**| |
|
||||
|
||||
### Return type
|
||||
|
||||
[**UserResponseDto**](UserResponseDto.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
[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)
|
||||
|
||||
# **getAllUsers**
|
||||
> List<UserResponseDto> getAllUsers(isAll)
|
||||
|
||||
@@ -322,6 +371,53 @@ No authorization required
|
||||
|
||||
[[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)
|
||||
|
||||
# **restoreUser**
|
||||
> UserResponseDto restoreUser(userId)
|
||||
|
||||
|
||||
|
||||
### Example
|
||||
```dart
|
||||
import 'package:openapi/api.dart';
|
||||
// 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 = UserApi();
|
||||
final userId = userId_example; // String |
|
||||
|
||||
try {
|
||||
final result = api_instance.restoreUser(userId);
|
||||
print(result);
|
||||
} catch (e) {
|
||||
print('Exception when calling UserApi->restoreUser: $e\n');
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**userId** | **String**| |
|
||||
|
||||
### Return type
|
||||
|
||||
[**UserResponseDto**](UserResponseDto.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
[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)
|
||||
|
||||
# **updateUser**
|
||||
> UserResponseDto updateUser(updateUserDto)
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ Name | Type | Description | Notes
|
||||
**profileImagePath** | **String** | |
|
||||
**shouldChangePassword** | **bool** | |
|
||||
**isAdmin** | **bool** | |
|
||||
**deletedAt** | [**DateTime**](DateTime.md) | |
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -120,6 +120,54 @@ class UserApi {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Performs an HTTP 'DELETE /user/{userId}' operation and returns the [Response].
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [String] userId (required):
|
||||
Future<Response> deleteUserWithHttpInfo(String userId,) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/user/{userId}'
|
||||
.replaceAll('{userId}', userId);
|
||||
|
||||
// ignore: prefer_final_locals
|
||||
Object? postBody;
|
||||
|
||||
final queryParams = <QueryParam>[];
|
||||
final headerParams = <String, String>{};
|
||||
final formParams = <String, String>{};
|
||||
|
||||
const contentTypes = <String>[];
|
||||
|
||||
|
||||
return apiClient.invokeAPI(
|
||||
path,
|
||||
'DELETE',
|
||||
queryParams,
|
||||
postBody,
|
||||
headerParams,
|
||||
formParams,
|
||||
contentTypes.isEmpty ? null : contentTypes.first,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [String] userId (required):
|
||||
Future<UserResponseDto?> deleteUser(String userId,) async {
|
||||
final response = await deleteUserWithHttpInfo(userId,);
|
||||
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), 'UserResponseDto',) as UserResponseDto;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Performs an HTTP 'GET /user' operation and returns the [Response].
|
||||
/// Parameters:
|
||||
///
|
||||
@@ -350,6 +398,54 @@ class UserApi {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Performs an HTTP 'POST /user/{userId}/restore' operation and returns the [Response].
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [String] userId (required):
|
||||
Future<Response> restoreUserWithHttpInfo(String userId,) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/user/{userId}/restore'
|
||||
.replaceAll('{userId}', userId);
|
||||
|
||||
// ignore: prefer_final_locals
|
||||
Object? postBody;
|
||||
|
||||
final queryParams = <QueryParam>[];
|
||||
final headerParams = <String, String>{};
|
||||
final formParams = <String, String>{};
|
||||
|
||||
const contentTypes = <String>[];
|
||||
|
||||
|
||||
return apiClient.invokeAPI(
|
||||
path,
|
||||
'POST',
|
||||
queryParams,
|
||||
postBody,
|
||||
headerParams,
|
||||
formParams,
|
||||
contentTypes.isEmpty ? null : contentTypes.first,
|
||||
);
|
||||
}
|
||||
|
||||
/// Parameters:
|
||||
///
|
||||
/// * [String] userId (required):
|
||||
Future<UserResponseDto?> restoreUser(String userId,) async {
|
||||
final response = await restoreUserWithHttpInfo(userId,);
|
||||
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), 'UserResponseDto',) as UserResponseDto;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Performs an HTTP 'PUT /user' operation and returns the [Response].
|
||||
/// Parameters:
|
||||
///
|
||||
|
||||
@@ -21,6 +21,7 @@ class UserResponseDto {
|
||||
required this.profileImagePath,
|
||||
required this.shouldChangePassword,
|
||||
required this.isAdmin,
|
||||
required this.deletedAt,
|
||||
});
|
||||
|
||||
String id;
|
||||
@@ -39,6 +40,8 @@ class UserResponseDto {
|
||||
|
||||
bool isAdmin;
|
||||
|
||||
DateTime? deletedAt;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is UserResponseDto &&
|
||||
other.id == id &&
|
||||
@@ -48,7 +51,8 @@ class UserResponseDto {
|
||||
other.createdAt == createdAt &&
|
||||
other.profileImagePath == profileImagePath &&
|
||||
other.shouldChangePassword == shouldChangePassword &&
|
||||
other.isAdmin == isAdmin;
|
||||
other.isAdmin == isAdmin &&
|
||||
other.deletedAt == deletedAt;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
@@ -60,10 +64,11 @@ class UserResponseDto {
|
||||
(createdAt.hashCode) +
|
||||
(profileImagePath.hashCode) +
|
||||
(shouldChangePassword.hashCode) +
|
||||
(isAdmin.hashCode);
|
||||
(isAdmin.hashCode) +
|
||||
(deletedAt == null ? 0 : deletedAt!.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'UserResponseDto[id=$id, email=$email, firstName=$firstName, lastName=$lastName, createdAt=$createdAt, profileImagePath=$profileImagePath, shouldChangePassword=$shouldChangePassword, isAdmin=$isAdmin]';
|
||||
String toString() => 'UserResponseDto[id=$id, email=$email, firstName=$firstName, lastName=$lastName, createdAt=$createdAt, profileImagePath=$profileImagePath, shouldChangePassword=$shouldChangePassword, isAdmin=$isAdmin, deletedAt=$deletedAt]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final _json = <String, dynamic>{};
|
||||
@@ -75,6 +80,11 @@ class UserResponseDto {
|
||||
_json[r'profileImagePath'] = profileImagePath;
|
||||
_json[r'shouldChangePassword'] = shouldChangePassword;
|
||||
_json[r'isAdmin'] = isAdmin;
|
||||
if (deletedAt != null) {
|
||||
_json[r'deletedAt'] = deletedAt!.toUtc().toIso8601String();
|
||||
} else {
|
||||
_json[r'deletedAt'] = null;
|
||||
}
|
||||
return _json;
|
||||
}
|
||||
|
||||
@@ -105,6 +115,7 @@ class UserResponseDto {
|
||||
profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
|
||||
shouldChangePassword: mapValueOfType<bool>(json, r'shouldChangePassword')!,
|
||||
isAdmin: mapValueOfType<bool>(json, r'isAdmin')!,
|
||||
deletedAt: mapDateTime(json, r'deletedAt', ''),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@@ -162,6 +173,7 @@ class UserResponseDto {
|
||||
'profileImagePath',
|
||||
'shouldChangePassword',
|
||||
'isAdmin',
|
||||
'deletedAt',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user