mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-04 03:39:37 -05:00 
			
		
		
		
	feat(web,server): logout all devices (#2415)
* feat: logout all devices * chore: regenerate openapi * chore: add test * chore: logout vs log out
This commit is contained in:
		
							parent
							
								
									c956eee919
								
							
						
					
					
						commit
						a808b9403e
					
				
							
								
								
									
										1
									
								
								mobile/openapi/README.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								mobile/openapi/README.md
									
									
									
										generated
									
									
									
								
							@ -120,6 +120,7 @@ Class | Method | HTTP request | Description
 | 
				
			|||||||
*AuthenticationApi* | [**login**](doc//AuthenticationApi.md#login) | **POST** /auth/login | 
 | 
					*AuthenticationApi* | [**login**](doc//AuthenticationApi.md#login) | **POST** /auth/login | 
 | 
				
			||||||
*AuthenticationApi* | [**logout**](doc//AuthenticationApi.md#logout) | **POST** /auth/logout | 
 | 
					*AuthenticationApi* | [**logout**](doc//AuthenticationApi.md#logout) | **POST** /auth/logout | 
 | 
				
			||||||
*AuthenticationApi* | [**logoutAuthDevice**](doc//AuthenticationApi.md#logoutauthdevice) | **DELETE** /auth/devices/{id} | 
 | 
					*AuthenticationApi* | [**logoutAuthDevice**](doc//AuthenticationApi.md#logoutauthdevice) | **DELETE** /auth/devices/{id} | 
 | 
				
			||||||
 | 
					*AuthenticationApi* | [**logoutAuthDevices**](doc//AuthenticationApi.md#logoutauthdevices) | **DELETE** /auth/devices | 
 | 
				
			||||||
*AuthenticationApi* | [**validateAccessToken**](doc//AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken | 
 | 
					*AuthenticationApi* | [**validateAccessToken**](doc//AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken | 
 | 
				
			||||||
*JobApi* | [**getAllJobsStatus**](doc//JobApi.md#getalljobsstatus) | **GET** /jobs | 
 | 
					*JobApi* | [**getAllJobsStatus**](doc//JobApi.md#getalljobsstatus) | **GET** /jobs | 
 | 
				
			||||||
*JobApi* | [**sendJobCommand**](doc//JobApi.md#sendjobcommand) | **PUT** /jobs/{jobId} | 
 | 
					*JobApi* | [**sendJobCommand**](doc//JobApi.md#sendjobcommand) | **PUT** /jobs/{jobId} | 
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										51
									
								
								mobile/openapi/doc/AuthenticationApi.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										51
									
								
								mobile/openapi/doc/AuthenticationApi.md
									
									
									
										generated
									
									
									
								
							@ -15,6 +15,7 @@ Method | HTTP request | Description
 | 
				
			|||||||
[**login**](AuthenticationApi.md#login) | **POST** /auth/login | 
 | 
					[**login**](AuthenticationApi.md#login) | **POST** /auth/login | 
 | 
				
			||||||
[**logout**](AuthenticationApi.md#logout) | **POST** /auth/logout | 
 | 
					[**logout**](AuthenticationApi.md#logout) | **POST** /auth/logout | 
 | 
				
			||||||
[**logoutAuthDevice**](AuthenticationApi.md#logoutauthdevice) | **DELETE** /auth/devices/{id} | 
 | 
					[**logoutAuthDevice**](AuthenticationApi.md#logoutauthdevice) | **DELETE** /auth/devices/{id} | 
 | 
				
			||||||
 | 
					[**logoutAuthDevices**](AuthenticationApi.md#logoutauthdevices) | **DELETE** /auth/devices | 
 | 
				
			||||||
[**validateAccessToken**](AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken | 
 | 
					[**validateAccessToken**](AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken | 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -311,6 +312,56 @@ void (empty response body)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# **logoutAuthDevices**
 | 
				
			||||||
 | 
					> logoutAuthDevices()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 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 = AuthenticationApi();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					try {
 | 
				
			||||||
 | 
					    api_instance.logoutAuthDevices();
 | 
				
			||||||
 | 
					} catch (e) {
 | 
				
			||||||
 | 
					    print('Exception when calling AuthenticationApi->logoutAuthDevices: $e\n');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Parameters
 | 
				
			||||||
 | 
					This endpoint does not need any parameter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Return type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void (empty response body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Authorization
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### HTTP request headers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 - **Content-Type**: Not defined
 | 
				
			||||||
 | 
					 - **Accept**: Not defined
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# **validateAccessToken**
 | 
					# **validateAccessToken**
 | 
				
			||||||
> ValidateAccessTokenResponseDto validateAccessToken()
 | 
					> ValidateAccessTokenResponseDto validateAccessToken()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										33
									
								
								mobile/openapi/lib/api/authentication_api.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										33
									
								
								mobile/openapi/lib/api/authentication_api.dart
									
									
									
										generated
									
									
									
								
							@ -282,6 +282,39 @@ class AuthenticationApi {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Performs an HTTP 'DELETE /auth/devices' operation and returns the [Response].
 | 
				
			||||||
 | 
					  Future<Response> logoutAuthDevicesWithHttpInfo() async {
 | 
				
			||||||
 | 
					    // ignore: prefer_const_declarations
 | 
				
			||||||
 | 
					    final path = r'/auth/devices';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 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,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> logoutAuthDevices() async {
 | 
				
			||||||
 | 
					    final response = await logoutAuthDevicesWithHttpInfo();
 | 
				
			||||||
 | 
					    if (response.statusCode >= HttpStatus.badRequest) {
 | 
				
			||||||
 | 
					      throw ApiException(response.statusCode, await _decodeBodyBytes(response));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Performs an HTTP 'POST /auth/validateToken' operation and returns the [Response].
 | 
					  /// Performs an HTTP 'POST /auth/validateToken' operation and returns the [Response].
 | 
				
			||||||
  Future<Response> validateAccessTokenWithHttpInfo() async {
 | 
					  Future<Response> validateAccessTokenWithHttpInfo() async {
 | 
				
			||||||
    // ignore: prefer_const_declarations
 | 
					    // ignore: prefer_const_declarations
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										5
									
								
								mobile/openapi/test/authentication_api_test.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								mobile/openapi/test/authentication_api_test.dart
									
									
									
										generated
									
									
									
								
							@ -47,6 +47,11 @@ void main() {
 | 
				
			|||||||
      // TODO
 | 
					      // TODO
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //Future logoutAuthDevices() async
 | 
				
			||||||
 | 
					    test('test logoutAuthDevices', () async {
 | 
				
			||||||
 | 
					      // TODO
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //Future<ValidateAccessTokenResponseDto> validateAccessToken() async
 | 
					    //Future<ValidateAccessTokenResponseDto> validateAccessToken() async
 | 
				
			||||||
    test('test validateAccessToken', () async {
 | 
					    test('test validateAccessToken', () async {
 | 
				
			||||||
      // TODO
 | 
					      // TODO
 | 
				
			||||||
 | 
				
			|||||||
@ -52,6 +52,12 @@ export class AuthController {
 | 
				
			|||||||
    return this.service.getDevices(authUser);
 | 
					    return this.service.getDevices(authUser);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Authenticated()
 | 
				
			||||||
 | 
					  @Delete('devices')
 | 
				
			||||||
 | 
					  logoutAuthDevices(@GetAuthUser() authUser: AuthUserDto): Promise<void> {
 | 
				
			||||||
 | 
					    return this.service.logoutDevices(authUser);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Authenticated()
 | 
					  @Authenticated()
 | 
				
			||||||
  @Delete('devices/:id')
 | 
					  @Delete('devices/:id')
 | 
				
			||||||
  logoutAuthDevice(@GetAuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise<void> {
 | 
					  logoutAuthDevice(@GetAuthUser() authUser: AuthUserDto, @Param() { id }: UUIDParamDto): Promise<void> {
 | 
				
			||||||
 | 
				
			|||||||
@ -393,6 +393,29 @@
 | 
				
			|||||||
            "api_key": []
 | 
					            "api_key": []
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "delete": {
 | 
				
			||||||
 | 
					        "operationId": "logoutAuthDevices",
 | 
				
			||||||
 | 
					        "parameters": [],
 | 
				
			||||||
 | 
					        "responses": {
 | 
				
			||||||
 | 
					          "200": {
 | 
				
			||||||
 | 
					            "description": ""
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "tags": [
 | 
				
			||||||
 | 
					          "Authentication"
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "security": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "bearer": []
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "cookie": []
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "api_key": []
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "/auth/devices/{id}": {
 | 
					    "/auth/devices/{id}": {
 | 
				
			||||||
 | 
				
			|||||||
@ -357,6 +357,18 @@ describe('AuthService', () => {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('logoutDevices', () => {
 | 
				
			||||||
 | 
					    it('should logout all devices', async () => {
 | 
				
			||||||
 | 
					      userTokenMock.getAll.mockResolvedValue([userTokenEntityStub.inactiveToken, userTokenEntityStub.userToken]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await sut.logoutDevices(authStub.user1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(userTokenMock.getAll).toHaveBeenCalledWith(authStub.user1.id);
 | 
				
			||||||
 | 
					      expect(userTokenMock.delete).toHaveBeenCalledWith(authStub.user1.id, 'not_active');
 | 
				
			||||||
 | 
					      expect(userTokenMock.delete).not.toHaveBeenCalledWith(authStub.user1.id, 'token-id');
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe('logoutDevice', () => {
 | 
					  describe('logoutDevice', () => {
 | 
				
			||||||
    it('should logout the device', async () => {
 | 
					    it('should logout the device', async () => {
 | 
				
			||||||
      await sut.logoutDevice(authStub.user1, 'token-1');
 | 
					      await sut.logoutDevice(authStub.user1, 'token-1');
 | 
				
			||||||
 | 
				
			|||||||
@ -163,6 +163,16 @@ export class AuthService {
 | 
				
			|||||||
    await this.userTokenCore.delete(authUser.id, deviceId);
 | 
					    await this.userTokenCore.delete(authUser.id, deviceId);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async logoutDevices(authUser: AuthUserDto): Promise<void> {
 | 
				
			||||||
 | 
					    const devices = await this.userTokenCore.getAll(authUser.id);
 | 
				
			||||||
 | 
					    for (const device of devices) {
 | 
				
			||||||
 | 
					      if (device.id === authUser.accessTokenId) {
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      await this.userTokenCore.delete(authUser.id, device.id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private getBearerToken(headers: IncomingHttpHeaders): string | null {
 | 
					  private getBearerToken(headers: IncomingHttpHeaders): string | null {
 | 
				
			||||||
    const [type, token] = (headers.authorization || '').split(' ');
 | 
					    const [type, token] = (headers.authorization || '').split(' ');
 | 
				
			||||||
    if (type.toLowerCase() === 'bearer') {
 | 
					    if (type.toLowerCase() === 'bearer') {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										65
									
								
								web/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										65
									
								
								web/src/api/open-api/api.ts
									
									
									
										generated
									
									
									
								
							@ -6299,6 +6299,44 @@ export const AuthenticationApiAxiosParamCreator = function (configuration?: Conf
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					            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}
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        logoutAuthDevices: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
 | 
				
			||||||
 | 
					            const localVarPath = `/auth/devices`;
 | 
				
			||||||
 | 
					            // 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: 'DELETE', ...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);
 | 
					            setSearchParams(localVarUrlObj, localVarQueryParameter);
 | 
				
			||||||
            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
 | 
					            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
 | 
				
			||||||
            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
 | 
					            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
 | 
				
			||||||
@ -6414,6 +6452,15 @@ export const AuthenticationApiFp = function(configuration?: Configuration) {
 | 
				
			|||||||
            const localVarAxiosArgs = await localVarAxiosParamCreator.logoutAuthDevice(id, options);
 | 
					            const localVarAxiosArgs = await localVarAxiosParamCreator.logoutAuthDevice(id, options);
 | 
				
			||||||
            return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
 | 
					            return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 
 | 
				
			||||||
 | 
					         * @param {*} [options] Override http request option.
 | 
				
			||||||
 | 
					         * @throws {RequiredError}
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        async logoutAuthDevices(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
 | 
				
			||||||
 | 
					            const localVarAxiosArgs = await localVarAxiosParamCreator.logoutAuthDevices(options);
 | 
				
			||||||
 | 
					            return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * 
 | 
					         * 
 | 
				
			||||||
         * @param {*} [options] Override http request option.
 | 
					         * @param {*} [options] Override http request option.
 | 
				
			||||||
@ -6485,6 +6532,14 @@ export const AuthenticationApiFactory = function (configuration?: Configuration,
 | 
				
			|||||||
        logoutAuthDevice(id: string, options?: any): AxiosPromise<void> {
 | 
					        logoutAuthDevice(id: string, options?: any): AxiosPromise<void> {
 | 
				
			||||||
            return localVarFp.logoutAuthDevice(id, options).then((request) => request(axios, basePath));
 | 
					            return localVarFp.logoutAuthDevice(id, options).then((request) => request(axios, basePath));
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 
 | 
				
			||||||
 | 
					         * @param {*} [options] Override http request option.
 | 
				
			||||||
 | 
					         * @throws {RequiredError}
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        logoutAuthDevices(options?: any): AxiosPromise<void> {
 | 
				
			||||||
 | 
					            return localVarFp.logoutAuthDevices(options).then((request) => request(axios, basePath));
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * 
 | 
					         * 
 | 
				
			||||||
         * @param {*} [options] Override http request option.
 | 
					         * @param {*} [options] Override http request option.
 | 
				
			||||||
@ -6567,6 +6622,16 @@ export class AuthenticationApi extends BaseAPI {
 | 
				
			|||||||
        return AuthenticationApiFp(this.configuration).logoutAuthDevice(id, options).then((request) => request(this.axios, this.basePath));
 | 
					        return AuthenticationApiFp(this.configuration).logoutAuthDevice(id, options).then((request) => request(this.axios, this.basePath));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * @param {*} [options] Override http request option.
 | 
				
			||||||
 | 
					     * @throws {RequiredError}
 | 
				
			||||||
 | 
					     * @memberof AuthenticationApi
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public logoutAuthDevices(options?: AxiosRequestConfig) {
 | 
				
			||||||
 | 
					        return AuthenticationApiFp(this.configuration).logoutAuthDevices(options).then((request) => request(this.axios, this.basePath));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 
 | 
					     * 
 | 
				
			||||||
     * @param {*} [options] Override http request option.
 | 
					     * @param {*} [options] Override http request option.
 | 
				
			||||||
 | 
				
			|||||||
@ -62,7 +62,7 @@
 | 
				
			|||||||
				<button
 | 
									<button
 | 
				
			||||||
					on:click={() => dispatcher('delete')}
 | 
										on:click={() => dispatcher('delete')}
 | 
				
			||||||
					class="bg-immich-primary dark:bg-immich-dark-primary text-gray-100 dark:text-gray-700  rounded-full p-3 transition-all duration-150 hover:bg-immich-primary/75"
 | 
										class="bg-immich-primary dark:bg-immich-dark-primary text-gray-100 dark:text-gray-700  rounded-full p-3 transition-all duration-150 hover:bg-immich-primary/75"
 | 
				
			||||||
					title="Logout"
 | 
										title="Log out"
 | 
				
			||||||
				>
 | 
									>
 | 
				
			||||||
					<TrashCanOutline size="16" />
 | 
										<TrashCanOutline size="16" />
 | 
				
			||||||
				</button>
 | 
									</button>
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@
 | 
				
			|||||||
	import { api, AuthDeviceResponseDto } from '@api';
 | 
						import { api, AuthDeviceResponseDto } from '@api';
 | 
				
			||||||
	import { onMount } from 'svelte';
 | 
						import { onMount } from 'svelte';
 | 
				
			||||||
	import { handleError } from '../../utils/handle-error';
 | 
						import { handleError } from '../../utils/handle-error';
 | 
				
			||||||
 | 
						import Button from '../elements/buttons/button.svelte';
 | 
				
			||||||
	import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
 | 
						import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte';
 | 
				
			||||||
	import {
 | 
						import {
 | 
				
			||||||
		notificationController,
 | 
							notificationController,
 | 
				
			||||||
@ -11,6 +12,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	let devices: AuthDeviceResponseDto[] = [];
 | 
						let devices: AuthDeviceResponseDto[] = [];
 | 
				
			||||||
	let deleteDevice: AuthDeviceResponseDto | null = null;
 | 
						let deleteDevice: AuthDeviceResponseDto | null = null;
 | 
				
			||||||
 | 
						let deleteAll = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const refresh = () => api.authenticationApi.getAuthDevices().then(({ data }) => (devices = data));
 | 
						const refresh = () => api.authenticationApi.getAuthDevices().then(({ data }) => (devices = data));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -30,22 +32,45 @@
 | 
				
			|||||||
			await api.authenticationApi.logoutAuthDevice(deleteDevice.id);
 | 
								await api.authenticationApi.logoutAuthDevice(deleteDevice.id);
 | 
				
			||||||
			notificationController.show({ message: `Logged out device`, type: NotificationType.Info });
 | 
								notificationController.show({ message: `Logged out device`, type: NotificationType.Info });
 | 
				
			||||||
		} catch (error) {
 | 
							} catch (error) {
 | 
				
			||||||
			handleError(error, 'Unable to logout device');
 | 
								handleError(error, 'Unable to log out device');
 | 
				
			||||||
		} finally {
 | 
							} finally {
 | 
				
			||||||
			await refresh();
 | 
								await refresh();
 | 
				
			||||||
			deleteDevice = null;
 | 
								deleteDevice = null;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const handleDeleteAll = async () => {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								await api.authenticationApi.logoutAuthDevices();
 | 
				
			||||||
 | 
								notificationController.show({
 | 
				
			||||||
 | 
									message: `Logged out all devices`,
 | 
				
			||||||
 | 
									type: NotificationType.Info
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							} catch (error) {
 | 
				
			||||||
 | 
								handleError(error, 'Unable to log out all devices');
 | 
				
			||||||
 | 
							} finally {
 | 
				
			||||||
 | 
								await refresh();
 | 
				
			||||||
 | 
								deleteAll = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{#if deleteDevice}
 | 
					{#if deleteDevice}
 | 
				
			||||||
	<ConfirmDialogue
 | 
						<ConfirmDialogue
 | 
				
			||||||
		prompt="Are you sure you want to logout this device?"
 | 
							prompt="Are you sure you want to log out this device?"
 | 
				
			||||||
		on:confirm={() => handleDelete()}
 | 
							on:confirm={() => handleDelete()}
 | 
				
			||||||
		on:cancel={() => (deleteDevice = null)}
 | 
							on:cancel={() => (deleteDevice = null)}
 | 
				
			||||||
	/>
 | 
						/>
 | 
				
			||||||
{/if}
 | 
					{/if}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{#if deleteAll}
 | 
				
			||||||
 | 
						<ConfirmDialogue
 | 
				
			||||||
 | 
							prompt="Are you sure you want to log out all devices?"
 | 
				
			||||||
 | 
							on:confirm={() => handleDeleteAll()}
 | 
				
			||||||
 | 
							on:cancel={() => (deleteAll = false)}
 | 
				
			||||||
 | 
						/>
 | 
				
			||||||
 | 
					{/if}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<section class="my-4">
 | 
					<section class="my-4">
 | 
				
			||||||
	{#if currentDevice}
 | 
						{#if currentDevice}
 | 
				
			||||||
		<div class="mb-6">
 | 
							<div class="mb-6">
 | 
				
			||||||
@ -56,7 +81,7 @@
 | 
				
			|||||||
		</div>
 | 
							</div>
 | 
				
			||||||
	{/if}
 | 
						{/if}
 | 
				
			||||||
	{#if otherDevices.length > 0}
 | 
						{#if otherDevices.length > 0}
 | 
				
			||||||
		<div>
 | 
							<div class="mb-6">
 | 
				
			||||||
			<h3 class="font-medium text-xs mb-2 text-immich-primary dark:text-immich-dark-primary">
 | 
								<h3 class="font-medium text-xs mb-2 text-immich-primary dark:text-immich-dark-primary">
 | 
				
			||||||
				OTHER DEVICES
 | 
									OTHER DEVICES
 | 
				
			||||||
			</h3>
 | 
								</h3>
 | 
				
			||||||
@ -67,5 +92,11 @@
 | 
				
			|||||||
				{/if}
 | 
									{/if}
 | 
				
			||||||
			{/each}
 | 
								{/each}
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
 | 
							<h3 class="font-medium text-xs mb-2 text-immich-primary dark:text-immich-dark-primary">
 | 
				
			||||||
 | 
								LOG OUT ALL DEVICES
 | 
				
			||||||
 | 
							</h3>
 | 
				
			||||||
 | 
							<div class="flex justify-end">
 | 
				
			||||||
 | 
								<Button color="red" size="sm" on:click={() => (deleteAll = true)}>Log Out All Devices</Button>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
	{/if}
 | 
						{/if}
 | 
				
			||||||
</section>
 | 
					</section>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user