Skip to content

Commit

Permalink
Add context option [CloudinaryFile]
Browse files Browse the repository at this point in the history
  • Loading branch information
djade007 committed Jul 27, 2021
1 parent 06ff29b commit d4788e5
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 35 deletions.
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## 0.9.0
- Add context option [CloudinaryFile]

## 0.8.2
- Add folder option to CloudinaryFile
- Add folder option to [CloudinaryFile]

## 0.8.1+1

Expand All @@ -11,7 +14,7 @@

## 0.7.0

- Added CloudinaryException
- Added [CloudinaryException]
- Replace Dio dependency with http

## 0.6.2
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ secretKey.

## Getting started

Add the dependency `cloudinary_public: ^0.8.2` to your project:
Add the dependency `cloudinary_public: ^0.9.0` to your project:

```dart
import 'package:cloudinary_public/cloudinary_public.dart';
Expand Down
4 changes: 4 additions & 0 deletions example/lib/src/image_picker_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ class _ImagePickerExampleState extends State<ImagePickerExample> {
CloudinaryFile.fromFile(
_pickedFile.path,
folder: 'hello-folder',
context: {
'alt': 'Hello',
'caption': 'An example image',
},
),
);
print(res);
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ packages:
path: ".."
relative: true
source: path
version: "0.8.1+1"
version: "0.9.0"
collection:
dependency: transitive
description:
Expand Down
62 changes: 39 additions & 23 deletions lib/src/cloudinary_file.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ class CloudinaryFile {
/// File tags
final List<String>? tags;

/// A pipe-separated list of the key-value pairs of contextual metadata to
/// attach to an uploaded asset.
///
/// Eg: {'alt': 'My image', 'caption': 'Profile image'}
final Map<String, dynamic>? context;

/// Determine if initialized from [CloudinaryFile.fromUrl]
bool get fromExternalUrl => url != null;

Expand All @@ -44,6 +50,7 @@ class CloudinaryFile {
this.url,
this.tags,
this.folder,
this.context,
}) : assert(
(byteData == null && filePath != null) ||
(byteData != null && filePath == null) ||
Expand All @@ -69,14 +76,17 @@ class CloudinaryFile {
CloudinaryResourceType resourceType: CloudinaryResourceType.Auto,
List<String>? tags,
String? folder,
}) =>
CloudinaryFile(
byteData: byteData,
identifier: identifier,
resourceType: resourceType,
tags: tags,
folder: folder,
);
Map<String, dynamic>? context,
}) {
return CloudinaryFile(
byteData: byteData,
identifier: identifier,
resourceType: resourceType,
tags: tags,
folder: folder,
context: context,
);
}

/// Instantiate [CloudinaryFile] from [File] path
factory CloudinaryFile.fromFile(
Expand All @@ -85,28 +95,34 @@ class CloudinaryFile {
CloudinaryResourceType resourceType: CloudinaryResourceType.Auto,
List<String>? tags,
String? folder,
}) =>
CloudinaryFile(
filePath: path,
identifier: identifier ??= path.split('/').last,
resourceType: resourceType,
tags: tags,
folder: folder,
);
Map<String, dynamic>? context,
}) {
return CloudinaryFile(
filePath: path,
identifier: identifier ??= path.split('/').last,
resourceType: resourceType,
tags: tags,
folder: folder,
context: context,
);
}

/// Instantiate [CloudinaryFile] from an external url
factory CloudinaryFile.fromUrl(
String url, {
CloudinaryResourceType resourceType: CloudinaryResourceType.Auto,
List<String>? tags,
String? folder,
}) =>
CloudinaryFile(
url: url,
identifier: url,
resourceType: resourceType,
folder: folder,
);
Map<String, dynamic>? context,
}) {
return CloudinaryFile(
url: url,
identifier: url,
resourceType: resourceType,
folder: folder,
context: context,
);
}

/// Convert [CloudinaryFile] to [MultipartFile]
Future<http.MultipartFile> toMultipartFile(
Expand Down
25 changes: 20 additions & 5 deletions lib/src/cloudinary_public.dart
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,33 @@ class CloudinaryPublic {
data['tags'] = file.tags!.join(',');
}

if (file.context != null && file.context!.isNotEmpty) {
String context = '';

file.context!.forEach((key, value) {
context += '|$key=$value';
});

// remove the extra `|` at the beginning
data['context'] = context.replaceFirst('|', '');
}

request.fields.addAll(data);

final sendRequest = await client!.send(request);

final res = await http.Response.fromStream(sendRequest);

if (res.statusCode != 200) {
throw CloudinaryException(res.body, res.statusCode, request: {
'url': file.url,
'path': file.filePath,
'identifier': file.identifier,
});
throw CloudinaryException(
res.body,
res.statusCode,
request: {
'url': file.url,
'path': file.filePath,
'identifier': file.identifier,
},
);
}

final cloudinaryResponse = CloudinaryResponse.fromMap(
Expand Down
12 changes: 12 additions & 0 deletions lib/src/cloudinary_response.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@ class CloudinaryResponse {
final String secureUrl;
final String originalFilename;
final List<String> tags;
final Map<String, dynamic> context;
final bool fromCache;

/// Extract and return the image context
Map<String, String> get customContext {
if (context['custom'] != null) return Map.castFrom(context['custom']);

return {};
}

CloudinaryResponse({
required this.assetId,
required this.publicId,
Expand All @@ -17,6 +25,7 @@ class CloudinaryResponse {
required this.secureUrl,
required this.originalFilename,
this.tags: const [],
this.context: const {},
this.fromCache: false,
});

Expand All @@ -32,6 +41,7 @@ class CloudinaryResponse {
tags: data['tags'] != null
? (data['tags'] as List).map((tag) => tag as String).toList()
: [],
context: data['context'] is Map ? data['context'] : {},
);
}

Expand All @@ -45,6 +55,7 @@ class CloudinaryResponse {
secureUrl: secureUrl,
originalFilename: originalFilename,
tags: tags,
context: context,
fromCache: true,
);
}
Expand All @@ -59,6 +70,7 @@ class CloudinaryResponse {
'secure_url': secureUrl,
'original_filename': originalFilename,
'tags': tags,
'context': context,
};
}

Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: cloudinary_public
description: This package allows you to upload media files directly to cloudinary, without exposing your apiKey or secretKey.
version: 0.8.2
version: 0.9.0
homepage: https://github.com/djade007/cloudinary_public

environment:
Expand Down
16 changes: 14 additions & 2 deletions test/cloudinary_public_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,13 @@ void main() {
);

final file = CloudinaryFile.fromFile(tempFile.path,
resourceType: CloudinaryResourceType.Image, tags: ['trip']);
resourceType: CloudinaryResourceType.Image,
tags: [
'trip'
],
context: {
'alt': 'Image',
});
final res = await cloudinary.uploadFile(file);
expect(res, TypeMatcher<CloudinaryResponse>());

Expand Down Expand Up @@ -229,5 +235,11 @@ const _sampleResponse = {
'http://res.cloudinary.com/$cloudName/image/upload/v1590212116/psryios0nkgpf1h4um3h.jpg',
'secure_url':
'https://res.cloudinary.com/$cloudName/image/upload/v1590212116/psryios0nkgpf1h4um3h.jpg',
'original_filename': '001'
'original_filename': '001',
'context': {
'custom': {
'alt': 'image',
'caption': 'Example image',
}
}
};

0 comments on commit d4788e5

Please sign in to comment.