diff --git a/CHANGELOG.md b/CHANGELOG.md
index 051a2f3..452fdb2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,106 +1,111 @@
+## 8.5.4
+
+- Added support for creating media from bytes
+- Updated documentation
+
## 8.5.3
-- ๐ฉน Fix invalid base url on web
+- Fix invalid base url on web
## 8.5.2
-- ๐ฉน Fix versions
+- Fix versions
## 8.5.1
-- ๐ฉน Fix dio sendTimeout exception
+- Fix dio sendTimeout exception
## 8.5.0
-- ๐ Added support for initialize the client without a base url.
+- Added support for initializing the client without a base url.
- Use the `WordpressClient.generic` constructor to initialize the client without a base url.
- Use the `reconfigure` method to set the base url after initializing the client.
- Failure to set the base url will throw an exception when making requests.
-- ๐ Added `isAuthenticated` method to check if the current instance has a valid authentication.
+- Added `isAuthenticated` method to check if the current instance has a valid authentication.
- Optionally, pass an instance of `IAuthorization` to check if the client is authenticated with the given authorization.
- ๐ฅ Deprecated `reconfigureClient` method in favour of `reconfigure` method.
## 8.4.10
-- ๐ฉน Fix bug on clearing middleware list
+- Fix bug on clearing middleware list
## 8.4.9
-- ๐ฆ Downgrade meta package to match flutter meta version
+- Downgrade meta package to match flutter meta version
## 8.4.8
-- ๐ฉน Bug fixes
+- Bug fixes
- ๐ฅ Deprecated `WordpressClient.initialize(...)` ctor and `initialize()` method
-- ๐ Added `WordpressClient.fromDioInstance(...)` constructor
+- Added `WordpressClient.fromDioInstance(...)` constructor
## 8.4.7
-- ๐ฉน Bug fixes
-- ๐ Fix validations for entered `baseUrl`; Supporting sites with custom REST Api paths
+- Bug fixes
+- Fix validations for entered `baseUrl`; Supporting sites with custom REST Api paths
## 8.4.6
-- ๐ฉน Bug fixes
-- ๐ Added validations for entered `baseUrl`
+- Bug fixes
+- Added validations for entered `baseUrl`
- ๐ฅ Renamed `executeGuarded` to `guardAsync` and added `guard` method
## 8.4.5
-- ๐ฉน Bug fixes
+- Bug fixes
## 8.4.4
-- ๐ฉน Bug fixes
+- Bug fixes
## 8.4.3
-- ๐ New static method to check if a site is built using WordPress
+- New static method to check if a site is built using WordPress
## 8.4.2
-- ๐ฉน Bug fixes
-- ๐ Added static methods to validate base URL and discover a website
+- Bug fixes
+- Added static methods to validate base URL and discover a website
## 8.4.1
-- ๐ Introduce `ParallelWordpress` class to generate and execute parallel requests
-- ๐ Bug fixes
+- Introduce `ParallelWordpress` class to generate and execute parallel requests
+- Bug fixes
## 8.4.0
-- ๐ Added support for Middlewares
+- Added support for Middlewares
- ๐ฅ Removed dependency on `synchronised` package
## 8.3.10
-- ๐ฉน Bug fixes
+- Bug fixes
## 8.3.9
-- ๐ฉน Bug fixes
-- ๐ Iterate over the raw response of the endpoint using [] operator
+- Bug fixes
+- Iterate over the raw response of the endpoint using [] operator
## 8.3.8
-- ๐ Renamed retrive -> retrieve. Fix typo
+- Renamed retrive -> retrieve. Fix typo
## 8.3.7
-- ๐ Support for raw requests
-- ๐ Bug fixes
+- Support for raw requests
+- Bug fixes
## 8.3.6
-- ๐ฉน Bug fixes on enum parsing
+- Bug fixes on enum parsing
## 8.3.5
-- ๐ฉน Bug fixes on comment list request
+- Bug fixes on comment list request
## 8.3.4
-- ๐ Media response model null exception when parsing if media details is empty
+- Media response model null exception when parsing if media details is empty
## 8.3.3
@@ -120,73 +125,73 @@
## 8.3.0
-- ๐ Supports Application Password endpoint
+- Supports Application Password endpoint
- Packages update
## 8.2.2
-- ๐ Bug fixes
+- Bug fixes
## 8.2.1
-- ๐ Fixed exporting WordPressDiscovery class
+- Fixed exporting WordPressDiscovery class
## 8.2.0
-- ๐ Added support for Pages endpoint
+- Added support for Pages endpoint
## 8.1.0
-- ๐ Added ability to fetch and cache the discovery endpoint of WordPress REST API
+- Added ability to fetch and cache the discovery endpoint of WordPress REST API
## 8.0.11
-- โ Added `extra` property to all request classes
-- โ Added `addAllIfNotNull(...)` extension method
+- Added `extra` property to all request classes
+- Added `addAllIfNotNull(...)` extension method
## 8.0.10
-- ๐ `featured_media_src_url` key now decodes as expected
-- โ Added `decodeByMultiKeys` method
+- `featured_media_src_url` key now decodes as expected
+- Added `decodeByMultiKeys` method
## 8.0.9
-- โ Added App Password support
+- Added App Password support
## 8.0.8
-- ๐ง Integrated new lint rules and code refactors
+- Integrated new lint rules and code refactors
## 8.0.7
-- ๐ Bug fixes
-- โ Introduced `RequestErrorType` for failure responses
-- โ Introduced `mapGuarded(...)` and `executeGuarded(...)` methods
-- ๐ง Usual refactors and improvements
+- Bug fixes
+- Introduced `RequestErrorType` for failure responses
+- Introduced `mapGuarded(...)` and `executeGuarded(...)` methods
+- Usual refactors and improvements
## 8.0.6
-- ๐ Docs update
+- Docs update
## 8.0.5
-- ๐ฉน Bug fixes and improvements
+- Bug fixes and improvements
## 8.0.4
-- ๐ฉน Bug fixes and improvements
+- Bug fixes and improvements
## 8.0.3
-- ๐ค Export response extensions
+- Export response extensions
## 8.0.2
-- ๐ฝ Downgrade collection version
+- Downgrade collection version
## 8.0.1
-- ๐ Docs update
+- Docs update
## 8.0.0
@@ -198,114 +203,114 @@
## 6.3.1
-- ๐ Implemented search endpoint
+- Implemented search endpoint
## 6.3.0
-- ๐ Major changes in the API
+- Major changes in the API
## 6.2.1-pre
-- ๐งช Misc changes
+- Misc changes
## 6.2.0-pre
-- ๐ง Refactoring, Request Synchronization, and Debug Mode
+- Refactoring, Request Synchronization, and Debug Mode
## 6.1.7-pre to 6.1.9-pre
-- ๐ง Refactoring & Bug fixes
+- Refactoring & Bug fixes
## 6.1.6-pre
-- ๐ Support 3xx series responses (Cached Response)
+- Support 3xx series responses (Cached Response)
## 6.1.5-pre
-- โ Added Post extension for Media and Author
+- Added Post extension for Media and Author
## 6.1.3-pre & 6.1.4-pre
-- ๐ฉน Bug fixes
+- Bug fixes
## 6.1.2-pre
-- ๐ Version fix
+- Version fix
## 6.1.1-pre
-- ๐๏ธ Removed test package
+- Removed test package
## 6.1.0-pre
-- ๐ Entire API changed
-- ๐ Fluency maintained using Dart's cascading operator
-- โก Performance and memory consumption improvements
+- Entire API changed
+- Fluency maintained using Dart's cascading operator
+- Performance and memory consumption improvements
## 5.4.3
-- ๐ Total pages parsing fix
+- Total pages parsing fix
## 5.4.2
-- ๐ฆ Packages fix
+- Packages fix
## 5.4.1
-- ๐ Null safety fix
+- Null safety fix
## 5.4.0
-- ๐ฆ Packages update
+- Packages update
## 5.3.1
-- ๐ Response structure fix
+- Response structure fix
## 5.3.0
-- ๐ฉน Bug fix
+- Bug fix
## 5.2.9
-- ๐ฉน Bug Fix
+- Bug Fix
## 5.2.8
-- ๐ Revert author meta & featured image removal
+- Revert author meta & featured image removal
## 5.2.7
-- ๐ฉน Bug fix
+- Bug fix
## 5.2.6
-- โ๏ธ Experimental Request Caching system
+- Experimental Request Caching system
## 5.2.5
-- ๐ BREAKING CHANGE: Remove Author Meta & Featured Image URL Fields from Post response
+- ๐ฅ BREAKING CHANGE: Remove Author Meta & Featured Image URL Fields from Post response
## 5.2.4
-- ๐๏ธ Remove unused package
+- Remove unused package
## 5.2.3
-- ๐ BREAKING CHANGE: Request API Change
+- ๐ฅ BREAKING CHANGE: Request API Change
## 5.1.1
-- ๐ Formatting changes
+- Formatting changes
## 5.1.0
-- ๐ BREAKING CHANGE: Authorization API Change
+- ๐ฅ BREAKING CHANGE: Authorization API Change
## 5.0.4
-- ๐ Fixed Authorization Bugs
+- Fixed Authorization Bugs
## 4.0.0
-- ๐ Initial version, created by Stagehand
+- Initial version, created by Stagehand
diff --git a/README.md b/README.md
index 24276f3..5824aef 100644
--- a/README.md
+++ b/README.md
@@ -2,20 +2,25 @@
WordPress Client
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
- A powerful and easy-to-use WordPress REST API client for Dart & Flutter.
-
-
+ A powerful and easy-to-use WordPress REST API client for Dart & Flutter.
+
-## โจ Features
+## ๐ Features
- ๐ฆ API discovery support.
- โฒ๏ธ Measures request completion time.
@@ -32,19 +37,21 @@
If you find any functionality which you require is missing from the package and you are not able to work it out using built in options like raw requests etc, then please share the functionality in details as a comment here: https://github.com/ArunPrakashG/wordpress_client/discussions/55
-## ๐ How to Use
+## ๐ฆ Installation
-### **1. Setup**
-
-Add `wordpress_client` in your `pubspec.yaml`:
+Add `wordpress_client` to your `pubspec.yaml`:
```dart
dependencies:
- wordpress_client: ^8.4.8
+ wordpress_client: ^8.5.3
```
> ๐ก Ensure you get the [latest version here](https://pub.dev/packages/wordpress_client).
+Then run `flutter pub get` to install the package.
+
+## ๐ง Usage
+
Import the package where you need:
```dart
@@ -153,23 +160,22 @@ By Useful Team, this is another implementation using JWT for authentication purp
Learn how to implement [Custom Requests here](https://github.com/ArunPrakashG/wordpress_client/wiki/Using-Custom-Requests).
-## ๐ฃ Feedback
+## ๐ค Feedback & Contributing
- ๐ For bugs or feature requests, use the [issue tracker][tracker].
- ๐ก Contributions are always appreciated. PRs are welcome!
-## ๐ License
+## ๐ License
-Licensed under [MIT](https://github.com/ArunPrakashG/wordpress_client/blob/master/LICENSE).
-
-[tracker]: https://github.com/ArunPrakashG/wordpress_client/issues
+This project is [MIT](https://github.com/ArunPrakashG/wordpress_client/blob/master/LICENSE) licensed.
---
-
-Support Me:
+ If you find this package helpful, consider supporting the development:
[![Buy Me A Coffee](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/arunprakashg)
+
+[tracker]: https://github.com/ArunPrakashG/wordpress_client/issues
diff --git a/analysis_options.yaml b/analysis_options.yaml
index aefa97f..a5228d6 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,3 +1,6 @@
+analyzer:
+ errors:
+ avoid_positional_boolean_parameters: ignore
include: package:personal_flutter_lints/analysis_options.yaml
linter:
diff --git a/lib/src/authorization/authorization_base.dart b/lib/src/authorization/authorization_base.dart
index eb6a0fa..277825b 100644
--- a/lib/src/authorization/authorization_base.dart
+++ b/lib/src/authorization/authorization_base.dart
@@ -4,13 +4,38 @@ import 'package:meta/meta.dart';
import '../../wordpress_client.dart';
import '../utilities/helpers.dart';
-/// Base class for all authorization types.
+/// Base class for all authorization types in the WordPress client.
///
-/// To implement a custom authorization system, You _must_ extend this class.
+/// To implement a custom authorization system, you must extend this class.
///
-/// Note that, there is no storage system internally to store and retrive
+/// Note: There is no built-in storage system to store and retrieve credentials.
+/// You need to implement your own storage mechanism if required.
+///
+/// Example of a custom authorization implementation:
+/// ```dart
+/// class CustomAuth extends IAuthorization {
+/// CustomAuth({required String userName, required String password})
+/// : super(userName: userName, password: password);
+///
+/// @override
+/// String get scheme => 'Custom';
+///
+/// @override
+/// Future authorize() async {
+/// // Implement your custom authorization logic here
+/// return true;
+/// }
+///
+/// // Implement other required methods...
+/// }
+/// ```
abstract base class IAuthorization {
/// Creates a new instance of [IAuthorization] with the given username and password.
+ ///
+ /// [userName]: The username for authentication.
+ /// [password]: The password for authentication.
+ /// [headerKey]: The HTTP header key to use for authorization (default is 'Authorization').
+ /// [events]: Optional [WordpressEvents] to listen to during the authorization process.
IAuthorization({
required this.userName,
required this.password,
@@ -18,35 +43,38 @@ abstract base class IAuthorization {
this.events,
});
- /// The base url of the wordpress site.
+ /// The base URL of the WordPress site.
late final Uri baseUrl;
- /// The username
+ /// The username for authentication.
final String userName;
- /// The password
+ /// The password for authentication.
final String password;
- /// The header key to use for authorization.
+ /// The HTTP header key to use for authorization.
final String headerKey;
- /// The events to listen to.
+ /// Optional events to listen to during the authorization process.
WordpressEvents? events;
- /// Gets if this authorization instance has valid authentication nounce. (token/encryptedToken)
+ /// Indicates if this authorization instance has a valid authentication nonce (token/encryptedToken).
bool get isValidAuth;
- /// Gets if this is an invalid or default authorization instance without username or password fields.
+ /// Indicates if this is an invalid or default authorization instance without username or password fields.
bool get isDefault => isNullOrEmpty(userName) || isNullOrEmpty(password);
- /// Gets the authorization scheme.
+ /// Gets the authorization scheme (e.g., 'Bearer' for JWT, 'Basic' for Basic Auth).
String get scheme;
- /// Helps to initialize authorization instance with internal requesting client passed as a parameter.
+ /// Initializes the authorization instance with the internal requesting client.
///
- /// This function is called only if there is no valid nounce available i.e., when isAuthenticated() returns false.
+ /// This method is called only if there is no valid nonce available (i.e., when [isAuthenticated] returns false).
+ /// [authorize] and [validate] methods will not be called before calling [initialize].
///
- /// `authorize()` / `validate()` functions will not be called before calling `initialize()` function.
+ /// [baseUrl]: The base URL of the WordPress site.
+ ///
+ /// Returns a [Future] indicating whether initialization was successful.
@mustCallSuper
Future initialize({
required Uri baseUrl,
@@ -56,39 +84,50 @@ abstract base class IAuthorization {
}
/// Provides this instance of [IAuthorization] with the Dio client instance for requests.
+ ///
+ /// [client]: The Dio client instance to use for making HTTP requests.
void clientFactoryProvider(Dio client);
- /// Called to validate token. (such as in JWT auth)
- ///
- /// As of right now, this function is not called outside of this instance. This can change in the future if there is a requirement to validate the nounce from the core client itself.
- /// Therefore, be sure to implement this with valid logic for the validation process.
+ /// Validates the authentication token (e.g., JWT token).
///
- /// Example 1: JWT authentication token can be validated through an endpoint, you can implement that validation logic inside this.
+ /// This method is not called outside of this instance by default, but it may be used in the future.
+ /// Implement this method with valid logic for the validation process.
///
- /// Example 2: Basic Auth does not require any validation, therefore you can simply return true or if still require some custom logic, you can implement that as well!
+ /// Example for JWT:
+ /// ```dart
+ /// @override
+ /// Future validate() async {
+ /// try {
+ /// final response = await _client.post('/validate-token', data: {'token': _token});
+ /// return response.statusCode == 200;
+ /// } catch (e) {
+ /// return false;
+ /// }
+ /// }
+ /// ```
Future validate();
- /// Called to check if this instance has a valid authentication nounce and generateAuthUrl() won't return null.
+ /// Checks if this instance has a valid authentication nonce and [generateAuthUrl] won't return null.
///
- /// This function will be called before init() function, therefore if you are using client instance passed through init() then there will be NullReferenceException.
+ /// This method is called before [initialize], so if you need to use the client instance,
+ /// you should implement custom logic to handle potential null references.
///
- /// If you require HTTP requests in this method, then you need to implement custom logic.
+ /// Returns a [Future] indicating whether the instance is authenticated.
Future isAuthenticated();
- /// Called to authorize a request if the request requires authentication.
+ /// Authorizes a request if authentication is required.
///
- /// Returning true means the request should be authorized, false means authorization failed.
+ /// Returns a [Future] indicating whether authorization was successful (true) or failed (false).
Future authorize();
- /// After `authorize()` is called, to get the authorization header string, (ie, '{scheme} {token}') the client calls this method to generate the raw string.
- ///
- /// The returning string formate must always be like
- ///
- /// {scheme} {token}
+ /// Generates the authorization header string after [authorize] is called.
///
- /// - Example 1: In case of JWT, `Bearer {jwt_token}`
+ /// The returned string format must always be: "{scheme} {token}"
///
- /// - Example 2: In case of Basic Auth, `Basic {Base64UsernamePassword}`
+ /// Examples:
+ /// - JWT: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
+ /// - Basic Auth: "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
///
+ /// Returns a [Future] containing the authorization header string, or null if not authorized.
Future generateAuthUrl();
}
diff --git a/lib/src/authorization/authorization_builder.dart b/lib/src/authorization/authorization_builder.dart
index d7982d6..26c2f39 100644
--- a/lib/src/authorization/authorization_builder.dart
+++ b/lib/src/authorization/authorization_builder.dart
@@ -8,33 +8,86 @@ import 'methods/basic_jwt.dart';
import 'methods/useful_jwt.dart';
/// Creates a new instance of [AuthorizationBuilder].
+///
+/// This class uses the builder pattern to construct an authorization instance.
+/// Use the various 'with' methods to set the required parameters, then call
+/// [build] to create the authorization object.
+///
+/// Example usage:
+/// ```dart
+/// final auth = AuthorizationBuilder()
+/// .withUserName('myusername')
+/// .withPassword('mypassword')
+/// .withType(AuthorizationType.useful_jwt)
+/// .build();
+/// ```
final class AuthorizationBuilder {
String _userName = '';
String _password = '';
AuthorizationType? _type;
WordpressEvents? _events;
+ /// Sets the username for the authorization.
+ ///
+ /// Example:
+ /// ```dart
+ /// builder.withUserName('myusername');
+ /// ```
AuthorizationBuilder withUserName(String userName) {
_userName = userName;
return this;
}
+ /// Sets the password for the authorization.
+ ///
+ /// Example:
+ /// ```dart
+ /// builder.withPassword('mypassword');
+ /// ```
AuthorizationBuilder withPassword(String password) {
_password = password;
return this;
}
+ /// Sets the authorization type.
+ ///
+ /// If not set, it defaults to [AuthorizationType.useful_jwt].
+ ///
+ /// Example:
+ /// ```dart
+ /// builder.withType(AuthorizationType.basic_jwt);
+ /// ```
AuthorizationBuilder withType(AuthorizationType type) {
_type = type;
return this;
}
+ /// Sets the WordPress events for the authorization.
+ ///
+ /// This is optional and can be used to handle specific WordPress events.
+ ///
+ /// Example:
+ /// ```dart
+ /// builder.withEvents(myWordPressEvents);
+ /// ```
AuthorizationBuilder withEvents(WordpressEvents events) {
_events = events;
return this;
}
- /// Builds the authorization instance.
+ /// Builds and returns the authorization instance based on the set parameters.
+ ///
+ /// If no type is specified, it defaults to [AuthorizationType.useful_jwt].
+ ///
+ /// Example:
+ /// ```dart
+ /// final auth = builder.build();
+ /// ```
+ ///
+ /// Returns an instance of [IAuthorization] which can be one of:
+ /// - [BasicJwtAuth]
+ /// - [UsefulJwtAuth]
+ /// - [AppPasswordAuth]
IAuthorization build() {
_type ??= AuthorizationType.useful_jwt;
diff --git a/lib/src/authorization/methods/app_password.dart b/lib/src/authorization/methods/app_password.dart
index 5ecb1c6..554f753 100644
--- a/lib/src/authorization/methods/app_password.dart
+++ b/lib/src/authorization/methods/app_password.dart
@@ -3,8 +3,24 @@ import 'package:dio/dio.dart';
import '../../../wordpress_client.dart';
import '../../utilities/helpers.dart';
-/// Authentication using Application Passwords which are supported on all Wordpress installations version 5.6 or higher.
+/// Authentication using Application Passwords, supported on WordPress installations version 5.6 or higher.
+///
+/// This class provides a way to authenticate with WordPress using Application Passwords,
+/// which is a secure method for third-party applications to access WordPress sites.
+///
+/// Example usage:
+/// ```dart
+/// final auth = AppPasswordAuth(
+/// userName: 'your_username',
+/// password: 'your_app_password',
+/// );
+///
final class AppPasswordAuth extends IAuthorization {
+ /// Creates an instance of [AppPasswordAuth].
+ ///
+ /// [userName]: The WordPress username.
+ /// [password]: The application password generated for this user in WordPress.
+ /// [events]: Optional [WordpressEvents] to listen to during the authorization process.
AppPasswordAuth({
required super.userName,
required super.password,
@@ -13,16 +29,19 @@ final class AppPasswordAuth extends IAuthorization {
@override
Future authorize() async {
+ // Application Passwords don't require an explicit authorization step
return true;
}
@override
Future generateAuthUrl() async {
+ // Generates the Basic Auth header value
return '$scheme ${base64Encode('$userName:$password')}';
}
@override
Future isAuthenticated() async {
+ // Application Passwords are always considered authenticated if provided
return true;
}
@@ -32,11 +51,14 @@ final class AppPasswordAuth extends IAuthorization {
@override
Future validate() async {
+ // Application Passwords don't require validation
return true;
}
@override
- void clientFactoryProvider(Dio client) {}
+ void clientFactoryProvider(Dio client) {
+ // No additional configuration needed for Dio client
+ }
@override
String get scheme => 'Basic';
diff --git a/lib/src/authorization/methods/basic_auth.dart b/lib/src/authorization/methods/basic_auth.dart
index 05fdade..00966a0 100644
--- a/lib/src/authorization/methods/basic_auth.dart
+++ b/lib/src/authorization/methods/basic_auth.dart
@@ -7,11 +7,31 @@ import '../authorization_base.dart';
/// The most basic authentication system using username and password.
///
-/// Implemented on basis of https://github.com/WP-API/Basic-Auth wordpress plugin.
+/// This class implements Basic Authentication for WordPress API, based on
+/// the https://github.com/WP-API/Basic-Auth WordPress plugin.
///
-/// Make sure to only use this method for testing purposes as this isn't secure.
+/// WARNING: This method should only be used for testing purposes as it is not secure
+/// for production environments.
+///
+/// Example usage:
+/// ```dart
+/// final auth = BasicAuth(userName: 'myuser', password: 'mypassword');
+/// final isAuthorized = await auth.authorize();
+/// if (isAuthorized) {
+/// final authHeader = await auth.generateAuthUrl();
+/// // Use authHeader in your API requests
+/// }
+/// ```
+///
+/// @deprecated Use AppPasswordAuth instead for more secure authentication.
@Deprecated('Use AppPasswordAuth instead')
final class BasicAuth extends IAuthorization {
+ /// Creates a new BasicAuth instance.
+ ///
+ /// [userName] and [password] are required parameters.
+ /// [events] is an optional parameter for authentication events.
+ ///
+ /// @deprecated Use AppPasswordAuth instead for more secure authentication.
@Deprecated('Use AppPasswordAuth instead')
BasicAuth({
required super.userName,
@@ -19,32 +39,54 @@ final class BasicAuth extends IAuthorization {
super.events,
});
+ /// Authorizes the user. Always returns true for BasicAuth.
+ ///
+ /// This method is part of the IAuthorization interface but doesn't perform
+ /// any actual authorization for BasicAuth.
@override
Future authorize() async {
return true;
}
+ /// Generates the authorization header value.
+ ///
+ /// Returns a Future containing the Basic Auth header value.
+ /// The returned string is in the format: "Basic base64EncodedCredentials"
@override
Future generateAuthUrl() async {
return '$scheme ${base64Encode('$userName:$password')}';
}
+ /// Checks if the user is authenticated. Always returns true for BasicAuth.
+ ///
+ /// This method is part of the IAuthorization interface but doesn't perform
+ /// any actual authentication check for BasicAuth.
@override
Future isAuthenticated() async {
return true;
}
+ /// Indicates whether the authentication is valid. Always true for BasicAuth.
@override
bool get isValidAuth => true;
+ /// Validates the authentication. Always returns true for BasicAuth.
+ ///
+ /// This method is part of the IAuthorization interface but doesn't perform
+ /// any actual validation for BasicAuth.
@override
Future validate() async {
return true;
}
+ /// Provides a way to modify the Dio client. Not used in BasicAuth.
+ ///
+ /// This method is part of the IAuthorization interface but doesn't perform
+ /// any modifications to the Dio client for BasicAuth.
@override
void clientFactoryProvider(Dio client) {}
+ /// The authentication scheme used. Returns 'Basic' for BasicAuth.
@override
String get scheme => 'Basic';
}
diff --git a/lib/src/authorization/methods/basic_jwt.dart b/lib/src/authorization/methods/basic_jwt.dart
index fcd709d..8cff06b 100644
--- a/lib/src/authorization/methods/basic_jwt.dart
+++ b/lib/src/authorization/methods/basic_jwt.dart
@@ -8,14 +8,38 @@ import '../../utilities/helpers.dart';
import '../authorization_base.dart';
import 'useful_jwt.dart';
-/// Most widely used authentication system, which is most easy to integrate and secure (when compared with basic auth)
+/// BasicJwtAuth implements JWT (JSON Web Token) authentication for WordPress APIs.
///
-/// Implemented on basis of https://github.com/Tmeister/wp-api-jwt-auth wordpress plugin.
+/// This class is based on the WordPress plugin https://github.com/Tmeister/wp-api-jwt-auth.
///
-/// ### NOTE
+/// ### Usage Example:
///
-/// This plugin isn't in active development and may contain lots of bugs/issues. It is recommended to use [UsefulJwtAuth] instead.
+/// ```dart
+/// final auth = BasicJwtAuth(
+/// userName: 'your_username',
+/// password: 'your_password',
+/// );
+///
+/// // Authorize the user
+/// bool isAuthorized = await auth.authorize();
+///
+/// if (isAuthorized) {
+/// print('Successfully authorized!');
+/// // Use the auth object for subsequent API calls
+/// } else {
+/// print('Authorization failed.');
+/// }
+/// ```
+///
+/// ### Important Note:
+///
+/// This implementation relies on a WordPress plugin that is not actively maintained.
+/// For a more robust and up-to-date JWT authentication, consider using [UsefulJwtAuth] instead.
final class BasicJwtAuth extends IAuthorization {
+ /// Creates a new instance of BasicJwtAuth.
+ ///
+ /// [userName] and [password] are required for authentication.
+ /// [events] is optional and can be used to handle authentication events.
BasicJwtAuth({
required super.userName,
required super.password,
@@ -27,17 +51,33 @@ final class BasicJwtAuth extends IAuthorization {
bool _hasValidatedOnce = false;
Dio? _client;
+ /// Number of days until the token expires.
static const int DAYS_UNTIL_TOKEN_EXPIRY = 3;
+ /// Checks if the current authentication is valid.
@override
bool get isValidAuth => !isNullOrEmpty(_encryptedAccessToken);
+ /// Checks if the current authentication has expired.
bool get _isAuthExpiried {
return _lastAuthorizedTime != null &&
DateTime.now().difference(_lastAuthorizedTime!).inHours >
(DAYS_UNTIL_TOKEN_EXPIRY * 24);
}
+ /// Authorizes the user with the provided credentials.
+ ///
+ /// Returns `true` if authorization is successful, `false` otherwise.
+ ///
+ /// Example:
+ /// ```dart
+ /// bool success = await auth.authorize();
+ /// if (success) {
+ /// print('Authorization successful');
+ /// } else {
+ /// print('Authorization failed');
+ /// }
+ /// ```
@override
Future authorize() async {
if (isValidAuth) {
@@ -86,6 +126,15 @@ final class BasicJwtAuth extends IAuthorization {
return _hasValidatedOnce = !isNullOrEmpty(_encryptedAccessToken);
}
+ /// Checks if the user is currently authenticated.
+ ///
+ /// Returns `true` if the user is authenticated, `false` otherwise.
+ ///
+ /// Example:
+ /// ```dart
+ /// bool isAuth = await auth.isAuthenticated();
+ /// print(isAuth ? 'User is authenticated' : 'User is not authenticated');
+ /// ```
@override
Future isAuthenticated() async {
if (_hasValidatedOnce && !isNullOrEmpty(_encryptedAccessToken)) {
@@ -95,6 +144,15 @@ final class BasicJwtAuth extends IAuthorization {
return false;
}
+ /// Validates the current authentication token.
+ ///
+ /// Returns `true` if the token is valid, `false` otherwise.
+ ///
+ /// Example:
+ /// ```dart
+ /// bool isValid = await auth.validate();
+ /// print(isValid ? 'Token is valid' : 'Token is invalid');
+ /// ```
@override
Future validate() async {
if (_client == null || isNullOrEmpty(_encryptedAccessToken)) {
@@ -122,6 +180,19 @@ final class BasicJwtAuth extends IAuthorization {
(response.data['code'] as String) == 'jwt_auth_valid_token';
}
+ /// Generates an authentication URL with the current token.
+ ///
+ /// Returns the authentication URL as a string, or `null` if not authenticated.
+ ///
+ /// Example:
+ /// ```dart
+ /// String? authUrl = await auth.generateAuthUrl();
+ /// if (authUrl != null) {
+ /// print('Auth URL: $authUrl');
+ /// } else {
+ /// print('Not authenticated');
+ /// }
+ /// ```
@override
Future generateAuthUrl() async {
if (!await isAuthenticated()) {
@@ -131,11 +202,15 @@ final class BasicJwtAuth extends IAuthorization {
return '$scheme $_encryptedAccessToken';
}
+ /// Sets the Dio client for making HTTP requests.
+ ///
+ /// This method is called internally to set up the HTTP client.
@override
void clientFactoryProvider(Dio client) {
_client = client;
}
+ /// The authentication scheme used for this method (Bearer).
@override
String get scheme => 'Bearer';
}
diff --git a/lib/src/authorization/methods/useful_jwt.dart b/lib/src/authorization/methods/useful_jwt.dart
index 12456fc..5e7c0e3 100644
--- a/lib/src/authorization/methods/useful_jwt.dart
+++ b/lib/src/authorization/methods/useful_jwt.dart
@@ -7,12 +7,42 @@ import 'package:dio/dio.dart';
import '../../enums.dart';
import '../../utilities/helpers.dart';
import '../authorization_base.dart';
-import 'basic_jwt.dart';
-/// Similar to [BasicJwtAuth], this plugin is in active development and has much more features than the previous one. It is recommended to use this plugin instead of the previous one.
+/// UsefulJwtAuth implements JWT (JSON Web Token) authentication for WordPress APIs.
///
-/// Implemented on basis of https://github.com/usefulteam/jwt-auth wordpress plugin.
+/// This class is based on the WordPress plugin https://github.com/usefulteam/jwt-auth,
+/// which is actively maintained and offers more features compared to the BasicJwtAuth.
+///
+/// ### Usage Example:
+///
+/// ```dart
+/// final auth = UsefulJwtAuth(
+/// userName: 'your_username',
+/// password: 'your_password',
+/// );
+///
+/// // Authorize the user
+/// bool isAuthorized = await auth.authorize();
+///
+/// if (isAuthorized) {
+/// print('Successfully authorized!');
+/// // Use the auth object for subsequent API calls
+/// } else {
+/// print('Authorization failed.');
+/// }
+///
+/// // Generate auth URL for API requests
+/// String? authHeader = await auth.generateAuthUrl();
+/// if (authHeader != null) {
+/// // Use authHeader in your API requests
+/// print('Auth header: $authHeader');
+/// }
+/// ```
final class UsefulJwtAuth extends IAuthorization {
+ /// Creates a new instance of UsefulJwtAuth.
+ ///
+ /// [userName] and [password] are required for authentication.
+ /// [events] is optional and can be used to handle authentication events.
UsefulJwtAuth({
required super.userName,
required super.password,
@@ -24,16 +54,32 @@ final class UsefulJwtAuth extends IAuthorization {
bool _hasValidatedOnce = false;
Dio? _client;
+ /// Number of days until the token expires.
static const int DAYS_UNTILS_TOKEN_EXPIRY = 3;
+ /// Checks if the current authentication is valid.
@override
bool get isValidAuth => !isNullOrEmpty(_encryptedAccessToken);
+ /// Checks if the current authentication has expired.
bool get _isAuthExpiried =>
_lastAuthorizedTime != null &&
DateTime.now().difference(_lastAuthorizedTime!).inHours >
(DAYS_UNTILS_TOKEN_EXPIRY * 24);
+ /// Authorizes the user with the provided credentials.
+ ///
+ /// Returns `true` if authorization is successful, `false` otherwise.
+ ///
+ /// Example:
+ /// ```dart
+ /// bool success = await auth.authorize();
+ /// if (success) {
+ /// print('Authorization successful');
+ /// } else {
+ /// print('Authorization failed');
+ /// }
+ /// ```
@override
Future authorize() async {
if (isValidAuth) {
@@ -79,6 +125,15 @@ final class UsefulJwtAuth extends IAuthorization {
return _hasValidatedOnce = !isNullOrEmpty(_encryptedAccessToken);
}
+ /// Checks if the user is currently authenticated.
+ ///
+ /// Returns `true` if the user is authenticated, `false` otherwise.
+ ///
+ /// Example:
+ /// ```dart
+ /// bool isAuth = await auth.isAuthenticated();
+ /// print(isAuth ? 'User is authenticated' : 'User is not authenticated');
+ /// ```
@override
Future isAuthenticated() async {
if (_hasValidatedOnce && !isNullOrEmpty(_encryptedAccessToken)) {
@@ -88,6 +143,15 @@ final class UsefulJwtAuth extends IAuthorization {
return false;
}
+ /// Validates the current authentication token.
+ ///
+ /// Returns `true` if the token is valid, `false` otherwise.
+ ///
+ /// Example:
+ /// ```dart
+ /// bool isValid = await auth.validate();
+ /// print(isValid ? 'Token is valid' : 'Token is invalid');
+ /// ```
@override
Future validate() async {
if (isNullOrEmpty(_encryptedAccessToken)) {
@@ -114,6 +178,18 @@ final class UsefulJwtAuth extends IAuthorization {
(response.data['code'] as String) == 'jwt_auth_valid_token';
}
+ /// Generates an authentication URL with the current token.
+ ///
+ /// Returns the authentication header as a string, or `null` if not authenticated.
+ ///
+ /// Example:
+ /// ```dart
+ /// String? authHeader = await auth.generateAuthUrl();
+ /// if (authHeader != null) {
+ /// print('Auth header: $authHeader');
+ /// // Use authHeader in your API requests
+ /// }
+ /// ```
@override
Future generateAuthUrl() async {
if (!await isAuthenticated()) {
@@ -123,11 +199,15 @@ final class UsefulJwtAuth extends IAuthorization {
return '$scheme $_encryptedAccessToken';
}
+ /// Configures the Dio client for this authentication method.
+ ///
+ /// This method is called internally by the WordPress client.
@override
void clientFactoryProvider(Dio client) {
_client = client;
}
+ /// The authentication scheme used. Returns 'Bearer' for UsefulJwtAuth.
@override
String get scheme => 'Bearer';
}
diff --git a/lib/src/bootstrap_builder.dart b/lib/src/bootstrap_builder.dart
index 3d951c0..d55247b 100644
--- a/lib/src/bootstrap_builder.dart
+++ b/lib/src/bootstrap_builder.dart
@@ -1,4 +1,4 @@
-// ignore_for_file: avoid_positional_boolean_parameters, avoid_returning_this
+// ignore_for_file: avoid_positional_boolean_parameters
import 'package:dio/dio.dart';
@@ -9,9 +9,17 @@ import 'constants.dart';
import 'middleware/wordpress_middleware_base.dart';
import 'utilities/typedefs.dart';
+/// A builder class for creating a [BootstrapConfiguration] with a fluent API.
+///
+/// This class allows for easy configuration of various WordPress client settings
+/// through method chaining.
class BootstrapBuilder {
+ /// Creates a new [BootstrapBuilder] instance.
BootstrapBuilder();
+ /// Creates a [BootstrapBuilder] instance from an existing [BootstrapConfiguration].
+ ///
+ /// This constructor initializes the builder with the values from the provided configuration.
BootstrapBuilder.fromConfiguration(BootstrapConfiguration config) {
_debugMode = config.enableDebugMode;
_statisticsDelegate = config.statisticsDelegate;
@@ -25,8 +33,7 @@ class BootstrapBuilder {
_followRedirects = config.shouldFollowRedirects;
_middlewares = config.middlewares;
}
-
- Duration _defaultRequestTimeout = DEFAULT_REQUEST_TIMEOUT; // 60 seconds
+ Duration _defaultRequestTimeout = DEFAULT_REQUEST_TIMEOUT;
bool Function(dynamic)? _responsePreprocessorDelegate;
IAuthorization? _defaultAuthorization;
String? _defaultUserAgent;
@@ -38,52 +45,62 @@ class BootstrapBuilder {
bool _debugMode = false;
List? _middlewares;
- /// Attaches [LogInterceptor] to the [Dio] instance.
+ /// Enables or disables debug mode.
+ ///
+ /// When enabled, this attaches a [LogInterceptor] to the [Dio] instance.
BootstrapBuilder withDebugMode(bool value) {
_debugMode = value;
return this;
}
+ /// Adds a single middleware to the configuration.
BootstrapBuilder withMiddleware(IWordpressMiddleware middleware) {
_middlewares ??= [];
_middlewares!.add(middleware);
return this;
}
+ /// Adds multiple middlewares to the configuration.
BootstrapBuilder withMiddlewares(Iterable middlewares) {
_middlewares ??= [];
_middlewares!.addAll(middlewares);
return this;
}
+ /// Adds a Dio interceptor to the configuration.
BootstrapBuilder withDioInterceptor(Interceptor interceptor) {
_interceptors ??= [];
_interceptors!.add(interceptor);
return this;
}
+ /// Sets the statistics delegate for collecting request statistics.
BootstrapBuilder withStatisticDelegate(StatisticsCallback? delegate) {
_statisticsDelegate = delegate;
return this;
}
+ /// Sets the default request timeout.
BootstrapBuilder withRequestTimeout(Duration timeout) {
_defaultRequestTimeout = timeout;
return this;
}
+ /// Sets a response preprocessor function.
BootstrapBuilder withResponsePreprocessor(
- bool Function(dynamic) responsePreprocessor,
+ bool Function(dynamic) preprocessor,
) {
- _responsePreprocessorDelegate = responsePreprocessor;
+ _responsePreprocessorDelegate = preprocessor;
return this;
}
+ /// Sets the default authorization for requests.
BootstrapBuilder withDefaultAuthorization(IAuthorization authorization) {
_defaultAuthorization = authorization;
return this;
}
+ /// Sets the default authorization using a builder function.
BootstrapBuilder withDefaultAuthorizationBuilder(
IAuthorization Function(AuthorizationBuilder) builder,
) {
@@ -91,26 +108,31 @@ class BootstrapBuilder {
return this;
}
+ /// Sets the default User-Agent header for requests.
BootstrapBuilder withDefaultUserAgent(String userAgent) {
_defaultUserAgent = userAgent;
return this;
}
+ /// Sets default headers for all requests.
BootstrapBuilder withDefaultHeaders(Map headers) {
_defaultHeaders = headers;
return this;
}
- BootstrapBuilder withFollowRedirects(bool followRedirects) {
- _followRedirects = followRedirects;
+ /// Configures whether to follow redirects automatically.
+ BootstrapBuilder withFollowRedirects(bool follow) {
+ _followRedirects = follow;
return this;
}
- BootstrapBuilder withDefaultMaxRedirects(int defaultMaxRedirects) {
- _defaultMaxRedirects = defaultMaxRedirects;
+ /// Sets the maximum number of redirects to follow.
+ BootstrapBuilder withMaxRedirects(int maxRedirects) {
+ _defaultMaxRedirects = maxRedirects;
return this;
}
+ /// Builds and returns a [BootstrapConfiguration] instance with the configured settings.
BootstrapConfiguration build() {
return BootstrapConfiguration(
receiveTimeout: _defaultRequestTimeout,
diff --git a/lib/src/cache/cache_entry.dart b/lib/src/cache/cache_entry.dart
new file mode 100644
index 0000000..ff8d3c6
--- /dev/null
+++ b/lib/src/cache/cache_entry.dart
@@ -0,0 +1,24 @@
+import 'package:meta/meta.dart';
+
+/// Represents an entry in the cache with a value and optional expiry time.
+@immutable
+class CacheEntry {
+ /// Creates a new [CacheEntry] with the given [value] and optional [expiryTime].
+ ///
+ /// [value] The data to be stored in the cache.
+ /// [expiryTime] Optional. The time at which this entry should be considered expired.
+ const CacheEntry(this.value, this.expiryTime);
+
+ /// The data stored in this cache entry.
+ final T value;
+
+ /// The time at which this entry should be considered expired.
+ /// If null, the entry does not expire.
+ final DateTime? expiryTime;
+
+ /// Checks if the cache entry has expired.
+ ///
+ /// Returns true if [expiryTime] is set and has passed, false otherwise.
+ bool get isExpired =>
+ expiryTime != null && DateTime.now().isAfter(expiryTime!);
+}
diff --git a/lib/src/cache/cache_exports.dart b/lib/src/cache/cache_exports.dart
new file mode 100644
index 0000000..361749a
--- /dev/null
+++ b/lib/src/cache/cache_exports.dart
@@ -0,0 +1,6 @@
+export 'cache_entry.dart';
+export 'cache_manager_base.dart';
+export 'exceptions/cache_exception_base.dart';
+export 'exceptions/cache_expired_exception.dart';
+export 'exceptions/cache_not_exists_exception.dart';
+export 'stores/memory_cache_store.dart';
diff --git a/lib/src/cache/cache_manager_base.dart b/lib/src/cache/cache_manager_base.dart
new file mode 100644
index 0000000..a466f01
--- /dev/null
+++ b/lib/src/cache/cache_manager_base.dart
@@ -0,0 +1,32 @@
+import 'dart:async';
+
+/// An abstract class defining the interface for a cache manager.
+///
+/// This interface provides methods for basic cache operations such as
+/// setting, getting, removing, and clearing cache entries.
+abstract class ICacheManager {
+ const ICacheManager();
+
+ /// Stores a value in the cache with the specified key.
+ ///
+ /// [key] The unique identifier for the cache entry.
+ /// [value] The value to be stored in the cache.
+ /// [expiry] Optional duration after which the cache entry should expire.
+ FutureOr set(String key, T value, {Duration? expiry});
+
+ /// Retrieves a value from the cache using the specified key.
+ ///
+ /// [key] The unique identifier for the cache entry.
+ /// [T] The expected type of the cached value.
+ ///
+ /// Returns a [FutureOr] that resolves to the cached value of type [T].
+ FutureOr get(String key);
+
+ /// Removes a specific entry from the cache.
+ ///
+ /// [key] The unique identifier of the cache entry to be removed.
+ FutureOr remove(String key);
+
+ /// Clears all entries from the cache.
+ FutureOr clear();
+}
diff --git a/lib/src/cache/exceptions/cache_exception_base.dart b/lib/src/cache/exceptions/cache_exception_base.dart
new file mode 100644
index 0000000..750f394
--- /dev/null
+++ b/lib/src/cache/exceptions/cache_exception_base.dart
@@ -0,0 +1,9 @@
+abstract base class CacheExceptionBase implements Exception {
+ const CacheExceptionBase({
+ required this.message,
+ this.cause,
+ });
+
+ final String message;
+ final Exception? cause;
+}
diff --git a/lib/src/cache/exceptions/cache_expired_exception.dart b/lib/src/cache/exceptions/cache_expired_exception.dart
new file mode 100644
index 0000000..8c59152
--- /dev/null
+++ b/lib/src/cache/exceptions/cache_expired_exception.dart
@@ -0,0 +1,8 @@
+import 'cache_exception_base.dart';
+
+final class CacheExpiredException extends CacheExceptionBase {
+ const CacheExpiredException({
+ super.cause,
+ super.message = 'Cache expired',
+ });
+}
diff --git a/lib/src/cache/exceptions/cache_not_exists_exception.dart b/lib/src/cache/exceptions/cache_not_exists_exception.dart
new file mode 100644
index 0000000..9311da8
--- /dev/null
+++ b/lib/src/cache/exceptions/cache_not_exists_exception.dart
@@ -0,0 +1,8 @@
+import 'cache_exception_base.dart';
+
+final class CacheNotExistsException extends CacheExceptionBase {
+ const CacheNotExistsException({
+ super.cause,
+ super.message = 'Cache with the specified key does not exist.',
+ });
+}
diff --git a/lib/src/cache/stores/memory_cache_store.dart b/lib/src/cache/stores/memory_cache_store.dart
new file mode 100644
index 0000000..a3a1247
--- /dev/null
+++ b/lib/src/cache/stores/memory_cache_store.dart
@@ -0,0 +1,37 @@
+import '../cache_entry.dart';
+import '../cache_manager_base.dart';
+
+class MemoryCacheStore implements ICacheManager {
+ MemoryCacheStore();
+
+ final Map> _cache = {};
+
+ @override
+ void set(String key, T value, {Duration? expiry}) {
+ final expiryTime = expiry != null ? DateTime.now().add(expiry) : null;
+ _cache[key] = CacheEntry(value, expiryTime);
+ }
+
+ @override
+ T? get(String key) {
+ final entry = _cache[key];
+
+ if (entry == null || entry.isExpired) {
+ _cache.remove(key);
+
+ return null;
+ }
+
+ return entry.value;
+ }
+
+ @override
+ void remove(String key) {
+ _cache.remove(key);
+ }
+
+ @override
+ void clear() {
+ _cache.clear();
+ }
+}
diff --git a/lib/src/client_configuration.dart b/lib/src/client_configuration.dart
index 34218a8..a2c1904 100644
--- a/lib/src/client_configuration.dart
+++ b/lib/src/client_configuration.dart
@@ -5,8 +5,13 @@ import 'package:meta/meta.dart';
import '../wordpress_client.dart';
import 'constants.dart';
+/// Configuration class for bootstrapping the WordPress client.
+///
+/// This class provides a fluent API for setting up various configuration options
+/// for the WordPress client, including timeouts, authorization, headers, and more.
@immutable
final class BootstrapConfiguration {
+ /// Creates a new instance of [BootstrapConfiguration] with default or specified values.
const BootstrapConfiguration({
this.receiveTimeout = DEFAULT_REQUEST_TIMEOUT,
this.connectTimeout = DEFAULT_CONNECT_TIMEOUT,
@@ -22,17 +27,40 @@ final class BootstrapConfiguration {
this.middlewares,
});
+ /// Enables or disables debug mode.
final bool enableDebugMode;
+
+ /// The timeout duration for receiving a response.
final Duration receiveTimeout;
+
+ /// The timeout duration for establishing a connection.
final Duration connectTimeout;
+
+ /// A function to preprocess the response before it's handled by the client.
final bool Function(dynamic)? responsePreprocessorDelegate;
+
+ /// The default authorization to use for requests.
final IAuthorization? defaultAuthorization;
+
+ /// The default User-Agent header to use for requests.
final String? defaultUserAgent;
+
+ /// Default headers to include in all requests.
final Map? defaultHeaders;
+
+ /// Whether to follow redirects automatically.
final bool shouldFollowRedirects;
+
+ /// The maximum number of redirects to follow.
final int maxRedirects;
+
+ /// A list of interceptors to use for requests.
final List? interceptors;
+
+ /// A callback for collecting statistics about requests.
final StatisticsCallback? statisticsDelegate;
+
+ /// A list of middlewares to apply to requests.
final List? middlewares;
@override
@@ -58,20 +86,23 @@ final class BootstrapConfiguration {
@override
int get hashCode {
- return enableDebugMode.hashCode ^
- receiveTimeout.hashCode ^
- responsePreprocessorDelegate.hashCode ^
- defaultAuthorization.hashCode ^
- defaultUserAgent.hashCode ^
- defaultHeaders.hashCode ^
- shouldFollowRedirects.hashCode ^
- maxRedirects.hashCode ^
- interceptors.hashCode ^
- middlewares.hashCode ^
- connectTimeout.hashCode ^
- statisticsDelegate.hashCode;
+ return Object.hash(
+ enableDebugMode,
+ receiveTimeout,
+ responsePreprocessorDelegate,
+ defaultAuthorization,
+ defaultUserAgent,
+ defaultHeaders,
+ shouldFollowRedirects,
+ maxRedirects,
+ interceptors,
+ middlewares,
+ connectTimeout,
+ statisticsDelegate,
+ );
}
+ /// Creates a copy of this configuration with the given fields replaced with new values.
BootstrapConfiguration copyWith({
bool? enableDebugMode,
Duration? receiveTimeout,
@@ -82,7 +113,6 @@ final class BootstrapConfiguration {
bool? shouldFollowRedirects,
int? maxRedirects,
List? interceptors,
- bool? synchronized,
StatisticsCallback? statisticsDelegate,
List? middlewares,
Duration? connectTimeout,
diff --git a/lib/src/constants.dart b/lib/src/constants.dart
index 4e7dd0f..9d701cf 100644
--- a/lib/src/constants.dart
+++ b/lib/src/constants.dart
@@ -1,3 +1,32 @@
+/// The default timeout duration for HTTP requests.
+///
+/// This constant defines the maximum amount of time allowed for an HTTP request
+/// to complete before it times out. If a request takes longer than this duration,
+/// it will be terminated, and an error will be thrown.
+///
+/// The value is set to 30 seconds, which is generally sufficient for most API
+/// calls, but can be adjusted if needed for specific use cases.
const Duration DEFAULT_REQUEST_TIMEOUT = Duration(seconds: 30);
+
+/// The default timeout duration for establishing a connection.
+///
+/// This constant specifies the maximum time allowed for the initial connection
+/// to be established with the server. If the connection cannot be made within
+/// this timeframe, the request will fail with a connection timeout error.
+///
+/// Like the request timeout, this is also set to 30 seconds, providing a
+/// balance between allowing enough time for connections in various network
+/// conditions and failing quickly in case of connectivity issues.
const Duration DEFAULT_CONNECT_TIMEOUT = Duration(seconds: 30);
+
+/// The header key used to identify local middleware.
+///
+/// This constant defines the HTTP header key that is used to indicate that
+/// a request has been processed by local middleware. It allows for tracking
+/// and managing the flow of requests through various middleware components
+/// in the WordPress client.
+///
+/// The value 'X-Local-Middleware' follows the convention of using 'X-' prefix
+/// for custom headers, making it clear that this is a non-standard header
+/// specific to this WordPress client implementation.
const String MIDDLEWARE_HEADER_KEY = 'X-Local-Middleware';
diff --git a/lib/src/enums.dart b/lib/src/enums.dart
index fd6ea85..9aac39e 100644
--- a/lib/src/enums.dart
+++ b/lib/src/enums.dart
@@ -1,163 +1,332 @@
// ignore_for_file: constant_identifier_names
+/// Represents various error types that can occur in the WordPress client.
enum ErrorType {
+ /// Interface does not exist
interfaceNotExist,
+
+ /// Interface already exists
interfaceAlreadyExist,
+
+ /// Request failed internally
requestFailedInternally,
+
+ /// Request failed
requestFailed,
+
+ /// Client is not ready
clientNotReady,
+
+ /// Authorization failed
authorizationFailed,
+
+ /// Bootstrap process failed
bootstrapFailed,
+
+ /// File doesn't exist
fileDoesntExist,
+
+ /// Interface does not exist
interfaceDoNotExist,
+
+ /// Interface exists
interfaceExist,
+
+ /// Interface is not initialized
interfaceNotInitialized,
+
+ /// Invalid interface
invalidInterface,
+
+ /// Discovery is pending
discoveryPending,
+
+ /// Discovery failed
discoveryFailed,
+
+ /// Null reference encountered
nullReference,
+
+ /// Request URI parsing failed
requestUriParsingFailed,
}
+/// Represents specific error types that can occur during a request.
enum RequestErrorType {
+ /// No error occurred
noError,
+
+ /// Unknown error
unknown,
+
+ /// Internal generic error
internalGenericError,
+
+ /// Authorization module not found
authorizationModuleNotFound,
+
+ /// Authorization failed with provided credentials
authorizationFailedWithProvidedCredentials,
+
+ /// Connection failed
connectionFailed,
+
+ /// Request was cancelled
requestCancelled,
+
+ /// Invalid status code received
invalidStatusCode,
+
+ /// Middleware aborted the request
middlewareAborted,
+
+ /// Middleware execution failed
middlewareExecutionFailed,
}
+/// Represents different types of search operations.
enum SearchType {
+ /// Search for posts
post,
+
+ /// Search for terms
term,
+
+ /// Search for post formats
postFormat,
}
+/// Represents the status of an item (e.g., a post or comment).
enum Status {
+ /// Item is open
open,
+
+ /// Item is closed
closed,
}
+/// Represents the status of a comment.
enum CommentStatus {
+ /// Comment is to be approved
approve,
+
+ /// Comment is approved
approved,
+
+ /// Comment is pending approval
pending,
}
-/// Different HTTP Methods which is supported by the client.
+/// Represents different HTTP methods supported by the client.
enum HttpMethod {
- /// Put Method
+ /// PUT method
put,
- /// Post Method
+ /// POST method
post,
- /// Get Method
+ /// GET method
get,
- /// Delete Method
+ /// DELETE method
delete,
- /// Update Method
+ /// UPDATE method
update,
- /// Head Method
+ /// HEAD method
head,
- /// Options Method
+ /// OPTIONS method
options,
- /// Patch Method
+ /// PATCH method
patch,
- /// Trace Method
+ /// TRACE method
trace,
}
+/// Represents the order of results (ascending or descending).
enum Order {
+ /// Ascending order
asc,
+
+ /// Descending order
desc,
}
+/// Represents different criteria for ordering results.
enum OrderBy {
+ /// Order by date
date,
+
+ /// Order by author
author,
+
+ /// Order by ID
id,
+
+ /// Order by included items
include,
+
+ /// Order by modification date
modified,
+
+ /// Order by parent
parent,
+
+ /// Order by relevance
relevance,
+
+ /// Order by slug
slug,
+
+ /// Order by included slugs
include_slugs,
+
+ /// Order by title
title,
+
+ /// Order by email
email,
+
+ /// Order by URL
url,
+
+ /// Order by name
name,
+
+ /// Order by registration date
registered_date,
+
+ /// Order by term group
term_group,
+
+ /// Order by description
description,
+
+ /// Order by count
count,
}
+/// Represents different contexts for a request.
enum RequestContext {
+ /// View context
view,
+
+ /// Embed context
embed,
+
+ /// Edit context
edit,
}
+/// Represents the status for media filtering.
enum MediaFilterStatus {
+ /// Inherit status from parent
inherit,
}
+/// Represents the relation between taxonomy terms.
enum TaxonomyRelation {
+ /// AND relation
and,
+
+ /// OR relation
or,
}
+/// Represents different statuses for content (e.g., posts).
enum ContentStatus {
+ /// Published content
publish,
+
+ /// Scheduled content
future,
+
+ /// Draft content
draft,
+
+ /// Pending content
pending,
+
+ /// Private content
private,
}
+/// Represents different post formats.
enum PostFormat {
+ /// Standard post format
standard,
+
+ /// Aside post format
aside,
+
+ /// Chat post format
chat,
+
+ /// Gallery post format
gallery,
+
+ /// Link post format
link,
+
+ /// Image post format
image,
+
+ /// Quote post format
quote,
+
+ /// Status post format
status,
+
+ /// Video post format
video,
+
+ /// Audio post format
audio,
}
+/// Represents different types of authorization.
enum AuthorizationType {
+ /// Basic JWT authorization
basic_jwt,
+
+ /// Useful JWT authorization
useful_jwt,
+
+ /// Basic authorization
basic,
}
+/// Represents different locales.
enum Locale {
+ /// English (United States)
en_US,
}
+/// Represents different types of media.
enum MediaType {
+ /// Image media type
image,
+
+ /// Video media type
video,
+
+ /// Text media type
text,
+
+ /// Application media type
application,
+
+ /// Audio media type
audio,
}
+/// Converts a string value to a [ContentStatus] enum.
+///
+/// If the value is null or doesn't match any enum value, returns [defaultValue].
ContentStatus getContentStatusFromValue(
String? value, {
ContentStatus defaultValue = ContentStatus.pending,
@@ -166,12 +335,15 @@ ContentStatus getContentStatusFromValue(
return defaultValue;
}
- return ContentStatus.values
- .where((element) => element.name.toLowerCase() == value.toLowerCase())
- .firstOrNull ??
- defaultValue;
+ return ContentStatus.values.firstWhere(
+ (element) => element.name.toLowerCase() == value.toLowerCase(),
+ orElse: () => defaultValue,
+ );
}
+/// Converts a string value to a [CommentStatus] enum.
+///
+/// If the value is null or doesn't match any enum value, returns [defaultValue].
CommentStatus getCommentStatusFromValue(
String? value, {
CommentStatus defaultValue = CommentStatus.pending,
@@ -180,12 +352,15 @@ CommentStatus getCommentStatusFromValue(
return defaultValue;
}
- return CommentStatus.values
- .where((element) => element.name.toLowerCase() == value.toLowerCase())
- .firstOrNull ??
- defaultValue;
+ return CommentStatus.values.firstWhere(
+ (element) => element.name.toLowerCase() == value.toLowerCase(),
+ orElse: () => defaultValue,
+ );
}
+/// Converts a string value to a [MediaFilterStatus] enum.
+///
+/// If the value is null or doesn't match any enum value, returns [defaultValue].
MediaFilterStatus getMediaFilterStatusFromValue(
String? value, {
MediaFilterStatus defaultValue = MediaFilterStatus.inherit,
@@ -194,12 +369,15 @@ MediaFilterStatus getMediaFilterStatusFromValue(
return defaultValue;
}
- return MediaFilterStatus.values
- .where((element) => element.name.toLowerCase() == value.toLowerCase())
- .firstOrNull ??
- defaultValue;
+ return MediaFilterStatus.values.firstWhere(
+ (element) => element.name.toLowerCase() == value.toLowerCase(),
+ orElse: () => defaultValue,
+ );
}
+/// Converts a string value to a [PostFormat] enum.
+///
+/// If the value is null or doesn't match any enum value, returns [defaultValue].
PostFormat getFormatFromValue(
String? value, {
PostFormat defaultValue = PostFormat.standard,
@@ -208,19 +386,22 @@ PostFormat getFormatFromValue(
return defaultValue;
}
- return PostFormat.values
- .where((e) => e.name.toLowerCase() == value.toLowerCase())
- .firstOrNull ??
- defaultValue;
+ return PostFormat.values.firstWhere(
+ (e) => e.name.toLowerCase() == value.toLowerCase(),
+ orElse: () => defaultValue,
+ );
}
+/// Converts a string value to a [Status] enum.
+///
+/// If the value is null, empty, or doesn't match any enum value, returns [defaultValue].
Status getStatusFromValue(String? value, {Status defaultValue = Status.open}) {
if (value == null || value.isEmpty) {
return defaultValue;
}
- return Status.values
- .where((element) => element.name.toLowerCase() == value.toLowerCase())
- .firstOrNull ??
- defaultValue;
+ return Status.values.firstWhere(
+ (element) => element.name.toLowerCase() == value.toLowerCase(),
+ orElse: () => defaultValue,
+ );
}
diff --git a/lib/src/interface/application_passwords.dart b/lib/src/interface/application_passwords.dart
index d821a3e..ac37035 100644
--- a/lib/src/interface/application_passwords.dart
+++ b/lib/src/interface/application_passwords.dart
@@ -1,6 +1,47 @@
import '../../wordpress_client.dart';
-/// Represents the application password interface.
+/// Represents the application password interface for WordPress.
+///
+/// This interface provides methods to manage application passwords, including:
+/// - Creating new application passwords
+/// - Deleting existing application passwords
+/// - Listing all application passwords
+/// - Retrieving specific application passwords
+/// - Updating existing application passwords
+///
+/// Example usage:
+/// ```dart
+/// final wpClient = WordpressClient(baseUrl: 'https://your-wordpress-site.com');
+/// final appPasswords = wpClient.applicationPasswords;
+///
+/// // Create a new application password
+/// final newPassword = await appPasswords.create(CreateApplicationPasswordRequest(
+/// name: 'My App Password',
+/// user: 1, // User ID
+/// ));
+///
+/// // List all application passwords
+/// final passwords = await appPasswords.list(ListApplicationPasswordRequest());
+///
+/// // Retrieve a specific application password
+/// final password = await appPasswords.retrieve(RetriveApplicationPasswordRequest(
+/// id: newPassword.id,
+/// user: 1, // User ID
+/// ));
+///
+/// // Update an application password
+/// final updatedPassword = await appPasswords.update(UpdateApplicationPasswordRequest(
+/// id: newPassword.id,
+/// user: 1, // User ID
+/// name: 'Updated App Password',
+/// ));
+///
+/// // Delete an application password
+/// await appPasswords.delete(DeleteApplicationPasswordRequest(
+/// id: newPassword.id,
+/// user: 1, // User ID
+/// ));
+/// ```
final class ApplicationPasswordsInterface extends IRequestInterface
with
CreateOperation,
diff --git a/lib/src/interface/category.dart b/lib/src/interface/category.dart
index acbfc5c..1bc57f9 100644
--- a/lib/src/interface/category.dart
+++ b/lib/src/interface/category.dart
@@ -1,6 +1,39 @@
import '../../wordpress_client.dart';
-/// Represents the category interface.
+/// Represents the category interface for interacting with WordPress categories.
+///
+/// This interface provides CRUD (Create, Read, Update, Delete) operations for categories.
+/// It extends [IRequestInterface] and mixes in various operations to handle different
+/// category-related tasks.
+///
+/// Example usage:
+/// ```dart
+/// final wordpress = WordpressClient(baseUrl: 'https://your-wordpress-site.com/wp-json');
+/// final categoryInterface = wordpress.categories;
+///
+/// // Create a new category
+/// final newCategory = await categoryInterface.create(
+/// CreateCategoryRequest(name: 'New Category'),
+/// );
+///
+/// // Retrieve a category
+/// final category = await categoryInterface.retrieve(
+/// RetrieveCategoryRequest(id: 123),
+/// );
+///
+/// // Update a category
+/// final updatedCategory = await categoryInterface.update(
+/// UpdateCategoryRequest(id: 123, name: 'Updated Category Name'),
+/// );
+///
+/// // Delete a category
+/// await categoryInterface.delete(DeleteCategoryRequest(id: 123));
+///
+/// // List categories
+/// final categories = await categoryInterface.list(
+/// ListCategoryRequest(perPage: 10, page: 1),
+/// );
+/// ```
final class CategoryInterface extends IRequestInterface
with
CreateOperation,
diff --git a/lib/src/interface/comments.dart b/lib/src/interface/comments.dart
index 479f2ba..d00c74e 100644
--- a/lib/src/interface/comments.dart
+++ b/lib/src/interface/comments.dart
@@ -1,6 +1,42 @@
import '../../wordpress_client.dart';
-/// Represents the comment interface.
+/// Represents the comment interface for interacting with WordPress comments.
+///
+/// This interface provides methods for creating, deleting, retrieving, updating,
+/// and listing comments in a WordPress site.
+///
+/// Example usage:
+///
+/// ```dart
+/// final wp = WordpressClient(baseUrl: 'https://your-wordpress-site.com/wp-json');
+/// final commentInterface = wp.comments;
+///
+/// // Create a new comment
+/// final newComment = await commentInterface.create(CreateCommentRequest(
+/// content: 'Great post!',
+/// post: 123,
+/// author: 'John Doe',
+/// authorEmail: 'john@example.com',
+/// ));
+///
+/// // Retrieve a comment
+/// final comment = await commentInterface.retrieve(RetrieveCommentRequest(id: 456));
+///
+/// // Update a comment
+/// final updatedComment = await commentInterface.update(UpdateCommentRequest(
+/// id: 456,
+/// content: 'Updated comment content',
+/// ));
+///
+/// // Delete a comment
+/// await commentInterface.delete(DeleteCommentRequest(id: 456));
+///
+/// // List comments
+/// final comments = await commentInterface.list(ListCommentRequest(
+/// post: 123,
+/// status: 'approved',
+/// ));
+/// ```
final class CommentInterface extends IRequestInterface
with
CreateOperation,
diff --git a/lib/src/interface/me.dart b/lib/src/interface/me.dart
index 09efdc3..efeb16e 100644
--- a/lib/src/interface/me.dart
+++ b/lib/src/interface/me.dart
@@ -1,6 +1,34 @@
import '../../wordpress_client.dart';
-/// Represents the current user interface.
+/// Represents the current user interface for interacting with the WordPress API.
+///
+/// This class provides operations to manage the current user's account, including:
+/// - Retrieving user information
+/// - Updating user details
+/// - Deleting the user account
+///
+/// Usage examples:
+///
+/// Retrieve current user information:
+/// ```dart
+/// final user = await interface.retrieve(RetrieveMeRequest());
+/// print(user.username);
+/// ```
+///
+/// Update user information:
+/// ```dart
+/// final updatedUser = await interface.update(UpdateMeRequest(
+/// firstName: 'John',
+/// lastName: 'Doe',
+/// ));
+/// print('Updated name: ${updatedUser.firstName} ${updatedUser.lastName}');
+/// ```
+///
+/// Delete user account:
+/// ```dart
+/// await interface.delete(DeleteMeRequest());
+/// print('User account deleted');
+/// ```
final class MeInterface extends IRequestInterface
with
DeleteOperation,
diff --git a/lib/src/interface/media.dart b/lib/src/interface/media.dart
index 6b2d62f..ac7203b 100644
--- a/lib/src/interface/media.dart
+++ b/lib/src/interface/media.dart
@@ -1,6 +1,39 @@
import '../../wordpress_client.dart';
-/// Represents the media interface.
+/// Represents the media interface for interacting with WordPress media items.
+///
+/// This interface provides operations to manage media files such as images,
+/// videos, and documents in a WordPress site.
+///
+/// Example usage:
+/// ```dart
+/// final wp = WordpressClient(baseUrl: 'https://example.com/wp-json');
+/// final mediaInterface = wp.media;
+///
+/// // Create a new media item
+/// final newMedia = await mediaInterface.create(CreateMediaRequest(
+/// file: File('image.jpg'),
+/// title: 'My Image',
+/// ));
+///
+/// // Retrieve a media item
+/// final media = await mediaInterface.retrieve(RetrieveMediaRequest(id: 123));
+///
+/// // Update a media item
+/// final updatedMedia = await mediaInterface.update(UpdateMediaRequest(
+/// id: 123,
+/// title: 'Updated Image Title',
+/// ));
+///
+/// // Delete a media item
+/// await mediaInterface.delete(DeleteMediaRequest(id: 123));
+///
+/// // List media items
+/// final mediaList = await mediaInterface.list(ListMediaRequest(
+/// perPage: 10,
+/// page: 1,
+/// ));
+/// ```
final class MediaInterface extends IRequestInterface
with
CreateOperation,
diff --git a/lib/src/interface/page.dart b/lib/src/interface/page.dart
index 9321ad1..740590c 100644
--- a/lib/src/interface/page.dart
+++ b/lib/src/interface/page.dart
@@ -1,6 +1,41 @@
import '../../wordpress_client.dart';
-/// Represents the page interface.
+/// Represents the interface for interacting with WordPress pages.
+///
+/// This class provides methods for creating, retrieving, updating, deleting,
+/// and listing pages in a WordPress site.
+///
+/// Example usage:
+///
+/// ```dart
+/// final wordpress = WordpressClient(baseUrl: 'https://your-site.com/wp-json');
+/// final pagesInterface = wordpress.pages;
+///
+/// // Create a new page
+/// final newPage = await pagesInterface.create(CreatePageRequest(
+/// title: 'My New Page',
+/// content: 'This is the content of my new page.',
+/// status: 'publish',
+/// ));
+///
+/// // Retrieve a page
+/// final page = await pagesInterface.retrieve(RetrievePageRequest(id: 123));
+///
+/// // Update a page
+/// final updatedPage = await pagesInterface.update(UpdatePageRequest(
+/// id: 123,
+/// title: 'Updated Page Title',
+/// ));
+///
+/// // Delete a page
+/// await pagesInterface.delete(DeletePageRequest(id: 123));
+///
+/// // List pages
+/// final pages = await pagesInterface.list(ListPageRequest(
+/// perPage: 10,
+/// page: 1,
+/// ));
+/// ```
final class PagesInterface extends IRequestInterface
with
CreateOperation,
diff --git a/lib/src/interface/posts.dart b/lib/src/interface/posts.dart
index 8e9355d..1d640f1 100644
--- a/lib/src/interface/posts.dart
+++ b/lib/src/interface/posts.dart
@@ -1,6 +1,41 @@
import '../../wordpress_client.dart';
-/// Represents the post interface.
+/// Represents the interface for interacting with WordPress posts.
+///
+/// This class provides methods for creating, retrieving, updating, deleting,
+/// and listing posts in a WordPress site.
+///
+/// Example usage:
+///
+/// ```dart
+/// final wordpress = WordpressClient(baseUrl: 'https://your-wordpress-site.com');
+/// final postsInterface = wordpress.posts;
+///
+/// // Create a new post
+/// final newPost = await postsInterface.create(CreatePostRequest(
+/// title: 'My New Post',
+/// content: 'This is the content of my new post.',
+/// status: 'publish',
+/// ));
+///
+/// // Retrieve a post
+/// final post = await postsInterface.retrieve(RetrievePostRequest(id: 123));
+///
+/// // Update a post
+/// final updatedPost = await postsInterface.update(UpdatePostRequest(
+/// id: 123,
+/// title: 'Updated Post Title',
+/// ));
+///
+/// // Delete a post
+/// await postsInterface.delete(DeletePostRequest(id: 123));
+///
+/// // List posts
+/// final posts = await postsInterface.list(ListPostRequest(
+/// perPage: 10,
+/// page: 1,
+/// ));
+/// ```
final class PostsInterface extends IRequestInterface
with
CreateOperation,
diff --git a/lib/src/interface/search.dart b/lib/src/interface/search.dart
index f37d4c7..9ea9bf1 100644
--- a/lib/src/interface/search.dart
+++ b/lib/src/interface/search.dart
@@ -1,5 +1,31 @@
import '../library_exports.dart';
-/// Represents the search interface.
+/// Represents the search interface for interacting with WordPress search functionality.
+///
+/// This interface provides methods for searching content across a WordPress site.
+///
+/// Example usage:
+///
+/// ```dart
+/// final wordpress = WordpressClient(baseUrl: 'https://your-wordpress-site.com/wp-json');
+/// final searchInterface = wordpress.search;
+///
+/// // Perform a search
+/// final searchResults = await searchInterface.list(ListSearchRequest(
+/// search: 'example query',
+/// perPage: 10,
+/// page: 1,
+/// ));
+///
+/// // Process search results
+/// for (var result in searchResults) {
+/// print('Title: ${result.title}');
+/// print('Type: ${result.type}');
+/// print('URL: ${result.url}');
+/// }
+/// ```
+///
+/// The SearchInterface uses the ListOperation to perform searches, returning
+/// a list of Search objects that match the given criteria.
final class SearchInterface extends IRequestInterface
with ListOperation {}
diff --git a/lib/src/interface/tags.dart b/lib/src/interface/tags.dart
index 6860e94..bac5697 100644
--- a/lib/src/interface/tags.dart
+++ b/lib/src/interface/tags.dart
@@ -1,6 +1,30 @@
import '../../wordpress_client.dart';
-/// Represents the tag interface.
+/// Represents the tag interface for interacting with WordPress tags.
+///
+/// This interface provides CRUD (Create, Read, Update, Delete) operations for tags.
+/// It extends [IRequestInterface] and mixes in various operations to handle tag-related tasks.
+///
+/// Example usage:
+/// ```dart
+/// final wordpress = WordpressClient(baseUrl: 'https://your-wordpress-site.com/wp-json');
+/// final tagInterface = wordpress.tags;
+///
+/// // Create a new tag
+/// final newTag = await tagInterface.create(CreateTagRequest(name: 'New Tag'));
+///
+/// // Retrieve a tag
+/// final tag = await tagInterface.retrieve(RetrieveTagRequest(id: 123));
+///
+/// // Update a tag
+/// final updatedTag = await tagInterface.update(UpdateTagRequest(id: 123, name: 'Updated Tag'));
+///
+/// // Delete a tag
+/// await tagInterface.delete(DeleteTagRequest(id: 123));
+///
+/// // List tags
+/// final tags = await tagInterface.list(ListTagRequest());
+/// ```
final class TagInterface extends IRequestInterface
with
CreateOperation,
diff --git a/lib/src/interface/users.dart b/lib/src/interface/users.dart
index b4d74e6..ee512eb 100644
--- a/lib/src/interface/users.dart
+++ b/lib/src/interface/users.dart
@@ -1,6 +1,42 @@
import '../../wordpress_client.dart';
-/// Represents the user interface.
+/// Represents the user interface for managing WordPress users.
+///
+/// This class provides methods for creating, deleting, retrieving, updating,
+/// and listing users in a WordPress site.
+///
+/// Example usage:
+///
+/// ```dart
+/// final wordpress = WordpressClient(baseUrl: 'https://your-site.com');
+/// final usersInterface = wordpress.users;
+///
+/// // Create a new user
+/// final newUser = await usersInterface.create(CreateUserRequest(
+/// username: 'newuser',
+/// email: 'newuser@example.com',
+/// password: 'securepassword',
+/// ));
+///
+/// // Retrieve a user
+/// final user = await usersInterface.retrieve(RetrieveUserRequest(id: 1));
+///
+/// // Update a user
+/// final updatedUser = await usersInterface.update(UpdateUserRequest(
+/// id: 1,
+/// firstName: 'John',
+/// lastName: 'Doe',
+/// ));
+///
+/// // Delete a user
+/// await usersInterface.delete(DeleteUserRequest(id: 1));
+///
+/// // List users
+/// final users = await usersInterface.list(ListUserRequest(
+/// page: 1,
+/// perPage: 10,
+/// ));
+/// ```
final class UsersInterface extends IRequestInterface
with
CreateOperation,
diff --git a/lib/src/interface_key.dart b/lib/src/interface_key.dart
index fefebf9..19922d2 100644
--- a/lib/src/interface_key.dart
+++ b/lib/src/interface_key.dart
@@ -2,26 +2,68 @@ import 'package:meta/meta.dart';
import 'utilities/helpers.dart';
+/// A class representing a unique key for an interface of type T.
+///
+/// This class is used to create a unique identifier for interfaces,
+/// combining the type T with an optional string key.
+///
+/// Example:
+/// ```dart
+/// final userKey = InterfaceKey('primary');
+/// final postKey = InterfaceKey();
+/// ```
@immutable
final class InterfaceKey {
+ /// Creates an [InterfaceKey] with an optional string key.
+ ///
+ /// If no key is provided, an empty string is used as the default.
+ ///
+ /// Example:
+ /// ```dart
+ /// final key1 = InterfaceKey('custom');
+ /// final key2 = InterfaceKey(); // Uses default empty string
+ /// ```
const InterfaceKey([this._key = '']);
+ /// The type of the interface this key represents.
Type get _type => typeOf();
+
+ /// An optional string to further specify the key.
final String? _key;
+ /// Compares this [InterfaceKey] with another object for equality.
+ ///
+ /// Two [InterfaceKey]s are considered equal if they have the same hash code.
@override
bool operator ==(Object other) => hashCode == other.hashCode;
+ /// Generates a hash code for this [InterfaceKey].
+ ///
+ /// The hash code is a combination of the type's hash code and the optional key's hash code.
@override
int get hashCode {
return _type.hashCode ^ (_key?.hashCode ?? 0);
}
+ /// Returns a string representation of this [InterfaceKey].
+ ///
+ /// Example:
+ /// ```dart
+ /// final key = InterfaceKey('admin');
+ /// print(key.toString()); // Outputs: InterfaceKeyadmin
+ /// ```
@override
String toString() {
return 'InterfaceKey<$_type>$_key';
}
+ /// Returns a more detailed string representation for debugging purposes.
+ ///
+ /// Example:
+ /// ```dart
+ /// final key = InterfaceKey('admin');
+ /// print(key.toDebugString()); // Outputs: InterfaceKey(User, admin)
+ /// ```
String toDebugString() {
final tag = _key == null ? '' : ', $_key';
return 'InterfaceKey<$_type>($_type$tag)';
diff --git a/lib/src/library_exports.dart b/lib/src/library_exports.dart
index 398c5ee..5638ddf 100644
--- a/lib/src/library_exports.dart
+++ b/lib/src/library_exports.dart
@@ -1,4 +1,5 @@
export 'authorization/authorization_export.dart';
+export 'cache/cache_exports.dart';
export 'client_configuration.dart';
export 'enums.dart';
export 'exceptions/exceptions_export.dart';
diff --git a/lib/src/middleware/delegated_middleware.dart b/lib/src/middleware/delegated_middleware.dart
index 52277a7..da873b3 100644
--- a/lib/src/middleware/delegated_middleware.dart
+++ b/lib/src/middleware/delegated_middleware.dart
@@ -2,21 +2,36 @@ import '../requests/wordpress_request.dart';
import '../responses/wordpress_raw_response.dart';
import 'middleware_exports.dart';
+/// A function type for modifying a WordPress request before it's sent.
typedef OnRequestDelegate = Future Function(
WordpressRequest request,
);
+/// A function type for processing a WordPress response after it's received.
typedef OnResponseDelegate = Future Function(
WordpressRawResponse response,
);
+/// A function type for initializing the middleware.
typedef InitializeDelegate = Future Function();
+
+/// A function type for cleaning up when the middleware is removed.
typedef OnRemovedDelegate = Future Function();
+
+/// A function type for custom execution logic in the middleware.
typedef OnExecuteDelegate = Future Function(
WordpressRequest request,
);
+/// A middleware that delegates its functionality to provided functions.
+///
+/// This allows for flexible and customizable middleware behavior without
+/// needing to create a new class for each variation.
final class DelegatedMiddleware extends IWordpressMiddleware {
+ /// Creates a new [DelegatedMiddleware] instance.
+ ///
+ /// [onRequestDelegate] and [onResponseDelegate] are required.
+ /// Other delegates are optional and will only be called if provided.
const DelegatedMiddleware({
required this.onRequestDelegate,
required this.onResponseDelegate,
@@ -25,10 +40,19 @@ final class DelegatedMiddleware extends IWordpressMiddleware {
this.onRemovedDelegate,
});
+ /// Called when the middleware is loaded.
final InitializeDelegate? initializeDelegate;
+
+ /// Called for each request passing through the middleware.
final OnRequestDelegate onRequestDelegate;
+
+ /// Called for each response passing through the middleware.
final OnResponseDelegate onResponseDelegate;
+
+ /// Called when the middleware is removed.
final OnRemovedDelegate? onRemovedDelegate;
+
+ /// Called for custom execution logic, if provided.
final OnExecuteDelegate? onExecuteDelegate;
@override
diff --git a/lib/src/middleware/models/middleware_raw_response.dart b/lib/src/middleware/models/middleware_raw_response.dart
index 9fc5f7e..958292c 100644
--- a/lib/src/middleware/models/middleware_raw_response.dart
+++ b/lib/src/middleware/models/middleware_raw_response.dart
@@ -1,4 +1,22 @@
+/// Represents a raw response from a middleware operation.
+///
+/// This class encapsulates various components of an HTTP response, including
+/// status code, headers, body, and additional metadata.
final class MiddlewareRawResponse {
+ /// Creates a new [MiddlewareRawResponse] instance.
+ ///
+ /// [statusCode] and [body] are required parameters, while [message], [headers],
+ /// and [extra] are optional.
+ ///
+ /// Example:
+ /// ```dart
+ /// final response = MiddlewareRawResponse(
+ /// statusCode: 200,
+ /// body: {'data': 'example'},
+ /// headers: {'Content-Type': 'application/json'},
+ /// message: 'Success',
+ /// );
+ /// ```
const MiddlewareRawResponse({
required this.statusCode,
required this.body,
@@ -7,16 +25,44 @@ final class MiddlewareRawResponse {
this.extra,
});
+ /// Creates a default instance of [MiddlewareRawResponse] with a status code of -99
+ /// and a null body.
+ ///
+ /// This can be used as a placeholder or for initialization purposes.
+ ///
+ /// Example:
+ /// ```dart
+ /// final defaultResponse = MiddlewareRawResponse.defaultInstance();
+ /// print(defaultResponse.statusCode); // Outputs: -99
+ /// ```
factory MiddlewareRawResponse.defaultInstance() {
return const MiddlewareRawResponse(statusCode: -99, body: null);
}
+ /// The HTTP status code of the response.
final int statusCode;
+
+ /// The headers of the HTTP response, if any.
final Map? headers;
+
+ /// Additional metadata or context information about the response.
final Map? extra;
+
+ /// The body of the HTTP response. Can be of any type.
final dynamic body;
+
+ /// An optional message associated with the response.
final String? message;
+ /// Indicates whether the response contains valid data.
+ ///
+ /// Returns true if the body is not null and the status code is in the 2xx range.
+ ///
+ /// Example:
+ /// ```dart
+ /// final response = MiddlewareRawResponse(statusCode: 200, body: {'key': 'value'});
+ /// print(response.hasData); // Outputs: true
+ /// ```
bool get hasData => body != null && statusCode >= 200 && statusCode < 300;
@override
diff --git a/lib/src/middleware/wordpress_middleware_base.dart b/lib/src/middleware/wordpress_middleware_base.dart
index 4d46810..5638301 100644
--- a/lib/src/middleware/wordpress_middleware_base.dart
+++ b/lib/src/middleware/wordpress_middleware_base.dart
@@ -3,30 +3,93 @@ import 'dart:async';
import '../library_exports.dart';
/// The base interface for WordPress middleware.
+///
+/// Middleware allows you to intercept and modify requests and responses
+/// in the WordPress API client. This can be useful for tasks such as
+/// authentication, caching, logging, or modifying request/response data.
abstract class IWordpressMiddleware {
const IWordpressMiddleware();
/// The name of the middleware.
+ ///
+ /// This should be a unique identifier for the middleware.
+ /// Example: 'AuthenticationMiddleware'
String get name;
/// Called when the middleware is loaded.
+ ///
+ /// Use this method to initialize any resources needed by the middleware.
+ /// Example:
+ /// ```dart
+ /// @override
+ /// Future onLoad() async {
+ /// await _initializeCache();
+ /// }
+ /// ```
Future onLoad();
/// Called before sending a request to the WordPress server.
+ ///
+ /// This method allows you to modify the outgoing request.
+ /// Example: Adding an authentication token to the request headers
+ /// ```dart
+ /// @override
+ /// Future onRequest(WordpressRequest request) async {
+ /// return request.copyWith(
+ /// headers: {...request.headers, 'Authorization': 'Bearer $token'},
+ /// );
+ /// }
+ /// ```
Future onRequest(WordpressRequest request);
/// Called before executing a request to the WordPress server.
///
+ /// This method can be used to return a custom response (e.g., a cached response)
+ /// or to cancel the request by throwing an exception.
+ ///
/// By default, it returns a [MiddlewareRawResponse] with default values.
///
- /// This can used for returning a custom response (cached response), or to cancel the request (By throwing an exception).
+ /// Example: Returning a cached response
+ /// ```dart
+ /// @override
+ /// Future onExecute(WordpressRequest request) async {
+ /// final cachedResponse = await _cache.get(request.url);
+ /// if (cachedResponse != null) {
+ /// return MiddlewareRawResponse(
+ /// statusCode: 200,
+ /// body: cachedResponse,
+ /// headers: {'X-Cache': 'HIT'},
+ /// );
+ /// }
+ /// return MiddlewareRawResponse.defaultInstance();
+ /// }
+ /// ```
Future onExecute(WordpressRequest request) async {
return MiddlewareRawResponse.defaultInstance();
}
/// Called after receiving a response from the WordPress server.
+ ///
+ /// This method allows you to modify or process the incoming response.
+ /// Example: Logging the response
+ /// ```dart
+ /// @override
+ /// Future onResponse(WordpressRawResponse response) async {
+ /// _logger.info('Received response: ${response.statusCode}');
+ /// return response;
+ /// }
+ /// ```
Future onResponse(WordpressRawResponse response);
/// Called when the middleware is unloaded.
+ ///
+ /// Use this method to clean up any resources used by the middleware.
+ /// Example:
+ /// ```dart
+ /// @override
+ /// Future onUnload() async {
+ /// await _closeConnections();
+ /// }
+ /// ```
Future onUnload();
}
diff --git a/lib/src/operations/create.dart b/lib/src/operations/create.dart
index e501b89..e8b0635 100644
--- a/lib/src/operations/create.dart
+++ b/lib/src/operations/create.dart
@@ -1,14 +1,32 @@
import '../library_exports.dart';
-/// Represents the create operation.
+/// Represents the create operation for WordPress API requests.
+///
+/// This mixin provides methods to create new resources using the WordPress API.
+/// It is generic over the type [T] of the response data and [R] which extends [IRequest].
base mixin CreateOperation on IRequestInterface {
+ /// Creates a new resource using the provided [request].
+ ///
+ /// This method sends a create request to the WordPress API and returns
+ /// a [WordpressResponse] containing the created resource of type [T].
+ ///
+ /// [request] is an instance of [R] that contains the necessary data for the create operation.
+ ///
+ /// Returns a [Future] that resolves to a [WordpressResponse].
Future> create(R request) async {
final wpRequest = await request.build(baseUrl);
return executor.create(wpRequest);
}
- /// Returns the raw response for the given [request].
+ /// Creates a new resource and returns the raw response for the given [request].
+ ///
+ /// This method is similar to [create], but instead of parsing the response,
+ /// it returns the raw response from the WordPress API.
+ ///
+ /// [request] is an instance of [R] that contains the necessary data for the create operation.
+ ///
+ /// Returns a [Future] that resolves to a [WordpressRawResponse].
Future createRaw(R request) async {
final wpRequest = await request.build(baseUrl);
diff --git a/lib/src/operations/custom.dart b/lib/src/operations/custom.dart
index 20acec4..61d3c1b 100644
--- a/lib/src/operations/custom.dart
+++ b/lib/src/operations/custom.dart
@@ -1,10 +1,21 @@
import '../library_exports.dart';
-/// Represents the custom operation. This mixin is used to create custom operations.
+/// Represents a custom operation for interacting with WordPress APIs.
+/// This mixin is used to create custom operations that can execute requests
+/// and handle responses.
base mixin CustomOperation on IRequestInterface {
+ /// Decodes the JSON response into the desired type [T].
+ /// Implement this method to define how the API response should be parsed.
T decode(dynamic json);
- /// Executes the given [request] and returns the response.
+ /// Executes the given [request] and returns a typed response.
+ ///
+ /// This method performs the following steps:
+ /// 1. Builds the WordPress request using the provided [request] object.
+ /// 2. Executes the request using the [executor].
+ /// 3. Decodes the response using the [decode] method.
+ ///
+ /// Returns a [WordpressResponse] containing the decoded data of type [T].
Future> request(R request) async {
final wpRequest = await request.build(baseUrl);
@@ -13,7 +24,14 @@ base mixin CustomOperation on IRequestInterface {
return response.asResponse(decoder: decode);
}
- /// Returns the raw response for the given [request].
+ /// Returns the raw response for the given [request] without decoding.
+ ///
+ /// This method is useful when you need access to the unprocessed API response.
+ /// It performs the following steps:
+ /// 1. Builds the WordPress request using the provided [request] object.
+ /// 2. Executes the request using the [executor] in raw mode.
+ ///
+ /// Returns a [WordpressRawResponse] containing the unprocessed API response.
Future raw(R request) async {
final wpRequest = await request.build(baseUrl);
diff --git a/lib/src/operations/delete.dart b/lib/src/operations/delete.dart
index f6de97d..1aa5783 100644
--- a/lib/src/operations/delete.dart
+++ b/lib/src/operations/delete.dart
@@ -1,16 +1,35 @@
import '../library_exports.dart';
-/// Represents the delete operation.
+/// Represents the delete operation for WordPress API requests.
+///
+/// This mixin provides methods to delete resources using the WordPress API.
+/// It is generic over [R] which extends [IRequest].
base mixin DeleteOperation on IRequestInterface {
+ /// Deletes a resource using the provided [request].
+ ///
+ /// This method sends a delete request to the WordPress API and returns
+ /// a [WordpressResponse] containing a boolean indicating the success of the operation.
+ ///
+ /// [request] is an instance of [R] that contains the necessary data for the delete operation.
+ ///
+ /// Returns a [Future] that resolves to a [WordpressResponse].
+ /// The boolean value is typically true if the deletion was successful.
Future> delete(R request) async {
final wpRequest = await request.build(baseUrl);
return executor.delete(wpRequest);
}
- /// Returns the raw response for the given [request].
+ /// Deletes a resource and returns the raw response for the given [request].
+ ///
+ /// This method is similar to [delete], but instead of parsing the response,
+ /// it returns the raw response from the WordPress API.
+ ///
+ /// [request] is an instance of [R] that contains the necessary data for the delete operation.
+ ///
+ /// Returns a [Future] that resolves to a [WordpressRawResponse].
///
- /// **Note that for delete responses, Wordpress API returns an empty response body.**
+ /// **Note: For delete operations, the WordPress API typically returns an empty response body.**
Future deleteRaw(R request) async {
final wpRequest = await request.build(baseUrl);
diff --git a/lib/src/operations/list.dart b/lib/src/operations/list.dart
index 4a9f2a8..72dcc6c 100644
--- a/lib/src/operations/list.dart
+++ b/lib/src/operations/list.dart
@@ -1,7 +1,19 @@
import '../../wordpress_client.dart';
-/// Represents the list operation.
+/// Represents the list operation for WordPress API requests.
+///
+/// This mixin provides methods to retrieve lists of resources using the WordPress API.
+/// It is generic over the type [T] of the response data and [R] which extends [IRequest].
base mixin ListOperation on IRequestInterface {
+ /// Retrieves a list of resources using the provided [request].
+ ///
+ /// This method sends a list request to the WordPress API and returns
+ /// a [WordpressResponse] containing a list of resources of type [T].
+ ///
+ /// [request] is an instance of [R] that contains the necessary parameters for the list operation,
+ /// such as pagination, filtering, or sorting options.
+ ///
+ /// Returns a [Future] that resolves to a [WordpressResponse>].
Future>> list(
R request,
) async {
@@ -10,7 +22,15 @@ base mixin ListOperation on IRequestInterface {
return executor.list(wpRequest);
}
- /// Returns the raw response for the given [request].
+ /// Retrieves a list of resources and returns the raw response for the given [request].
+ ///
+ /// This method is similar to [list], but instead of parsing the response,
+ /// it returns the raw response from the WordPress API.
+ ///
+ /// [request] is an instance of [R] that contains the necessary parameters for the list operation.
+ ///
+ /// Returns a [Future] that resolves to a [WordpressRawResponse].
+ /// This can be useful for debugging or when you need access to the full, unprocessed API response.
Future listRaw(
R request,
) async {
diff --git a/lib/src/operations/retrieve.dart b/lib/src/operations/retrieve.dart
index 589492b..70a0ecd 100644
--- a/lib/src/operations/retrieve.dart
+++ b/lib/src/operations/retrieve.dart
@@ -1,14 +1,28 @@
import '../../wordpress_client.dart';
-/// Represents the retrive operation.
+/// Represents the retrieve operation for WordPress API requests.
+///
+/// This mixin provides methods to retrieve data from a WordPress site
+/// using the WordPress REST API.
base mixin RetrieveOperation on IRequestInterface {
+ /// Retrieves data from the WordPress API and returns a typed response.
+ ///
+ /// [request] is the request object containing the necessary parameters.
+ ///
+ /// Returns a [Future] that resolves to a [WordpressResponse] containing
+ /// the retrieved data of type [T].
Future> retrieve(R request) async {
final wpRequest = await request.build(baseUrl);
return executor.retrive(wpRequest);
}
- /// Returns the raw response for the given [request].
+ /// Retrieves raw data from the WordPress API.
+ ///
+ /// [request] is the request object containing the necessary parameters.
+ ///
+ /// Returns a [Future] that resolves to a [WordpressRawResponse] containing
+ /// the raw response data from the API.
Future retrieveRaw(R request) async {
final wpRequest = await request.build(baseUrl);
diff --git a/lib/src/operations/update.dart b/lib/src/operations/update.dart
index a16afa9..ad8fb53 100644
--- a/lib/src/operations/update.dart
+++ b/lib/src/operations/update.dart
@@ -1,14 +1,29 @@
import '../../wordpress_client.dart';
-/// Represents the update operation.
+/// Represents the update operation for WordPress API requests.
+///
+/// This mixin provides methods to perform update operations on WordPress resources.
+/// It is designed to be used with classes that implement [IRequestInterface].
base mixin UpdateOperation on IRequestInterface {
+ /// Performs an update operation using the provided [request].
+ ///
+ /// [T] is the type of the expected response data.
+ /// [R] is the type of the request, which must extend [IRequest].
+ ///
+ /// Returns a [Future] that resolves to a [WordpressResponse] containing
+ /// the updated resource data.
Future> update(R request) async {
final wpRequest = await request.build(baseUrl);
return executor.update(wpRequest);
}
- /// Returns the raw response for the given [request].
+ /// Performs an update operation and returns the raw response for the given [request].
+ ///
+ /// This method is useful when you need access to the full, unprocessed API response.
+ ///
+ /// Returns a [Future] that resolves to a [WordpressRawResponse] containing
+ /// the raw API response data.
Future updateRaw(R request) async {
final wpRequest = await request.build(baseUrl);
diff --git a/lib/src/parallel_wordpress/exports.dart b/lib/src/parallel_wordpress/exports.dart
index f228d09..582b116 100644
--- a/lib/src/parallel_wordpress/exports.dart
+++ b/lib/src/parallel_wordpress/exports.dart
@@ -1,3 +1,4 @@
+export 'extensions/parallel_result_exts.dart';
export 'parallel_request.dart';
export 'parallel_result.dart';
export 'parallel_wordpress.dart';
diff --git a/lib/src/parallel_wordpress/extensions/parallel_result_exts.dart b/lib/src/parallel_wordpress/extensions/parallel_result_exts.dart
new file mode 100644
index 0000000..d526457
--- /dev/null
+++ b/lib/src/parallel_wordpress/extensions/parallel_result_exts.dart
@@ -0,0 +1,46 @@
+import '../parallel_result.dart';
+
+/// Extension methods for [Iterable>].
+extension ParallelResultExts on Iterable> {
+ /// Converts this iterable of [ParallelResult] into a [Stream].
+ ///
+ /// This method allows you to work with the results as a stream, which can be
+ /// useful for processing results asynchronously or applying stream operations.
+ ///
+ /// Example:
+ /// ```dart
+ /// final results = [ParallelResult(1), ParallelResult(2), ParallelResult(3)];
+ /// final stream = results.streamed();
+ /// await for (final result in stream) {
+ /// print(result.value);
+ /// }
+ /// ```
+ Stream> streamed() {
+ return Stream.fromIterable(this);
+ }
+}
+
+/// Extension methods for [Iterable>].
+extension ParallelIterableResultExts on Iterable> {
+ /// Converts this iterable of [ParallelIterableResult] into a [Stream].
+ ///
+ /// This method is particularly useful when working with results that contain
+ /// iterables, allowing you to process them as a stream.
+ ///
+ /// Example:
+ /// ```dart
+ /// final results = [
+ /// ParallelIterableResult(['a', 'b']),
+ /// ParallelIterableResult(['c', 'd']),
+ /// ];
+ /// final stream = results.streamed();
+ /// await for (final result in stream) {
+ /// for (final item in result.value) {
+ /// print(item);
+ /// }
+ /// }
+ /// ```
+ Stream> streamed() {
+ return Stream.fromIterable(this);
+ }
+}
diff --git a/lib/src/parallel_wordpress/parallel_result.dart b/lib/src/parallel_wordpress/parallel_result.dart
index dcce6a8..8d1df73 100644
--- a/lib/src/parallel_wordpress/parallel_result.dart
+++ b/lib/src/parallel_wordpress/parallel_result.dart
@@ -1,8 +1,8 @@
import 'package:meta/meta.dart';
@immutable
-final class ParallelResult {
- const ParallelResult({
+final class ParallelIterableResult {
+ const ParallelIterableResult({
required this.page,
required this.results,
});
@@ -16,7 +16,7 @@ final class ParallelResult {
final Iterable results;
@override
- bool operator ==(covariant ParallelResult other) {
+ bool operator ==(covariant ParallelIterableResult other) {
if (identical(this, other)) return true;
return other.page == page && other.results == results;
@@ -27,3 +27,29 @@ final class ParallelResult {
T operator [](int index) => results.elementAt(index);
}
+
+@immutable
+final class ParallelResult {
+ const ParallelResult({
+ required this.page,
+ required this.result,
+ });
+
+ /// The page number of the results.
+ ///
+ /// Note that, if this instance contains results from the `initial()` method, then the `page` will be `0`.
+ final int page;
+
+ /// The results of the request.
+ final T result;
+
+ @override
+ bool operator ==(covariant ParallelResult other) {
+ if (identical(this, other)) return true;
+
+ return other.page == page && other.result == result;
+ }
+
+ @override
+ int get hashCode => page.hashCode ^ result.hashCode;
+}
diff --git a/lib/src/parallel_wordpress/parallel_wordpress.dart b/lib/src/parallel_wordpress/parallel_wordpress.dart
index f64bb14..d75b4e9 100644
--- a/lib/src/parallel_wordpress/parallel_wordpress.dart
+++ b/lib/src/parallel_wordpress/parallel_wordpress.dart
@@ -5,8 +5,8 @@ import 'package:collection/collection.dart';
import '../library_exports.dart';
import 'parallel_raw_result.dart';
-/// `ParallelWordpress` is a class that uses a `WordpressClient` to fetch data from a WordPress site.
-/// It provides a method to fetch a list of items in parallel, which can significantly speed up the fetching process.
+/// `ParallelWordpress` is a class that uses a `WordpressClient` to perform parallel operations on a WordPress site.
+/// It provides methods to fetch, create, update, delete, and retrieve items in parallel, which can significantly speed up the process.
final class ParallelWordpress {
/// Constructs a `ParallelWordpress` instance.
///
@@ -15,22 +15,24 @@ final class ParallelWordpress {
required this.client,
});
+ /// The WordPress client used to make API requests.
final WordpressClient client;
/// Fetches a list of items of type `T` in parallel.
///
- /// The `requestBuilder` parameter is a function that builds a list of requests to be made.
- /// The `interface` parameter is a function that performs the list operation for each request.
- /// The `transformer` parameter is an optional function that transforms the results of each request.
- /// The `onException` parameter is an optional function that handles exceptions that occur during the processing of the requests.
- /// The `initial` parameter is an optional function that provides an initial list of items.
+ /// Parameters:
+ /// - `requestBuilder`: A function that builds a list of requests to be made.
+ /// - `interface`: A function that performs the list operation for each request.
+ /// - `transformer`: An optional function that transforms the results of each request.
+ /// - `onException`: An optional function that handles exceptions that occur during the processing of the requests.
+ /// - `initial`: An optional function that provides an initial list of items.
///
- /// Returns a `Future` that completes with a list of items of type `T`.
- Future>> list({
+ /// Returns a `Future` that completes with an `Iterable` of `ParallelIterableResult`.
+ Future>> list({
required RequestBuilder requestBuilder,
required ListOperation interface,
- ParallelResultTransformer? transformer,
- ParallelExceptionHandler? onException,
+ ParallelIterableResultTransformer? transformer,
+ ParallelIterableExceptionHandler? onException,
ParallelInitialItems? initial,
}) async {
final requests = await requestBuilder();
@@ -54,7 +56,7 @@ final class ParallelWordpress {
final successResponse = response.results.asSuccess();
- return ParallelResult(
+ return ParallelIterableResult(
page: response.page,
results: successResponse.data,
);
@@ -76,8 +78,265 @@ final class ParallelWordpress {
return sortedResults;
}
- final initialItems = ParallelResult(page: 0, results: await initial());
+ final initialItems =
+ ParallelIterableResult(page: 0, results: await initial());
return [initialItems, ...sortedResults];
}
+
+ /// Creates multiple items of type `T` in parallel.
+ ///
+ /// Parameters:
+ /// - `requestBuilder`: A function that builds a list of requests to be made.
+ /// - `interface`: A function that performs the create operation for each request.
+ /// - `transformer`: An optional function that transforms the results of each request.
+ /// - `onException`: An optional function that handles exceptions that occur during the processing of the requests.
+ /// - `initial`: An optional function that provides an initial item.
+ ///
+ /// Returns a `Future` that completes with an `Iterable` of `ParallelResult`.
+ Future>> create({
+ required RequestBuilder requestBuilder,
+ required CreateOperation interface,
+ ParallelResultTransformer? transformer,
+ ParallelExceptionHandler? onException,
+ ParallelInitialItem? initial,
+ }) async {
+ final requests = await requestBuilder();
+
+ final responses = await Future.wait(
+ requests.map((x) async {
+ return ParallelRawResult(
+ page: x.page,
+ results: await interface.create(x.request),
+ );
+ }),
+ eagerError: true,
+ );
+
+ final results = await responses.mapAsync(
+ (response) async => guardAsync(
+ function: () async {
+ if (transformer != null) {
+ return await transformer(response.results);
+ }
+
+ final successResponse = response.results.asSuccess();
+
+ return ParallelResult(
+ page: response.page,
+ result: successResponse.data,
+ );
+ },
+ onError: (error, stackTrace) async {
+ if (onException != null) {
+ return await onException(error);
+ }
+
+ throw ParallelProcessingException(error, stackTrace);
+ },
+ ),
+ );
+
+ final sortedResults =
+ results.sorted((a, b) => a.page.compareTo(b.page)).map((e) => e);
+
+ if (initial == null) {
+ return sortedResults;
+ }
+
+ final initialItem = ParallelResult(page: 0, result: await initial());
+ return [initialItem, ...sortedResults];
+ }
+
+ /// Updates multiple items of type `T` in parallel.
+ ///
+ /// Parameters:
+ /// - `requestBuilder`: A function that builds a list of requests to be made.
+ /// - `interface`: A function that performs the update operation for each request.
+ /// - `transformer`: An optional function that transforms the results of each request.
+ /// - `onException`: An optional function that handles exceptions that occur during the processing of the requests.
+ /// - `initial`: An optional function that provides an initial item.
+ ///
+ /// Returns a `Future` that completes with an `Iterable` of `ParallelResult`.
+ Future>> update({
+ required RequestBuilder requestBuilder,
+ required UpdateOperation interface,
+ ParallelResultTransformer? transformer,
+ ParallelExceptionHandler? onException,
+ ParallelInitialItem? initial,
+ }) async {
+ final requests = await requestBuilder();
+
+ final responses = await Future.wait(
+ requests.map((x) async {
+ return ParallelRawResult(
+ page: x.page,
+ results: await interface.update(x.request),
+ );
+ }),
+ eagerError: true,
+ );
+
+ final results = await responses.mapAsync(
+ (response) async => guardAsync(
+ function: () async {
+ if (transformer != null) {
+ return await transformer(response.results);
+ }
+
+ final successResponse = response.results.asSuccess();
+
+ return ParallelResult(
+ page: response.page,
+ result: successResponse.data,
+ );
+ },
+ onError: (error, stackTrace) async {
+ if (onException != null) {
+ return await onException(error);
+ }
+
+ throw ParallelProcessingException(error, stackTrace);
+ },
+ ),
+ );
+
+ final sortedResults =
+ results.sorted((a, b) => a.page.compareTo(b.page)).map((e) => e);
+
+ if (initial == null) {
+ return sortedResults;
+ }
+
+ final initialItem = ParallelResult(page: 0, result: await initial());
+ return [initialItem, ...sortedResults];
+ }
+
+ /// Deletes multiple items in parallel.
+ ///
+ /// Parameters:
+ /// - `requestBuilder`: A function that builds a list of requests to be made.
+ /// - `interface`: A function that performs the delete operation for each request.
+ /// - `transformer`: An optional function that transforms the results of each request.
+ /// - `onException`: An optional function that handles exceptions that occur during the processing of the requests.
+ /// - `initial`: An optional function that provides an initial boolean value.
+ ///
+ /// Returns a `Future` that completes with an `Iterable` of `ParallelResult`.
+ Future>> delete({
+ required RequestBuilder requestBuilder,
+ required DeleteOperation interface,
+ ParallelResultTransformer? transformer,
+ ParallelExceptionHandler? onException,
+ ParallelInitialItem? initial,
+ }) async {
+ final requests = await requestBuilder();
+
+ final responses = await Future.wait(
+ requests.map((x) async {
+ return ParallelRawResult(
+ page: x.page,
+ results: await interface.delete(x.request),
+ );
+ }),
+ eagerError: true,
+ );
+
+ final results = await responses.mapAsync(
+ (response) async => guardAsync(
+ function: () async {
+ if (transformer != null) {
+ return await transformer(response.results);
+ }
+
+ final successResponse = response.results.asSuccess();
+
+ return ParallelResult(
+ page: response.page,
+ result: successResponse.data,
+ );
+ },
+ onError: (error, stackTrace) async {
+ if (onException != null) {
+ return await onException(error);
+ }
+
+ throw ParallelProcessingException(error, stackTrace);
+ },
+ ),
+ );
+
+ final sortedResults =
+ results.sorted((a, b) => a.page.compareTo(b.page)).map((e) => e);
+
+ if (initial == null) {
+ return sortedResults;
+ }
+
+ final initialItem = ParallelResult(page: 0, result: await initial());
+ return [initialItem, ...sortedResults];
+ }
+
+ /// Retrieves multiple items of type `T` in parallel.
+ ///
+ /// Parameters:
+ /// - `requestBuilder`: A function that builds a list of requests to be made.
+ /// - `interface`: A function that performs the retrieve operation for each request.
+ /// - `transformer`: An optional function that transforms the results of each request.
+ /// - `onException`: An optional function that handles exceptions that occur during the processing of the requests.
+ /// - `initial`: An optional function that provides an initial item.
+ ///
+ /// Returns a `Future` that completes with an `Iterable` of `ParallelResult`.
+ Future>> retrieve({
+ required RequestBuilder requestBuilder,
+ required RetrieveOperation interface,
+ ParallelResultTransformer? transformer,
+ ParallelExceptionHandler? onException,
+ ParallelInitialItem? initial,
+ }) async {
+ final requests = await requestBuilder();
+
+ final responses = await Future.wait(
+ requests.map((x) async {
+ return ParallelRawResult(
+ page: x.page,
+ results: await interface.retrieve(x.request),
+ );
+ }),
+ eagerError: true,
+ );
+
+ final results = await responses.mapAsync(
+ (response) async => guardAsync(
+ function: () async {
+ if (transformer != null) {
+ return await transformer(response.results);
+ }
+
+ final successResponse = response.results.asSuccess();
+
+ return ParallelResult(
+ page: response.page,
+ result: successResponse.data,
+ );
+ },
+ onError: (error, stackTrace) async {
+ if (onException != null) {
+ return await onException(error);
+ }
+
+ throw ParallelProcessingException(error, stackTrace);
+ },
+ ),
+ );
+
+ final sortedResults =
+ results.sorted((a, b) => a.page.compareTo(b.page)).map((e) => e);
+
+ if (initial == null) {
+ return sortedResults;
+ }
+
+ final initialItem = ParallelResult(page: 0, result: await initial());
+ return [initialItem, ...sortedResults];
+ }
}
diff --git a/lib/src/parallel_wordpress/typedefs.dart b/lib/src/parallel_wordpress/typedefs.dart
index 8d33625..dd7bbdf 100644
--- a/lib/src/parallel_wordpress/typedefs.dart
+++ b/lib/src/parallel_wordpress/typedefs.dart
@@ -2,10 +2,20 @@ import 'dart:async';
import '../../wordpress_client.dart';
-typedef ParallelResultTransformer = FutureOr> Function(
+typedef ParallelIterableResultTransformer
+ = FutureOr> Function(
WordpressResponse> response,
);
+typedef ParallelResultTransformer = FutureOr> Function(
+ WordpressResponse response,
+);
+
+typedef ParallelIterableExceptionHandler
+ = FutureOr> Function(
+ Object error,
+);
+
typedef ParallelExceptionHandler = FutureOr> Function(
Object error,
);
@@ -13,3 +23,4 @@ typedef ParallelExceptionHandler = FutureOr> Function(
typedef RequestBuilder = FutureOr>> Function();
typedef ParallelInitialItems = FutureOr> Function();
+typedef ParallelInitialItem = FutureOr Function();
diff --git a/lib/src/request_executor_base.dart b/lib/src/request_executor_base.dart
index f7672b9..b16f057 100644
--- a/lib/src/request_executor_base.dart
+++ b/lib/src/request_executor_base.dart
@@ -6,13 +6,30 @@ import 'library_exports.dart';
import 'responses/wordpress_error.dart';
import 'utilities/codable_map/codable_map.dart';
+/// Base class for request executors in the WordPress API client.
+///
+/// This class provides the core functionality for executing requests,
+/// handling middleware, and processing responses.
abstract base class IRequestExecutor {
+ /// The base URL for the WordPress API.
Uri get baseUrl;
+ /// The list of middleware to be applied to requests and responses.
Iterable get middlewares;
+ /// Configures the executor with the given bootstrap configuration.
+ ///
+ /// This method should be called before making any requests.
+ ///
+ /// [configuration] The configuration to apply.
void configure(BootstrapConfiguration configuration);
+ /// Applies request middleware to the given request.
+ ///
+ /// [request] The original request.
+ /// [middlewares] The list of middleware to apply.
+ ///
+ /// Returns the modified request after applying all middleware.
Future _handleRequestMiddlewares({
required WordpressRequest request,
required Iterable middlewares,
@@ -23,6 +40,12 @@ abstract base class IRequestExecutor {
);
}
+ /// Applies response middleware to the given response.
+ ///
+ /// [middlewares] The list of middleware to apply.
+ /// [response] The original response.
+ ///
+ /// Returns the modified response after applying all middleware.
Future _handleResponseMiddlewares({
required Iterable middlewares,
required WordpressRawResponse response,
@@ -33,6 +56,13 @@ abstract base class IRequestExecutor {
);
}
+ /// Executes a raw request and returns the response.
+ ///
+ /// This method applies middleware, executes the request, and handles errors.
+ ///
+ /// [request] The request to execute.
+ ///
+ /// Returns a [WordpressRawResponse] containing the raw response data.
@internal
Future raw(WordpressRequest request) async {
return guardAsync(
@@ -68,6 +98,13 @@ abstract base class IRequestExecutor {
);
}
+ /// Creates a new resource using the given request.
+ ///
+ /// This method is used for POST requests to create new items in the WordPress API.
+ ///
+ /// [request] The request containing the data for the new resource.
+ ///
+ /// Returns a [WordpressResponse] with the created item of type [T].
@internal
Future> create(
WordpressRequest request,
@@ -140,6 +177,13 @@ abstract base class IRequestExecutor {
);
}
+ /// Retrieves a resource using the given request.
+ ///
+ /// This method is used for GET requests to fetch existing items from the WordPress API.
+ ///
+ /// [request] The request specifying the resource to retrieve.
+ ///
+ /// Returns a [WordpressResponse] with the retrieved item of type [T].
@internal
Future> retrive(
WordpressRequest request,
@@ -212,6 +256,13 @@ abstract base class IRequestExecutor {
);
}
+ /// Deletes a resource using the given request.
+ ///
+ /// This method is used for DELETE requests to remove items from the WordPress API.
+ ///
+ /// [request] The request specifying the resource to delete.
+ ///
+ /// Returns a [WordpressResponse] with a boolean indicating success or failure.
@internal
Future> delete(
WordpressRequest request,
@@ -281,6 +332,13 @@ abstract base class IRequestExecutor {
);
}
+ /// Retrieves a list of resources using the given request.
+ ///
+ /// This method is used for GET requests to fetch multiple items from the WordPress API.
+ ///
+ /// [request] The request specifying the resources to list.
+ ///
+ /// Returns a [WordpressResponse] with a list of items of type [T].
@internal
Future>> list(
WordpressRequest request,
@@ -355,6 +413,13 @@ abstract base class IRequestExecutor {
);
}
+ /// Updates an existing resource using the given request.
+ ///
+ /// This method is used for PUT or PATCH requests to modify existing items in the WordPress API.
+ ///
+ /// [request] The request containing the updated data for the resource.
+ ///
+ /// Returns a [WordpressResponse] with the updated item of type [T].
@internal
Future> update(
WordpressRequest request,
@@ -427,7 +492,13 @@ abstract base class IRequestExecutor {
);
}
- /// Executes the given [request] on the associated base url and returns the result in raw format.
+ /// Executes the given [request] on the associated base URL and returns the result in raw format.
+ ///
+ /// This method should be implemented by subclasses to perform the actual HTTP request.
+ ///
+ /// [request] The request to execute.
+ ///
+ /// Returns a [WordpressRawResponse] containing the raw response data.
@internal
Future execute(WordpressRequest request);
}
diff --git a/lib/src/requests/create/create_media.dart b/lib/src/requests/create/create_media.dart
index 1dd06ad..b43649f 100644
--- a/lib/src/requests/create/create_media.dart
+++ b/lib/src/requests/create/create_media.dart
@@ -1,22 +1,25 @@
// ignore_for_file: avoid_slow_async_io
import 'dart:io';
+import 'dart:typed_data';
import 'package:dio/dio.dart';
-import 'package:http_parser/http_parser.dart' show MediaType;
import 'package:path/path.dart';
-import '../../enums.dart' show Status, HttpMethod;
-import '../../exceptions/file_not_exist_exception.dart';
-import '../../utilities/extensions/map_extensions.dart';
-import '../../utilities/helpers.dart';
-import '../../utilities/request_url.dart';
-import '../request_interface.dart';
-import '../wordpress_request.dart';
+import '../../../wordpress_client.dart';
+import '../../constants.dart';
+/// A request class for creating media in WordPress.
+///
+/// This class provides functionality to create media items in WordPress,
+/// supporting both file-based and byte-based media uploads.
final class CreateMediaRequest extends IRequest {
- CreateMediaRequest({
- required this.mediaFilePath,
+ /// Private constructor for CreateMediaRequest.
+ ///
+ /// This constructor is used internally by the factory methods.
+ CreateMediaRequest._({
+ required this.mediaFile,
+ required this.fileName,
this.altText,
this.caption,
this.description,
@@ -38,39 +41,197 @@ final class CreateMediaRequest extends IRequest {
super.queryParameters,
});
- String mediaFilePath;
- String? altText;
- String? caption;
- String? description;
- String? mediaStatus;
- int? post;
- String? title;
- int? authorId;
- Status? commentStatus;
- Status? pingStatus;
+ /// Creates a CreateMediaRequest instance from a File.
+ ///
+ /// Use this factory method when you have a file on the device that you want to upload.
+ ///
+ /// [file] is the File object representing the media to be uploaded.
+ /// Other parameters are optional and correspond to various media attributes and request options.
+ factory CreateMediaRequest.fromFile({
+ required File file,
+ String? altText,
+ String? caption,
+ String? description,
+ String? mediaStatus,
+ int? post,
+ String? title,
+ int? authorId,
+ Status? commentStatus,
+ Status? pingStatus,
+ CancelToken? cancelToken,
+ IAuthorization? authorization,
+ WordpressEvents? events,
+ Duration? receiveTimeout,
+ bool? requireAuth,
+ Duration? sendTimeout,
+ ValidatorCallback? validator,
+ Map? extra,
+ Map? headers,
+ Map? queryParameters,
+ }) {
+ return CreateMediaRequest._(
+ mediaFile: file,
+ fileName: basename(file.path),
+ altText: altText,
+ caption: caption,
+ description: description,
+ mediaStatus: mediaStatus,
+ post: post,
+ title: title,
+ authorId: authorId,
+ commentStatus: commentStatus,
+ pingStatus: pingStatus,
+ cancelToken: cancelToken,
+ authorization: authorization,
+ events: events,
+ receiveTimeout: receiveTimeout ?? DEFAULT_REQUEST_TIMEOUT,
+ requireAuth: requireAuth ?? true,
+ sendTimeout: sendTimeout ?? DEFAULT_REQUEST_TIMEOUT,
+ validator: validator,
+ extra: extra,
+ headers: headers,
+ queryParameters: queryParameters,
+ );
+ }
+
+ /// Creates a CreateMediaRequest instance from bytes.
+ ///
+ /// Use this factory method when you have the media content as a byte array.
+ ///
+ /// [bytes] is the Uint8List containing the media data.
+ /// [fileName] is the name to be given to the file when uploaded.
+ /// Other parameters are optional and correspond to various media attributes and request options.
+ factory CreateMediaRequest.fromBytes({
+ required Uint8List bytes,
+ required String fileName,
+ String? altText,
+ String? caption,
+ String? description,
+ String? mediaStatus,
+ int? post,
+ String? title,
+ int? authorId,
+ Status? commentStatus,
+ Status? pingStatus,
+ CancelToken? cancelToken,
+ IAuthorization? authorization,
+ WordpressEvents? events,
+ Duration? receiveTimeout,
+ bool? requireAuth,
+ Duration? sendTimeout,
+ ValidatorCallback? validator,
+ Map? extra,
+ Map? headers,
+ Map? queryParameters,
+ }) {
+ return CreateMediaRequest._(
+ mediaFile: bytes,
+ fileName: fileName,
+ altText: altText,
+ caption: caption,
+ description: description,
+ mediaStatus: mediaStatus,
+ post: post,
+ title: title,
+ authorId: authorId,
+ commentStatus: commentStatus,
+ pingStatus: pingStatus,
+ cancelToken: cancelToken,
+ authorization: authorization,
+ events: events,
+ receiveTimeout: receiveTimeout ?? DEFAULT_REQUEST_TIMEOUT,
+ requireAuth: requireAuth ?? true,
+ sendTimeout: sendTimeout ?? DEFAULT_REQUEST_TIMEOUT,
+ validator: validator,
+ extra: extra,
+ headers: headers,
+ queryParameters: queryParameters,
+ );
+ }
+
+ /// The media file to be uploaded, either as a File or Uint8List.
+ final dynamic mediaFile;
+
+ /// The name of the file to be uploaded.
+ final String fileName;
+ /// Alternative text for the media.
+ final String? altText;
+
+ /// Caption for the media.
+ final String? caption;
+
+ /// Description of the media.
+ final String? description;
+
+ /// Status of the media (e.g., 'publish', 'draft').
+ final String? mediaStatus;
+
+ /// ID of the post to which this media is attached.
+ final int? post;
+
+ /// Title of the media.
+ final String? title;
+
+ /// ID of the author of the media.
+ final int? authorId;
+
+ /// Comment status for the media.
+ final Status? commentStatus;
+
+ /// Ping status for the media.
+ final Status? pingStatus;
+
+ /// Builds the WordPress request for creating media.
+ ///
+ /// This method prepares the request by creating a MultipartFile from the media,
+ /// setting up the necessary headers and body, and returning a WordpressRequest object.
@override
Future build(Uri baseUrl) async {
- final file = File(mediaFilePath);
+ MultipartFile? multipartFile;
+ String? mimeType;
- if (!await file.exists()) {
- throw FileDoesntExistException(
- 'The file at path "$mediaFilePath" doesn\'t exist.',
+ if (mediaFile is File) {
+ final file = mediaFile as File;
+ if (!await file.exists()) {
+ throw FileDoesntExistException(
+ 'The file at path "${file.path}" doesn\'t exist.',
+ );
+ }
+
+ final mediaType = getMIMETypeFromExtension(
+ extension(fileName).replaceFirst('.', ''),
);
- }
- final fileName = basename(file.path);
- final mediaType = getMIMETypeFromExtension(
- extension(fileName).replaceFirst('.', ''),
- );
+ multipartFile = await MultipartFile.fromFile(
+ file.path,
+ filename: fileName,
+ contentType: DioMediaType.parse(mediaType),
+ );
+ mimeType = mediaType;
+ } else if (mediaFile is Uint8List) {
+ final bytes = mediaFile as Uint8List;
- final multipartFile = MultipartFile.fromBytes(
- await file.readAsBytes(),
- filename: fileName,
- contentType: MediaType.parse(mediaType),
- );
+ if (!fileName.contains('.')) {
+ throw ArgumentError(
+ 'The file name must contain a file extension.',
+ );
+ }
- final mimeType = multipartFile.contentType!.mimeType;
+ final mediaType = getMIMETypeFromExtension(
+ extension(fileName).replaceFirst('.', ''),
+ );
+ multipartFile = MultipartFile.fromBytes(
+ bytes,
+ filename: fileName,
+ contentType: DioMediaType.parse(mediaType),
+ );
+ mimeType = mediaType;
+ } else {
+ throw ArgumentError(
+ 'Invalid content type for the file. Please use the `fromBytes` factory method to upload files with custom content types.',
+ );
+ }
final body = {}
..addIfNotNull('alt_text', altText)
diff --git a/lib/src/requests/query_builder_base.dart b/lib/src/requests/query_builder_base.dart
new file mode 100644
index 0000000..ea93aa0
--- /dev/null
+++ b/lib/src/requests/query_builder_base.dart
@@ -0,0 +1,74 @@
+import 'package:dio/dio.dart';
+
+import '../../wordpress_client.dart';
+
+abstract base class IQueryBuilder> extends IRequest {
+ final Map _queryParameters = {};
+ final Map _body = {};
+ final Map _headers = {};
+ final Map _extra = {};
+ bool _requireAuth = false;
+ CancelToken? _cancelToken;
+ IAuthorization? _authorization;
+ WordpressEvents? _events;
+ Duration _receiveTimeout = const Duration(seconds: 30);
+ Duration _sendTimeout = const Duration(seconds: 30);
+ ValidatorCallback? _validator;
+
+ IQueryBuilder withQueryParameter(String key, dynamic value) {
+ _queryParameters[key] = value;
+ return this;
+ }
+
+ IQueryBuilder withBodyParameter(String key, dynamic value) {
+ _body[key] = value;
+ return this;
+ }
+
+ IQueryBuilder withHeader(String key, String value) {
+ _headers[key] = value;
+ return this;
+ }
+
+ IQueryBuilder withExtra(String key, dynamic value) {
+ _extra[key] = value;
+ return this;
+ }
+
+ IQueryBuilder withAuthRequired(bool value) {
+ _requireAuth = value;
+ return this;
+ }
+
+ IQueryBuilder withCancelToken(CancelToken token) {
+ _cancelToken = token;
+ return this;
+ }
+
+ IQueryBuilder withAuthorization(IAuthorization auth) {
+ _authorization = auth;
+ return this;
+ }
+
+ IQueryBuilder withEvents(WordpressEvents events) {
+ _events = events;
+ return this;
+ }
+
+ IQueryBuilder withReceiveTimeout(Duration timeout) {
+ _receiveTimeout = timeout;
+ return this;
+ }
+
+ IQueryBuilder withSendTimeout(Duration timeout) {
+ _sendTimeout = timeout;
+ return this;
+ }
+
+ IQueryBuilder withValidator(ValidatorCallback validator) {
+ _validator = validator;
+ return this;
+ }
+
+ WordpressRequest build(Uri baseUrl);
+}
diff --git a/lib/src/requests/wordpress_request.dart b/lib/src/requests/wordpress_request.dart
index 2c688e4..10faf51 100644
--- a/lib/src/requests/wordpress_request.dart
+++ b/lib/src/requests/wordpress_request.dart
@@ -3,8 +3,15 @@ import 'package:dio/dio.dart';
import '../../wordpress_client.dart';
import '../constants.dart';
-/// Represents a request to the Wordpress REST API.
+/// Represents a request to the WordPress REST API.
+///
+/// This class encapsulates all the necessary information for making a request
+/// to the WordPress REST API, including the URL, method, headers, and other
+/// configuration options.
final class WordpressRequest {
+ /// Creates a new [WordpressRequest] instance.
+ ///
+ /// [url] and [method] are required parameters. All other parameters are optional.
const WordpressRequest({
required this.url,
required this.method,
@@ -20,51 +27,54 @@ final class WordpressRequest {
this.receiveTimeout = DEFAULT_REQUEST_TIMEOUT,
});
- /// The request url.
+ /// The URL for the request.
final RequestUrl url;
- /// The request method.
+ /// The HTTP method for the request (e.g., GET, POST, PUT, DELETE).
final HttpMethod method;
- /// The request headers.
+ /// Optional headers to be included with the request.
final Map? headers;
- /// The request query parameters.
+ /// Optional query parameters to be appended to the URL.
final Map? queryParameters;
- /// The request body.
+ /// The body of the request, typically used for POST or PUT requests.
final dynamic body;
- /// Specifies if this request requires authentication.
+ /// Indicates whether this request requires authentication.
final bool requireAuth;
- /// The cancel token.
+ /// A token that can be used to cancel the request.
final CancelToken? cancelToken;
- /// The authorization instance.
+ /// The authorization instance to be used for this request, if required.
final IAuthorization? authorization;
- /// The request send timeout.
+ /// The timeout duration for sending the request.
final Duration sendTimeout;
- /// The request receive timeout.
+ /// The timeout duration for receiving the response.
final Duration receiveTimeout;
- /// The events instance.
+ /// An optional [WordpressEvents] instance for handling request lifecycle events.
final WordpressEvents? events;
- /// The validator callback.
+ /// An optional callback function for custom validation of the response.
final ValidatorCallback? validator;
- /// Gets if this request has events.
+ /// Indicates whether this request has associated events.
bool get hasEvents => events != null;
- /// Gets if this request has a validator overload.
+ /// Indicates whether this request has a custom validator.
bool get hasValidator => validator != null;
- /// Gets if this request has a authorization module.
+ /// Indicates whether this request has an associated authorization module.
bool get hasAuthorization => authorization != null;
+ /// Creates a copy of this [WordpressRequest] with the given fields replaced with new values.
+ ///
+ /// This method is useful for modifying a request while keeping the original intact.
WordpressRequest copyWith({
RequestUrl? url,
HttpMethod? method,
diff --git a/lib/src/responses/application_password_response.dart b/lib/src/responses/application_password_response.dart
index 0376bc9..ab4da7d 100644
--- a/lib/src/responses/application_password_response.dart
+++ b/lib/src/responses/application_password_response.dart
@@ -3,8 +3,22 @@ import 'package:meta/meta.dart';
import '../library_exports.dart';
import '../utilities/self_representive_base.dart';
+/// Represents an application password in the WordPress system.
+///
+/// Application passwords allow authentication for non-interactive systems, such as mobile or desktop applications,
+/// without providing your actual password. Each application password has limited capabilities compared to your main account password.
@immutable
final class ApplicationPassword implements ISelfRespresentive {
+ /// Creates a new [ApplicationPassword] instance.
+ ///
+ /// - [uuid]: The unique identifier for this application password.
+ /// - [appId]: The ID of the application associated with this password.
+ /// - [name]: The name of the application password.
+ /// - [created]: The date and time when the password was created.
+ /// - [lastUsed]: The date and time when the password was last used.
+ /// - [lastIp]: The IP address from which the password was last used.
+ /// - [password]: The actual password string (only available when first created).
+ /// - [self]: The raw JSON representation of this object.
const ApplicationPassword({
required this.uuid,
required this.appId,
@@ -16,6 +30,9 @@ final class ApplicationPassword implements ISelfRespresentive {
this.password,
});
+ /// Creates an [ApplicationPassword] instance from a JSON map.
+ ///
+ /// [json] is the JSON map containing the application password data.
factory ApplicationPassword.fromJson(Map json) {
return ApplicationPassword(
uuid: castOrElse(json['uuid']),
@@ -29,17 +46,32 @@ final class ApplicationPassword implements ISelfRespresentive {
);
}
+ /// The unique identifier for this application password.
final String uuid;
+
+ /// The ID of the application associated with this password.
final String? appId;
+
+ /// The name of the application password.
final String name;
+
+ /// The date and time when the password was created.
final DateTime? created;
+
+ /// The date and time when the password was last used.
final DateTime? lastUsed;
+
+ /// The IP address from which the password was last used.
final String? lastIp;
+
+ /// The actual password string (only available when first created).
final String? password;
+ /// The raw JSON representation of this object.
@override
final Map self;
+ /// Converts this [ApplicationPassword] instance to a JSON map.
Map toJson() {
return {
'uuid': uuid,
@@ -51,4 +83,35 @@ final class ApplicationPassword implements ISelfRespresentive {
'password': password,
};
}
+
+ @override
+ bool operator ==(covariant ApplicationPassword other) {
+ if (identical(this, other)) {
+ return true;
+ }
+
+ return other.uuid == uuid &&
+ other.appId == appId &&
+ other.name == name &&
+ other.created == created &&
+ other.lastUsed == lastUsed &&
+ other.lastIp == lastIp &&
+ other.password == password;
+ }
+
+ @override
+ int get hashCode {
+ return uuid.hashCode ^
+ appId.hashCode ^
+ name.hashCode ^
+ created.hashCode ^
+ lastUsed.hashCode ^
+ lastIp.hashCode ^
+ password.hashCode;
+ }
+
+ @override
+ String toString() {
+ return 'ApplicationPassword(uuid: $uuid, appId: $appId, name: $name, created: $created, lastUsed: $lastUsed, lastIp: $lastIp, password: $password)';
+ }
}
diff --git a/lib/src/responses/category_response.dart b/lib/src/responses/category_response.dart
index 8df2164..6a960e5 100644
--- a/lib/src/responses/category_response.dart
+++ b/lib/src/responses/category_response.dart
@@ -4,8 +4,23 @@ import 'package:meta/meta.dart';
import '../utilities/helpers.dart';
import '../utilities/self_representive_base.dart';
+/// Represents a category in WordPress.
+///
+/// Categories are a taxonomy in WordPress used to group and organize content.
+/// They can be hierarchical, allowing for parent-child relationships between categories.
@immutable
class Category implements ISelfRespresentive {
+ /// Creates a new [Category] instance.
+ ///
+ /// - [id]: Unique identifier for the category.
+ /// - [count]: Number of posts in the category.
+ /// - [description]: HTML description of the category.
+ /// - [link]: URL to the category's archive page.
+ /// - [slug]: An alphanumeric identifier for the category unique to its type.
+ /// - [taxonomy]: Type of taxonomy. For categories, this is always "category".
+ /// - [parent]: The parent category ID, if any.
+ /// - [self]: The raw JSON representation of this object.
+ /// - [name]: HTML title for the category.
const Category({
required this.id,
required this.count,
@@ -18,6 +33,9 @@ class Category implements ISelfRespresentive {
this.name,
});
+ /// Creates a [Category] instance from a JSON map.
+ ///
+ /// [json] is the JSON map containing the category data.
factory Category.fromJson(dynamic json) {
return Category(
id: castOrElse(json['id']),
@@ -32,18 +50,35 @@ class Category implements ISelfRespresentive {
);
}
+ /// Unique identifier for the category.
final int id;
+
+ /// Number of posts in the category.
final int count;
+
+ /// HTML description of the category.
final String? description;
+
+ /// URL to the category's archive page.
final String? link;
+
+ /// HTML title for the category.
final String? name;
+
+ /// An alphanumeric identifier for the category unique to its type.
final String slug;
+
+ /// Type of taxonomy. For categories, this is always "category".
final String? taxonomy;
+
+ /// The parent category ID, if any.
final int? parent;
+ /// The raw JSON representation of this object.
@override
final Map self;
+ /// Converts this [Category] instance to a JSON map.
Map toJson() {
return {
'id': id,
diff --git a/lib/src/responses/comment_response.dart b/lib/src/responses/comment_response.dart
index 3774c5d..eae9a7c 100644
--- a/lib/src/responses/comment_response.dart
+++ b/lib/src/responses/comment_response.dart
@@ -7,8 +7,15 @@ import '../utilities/self_representive_base.dart';
import 'properties/avatar_urls.dart';
import 'properties/content.dart';
+/// Represents a comment in the WordPress system.
+///
+/// This class encapsulates all the properties of a comment as defined in the WordPress REST API.
+/// For more details, see: https://developer.wordpress.org/rest-api/reference/comments/
@immutable
final class Comment implements ISelfRespresentive {
+ /// Creates a new [Comment] instance.
+ ///
+ /// All parameters correspond to the properties of a comment as defined in the WordPress REST API.
const Comment({
required this.self,
required this.status,
@@ -29,6 +36,9 @@ final class Comment implements ISelfRespresentive {
this.authorAvatarUrls,
});
+ /// Creates a [Comment] instance from a JSON map.
+ ///
+ /// [json] is the JSON map containing the comment data.
factory Comment.fromJson(Map json) {
return Comment(
id: castOrElse(json['id']),
@@ -59,26 +69,59 @@ final class Comment implements ISelfRespresentive {
);
}
+ /// Unique identifier for the comment.
final int id;
+
+ /// The ID of the associated post.
final int? post;
+
+ /// The ID of the parent comment (if this is a reply).
final int? parent;
+
+ /// The ID of the user who authored the comment (if they were logged in).
final int? author;
+
+ /// Display name of the comment author.
final String? authorName;
+
+ /// Email address of the comment author.
final String? authorEmail;
+
+ /// URL provided by the comment author.
final String authorUrl;
+
+ /// IP address of the comment author.
final String? authorIp;
+
+ /// User agent of the browser used to submit the comment.
final String? authorUserAgent;
+
+ /// The date the comment was published, in the site's timezone.
final DateTime? date;
+
+ /// The date the comment was published, as GMT.
final DateTime? dateGmt;
+
+ /// The content of the comment.
final Content? content;
+
+ /// URL to the comment.
final String link;
+
+ /// Status of the comment (approved, pending, spam).
final CommentStatus status;
+
+ /// Type of the comment (typically 'comment').
final String type;
+
+ /// Avatar URLs for the comment author.
final AvatarUrls? authorAvatarUrls;
+ /// The raw JSON representation of this object.
@override
final Map self;
+ /// Converts this [Comment] instance to a JSON map.
Map toJson() {
return {
'id': id,
diff --git a/lib/src/responses/media_response.dart b/lib/src/responses/media_response.dart
index 5e14e8d..19a42eb 100644
--- a/lib/src/responses/media_response.dart
+++ b/lib/src/responses/media_response.dart
@@ -7,8 +7,17 @@ import '../utilities/self_representive_base.dart';
import 'properties/content.dart';
import 'properties/media_details.dart';
+/// Represents a media item in the WordPress system.
+///
+/// This class encapsulates all the properties of a media item as defined in the WordPress REST API.
+/// Media items are attachments, such as images, documents, or videos.
+///
+/// For more details, see: https://developer.wordpress.org/rest-api/reference/media/
@immutable
final class Media implements ISelfRespresentive {
+ /// Creates a new [Media] instance.
+ ///
+ /// All parameters correspond to the properties of a media item as defined in the WordPress REST API.
const Media({
required this.self,
required this.id,
@@ -37,6 +46,9 @@ final class Media implements ISelfRespresentive {
this.sourceUrl,
});
+ /// Creates a [Media] instance from a JSON map.
+ ///
+ /// [json] is the JSON map containing the media item data.
factory Media.fromJson(Map