Skip to content

Commit bab6de2

Browse files
Merge pull request #1 from dart-pacotes/null-safety
Null safety
2 parents 059ec37 + 3c577d4 commit bab6de2

16 files changed

+401
-265
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,6 @@ pubspec.lock
7979

8080
# Ignore .metadata
8181
.metadata
82+
83+
# Ignore test coverage
84+
coverage

README.md

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,57 @@
11
# pastebin
22

3-
A pure Dart Pastebin API Wrapper.
3+
A pure Dart Pastebin API Wrapper.
4+
5+
## Features
6+
7+
This package covers every endpoint disclosed in [Pastebin API documentation](https://pastebin.com/doc_api#9) (as of 16 May, 2022). The following table links the endpoints to the respective package functions:
8+
9+
|API Endpoints|Function|Description|
10+
|-------------|--------|-----------|
11+
|[`/api/api_post.php` (2-8)](https://pastebin.com/doc_api#2)|[`paste(pasteText, options)`](https://pub.dev/documentation/pastebin/latest/pastebin/PastebinClient/paste.html)|Publishes a paste (with support for optional parameters) in Pastebin.|
12+
|[`/api/api_login.php` (9)](https://pastebin.com/doc_api#9)|[`apiUserKey(username, password)`](https://pub.dev/documentation/pastebin/latest/pastebin/PastebinClient/apiUserKey.html)|Retrieves and refreshes user API key (not developer key).|
13+
|[`/api/api_post.php` (10)](https://pastebin.com/doc_api#10)|[`pastes(userKey, limit=50)`](https://pub.dev/documentation/pastebin/latest/pastebin/PastebinClient/pastes.html)|Fetches an user pastes, with support for limiting how many pastes are returned.|
14+
|[`/api/api_post.php` (11)](https://pastebin.com/doc_api#11)|[`delete(pasteKey, userKey)`](https://pub.dev/documentation/pastebin/latest/pastebin/PastebinClient/delete.html)|Deletes an user paste.|
15+
|[`/api/api_post.php` (12)](https://pastebin.com/doc_api#12)|[`userInfo(userKey)`](https://pub.dev/documentation/pastebin/latest/pastebin/PastebinClient/userInfo.html)|Obtains user information and settings.|
16+
|[`/api/api_raw.php` (13)](https://pastebin.com/doc_api#13)|[`rawPaste(pasteKey, visibility, userKey)`](https://pub.dev/documentation/pastebin/latest/pastebin/PastebinClient/userInfo.html)|Gets the raw paste (full text) of a user paste.|
17+
|[`/api/raw.php` (14)](https://pastebin.com/doc_api#14)|[`rawPaste(pasteKey, visibility)`](https://pub.dev/documentation/pastebin/latest/pastebin/PastebinClient/userInfo.html)|Gets the raw paste (full text) of paste.|
18+
19+
There is also support for multiple API key ingestion, a neat feature for making sure that pastes are published, even if you are rate limited by Pastebin.
20+
21+
```dart
22+
// Using Official Pastebin API with a single API Dev Key
23+
var pastebinClient = withSingleApiDevKey(
24+
apiDevKey: primaryApiDevKey,
25+
);
26+
27+
// Using Official Pastebin API with multiple API Dev Key
28+
pastebinClient = withMultipleApiDevKey(
29+
apiDevKeys: [
30+
primaryApiDevKey,
31+
fallbackApiDevKey1,
32+
fallbackApiDevKey2,
33+
...
34+
fallbackApiDevKeyN,
35+
],
36+
);
37+
```
38+
39+
## Side Effects
40+
41+
Powered by Dart null sound + [`dartz`](https://pub.dev/packages/dartz) monads, this package is free of null issues and side effects. This is to prevent the throw of any exception that may not be known and caught by developers, and to make sure that information is consistent by contract.
42+
43+
Every HTTP request returns an `Either` monad that either returns the response result on the right hand, or `ResponseError` instance on the left hand that is typed to each possible Pastebin error (see available errors [here](https://pub.dev/documentation/pastebin/latest/pastebin/RequestError-class.html)).
44+
45+
## Why use pastebin.dart?
46+
47+
The main use case that inspired the development of this package, is to provide developers (mostly indie) a way to publish and read app logs for free.
48+
49+
---
50+
51+
### Bugs and Contributions
52+
53+
Found any bug (including typos) in the package? Do you have any suggestion or feature to include for future releases? Please create an issue via GitHub in order to track each contribution. Also, pull requests are very welcome!
54+
55+
### Disclaimer
56+
57+
This is not an official library/SDK implemented by the Pastebin team, but rather a developer implementation that uses it.

analysis_options.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
include: package:effective_dart/analysis_options.yaml # https://pub.dartlang.org/packages/effective_dart
21
linter: # Lint rules: http://dart-lang.github.io/linter/lints/
32
rules:
43
public_member_api_docs: false
@@ -17,4 +16,4 @@ linter: # Lint rules: http://dart-lang.github.io/linter/lints/
1716
unawaited_futures: false # https://dart-lang.github.io/linter/lints/unawaited_futures.html
1817
unnecessary_statements: true # http://dart-lang.github.io/linter/lints/unnecessary_statements.html
1918
unrelated_type_equality_checks: true # https://dart-lang.github.io/linter/lints/unrelated_type_equality_checks.html
20-
valid_regexps: true # https://dart-lang.github.io/linter/lints/valid_regexps.html
19+
valid_regexps: true # https://dart-lang.github.io/linter/lints/valid_regexps.html

example/pubspec.yaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
name: example
22
version: 1.0.0
3+
publish_to: none
34

45
environment:
56
sdk: ">=2.7.0 <3.0.0"
67

7-
dependencies:
8+
dependencies:
89
pastebin:
910
path: ../
10-
11-
dev_dependencies:

lib/src/models/expire_date.dart

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ enum ExpireDate {
1212
oneYear,
1313
}
1414

15-
extension ExpireDateExtension on ExpireDate {
15+
extension ExpireDateExtension on ExpireDate? {
1616
static const Map<ExpireDate, String> values = {
1717
ExpireDate.never: 'N',
1818
ExpireDate.tenMinutes: '10M',
@@ -25,18 +25,19 @@ extension ExpireDateExtension on ExpireDate {
2525
};
2626

2727
static ExpireDate parse(
28-
final String expireDate,
29-
final MapEntry<ExpireDate, String> Function() onError,
28+
final String? expireDate,
29+
final MapEntry<ExpireDate, String>? Function() onError,
3030
) {
3131
return values.entries
32-
.firstWhere((entry) => entry.value == expireDate, orElse: onError)
32+
.firstWhere((entry) => entry.value == expireDate,
33+
orElse: onError as MapEntry<ExpireDate, String> Function()?)
3334
.key;
3435
}
3536

36-
static ExpireDate tryParse(final String expireDate) =>
37+
static ExpireDate tryParse(final String? expireDate) =>
3738
parse(expireDate, () => null);
3839

39-
String value() {
40-
return values[this];
40+
String? value() {
41+
return values[this!];
4142
}
4243
}

lib/src/models/format.dart

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ enum Format {
258258
zxbasic
259259
}
260260

261-
extension FormatExtension on Format {
261+
extension FormatExtension on Format? {
262262
static const Map<Format, String> values = {
263263
Format.cs4: '4cs',
264264
Format.acme6502: '6502acme',
@@ -517,17 +517,18 @@ extension FormatExtension on Format {
517517
};
518518

519519
static Format parse(
520-
final String format,
521-
final MapEntry<Format, String> Function() onError,
520+
final String? format,
521+
final MapEntry<Format, String>? Function() onError,
522522
) {
523523
return values.entries
524-
.firstWhere((entry) => entry.value == format, orElse: onError)
524+
.firstWhere((entry) => entry.value == format,
525+
orElse: onError as MapEntry<Format, String> Function()?)
525526
.key;
526527
}
527528

528-
static Format tryParse(final String format) => parse(format, () => null);
529+
static Format tryParse(final String? format) => parse(format, () => null);
529530

530-
String value() {
531-
return values[this];
531+
String? value() {
532+
return values[this!];
532533
}
533534
}

lib/src/models/paste.dart

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'package:meta/meta.dart';
21
import 'package:xml/xml.dart';
32

43
import 'models.dart';
@@ -7,34 +6,34 @@ import 'models.dart';
76
/// Models a Pastebin paste
87
///
98
class Paste {
10-
final String key;
9+
final String? key;
1110

1211
final DateTime createdDate;
1312

1413
final DateTime expiredDate;
1514

16-
final String title;
15+
final String? title;
1716

18-
final int sizeInBytes;
17+
final int? sizeInBytes;
1918

2019
final Visibility visibility;
2120

2221
final Format format;
2322

24-
final Uri url;
23+
final Uri? url;
2524

26-
final int hits;
25+
final int? hits;
2726

2827
const Paste({
29-
@required this.createdDate,
30-
@required this.expiredDate,
31-
@required this.format,
32-
@required this.hits,
33-
@required this.key,
34-
@required this.sizeInBytes,
35-
@required this.title,
36-
@required this.url,
37-
@required this.visibility,
28+
required this.createdDate,
29+
required this.expiredDate,
30+
required this.format,
31+
required this.hits,
32+
required this.key,
33+
required this.sizeInBytes,
34+
required this.title,
35+
required this.url,
36+
required this.visibility,
3837
});
3938

4039
static List<Paste> fromXmlDocument(final XmlDocument xmlDocument) {
@@ -44,22 +43,22 @@ class Paste {
4443
static Paste fromXmlNode(final XmlNode xmlNode) {
4544
return Paste(
4645
createdDate: DateTime.fromMillisecondsSinceEpoch(
47-
int.tryParse(xmlNode.getElement('paste_date')?.text),
46+
int.tryParse(xmlNode.getElement('paste_date')!.text)!,
4847
),
4948
expiredDate: DateTime.fromMillisecondsSinceEpoch(
50-
int.tryParse(xmlNode.getElement('paste_expire_date')?.text),
49+
int.tryParse(xmlNode.getElement('paste_expire_date')!.text)!,
5150
),
5251
format: FormatExtension.tryParse(
5352
xmlNode.getElement('paste_format_short')?.text,
5453
),
5554
visibility: VisibilityExtension.tryParse(
5655
xmlNode.getElement('paste_private')?.text,
5756
),
58-
hits: int.tryParse(xmlNode.getElement('paste_hits')?.text),
57+
hits: int.tryParse(xmlNode.getElement('paste_hits')!.text),
5958
key: xmlNode.getElement('paste_key')?.text,
60-
sizeInBytes: int.tryParse(xmlNode.getElement('paste_size')?.text),
59+
sizeInBytes: int.tryParse(xmlNode.getElement('paste_size')!.text),
6160
title: xmlNode.getElement('paste_title')?.text,
62-
url: Uri.tryParse(xmlNode.getElement('paste_url')?.text),
61+
url: Uri.tryParse(xmlNode.getElement('paste_url')!.text),
6362
);
6463
}
6564
}

lib/src/models/paste_options.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ import 'visibility.dart';
66
/// Model for available settings of a [Paste] that can be set
77
///
88
class PasteOptions {
9-
final String apiUserKey;
9+
final String? apiUserKey;
1010

11-
final String pasteName;
11+
final String? pasteName;
1212

13-
final Format pasteFormat;
13+
final Format? pasteFormat;
1414

15-
final Visibility pasteVisiblity;
15+
final Visibility? pasteVisiblity;
1616

17-
final ExpireDate pasteExpireDate;
17+
final ExpireDate? pasteExpireDate;
1818

1919
const PasteOptions({
2020
this.apiUserKey,

lib/src/models/user_info.dart

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'package:meta/meta.dart';
21
import 'package:xml/xml.dart';
32

43
import 'models.dart';
@@ -7,47 +6,49 @@ import 'models.dart';
76
/// Models the information and settings of Pastebin user
87
///
98
class UserInfo {
10-
final String userName;
9+
final String? userName;
1110

1211
final Format format;
1312

1413
final ExpireDate expiration;
1514

16-
final Uri avatarUrl;
15+
final Uri? avatarUrl;
1716

1817
final Visibility visibility;
1918

20-
final String website;
19+
final String? website;
2120

22-
final String email;
21+
final String? email;
2322

24-
final String location;
23+
final String? location;
2524

26-
final bool isPro;
25+
final bool? isPro;
2726

2827
const UserInfo({
29-
@required this.avatarUrl,
30-
@required this.email,
31-
@required this.expiration,
32-
@required this.format,
33-
@required this.isPro,
34-
@required this.location,
35-
@required this.userName,
36-
@required this.visibility,
37-
@required this.website,
28+
required this.avatarUrl,
29+
required this.email,
30+
required this.expiration,
31+
required this.format,
32+
required this.isPro,
33+
required this.location,
34+
required this.userName,
35+
required this.visibility,
36+
required this.website,
3837
});
3938

4039
static UserInfo fromXmlNode(final XmlNode xmlNode) {
4140
return UserInfo(
42-
avatarUrl: Uri.tryParse(xmlNode.getElement('user_avatar_url')?.text),
41+
avatarUrl: Uri.tryParse(
42+
xmlNode.getElement('user_avatar_url')?.text ?? '',
43+
),
4344
email: xmlNode.getElement('user_email')?.text,
4445
expiration: ExpireDateExtension.tryParse(
4546
xmlNode.getElement('user_expiration')?.text,
4647
),
4748
format: FormatExtension.tryParse(
4849
xmlNode.getElement('user_format_short')?.text,
4950
),
50-
isPro: xmlNode.getElement('user_format_short')?.text?.endsWith('1'),
51+
isPro: xmlNode.getElement('user_format_short')?.text.endsWith('1'),
5152
location: xmlNode.getElement('user_location')?.text,
5253
userName: xmlNode.getElement('user_name')?.text,
5354
visibility: VisibilityExtension.tryParse(

lib/src/models/visibility.dart

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,27 @@ enum Visibility {
77
private,
88
}
99

10-
extension VisibilityExtension on Visibility {
10+
extension VisibilityExtension on Visibility? {
1111
static const Map<Visibility, String> values = {
1212
Visibility.public: '0',
1313
Visibility.unlisted: '1',
1414
Visibility.private: '2',
1515
};
1616

1717
static Visibility parse(
18-
final String visibility,
19-
final MapEntry<Visibility, String> Function() onError,
18+
final String? visibility,
19+
final MapEntry<Visibility, String>? Function() onError,
2020
) {
2121
return values.entries
22-
.firstWhere((entry) => entry.value == visibility, orElse: onError)
22+
.firstWhere((entry) => entry.value == visibility,
23+
orElse: onError as MapEntry<Visibility, String> Function()?)
2324
.key;
2425
}
2526

26-
static Visibility tryParse(final String visibility) =>
27+
static Visibility tryParse(final String? visibility) =>
2728
parse(visibility, () => null);
2829

29-
String value() {
30-
return values[this];
30+
String? value() {
31+
return values[this!];
3132
}
3233
}

0 commit comments

Comments
 (0)