change readonly boolean to role enum
This commit is contained in:
Generated
+3
@@ -17,6 +17,7 @@ doc/AlbumApi.md
|
|||||||
doc/AlbumCountResponseDto.md
|
doc/AlbumCountResponseDto.md
|
||||||
doc/AlbumResponseDto.md
|
doc/AlbumResponseDto.md
|
||||||
doc/AlbumUserResponseDto.md
|
doc/AlbumUserResponseDto.md
|
||||||
|
doc/AlbumUserRole.md
|
||||||
doc/AllJobStatusResponseDto.md
|
doc/AllJobStatusResponseDto.md
|
||||||
doc/AssetApi.md
|
doc/AssetApi.md
|
||||||
doc/AssetBulkDeleteDto.md
|
doc/AssetBulkDeleteDto.md
|
||||||
@@ -240,6 +241,7 @@ lib/model/add_users_dto.dart
|
|||||||
lib/model/album_count_response_dto.dart
|
lib/model/album_count_response_dto.dart
|
||||||
lib/model/album_response_dto.dart
|
lib/model/album_response_dto.dart
|
||||||
lib/model/album_user_response_dto.dart
|
lib/model/album_user_response_dto.dart
|
||||||
|
lib/model/album_user_role.dart
|
||||||
lib/model/all_job_status_response_dto.dart
|
lib/model/all_job_status_response_dto.dart
|
||||||
lib/model/api_key_create_dto.dart
|
lib/model/api_key_create_dto.dart
|
||||||
lib/model/api_key_create_response_dto.dart
|
lib/model/api_key_create_response_dto.dart
|
||||||
@@ -419,6 +421,7 @@ test/album_api_test.dart
|
|||||||
test/album_count_response_dto_test.dart
|
test/album_count_response_dto_test.dart
|
||||||
test/album_response_dto_test.dart
|
test/album_response_dto_test.dart
|
||||||
test/album_user_response_dto_test.dart
|
test/album_user_response_dto_test.dart
|
||||||
|
test/album_user_role_test.dart
|
||||||
test/all_job_status_response_dto_test.dart
|
test/all_job_status_response_dto_test.dart
|
||||||
test/api_key_api_test.dart
|
test/api_key_api_test.dart
|
||||||
test/api_key_create_dto_test.dart
|
test/api_key_create_dto_test.dart
|
||||||
|
|||||||
Generated
+1
@@ -235,6 +235,7 @@ Class | Method | HTTP request | Description
|
|||||||
- [AlbumCountResponseDto](doc//AlbumCountResponseDto.md)
|
- [AlbumCountResponseDto](doc//AlbumCountResponseDto.md)
|
||||||
- [AlbumResponseDto](doc//AlbumResponseDto.md)
|
- [AlbumResponseDto](doc//AlbumResponseDto.md)
|
||||||
- [AlbumUserResponseDto](doc//AlbumUserResponseDto.md)
|
- [AlbumUserResponseDto](doc//AlbumUserResponseDto.md)
|
||||||
|
- [AlbumUserRole](doc//AlbumUserRole.md)
|
||||||
- [AllJobStatusResponseDto](doc//AllJobStatusResponseDto.md)
|
- [AllJobStatusResponseDto](doc//AllJobStatusResponseDto.md)
|
||||||
- [AssetBulkDeleteDto](doc//AssetBulkDeleteDto.md)
|
- [AssetBulkDeleteDto](doc//AssetBulkDeleteDto.md)
|
||||||
- [AssetBulkUpdateDto](doc//AssetBulkUpdateDto.md)
|
- [AssetBulkUpdateDto](doc//AssetBulkUpdateDto.md)
|
||||||
|
|||||||
Generated
+1
-1
@@ -23,7 +23,7 @@ Name | Type | Description | Notes
|
|||||||
**owner** | [**UserResponseDto**](UserResponseDto.md) | |
|
**owner** | [**UserResponseDto**](UserResponseDto.md) | |
|
||||||
**ownerId** | **String** | |
|
**ownerId** | **String** | |
|
||||||
**shared** | **bool** | |
|
**shared** | **bool** | |
|
||||||
**sharedUsers** | [**List<UserResponseDto>**](UserResponseDto.md) | Deprecated in favor of users | [default to const []]
|
**sharedUsers** | [**List<UserResponseDto>**](UserResponseDto.md) | Deprecated in favor of sharedUsersV2 | [default to const []]
|
||||||
**sharedUsersV2** | [**List<AlbumUserResponseDto>**](AlbumUserResponseDto.md) | | [default to const []]
|
**sharedUsersV2** | [**List<AlbumUserResponseDto>**](AlbumUserResponseDto.md) | | [default to const []]
|
||||||
**startDate** | [**DateTime**](DateTime.md) | | [optional]
|
**startDate** | [**DateTime**](DateTime.md) | | [optional]
|
||||||
**updatedAt** | [**DateTime**](DateTime.md) | |
|
**updatedAt** | [**DateTime**](DateTime.md) | |
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ import 'package:openapi/api.dart';
|
|||||||
## Properties
|
## Properties
|
||||||
Name | Type | Description | Notes
|
Name | Type | Description | Notes
|
||||||
------------ | ------------- | ------------- | -------------
|
------------ | ------------- | ------------- | -------------
|
||||||
**readonly** | **bool** | |
|
**role** | [**AlbumUserRole**](AlbumUserRole.md) | |
|
||||||
**user** | [**UserResponseDto**](UserResponseDto.md) | |
|
**user** | [**UserResponseDto**](UserResponseDto.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)
|
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||||
|
|||||||
Generated
+14
@@ -0,0 +1,14 @@
|
|||||||
|
# openapi.model.AlbumUserRole
|
||||||
|
|
||||||
|
## Load the model package
|
||||||
|
```dart
|
||||||
|
import 'package:openapi/api.dart';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
Name | Type | Description | Notes
|
||||||
|
------------ | ------------- | ------------- | -------------
|
||||||
|
|
||||||
|
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||||
|
|
||||||
|
|
||||||
Generated
+1
-1
@@ -8,7 +8,7 @@ import 'package:openapi/api.dart';
|
|||||||
## Properties
|
## Properties
|
||||||
Name | Type | Description | Notes
|
Name | Type | Description | Notes
|
||||||
------------ | ------------- | ------------- | -------------
|
------------ | ------------- | ------------- | -------------
|
||||||
**readonly** | **bool** | |
|
**role** | [**AlbumUserRole**](AlbumUserRole.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)
|
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||||
|
|
||||||
|
|||||||
Generated
+1
@@ -63,6 +63,7 @@ part 'model/add_users_dto.dart';
|
|||||||
part 'model/album_count_response_dto.dart';
|
part 'model/album_count_response_dto.dart';
|
||||||
part 'model/album_response_dto.dart';
|
part 'model/album_response_dto.dart';
|
||||||
part 'model/album_user_response_dto.dart';
|
part 'model/album_user_response_dto.dart';
|
||||||
|
part 'model/album_user_role.dart';
|
||||||
part 'model/all_job_status_response_dto.dart';
|
part 'model/all_job_status_response_dto.dart';
|
||||||
part 'model/asset_bulk_delete_dto.dart';
|
part 'model/asset_bulk_delete_dto.dart';
|
||||||
part 'model/asset_bulk_update_dto.dart';
|
part 'model/asset_bulk_update_dto.dart';
|
||||||
|
|||||||
Generated
+2
@@ -204,6 +204,8 @@ class ApiClient {
|
|||||||
return AlbumResponseDto.fromJson(value);
|
return AlbumResponseDto.fromJson(value);
|
||||||
case 'AlbumUserResponseDto':
|
case 'AlbumUserResponseDto':
|
||||||
return AlbumUserResponseDto.fromJson(value);
|
return AlbumUserResponseDto.fromJson(value);
|
||||||
|
case 'AlbumUserRole':
|
||||||
|
return AlbumUserRoleTypeTransformer().decode(value);
|
||||||
case 'AllJobStatusResponseDto':
|
case 'AllJobStatusResponseDto':
|
||||||
return AllJobStatusResponseDto.fromJson(value);
|
return AllJobStatusResponseDto.fromJson(value);
|
||||||
case 'AssetBulkDeleteDto':
|
case 'AssetBulkDeleteDto':
|
||||||
|
|||||||
Generated
+3
@@ -55,6 +55,9 @@ String parameterToString(dynamic value) {
|
|||||||
if (value is DateTime) {
|
if (value is DateTime) {
|
||||||
return value.toUtc().toIso8601String();
|
return value.toUtc().toIso8601String();
|
||||||
}
|
}
|
||||||
|
if (value is AlbumUserRole) {
|
||||||
|
return AlbumUserRoleTypeTransformer().encode(value).toString();
|
||||||
|
}
|
||||||
if (value is AssetJobName) {
|
if (value is AssetJobName) {
|
||||||
return AssetJobNameTypeTransformer().encode(value).toString();
|
return AssetJobNameTypeTransformer().encode(value).toString();
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -82,7 +82,7 @@ class AlbumResponseDto {
|
|||||||
|
|
||||||
bool shared;
|
bool shared;
|
||||||
|
|
||||||
/// Deprecated in favor of users
|
/// Deprecated in favor of sharedUsersV2
|
||||||
List<UserResponseDto> sharedUsers;
|
List<UserResponseDto> sharedUsers;
|
||||||
|
|
||||||
List<AlbumUserResponseDto> sharedUsersV2;
|
List<AlbumUserResponseDto> sharedUsersV2;
|
||||||
|
|||||||
+8
-8
@@ -13,31 +13,31 @@ part of openapi.api;
|
|||||||
class AlbumUserResponseDto {
|
class AlbumUserResponseDto {
|
||||||
/// Returns a new [AlbumUserResponseDto] instance.
|
/// Returns a new [AlbumUserResponseDto] instance.
|
||||||
AlbumUserResponseDto({
|
AlbumUserResponseDto({
|
||||||
required this.readonly,
|
required this.role,
|
||||||
required this.user,
|
required this.user,
|
||||||
});
|
});
|
||||||
|
|
||||||
bool readonly;
|
AlbumUserRole role;
|
||||||
|
|
||||||
UserResponseDto user;
|
UserResponseDto user;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => identical(this, other) || other is AlbumUserResponseDto &&
|
bool operator ==(Object other) => identical(this, other) || other is AlbumUserResponseDto &&
|
||||||
other.readonly == readonly &&
|
other.role == role &&
|
||||||
other.user == user;
|
other.user == user;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
// ignore: unnecessary_parenthesis
|
// ignore: unnecessary_parenthesis
|
||||||
(readonly.hashCode) +
|
(role.hashCode) +
|
||||||
(user.hashCode);
|
(user.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'AlbumUserResponseDto[readonly=$readonly, user=$user]';
|
String toString() => 'AlbumUserResponseDto[role=$role, user=$user]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
json[r'readonly'] = this.readonly;
|
json[r'role'] = this.role;
|
||||||
json[r'user'] = this.user;
|
json[r'user'] = this.user;
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ class AlbumUserResponseDto {
|
|||||||
final json = value.cast<String, dynamic>();
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
return AlbumUserResponseDto(
|
return AlbumUserResponseDto(
|
||||||
readonly: mapValueOfType<bool>(json, r'readonly')!,
|
role: AlbumUserRole.fromJson(json[r'role'])!,
|
||||||
user: UserResponseDto.fromJson(json[r'user'])!,
|
user: UserResponseDto.fromJson(json[r'user'])!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -99,7 +99,7 @@ class AlbumUserResponseDto {
|
|||||||
|
|
||||||
/// The list of required keys that must be present in a JSON.
|
/// The list of required keys that must be present in a JSON.
|
||||||
static const requiredKeys = <String>{
|
static const requiredKeys = <String>{
|
||||||
'readonly',
|
'role',
|
||||||
'user',
|
'user',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
//
|
||||||
|
// 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 AlbumUserRole {
|
||||||
|
/// Instantiate a new enum with the provided [value].
|
||||||
|
const AlbumUserRole._(this.value);
|
||||||
|
|
||||||
|
/// The underlying value of this enum member.
|
||||||
|
final String value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => value;
|
||||||
|
|
||||||
|
String toJson() => value;
|
||||||
|
|
||||||
|
static const editor = AlbumUserRole._(r'editor');
|
||||||
|
static const viewer = AlbumUserRole._(r'viewer');
|
||||||
|
|
||||||
|
/// List of all possible values in this [enum][AlbumUserRole].
|
||||||
|
static const values = <AlbumUserRole>[
|
||||||
|
editor,
|
||||||
|
viewer,
|
||||||
|
];
|
||||||
|
|
||||||
|
static AlbumUserRole? fromJson(dynamic value) => AlbumUserRoleTypeTransformer().decode(value);
|
||||||
|
|
||||||
|
static List<AlbumUserRole> listFromJson(dynamic json, {bool growable = false,}) {
|
||||||
|
final result = <AlbumUserRole>[];
|
||||||
|
if (json is List && json.isNotEmpty) {
|
||||||
|
for (final row in json) {
|
||||||
|
final value = AlbumUserRole.fromJson(row);
|
||||||
|
if (value != null) {
|
||||||
|
result.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toList(growable: growable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transformation class that can [encode] an instance of [AlbumUserRole] to String,
|
||||||
|
/// and [decode] dynamic data back to [AlbumUserRole].
|
||||||
|
class AlbumUserRoleTypeTransformer {
|
||||||
|
factory AlbumUserRoleTypeTransformer() => _instance ??= const AlbumUserRoleTypeTransformer._();
|
||||||
|
|
||||||
|
const AlbumUserRoleTypeTransformer._();
|
||||||
|
|
||||||
|
String encode(AlbumUserRole data) => data.value;
|
||||||
|
|
||||||
|
/// Decodes a [dynamic value][data] to a AlbumUserRole.
|
||||||
|
///
|
||||||
|
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
|
||||||
|
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
|
||||||
|
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
|
||||||
|
///
|
||||||
|
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
|
||||||
|
/// and users are still using an old app with the old code.
|
||||||
|
AlbumUserRole? decode(dynamic data, {bool allowNull = true}) {
|
||||||
|
if (data != null) {
|
||||||
|
switch (data) {
|
||||||
|
case r'editor': return AlbumUserRole.editor;
|
||||||
|
case r'viewer': return AlbumUserRole.viewer;
|
||||||
|
default:
|
||||||
|
if (!allowNull) {
|
||||||
|
throw ArgumentError('Unknown enum value to decode: $data');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Singleton [AlbumUserRoleTypeTransformer] instance.
|
||||||
|
static AlbumUserRoleTypeTransformer? _instance;
|
||||||
|
}
|
||||||
|
|
||||||
+8
-8
@@ -13,26 +13,26 @@ part of openapi.api;
|
|||||||
class UpdateAlbumUserDto {
|
class UpdateAlbumUserDto {
|
||||||
/// Returns a new [UpdateAlbumUserDto] instance.
|
/// Returns a new [UpdateAlbumUserDto] instance.
|
||||||
UpdateAlbumUserDto({
|
UpdateAlbumUserDto({
|
||||||
required this.readonly,
|
required this.role,
|
||||||
});
|
});
|
||||||
|
|
||||||
bool readonly;
|
AlbumUserRole role;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => identical(this, other) || other is UpdateAlbumUserDto &&
|
bool operator ==(Object other) => identical(this, other) || other is UpdateAlbumUserDto &&
|
||||||
other.readonly == readonly;
|
other.role == role;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
// ignore: unnecessary_parenthesis
|
// ignore: unnecessary_parenthesis
|
||||||
(readonly.hashCode);
|
(role.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'UpdateAlbumUserDto[readonly=$readonly]';
|
String toString() => 'UpdateAlbumUserDto[role=$role]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
json[r'readonly'] = this.readonly;
|
json[r'role'] = this.role;
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ class UpdateAlbumUserDto {
|
|||||||
final json = value.cast<String, dynamic>();
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
return UpdateAlbumUserDto(
|
return UpdateAlbumUserDto(
|
||||||
readonly: mapValueOfType<bool>(json, r'readonly')!,
|
role: AlbumUserRole.fromJson(json[r'role'])!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -92,7 +92,7 @@ class UpdateAlbumUserDto {
|
|||||||
|
|
||||||
/// The list of required keys that must be present in a JSON.
|
/// The list of required keys that must be present in a JSON.
|
||||||
static const requiredKeys = <String>{
|
static const requiredKeys = <String>{
|
||||||
'readonly',
|
'role',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -91,7 +91,7 @@ void main() {
|
|||||||
// TODO
|
// TODO
|
||||||
});
|
});
|
||||||
|
|
||||||
// Deprecated in favor of users
|
// Deprecated in favor of sharedUsersV2
|
||||||
// List<UserResponseDto> sharedUsers (default value: const [])
|
// List<UserResponseDto> sharedUsers (default value: const [])
|
||||||
test('to test the property `sharedUsers`', () async {
|
test('to test the property `sharedUsers`', () async {
|
||||||
// TODO
|
// TODO
|
||||||
|
|||||||
+2
-2
@@ -16,8 +16,8 @@ void main() {
|
|||||||
// final instance = AlbumUserResponseDto();
|
// final instance = AlbumUserResponseDto();
|
||||||
|
|
||||||
group('test AlbumUserResponseDto', () {
|
group('test AlbumUserResponseDto', () {
|
||||||
// bool readonly
|
// AlbumUserRole role
|
||||||
test('to test the property `readonly`', () async {
|
test('to test the property `role`', () async {
|
||||||
// TODO
|
// TODO
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
|
|
||||||
|
import 'package:openapi/api.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
// tests for AlbumUserRole
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
group('test AlbumUserRole', () {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
+2
-2
@@ -16,8 +16,8 @@ void main() {
|
|||||||
// final instance = UpdateAlbumUserDto();
|
// final instance = UpdateAlbumUserDto();
|
||||||
|
|
||||||
group('test UpdateAlbumUserDto', () {
|
group('test UpdateAlbumUserDto', () {
|
||||||
// bool readonly
|
// AlbumUserRole role
|
||||||
test('to test the property `readonly`', () async {
|
test('to test the property `role`', () async {
|
||||||
// TODO
|
// TODO
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -7174,7 +7174,7 @@
|
|||||||
},
|
},
|
||||||
"sharedUsers": {
|
"sharedUsers": {
|
||||||
"deprecated": true,
|
"deprecated": true,
|
||||||
"description": "Deprecated in favor of users",
|
"description": "Deprecated in favor of sharedUsersV2",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/components/schemas/UserResponseDto"
|
"$ref": "#/components/schemas/UserResponseDto"
|
||||||
},
|
},
|
||||||
@@ -7216,19 +7216,26 @@
|
|||||||
},
|
},
|
||||||
"AlbumUserResponseDto": {
|
"AlbumUserResponseDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"readonly": {
|
"role": {
|
||||||
"type": "boolean"
|
"$ref": "#/components/schemas/AlbumUserRole"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"$ref": "#/components/schemas/UserResponseDto"
|
"$ref": "#/components/schemas/UserResponseDto"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"readonly",
|
"role",
|
||||||
"user"
|
"user"
|
||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"AlbumUserRole": {
|
||||||
|
"enum": [
|
||||||
|
"editor",
|
||||||
|
"viewer"
|
||||||
|
],
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"AllJobStatusResponseDto": {
|
"AllJobStatusResponseDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"backgroundTask": {
|
"backgroundTask": {
|
||||||
@@ -10962,12 +10969,12 @@
|
|||||||
},
|
},
|
||||||
"UpdateAlbumUserDto": {
|
"UpdateAlbumUserDto": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"readonly": {
|
"role": {
|
||||||
"type": "boolean"
|
"$ref": "#/components/schemas/AlbumUserRole"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"readonly"
|
"role"
|
||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ export type AssetResponseDto = {
|
|||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
};
|
};
|
||||||
export type AlbumUserResponseDto = {
|
export type AlbumUserResponseDto = {
|
||||||
"readonly": boolean;
|
role: AlbumUserRole;
|
||||||
user: UserResponseDto;
|
user: UserResponseDto;
|
||||||
};
|
};
|
||||||
export type AlbumResponseDto = {
|
export type AlbumResponseDto = {
|
||||||
@@ -161,7 +161,7 @@ export type AlbumResponseDto = {
|
|||||||
owner: UserResponseDto;
|
owner: UserResponseDto;
|
||||||
ownerId: string;
|
ownerId: string;
|
||||||
shared: boolean;
|
shared: boolean;
|
||||||
/** Deprecated in favor of users */
|
/** Deprecated in favor of sharedUsersV2 */
|
||||||
sharedUsers: UserResponseDto[];
|
sharedUsers: UserResponseDto[];
|
||||||
sharedUsersV2: AlbumUserResponseDto[];
|
sharedUsersV2: AlbumUserResponseDto[];
|
||||||
startDate?: string;
|
startDate?: string;
|
||||||
@@ -194,7 +194,7 @@ export type BulkIdResponseDto = {
|
|||||||
success: boolean;
|
success: boolean;
|
||||||
};
|
};
|
||||||
export type UpdateAlbumUserDto = {
|
export type UpdateAlbumUserDto = {
|
||||||
"readonly": boolean;
|
role: AlbumUserRole;
|
||||||
};
|
};
|
||||||
export type AddUsersDto = {
|
export type AddUsersDto = {
|
||||||
sharedUserIds: string[];
|
sharedUserIds: string[];
|
||||||
@@ -2901,6 +2901,10 @@ export enum AssetOrder {
|
|||||||
Asc = "asc",
|
Asc = "asc",
|
||||||
Desc = "desc"
|
Desc = "desc"
|
||||||
}
|
}
|
||||||
|
export enum AlbumUserRole {
|
||||||
|
Editor = "editor",
|
||||||
|
Viewer = "viewer"
|
||||||
|
}
|
||||||
export enum Error {
|
export enum Error {
|
||||||
Duplicate = "duplicate",
|
Duplicate = "duplicate",
|
||||||
NoPermission = "no_permission",
|
NoPermission = "no_permission",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { BadRequestException, UnauthorizedException } from '@nestjs/common';
|
import { BadRequestException, UnauthorizedException } from '@nestjs/common';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
|
import { AlbumUserRole } from 'src/entities/album-user.entity';
|
||||||
import { SharedLinkEntity } from 'src/entities/shared-link.entity';
|
import { SharedLinkEntity } from 'src/entities/shared-link.entity';
|
||||||
import { IAccessRepository } from 'src/interfaces/access.interface';
|
import { IAccessRepository } from 'src/interfaces/access.interface';
|
||||||
import { setDifference, setIsEqual, setUnion } from 'src/utils/set';
|
import { setDifference, setIsEqual, setUnion } from 'src/utils/set';
|
||||||
@@ -219,7 +220,7 @@ export class AccessCore {
|
|||||||
const isShared = await this.repository.album.checkSharedAlbumAccess(
|
const isShared = await this.repository.album.checkSharedAlbumAccess(
|
||||||
auth.user.id,
|
auth.user.id,
|
||||||
setDifference(ids, isOwner),
|
setDifference(ids, isOwner),
|
||||||
'read',
|
AlbumUserRole.Viewer,
|
||||||
);
|
);
|
||||||
return setUnion(isOwner, isShared);
|
return setUnion(isOwner, isShared);
|
||||||
}
|
}
|
||||||
@@ -229,7 +230,7 @@ export class AccessCore {
|
|||||||
const isShared = await this.repository.album.checkSharedAlbumAccess(
|
const isShared = await this.repository.album.checkSharedAlbumAccess(
|
||||||
auth.user.id,
|
auth.user.id,
|
||||||
setDifference(ids, isOwner),
|
setDifference(ids, isOwner),
|
||||||
'write',
|
AlbumUserRole.Editor,
|
||||||
);
|
);
|
||||||
return setUnion(isOwner, isShared);
|
return setUnion(isOwner, isShared);
|
||||||
}
|
}
|
||||||
@@ -251,7 +252,7 @@ export class AccessCore {
|
|||||||
const isShared = await this.repository.album.checkSharedAlbumAccess(
|
const isShared = await this.repository.album.checkSharedAlbumAccess(
|
||||||
auth.user.id,
|
auth.user.id,
|
||||||
setDifference(ids, isOwner),
|
setDifference(ids, isOwner),
|
||||||
'read',
|
AlbumUserRole.Viewer,
|
||||||
);
|
);
|
||||||
return setUnion(isOwner, isShared);
|
return setUnion(isOwner, isShared);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { ArrayNotEmpty, IsEnum, IsString } from 'class-validator';
|
|||||||
import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto';
|
import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
import { UserResponseDto, mapUser } from 'src/dtos/user.dto';
|
import { UserResponseDto, mapUser } from 'src/dtos/user.dto';
|
||||||
|
import { AlbumUserRole } from 'src/entities/album-user.entity';
|
||||||
import { AlbumEntity, AssetOrder } from 'src/entities/album.entity';
|
import { AlbumEntity, AssetOrder } from 'src/entities/album.entity';
|
||||||
import { Optional, ValidateBoolean, ValidateUUID } from 'src/validation';
|
import { Optional, ValidateBoolean, ValidateUUID } from 'src/validation';
|
||||||
|
|
||||||
@@ -84,13 +85,15 @@ export class AlbumCountResponseDto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateAlbumUserDto {
|
export class UpdateAlbumUserDto {
|
||||||
@ValidateBoolean()
|
@IsEnum(AlbumUserRole)
|
||||||
readonly!: boolean;
|
@ApiProperty({ enum: AlbumUserRole, enumName: 'AlbumUserRole' })
|
||||||
|
role!: AlbumUserRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AlbumUserResponseDto {
|
export class AlbumUserResponseDto {
|
||||||
user!: UserResponseDto;
|
user!: UserResponseDto;
|
||||||
readonly!: boolean;
|
@ApiProperty({ enum: AlbumUserRole, enumName: 'AlbumUserRole' })
|
||||||
|
role!: AlbumUserRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AlbumResponseDto {
|
export class AlbumResponseDto {
|
||||||
@@ -128,7 +131,7 @@ export const mapAlbum = (entity: AlbumEntity, withAssets: boolean, auth?: AuthDt
|
|||||||
sharedUsers.push(mapUser(permission.user));
|
sharedUsers.push(mapUser(permission.user));
|
||||||
sharedUsersV2.push({
|
sharedUsersV2.push({
|
||||||
user: mapUser(permission.user),
|
user: mapUser(permission.user),
|
||||||
readonly: permission.readonly,
|
role: permission.role,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,11 @@ import { AlbumEntity } from 'src/entities/album.entity';
|
|||||||
import { UserEntity } from 'src/entities/user.entity';
|
import { UserEntity } from 'src/entities/user.entity';
|
||||||
import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
|
import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
|
||||||
|
|
||||||
|
export enum AlbumUserRole {
|
||||||
|
Editor = 'editor',
|
||||||
|
Viewer = 'viewer',
|
||||||
|
}
|
||||||
|
|
||||||
@Entity('albums_shared_users_users')
|
@Entity('albums_shared_users_users')
|
||||||
// Pre-existing indices from original album <--> user ManyToMany mapping
|
// Pre-existing indices from original album <--> user ManyToMany mapping
|
||||||
@Index('IDX_427c350ad49bd3935a50baab73', ['album'])
|
@Index('IDX_427c350ad49bd3935a50baab73', ['album'])
|
||||||
@@ -17,6 +22,6 @@ export class AlbumUserEntity {
|
|||||||
@ManyToOne(() => UserEntity, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: false })
|
@ManyToOne(() => UserEntity, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: false })
|
||||||
user!: UserEntity;
|
user!: UserEntity;
|
||||||
|
|
||||||
@Column({ default: true })
|
@Column({ type: 'varchar', default: 'viewer' })
|
||||||
readonly!: boolean;
|
role!: AlbumUserRole;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { AlbumUserRole } from 'src/entities/album-user.entity';
|
||||||
|
|
||||||
export const IAccessRepository = 'IAccessRepository';
|
export const IAccessRepository = 'IAccessRepository';
|
||||||
|
|
||||||
export type ReadWrite = 'read' | 'write';
|
export type ReadWrite = 'read' | 'write';
|
||||||
@@ -22,7 +24,7 @@ export interface IAccessRepository {
|
|||||||
|
|
||||||
album: {
|
album: {
|
||||||
checkOwnerAccess(userId: string, albumIds: Set<string>): Promise<Set<string>>;
|
checkOwnerAccess(userId: string, albumIds: Set<string>): Promise<Set<string>>;
|
||||||
checkSharedAlbumAccess(userId: string, albumIds: Set<string>, readWrite: ReadWrite): Promise<Set<string>>;
|
checkSharedAlbumAccess(userId: string, albumIds: Set<string>, access: AlbumUserRole): Promise<Set<string>>;
|
||||||
checkSharedLinkAccess(sharedLinkId: string, albumIds: Set<string>): Promise<Set<string>>;
|
checkSharedLinkAccess(sharedLinkId: string, albumIds: Set<string>): Promise<Set<string>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -1,15 +1,15 @@
|
|||||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
export class AddAlbumUserReadonly1713298646379 implements MigrationInterface {
|
export class AddAlbumUserRole1713337511945 implements MigrationInterface {
|
||||||
name = 'AddAlbumUserReadonly1713298646379'
|
name = 'AddAlbumUserRole1713337511945'
|
||||||
|
|
||||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" ADD "readonly" boolean NOT NULL DEFAULT false`);
|
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" ADD "role" character varying NOT NULL DEFAULT 'editor'`);
|
||||||
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" ALTER COLUMN "readonly" SET DEFAULT true`);
|
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" ALTER COLUMN "role" SET DEFAULT 'viewer'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" DROP COLUMN "readonly"`);
|
await queryRunner.query(`ALTER TABLE "albums_shared_users_users" DROP COLUMN "role"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ SELECT
|
|||||||
"AlbumEntity"."id" AS "AlbumEntity_id",
|
"AlbumEntity"."id" AS "AlbumEntity_id",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."readonly" AS "AlbumEntity__AlbumEntity_sharedUsers_readonly"
|
"AlbumEntity__AlbumEntity_sharedUsers"."role" AS "AlbumEntity__AlbumEntity_sharedUsers_role"
|
||||||
FROM
|
FROM
|
||||||
"albums" "AlbumEntity"
|
"albums" "AlbumEntity"
|
||||||
LEFT JOIN "albums_shared_users_users" "AlbumEntity__AlbumEntity_sharedUsers" ON "AlbumEntity__AlbumEntity_sharedUsers"."albumsId" = "AlbumEntity"."id"
|
LEFT JOIN "albums_shared_users_users" "AlbumEntity__AlbumEntity_sharedUsers" ON "AlbumEntity__AlbumEntity_sharedUsers"."albumsId" = "AlbumEntity"."id"
|
||||||
@@ -83,6 +83,9 @@ WHERE
|
|||||||
(
|
(
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" = $2
|
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" = $2
|
||||||
)
|
)
|
||||||
|
AND (
|
||||||
|
"AlbumEntity__AlbumEntity_sharedUsers"."role" IN ($3, $4)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ FROM
|
|||||||
"AlbumEntity__AlbumEntity_owner"."quotaUsageInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaUsageInBytes",
|
"AlbumEntity__AlbumEntity_owner"."quotaUsageInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaUsageInBytes",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."readonly" AS "AlbumEntity__AlbumEntity_sharedUsers_readonly",
|
"AlbumEntity__AlbumEntity_sharedUsers"."role" AS "AlbumEntity__AlbumEntity_sharedUsers_role",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."id" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_id",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."id" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_id",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."name" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_name",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."name" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_name",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."avatarColor" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_avatarColor",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."avatarColor" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_avatarColor",
|
||||||
@@ -114,7 +114,7 @@ SELECT
|
|||||||
"AlbumEntity__AlbumEntity_owner"."quotaUsageInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaUsageInBytes",
|
"AlbumEntity__AlbumEntity_owner"."quotaUsageInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaUsageInBytes",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."readonly" AS "AlbumEntity__AlbumEntity_sharedUsers_readonly",
|
"AlbumEntity__AlbumEntity_sharedUsers"."role" AS "AlbumEntity__AlbumEntity_sharedUsers_role",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."id" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_id",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."id" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_id",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."name" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_name",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."name" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_name",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."avatarColor" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_avatarColor",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."avatarColor" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_avatarColor",
|
||||||
@@ -176,7 +176,7 @@ SELECT
|
|||||||
"AlbumEntity__AlbumEntity_owner"."quotaUsageInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaUsageInBytes",
|
"AlbumEntity__AlbumEntity_owner"."quotaUsageInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaUsageInBytes",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."readonly" AS "AlbumEntity__AlbumEntity_sharedUsers_readonly",
|
"AlbumEntity__AlbumEntity_sharedUsers"."role" AS "AlbumEntity__AlbumEntity_sharedUsers_role",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."id" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_id",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."id" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_id",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."name" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_name",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."name" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_name",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."avatarColor" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_avatarColor",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."avatarColor" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_avatarColor",
|
||||||
@@ -296,7 +296,7 @@ SELECT
|
|||||||
"AlbumEntity"."order" AS "AlbumEntity_order",
|
"AlbumEntity"."order" AS "AlbumEntity_order",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."readonly" AS "AlbumEntity__AlbumEntity_sharedUsers_readonly",
|
"AlbumEntity__AlbumEntity_sharedUsers"."role" AS "AlbumEntity__AlbumEntity_sharedUsers_role",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."id" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_id",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."id" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_id",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."name" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_name",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."name" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_name",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."avatarColor" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_avatarColor",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."avatarColor" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_avatarColor",
|
||||||
@@ -373,7 +373,7 @@ SELECT
|
|||||||
"AlbumEntity"."order" AS "AlbumEntity_order",
|
"AlbumEntity"."order" AS "AlbumEntity_order",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."readonly" AS "AlbumEntity__AlbumEntity_sharedUsers_readonly",
|
"AlbumEntity__AlbumEntity_sharedUsers"."role" AS "AlbumEntity__AlbumEntity_sharedUsers_role",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."id" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_id",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."id" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_id",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."name" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_name",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."name" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_name",
|
||||||
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."avatarColor" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_avatarColor",
|
"c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a"."avatarColor" AS "c20102de0f4f51a0efbaca481ef9bb2f99dd7c0a_avatarColor",
|
||||||
@@ -489,7 +489,7 @@ SELECT
|
|||||||
"AlbumEntity"."order" AS "AlbumEntity_order",
|
"AlbumEntity"."order" AS "AlbumEntity_order",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."albumsId" AS "AlbumEntity__AlbumEntity_sharedUsers_albumsId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
"AlbumEntity__AlbumEntity_sharedUsers"."usersId" AS "AlbumEntity__AlbumEntity_sharedUsers_usersId",
|
||||||
"AlbumEntity__AlbumEntity_sharedUsers"."readonly" AS "AlbumEntity__AlbumEntity_sharedUsers_readonly",
|
"AlbumEntity__AlbumEntity_sharedUsers"."role" AS "AlbumEntity__AlbumEntity_sharedUsers_role",
|
||||||
"AlbumEntity__AlbumEntity_sharedLinks"."id" AS "AlbumEntity__AlbumEntity_sharedLinks_id",
|
"AlbumEntity__AlbumEntity_sharedLinks"."id" AS "AlbumEntity__AlbumEntity_sharedLinks_id",
|
||||||
"AlbumEntity__AlbumEntity_sharedLinks"."description" AS "AlbumEntity__AlbumEntity_sharedLinks_description",
|
"AlbumEntity__AlbumEntity_sharedLinks"."description" AS "AlbumEntity__AlbumEntity_sharedLinks_description",
|
||||||
"AlbumEntity__AlbumEntity_sharedLinks"."password" AS "AlbumEntity__AlbumEntity_sharedLinks_password",
|
"AlbumEntity__AlbumEntity_sharedLinks"."password" AS "AlbumEntity__AlbumEntity_sharedLinks_password",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { ChunkedSet, DummyValue, GenerateSql } from 'src/decorators';
|
import { ChunkedSet, DummyValue, GenerateSql } from 'src/decorators';
|
||||||
import { ActivityEntity } from 'src/entities/activity.entity';
|
import { ActivityEntity } from 'src/entities/activity.entity';
|
||||||
|
import { AlbumUserRole } from 'src/entities/album-user.entity';
|
||||||
import { AlbumEntity } from 'src/entities/album.entity';
|
import { AlbumEntity } from 'src/entities/album.entity';
|
||||||
import { AssetFaceEntity } from 'src/entities/asset-face.entity';
|
import { AssetFaceEntity } from 'src/entities/asset-face.entity';
|
||||||
import { AssetEntity } from 'src/entities/asset.entity';
|
import { AssetEntity } from 'src/entities/asset.entity';
|
||||||
@@ -10,7 +11,7 @@ import { PartnerEntity } from 'src/entities/partner.entity';
|
|||||||
import { PersonEntity } from 'src/entities/person.entity';
|
import { PersonEntity } from 'src/entities/person.entity';
|
||||||
import { SharedLinkEntity } from 'src/entities/shared-link.entity';
|
import { SharedLinkEntity } from 'src/entities/shared-link.entity';
|
||||||
import { UserTokenEntity } from 'src/entities/user-token.entity';
|
import { UserTokenEntity } from 'src/entities/user-token.entity';
|
||||||
import { IAccessRepository, ReadWrite } from 'src/interfaces/access.interface';
|
import { IAccessRepository } from 'src/interfaces/access.interface';
|
||||||
import { Instrumentation } from 'src/utils/instrumentation';
|
import { Instrumentation } from 'src/utils/instrumentation';
|
||||||
import { Brackets, In, Repository } from 'typeorm';
|
import { Brackets, In, Repository } from 'typeorm';
|
||||||
|
|
||||||
@@ -119,7 +120,7 @@ class AlbumAccess implements IAlbumAccess {
|
|||||||
|
|
||||||
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] })
|
@GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] })
|
||||||
@ChunkedSet({ paramIndex: 1 })
|
@ChunkedSet({ paramIndex: 1 })
|
||||||
async checkSharedAlbumAccess(userId: string, albumIds: Set<string>, readWrite: ReadWrite): Promise<Set<string>> {
|
async checkSharedAlbumAccess(userId: string, albumIds: Set<string>, access: AlbumUserRole): Promise<Set<string>> {
|
||||||
if (albumIds.size === 0) {
|
if (albumIds.size === 0) {
|
||||||
return new Set();
|
return new Set();
|
||||||
}
|
}
|
||||||
@@ -132,8 +133,9 @@ class AlbumAccess implements IAlbumAccess {
|
|||||||
id: In([...albumIds]),
|
id: In([...albumIds]),
|
||||||
sharedUsers: {
|
sharedUsers: {
|
||||||
user: { id: userId },
|
user: { id: userId },
|
||||||
// If write is needed we check for it, otherwise both are accepted
|
// If editor access is needed we check for it, otherwise both are accepted
|
||||||
readonly: readWrite === 'write' ? false : undefined,
|
role:
|
||||||
|
access === AlbumUserRole.Editor ? AlbumUserRole.Editor : In([AlbumUserRole.Editor, AlbumUserRole.Viewer]),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ export class AlbumService {
|
|||||||
throw new BadRequestException('Album not shared with user');
|
throw new BadRequestException('Album not shared with user');
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.albumPermissionRepository.update({ albumId: id, userId }, { readonly: dto.readonly });
|
await this.albumPermissionRepository.update({ albumId: id, userId }, { role: dto.role });
|
||||||
}
|
}
|
||||||
|
|
||||||
private async findOrFail(id: string, options: AlbumInfoOptions) {
|
private async findOrFail(id: string, options: AlbumInfoOptions) {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
removeUserFromAlbum,
|
removeUserFromAlbum,
|
||||||
type AlbumResponseDto,
|
type AlbumResponseDto,
|
||||||
type UserResponseDto,
|
type UserResponseDto,
|
||||||
updateAlbumUser,
|
updateAlbumUser, AlbumUserRole,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk'
|
||||||
import { mdiDotsVertical } from '@mdi/js';
|
import { mdiDotsVertical } from '@mdi/js';
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
import { createEventDispatcher, onMount } from 'svelte';
|
||||||
import { getContextMenuPosition } from '../../utils/context-menu';
|
import { getContextMenuPosition } from '../../utils/context-menu';
|
||||||
@@ -71,10 +71,10 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSetReadonly = async (user: UserResponseDto, readonly: boolean) => {
|
const handleSetReadonly = async (user: UserResponseDto, role: AlbumUserRole) => {
|
||||||
try {
|
try {
|
||||||
await updateAlbumUser({ id: album.id, userId: user.id, updateAlbumUserDto: { readonly } });
|
await updateAlbumUser({ id: album.id, userId: user.id, updateAlbumUserDto: { role } });
|
||||||
const message = readonly ? `Set ${user.name} as viewer` : `Set ${user.name} as editor`;
|
const message = `Set ${user.name} as ${role}`;
|
||||||
dispatch('refreshAlbum');
|
dispatch('refreshAlbum');
|
||||||
notificationController.show({ type: NotificationType.Info, message });
|
notificationController.show({ type: NotificationType.Info, message });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -99,14 +99,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#each album.sharedUsersV2.toSorted((a, b) => {
|
{#each album.sharedUsersV2.toSorted((a, b) => {
|
||||||
if (a.readonly && !b.readonly) {
|
if (a.role === AlbumUserRole.Viewer && b.role === AlbumUserRole.Editor) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!a.readonly && b.readonly) {
|
if (a.role === AlbumUserRole.Editor && b.role === AlbumUserRole.Viewer) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return a.user.name.localeCompare(b.user.name);
|
return a.user.name.localeCompare(b.user.name);
|
||||||
}) as { user, readonly }}
|
}) as { user, role }}
|
||||||
<div
|
<div
|
||||||
class="flex w-full place-items-center justify-between gap-4 p-5 transition-colors hover:bg-gray-50 dark:hover:bg-gray-700"
|
class="flex w-full place-items-center justify-between gap-4 p-5 transition-colors hover:bg-gray-50 dark:hover:bg-gray-700"
|
||||||
>
|
>
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
|
|
||||||
<div id="icon-{user.id}" class="flex place-items-center gap-2">
|
<div id="icon-{user.id}" class="flex place-items-center gap-2">
|
||||||
<div>
|
<div>
|
||||||
{#if readonly}
|
{#if role === AlbumUserRole.Viewer}
|
||||||
Viewer
|
Viewer
|
||||||
{:else}
|
{:else}
|
||||||
Editor
|
Editor
|
||||||
@@ -136,10 +136,10 @@
|
|||||||
|
|
||||||
{#if selectedMenuUser === user}
|
{#if selectedMenuUser === user}
|
||||||
<ContextMenu {...position} on:outclick={() => (selectedMenuUser = null)}>
|
<ContextMenu {...position} on:outclick={() => (selectedMenuUser = null)}>
|
||||||
{#if readonly}
|
{#if role === AlbumUserRole.Viewer}
|
||||||
<MenuOption on:click={() => handleSetReadonly(user, false)} text="Allow edits" />
|
<MenuOption on:click={() => handleSetReadonly(user, AlbumUserRole.Editor)} text="Allow edits" />
|
||||||
{:else}
|
{:else}
|
||||||
<MenuOption on:click={() => handleSetReadonly(user, true)} text="Disallow edits" />
|
<MenuOption on:click={() => handleSetReadonly(user, AlbumUserRole.Viewer)} text="Disallow edits" />
|
||||||
{/if}
|
{/if}
|
||||||
<MenuOption on:click={handleMenuRemove} text="Remove" />
|
<MenuOption on:click={handleMenuRemove} text="Remove" />
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
|
|||||||
@@ -1,84 +1,83 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { afterNavigate, goto } from '$app/navigation';
|
import {afterNavigate, goto} from '$app/navigation'
|
||||||
import AlbumOptions from '$lib/components/album-page/album-options.svelte';
|
import AlbumDescription from '$lib/components/album-page/album-description.svelte'
|
||||||
import ShareInfoModal from '$lib/components/album-page/share-info-modal.svelte';
|
import AlbumOptions from '$lib/components/album-page/album-options.svelte'
|
||||||
import UserSelectionModal from '$lib/components/album-page/user-selection-modal.svelte';
|
import AlbumSummary from '$lib/components/album-page/album-summary.svelte'
|
||||||
import ActivityStatus from '$lib/components/asset-viewer/activity-status.svelte';
|
import AlbumTitle from '$lib/components/album-page/album-title.svelte'
|
||||||
import ActivityViewer from '$lib/components/asset-viewer/activity-viewer.svelte';
|
import ShareInfoModal from '$lib/components/album-page/share-info-modal.svelte'
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
import UserSelectionModal from '$lib/components/album-page/user-selection-modal.svelte'
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import ActivityStatus from '$lib/components/asset-viewer/activity-status.svelte'
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import ActivityViewer from '$lib/components/asset-viewer/activity-viewer.svelte'
|
||||||
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte';
|
import Button from '$lib/components/elements/buttons/button.svelte'
|
||||||
import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'
|
||||||
import ChangeDate from '$lib/components/photos-page/actions/change-date-action.svelte';
|
import Icon from '$lib/components/elements/icon.svelte'
|
||||||
import ChangeLocation from '$lib/components/photos-page/actions/change-location-action.svelte';
|
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte'
|
||||||
import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte';
|
import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte'
|
||||||
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte';
|
import ChangeDate from '$lib/components/photos-page/actions/change-date-action.svelte'
|
||||||
import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte';
|
import ChangeLocation from '$lib/components/photos-page/actions/change-location-action.svelte'
|
||||||
import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte';
|
import CreateSharedLink from '$lib/components/photos-page/actions/create-shared-link.svelte'
|
||||||
import RemoveFromAlbum from '$lib/components/photos-page/actions/remove-from-album.svelte';
|
import DeleteAssets from '$lib/components/photos-page/actions/delete-assets.svelte'
|
||||||
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte';
|
import DownloadAction from '$lib/components/photos-page/actions/download-action.svelte'
|
||||||
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte';
|
import FavoriteAction from '$lib/components/photos-page/actions/favorite-action.svelte'
|
||||||
import AssetSelectContextMenu from '$lib/components/photos-page/asset-select-context-menu.svelte';
|
import RemoveFromAlbum from '$lib/components/photos-page/actions/remove-from-album.svelte'
|
||||||
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte';
|
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte'
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
import AssetGrid from '$lib/components/photos-page/asset-grid.svelte'
|
||||||
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
|
import AssetSelectContextMenu from '$lib/components/photos-page/asset-select-context-menu.svelte'
|
||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
import AssetSelectControlBar from '$lib/components/photos-page/asset-select-control-bar.svelte'
|
||||||
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte'
|
||||||
import CreateSharedLinkModal from '$lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte';
|
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte'
|
||||||
|
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte'
|
||||||
|
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte'
|
||||||
|
import CreateSharedLinkModal
|
||||||
|
from '$lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte'
|
||||||
|
import {notificationController, NotificationType,} from '$lib/components/shared-components/notification/notification'
|
||||||
|
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte'
|
||||||
|
import {AppRoute} from '$lib/constants'
|
||||||
|
import {numberOfComments, setNumberOfComments, updateNumberOfComments} from '$lib/stores/activity.store'
|
||||||
|
import {createAssetInteractionStore} from '$lib/stores/asset-interaction.store'
|
||||||
|
import {assetViewingStore} from '$lib/stores/asset-viewing.store'
|
||||||
|
import {AssetStore} from '$lib/stores/assets.store'
|
||||||
|
import {locale} from '$lib/stores/preferences.store'
|
||||||
|
import {SlideshowNavigation, SlideshowState, slideshowStore} from '$lib/stores/slideshow.store'
|
||||||
|
import {user} from '$lib/stores/user.store'
|
||||||
|
import {handlePromiseError} from '$lib/utils'
|
||||||
|
import {downloadAlbum} from '$lib/utils/asset-utils'
|
||||||
|
import {clickOutside} from '$lib/utils/click-outside'
|
||||||
|
import {getContextMenuPosition} from '$lib/utils/context-menu'
|
||||||
|
import {openFileUploadDialog} from '$lib/utils/file-uploader'
|
||||||
|
import {handleError} from '$lib/utils/handle-error'
|
||||||
import {
|
import {
|
||||||
NotificationType,
|
type ActivityResponseDto,
|
||||||
notificationController,
|
|
||||||
} from '$lib/components/shared-components/notification/notification';
|
|
||||||
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
|
|
||||||
import { AppRoute } from '$lib/constants';
|
|
||||||
import { numberOfComments, setNumberOfComments, updateNumberOfComments } from '$lib/stores/activity.store';
|
|
||||||
import { createAssetInteractionStore } from '$lib/stores/asset-interaction.store';
|
|
||||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
|
||||||
import { AssetStore } from '$lib/stores/assets.store';
|
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
|
||||||
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
|
|
||||||
import { user } from '$lib/stores/user.store';
|
|
||||||
import { downloadAlbum } from '$lib/utils/asset-utils';
|
|
||||||
import { clickOutside } from '$lib/utils/click-outside';
|
|
||||||
import { getContextMenuPosition } from '$lib/utils/context-menu';
|
|
||||||
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
|
||||||
import {
|
|
||||||
ReactionLevel,
|
|
||||||
ReactionType,
|
|
||||||
addAssetsToAlbum,
|
addAssetsToAlbum,
|
||||||
addUsersToAlbum,
|
addUsersToAlbum,
|
||||||
|
AlbumUserRole,
|
||||||
|
AssetOrder,
|
||||||
createActivity,
|
createActivity,
|
||||||
deleteActivity,
|
deleteActivity,
|
||||||
deleteAlbum,
|
deleteAlbum,
|
||||||
getActivities,
|
getActivities,
|
||||||
getActivityStatistics,
|
getActivityStatistics,
|
||||||
getAlbumInfo,
|
getAlbumInfo,
|
||||||
|
ReactionLevel,
|
||||||
|
ReactionType,
|
||||||
updateAlbumInfo,
|
updateAlbumInfo,
|
||||||
type ActivityResponseDto,
|
|
||||||
type UserResponseDto,
|
type UserResponseDto,
|
||||||
AssetOrder,
|
} from '@immich/sdk'
|
||||||
} from '@immich/sdk';
|
|
||||||
import {
|
import {
|
||||||
mdiArrowLeft,
|
mdiArrowLeft,
|
||||||
|
mdiCogOutline,
|
||||||
mdiDeleteOutline,
|
mdiDeleteOutline,
|
||||||
mdiDotsVertical,
|
mdiDotsVertical,
|
||||||
mdiFolderDownloadOutline,
|
mdiFolderDownloadOutline,
|
||||||
mdiLink,
|
|
||||||
mdiPlus,
|
|
||||||
mdiShareVariantOutline,
|
|
||||||
mdiPresentationPlay,
|
|
||||||
mdiCogOutline,
|
|
||||||
mdiImageOutline,
|
mdiImageOutline,
|
||||||
mdiImagePlusOutline,
|
mdiImagePlusOutline,
|
||||||
} from '@mdi/js';
|
mdiLink,
|
||||||
import { fly } from 'svelte/transition';
|
mdiPlus,
|
||||||
import type { PageData } from './$types';
|
mdiPresentationPlay,
|
||||||
import AlbumTitle from '$lib/components/album-page/album-title.svelte';
|
mdiShareVariantOutline,
|
||||||
import AlbumDescription from '$lib/components/album-page/album-description.svelte';
|
} from '@mdi/js'
|
||||||
import { handlePromiseError } from '$lib/utils';
|
import {fly} from 'svelte/transition'
|
||||||
import AlbumSummary from '$lib/components/album-page/album-summary.svelte';
|
import type {PageData} from './$types'
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
@@ -136,8 +135,8 @@
|
|||||||
$: showActivityStatus =
|
$: showActivityStatus =
|
||||||
album.sharedUsers.length > 0 && !$showAssetViewer && (album.isActivityEnabled || $numberOfComments > 0);
|
album.sharedUsers.length > 0 && !$showAssetViewer && (album.isActivityEnabled || $numberOfComments > 0);
|
||||||
|
|
||||||
$: userHasWriteAccess = !album.sharedUsersV2.find(({ user: { id } }) => id === $user.id)?.readonly;
|
$: isEditor = album.sharedUsersV2.find(({ user: { id } }) => id === $user.id)?.role === AlbumUserRole.Editor;
|
||||||
$: albumHasReadonlyUsers = album.sharedUsersV2.some(({ readonly }) => readonly);
|
$: albumHasViewers = album.sharedUsersV2.some(({ role }) => role === AlbumUserRole.Viewer);
|
||||||
|
|
||||||
afterNavigate(({ from }) => {
|
afterNavigate(({ from }) => {
|
||||||
assetViewingStore.showAssetViewer(false);
|
assetViewingStore.showAssetViewer(false);
|
||||||
@@ -436,7 +435,7 @@
|
|||||||
{#if viewMode === ViewMode.VIEW || viewMode === ViewMode.ALBUM_OPTIONS}
|
{#if viewMode === ViewMode.VIEW || viewMode === ViewMode.ALBUM_OPTIONS}
|
||||||
<ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close={() => goto(backUrl)}>
|
<ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close={() => goto(backUrl)}>
|
||||||
<svelte:fragment slot="trailing">
|
<svelte:fragment slot="trailing">
|
||||||
{#if userHasWriteAccess}
|
{#if isEditor}
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
title="Add photos"
|
title="Add photos"
|
||||||
on:click={() => (viewMode = ViewMode.SELECT_ASSETS)}
|
on:click={() => (viewMode = ViewMode.SELECT_ASSETS)}
|
||||||
@@ -584,14 +583,14 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- users with write access (collaborators) -->
|
<!-- users with write access (collaborators) -->
|
||||||
{#each album.sharedUsersV2.filter(({ readonly }) => !readonly) as { user } (user.id)}
|
{#each album.sharedUsersV2.filter(({ role }) => role === AlbumUserRole.Editor) as { user } (user.id)}
|
||||||
<button on:click={() => (viewMode = ViewMode.VIEW_USERS)}>
|
<button on:click={() => (viewMode = ViewMode.VIEW_USERS)}>
|
||||||
<UserAvatar {user} size="md" />
|
<UserAvatar {user} size="md" />
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<!-- display ellipsis if there are readonly users too -->
|
<!-- display ellipsis if there are readonly users too -->
|
||||||
{#if albumHasReadonlyUsers}
|
{#if albumHasViewers}
|
||||||
<CircleIconButton
|
<CircleIconButton
|
||||||
title="View all users"
|
title="View all users"
|
||||||
backgroundColor="#d3d3d3"
|
backgroundColor="#d3d3d3"
|
||||||
|
|||||||
Reference in New Issue
Block a user